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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/bundled/qc-helper/docs/configuration/model-providers.md +8 -8
  2. package/bundled/qc-helper/docs/configuration/settings.md +15 -15
  3. package/bundled/qc-helper/docs/features/code-review.md +2 -0
  4. package/bundled/qc-helper/docs/features/headless.md +31 -0
  5. package/bundled/qc-helper/docs/qwen-serve.md +75 -0
  6. package/bundled/review/SKILL.md +59 -52
  7. package/chunks/{MaxSizedBox-2MWU5JYB.js → MaxSizedBox-A3UYJS6B.js} +8 -7
  8. package/chunks/{StandaloneSessionPicker-B6MI5NTB.js → StandaloneSessionPicker-NGLY26I4.js} +21 -20
  9. package/chunks/{acpAgent-MRPYN6FH.js → acpAgent-V54T2EEL.js} +215 -63
  10. package/chunks/{agent-NAOXNW4I.js → agent-2P53VL2L.js} +8 -7
  11. package/chunks/{agent-headless-L4PPVFKW.js → agent-headless-6X4GCFRD.js} +8 -7
  12. package/chunks/{bridge-LHXGYNCO.js → bridge-TCFMLKHR.js} +12 -10
  13. package/chunks/{channel-settings-store-QB54TLYE.js → channel-settings-store-B4HNMNQV.js} +13 -12
  14. package/chunks/{channel-worker-group-NDG4WOOZ.js → channel-worker-group-SVGPDH2C.js} +3 -2
  15. package/chunks/{channel-worker-manager-ZCW6UW34.js → channel-worker-manager-72ZK2GTS.js} +3 -2
  16. package/chunks/{channel-worker-supervisor-ATGFTZRN.js → channel-worker-supervisor-NUEDVHX4.js} +2 -1
  17. package/chunks/{chunk-UWSXFI6E.js → chunk-2U7GPHA6.js} +6 -2
  18. package/chunks/{chunk-CIUUYB23.js → chunk-3DTM3RPU.js} +1 -1
  19. package/chunks/{chunk-7MFQLOHZ.js → chunk-3PRJYMXC.js} +1 -1
  20. package/chunks/{chunk-K6VEL5KP.js → chunk-3ZRS2XNY.js} +1 -1
  21. package/chunks/{chunk-GBY3ODW7.js → chunk-4E5PO6R7.js} +3 -3
  22. package/chunks/{chunk-KH2BIJ4H.js → chunk-4T6QMNX2.js} +89 -6
  23. package/chunks/{chunk-K64OI7S7.js → chunk-546CDN6D.js} +1 -1
  24. package/chunks/{chunk-J7I2BZHS.js → chunk-5CDI4UOY.js} +23 -6
  25. package/chunks/{chunk-7W5KOBYU.js → chunk-6D6V55ZQ.js} +1 -1
  26. package/chunks/{chunk-WU5NBSLD.js → chunk-6KEN3RIC.js} +3 -3
  27. package/chunks/{chunk-FEUXV3DC.js → chunk-6KZP75GT.js} +1 -1
  28. package/chunks/{chunk-B3EBIZUY.js → chunk-72DZPDH4.js} +1 -1
  29. package/chunks/{chunk-TCOJPG2P.js → chunk-7FUVSN4D.js} +1 -1
  30. package/chunks/{chunk-EXHQZBVJ.js → chunk-AFZTZLFB.js} +2 -2
  31. package/chunks/{chunk-AEWOKOJY.js → chunk-AU3XNTMV.js} +1 -1
  32. package/chunks/{chunk-C6ARWPCG.js → chunk-AVDEBBMI.js} +2 -2
  33. package/chunks/chunk-BKHCW2BI.js +41 -0
  34. package/chunks/{chunk-ZLGPHA34.js → chunk-BU4BRCPX.js} +4 -4
  35. package/chunks/{chunk-3GOCVBYR.js → chunk-C4GRKMUL.js} +4 -4
  36. package/chunks/{chunk-VOA2UPZM.js → chunk-CDHNGCJI.js} +3 -3
  37. package/chunks/{chunk-3H5RFLTS.js → chunk-CJBRIJ7W.js} +1 -1
  38. package/chunks/{chunk-D7QAZ5DF.js → chunk-CXYBX4AL.js} +1 -1
  39. package/chunks/{chunk-GEP54CHX.js → chunk-DBIEZC7T.js} +3 -3
  40. package/chunks/{chunk-BWLUCN35.js → chunk-DG563ZCS.js} +2 -2
  41. package/chunks/{chunk-YLL3SC5S.js → chunk-DOA7MCDY.js} +167 -99
  42. package/chunks/{chunk-OIGB253L.js → chunk-DOICUTPO.js} +7 -7
  43. package/chunks/{chunk-VJPF6GF2.js → chunk-EHMN6SEG.js} +2 -2
  44. package/chunks/{chunk-YO4JI7B4.js → chunk-EKWNNQQD.js} +4 -4
  45. package/chunks/{chunk-B2RBYP7Z.js → chunk-FDV3CXTD.js} +2 -2
  46. package/chunks/{chunk-LMNM37OE.js → chunk-HKNSU4WX.js} +1 -1
  47. package/chunks/{chunk-4LLUH3A7.js → chunk-HU5TUALO.js} +95 -8
  48. package/chunks/{chunk-G2UXFO2B.js → chunk-IISDPZ5X.js} +1 -1
  49. package/chunks/{chunk-LYPXNRBX.js → chunk-IKXE3AAC.js} +1 -1
  50. package/chunks/{chunk-TJ56V3AR.js → chunk-MFBUJMQ3.js} +3 -3
  51. package/chunks/{chunk-SQTA6PAY.js → chunk-MVLM6PJK.js} +1 -1
  52. package/chunks/{chunk-4NEBUDWS.js → chunk-N47ZM2KI.js} +9 -9
  53. package/chunks/{chunk-5HWAJ4BK.js → chunk-NAYPZ72V.js} +1 -1
  54. package/chunks/{chunk-IZ2CMEYO.js → chunk-NKST54XA.js} +1 -1
  55. package/chunks/{chunk-IK3RYLAD.js → chunk-NYZAL2W2.js} +3 -3
  56. package/chunks/{chunk-ZPGMDT4S.js → chunk-O656RSMC.js} +19 -92
  57. package/chunks/{chunk-XD2PNH3K.js → chunk-P7LKADIT.js} +5 -5
  58. package/chunks/{chunk-JDNWIXHJ.js → chunk-PQTK2FVO.js} +3 -3
  59. package/chunks/{chunk-LSYVASZS.js → chunk-QG2ACINA.js} +1 -1
  60. package/chunks/{chunk-IWYXZAGT.js → chunk-QWUYFMAR.js} +24 -24
  61. package/chunks/{chunk-YMUZQ3MQ.js → chunk-RTWF7FF7.js} +3 -3
  62. package/chunks/{chunk-5XNO4AW7.js → chunk-SPUDIAHX.js} +11 -11
  63. package/chunks/{chunk-7M2RLFNX.js → chunk-SQ3ZJOYL.js} +11 -11
  64. package/chunks/{chunk-SJMCYCUQ.js → chunk-T4XY5CT4.js} +4 -4
  65. package/chunks/{chunk-2JBETW4S.js → chunk-TVFC3XF5.js} +5 -5
  66. package/chunks/{chunk-NLQIEY6W.js → chunk-VDLXPEI5.js} +3 -3
  67. package/chunks/{chunk-Q2V4AOQL.js → chunk-WAOLM6SQ.js} +1 -1
  68. package/chunks/{chunk-N3RERU5N.js → chunk-WIPQR44Y.js} +3 -3
  69. package/chunks/{chunk-PDDYAXL2.js → chunk-WIRAPZ62.js} +7 -0
  70. package/chunks/chunk-WOJZWRAZ.js +123 -0
  71. package/chunks/{chunk-SVIEVA3L.js → chunk-WPKIU4PA.js} +28 -3
  72. package/chunks/{chunk-K2ETEWG6.js → chunk-WVRJKSIG.js} +1 -1
  73. package/chunks/{chunk-WTM5QONI.js → chunk-WXS647W5.js} +2 -2
  74. package/chunks/{chunk-4O6HLCOF.js → chunk-X6DV3WKN.js} +1 -1
  75. package/chunks/{chunk-OGAARVN7.js → chunk-XKTCA6BW.js} +3 -3
  76. package/chunks/{chunk-FHPKHXHT.js → chunk-XNZBXQCG.js} +4 -0
  77. package/chunks/{chunk-GP4IMBX5.js → chunk-XOZ2R6XI.js} +529 -259
  78. package/chunks/{chunk-IWGMDSC3.js → chunk-XSGQKR37.js} +4 -4
  79. package/chunks/{chunk-ZLJQIGCH.js → chunk-XZCMQUOF.js} +8 -0
  80. package/chunks/{chunk-P3SLTSNY.js → chunk-Y5HIDFKZ.js} +4 -4
  81. package/chunks/{chunk-RM3F46UT.js → chunk-YUVTZ4UH.js} +6 -6
  82. package/chunks/{chunk-3P4GP4S2.js → chunk-Z5S6KH2B.js} +1 -1
  83. package/chunks/{chunk-4NNR24EP.js → chunk-ZH7G3A4U.js} +3 -3
  84. package/chunks/{chunk-CAX76R46.js → chunk-ZQL73PPE.js} +1 -1
  85. package/chunks/{computer-use-XDOGP2KA.js → computer-use-GTOP2CVH.js} +8 -7
  86. package/chunks/{config-utils-E3ZQTHGM.js → config-utils-LIRO7NSU.js} +2 -2
  87. package/chunks/{contextCommand-N3LQDCYJ.js → contextCommand-K6T6RRF3.js} +10 -9
  88. package/chunks/{core-runtime-STAFP45W.js → core-runtime-D2626QQU.js} +8 -7
  89. package/chunks/{create-sub-session-2B3JENWD.js → create-sub-session-MWUWNBM6.js} +8 -7
  90. package/chunks/{daemon-status-provider-PPAH3ATF.js → daemon-status-provider-2EHRZZVF.js} +16 -14
  91. package/chunks/{daemon-trust-policy-X6XL3MB4.js → daemon-trust-policy-B3EPDJDR.js} +13 -12
  92. package/chunks/{daemon-trust-policy-monitor-M5LBL2HD.js → daemon-trust-policy-monitor-MFM5X26G.js} +13 -12
  93. package/chunks/{deferred-core-runtime-O54YPTBU.js → deferred-core-runtime-KXN7HLN7.js} +8 -7
  94. package/chunks/{earlyInputCapture-CBIT2RGT.js → earlyInputCapture-WUNYYFOS.js} +8 -7
  95. package/chunks/{edit-KW2TOC6A.js → edit-DMFCBP2D.js} +8 -7
  96. package/chunks/{enter-worktree-YL34NEU5.js → enter-worktree-5SVBCXFC.js} +8 -7
  97. package/chunks/{enterPlanMode-JFJTDASQ.js → enterPlanMode-QUIZFQ4M.js} +8 -7
  98. package/chunks/{environment-IATU5GXG.js → environment-U6QP23VJ.js} +10 -9
  99. package/chunks/{errors-SAVRDE7Q.js → errors-GZWFA6ON.js} +10 -9
  100. package/chunks/{exit-worktree-5M43QPBB.js → exit-worktree-FUB44KAF.js} +8 -7
  101. package/chunks/{exitPlanMode-W4EICZ4N.js → exitPlanMode-XSHHYR73.js} +8 -7
  102. package/chunks/external-tool-guard-provider-5HTGOPGU.js +273 -0
  103. package/chunks/{fast-path-YQJPIKMP.js → fast-path-JHQJSIMZ.js} +5 -5
  104. package/chunks/{gemini-FUF5SSPR.js → gemini-O44ETOKT.js} +61 -46
  105. package/chunks/{geminiContentGenerator-LLLZBOUG.js → geminiContentGenerator-TTM4TZJM.js} +1 -1
  106. package/chunks/{glob-LJFFMN4D.js → glob-YECOWTRW.js} +8 -7
  107. package/chunks/{grep-Q64EAM73.js → grep-BZO4LOTA.js} +8 -7
  108. package/chunks/{handleAutoUpdate-QBMPRTSQ.js → handleAutoUpdate-TOO52D6H.js} +12 -11
  109. package/chunks/{i18n-LDUW5DMN.js → i18n-ARJYXZQ5.js} +9 -8
  110. package/chunks/{image-gen-G7RLG3KR.js → image-gen-J6Q2YBEU.js} +1 -1
  111. package/chunks/{initializer-74A7DMMD.js → initializer-CEZ4RPQV.js} +13 -12
  112. package/chunks/{installationInfo-OFDYLDFD.js → installationInfo-AEGIIQAT.js} +9 -8
  113. package/chunks/{list-JA2EWRHJ.js → list-7XLPV5GC.js} +16 -15
  114. package/chunks/{loadedSettingsAdapter-2GNJOQ3L.js → loadedSettingsAdapter-YK5SBHOT.js} +13 -12
  115. package/chunks/{loggingContentGenerator-B6B5EGB3.js → loggingContentGenerator-I7QDXS43.js} +4 -3
  116. package/chunks/{managed-npm-update-4YZHLUER.js → managed-npm-update-YSL7PA7G.js} +9 -8
  117. package/chunks/{mcp-LLK5YJVH.js → mcp-RKFQZXP6.js} +13 -12
  118. package/chunks/{monitor-NYJPAWVP.js → monitor-QHHJIKGL.js} +8 -7
  119. package/chunks/{nonInteractiveCli-HZBBBDJD.js → nonInteractiveCli-XEBIE7MG.js} +41 -39
  120. package/chunks/{notebook-edit-LLM6UXFX.js → notebook-edit-SG7X2EQA.js} +8 -7
  121. package/chunks/{openaiContentGenerator-2AEXDN55.js → openaiContentGenerator-63CVR33K.js} +5 -4
  122. package/chunks/{pidfile-3JUWX7G2.js → pidfile-I3CXJGQD.js} +8 -7
  123. package/chunks/{processUtils-JLLRVZHT.js → processUtils-LJ3DSANX.js} +2 -2
  124. package/chunks/{qwenContentGenerator-2FESCF27.js → qwenContentGenerator-JINBVCH6.js} +9 -8
  125. package/chunks/{qwenOAuth2-2KKPYA5J.js → qwenOAuth2-SY2O3NRR.js} +1 -1
  126. package/chunks/{read-file-5GVXLY74.js → read-file-PGTXF25I.js} +3 -2
  127. package/chunks/{record-artifact-L3BAHQFN.js → record-artifact-E6AWQU2Z.js} +1 -1
  128. package/chunks/{resumeHistoryUtils-Z4OFBXPM.js → resumeHistoryUtils-FB2NFVZ2.js} +11 -10
  129. package/chunks/{ripGrep-TKOJTIAB.js → ripGrep-IY3KGPM6.js} +8 -7
  130. package/chunks/{run-qwen-serve-K5W6MM6M.js → run-qwen-serve-UYEMGPKA.js} +72 -36
  131. package/chunks/{runtime-IADXMRCY.js → runtime-CG3BKRFE.js} +16 -15
  132. package/chunks/{scheduler-T7AV37LD.js → scheduler-VFUVGDE5.js} +8 -7
  133. package/chunks/{serve-ROEGMS3I.js → serve-ZCCQ2G2L.js} +14 -12
  134. package/chunks/{server-NGXMRODI.js → server-WS7LWXPP.js} +161 -54
  135. package/chunks/{session-RCDLDJA4.js → session-IQLCT32T.js} +42 -40
  136. package/chunks/{settings-E6H3AURD.js → settings-NX4EUIE6.js} +12 -11
  137. package/chunks/{shell-RHGGJ6BE.js → shell-THDYM4CS.js} +8 -7
  138. package/chunks/{skill-GQ7PBS25.js → skill-OXXZBNQB.js} +3 -2
  139. package/chunks/{skill-settings-E2F7OCBL.js → skill-settings-T3JZ33T2.js} +12 -11
  140. package/chunks/{spawnChannel-Q2IQBHME.js → spawnChannel-COLJMSA7.js} +11 -9
  141. package/chunks/{standalone-update-NYYZEHLD.js → standalone-update-ICW7H5IF.js} +10 -9
  142. package/chunks/{startInteractiveUI-IX6I3Y2Z.js → startInteractiveUI-6BDRXSMF.js} +60 -58
  143. package/chunks/{team-create-UTRVUEDA.js → team-create-BCSMDK4Z.js} +8 -7
  144. package/chunks/{team-plan-approval-YZNB4U5U.js → team-plan-approval-B5YRLJFV.js} +8 -7
  145. package/chunks/{terminal-image-renderer-QRSCS2BE.js → terminal-image-renderer-PW6Z6VFY.js} +8 -7
  146. package/chunks/{theme-manager-EKZBY34I.js → theme-manager-CMVKD2JH.js} +8 -7
  147. package/chunks/{tool-search-N2R7LVMC.js → tool-search-SQTUSG6P.js} +3 -2
  148. package/chunks/{total-session-admission-HBIYARPO.js → total-session-admission-XAXOSE46.js} +12 -10
  149. package/chunks/{trustedFolders-ZQLYRCSY.js → trustedFolders-Z2UAEG2V.js} +9 -8
  150. package/chunks/{update-relaunch-PJWXMPCR.js → update-relaunch-JBLI6LJF.js} +5 -5
  151. package/chunks/{updateCheck-ZXRCGY66.js → updateCheck-FDAVGOFT.js} +11 -10
  152. package/chunks/{useAutoAcceptIndicator-ZYQW5SGJ.js → useAutoAcceptIndicator-PDZFIYRM.js} +14 -13
  153. package/chunks/{validateNonInterActiveAuth-M7J7OTRH.js → validateNonInterActiveAuth-Q4763ONQ.js} +38 -36
  154. package/chunks/{version-2AOHMPK3.js → version-C7MPCGWD.js} +1 -1
  155. package/chunks/{web-fetch-DS34CJ3R.js → web-fetch-L7RAPOJB.js} +3 -2
  156. package/chunks/{web-search-ITFPD7V4.js → web-search-IDOYUOWX.js} +4 -3
  157. package/chunks/{workflow-LZQ4PGNS.js → workflow-HXURUJB5.js} +9 -8
  158. package/chunks/{workspace-providers-status-ZPTLKOBM.js → workspace-providers-status-JZ3GPWNU.js} +16 -15
  159. package/chunks/{workspace-registration-store-OTFKSGG7.js → workspace-registration-store-SM2PWB6L.js} +1 -1
  160. package/chunks/{workspace-registry-YZ3OXPHP.js → workspace-registry-6W4ES7BJ.js} +12 -10
  161. package/chunks/{workspace-service-OCZXOOSQ.js → workspace-service-V47ZFJRX.js} +17 -16
  162. package/chunks/{workspace-skills-status-K2ALGUCD.js → workspace-skills-status-6ZQ45XKA.js} +14 -13
  163. package/chunks/{workspace-trust-reconciler-KMRZISJP.js → workspace-trust-reconciler-6V25LMCN.js} +17 -15
  164. package/chunks/{write-file-AWBI4GJS.js → write-file-H2QOF25K.js} +8 -7
  165. package/chunks/{zoom-image-NHKN6F77.js → zoom-image-JTUSS43N.js} +3 -2
  166. package/cli-entry.js +14 -0
  167. package/cli.js +16 -12
  168. package/package.json +3 -3
  169. package/web-shell/assets/{arc-Dpg66jw7.js → arc-DtI1rZcQ.js} +1 -1
  170. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BJ4FIBxN.js → architectureDiagram-3BPJPVTR-BPZwSVct.js} +1 -1
  171. package/web-shell/assets/{blockDiagram-GPEHLZMM-VXmYdtYT.js → blockDiagram-GPEHLZMM-BIQ03j4C.js} +1 -1
  172. package/web-shell/assets/{c4Diagram-AAUBKEIU-BNLDb8FE.js → c4Diagram-AAUBKEIU-CB0RyFGm.js} +1 -1
  173. package/web-shell/assets/channel-vfbVFuM1.js +1 -0
  174. package/web-shell/assets/{chunk-2J33WTMH-DR5yHxr0.js → chunk-2J33WTMH-B3WoS-4H.js} +1 -1
  175. package/web-shell/assets/{chunk-4BX2VUAB-Czkq8UZU.js → chunk-4BX2VUAB-C98xYZ1X.js} +1 -1
  176. package/web-shell/assets/{chunk-55IACEB6-DugUgM6s.js → chunk-55IACEB6-CbTIWRwQ.js} +1 -1
  177. package/web-shell/assets/{chunk-727SXJPM-Dw6quA1K.js → chunk-727SXJPM-DWGnKTPu.js} +1 -1
  178. package/web-shell/assets/{chunk-AQP2D5EJ-BoVYOTTz.js → chunk-AQP2D5EJ-4__QyCEX.js} +1 -1
  179. package/web-shell/assets/{chunk-FMBD7UC4--Amcse-j.js → chunk-FMBD7UC4-DFtG1YCW.js} +1 -1
  180. package/web-shell/assets/{chunk-ND2GUHAM-ajaEYAC8.js → chunk-ND2GUHAM-rvAhW51N.js} +1 -1
  181. package/web-shell/assets/{chunk-QZHKN3VN-CUNDZ7im.js → chunk-QZHKN3VN-DfiU9pwZ.js} +1 -1
  182. package/web-shell/assets/classDiagram-4FO5ZUOK-Cvr8atq3.js +1 -0
  183. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvr8atq3.js +1 -0
  184. package/web-shell/assets/{cose-bilkent-S5V4N54A-BnfkD-m1.js → cose-bilkent-S5V4N54A-Cc4EIdxu.js} +1 -1
  185. package/web-shell/assets/{dagre-BM42HDAG-BuUdFk7Z.js → dagre-BM42HDAG-CZNj4dGW.js} +1 -1
  186. package/web-shell/assets/{diagram-2AECGRRQ-B2ZXxoab.js → diagram-2AECGRRQ-D5tiqQCr.js} +1 -1
  187. package/web-shell/assets/{diagram-5GNKFQAL-BsgOICzM.js → diagram-5GNKFQAL-pwzw0jVO.js} +1 -1
  188. package/web-shell/assets/{diagram-KO2AKTUF-DTTjG6U-.js → diagram-KO2AKTUF-4CWiM00x.js} +1 -1
  189. package/web-shell/assets/{diagram-LMA3HP47-temLf1x7.js → diagram-LMA3HP47-Dd7rc7Qf.js} +1 -1
  190. package/web-shell/assets/{diagram-OG6HWLK6-CRFjScs2.js → diagram-OG6HWLK6-_vzV52ml.js} +1 -1
  191. package/web-shell/assets/{erDiagram-TEJ5UH35-D4oaY-rQ.js → erDiagram-TEJ5UH35-CqbE2bx_.js} +1 -1
  192. package/web-shell/assets/{flowDiagram-I6XJVG4X-BqG8B49b.js → flowDiagram-I6XJVG4X-CaxNr7w4.js} +1 -1
  193. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DffQBdd5.js → ganttDiagram-6RSMTGT7-AGjrtfUA.js} +1 -1
  194. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CMDPfseF.js → gitGraphDiagram-PVQCEYII-ADG2zSkc.js} +1 -1
  195. package/web-shell/assets/{index-qTQR_smP.js → index-BOryKCqt.js} +1 -1
  196. package/web-shell/assets/{index-CaucmEO_.css → index-Cb1LjsCv.css} +1 -1
  197. package/web-shell/assets/{index-2F4RsNzd.js → index-CvJDaIy8.js} +311 -311
  198. package/web-shell/assets/{infoDiagram-5YYISTIA-Cn3T83MA.js → infoDiagram-5YYISTIA-CE3B_IoZ.js} +1 -1
  199. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-ijFs7e25.js → ishikawaDiagram-YF4QCWOH-CN-Frhoi.js} +1 -1
  200. package/web-shell/assets/{journeyDiagram-JHISSGLW-CINTv8VB.js → journeyDiagram-JHISSGLW-CGgezS93.js} +1 -1
  201. package/web-shell/assets/{kanban-definition-UN3LZRKU-CMGRZCxx.js → kanban-definition-UN3LZRKU-BqWijky5.js} +1 -1
  202. package/web-shell/assets/{linear-Co-2_37d.js → linear-D8sfpZf6.js} +1 -1
  203. package/web-shell/assets/{mermaid.core-DijbyaN5.js → mermaid.core-3PA4QrzM.js} +5 -5
  204. package/web-shell/assets/{mindmap-definition-RKZ34NQL-k_sDYDPZ.js → mindmap-definition-RKZ34NQL-D9QxwiCY.js} +1 -1
  205. package/web-shell/assets/{pieDiagram-4H26LBE5-CG-oz8V3.js → pieDiagram-4H26LBE5-Bioaf6uE.js} +1 -1
  206. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Baq7HIG2.js → quadrantDiagram-W4KKPZXB-DBb2AS73.js} +1 -1
  207. package/web-shell/assets/{requirementDiagram-4Y6WPE33-CDM3ZvBt.js → requirementDiagram-4Y6WPE33-DXOvZ3KB.js} +1 -1
  208. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-C2dJbWKN.js → sankeyDiagram-5OEKKPKP-D9qg09Dm.js} +1 -1
  209. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-Cf1_h59p.js → sequenceDiagram-3UESZ5HK-DSAUIfpw.js} +1 -1
  210. package/web-shell/assets/{stateDiagram-AJRCARHV-CI5clUEc.js → stateDiagram-AJRCARHV-BPZkzfQ3.js} +1 -1
  211. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DInOqnhZ.js +1 -0
  212. package/web-shell/assets/{timeline-definition-PNZ67QCA-B2O8cAZX.js → timeline-definition-PNZ67QCA-UDaQp9sP.js} +1 -1
  213. package/web-shell/assets/{vennDiagram-CIIHVFJN-BLsJ_h9s.js → vennDiagram-CIIHVFJN-2ouhAnHO.js} +1 -1
  214. package/web-shell/assets/{wardley-L42UT6IY-BlPU4FTA.js → wardley-L42UT6IY-Cq_WEvTK.js} +1 -1
  215. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-D_U-RdU4.js → wardleyDiagram-YWT4CUSO-Dt24aXOM.js} +1 -1
  216. package/web-shell/assets/{xychartDiagram-2RQKCTM6-BynXGSTl.js → xychartDiagram-2RQKCTM6-A5Xk2WCH.js} +1 -1
  217. package/web-shell/index.html +2 -2
  218. package/bundled/review/DESIGN.md +0 -724
  219. package/web-shell/assets/channel-Bd9wOnaA.js +0 -1
  220. package/web-shell/assets/classDiagram-4FO5ZUOK-XhCT8FE3.js +0 -1
  221. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-XhCT8FE3.js +0 -1
  222. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BDc8asKD.js +0 -1
  223. package/chunks/{channel-management-service-UHX56NBO.js → channel-management-service-5XPPTWUQ.js} +3 -3
  224. package/chunks/{chunk-LEZFUYPM.js → chunk-7GYP5COR.js} +3 -3
@@ -2,13 +2,13 @@
2
2
  "use strict";
3
3
  import {
4
4
  serveCommand
5
- } from "./chunk-SVIEVA3L.js";
5
+ } from "./chunk-WPKIU4PA.js";
6
6
  import {
7
7
  listCommand
8
- } from "./chunk-ZLGPHA34.js";
8
+ } from "./chunk-BU4BRCPX.js";
9
9
  import {
10
10
  getErrorMessage as getErrorMessage2
11
- } from "./chunk-VJPF6GF2.js";
11
+ } from "./chunk-EHMN6SEG.js";
12
12
  import {
13
13
  ObservedChannelContactStore
14
14
  } from "./chunk-DYA25Y7U.js";
@@ -46,22 +46,22 @@ import {
46
46
  registerToolCallDispatch,
47
47
  selectFirstModel,
48
48
  sessionsPath
49
- } from "./chunk-VOA2UPZM.js";
49
+ } from "./chunk-CDHNGCJI.js";
50
50
  import {
51
51
  getExtensionManager,
52
52
  requestChoicePluginNonInteractive,
53
53
  requestConsentNonInteractive,
54
54
  requestConsentOrFail,
55
55
  resolveExtensionCommandScope
56
- } from "./chunk-3GOCVBYR.js";
56
+ } from "./chunk-C4GRKMUL.js";
57
57
  import {
58
58
  collectProviderModelsForProtocol,
59
59
  getAuthTypeFromEnv,
60
60
  resolveCliGenerationConfig
61
- } from "./chunk-WU5NBSLD.js";
61
+ } from "./chunk-6KEN3RIC.js";
62
62
  import {
63
63
  parseChannelConfig
64
- } from "./chunk-LEZFUYPM.js";
64
+ } from "./chunk-7GYP5COR.js";
65
65
  import {
66
66
  findCliEntryPath
67
67
  } from "./chunk-V6WHFGST.js";
@@ -96,6 +96,9 @@ import {
96
96
  import {
97
97
  normalizeServeChannelSelection
98
98
  } from "./chunk-ALMR3E6Q.js";
99
+ import {
100
+ EXTERNAL_TOOL_GUARD_TOKEN_ENV
101
+ } from "./chunk-BKHCW2BI.js";
99
102
  import {
100
103
  redactLogCredentials
101
104
  } from "./chunk-M5GB774H.js";
@@ -128,29 +131,29 @@ import {
128
131
  assembleMcpServers,
129
132
  getPendingGatedMcpServers,
130
133
  mcpCommand
131
- } from "./chunk-SJMCYCUQ.js";
134
+ } from "./chunk-T4XY5CT4.js";
132
135
  import {
133
136
  loadSettings
134
- } from "./chunk-RM3F46UT.js";
137
+ } from "./chunk-YUVTZ4UH.js";
135
138
  import {
136
139
  detectSystemLanguage,
137
140
  getCurrentLanguage,
138
141
  initializeI18n,
139
142
  resolveLanguageSetting,
140
143
  t
141
- } from "./chunk-K64OI7S7.js";
144
+ } from "./chunk-546CDN6D.js";
142
145
  import {
143
146
  loadEnvironment
144
- } from "./chunk-LYPXNRBX.js";
147
+ } from "./chunk-IKXE3AAC.js";
145
148
  import {
146
149
  getCliVersion
147
- } from "./chunk-IZ2CMEYO.js";
150
+ } from "./chunk-NKST54XA.js";
148
151
  import {
149
152
  getPackageJson
150
153
  } from "./chunk-VJNBRRZG.js";
151
154
  import {
152
155
  isWorkspaceTrusted
153
- } from "./chunk-B3EBIZUY.js";
156
+ } from "./chunk-72DZPDH4.js";
154
157
  import {
155
158
  require_strip_json_comments
156
159
  } from "./chunk-ALGGS7UH.js";
@@ -191,7 +194,7 @@ import {
191
194
  unquoteCStylePath,
192
195
  updateChannelMemoryEntry,
193
196
  updateSetting
194
- } from "./chunk-YLL3SC5S.js";
197
+ } from "./chunk-DOA7MCDY.js";
195
198
  import {
196
199
  nextFireTime,
197
200
  parseCron
@@ -206,14 +209,14 @@ import {
206
209
  import {
207
210
  getAllGeminiMdFilenames,
208
211
  setGeminiMdFilename
209
- } from "./chunk-ZPGMDT4S.js";
212
+ } from "./chunk-O656RSMC.js";
210
213
  import {
211
214
  SchemaValidator,
212
215
  ToolNames
213
216
  } from "./chunk-D7D7RXIJ.js";
214
217
  import {
215
218
  DEFAULT_QWEN_EMBEDDING_MODEL
216
- } from "./chunk-XD2PNH3K.js";
219
+ } from "./chunk-P7LKADIT.js";
217
220
  import {
218
221
  isTlsVerificationDisabled
219
222
  } from "./chunk-BFHXDAR7.js";
@@ -3585,6 +3588,7 @@ function scrubDaemonWorkerEnv() {
3585
3588
  delete process.env[QWEN_DAEMON_URL_ENV];
3586
3589
  delete process.env[QWEN_DAEMON_WORKSPACE_ENV];
3587
3590
  delete process.env[QWEN_SERVER_TOKEN_ENV];
3591
+ delete process.env[EXTERNAL_TOOL_GUARD_TOKEN_ENV];
3588
3592
  }
3589
3593
  __name(scrubDaemonWorkerEnv, "scrubDaemonWorkerEnv");
3590
3594
  function readDaemonWorkerEnv() {
@@ -4547,12 +4551,12 @@ var parseArgsCommand = {
4547
4551
 
4548
4552
  // packages/cli/src/commands/review/compose-review.ts
4549
4553
  init_esbuild_shims();
4550
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
4551
- import { dirname as dirname4, join as join8 } from "node:path";
4554
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
4555
+ import { dirname as dirname4, join as join9 } from "node:path";
4552
4556
 
4553
4557
  // packages/cli/src/commands/review/lib/coverage.ts
4554
4558
  init_esbuild_shims();
4555
- import { readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
4559
+ import { readFileSync as readFileSync8, statSync as statSync3 } from "node:fs";
4556
4560
 
4557
4561
  // packages/cli/src/commands/review/lib/transcripts.ts
4558
4562
  init_esbuild_shims();
@@ -6186,6 +6190,150 @@ If you find no new gap in your scope, say so **and name what you re-examined** \
6186
6190
  }
6187
6191
  };
6188
6192
 
6193
+ // packages/cli/src/commands/review/lib/deadline.ts
6194
+ init_esbuild_shims();
6195
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, statSync as statSync2, writeFileSync as writeFileSync5 } from "node:fs";
6196
+ import { join as join8 } from "node:path";
6197
+ var DEADLINE_ENV = "QWEN_REVIEW_DEADLINE_EPOCH";
6198
+ var RESERVE_ENV = "QWEN_REVIEW_DEADLINE_RESERVE_SECONDS";
6199
+ var DEFAULT_RESERVE_SECONDS = 3600;
6200
+ var DEFAULT_ROUND_SECONDS = 1800;
6201
+ var MIN_OBSERVED_ROUND_SECONDS = 600;
6202
+ var STAMPS_FILE = "budget-rounds.json";
6203
+ var STOP_FILE = "budget-stop.json";
6204
+ var RUN_EPOCH_SLACK_MS = 2e3;
6205
+ function runEpochMs(planPath) {
6206
+ try {
6207
+ return statSync2(planPath).mtimeMs - RUN_EPOCH_SLACK_MS;
6208
+ } catch {
6209
+ return Number.NEGATIVE_INFINITY;
6210
+ }
6211
+ }
6212
+ __name(runEpochMs, "runEpochMs");
6213
+ function readRoundStamps(planPath) {
6214
+ try {
6215
+ const raw = readFileSync7(
6216
+ join8(promptRecordDir(planPath), STAMPS_FILE),
6217
+ "utf8"
6218
+ );
6219
+ const parsed = JSON.parse(raw);
6220
+ if (!Array.isArray(parsed)) return [];
6221
+ const epoch = runEpochMs(planPath);
6222
+ return parsed.filter(
6223
+ (e) => typeof e === "object" && e !== null && typeof e.atMs === "number" && e.atMs >= epoch
6224
+ );
6225
+ } catch {
6226
+ return [];
6227
+ }
6228
+ }
6229
+ __name(readRoundStamps, "readRoundStamps");
6230
+ function stampRound(planPath, round, nowMs = Date.now()) {
6231
+ try {
6232
+ const stamps = readRoundStamps(planPath);
6233
+ if (round !== void 0 && stamps.some((s) => s.round === round)) return;
6234
+ stamps.push({ round: round ?? null, atMs: nowMs });
6235
+ const dir = promptRecordDir(planPath);
6236
+ mkdirSync5(dir, { recursive: true });
6237
+ writeFileSync5(join8(dir, STAMPS_FILE), JSON.stringify(stamps));
6238
+ } catch {
6239
+ }
6240
+ }
6241
+ __name(stampRound, "stampRound");
6242
+ 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);
6249
+ }
6250
+ return DEFAULT_ROUND_SECONDS;
6251
+ }
6252
+ __name(expectedRoundSeconds, "expectedRoundSeconds");
6253
+ function reverseAuditBudgetExhausted(env, roundCostSeconds, nowMs = Date.now()) {
6254
+ const raw = env[DEADLINE_ENV];
6255
+ if (raw === void 0 || raw.trim() === "") return null;
6256
+ const deadline = Number(raw);
6257
+ if (!Number.isFinite(deadline) || deadline <= 0) return null;
6258
+ let reserve = DEFAULT_RESERVE_SECONDS;
6259
+ const reserveRaw = env[RESERVE_ENV];
6260
+ if (reserveRaw !== void 0 && reserveRaw.trim() !== "") {
6261
+ const r = Number(reserveRaw);
6262
+ if (Number.isFinite(r) && r >= 0) reserve = r;
6263
+ }
6264
+ const remainingSeconds = Math.floor(deadline - nowMs / 1e3);
6265
+ if (remainingSeconds >= reserve + roundCostSeconds) return null;
6266
+ return {
6267
+ remainingSeconds,
6268
+ reserveSeconds: reserve,
6269
+ expectedRoundSeconds: roundCostSeconds
6270
+ };
6271
+ }
6272
+ __name(reverseAuditBudgetExhausted, "reverseAuditBudgetExhausted");
6273
+ var BUDGET_STOP_PHRASE = "review time budget";
6274
+ function budgetStopDisclosure(round) {
6275
+ const which = round !== void 0 ? `round ${round}` : "the next round";
6276
+ const whichZh = round !== void 0 ? `\u7B2C ${round} \u8F6E` : "\u4E0B\u4E00\u8F6E";
6277
+ return {
6278
+ subject: "reverse audit",
6279
+ reason: `stopped before ${which} by the ${BUDGET_STOP_PHRASE}`,
6280
+ subjectZh: "\u53CD\u5411\u5BA1\u8BA1",
6281
+ reasonZh: `\u8BC4\u5BA1\u65F6\u95F4\u9884\u7B97\u4E0D\u8DB3\uFF0C\u672A\u80FD\u5F00\u59CB${whichZh}`
6282
+ };
6283
+ }
6284
+ __name(budgetStopDisclosure, "budgetStopDisclosure");
6285
+ function budgetStopEntry(round) {
6286
+ const d = budgetStopDisclosure(round);
6287
+ return `${d.subject} \u2014 ${d.reason}`;
6288
+ }
6289
+ __name(budgetStopEntry, "budgetStopEntry");
6290
+ function budgetStopEntryZh(round) {
6291
+ const d = budgetStopDisclosure(round);
6292
+ return `${d.subjectZh}\u2014\u2014${d.reasonZh}`;
6293
+ }
6294
+ __name(budgetStopEntryZh, "budgetStopEntryZh");
6295
+ function writeBudgetStop(planPath, spent, round, nowMs = Date.now()) {
6296
+ try {
6297
+ const dir = promptRecordDir(planPath);
6298
+ mkdirSync5(dir, { recursive: true });
6299
+ const stop = {
6300
+ entry: budgetStopEntry(round),
6301
+ entryZh: budgetStopEntryZh(round),
6302
+ round: round ?? null,
6303
+ remainingSeconds: spent.remainingSeconds,
6304
+ reserveSeconds: spent.reserveSeconds,
6305
+ atMs: nowMs
6306
+ };
6307
+ writeFileSync5(join8(dir, STOP_FILE), JSON.stringify(stop, null, 2));
6308
+ } catch {
6309
+ }
6310
+ }
6311
+ __name(writeBudgetStop, "writeBudgetStop");
6312
+ function readBudgetStop(planPath) {
6313
+ try {
6314
+ const raw = readFileSync7(
6315
+ join8(promptRecordDir(planPath), STOP_FILE),
6316
+ "utf8"
6317
+ );
6318
+ const parsed = JSON.parse(raw);
6319
+ if (typeof parsed !== "object" || parsed === null || typeof parsed.entry !== "string" || typeof parsed.atMs !== "number" || parsed.atMs < runEpochMs(planPath)) {
6320
+ return null;
6321
+ }
6322
+ return parsed;
6323
+ } catch {
6324
+ return null;
6325
+ }
6326
+ }
6327
+ __name(readBudgetStop, "readBudgetStop");
6328
+ function reverseAuditBudgetMessage(spent, round) {
6329
+ const minutesLeft = Math.max(0, Math.floor(spent.remainingSeconds / 60));
6330
+ const reserveMinutes = Math.round(spent.reserveSeconds / 60);
6331
+ const roundMinutes = Math.round(spent.expectedRoundSeconds / 60);
6332
+ const which = round !== void 0 ? `round ${round}` : "the next round";
6333
+ return `BUDGET: ${minutesLeft} minute(s) remain before this review's deadline \u2014 not enough for the ~${roundMinutes}-minute round being asked for plus the ${reserveMinutes}-minute reserve kept for its verification, compose-review and submission \u2014 so no further reverse-audit round will be built. This is the loop's termination rule, not an error: do not rebuild ${which} and do not relaunch auditors. A budget-stop marker has been recorded and compose-review will disclose it and cap the verdict itself; also add exactly this entry to unreviewedDimensions so the terminal report says it too \u2014 \`${budgetStopEntry(round)}\` \u2014 and proceed to Step 6 with the findings already confirmed. Spend what time remains only on verifying findings already in hand, composing, and submitting. A review that stops here still reports everything it proved; a review that runs past its deadline is killed holding all of it.`;
6334
+ }
6335
+ __name(reverseAuditBudgetMessage, "reverseAuditBudgetMessage");
6336
+
6189
6337
  // packages/cli/src/commands/review/lib/shell-quote.ts
6190
6338
  init_esbuild_shims();
6191
6339
  function shellQuotePath(p) {
@@ -6195,7 +6343,7 @@ __name(shellQuotePath, "shellQuotePath");
6195
6343
 
6196
6344
  // packages/cli/src/commands/review/lib/coverage.ts
6197
6345
  function readPlan(path3) {
6198
- const plan = JSON.parse(readFileSync7(path3, "utf8"));
6346
+ const plan = JSON.parse(readFileSync8(path3, "utf8"));
6199
6347
  if (typeof plan?.diffPathAbsolute !== "string" || !plan.diffPathAbsolute) {
6200
6348
  throw new Error(`coverage: ${path3} has no diffPathAbsolute`);
6201
6349
  }
@@ -6206,7 +6354,7 @@ function readPlan(path3) {
6206
6354
  if (problem) {
6207
6355
  throw new Error(`coverage: ${path3} has ${problem}`);
6208
6356
  }
6209
- return { plan, mtimeMs: statSync2(path3).mtimeMs };
6357
+ return { plan, mtimeMs: statSync3(path3).mtimeMs };
6210
6358
  }
6211
6359
  __name(readPlan, "readPlan");
6212
6360
  var CHUNK_RE = /\bchunk\s+(\d+)\s+of\s+\d+\b/i;
@@ -6552,7 +6700,13 @@ function coverageFromTranscripts(planPath, env = process.env) {
6552
6700
  };
6553
6701
  }
6554
6702
  __name(coverageFromTranscripts, "coverageFromTranscripts");
6555
- var rebuildFix = /* @__PURE__ */ __name((role, noun) => `build the prompt with \`"\${QWEN_CODE_CLI:-qwen}" review agent-prompt --plan <plan> --role ${role} --findings <file> [--rules <rules file>] [--round <k>]\` ` + (role === "reverse-audit" ? `(an early round with nothing confirmed passes an empty file; ` : `(pass the shard's findings, never an empty file \u2014 a verifier that sees no findings verifies nothing; `) + `pass --rules whenever the review loaded any, or the rebuilt brief silently drops the project rules) and launch an agent with EXACTLY what it prints \u2014 no hand-added ${noun} number` + // --round bakes in a ROUND number. Verify's noun is "shard", and a
6703
+ var rebuildFix = /* @__PURE__ */ __name((role, noun) => `build the prompt with \`"\${QWEN_CODE_CLI:-qwen}" review agent-prompt --plan <plan> --role ${role} --findings <file> [--rules <rules file>] ` + // --round is MANDATORY for a reverse-audit build (`agent-prompt` refuses a
6704
+ // round-less call — the label keys the record and the budget gate's
6705
+ // accounting), so the paste-and-run repair must not bracket it as optional:
6706
+ // an orchestrator honouring the bracket convention would have its first
6707
+ // repair attempt rejected. Verify genuinely takes it or not (only a repeat
6708
+ // verification round passes one), so its brackets stay.
6709
+ (role === "reverse-audit" ? `--round <k>\` ` : `[--round <k>]\` `) + (role === "reverse-audit" ? `(an early round with nothing confirmed passes an empty file; ` : `(pass the shard's findings, never an empty file \u2014 a verifier that sees no findings verifies nothing; `) + `pass --rules whenever the review loaded any, or the rebuilt brief silently drops the project rules) and launch an agent with EXACTLY what it prints \u2014 no hand-added ${noun} number` + // --round bakes in a ROUND number. Verify's noun is "shard", and a
6556
6710
  // parenthetical claiming --round bakes it in would send the reader to the
6557
6711
  // wrong flag — shards are already told apart by their findings digest.
6558
6712
  (role === "reverse-audit" ? ` (--round bakes it in)` : ``) + `, no summary of your own, no rewording`, "rebuildFix");
@@ -6667,7 +6821,9 @@ function verificationGaps(planPath, opts, env = process.env) {
6667
6821
  (k) => k === "reverse-audit" || k.startsWith("reverse-audit--")
6668
6822
  );
6669
6823
  const reverse = bestDelivery(reverseKeys);
6670
- const reverseGap = !balancedMedium && reverse !== "ok";
6824
+ const budgetStopped = readBudgetStop(planPath) !== null;
6825
+ const reverseByDesign = budgetStopped && reverse === "not-built";
6826
+ const reverseGap = !balancedMedium && !reverseByDesign && reverse !== "ok";
6671
6827
  if (reverseGap) {
6672
6828
  remediation.push(
6673
6829
  `reverse audit: ${REVERSE_AUDIT_GAP[reverse].fix.replace(
@@ -6970,6 +7126,24 @@ function unmarkedComments(comments) {
6970
7126
  }
6971
7127
  __name(unmarkedComments, "unmarkedComments");
6972
7128
 
7129
+ // packages/cli/src/commands/review/lib/review-footer.ts
7130
+ init_esbuild_shims();
7131
+ var FOOTER_MARKER = "via Qwen Code /review";
7132
+ function reviewFooter(modelId, cliVersion) {
7133
+ return `_\u2014 ${modelId} ${FOOTER_MARKER} (v${cliVersion})_`;
7134
+ }
7135
+ __name(reviewFooter, "reviewFooter");
7136
+ var REVIEW_FOOTER_RE = /\s*(?:_— (?:(?! via Qwen Code \/review)[^\n])* via Qwen Code \/review(?: \(v[^\n)]*\))?_?\s*)+$/;
7137
+ function isFooterSafeModelId(modelId) {
7138
+ return !/[\n\r]/.test(modelId) && !modelId.includes(FOOTER_MARKER);
7139
+ }
7140
+ __name(isFooterSafeModelId, "isFooterSafeModelId");
7141
+ var FOOTER_VERSION_RE = /^[A-Za-z0-9._+-]+$/;
7142
+ function footerVersion(stamp) {
7143
+ return stamp !== void 0 && FOOTER_VERSION_RE.test(stamp) ? stamp : void 0;
7144
+ }
7145
+ __name(footerVersion, "footerVersion");
7146
+
6973
7147
  // packages/cli/src/commands/review/compose-review.ts
6974
7148
  var LOW_SIGNAL_SRC_DIFF_LINES = 100;
6975
7149
  function withMarker(line) {
@@ -6996,6 +7170,10 @@ function toStringList(value, field) {
6996
7170
  return [...value];
6997
7171
  }
6998
7172
  __name(toStringList, "toStringList");
7173
+ function stripReviewFooter(entry) {
7174
+ return entry.replace(REVIEW_FOOTER_RE, "");
7175
+ }
7176
+ __name(stripReviewFooter, "stripReviewFooter");
6999
7177
  function toBool(value, field) {
7000
7178
  if (value === void 0 || value === null) return false;
7001
7179
  if (typeof value !== "boolean") {
@@ -7017,15 +7195,15 @@ __name(composeReview, "composeReview");
7017
7195
  function ledgerMarkerFor(input) {
7018
7196
  try {
7019
7197
  if (!input.planPath) return null;
7020
- const plan = JSON.parse(readFileSync8(input.planPath, "utf8"));
7198
+ const plan = JSON.parse(readFileSync9(input.planPath, "utf8"));
7021
7199
  const pr = plan?.prNumber;
7022
7200
  const isPr = typeof pr === "number" && Number.isInteger(pr) && pr > 0 || typeof pr === "string" && /^\d+$/.test(pr);
7023
7201
  if (!isPr) return null;
7024
7202
  let prevRound = 0;
7025
7203
  try {
7026
7204
  const prev = JSON.parse(
7027
- readFileSync8(
7028
- join8(
7205
+ readFileSync9(
7206
+ join9(
7029
7207
  dirname4(input.planPath),
7030
7208
  `qwen-review-pr-${pr}-prev-ledger.json`
7031
7209
  ),
@@ -7040,7 +7218,7 @@ function ledgerMarkerFor(input) {
7040
7218
  buildLedger(
7041
7219
  prevRound + 1,
7042
7220
  input.draftedComments ?? [],
7043
- toStringList(input.bodyCriticals, "bodyCriticals")
7221
+ toStringList(input.bodyCriticals, "bodyCriticals").map(stripReviewFooter).filter((entry) => entry.trim() !== "")
7044
7222
  )
7045
7223
  );
7046
7224
  } catch {
@@ -7054,7 +7232,7 @@ function composeReviewBody(input, cliVersion) {
7054
7232
  input.suggestionsInline,
7055
7233
  "suggestionsInline"
7056
7234
  );
7057
- const bodyCriticals = toStringList(input.bodyCriticals, "bodyCriticals");
7235
+ const bodyCriticals = toStringList(input.bodyCriticals, "bodyCriticals").map(stripReviewFooter).filter((entry) => entry.trim() !== "");
7058
7236
  const suggestionsDiscarded = toCount(
7059
7237
  input.suggestionsDiscarded,
7060
7238
  "suggestionsDiscarded"
@@ -7062,7 +7240,7 @@ function composeReviewBody(input, cliVersion) {
7062
7240
  const cannotTell = toStringList(
7063
7241
  input.cannotTellCriticals,
7064
7242
  "cannotTellCriticals"
7065
- );
7243
+ ).map(stripReviewFooter).filter((entry) => entry.trim() !== "");
7066
7244
  const uncoverable = toStringList(
7067
7245
  input.uncoverableChunks,
7068
7246
  "uncoverableChunks"
@@ -7072,6 +7250,19 @@ function composeReviewBody(input, cliVersion) {
7072
7250
  "unreviewedDimensions"
7073
7251
  );
7074
7252
  const coverageEntries = [];
7253
+ let budgetEntry;
7254
+ if (input.planPath) {
7255
+ const stop = readBudgetStop(input.planPath);
7256
+ if (stop !== null) {
7257
+ for (let i = unreviewed.length - 1; i >= 0; i--) {
7258
+ if (unreviewed[i].includes(BUDGET_STOP_PHRASE)) {
7259
+ unreviewed.splice(i, 1);
7260
+ }
7261
+ }
7262
+ budgetEntry = budgetStopDisclosure(stop.round ?? void 0);
7263
+ coverageEntries.push(budgetEntry);
7264
+ }
7265
+ }
7075
7266
  const remediation = [];
7076
7267
  const planRef = input.planPath ? shellQuotePath(input.planPath) : "<plan>";
7077
7268
  const missingReceipts = [];
@@ -7231,6 +7422,11 @@ function composeReviewBody(input, cliVersion) {
7231
7422
  "compose-review: modelId is required (the public footer names the reviewing model)"
7232
7423
  );
7233
7424
  }
7425
+ if (!isFooterSafeModelId(modelId)) {
7426
+ throw new TypeError(
7427
+ "compose-review: modelId is interpolated into the public footer verbatim \u2014 it must be a single line that does not contain the footer marker"
7428
+ );
7429
+ }
7234
7430
  const c = criticalsInline + bodyCriticals.length;
7235
7431
  const s = suggestionsInline + suggestionsDiscarded;
7236
7432
  const baseEvent = c >= 1 ? "REQUEST_CHANGES" : s >= 1 ? "COMMENT" : "APPROVE";
@@ -7264,7 +7460,7 @@ function composeReviewBody(input, cliVersion) {
7264
7460
  if (event2 === "APPROVE" && input.planPath) {
7265
7461
  try {
7266
7462
  const plan = JSON.parse(
7267
- readFileSync8(input.planPath, "utf8")
7463
+ readFileSync9(input.planPath, "utf8")
7268
7464
  );
7269
7465
  const src = Number(plan.srcDiffLines ?? 0);
7270
7466
  if (src > LOW_SIGNAL_SRC_DIFF_LINES) {
@@ -7273,7 +7469,7 @@ function composeReviewBody(input, cliVersion) {
7273
7469
  } catch {
7274
7470
  }
7275
7471
  }
7276
- const footer = `_\u2014 ${modelId} via Qwen Code /review (v${cliVersion})_`;
7472
+ const footer = reviewFooter(modelId, cliVersion);
7277
7473
  const bilingual = bilingualFromPlan(input.planPath, input.prBodyFetcher);
7278
7474
  const render = /* @__PURE__ */ __name((parts, sep5) => {
7279
7475
  const en = parts.map((p) => p.en).join(sep5);
@@ -7332,7 +7528,7 @@ ${footer}`;
7332
7528
  if (seenCaller.has(d)) continue;
7333
7529
  seenCaller.add(d);
7334
7530
  const echoesCoverage = covEntries.some(
7335
- (e) => d === e.subject || d.startsWith(`${e.subject} \u2014 `)
7531
+ (e) => d === e.subject || e !== budgetEntry && d.startsWith(`${e.subject} \u2014 `)
7336
7532
  );
7337
7533
  if (!echoesCoverage) callerLeft.push(d);
7338
7534
  }
@@ -7556,7 +7752,7 @@ function scriptLintGate(planPath) {
7556
7752
  const disclosed = [];
7557
7753
  let plan;
7558
7754
  try {
7559
- plan = JSON.parse(readFileSync8(planPath, "utf8"));
7755
+ plan = JSON.parse(readFileSync9(planPath, "utf8"));
7560
7756
  } catch {
7561
7757
  unreviewed.push(
7562
7758
  "the executable-script lint \u2014 could not read the plan to check the gate"
@@ -7567,13 +7763,13 @@ function scriptLintGate(planPath) {
7567
7763
  return { criticals, unreviewed, disclosed };
7568
7764
  }
7569
7765
  const owed = hasExecutableScript(plan);
7570
- const reportPath = join8(
7766
+ const reportPath = join9(
7571
7767
  dirname4(planPath),
7572
7768
  scriptLintReportName(plan.prNumber)
7573
7769
  );
7574
7770
  let report;
7575
7771
  try {
7576
- report = JSON.parse(readFileSync8(reportPath, "utf8"));
7772
+ report = JSON.parse(readFileSync9(reportPath, "utf8"));
7577
7773
  } catch {
7578
7774
  if (owed) {
7579
7775
  unreviewed.push(
@@ -7629,7 +7825,7 @@ function testPlanGate(planPath) {
7629
7825
  const notes = [];
7630
7826
  let plan;
7631
7827
  try {
7632
- plan = JSON.parse(readFileSync8(planPath, "utf8"));
7828
+ plan = JSON.parse(readFileSync9(planPath, "utf8"));
7633
7829
  } catch {
7634
7830
  return { notes };
7635
7831
  }
@@ -7639,8 +7835,8 @@ function testPlanGate(planPath) {
7639
7835
  let report;
7640
7836
  try {
7641
7837
  report = JSON.parse(
7642
- readFileSync8(
7643
- join8(dirname4(planPath), `qwen-review-pr-${pr}-test-plan.json`),
7838
+ readFileSync9(
7839
+ join9(dirname4(planPath), `qwen-review-pr-${pr}-test-plan.json`),
7644
7840
  "utf8"
7645
7841
  )
7646
7842
  );
@@ -7673,7 +7869,7 @@ function bilingualFromPlan(planPath, fetchPrBody2 = fetchPrBodyViaGh) {
7673
7869
  if (!planPath) return false;
7674
7870
  let plan;
7675
7871
  try {
7676
- plan = JSON.parse(readFileSync8(planPath, "utf8"));
7872
+ plan = JSON.parse(readFileSync9(planPath, "utf8"));
7677
7873
  } catch {
7678
7874
  return false;
7679
7875
  }
@@ -7693,7 +7889,7 @@ __name(bilingualFromPlan, "bilingualFromPlan");
7693
7889
  function readDraftedComments(path3) {
7694
7890
  let raw;
7695
7891
  try {
7696
- raw = readFileSync8(path3, "utf8");
7892
+ raw = readFileSync9(path3, "utf8");
7697
7893
  } catch (err) {
7698
7894
  throw new Error(
7699
7895
  `compose-review: cannot read the comments file ${path3}: ${err.message}. Pass the drafted inline comments \u2014 the same array the review payload will carry \u2014 or a file containing [] when nothing anchors inline.`
@@ -7747,7 +7943,7 @@ var composeReviewCommand = {
7747
7943
  "compose-review: --comments is required \u2014 the inline counts are counted from the drafted comments file, never typed. Pass a file containing [] when nothing anchors inline."
7748
7944
  );
7749
7945
  }
7750
- const raw = readFileSync8(input ?? 0, "utf8");
7946
+ const raw = readFileSync9(input ?? 0, "utf8");
7751
7947
  const parsed = JSON.parse(raw);
7752
7948
  delete parsed.env;
7753
7949
  delete parsed.prBodyFetcher;
@@ -7764,7 +7960,9 @@ var composeReviewCommand = {
7764
7960
  ...countInlineFindings(drafted),
7765
7961
  draftedComments: drafted
7766
7962
  },
7767
- await getCliVersion()
7963
+ // Same pin as `submit`: the startup stamp, not a version resolved at
7964
+ // compose time — a shared runner can rewrite the install mid-session.
7965
+ footerVersion(process.env["QWEN_CODE_STARTUP_VERSION"]) ?? await getCliVersion()
7768
7966
  );
7769
7967
  const json = JSON.stringify(
7770
7968
  { ...result, verdictLine: verdictLine(result) },
@@ -7772,8 +7970,8 @@ var composeReviewCommand = {
7772
7970
  2
7773
7971
  );
7774
7972
  if (out) {
7775
- mkdirSync5(dirname4(out), { recursive: true });
7776
- writeFileSync5(out, json, "utf8");
7973
+ mkdirSync6(dirname4(out), { recursive: true });
7974
+ writeFileSync6(out, json, "utf8");
7777
7975
  }
7778
7976
  writeStdoutLine(json);
7779
7977
  for (const fix of result.remediation) {
@@ -7874,7 +8072,7 @@ __name(verdictLine, "verdictLine");
7874
8072
 
7875
8073
  // packages/cli/src/commands/review/findings.ts
7876
8074
  init_esbuild_shims();
7877
- import { existsSync as existsSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "node:fs";
8075
+ import { existsSync as existsSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
7878
8076
  import { dirname as dirname5, resolve as resolve5 } from "node:path";
7879
8077
  var SEVERITIES = ["Critical", "Suggestion", "Nice to have"];
7880
8078
  var CONFIDENCES = ["high", "low"];
@@ -8248,7 +8446,7 @@ __name(renderFindings, "renderFindings");
8248
8446
  function readJson(path3, what) {
8249
8447
  let text;
8250
8448
  try {
8251
- text = readFileSync9(resolve5(path3), "utf8");
8449
+ text = readFileSync10(resolve5(path3), "utf8");
8252
8450
  } catch (err) {
8253
8451
  throw new Error(
8254
8452
  `Could not read the ${what} file at ${JSON.stringify(path3)}: ${err instanceof Error ? err.message : String(err)}`
@@ -8319,8 +8517,8 @@ var findingsCommand = {
8319
8517
  }
8320
8518
  const report = buildReport(findings);
8321
8519
  const target = resolve5(out);
8322
- mkdirSync6(dirname5(target), { recursive: true });
8323
- writeFileSync6(target, `${JSON.stringify(report, null, 2)}
8520
+ mkdirSync7(dirname5(target), { recursive: true });
8521
+ writeFileSync7(target, `${JSON.stringify(report, null, 2)}
8324
8522
  `, "utf8");
8325
8523
  const { bySeverity, byConfidence } = report.counts;
8326
8524
  writeStderrLine(
@@ -8351,7 +8549,7 @@ var findingsCommand = {
8351
8549
  // packages/cli/src/commands/review/fetch-pr.ts
8352
8550
  init_esbuild_shims();
8353
8551
  import { execFileSync as execFileSync4 } from "node:child_process";
8354
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
8552
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
8355
8553
  import { dirname as dirname6, resolve as resolve6 } from "node:path";
8356
8554
 
8357
8555
  // packages/cli/src/commands/review/lib/git.ts
@@ -8459,11 +8657,11 @@ var LITERAL_PATHSPECS = "--literal-pathspecs";
8459
8657
 
8460
8658
  // packages/cli/src/commands/review/lib/effort.ts
8461
8659
  init_esbuild_shims();
8462
- import { readFileSync as readFileSync10 } from "node:fs";
8660
+ import { readFileSync as readFileSync11 } from "node:fs";
8463
8661
  function resolveEffort(explicit) {
8464
8662
  if (explicit && EFFORT_LEVELS.has(explicit)) return explicit;
8465
8663
  try {
8466
- const parsed = JSON.parse(readFileSync10(PARSE_ARGS_REPORT, "utf8"));
8664
+ const parsed = JSON.parse(readFileSync11(PARSE_ARGS_REPORT, "utf8"));
8467
8665
  if (typeof parsed.effort === "string" && EFFORT_LEVELS.has(parsed.effort)) {
8468
8666
  return parsed.effort;
8469
8667
  }
@@ -8484,7 +8682,7 @@ __name(planEffortField, "planEffortField");
8484
8682
 
8485
8683
  // packages/cli/src/commands/review/lib/report.ts
8486
8684
  init_esbuild_shims();
8487
- import { statSync as statSync3 } from "node:fs";
8685
+ import { statSync as statSync4 } from "node:fs";
8488
8686
 
8489
8687
  // packages/cli/src/commands/review/lib/heavy.ts
8490
8688
  init_esbuild_shims();
@@ -8587,7 +8785,7 @@ __name(buildPlanReport, "buildPlanReport");
8587
8785
  function warnOnReportSize(path3, cap) {
8588
8786
  let size = 0;
8589
8787
  try {
8590
- size = statSync3(path3).size;
8788
+ size = statSync4(path3).size;
8591
8789
  } catch {
8592
8790
  return;
8593
8791
  }
@@ -8710,7 +8908,7 @@ async function runFetchPr(args) {
8710
8908
  );
8711
8909
  }
8712
8910
  try {
8713
- mkdirSync7(dirname6(wt), { recursive: true });
8911
+ mkdirSync8(dirname6(wt), { recursive: true });
8714
8912
  git("worktree", "add", wt, ref);
8715
8913
  } catch (err) {
8716
8914
  tryRemove(
@@ -8720,7 +8918,7 @@ async function runFetchPr(args) {
8720
8918
  `Failed to create worktree at ${wt}: ${err.message}`
8721
8919
  );
8722
8920
  }
8723
- mkdirSync7(REVIEW_TMP_DIR, { recursive: true });
8921
+ mkdirSync8(REVIEW_TMP_DIR, { recursive: true });
8724
8922
  const { sha: mergeBaseSha, baseFetchFailed } = resolveMergeBase(
8725
8923
  remote,
8726
8924
  meta.baseRefName,
@@ -8744,7 +8942,7 @@ async function runFetchPr(args) {
8744
8942
  ...PINNED_DIFF_FLAGS,
8745
8943
  `${mergeBaseSha}..${fetchedSha}`
8746
8944
  );
8747
- writeFileSync7(diffRel, buf);
8945
+ writeFileSync8(diffRel, buf);
8748
8946
  diffText = buf.toString("utf8");
8749
8947
  diffPath = diffRel;
8750
8948
  diffPathAbsolute = resolve6(diffRel);
@@ -8771,7 +8969,7 @@ async function runFetchPr(args) {
8771
8969
  let auditSince = fetchedAt;
8772
8970
  let prevRaw = null;
8773
8971
  try {
8774
- prevRaw = readFileSync11(out, "utf8");
8972
+ prevRaw = readFileSync12(out, "utf8");
8775
8973
  } catch (err) {
8776
8974
  const code = err.code;
8777
8975
  if (code !== "ENOENT") {
@@ -8854,7 +9052,7 @@ async function runFetchPr(args) {
8854
9052
  ...buildPlanReport(plan, (path3) => fileLineCount(fetchedSha, path3)),
8855
9053
  ...planEffortField(args.effort)
8856
9054
  };
8857
- writeFileSync7(out, stringifyPlanReport(result), "utf8");
9055
+ writeFileSync8(out, stringifyPlanReport(result), "utf8");
8858
9056
  writeStdoutLine(`Wrote fetch-pr report to ${out}`);
8859
9057
  if (diffPath) writeStdoutLine(`Wrote review diff to ${diffPath}`);
8860
9058
  writeStderrLine(
@@ -8938,13 +9136,13 @@ var fetchPrCommand = {
8938
9136
 
8939
9137
  // packages/cli/src/commands/review/capture-local.ts
8940
9138
  init_esbuild_shims();
8941
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
9139
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "node:fs";
8942
9140
  import { dirname as dirname7, resolve as resolve8 } from "node:path";
8943
9141
 
8944
9142
  // packages/cli/src/commands/review/lib/local-diff.ts
8945
9143
  init_esbuild_shims();
8946
- import { lstatSync as lstatSync2, statSync as statSync4, realpathSync as realpathSync2 } from "node:fs";
8947
- import { join as join9, relative as relative2, resolve as resolve7, isAbsolute as isAbsolute2, sep as sep2 } from "node:path";
9144
+ import { lstatSync as lstatSync2, statSync as statSync5, realpathSync as realpathSync2 } from "node:fs";
9145
+ import { join as join10, relative as relative2, resolve as resolve7, isAbsolute as isAbsolute2, sep as sep2 } from "node:path";
8948
9146
  var MAX_UNTRACKED_BYTES = 1e6;
8949
9147
  var MAX_UNTRACKED_FILES = 500;
8950
9148
  var MAX_UNTRACKED_TOTAL_BYTES = 1e7;
@@ -8965,7 +9163,7 @@ function describeUndiffable(abs, st) {
8965
9163
  }
8966
9164
  if (st.isSymbolicLink()) {
8967
9165
  try {
8968
- return statSync4(abs).isDirectory() ? "is a symlink to a directory \u2014 git cannot diff it as a file" : null;
9166
+ return statSync5(abs).isDirectory() ? "is a symlink to a directory \u2014 git cannot diff it as a file" : null;
8969
9167
  } catch {
8970
9168
  return null;
8971
9169
  }
@@ -9070,7 +9268,7 @@ function captureLocalDiff(opts) {
9070
9268
  for (const path3 of candidates) {
9071
9269
  let bytes;
9072
9270
  try {
9073
- const abs = join9(repoRoot, path3);
9271
+ const abs = join10(repoRoot, path3);
9074
9272
  const st = lstatSync2(abs);
9075
9273
  const kind = describeUndiffable(abs, st);
9076
9274
  if (kind) {
@@ -9162,10 +9360,10 @@ function runCaptureLocal(args) {
9162
9360
  includeUntracked: args.untracked
9163
9361
  });
9164
9362
  const diffText = capture.diff.toString("utf8");
9165
- mkdirSync8(REVIEW_TMP_DIR, { recursive: true });
9166
- mkdirSync8(dirname7(resolve8(out)), { recursive: true });
9363
+ mkdirSync9(REVIEW_TMP_DIR, { recursive: true });
9364
+ mkdirSync9(dirname7(resolve8(out)), { recursive: true });
9167
9365
  const diffPath = tmpFile(target, "diff.txt");
9168
- writeFileSync8(diffPath, capture.diff);
9366
+ writeFileSync9(diffPath, capture.diff);
9169
9367
  const plan = buildDiffPlan(diffText);
9170
9368
  const result = {
9171
9369
  diffPath,
@@ -9178,7 +9376,7 @@ function runCaptureLocal(args) {
9178
9376
  skippedFiles: capture.skipped,
9179
9377
  ...planEffortField(args.effort)
9180
9378
  };
9181
- writeFileSync8(out, stringifyPlanReport(result), "utf8");
9379
+ writeFileSync9(out, stringifyPlanReport(result), "utf8");
9182
9380
  writeStdoutLine(`Wrote diff to ${diffPath} and plan to ${out}`);
9183
9381
  if (capture.unbornHead) {
9184
9382
  writeStderrLine(
@@ -9236,13 +9434,13 @@ var captureLocalCommand = {
9236
9434
 
9237
9435
  // packages/cli/src/commands/review/plan-diff.ts
9238
9436
  init_esbuild_shims();
9239
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
9437
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10 } from "node:fs";
9240
9438
  import { resolve as resolve9 } from "node:path";
9241
9439
  function runPlanDiff(args) {
9242
9440
  const { diff_path: diffPath, out } = args;
9243
9441
  let diffText;
9244
9442
  try {
9245
- diffText = readFileSync12(diffPath, "utf8");
9443
+ diffText = readFileSync13(diffPath, "utf8");
9246
9444
  } catch (err) {
9247
9445
  throw new Error(
9248
9446
  `Cannot read diff file ${diffPath}: ${err.message}`
@@ -9269,8 +9467,8 @@ function runPlanDiff(args) {
9269
9467
  ...buildPlanReport(plan, null),
9270
9468
  ...planEffortField(args.effort)
9271
9469
  };
9272
- mkdirSync9(REVIEW_TMP_DIR, { recursive: true });
9273
- writeFileSync9(out, stringifyPlanReport(result), "utf8");
9470
+ mkdirSync10(REVIEW_TMP_DIR, { recursive: true });
9471
+ writeFileSync10(out, stringifyPlanReport(result), "utf8");
9274
9472
  writeStdoutLine(`Wrote diff plan to ${out}`);
9275
9473
  if (plan.diffLines === 0) {
9276
9474
  writeStderrLine(
@@ -9316,8 +9514,8 @@ var planDiffCommand = {
9316
9514
 
9317
9515
  // packages/cli/src/commands/review/pr-context.ts
9318
9516
  init_esbuild_shims();
9319
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "node:fs";
9320
- import { dirname as dirname8, join as join10 } from "node:path";
9517
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
9518
+ import { dirname as dirname8, join as join11 } from "node:path";
9321
9519
  var SUMMARY_MARKER = "<!-- qwen-review-suggestion-summary -->";
9322
9520
  function isLegacySuggestionSummary(body) {
9323
9521
  return (body ?? "").includes(SUMMARY_MARKER);
@@ -9795,9 +9993,9 @@ async function runPrContext(args) {
9795
9993
  }
9796
9994
  if (prevLedger) {
9797
9995
  try {
9798
- mkdirSync10(dirname8(out), { recursive: true });
9799
- writeFileSync10(
9800
- join10(dirname8(out), `qwen-review-pr-${prNumber}-prev-ledger.json`),
9996
+ mkdirSync11(dirname8(out), { recursive: true });
9997
+ writeFileSync11(
9998
+ join11(dirname8(out), `qwen-review-pr-${prNumber}-prev-ledger.json`),
9801
9999
  JSON.stringify(prevLedger, null, 2)
9802
10000
  );
9803
10001
  } catch {
@@ -9812,8 +10010,8 @@ async function runPrContext(args) {
9812
10010
  reviews,
9813
10011
  prevLedger
9814
10012
  );
9815
- mkdirSync10(dirname8(out), { recursive: true });
9816
- writeFileSync10(out, md, "utf8");
10013
+ mkdirSync11(dirname8(out), { recursive: true });
10014
+ writeFileSync11(out, md, "utf8");
9817
10015
  const meaningfulReviewCount = reviews.filter(
9818
10016
  (r) => isReviewWorthShowing(stripLedgerMarker(r.body ?? ""))
9819
10017
  ).length;
@@ -9867,7 +10065,7 @@ var prContextCommand = {
9867
10065
 
9868
10066
  // packages/cli/src/commands/review/comment-status.ts
9869
10067
  init_esbuild_shims();
9870
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
10068
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "node:fs";
9871
10069
  import { dirname as dirname9 } from "node:path";
9872
10070
  var TOUCHED_BY_CAP = 10;
9873
10071
  function buildThreadStatuses(comments, prAuthor, probe) {
@@ -10073,9 +10271,9 @@ async function runCommentStatus(args) {
10073
10271
  summary,
10074
10272
  threads
10075
10273
  };
10076
- mkdirSync11(dirname9(out), { recursive: true });
10274
+ mkdirSync12(dirname9(out), { recursive: true });
10077
10275
  const json = JSON.stringify(report, null, 2) + "\n";
10078
- writeFileSync11(out, json, "utf8");
10276
+ writeFileSync12(out, json, "utf8");
10079
10277
  writeStdoutLine(
10080
10278
  `Wrote comment-status report to ${out} (${comments.length} inline comments in ${summary.threads} threads: ${summary.outdated} outdated, ${summary.blockers} blocker(s), ${summary.changedSinceComment} on files changed since their comment, ${summary.withReplies} with replies, ${summary.authorReplied} answered by the PR author)`
10081
10279
  );
@@ -10103,8 +10301,8 @@ async function runCommentStatus(args) {
10103
10301
  writeStdoutLine(
10104
10302
  `warning: comment-status failed: ${msg}. It is an index, not the evidence \u2014 re-derive thread statuses per-comment if needed.`
10105
10303
  );
10106
- mkdirSync11(dirname9(out), { recursive: true });
10107
- writeFileSync11(
10304
+ mkdirSync12(dirname9(out), { recursive: true });
10305
+ writeFileSync12(
10108
10306
  out,
10109
10307
  JSON.stringify(
10110
10308
  {
@@ -10166,7 +10364,7 @@ var commentStatusCommand = {
10166
10364
 
10167
10365
  // packages/cli/src/commands/review/load-rules.ts
10168
10366
  init_esbuild_shims();
10169
- import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "node:fs";
10367
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "node:fs";
10170
10368
  import { dirname as dirname10 } from "node:path";
10171
10369
  function showFile(baseRef, path3) {
10172
10370
  return gitOpt("show", `${baseRef}:${path3}`);
@@ -10247,8 +10445,8 @@ __name(loadCombined, "loadCombined");
10247
10445
  async function runLoadRules(args) {
10248
10446
  const { base_ref: baseRef, out } = args;
10249
10447
  const { combined, loaded } = loadCombined(baseRef);
10250
- mkdirSync12(dirname10(out), { recursive: true });
10251
- writeFileSync12(out, combined, "utf8");
10448
+ mkdirSync13(dirname10(out), { recursive: true });
10449
+ writeFileSync13(out, combined, "utf8");
10252
10450
  if (loaded.length === 0) {
10253
10451
  writeStdoutLine(
10254
10452
  `No review rules found on ${baseRef}; wrote empty file to ${out}`
@@ -10279,7 +10477,7 @@ var loadRulesCommand = {
10279
10477
 
10280
10478
  // packages/cli/src/commands/review/presubmit.ts
10281
10479
  init_esbuild_shims();
10282
- import { writeFileSync as writeFileSync13, readFileSync as readFileSync13 } from "node:fs";
10480
+ import { writeFileSync as writeFileSync14, readFileSync as readFileSync14 } from "node:fs";
10283
10481
  function verdictStamp(run4) {
10284
10482
  return run4.completed_at ?? run4.started_at ?? "";
10285
10483
  }
@@ -10315,7 +10513,7 @@ __name(isCurrentActionsRunCheck, "isCurrentActionsRunCheck");
10315
10513
  function parseFindingsFile(path3) {
10316
10514
  let parsed;
10317
10515
  try {
10318
- parsed = JSON.parse(readFileSync13(path3, "utf8"));
10516
+ parsed = JSON.parse(readFileSync14(path3, "utf8"));
10319
10517
  } catch {
10320
10518
  return null;
10321
10519
  }
@@ -10618,7 +10816,7 @@ async function runPresubmit(args) {
10618
10816
  findingsFileInvalid,
10619
10817
  headDrift
10620
10818
  };
10621
- writeFileSync13(outPath, JSON.stringify(result, null, 2) + "\n", "utf8");
10819
+ writeFileSync14(outPath, JSON.stringify(result, null, 2) + "\n", "utf8");
10622
10820
  writeStdoutLine(`Wrote presubmit report to ${outPath}`);
10623
10821
  }
10624
10822
  __name(runPresubmit, "runPresubmit");
@@ -10657,17 +10855,17 @@ var presubmitCommand = {
10657
10855
  // packages/cli/src/commands/review/publish-assets.ts
10658
10856
  init_esbuild_shims();
10659
10857
  import { createHash as createHash2 } from "node:crypto";
10660
- import { readFileSync as readFileSync15, statSync as statSync5, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14 } from "node:fs";
10858
+ import { readFileSync as readFileSync16, statSync as statSync6, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "node:fs";
10661
10859
  import { basename as basename5, dirname as dirname11, resolve as resolve10 } from "node:path";
10662
10860
 
10663
10861
  // packages/cli/src/commands/review/lib/authorization.ts
10664
10862
  init_esbuild_shims();
10665
- import { readFileSync as readFileSync14 } from "node:fs";
10863
+ import { readFileSync as readFileSync15 } from "node:fs";
10666
10864
 
10667
10865
  // packages/cli/src/services/skill-args-file.ts
10668
10866
  init_esbuild_shims();
10669
10867
  import {
10670
- mkdirSync as mkdirSync13,
10868
+ mkdirSync as mkdirSync14,
10671
10869
  openSync as openSync2,
10672
10870
  writeSync,
10673
10871
  closeSync as closeSync2,
@@ -10676,9 +10874,9 @@ import {
10676
10874
  existsSync as existsSync5,
10677
10875
  constants
10678
10876
  } from "node:fs";
10679
- import { join as join11 } from "node:path";
10877
+ import { join as join12 } from "node:path";
10680
10878
  var debugLogger3 = createDebugLogger("SKILL_ARGS_FILE");
10681
- var SKILL_ARGS_DIR = join11(".qwen", "tmp");
10879
+ var SKILL_ARGS_DIR = join12(".qwen", "tmp");
10682
10880
  function safe(s) {
10683
10881
  return s.replace(/[^A-Za-z0-9._-]/g, "_");
10684
10882
  }
@@ -10688,11 +10886,11 @@ function currentSessionId() {
10688
10886
  }
10689
10887
  __name(currentSessionId, "currentSessionId");
10690
10888
  function skillArgsDir(sessionId = currentSessionId()) {
10691
- return sessionId ? join11(SKILL_ARGS_DIR, `s-${safe(sessionId)}`) : SKILL_ARGS_DIR;
10889
+ return sessionId ? join12(SKILL_ARGS_DIR, `s-${safe(sessionId)}`) : SKILL_ARGS_DIR;
10692
10890
  }
10693
10891
  __name(skillArgsDir, "skillArgsDir");
10694
10892
  function skillArgsPath(skillName, sessionId = currentSessionId()) {
10695
- return join11(
10893
+ return join12(
10696
10894
  skillArgsDir(sessionId),
10697
10895
  `qwen-skill-args-${safe(skillName)}.txt`
10698
10896
  );
@@ -10702,7 +10900,7 @@ function writeSkillArgs(skillName, args) {
10702
10900
  const path3 = skillArgsPath(skillName);
10703
10901
  try {
10704
10902
  const dir = skillArgsDir();
10705
- mkdirSync13(dir, { recursive: true });
10903
+ mkdirSync14(dir, { recursive: true });
10706
10904
  if (lstatSync3(dir).isSymbolicLink()) {
10707
10905
  debugLogger3.warn(
10708
10906
  `Skill args directory ${dir} is a symlink; refusing to write through it.`
@@ -10785,7 +10983,7 @@ function reviewWriteAuthorization(req) {
10785
10983
  const path3 = currentSessionId() === "" && req.skillArgs ? req.skillArgs : sessionScoped;
10786
10984
  let raw;
10787
10985
  try {
10788
- raw = readFileSync14(path3, "utf8");
10986
+ raw = readFileSync15(path3, "utf8");
10789
10987
  } catch {
10790
10988
  return {
10791
10989
  ok: false,
@@ -11051,7 +11249,7 @@ function runPublishAssets(args) {
11051
11249
  const fileList = [...args.files ?? []];
11052
11250
  if (args.findings) {
11053
11251
  try {
11054
- const artifact = JSON.parse(readFileSync15(resolve10(args.findings), "utf8"));
11252
+ const artifact = JSON.parse(readFileSync16(resolve10(args.findings), "utf8"));
11055
11253
  findings = validateFindings(
11056
11254
  Array.isArray(artifact) ? artifact : artifact.findings
11057
11255
  );
@@ -11081,7 +11279,7 @@ function runPublishAssets(args) {
11081
11279
  for (const file of unique) {
11082
11280
  const abs = resolve10(file);
11083
11281
  try {
11084
- const st = statSync5(abs);
11282
+ const st = statSync6(abs);
11085
11283
  if (!st.isFile()) throw new Error("not a regular file");
11086
11284
  stats.push({ file, abs, basename: basename5(abs), bytes: st.size });
11087
11285
  } catch (err) {
@@ -11100,7 +11298,7 @@ function runPublishAssets(args) {
11100
11298
  for (const st of stats) {
11101
11299
  let content;
11102
11300
  try {
11103
- content = readFileSync15(st.abs);
11301
+ content = readFileSync16(st.abs);
11104
11302
  } catch (err) {
11105
11303
  refuse(
11106
11304
  `cannot read ${JSON.stringify(st.file)}: ${err instanceof Error ? err.message : String(err)}`
@@ -11147,8 +11345,8 @@ function runPublishAssets(args) {
11147
11345
  published
11148
11346
  };
11149
11347
  const outPath = resolve10(args.out);
11150
- mkdirSync14(dirname11(outPath), { recursive: true });
11151
- writeFileSync14(outPath, `${JSON.stringify(manifest, null, 2)}
11348
+ mkdirSync15(dirname11(outPath), { recursive: true });
11349
+ writeFileSync15(outPath, `${JSON.stringify(manifest, null, 2)}
11152
11350
  `, "utf8");
11153
11351
  if (findings && !args.findingsOut) {
11154
11352
  writeStderrLine(
@@ -11163,8 +11361,8 @@ function runPublishAssets(args) {
11163
11361
  });
11164
11362
  const report = buildReport(updated);
11165
11363
  const fOut = resolve10(args.findingsOut);
11166
- mkdirSync14(dirname11(fOut), { recursive: true });
11167
- writeFileSync14(fOut, `${JSON.stringify(report, null, 2)}
11364
+ mkdirSync15(dirname11(fOut), { recursive: true });
11365
+ writeFileSync15(fOut, `${JSON.stringify(report, null, 2)}
11168
11366
  `, "utf8");
11169
11367
  }
11170
11368
  writeStderrLine(
@@ -11226,7 +11424,7 @@ var publishAssetsCommand = {
11226
11424
 
11227
11425
  // packages/cli/src/commands/review/resolve-anchors.ts
11228
11426
  init_esbuild_shims();
11229
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "node:fs";
11427
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync16, mkdirSync as mkdirSync16 } from "node:fs";
11230
11428
  import { dirname as dirname12, resolve as resolve11 } from "node:path";
11231
11429
 
11232
11430
  // packages/cli/src/commands/review/lib/anchors.ts
@@ -11451,7 +11649,7 @@ __name(validateRequests, "validateRequests");
11451
11649
  function runResolveAnchors(args) {
11452
11650
  let diffText;
11453
11651
  try {
11454
- diffText = readFileSync16(args.diff, "utf8");
11652
+ diffText = readFileSync17(args.diff, "utf8");
11455
11653
  } catch (err) {
11456
11654
  throw new Error(
11457
11655
  `Cannot read diff file ${args.diff}: ${err.message}`
@@ -11459,7 +11657,7 @@ function runResolveAnchors(args) {
11459
11657
  }
11460
11658
  let rawText;
11461
11659
  try {
11462
- rawText = readFileSync16(args.input, "utf8");
11660
+ rawText = readFileSync17(args.input, "utf8");
11463
11661
  } catch (err) {
11464
11662
  throw new Error(
11465
11663
  `Cannot read findings file ${args.input}: ${err.message}`
@@ -11490,8 +11688,8 @@ function runResolveAnchors(args) {
11490
11688
  loose: resolved.filter((r) => r.tier?.startsWith("loose")).length
11491
11689
  }
11492
11690
  };
11493
- mkdirSync15(dirname12(resolve11(args.out)), { recursive: true });
11494
- writeFileSync15(args.out, JSON.stringify(report, null, 2), "utf8");
11691
+ mkdirSync16(dirname12(resolve11(args.out)), { recursive: true });
11692
+ writeFileSync16(args.out, JSON.stringify(report, null, 2), "utf8");
11495
11693
  writeStdoutLine(`Wrote resolved anchors to ${args.out}`);
11496
11694
  const s = report.stats;
11497
11695
  writeStderrLine(
@@ -11538,7 +11736,7 @@ var resolveAnchorsCommand = {
11538
11736
 
11539
11737
  // packages/cli/src/commands/review/check-coverage.ts
11540
11738
  init_esbuild_shims();
11541
- import { writeFileSync as writeFileSync16, mkdirSync as mkdirSync16 } from "node:fs";
11739
+ import { writeFileSync as writeFileSync17, mkdirSync as mkdirSync17 } from "node:fs";
11542
11740
  import { dirname as dirname13, resolve as resolve12 } from "node:path";
11543
11741
  function runCheckCoverage(args) {
11544
11742
  let report;
@@ -11555,8 +11753,8 @@ This is an environment problem, not a finding about the agents. Coverage cannot
11555
11753
  }
11556
11754
  throw err;
11557
11755
  }
11558
- mkdirSync16(dirname13(resolve12(args.out)), { recursive: true });
11559
- writeFileSync16(args.out, JSON.stringify(report, null, 2));
11756
+ mkdirSync17(dirname13(resolve12(args.out)), { recursive: true });
11757
+ writeFileSync17(args.out, JSON.stringify(report, null, 2));
11560
11758
  writeStdoutLine(`Wrote coverage report to ${args.out}`);
11561
11759
  const totalChunks = report.coveredChunks.length + report.missingChunks.length + report.uncoverableChunks.length;
11562
11760
  const worked = report.agents - report.blindAgents.length - report.idleAgents.length;
@@ -11655,8 +11853,8 @@ var checkCoverageCommand = {
11655
11853
  // packages/cli/src/commands/review/agent-prompt.ts
11656
11854
  init_esbuild_shims();
11657
11855
  import { createHash as createHash3 } from "node:crypto";
11658
- import { readFileSync as readFileSync17 } from "node:fs";
11659
- import { dirname as dirname14, join as join12, resolve as resolve13 } from "node:path";
11856
+ import { readFileSync as readFileSync18 } from "node:fs";
11857
+ import { dirname as dirname14, join as join13, resolve as resolve13 } from "node:path";
11660
11858
 
11661
11859
  // packages/cli/src/commands/review/lib/path-rules.ts
11662
11860
  init_esbuild_shims();
@@ -12108,7 +12306,7 @@ function buildRoleBrief(report, role, opts = {}) {
12108
12306
  "agent-prompt: --role 0 needs a plan with `prNumber` and `ownerRepo` (the report `fetch-pr` writes). Issue fidelity has nothing to check against without a pull request."
12109
12307
  );
12110
12308
  }
12111
- const ctx = opts.planPath ? join12(dirname14(resolve13(opts.planPath)), `qwen-review-pr-${pr}-context.md`) : null;
12309
+ const ctx = opts.planPath ? join13(dirname14(resolve13(opts.planPath)), `qwen-review-pr-${pr}-context.md`) : null;
12112
12310
  parts.push(
12113
12311
  "",
12114
12312
  `**This PR:** #${pr} of \`${repo}\`. Use exactly that number and repo \u2014 a bare \`gh pr view\` falls back to the current branch's PR and would judge this diff against an unrelated issue.`
@@ -12367,7 +12565,7 @@ The \`description\` parameter of each Agent call is the task name the user watch
12367
12565
  );
12368
12566
  }
12369
12567
  __name(runRoster, "runRoster");
12370
- function runAllChunks(report, planPath, role, findingsContent, rules, round) {
12568
+ function requireAuditableChunks(report) {
12371
12569
  if (!Array.isArray(report.chunks) || report.chunks.length === 0) {
12372
12570
  throw new Error("agent-prompt: the plan has no `chunks[]`.");
12373
12571
  }
@@ -12378,6 +12576,11 @@ function runAllChunks(report, planPath, role, findingsContent, rules, round) {
12378
12576
  `agent-prompt: the plan has ${problem} \u2014 a round built from what remains would look complete while a territory goes unaudited. Re-run the Step 1 capture; do not hand-edit the plan.`
12379
12577
  );
12380
12578
  }
12579
+ return chunks;
12580
+ }
12581
+ __name(requireAuditableChunks, "requireAuditableChunks");
12582
+ function runAllChunks(report, planPath, role, findingsContent, rules, round) {
12583
+ const chunks = requireAuditableChunks(report);
12381
12584
  const digest = findingsDigest(findingsContent, rules);
12382
12585
  const roundPart = round !== void 0 ? `--round-${round}` : "";
12383
12586
  const blocks = chunks.map((c, i) => {
@@ -12483,6 +12686,11 @@ function runAgentPrompt(args) {
12483
12686
  );
12484
12687
  }
12485
12688
  }
12689
+ if (role === "reverse-audit" && !hasRound) {
12690
+ bad(
12691
+ "--role reverse-audit builds one round of the Step 5 loop and requires --round <k>: the label keys the record and the budget gate's per-round accounting."
12692
+ );
12693
+ }
12486
12694
  } else if (hasFindings) {
12487
12695
  const findingRoles = Object.keys(BRIEFS).filter(
12488
12696
  (r) => BRIEFS[r].acceptsFindings
@@ -12513,7 +12721,7 @@ function runAgentPrompt(args) {
12513
12721
  }
12514
12722
  let report;
12515
12723
  try {
12516
- report = JSON.parse(readFileSync17(args.plan, "utf8"));
12724
+ report = JSON.parse(readFileSync18(args.plan, "utf8"));
12517
12725
  } catch (err) {
12518
12726
  throw new Error(
12519
12727
  `agent-prompt: cannot read the plan ${args.plan}: ${err.message}`
@@ -12522,7 +12730,7 @@ function runAgentPrompt(args) {
12522
12730
  let rules;
12523
12731
  if (args.rules) {
12524
12732
  try {
12525
- rules = readFileSync17(args.rules, "utf8");
12733
+ rules = readFileSync18(args.rules, "utf8");
12526
12734
  } catch (err) {
12527
12735
  throw new Error(
12528
12736
  `agent-prompt: cannot read the rules ${args.rules}: ${err.message}. Omit --rules if this review has none; passing a path that does not resolve would silently review without the project rules it was told to enforce.`
@@ -12537,7 +12745,7 @@ function runAgentPrompt(args) {
12537
12745
  if (hasFindings && args.role) {
12538
12746
  const role = args.role;
12539
12747
  try {
12540
- findingsContent = readFileSync17(args.findings, "utf8");
12748
+ findingsContent = readFileSync18(args.findings, "utf8");
12541
12749
  } catch (err) {
12542
12750
  throw new Error(
12543
12751
  `agent-prompt: cannot read the findings ${args.findings}: ${err.message}. Pass a path that resolves \u2014 --findings is required for this role, so omitting it only fails one guard earlier. An early reverse-audit round with nothing confirmed passes an empty file (create it first).`
@@ -12549,6 +12757,21 @@ function runAgentPrompt(args) {
12549
12757
  );
12550
12758
  }
12551
12759
  }
12760
+ if (args.allChunks && args.role && findingsContent !== void 0) {
12761
+ requireAuditableChunks(report);
12762
+ }
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;
12773
+ }
12774
+ }
12552
12775
  if (args.allChunks && args.role && findingsContent !== void 0) {
12553
12776
  runAllChunks(
12554
12777
  report,
@@ -12558,6 +12781,9 @@ function runAgentPrompt(args) {
12558
12781
  rules,
12559
12782
  args.round
12560
12783
  );
12784
+ if (args.role === "reverse-audit") {
12785
+ stampRound(args.plan, args.round);
12786
+ }
12561
12787
  return;
12562
12788
  }
12563
12789
  let prompt;
@@ -12588,11 +12814,14 @@ function runAgentPrompt(args) {
12588
12814
  const printed = findingsContent !== void 0 && args.role ? foldFindings(args.role, findingsContent, prompt) : prompt;
12589
12815
  recordPrompt(args.plan, key, printed);
12590
12816
  writeStdoutLine(printed);
12817
+ if (args.role === "reverse-audit") {
12818
+ stampRound(args.plan, args.round);
12819
+ }
12591
12820
  }
12592
12821
  __name(runAgentPrompt, "runAgentPrompt");
12593
12822
  var agentPromptCommand = {
12594
12823
  command: "agent-prompt",
12595
- 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)",
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.",
12596
12825
  builder: /* @__PURE__ */ __name((yargs) => yargs.option("plan", {
12597
12826
  type: "string",
12598
12827
  demandOption: true,
@@ -12647,17 +12876,17 @@ init_esbuild_shims();
12647
12876
  import { spawnSync as spawnSync2 } from "node:child_process";
12648
12877
  import {
12649
12878
  existsSync as existsSync7,
12650
- readFileSync as readFileSync19,
12879
+ readFileSync as readFileSync20,
12651
12880
  rmSync as rmSync5,
12652
12881
  statfsSync,
12653
- writeFileSync as writeFileSync17
12882
+ writeFileSync as writeFileSync18
12654
12883
  } from "node:fs";
12655
- import { join as join14, resolve as resolve14 } from "node:path";
12884
+ import { join as join15, resolve as resolve14 } from "node:path";
12656
12885
 
12657
12886
  // packages/cli/src/commands/review/lib/workspaces.ts
12658
12887
  init_esbuild_shims();
12659
- import { existsSync as existsSync6, readFileSync as readFileSync18, readdirSync as readdirSync4 } from "node:fs";
12660
- import { join as join13 } from "node:path";
12888
+ import { existsSync as existsSync6, readFileSync as readFileSync19, readdirSync as readdirSync4 } from "node:fs";
12889
+ import { join as join14 } from "node:path";
12661
12890
  function isWorkspaceMember(filePath, workspaceGlobs) {
12662
12891
  return workspaceDirFor(filePath, workspaceGlobs) !== null;
12663
12892
  }
@@ -12695,7 +12924,7 @@ __name(hasUnmodeledWorkspaceGlob, "hasUnmodeledWorkspaceGlob");
12695
12924
  function readWorkspaceGlobs(root) {
12696
12925
  try {
12697
12926
  const pkg = JSON.parse(
12698
- readFileSync18(join13(root, "package.json"), "utf8")
12927
+ readFileSync19(join14(root, "package.json"), "utf8")
12699
12928
  );
12700
12929
  const ws = pkg.workspaces;
12701
12930
  const globs = Array.isArray(ws) ? ws : Array.isArray(ws?.packages) ? ws.packages : [];
@@ -12708,7 +12937,7 @@ __name(readWorkspaceGlobs, "readWorkspaceGlobs");
12708
12937
  function readRootPackage(root) {
12709
12938
  let pkg;
12710
12939
  try {
12711
- pkg = JSON.parse(readFileSync18(join13(root, "package.json"), "utf8"));
12940
+ pkg = JSON.parse(readFileSync19(join14(root, "package.json"), "utf8"));
12712
12941
  } catch {
12713
12942
  return null;
12714
12943
  }
@@ -12732,7 +12961,7 @@ function readWorkspacePackages(root) {
12732
12961
  const base = g.slice(0, -2);
12733
12962
  let entries;
12734
12963
  try {
12735
- entries = readdirSync4(join13(root, base), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
12964
+ entries = readdirSync4(join14(root, base), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
12736
12965
  } catch {
12737
12966
  continue;
12738
12967
  }
@@ -12744,11 +12973,11 @@ function readWorkspacePackages(root) {
12744
12973
  const pkgs = [];
12745
12974
  for (const dir of dirs) {
12746
12975
  if (workspaceDirFor(`${dir}/package.json`, globs) !== dir) continue;
12747
- const manifest = join13(root, dir, "package.json");
12976
+ const manifest = join14(root, dir, "package.json");
12748
12977
  if (!existsSync6(manifest)) continue;
12749
12978
  let pkg;
12750
12979
  try {
12751
- pkg = JSON.parse(readFileSync18(manifest, "utf8"));
12980
+ pkg = JSON.parse(readFileSync19(manifest, "utf8"));
12752
12981
  } catch {
12753
12982
  continue;
12754
12983
  }
@@ -12921,7 +13150,7 @@ __name(unresolvedWorkspaceDeps, "unresolvedWorkspaceDeps");
12921
13150
  function changedFilesFrom(planPath) {
12922
13151
  let parsed;
12923
13152
  try {
12924
- parsed = JSON.parse(readFileSync19(planPath, "utf8"));
13153
+ parsed = JSON.parse(readFileSync20(planPath, "utf8"));
12925
13154
  } catch (err) {
12926
13155
  throw new Error(
12927
13156
  `build-test: cannot read the plan ${planPath}: ${err.message}`
@@ -13004,15 +13233,15 @@ function runBuildTest(args) {
13004
13233
  timedOut: [],
13005
13234
  note: ""
13006
13235
  };
13007
- const npmLock = existsSync7(join14(root, "package-lock.json"));
13008
- const installComplete = /* @__PURE__ */ __name(() => existsSync7(join14(root, "node_modules", ".package-lock.json")), "installComplete");
13009
- if (args.install && !npmLock && !existsSync7(join14(root, "node_modules"))) {
13236
+ const npmLock = existsSync7(join15(root, "package-lock.json"));
13237
+ const installComplete = /* @__PURE__ */ __name(() => existsSync7(join15(root, "node_modules", ".package-lock.json")), "installComplete");
13238
+ if (args.install && !npmLock && !existsSync7(join15(root, "node_modules"))) {
13010
13239
  const altLock = [
13011
13240
  ["yarn.lock", "yarn install --frozen-lockfile"],
13012
13241
  ["pnpm-lock.yaml", "pnpm install --frozen-lockfile"],
13013
13242
  ["bun.lockb", "bun install --frozen-lockfile"],
13014
13243
  ["bun.lock", "bun install --frozen-lockfile"]
13015
- ].find(([f]) => existsSync7(join14(root, f)));
13244
+ ].find(([f]) => existsSync7(join15(root, f)));
13016
13245
  return unsupportedReport(
13017
13246
  altLock ? `This is a ${altLock[0]} repo with no installed \`node_modules\`, so \`npm ci\` cannot install it. Run \`${altLock[1]}\` first, then fall back to the build/test precedence in your brief, each command with a deadline it can meet.` : "There is no lockfile and no `node_modules` here, so nothing can be installed deterministically. Install dependencies first, then fall back to the build/test precedence in your brief."
13018
13247
  );
@@ -13030,7 +13259,7 @@ function runBuildTest(args) {
13030
13259
  if (install.timedOut) results.timedOut.push(install.command);
13031
13260
  if (install.timedOut) {
13032
13261
  try {
13033
- rmSync5(join14(root, "node_modules"), {
13262
+ rmSync5(join15(root, "node_modules"), {
13034
13263
  recursive: true,
13035
13264
  force: true,
13036
13265
  maxRetries: 3
@@ -13153,7 +13382,7 @@ var buildTestCommand = {
13153
13382
  try {
13154
13383
  const report = runBuildTest(args);
13155
13384
  if (args.out) {
13156
- writeFileSync17(args.out, JSON.stringify(report, null, 2));
13385
+ writeFileSync18(args.out, JSON.stringify(report, null, 2));
13157
13386
  }
13158
13387
  writeStdoutLine(JSON.stringify(report, null, 2));
13159
13388
  } catch (err) {
@@ -13168,13 +13397,13 @@ init_esbuild_shims();
13168
13397
  import { spawnSync as spawnSync4 } from "node:child_process";
13169
13398
  import {
13170
13399
  existsSync as existsSync8,
13171
- mkdirSync as mkdirSync17,
13172
- readFileSync as readFileSync20,
13400
+ mkdirSync as mkdirSync18,
13401
+ readFileSync as readFileSync21,
13173
13402
  rmSync as rmSync7,
13174
- statSync as statSync6,
13175
- writeFileSync as writeFileSync18
13403
+ statSync as statSync7,
13404
+ writeFileSync as writeFileSync19
13176
13405
  } from "node:fs";
13177
- import { dirname as dirname15, join as join15, resolve as resolve15 } from "node:path";
13406
+ import { dirname as dirname15, join as join16, resolve as resolve15 } from "node:path";
13178
13407
 
13179
13408
  // packages/cli/src/commands/review/lib/worktree.ts
13180
13409
  init_esbuild_shims();
@@ -13221,7 +13450,7 @@ function runBaseTree(args) {
13221
13450
  }), "unavailable");
13222
13451
  let plan;
13223
13452
  try {
13224
- plan = JSON.parse(readFileSync20(args.plan, "utf8"));
13453
+ plan = JSON.parse(readFileSync21(args.plan, "utf8"));
13225
13454
  } catch (err) {
13226
13455
  return unavailable(
13227
13456
  `cannot read the plan ${args.plan}: ${err.message}`
@@ -13243,10 +13472,10 @@ function runBaseTree(args) {
13243
13472
  return unavailable(`the review worktree ${worktree} does not exist`);
13244
13473
  }
13245
13474
  const tree = baseWorktreePath(worktree);
13246
- const marker = /* @__PURE__ */ __name(() => join15(tree, ".qwen-review-base-ok"), "marker");
13247
- const failedMarker = /* @__PURE__ */ __name(() => join15(tree, ".qwen-review-base-failed"), "failedMarker");
13475
+ const marker = /* @__PURE__ */ __name(() => join16(tree, ".qwen-review-base-ok"), "marker");
13476
+ const failedMarker = /* @__PURE__ */ __name(() => join16(tree, ".qwen-review-base-failed"), "failedMarker");
13248
13477
  try {
13249
- if (existsSync8(tree) && readFileSync20(marker(), "utf8").trim() === baseSha && gitOut(tree, "rev-parse", "HEAD") === baseSha) {
13478
+ if (existsSync8(tree) && readFileSync21(marker(), "utf8").trim() === baseSha && gitOut(tree, "rev-parse", "HEAD") === baseSha) {
13250
13479
  return {
13251
13480
  available: true,
13252
13481
  path: tree,
@@ -13258,7 +13487,7 @@ function runBaseTree(args) {
13258
13487
  } catch {
13259
13488
  }
13260
13489
  try {
13261
- if (existsSync8(tree) && readFileSync20(failedMarker(), "utf8").trim() === baseSha) {
13490
+ if (existsSync8(tree) && readFileSync21(failedMarker(), "utf8").trim() === baseSha) {
13262
13491
  return {
13263
13492
  available: false,
13264
13493
  path: tree,
@@ -13271,14 +13500,14 @@ function runBaseTree(args) {
13271
13500
  }
13272
13501
  const lock = `${tree}.lock`;
13273
13502
  try {
13274
- const age = Date.now() - statSync6(lock).mtimeMs;
13503
+ const age = Date.now() - statSync7(lock).mtimeMs;
13275
13504
  if (age > 30 * 60 * 1e3) {
13276
13505
  rmSync7(lock, { recursive: true, force: true });
13277
13506
  }
13278
13507
  } catch {
13279
13508
  }
13280
13509
  try {
13281
- mkdirSync17(lock);
13510
+ mkdirSync18(lock);
13282
13511
  } catch (err) {
13283
13512
  if (err.code !== "EEXIST") {
13284
13513
  return unavailable(
@@ -13316,7 +13545,7 @@ function runBaseTree(args) {
13316
13545
  });
13317
13546
  if (!build.ok || build.toolchain !== "npm" || build.build.length === 0) {
13318
13547
  try {
13319
- writeFileSync18(failedMarker(), `${baseSha2}
13548
+ writeFileSync19(failedMarker(), `${baseSha2}
13320
13549
  `);
13321
13550
  } catch {
13322
13551
  }
@@ -13329,7 +13558,7 @@ function runBaseTree(args) {
13329
13558
  };
13330
13559
  }
13331
13560
  try {
13332
- writeFileSync18(marker(), `${baseSha2}
13561
+ writeFileSync19(marker(), `${baseSha2}
13333
13562
  `);
13334
13563
  } catch {
13335
13564
  }
@@ -13369,8 +13598,8 @@ var baseTreeCommand = {
13369
13598
  try {
13370
13599
  const report = runBaseTree(args);
13371
13600
  if (args.out) {
13372
- mkdirSync17(dirname15(resolve15(args.out)), { recursive: true });
13373
- writeFileSync18(resolve15(args.out), JSON.stringify(report, null, 2));
13601
+ mkdirSync18(dirname15(resolve15(args.out)), { recursive: true });
13602
+ writeFileSync19(resolve15(args.out), JSON.stringify(report, null, 2));
13374
13603
  }
13375
13604
  writeStdoutLine(JSON.stringify(report, null, 2));
13376
13605
  writeStderrLine(`base-tree: ${report.note}`);
@@ -13384,7 +13613,7 @@ var baseTreeCommand = {
13384
13613
  // packages/cli/src/commands/review/test-delta.ts
13385
13614
  init_esbuild_shims();
13386
13615
  import { spawnSync as spawnSync5 } from "node:child_process";
13387
- import { existsSync as existsSync9, mkdirSync as mkdirSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync19 } from "node:fs";
13616
+ import { existsSync as existsSync9, mkdirSync as mkdirSync19, readFileSync as readFileSync22, writeFileSync as writeFileSync20 } from "node:fs";
13388
13617
  import { dirname as dirname16, resolve as resolve16 } from "node:path";
13389
13618
  var ANSI_SGR_RE2 = /\x1b\[[0-9;]*m/g;
13390
13619
  var RERUNNABLE_COMMAND_RE = /^npm test(?: --workspace="[\w@./-]+")?$/;
@@ -13458,7 +13687,7 @@ function runTestDelta(args) {
13458
13687
  }), "empty");
13459
13688
  let report;
13460
13689
  try {
13461
- report = JSON.parse(readFileSync21(args.report, "utf8"));
13690
+ report = JSON.parse(readFileSync22(args.report, "utf8"));
13462
13691
  } catch (err) {
13463
13692
  return empty(
13464
13693
  `cannot read the build-test report ${args.report}: ${err.message}`
@@ -13600,8 +13829,8 @@ var testDeltaCommand = {
13600
13829
  const args = argv;
13601
13830
  const report = runTestDelta(args);
13602
13831
  if (args.out) {
13603
- mkdirSync18(dirname16(resolve16(args.out)), { recursive: true });
13604
- writeFileSync19(resolve16(args.out), JSON.stringify(report, null, 2));
13832
+ mkdirSync19(dirname16(resolve16(args.out)), { recursive: true });
13833
+ writeFileSync20(resolve16(args.out), JSON.stringify(report, null, 2));
13605
13834
  }
13606
13835
  writeStdoutLine(JSON.stringify(report, null, 2));
13607
13836
  writeStderrLine(`test-delta: ${report.note}`);
@@ -13612,14 +13841,14 @@ var testDeltaCommand = {
13612
13841
  init_esbuild_shims();
13613
13842
  import { spawnSync as spawnSync6 } from "node:child_process";
13614
13843
  import {
13615
- mkdirSync as mkdirSync19,
13616
- writeFileSync as writeFileSync20,
13617
- readFileSync as readFileSync22,
13844
+ mkdirSync as mkdirSync20,
13845
+ writeFileSync as writeFileSync21,
13846
+ readFileSync as readFileSync23,
13618
13847
  existsSync as existsSync10,
13619
13848
  rmSync as rmSync8,
13620
- statSync as statSync7
13849
+ statSync as statSync8
13621
13850
  } from "node:fs";
13622
- import { dirname as dirname17, join as join16, resolve as resolve17 } from "node:path";
13851
+ import { dirname as dirname17, join as join17, resolve as resolve17 } from "node:path";
13623
13852
  import { tmpdir as tmpdir2 } from "node:os";
13624
13853
  var SERVER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
13625
13854
  function shellQuote(v) {
@@ -13631,7 +13860,7 @@ var LOG_MAX_BYTES = 8 * 1024 * 1024;
13631
13860
  var POLL_MS = 250;
13632
13861
  function logBytes(p) {
13633
13862
  try {
13634
- return statSync7(p).size;
13863
+ return statSync8(p).size;
13635
13864
  } catch {
13636
13865
  return 0;
13637
13866
  }
@@ -13737,13 +13966,13 @@ function runDrive(args) {
13737
13966
  waitMs(POLL_MS);
13738
13967
  }
13739
13968
  }
13740
- const dir = join16(tmpdir2(), `qwen-review-drive-${server}`);
13741
- mkdirSync19(dir, { recursive: true });
13742
- const scriptPath = join16(dir, "drive.sh");
13743
- const logPath = args.logPath ?? join16(dir, "drive.log");
13744
- const sentinelPath = join16(dir, "drive.rc");
13969
+ const dir = join17(tmpdir2(), `qwen-review-drive-${server}`);
13970
+ mkdirSync20(dir, { recursive: true });
13971
+ const scriptPath = join17(dir, "drive.sh");
13972
+ const logPath = args.logPath ?? join17(dir, "drive.log");
13973
+ const sentinelPath = join17(dir, "drive.rc");
13745
13974
  rmSync8(sentinelPath, { force: true });
13746
- writeFileSync20(scriptPath, wrapScript(args.script, sentinelPath), "utf8");
13975
+ writeFileSync21(scriptPath, wrapScript(args.script, sentinelPath), "utf8");
13747
13976
  const droveFrom = Date.now();
13748
13977
  let output = "";
13749
13978
  let exitCode = null;
@@ -13773,8 +14002,8 @@ function runDrive(args) {
13773
14002
  }
13774
14003
  const deadline = droveFrom + args.timeout * 1e3;
13775
14004
  for (; ; ) {
13776
- output = existsSync10(logPath) ? readFileSync22(logPath, "utf8") : "";
13777
- exitCode = existsSync10(sentinelPath) ? sentinelExitCode(readFileSync22(sentinelPath, "utf8")) : null;
14005
+ output = existsSync10(logPath) ? readFileSync23(logPath, "utf8") : "";
14006
+ exitCode = existsSync10(sentinelPath) ? sentinelExitCode(readFileSync23(sentinelPath, "utf8")) : null;
13778
14007
  if (exitCode !== null) {
13779
14008
  outcome = "completed";
13780
14009
  break;
@@ -13841,8 +14070,8 @@ var driveCommand = {
13841
14070
  const args = argv;
13842
14071
  const report = runDrive(args);
13843
14072
  if (args.out) {
13844
- mkdirSync19(dirname17(resolve17(args.out)), { recursive: true });
13845
- writeFileSync20(resolve17(args.out), JSON.stringify(report, null, 2));
14073
+ mkdirSync20(dirname17(resolve17(args.out)), { recursive: true });
14074
+ writeFileSync21(resolve17(args.out), JSON.stringify(report, null, 2));
13846
14075
  }
13847
14076
  writeStdoutLine(JSON.stringify(report, null, 2));
13848
14077
  writeStderrLine(`drive: ${report.note}`);
@@ -13859,7 +14088,7 @@ init_esbuild_shims();
13859
14088
  import {
13860
14089
  createServer
13861
14090
  } from "node:http";
13862
- import { appendFileSync, mkdirSync as mkdirSync20, writeFileSync as writeFileSync21 } from "node:fs";
14091
+ import { appendFileSync, mkdirSync as mkdirSync21, writeFileSync as writeFileSync22 } from "node:fs";
13863
14092
  import { dirname as dirname18, resolve as resolve18 } from "node:path";
13864
14093
  import { pathToFileURL } from "node:url";
13865
14094
  function messagesText(body) {
@@ -14116,8 +14345,8 @@ async function startMockProvider(args, respondOverride) {
14116
14345
  respond = fn;
14117
14346
  }
14118
14347
  const logPath = resolve18(args.log);
14119
- mkdirSync20(dirname18(logPath), { recursive: true });
14120
- writeFileSync21(logPath, "");
14348
+ mkdirSync21(dirname18(logPath), { recursive: true });
14349
+ writeFileSync22(logPath, "");
14121
14350
  let n = 0;
14122
14351
  const record = /* @__PURE__ */ __name((entry) => appendFileSync(logPath, `${JSON.stringify(entry)}
14123
14352
  `), "record");
@@ -14279,8 +14508,8 @@ var mockProviderCommand = {
14279
14508
  const args = argv;
14280
14509
  const { report, close } = await startMockProvider(args);
14281
14510
  if (args.out) {
14282
- mkdirSync20(dirname18(resolve18(args.out)), { recursive: true });
14283
- writeFileSync21(resolve18(args.out), JSON.stringify(report, null, 2));
14511
+ mkdirSync21(dirname18(resolve18(args.out)), { recursive: true });
14512
+ writeFileSync22(resolve18(args.out), JSON.stringify(report, null, 2));
14284
14513
  }
14285
14514
  writeStdoutLine(JSON.stringify(report, null, 2));
14286
14515
  writeStderrLine(`mock-provider: ${report.note}`);
@@ -14298,7 +14527,7 @@ var mockProviderCommand = {
14298
14527
  // packages/cli/src/commands/review/extract-step.ts
14299
14528
  init_esbuild_shims();
14300
14529
  var import_yaml = __toESM(require_dist(), 1);
14301
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync23, writeFileSync as writeFileSync22, chmodSync } from "node:fs";
14530
+ import { mkdirSync as mkdirSync22, readFileSync as readFileSync24, writeFileSync as writeFileSync23, chmodSync } from "node:fs";
14302
14531
  import { dirname as dirname19, resolve as resolve19 } from "node:path";
14303
14532
  function expressionsOf(...texts) {
14304
14533
  const seen = /* @__PURE__ */ new Set();
@@ -14546,7 +14775,7 @@ function runExtractStep(args) {
14546
14775
  const wfPath = resolve19(args.workflow);
14547
14776
  let text;
14548
14777
  try {
14549
- text = readFileSync23(wfPath, "utf8");
14778
+ text = readFileSync24(wfPath, "utf8");
14550
14779
  } catch (err) {
14551
14780
  throw new Error(
14552
14781
  `extract-step: cannot read ${args.workflow}: ${err.message}`
@@ -14613,7 +14842,7 @@ function runExtractStep(args) {
14613
14842
  const script = step.run;
14614
14843
  const stepLabel = String(step.name ?? step.id ?? index);
14615
14844
  const outPath = resolve19(args.out);
14616
- mkdirSync21(dirname19(outPath), { recursive: true });
14845
+ mkdirSync22(dirname19(outPath), { recursive: true });
14617
14846
  const header = [
14618
14847
  `#!/usr/bin/env ${shellCommand}`,
14619
14848
  ...commentLines(
@@ -14637,7 +14866,7 @@ function runExtractStep(args) {
14637
14866
  ),
14638
14867
  ""
14639
14868
  ].join("\n");
14640
- writeFileSync22(outPath, header + script + (script.endsWith("\n") ? "" : "\n"));
14869
+ writeFileSync23(outPath, header + script + (script.endsWith("\n") ? "" : "\n"));
14641
14870
  chmodSync(outPath, 493);
14642
14871
  return {
14643
14872
  workflow: args.workflow,
@@ -14698,7 +14927,7 @@ var extractStepCommand = {
14698
14927
 
14699
14928
  // packages/cli/src/commands/review/submit.ts
14700
14929
  init_esbuild_shims();
14701
- import { mkdirSync as mkdirSync22, readFileSync as readFileSync24 } from "node:fs";
14930
+ import { mkdirSync as mkdirSync23, readFileSync as readFileSync25 } from "node:fs";
14702
14931
 
14703
14932
  // packages/cli/src/commands/review/lib/receipt.ts
14704
14933
  init_esbuild_shims();
@@ -14720,7 +14949,7 @@ __name(parseReceiptIds, "parseReceiptIds");
14720
14949
  var EVENTS = /* @__PURE__ */ new Set(["APPROVE", "REQUEST_CHANGES", "COMMENT"]);
14721
14950
  function readReceiptIds(receiptPath) {
14722
14951
  try {
14723
- return parseReceiptIds(readFileSync24(receiptPath, "utf8"));
14952
+ return parseReceiptIds(readFileSync25(receiptPath, "utf8"));
14724
14953
  } catch {
14725
14954
  return [];
14726
14955
  }
@@ -14730,6 +14959,24 @@ function isDiffLine(n) {
14730
14959
  return typeof n === "number" && Number.isSafeInteger(n) && n > 0;
14731
14960
  }
14732
14961
  __name(isDiffLine, "isDiffLine");
14962
+ function normalizeInlineComments(comments, modelId, cliVersion) {
14963
+ if (typeof modelId !== "string" || modelId.trim() === "") return comments;
14964
+ const footer = reviewFooter(modelId, cliVersion);
14965
+ return comments.map(
14966
+ (comment) => (
14967
+ // An empty body stays empty: this runs BEFORE the consistency check, and
14968
+ // a footer pasted onto '' would hide the emptiness from the refusal that
14969
+ // names it ('has no body — an empty comment').
14970
+ typeof comment.body === "string" && comment.body.trim() !== "" ? {
14971
+ ...comment,
14972
+ body: `${comment.body.replace(REVIEW_FOOTER_RE, "")}
14973
+
14974
+ ${footer}`
14975
+ } : comment
14976
+ )
14977
+ );
14978
+ }
14979
+ __name(normalizeInlineComments, "normalizeInlineComments");
14733
14980
  function authorization(args) {
14734
14981
  return reviewWriteAuthorization({
14735
14982
  userAuthorized: args.userAuthorized,
@@ -14775,6 +15022,18 @@ __name(compose, "compose");
14775
15022
  function structuralProblems(payload) {
14776
15023
  const problems = [];
14777
15024
  if (!payload.commit_id) problems.push("`commit_id` is missing");
15025
+ if (payload.comments !== void 0 && !Array.isArray(payload.comments)) {
15026
+ problems.push(
15027
+ "`comments` is not an array \u2014 it is the list of findings this post carries; any other shape is not a list of findings."
15028
+ );
15029
+ }
15030
+ if (Array.isArray(payload.comments) && payload.comments.some(
15031
+ (c) => c === null || typeof c !== "object"
15032
+ )) {
15033
+ problems.push(
15034
+ "`comments` entries must each be an object \u2014 a finding is a path, a line and a body; any other shape is not a finding."
15035
+ );
15036
+ }
14778
15037
  if (payload.event !== void 0 || payload.body !== void 0) {
14779
15038
  problems.push(
14780
15039
  "the payload carries `event`/`body`. Those are computed here, from `state` and from the comments you attached \u2014 they are not inputs. Remove them. (A run that skipped `compose-review` and typed its own Approve is exactly what this refuses.)"
@@ -14855,7 +15114,7 @@ function runSubmit(args, cliVersion = "unknown") {
14855
15114
  }
14856
15115
  let payload;
14857
15116
  try {
14858
- payload = JSON.parse(readFileSync24(args.review, "utf8"));
15117
+ payload = JSON.parse(readFileSync25(args.review, "utf8"));
14859
15118
  } catch (err) {
14860
15119
  throw new Error(
14861
15120
  `Cannot read review JSON ${args.review}: ${err.message}`
@@ -14880,6 +15139,14 @@ Posting is a public, irreversible write, and this run has no authorisation for o
14880
15139
  ` + structural.map((p) => ` - ${p}`).join("\n")
14881
15140
  );
14882
15141
  }
15142
+ payload = {
15143
+ ...payload,
15144
+ comments: normalizeInlineComments(
15145
+ payload.comments ?? [],
15146
+ payload.state?.modelId,
15147
+ cliVersion
15148
+ )
15149
+ };
14883
15150
  let event2;
14884
15151
  let body;
14885
15152
  let cappedBy;
@@ -14931,7 +15198,7 @@ Posting is a public, irreversible write, and this run has no authorisation for o
14931
15198
  const receiptPath = tmpFile(`pr-${args.pr}`, "submit-receipt.json");
14932
15199
  const priorIds = readReceiptIds(receiptPath);
14933
15200
  const reviewIds = [.../* @__PURE__ */ new Set([...priorIds, reviewId])];
14934
- mkdirSync22(REVIEW_TMP_DIR, { recursive: true });
15201
+ mkdirSync23(REVIEW_TMP_DIR, { recursive: true });
14935
15202
  atomicWriteFileSync(
14936
15203
  receiptPath,
14937
15204
  `${JSON.stringify({ reviewIds, event: event2, postedAt: (/* @__PURE__ */ new Date()).toISOString() })}
@@ -14988,7 +15255,8 @@ var submitCommand = {
14988
15255
  describe: "Check authorisation and payload consistency, then stop."
14989
15256
  }), "builder"),
14990
15257
  handler: /* @__PURE__ */ __name(async (argv) => {
14991
- runSubmit(argv, await getCliVersion());
15258
+ const cliVersion = footerVersion(process.env["QWEN_CODE_STARTUP_VERSION"]) ?? await getCliVersion();
15259
+ runSubmit(argv, cliVersion);
14992
15260
  }, "handler")
14993
15261
  };
14994
15262
 
@@ -14996,18 +15264,18 @@ var submitCommand = {
14996
15264
  init_esbuild_shims();
14997
15265
  import { spawnSync as spawnSync7 } from "node:child_process";
14998
15266
  import {
14999
- mkdirSync as mkdirSync23,
15267
+ mkdirSync as mkdirSync24,
15000
15268
  readdirSync as readdirSync5,
15001
- writeFileSync as writeFileSync23,
15002
- readFileSync as readFileSync25,
15269
+ writeFileSync as writeFileSync24,
15270
+ readFileSync as readFileSync26,
15003
15271
  rmSync as rmSync9,
15004
15272
  lstatSync as lstatSync4,
15005
15273
  existsSync as existsSync11,
15006
- statSync as statSync8,
15274
+ statSync as statSync9,
15007
15275
  symlinkSync
15008
15276
  } from "node:fs";
15009
15277
  import { createRequire } from "node:module";
15010
- import { dirname as dirname20, join as join17, isAbsolute as isAbsolute3, sep as sep3 } from "node:path";
15278
+ import { dirname as dirname20, join as join18, isAbsolute as isAbsolute3, sep as sep3 } from "node:path";
15011
15279
  var FIXTURE_DIR_RE = /(^|\/)(__fixtures__|__mocks__|__snapshots__|fixtures)\//;
15012
15280
  function planTestEfficacy(files, workspaceGlobs) {
15013
15281
  const tests = files.filter((f) => f.kind === "test").map((f) => f.path);
@@ -15530,23 +15798,24 @@ function gitOut2(cwd, ...args) {
15530
15798
  return (r.stdout ?? "").trim();
15531
15799
  }
15532
15800
  __name(gitOut2, "gitOut");
15533
- function findVitestBin(worktree) {
15534
- const req = createRequire(join17(worktree, "noop.js"));
15801
+ function findVitestBin(worktree, resolveModule = createRequire(
15802
+ join18(worktree, "noop.js")
15803
+ ).resolve) {
15535
15804
  let pkgPath;
15536
15805
  try {
15537
- pkgPath = req.resolve("vitest/package.json");
15806
+ pkgPath = resolveModule("vitest/package.json");
15538
15807
  } catch (error) {
15539
15808
  if (error.code === "MODULE_NOT_FOUND") {
15540
15809
  throw new Error(`vitest not found searching up from ${worktree}`);
15541
15810
  }
15542
15811
  throw error;
15543
15812
  }
15544
- const pkg = JSON.parse(readFileSync25(pkgPath, "utf8"));
15813
+ const pkg = JSON.parse(readFileSync26(pkgPath, "utf8"));
15545
15814
  const bin = pkg.bin?.vitest;
15546
15815
  if (!bin) {
15547
15816
  throw new Error(`vitest package at ${pkgPath} declares no "vitest" bin`);
15548
15817
  }
15549
- return join17(dirname20(pkgPath), bin);
15818
+ return join18(dirname20(pkgPath), bin);
15550
15819
  }
15551
15820
  __name(findVitestBin, "findVitestBin");
15552
15821
  function gitCapture(cwd, ...args) {
@@ -15572,7 +15841,7 @@ function safeRmWithin(worktree, relPath) {
15572
15841
  const parts = relPath.split(/[/\\]+/).filter((s) => s && s !== ".");
15573
15842
  let cur = worktree;
15574
15843
  for (let i = 0; i < parts.length; i++) {
15575
- cur = join17(cur, parts[i]);
15844
+ cur = join18(cur, parts[i]);
15576
15845
  let st;
15577
15846
  try {
15578
15847
  st = lstatSync4(cur);
@@ -15597,15 +15866,15 @@ __name(probeCleanupFailureDetail, "probeCleanupFailureDetail");
15597
15866
  function exposeDependencies(probeTree, dependencyRoot) {
15598
15867
  const done = { linked: 0, failed: 0 };
15599
15868
  if (probeTree === dependencyRoot) return done;
15600
- const source = join17(dependencyRoot, "node_modules");
15601
- const target = join17(probeTree, "node_modules");
15869
+ const source = join18(dependencyRoot, "node_modules");
15870
+ const target = join18(probeTree, "node_modules");
15602
15871
  if (!existsSync11(source) || existsSync11(target)) return done;
15603
- mkdirSync23(target);
15872
+ mkdirSync24(target);
15604
15873
  const linkType = process.platform === "win32" ? "junction" : "dir";
15605
15874
  for (const entry of readdirSync5(source, { withFileTypes: true })) {
15606
15875
  if (entry.name === ".vite" || entry.name === ".vite-temp") continue;
15607
- const sourceEntry = join17(source, entry.name);
15608
- const targetEntry = join17(target, entry.name);
15876
+ const sourceEntry = join18(source, entry.name);
15877
+ const targetEntry = join18(target, entry.name);
15609
15878
  let sourceStats;
15610
15879
  try {
15611
15880
  sourceStats = lstatSync4(sourceEntry);
@@ -15615,7 +15884,7 @@ function exposeDependencies(probeTree, dependencyRoot) {
15615
15884
  }
15616
15885
  if (sourceStats.isSymbolicLink()) {
15617
15886
  try {
15618
- if (!statSync8(sourceEntry).isDirectory()) continue;
15887
+ if (!statSync9(sourceEntry).isDirectory()) continue;
15619
15888
  } catch {
15620
15889
  continue;
15621
15890
  }
@@ -15625,7 +15894,7 @@ function exposeDependencies(probeTree, dependencyRoot) {
15625
15894
  if (entry.name.startsWith("@")) {
15626
15895
  let pkgs;
15627
15896
  try {
15628
- mkdirSync23(targetEntry);
15897
+ mkdirSync24(targetEntry);
15629
15898
  pkgs = readdirSync5(sourceEntry);
15630
15899
  } catch {
15631
15900
  done.failed++;
@@ -15633,7 +15902,7 @@ function exposeDependencies(probeTree, dependencyRoot) {
15633
15902
  }
15634
15903
  for (const pkg of pkgs) {
15635
15904
  try {
15636
- symlinkSync(join17(sourceEntry, pkg), join17(targetEntry, pkg), linkType);
15905
+ symlinkSync(join18(sourceEntry, pkg), join18(targetEntry, pkg), linkType);
15637
15906
  done.linked++;
15638
15907
  } catch {
15639
15908
  done.failed++;
@@ -15779,10 +16048,10 @@ function newSideLength(header) {
15779
16048
  __name(newSideLength, "newSideLength");
15780
16049
  function runOneHunkProbe(probeTree, hunk, probes, deadlineAt, now = Date.now) {
15781
16050
  const { patch: _patch, ...meta } = hunk;
15782
- const abs = join17(probeTree, hunk.file);
16051
+ const abs = join18(probeTree, hunk.file);
15783
16052
  let original;
15784
16053
  try {
15785
- original = readFileSync25(abs, "utf8");
16054
+ original = readFileSync26(abs, "utf8");
15786
16055
  } catch (e) {
15787
16056
  return {
15788
16057
  ...meta,
@@ -15808,21 +16077,21 @@ function runOneHunkProbe(probeTree, hunk, probes, deadlineAt, now = Date.now) {
15808
16077
  const detail = verdict === "killed" ? "the suite went red with this hunk reverted \u2014 a test covers this change" : verdict === "survived" ? "every affected test still PASSED with this hunk reverted \u2014 no test in this diff fails when the change is undone" : "the tree with this hunk reverted produced no clean verdict (likely a compile or import error) \u2014 not evidence either way";
15809
16078
  return { ...meta, verdict, detail };
15810
16079
  } finally {
15811
- mkdirSync23(dirname20(abs), { recursive: true });
15812
- writeFileSync23(abs, original, "utf8");
16080
+ mkdirSync24(dirname20(abs), { recursive: true });
16081
+ writeFileSync24(abs, original, "utf8");
15813
16082
  }
15814
16083
  }
15815
16084
  __name(runOneHunkProbe, "runOneHunkProbe");
15816
16085
  function runControlMutant(probeTree, probeFile, deadlineAt, now = Date.now) {
15817
- const abs = join17(probeTree, probeFile);
16086
+ const abs = join18(probeTree, probeFile);
15818
16087
  let original;
15819
16088
  try {
15820
- original = readFileSync25(abs, "utf8");
16089
+ original = readFileSync26(abs, "utf8");
15821
16090
  } catch {
15822
16091
  return null;
15823
16092
  }
15824
16093
  try {
15825
- writeFileSync23(
16094
+ writeFileSync24(
15826
16095
  abs,
15827
16096
  `${original}
15828
16097
  ;import { it as __qcIt, expect as __qcExpect } from 'vitest';
@@ -15835,13 +16104,13 @@ __qcIt('QWEN-REVIEW-POSITIVE-CONTROL', () => {
15835
16104
  const { perFile } = runProbeSuite(probeTree, [probeFile], deadlineAt, now);
15836
16105
  return perFile.some((r) => r.verdict === "gated");
15837
16106
  } finally {
15838
- writeFileSync23(abs, original, "utf8");
16107
+ writeFileSync24(abs, original, "utf8");
15839
16108
  }
15840
16109
  }
15841
16110
  __name(runControlMutant, "runControlMutant");
15842
16111
  function runOneMutant(probeTree, mutant, probes, deadlineAt, now = Date.now, dependencyRoot = probeTree) {
15843
- const abs = join17(probeTree, mutant.file);
15844
- const original = readFileSync25(abs, "utf8");
16112
+ const abs = join18(probeTree, mutant.file);
16113
+ const original = readFileSync26(abs, "utf8");
15845
16114
  const lines2 = original.split("\n");
15846
16115
  if ((lines2[mutant.line - 1] ?? "").trim() !== mutant.statement) {
15847
16116
  return {
@@ -15857,7 +16126,7 @@ function runOneMutant(probeTree, mutant, probes, deadlineAt, now = Date.now, dep
15857
16126
  lines2.splice(mutant.line - 1, 1);
15858
16127
  }
15859
16128
  try {
15860
- writeFileSync23(abs, lines2.join("\n"), "utf8");
16129
+ writeFileSync24(abs, lines2.join("\n"), "utf8");
15861
16130
  const { perFile } = runProbeSuite(
15862
16131
  probeTree,
15863
16132
  probes,
@@ -15869,7 +16138,7 @@ function runOneMutant(probeTree, mutant, probes, deadlineAt, now = Date.now, dep
15869
16138
  const detail = verdict === "killed" ? `the suite went red with this statement ${what} \u2014 a test catches it` : verdict === "survived" ? `every affected test still PASSED with this statement ${what} \u2014 no test fails ${mutant.mutated === void 0 ? "when it is removed" : "when it changes"}` : "the mutated tree produced no clean verdict (likely a compile or import error) \u2014 not evidence either way";
15870
16139
  return { ...mutant, verdict, detail };
15871
16140
  } finally {
15872
- writeFileSync23(abs, original, "utf8");
16141
+ writeFileSync24(abs, original, "utf8");
15873
16142
  }
15874
16143
  }
15875
16144
  __name(runOneMutant, "runOneMutant");
@@ -15908,9 +16177,9 @@ async function runTestEfficacy(args) {
15908
16177
  const now = args.now ?? Date.now;
15909
16178
  const startedAt = now();
15910
16179
  const { report, worktree, base, out } = args;
15911
- const plan = JSON.parse(readFileSync25(report, "utf8"));
16180
+ const plan = JSON.parse(readFileSync26(report, "utf8"));
15912
16181
  const rootPkg = JSON.parse(
15913
- readFileSync25(`${worktree}/package.json`, "utf8")
16182
+ readFileSync26(`${worktree}/package.json`, "utf8")
15914
16183
  );
15915
16184
  const globs = rootPkg.workspaces ?? [];
15916
16185
  const { unreachable, probes, revert } = planTestEfficacy(
@@ -15918,8 +16187,8 @@ async function runTestEfficacy(args) {
15918
16187
  globs
15919
16188
  );
15920
16189
  for (const p of revert) {
15921
- const norm = join17(worktree, p);
15922
- const root = join17(worktree, ".");
16190
+ const norm = join18(worktree, p);
16191
+ const root = join18(worktree, ".");
15923
16192
  if (isAbsolute3(p) || norm !== root && !norm.startsWith(root + sep3)) {
15924
16193
  throw new Error(
15925
16194
  `refusing to run: revert path escapes the worktree: ${JSON.stringify(p)}`
@@ -16290,8 +16559,8 @@ async function runTestEfficacy(args) {
16290
16559
  findings,
16291
16560
  cleanupFailure
16292
16561
  };
16293
- mkdirSync23(dirname20(out), { recursive: true });
16294
- writeFileSync23(out, JSON.stringify(result, null, 2), "utf8");
16562
+ mkdirSync24(dirname20(out), { recursive: true });
16563
+ writeFileSync24(out, JSON.stringify(result, null, 2), "utf8");
16295
16564
  writeStdoutLine(
16296
16565
  `Wrote test-efficacy report to ${out} (${unreachable.length} unreachable, ${results.length} probed, ${mutantResults.length} mutant(s), ${hunkResults.length} hunk probe(s), ${findings.length} finding(s))`
16297
16566
  );
@@ -16368,8 +16637,8 @@ var testEfficacyCommand = {
16368
16637
 
16369
16638
  // packages/cli/src/commands/review/test-plan.ts
16370
16639
  init_esbuild_shims();
16371
- import { existsSync as existsSync12, mkdirSync as mkdirSync24, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "node:fs";
16372
- import { dirname as dirname21, join as join18, normalize, resolve as resolve20 } from "node:path";
16640
+ import { existsSync as existsSync12, mkdirSync as mkdirSync25, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "node:fs";
16641
+ import { dirname as dirname21, join as join19, normalize, resolve as resolve20 } from "node:path";
16373
16642
  var PLAN_NAME_RE = /(test\s*plan|\btesting\b|how\s+(?:has\s+this|to)\s+(?:been\s+)?test(?:ed)?|测试计划|测试方案|测试步骤)/i;
16374
16643
  var HEADING_LINE_RE = /^(#{1,6})(?:[ \t](.*))?$/;
16375
16644
  var BOLD_LINE_RE = /^\*\*([^*\n]+)\*\*:?\s*$/;
@@ -16572,7 +16841,7 @@ function rulePath(text, worktree, changed) {
16572
16841
  };
16573
16842
  }
16574
16843
  const ignored = isGitIgnored(worktree, path3);
16575
- if (existsSync12(join18(worktree, path3))) {
16844
+ if (existsSync12(join19(worktree, path3))) {
16576
16845
  return {
16577
16846
  kind: "path",
16578
16847
  text,
@@ -16643,7 +16912,7 @@ function ruleCommand(text, worktree, buildTest) {
16643
16912
  let rootScripts = [];
16644
16913
  try {
16645
16914
  const rootPkg = JSON.parse(
16646
- readFileSync26(join18(worktree, "package.json"), "utf8")
16915
+ readFileSync27(join19(worktree, "package.json"), "utf8")
16647
16916
  );
16648
16917
  rootScripts = Object.keys(rootPkg.scripts ?? {});
16649
16918
  } catch {
@@ -16721,7 +16990,7 @@ __name(fetchPrBody, "fetchPrBody");
16721
16990
  function runTestPlan(args, fetchBody = fetchPrBody) {
16722
16991
  let plan;
16723
16992
  try {
16724
- plan = JSON.parse(readFileSync26(args.plan, "utf8"));
16993
+ plan = JSON.parse(readFileSync27(args.plan, "utf8"));
16725
16994
  } catch (err) {
16726
16995
  throw new Error(
16727
16996
  `test-plan: cannot read the plan ${args.plan}: ${err.message}`
@@ -16756,7 +17025,7 @@ function runTestPlan(args, fetchBody = fetchPrBody) {
16756
17025
  if (args.buildTest) {
16757
17026
  try {
16758
17027
  buildTest = JSON.parse(
16759
- readFileSync26(args.buildTest, "utf8")
17028
+ readFileSync27(args.buildTest, "utf8")
16760
17029
  );
16761
17030
  } catch {
16762
17031
  buildTest = null;
@@ -16813,8 +17082,8 @@ var testPlanCommand = {
16813
17082
  try {
16814
17083
  const report = runTestPlan(args);
16815
17084
  if (args.out) {
16816
- mkdirSync24(dirname21(resolve20(args.out)), { recursive: true });
16817
- writeFileSync24(resolve20(args.out), JSON.stringify(report, null, 2));
17085
+ mkdirSync25(dirname21(resolve20(args.out)), { recursive: true });
17086
+ writeFileSync25(resolve20(args.out), JSON.stringify(report, null, 2));
16818
17087
  }
16819
17088
  writeStdoutLine(JSON.stringify(report, null, 2));
16820
17089
  writeStderrLine(`test-plan: ${report.note}`);
@@ -16828,8 +17097,8 @@ var testPlanCommand = {
16828
17097
  // packages/cli/src/commands/review/cleanup.ts
16829
17098
  init_esbuild_shims();
16830
17099
  import { execFileSync as execFileSync5 } from "node:child_process";
16831
- import { existsSync as existsSync13, readFileSync as readFileSync27, readdirSync as readdirSync6, rmSync as rmSync10 } from "node:fs";
16832
- import { join as join19 } from "node:path";
17100
+ import { existsSync as existsSync13, readFileSync as readFileSync28, readdirSync as readdirSync6, rmSync as rmSync10 } from "node:fs";
17101
+ import { join as join20 } from "node:path";
16833
17102
  var AUTOMATION_MARKER = "<!-- qwen-";
16834
17103
  function isAutomationComment(body) {
16835
17104
  return (body ?? "").trimStart().startsWith(AUTOMATION_MARKER);
@@ -16860,7 +17129,7 @@ var OWNER_REPO_RE = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
16860
17129
  function readAuditWindow(target, expectedPrNumber) {
16861
17130
  let raw;
16862
17131
  try {
16863
- raw = readFileSync27(tmpFile(target, "fetch.json"), "utf8");
17132
+ raw = readFileSync28(tmpFile(target, "fetch.json"), "utf8");
16864
17133
  } catch (err) {
16865
17134
  const code = err.code;
16866
17135
  return code === "ENOENT" ? { skip: "no fetch report" } : {
@@ -16907,7 +17176,7 @@ function readSubmitReceipt(target) {
16907
17176
  try {
16908
17177
  return new Set(
16909
17178
  parseReceiptIds(
16910
- readFileSync27(tmpFile(target, "submit-receipt.json"), "utf8")
17179
+ readFileSync28(tmpFile(target, "submit-receipt.json"), "utf8")
16911
17180
  )
16912
17181
  );
16913
17182
  } catch {
@@ -17042,7 +17311,7 @@ function runCleanup(target) {
17042
17311
  }
17043
17312
  for (const file of tmpEntries) {
17044
17313
  if (!file.startsWith(prefix)) continue;
17045
- const full = join19(REVIEW_TMP_DIR, file);
17314
+ const full = join20(REVIEW_TMP_DIR, file);
17046
17315
  try {
17047
17316
  rmSync10(full, { recursive: true, force: true });
17048
17317
  writeStdoutLine(`Removed temp file: ${full}`);
@@ -17076,8 +17345,8 @@ var cleanupCommand = {
17076
17345
  // packages/cli/src/commands/review/run.ts
17077
17346
  init_esbuild_shims();
17078
17347
  import { spawn, execFileSync as execFileSync6 } from "node:child_process";
17079
- import { readdirSync as readdirSync7, readFileSync as readFileSync28, realpathSync as realpathSync3, statSync as statSync9 } from "node:fs";
17080
- import { dirname as dirname22, join as join20, resolve as resolve21 } from "node:path";
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";
17081
17350
  var COMPOSED_PATTERN = /^qwen-review-.*composed\.json$/;
17082
17351
  var COMPOSED_POLL_MS = 250;
17083
17352
  var SIGNAL_EXIT_CODES = {
@@ -17111,10 +17380,10 @@ function newestArtifactSince(dir, pattern, startMs) {
17111
17380
  }
17112
17381
  for (const name of names) {
17113
17382
  if (!pattern.test(name)) continue;
17114
- const path3 = join20(dir, name);
17383
+ const path3 = join21(dir, name);
17115
17384
  let mtime;
17116
17385
  try {
17117
- mtime = statSync9(path3).mtimeMs;
17386
+ mtime = statSync10(path3).mtimeMs;
17118
17387
  } catch {
17119
17388
  continue;
17120
17389
  }
@@ -17132,7 +17401,7 @@ function exitCodeFor(completed, event2, failOn) {
17132
17401
  __name(exitCodeFor, "exitCodeFor");
17133
17402
  function readComposed(path3) {
17134
17403
  try {
17135
- const parsed = JSON.parse(readFileSync28(path3, "utf8"));
17404
+ const parsed = JSON.parse(readFileSync29(path3, "utf8"));
17136
17405
  return typeof parsed.event === "string" ? parsed : null;
17137
17406
  } catch {
17138
17407
  return null;
@@ -17368,14 +17637,14 @@ init_esbuild_shims();
17368
17637
  import {
17369
17638
  existsSync as existsSync14,
17370
17639
  lstatSync as lstatSync5,
17371
- mkdirSync as mkdirSync25,
17372
- readFileSync as readFileSync29,
17373
- statSync as statSync10
17640
+ mkdirSync as mkdirSync26,
17641
+ readFileSync as readFileSync30,
17642
+ statSync as statSync11
17374
17643
  } from "node:fs";
17375
17644
  import {
17376
17645
  dirname as dirname23,
17377
17646
  isAbsolute as isAbsolute4,
17378
- join as join21,
17647
+ join as join22,
17379
17648
  relative as relative3,
17380
17649
  resolve as resolve22,
17381
17650
  sep as sep4,
@@ -17405,7 +17674,7 @@ function rejectSymlinkPath(root, path3, label2) {
17405
17674
  const rel = relative3(root, path3);
17406
17675
  let current = root;
17407
17676
  for (const segment of rel.split(sep4)) {
17408
- current = join21(current, segment);
17677
+ current = join22(current, segment);
17409
17678
  if (existsSync14(current) && lstatSync5(current).isSymbolicLink()) {
17410
17679
  throw new Error(`${label2} must not traverse a symbolic link.`);
17411
17680
  }
@@ -17415,14 +17684,14 @@ __name(rejectSymlinkPath, "rejectSymlinkPath");
17415
17684
  function sameFile(left, right) {
17416
17685
  if (left === right) return true;
17417
17686
  if (!existsSync14(left) || !existsSync14(right)) return false;
17418
- const leftStat = statSync10(left);
17419
- const rightStat = statSync10(right);
17687
+ const leftStat = statSync11(left);
17688
+ const rightStat = statSync11(right);
17420
17689
  return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
17421
17690
  }
17422
17691
  __name(sameFile, "sameFile");
17423
17692
  function readText(path3, label2) {
17424
17693
  try {
17425
- return readFileSync29(path3, "utf8");
17694
+ return readFileSync30(path3, "utf8");
17426
17695
  } catch (error) {
17427
17696
  throw new Error(
17428
17697
  `Could not read the ${label2} file at ${JSON.stringify(path3)}: ${error instanceof Error ? error.message : String(error)}`
@@ -17589,7 +17858,7 @@ function saveReviewArtifact(args) {
17589
17858
  const verdict = validateVerdict(readJson2(composedPath, "composed verdict"));
17590
17859
  let reportIsFile;
17591
17860
  try {
17592
- reportIsFile = statSync10(reportPath).isFile();
17861
+ reportIsFile = statSync11(reportPath).isFile();
17593
17862
  } catch {
17594
17863
  }
17595
17864
  if (reportIsFile === false) {
@@ -17609,7 +17878,7 @@ function saveReviewArtifact(args) {
17609
17878
  outcomesRecorded: findings.outcomesRecorded,
17610
17879
  markdownReportPath
17611
17880
  };
17612
- mkdirSync25(dirname23(outputPath), { recursive: true });
17881
+ mkdirSync26(dirname23(outputPath), { recursive: true });
17613
17882
  atomicWriteFileSync(
17614
17883
  toNamespacedPath(outputPath),
17615
17884
  `${JSON.stringify(document, null, 2)}
@@ -17864,10 +18133,10 @@ var updateCommand3 = {
17864
18133
  stdioHelpers,
17865
18134
  { updateEventEmitter }
17866
18135
  ] = await Promise.all([
17867
- import("./settings-E6H3AURD.js"),
17868
- import("./updateCheck-ZXRCGY66.js"),
17869
- import("./installationInfo-OFDYLDFD.js"),
17870
- import("./standalone-update-NYYZEHLD.js"),
18136
+ import("./settings-NX4EUIE6.js"),
18137
+ import("./updateCheck-FDAVGOFT.js"),
18138
+ import("./installationInfo-AEGIIQAT.js"),
18139
+ import("./standalone-update-ICW7H5IF.js"),
17871
18140
  import("./stdioHelpers-HGIYTWAY.js"),
17872
18141
  import("./updateEventEmitter-5MKC7BLQ.js")
17873
18142
  ]);
@@ -18713,7 +18982,7 @@ var SessionIdConflictError = class extends Error {
18713
18982
  this.sessionId = sessionId;
18714
18983
  }
18715
18984
  };
18716
- async function loadCliConfig(settings, argv, cwd = process.cwd(), overrideExtensions, hooksConfig, disabledSkillNamesProvider, sessionMcpServers, settingsWatcher, throwOnSessionIdConflict = false) {
18985
+ async function loadCliConfig(settings, argv, cwd = process.cwd(), overrideExtensions, hooksConfig, disabledSkillNamesProvider, sessionMcpServers, settingsWatcher, throwOnSessionIdConflict = false, hostPolicy) {
18717
18986
  const debugMode = isDebugMode(argv);
18718
18987
  if (debugMode && process.env["QWEN_DEBUG_LOG_FILE"] === void 0) {
18719
18988
  process.env["QWEN_DEBUG_LOG_FILE"] = "1";
@@ -19034,7 +19303,7 @@ async function loadCliConfig(settings, argv, cwd = process.cwd(), overrideExtens
19034
19303
  disabledSlashCommands: disabledSlashCommands.length > 0 ? disabledSlashCommands : void 0,
19035
19304
  disabledSkillNamesProvider: bareMode || safeMode ? void 0 : disabledSkillNamesProvider,
19036
19305
  terminalImageRenderSupportProvider: interactive ? async () => {
19037
- const { getTerminalImageRenderSupport } = await import("./terminal-image-renderer-QRSCS2BE.js");
19306
+ const { getTerminalImageRenderSupport } = await import("./terminal-image-renderer-PW6Z6VFY.js");
19038
19307
  return getTerminalImageRenderSupport();
19039
19308
  } : void 0,
19040
19309
  disabledSkillLevels: bareMode || safeMode || !Array.isArray(settings.skills?.disabledLevels) ? void 0 : settings.skills.disabledLevels.filter(isSkillLevel),
@@ -19051,6 +19320,7 @@ async function loadCliConfig(settings, argv, cwd = process.cwd(), overrideExtens
19051
19320
  deny: mergedDeny.length > 0 ? mergedDeny : void 0,
19052
19321
  autoMode: bareMode || safeMode ? void 0 : settings.permissions?.autoMode
19053
19322
  },
19323
+ toolInvocationGuard: hostPolicy?.toolInvocationGuard,
19054
19324
  // Permission rule persistence callback (writes to settings files).
19055
19325
  onPersistPermissionRule: /* @__PURE__ */ __name(async (scope, ruleType, rule) => {
19056
19326
  const currentSettings = loadSettings(cwd);