@qwen-code/qwen-code 0.21.13 → 0.21.14-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 (293) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +13 -7
  2. package/bundled/qc-helper/docs/features/code-review.md +5 -1
  3. package/bundled/qc-helper/docs/features/commands.md +120 -8
  4. package/bundled/qc-helper/docs/features/sub-agents.md +2 -2
  5. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
  6. package/bundled/qc-helper/docs/qwen-serve.md +20 -3
  7. package/bundled/review/SKILL.md +50 -30
  8. package/chunks/{MaxSizedBox-UQALOVVT.js → MaxSizedBox-3PZITE2Y.js} +24 -23
  9. package/chunks/{StandaloneSessionPicker-KEGXNUG6.js → StandaloneSessionPicker-2C34PNGO.js} +41 -40
  10. package/chunks/{acp-startup-profiler-NMDXYGDN.js → acp-startup-profiler-HUYGO57H.js} +2 -2
  11. package/chunks/{acpAgent-XPES32S7.js → acpAgent-3J4NHAYT.js} +626 -141
  12. package/chunks/{agent-DPTOZFEM.js → agent-VFX4RPP5.js} +22 -21
  13. package/chunks/{agent-headless-GJCQMURW.js → agent-headless-6WCF4J6N.js} +22 -21
  14. package/chunks/{anthropicContentGenerator-G7BVXTKN.js → anthropicContentGenerator-M7XRJMSK.js} +3 -3
  15. package/chunks/{bridge-YNQBAA4Z.js → bridge-XR5ZSR7U.js} +26 -25
  16. package/chunks/{ca-4CQ6MYNQ.js → ca-SLZJD6QH.js} +8 -0
  17. package/chunks/{channel-management-service-GWY2GAIC.js → channel-management-service-X6LCQUAD.js} +1 -1
  18. package/chunks/{channel-settings-store-WNWYFHG7.js → channel-settings-store-Z7BUEUJE.js} +30 -29
  19. package/chunks/{channel-worker-group-7LXCMZ77.js → channel-worker-group-TJ35JDPE.js} +2 -2
  20. package/chunks/{channel-worker-manager-RYEME4ZZ.js → channel-worker-manager-G5LKWGOG.js} +2 -2
  21. package/chunks/{chunk-MLPXSYXR.js → chunk-25GHLMQQ.js} +25 -16
  22. package/chunks/chunk-2C6HJMG3.js +757 -0
  23. package/chunks/{chunk-TUGSVUJB.js → chunk-2JXDFSVE.js} +5 -5
  24. package/chunks/{chunk-AS5IN4GK.js → chunk-2OA3JMRD.js} +3 -3
  25. package/chunks/chunk-3PWCMXIR.js +9169 -0
  26. package/chunks/{chunk-U3VNBPUO.js → chunk-4KQ2TI2K.js} +2 -2
  27. package/chunks/{chunk-NEFOOD54.js → chunk-4V4DFJBS.js} +2 -2
  28. package/chunks/{chunk-OMLJNPBE.js → chunk-4ZMS3JCR.js} +1 -0
  29. package/chunks/{chunk-PP4FUZNV.js → chunk-55PIFSP2.js} +2 -2
  30. package/chunks/{chunk-3U3VAL47.js → chunk-57KOJ2KZ.js} +1 -1
  31. package/chunks/{chunk-A4QRWUDE.js → chunk-5IYS4WWR.js} +1 -1
  32. package/chunks/{chunk-TS6625XH.js → chunk-5MK45KZ3.js} +9 -5
  33. package/chunks/{chunk-CU6GJD55.js → chunk-6DFPR7CS.js} +1 -1
  34. package/chunks/{chunk-V57QC6WW.js → chunk-6LAPGPVA.js} +5 -3
  35. package/chunks/{chunk-OOQUVWIG.js → chunk-6PDOHRN6.js} +4 -4
  36. package/chunks/{chunk-UZPM4XHR.js → chunk-6VDPDHIP.js} +29 -8
  37. package/chunks/{chunk-O4D7SPJN.js → chunk-73G3Z7QS.js} +3 -3
  38. package/chunks/{chunk-QIH2HAEN.js → chunk-7OCSX7FC.js} +1 -1
  39. package/chunks/{chunk-OVZPVYZB.js → chunk-AKBOLMUF.js} +95 -17
  40. package/chunks/{chunk-DGK6P3BQ.js → chunk-AQBHJ2IG.js} +10 -10
  41. package/chunks/{chunk-JNDY2MDR.js → chunk-BOJNAPUE.js} +1 -1
  42. package/chunks/{chunk-NHDR76JX.js → chunk-BQWNIPTE.js} +1 -1
  43. package/chunks/{chunk-AA2BEKV3.js → chunk-CH5OFRV7.js} +1 -1
  44. package/chunks/{chunk-MS7GNABG.js → chunk-CXJHQVEK.js} +8 -0
  45. package/chunks/{chunk-K5IDV3PC.js → chunk-D34RDOLP.js} +12 -2
  46. package/chunks/{chunk-OXCMMLED.js → chunk-DGJ7O55J.js} +1 -1
  47. package/chunks/{chunk-BKPPWD33.js → chunk-DRKYT2TR.js} +1 -1
  48. package/chunks/{chunk-P7MPQI75.js → chunk-DVR7XKO5.js} +1 -1
  49. package/chunks/{chunk-MRMJCLIY.js → chunk-DZCV3ZYU.js} +2 -2
  50. package/chunks/{chunk-EZ5RP345.js → chunk-E5RS7LF4.js} +40 -9
  51. package/chunks/{chunk-4NFY2S7N.js → chunk-E7REAOTN.js} +15 -0
  52. package/chunks/chunk-EOCQCNV4.js +3887 -0
  53. package/chunks/{chunk-BVJS5BSP.js → chunk-FCTLOVYW.js} +1 -1
  54. package/chunks/{chunk-DGZEMW5R.js → chunk-FS5NGKWC.js} +1 -1
  55. package/chunks/{chunk-XHRY7BXD.js → chunk-G6FFFICU.js} +3 -3
  56. package/chunks/{chunk-NM5V5OVW.js → chunk-GV3OIADZ.js} +2 -2
  57. package/chunks/{chunk-QV5YN5YD.js → chunk-HGPMOXLZ.js} +5 -5
  58. package/chunks/{chunk-GMIEIY3Y.js → chunk-I3N2Z25H.js} +1 -1
  59. package/chunks/{chunk-RIAABG2K.js → chunk-I7NTHW4C.js} +1 -1
  60. package/chunks/{chunk-HUTNYWBG.js → chunk-IOTPI425.js} +18 -10
  61. package/chunks/{chunk-ZYYTZUI2.js → chunk-ISRHAMNL.js} +3 -3
  62. package/chunks/{chunk-BHILXOC3.js → chunk-J63PKMYA.js} +1 -1
  63. package/chunks/{chunk-KD5BOPLP.js → chunk-J6YS7Z25.js} +98 -4
  64. package/chunks/{chunk-GO7STP6N.js → chunk-K3CECR5C.js} +4 -4
  65. package/chunks/{chunk-RVOJ2FBP.js → chunk-KC4WMLZO.js} +1486 -10574
  66. package/chunks/{chunk-IGGGG5CX.js → chunk-KSGWAYNE.js} +4580 -1652
  67. package/chunks/{chunk-X26JYGTD.js → chunk-L6CCLB3G.js} +1 -1
  68. package/chunks/{chunk-M6NDLY2T.js → chunk-LD5VIJ7S.js} +1 -1
  69. package/chunks/{chunk-ZYBBISBY.js → chunk-LLR424CQ.js} +15 -12
  70. package/chunks/{chunk-JUEPY766.js → chunk-LRDB2OLB.js} +2 -2
  71. package/chunks/{chunk-PQ36L4F5.js → chunk-MCG53LWC.js} +1 -1
  72. package/chunks/{chunk-OD2WU5QY.js → chunk-NRPXRNN4.js} +1 -1
  73. package/chunks/{chunk-76J3IJ3M.js → chunk-NV6LW6FT.js} +3 -3
  74. package/chunks/{chunk-CKSJECTU.js → chunk-NVRMCWTP.js} +8 -4
  75. package/chunks/{chunk-Y3YCSWG5.js → chunk-OBJYN4MX.js} +1 -1
  76. package/chunks/{chunk-WFSTRPRO.js → chunk-OJOP26ET.js} +1 -1
  77. package/chunks/{chunk-A267JX7H.js → chunk-OLZSWUZR.js} +6 -6
  78. package/chunks/{chunk-TIGA2IVL.js → chunk-OO4FKHLO.js} +2 -2
  79. package/chunks/{chunk-OY5RNSV4.js → chunk-OSAFWBNR.js} +3 -3
  80. package/chunks/{chunk-BZ263IKX.js → chunk-OVY67CYC.js} +1 -1
  81. package/chunks/{chunk-YEYY7TEP.js → chunk-P425IVUK.js} +5 -5
  82. package/chunks/{chunk-AFSG32D5.js → chunk-PMS7O6SA.js} +1 -1
  83. package/chunks/{chunk-6ORZ2EDC.js → chunk-PPTM4O4R.js} +1 -1
  84. package/chunks/{chunk-JOOFMXGF.js → chunk-QECSDJET.js} +5 -5
  85. package/chunks/{chunk-CZBYX5MY.js → chunk-QEJZUXSK.js} +1 -1
  86. package/chunks/{chunk-4PKCUT7F.js → chunk-QIHHJKXT.js} +6 -6
  87. package/chunks/{chunk-QRCNA3SR.js → chunk-RAQBBGS6.js} +49 -69
  88. package/chunks/{chunk-M732YJPW.js → chunk-RXHBTKMG.js} +2 -2
  89. package/chunks/{chunk-XIT3GURH.js → chunk-S6CXQKDD.js} +3 -3
  90. package/chunks/{chunk-GGDBMYGZ.js → chunk-SA7GBPEA.js} +3 -3
  91. package/chunks/{chunk-7UXUJ5T3.js → chunk-SBRIBTYN.js} +1 -1
  92. package/chunks/{chunk-MC4TLKEI.js → chunk-SGLPDKRT.js} +2 -2
  93. package/chunks/{chunk-WSH6GRKG.js → chunk-SLILKYV2.js} +2 -2
  94. package/chunks/{chunk-DXIBNLBZ.js → chunk-SNQZZ765.js} +1 -1
  95. package/chunks/{chunk-5EYKMUUY.js → chunk-SR2LYSMT.js} +1 -1
  96. package/chunks/{chunk-AW4TRXOC.js → chunk-TNPWODIZ.js} +1 -1
  97. package/chunks/{chunk-QF2NHSPB.js → chunk-U6RZRKNM.js} +233 -184
  98. package/chunks/{chunk-QNQAPSN2.js → chunk-UC67T4SF.js} +3 -1
  99. package/chunks/{chunk-O565M6A4.js → chunk-UYDGFWIJ.js} +199 -14
  100. package/chunks/{chunk-LJQAUZMR.js → chunk-VGAAAMRD.js} +925 -92
  101. package/chunks/{chunk-UKMR3CKV.js → chunk-VHPMDDPT.js} +3 -3
  102. package/chunks/{chunk-S5DWMTHO.js → chunk-WP4WIUOJ.js} +2 -0
  103. package/chunks/{chunk-25EYDK42.js → chunk-WPVUOVYX.js} +1 -1
  104. package/chunks/{chunk-AXN7UPYQ.js → chunk-WSSH2BNO.js} +1 -1
  105. package/chunks/{chunk-6YKYPVDV.js → chunk-WVIABDXV.js} +3 -3
  106. package/chunks/chunk-WZAD4ZNJ.js +59 -0
  107. package/chunks/{chunk-N5YPT6PH.js → chunk-X3YA3YGG.js} +7 -4
  108. package/chunks/{chunk-4S5337WV.js → chunk-XC377TLN.js} +4312 -2704
  109. package/chunks/{chunk-NNHNLJ2X.js → chunk-XO24LIZC.js} +240 -42
  110. package/chunks/{chunk-EL5SXY3T.js → chunk-XT4RKHVE.js} +2 -2
  111. package/chunks/{chunk-FDGGZIYW.js → chunk-YECDICIO.js} +2 -2
  112. package/chunks/{chunk-E23IPNGS.js → chunk-YFPZ3NNC.js} +12 -3
  113. package/chunks/{chunk-46UV252V.js → chunk-YHC2EYYG.js} +35 -38
  114. package/chunks/{chunk-V26NVGAU.js → chunk-YIWH3MKK.js} +8 -3
  115. package/chunks/{chunk-IWPYVAO2.js → chunk-YXC7JYUI.js} +2 -2
  116. package/chunks/{chunk-A4MFR4C5.js → chunk-ZIGC3MUS.js} +2 -4
  117. package/chunks/{chunk-ZZO74WKW.js → chunk-ZXEAEZFN.js} +24 -18
  118. package/chunks/{computer-use-77C5FHMW.js → computer-use-ABECHPS5.js} +22 -21
  119. package/chunks/{config-utils-IVHRSXWI.js → config-utils-NJQA5YLJ.js} +2 -2
  120. package/chunks/{contextCommand-PJ77GBWL.js → contextCommand-4CD5HZQQ.js} +24 -23
  121. package/chunks/{core-runtime-7VMIKUTG.js → core-runtime-2MOVQ4VX.js} +22 -21
  122. package/chunks/{create-sub-session-2L5MQRN4.js → create-sub-session-L6NNHG5N.js} +26 -24
  123. package/chunks/{cron-create-H7UEPDSN.js → cron-create-NFRZEOQX.js} +2 -2
  124. package/chunks/{cron-delete-6SZK7YFM.js → cron-delete-GFVSVO7C.js} +2 -2
  125. package/chunks/{cron-list-H25JIHEZ.js → cron-list-NRW34CLU.js} +2 -2
  126. package/chunks/{daemon-2KTG7ZBN.js → daemon-XH76IXOC.js} +356 -21
  127. package/chunks/{daemon-git-worktree-guard-DXYIMWFT.js → daemon-git-worktree-guard-BLXFEG4Q.js} +24 -23
  128. package/chunks/{daemon-status-provider-ZDOYJCU6.js → daemon-status-provider-XGD3TPTO.js} +31 -30
  129. package/chunks/{daemon-trust-policy-E67OYUK2.js → daemon-trust-policy-THEGCWPO.js} +29 -28
  130. package/chunks/{daemon-trust-policy-monitor-RYYGCQ3J.js → daemon-trust-policy-monitor-L7L4ACWQ.js} +29 -28
  131. package/chunks/{de-UBEBKG6V.js → de-AH4LGCF5.js} +8 -0
  132. package/chunks/{deferred-core-runtime-3SGXFXEQ.js → deferred-core-runtime-YQLHDUGE.js} +22 -21
  133. package/chunks/{discovery-ORA5J7YP.js → discovery-X2NV535U.js} +1 -1
  134. package/chunks/{dist-WJ4BHIEW.js → dist-ESS34DHC.js} +72 -0
  135. package/chunks/{earlyInputCapture-KJMLFVQV.js → earlyInputCapture-PCTXNW7N.js} +22 -21
  136. package/chunks/{edit-I4LQFAEC.js → edit-QX2EGWYW.js} +25 -23
  137. package/chunks/{en-X6YV7GME.js → en-MD3GP5YL.js} +8 -0
  138. package/chunks/{enter-worktree-YNPOJSRH.js → enter-worktree-EM3ZZ2SB.js} +22 -21
  139. package/chunks/{enterPlanMode-XCPK62ER.js → enterPlanMode-ESCMVAKB.js} +22 -21
  140. package/chunks/{environment-S7CTIHMX.js → environment-TOJI56YV.js} +25 -24
  141. package/chunks/{errors-7HB2AIDS.js → errors-DZ5FWWEM.js} +24 -23
  142. package/chunks/{exit-worktree-AIIY7SR6.js → exit-worktree-KUIJ36XA.js} +22 -21
  143. package/chunks/{exitPlanMode-R4JY7V2O.js → exitPlanMode-NFVY54FV.js} +22 -21
  144. package/chunks/{fast-path-NDJV3ZFJ.js → fast-path-JLQXJSH6.js} +3 -3
  145. package/chunks/{fast-path-settings-LNOFM2YP.js → fast-path-settings-WHX3J3ZI.js} +2 -2
  146. package/chunks/{fr-VENTC2BS.js → fr-ZEML2JWS.js} +8 -0
  147. package/chunks/{gemini-RSUFP5OE.js → gemini-I7OT4FWL.js} +62 -61
  148. package/chunks/{geminiContentGenerator-SQ5XBPZ7.js → geminiContentGenerator-GRIS77NJ.js} +3 -3
  149. package/chunks/{glob-J4RUJAHX.js → glob-7TBUUV6R.js} +22 -21
  150. package/chunks/{goal-tools-VHTNVOKK.js → goal-tools-K5OHOJ6B.js} +1 -1
  151. package/chunks/{grep-VJWPLFOT.js → grep-743SYWCZ.js} +22 -21
  152. package/chunks/{handleAutoUpdate-POCX2MNB.js → handleAutoUpdate-GAOYUYOD.js} +26 -25
  153. package/chunks/{i18n-RM5YOICI.js → i18n-2ITURYX6.js} +23 -22
  154. package/chunks/{image-gen-EXECB5XM.js → image-gen-4OIWDZD6.js} +2 -2
  155. package/chunks/{initializer-Z2AFGBNR.js → initializer-OC7LWA6X.js} +29 -28
  156. package/chunks/{installationInfo-4I5FXNMH.js → installationInfo-CO47QX3Q.js} +23 -22
  157. package/chunks/{ja-QHT4EQTO.js → ja-UM5B2HMD.js} +8 -0
  158. package/chunks/{list-ZMBFIGZA.js → list-ATR2SFWT.js} +32 -31
  159. package/chunks/{loadedSettingsAdapter-T6TV4YJ7.js → loadedSettingsAdapter-NK4B7AGK.js} +29 -28
  160. package/chunks/{loggingContentGenerator-WF4ZOJEZ.js → loggingContentGenerator-3WXBU5TQ.js} +12 -10
  161. package/chunks/{loop-wakeup-WQS6JYAG.js → loop-wakeup-HWVUU5CF.js} +3 -3
  162. package/chunks/{managed-npm-update-E7IW6N7V.js → managed-npm-update-4SSBWI2D.js} +23 -22
  163. package/chunks/{mcp-6UNYX4HG.js → mcp-C62AE2QI.js} +29 -28
  164. package/chunks/{monitor-EE2UYMGE.js → monitor-FEYEGASA.js} +22 -21
  165. package/chunks/{nonInteractiveCli-WAY237O4.js → nonInteractiveCli-AJEV5ZWO.js} +59 -57
  166. package/chunks/{notebook-edit-NTDY4QDU.js → notebook-edit-SLLTEY4O.js} +26 -24
  167. package/chunks/{openaiContentGenerator-YNFVJMRJ.js → openaiContentGenerator-WLUGIAPX.js} +12 -11
  168. package/chunks/{pidfile-4XSFLYBZ.js → pidfile-TV2VWUMB.js} +22 -21
  169. package/chunks/{processUtils-WDA2MJFD.js → processUtils-3IN2ZR55.js} +2 -2
  170. package/chunks/{pt-VL3I5RNY.js → pt-5BMJ3XYH.js} +8 -0
  171. package/chunks/{qwenContentGenerator-434M7QKY.js → qwenContentGenerator-GSGRFPJE.js} +25 -24
  172. package/chunks/{qwenOAuth2-GMYZOO6A.js → qwenOAuth2-JLSTIS4Z.js} +3 -3
  173. package/chunks/{read-file-TAFBKMNI.js → read-file-6PZZRGZZ.js} +9 -7
  174. package/chunks/{record-artifact-SEYFJEJF.js → record-artifact-GLU3UWBV.js} +3 -1
  175. package/chunks/{resumeHistoryUtils-EVG3WYK2.js → resumeHistoryUtils-5GEWKOOO.js} +25 -24
  176. package/chunks/{ripGrep-WOEK2PXS.js → ripGrep-FX7GBGFN.js} +22 -21
  177. package/chunks/{ru-4RCKL4PY.js → ru-6GL66ORV.js} +8 -0
  178. package/chunks/{run-qwen-serve-3QSGRXAN.js → run-qwen-serve-7RHU3NSV.js} +49 -40
  179. package/chunks/{runtime-5MLLZ7DC.js → runtime-EPOXAMLP.js} +32 -31
  180. package/chunks/{scheduler-RPBJ63CH.js → scheduler-F4Y7ENVV.js} +24 -23
  181. package/chunks/{sdk-exporters-http-XUVP63H6.js → sdk-exporters-http-NC746HLT.js} +2 -2
  182. package/chunks/{sdk-impl-YXUEN2Z2.js → sdk-impl-YVL7BP6Y.js} +2 -2
  183. package/chunks/{send-message-VZENRWRH.js → send-message-TNBG5EVA.js} +1 -1
  184. package/chunks/{serve-HS3XLPXU.js → serve-LQV4TN5A.js} +29 -30
  185. package/chunks/{server-TC4A7AAZ.js → server-IZCKLIYQ.js} +1267 -165
  186. package/chunks/{session-UBOFXVMN.js → session-52ZGTDVB.js} +60 -58
  187. package/chunks/{settings-D5644OM5.js → settings-WCVB34HW.js} +28 -27
  188. package/chunks/{shell-3PZULQQV.js → shell-33BIUBLH.js} +22 -21
  189. package/chunks/{skill-PEVVXQ3L.js → skill-IYVQ2QNK.js} +11 -9
  190. package/chunks/{skill-settings-J65JKKES.js → skill-settings-YG4ZS4OZ.js} +28 -27
  191. package/chunks/{spawnChannel-IYGXRHSQ.js → spawnChannel-BLA4YT4W.js} +24 -23
  192. package/chunks/{standalone-update-IFM53PE7.js → standalone-update-ALRIPWSM.js} +24 -23
  193. package/chunks/{startInteractiveUI-3AVH7L6H.js → startInteractiveUI-PISBXWKA.js} +262 -191
  194. package/chunks/{task-create-FCBDX7UH.js → task-create-EILHJJB7.js} +4 -4
  195. package/chunks/{task-list-YIYIUFUA.js → task-list-WGJR6YL5.js} +18 -4
  196. package/chunks/{task-update-MYPFVOVM.js → task-update-XZAHVXJ5.js} +79 -8
  197. package/chunks/{team-create-ZAIA7KAV.js → team-create-CIQDCC6A.js} +23 -23
  198. package/chunks/{team-delete-6UMU4XLS.js → team-delete-UEP4QOOT.js} +3 -3
  199. package/chunks/{team-plan-approval-UNIUS7OD.js → team-plan-approval-664XCRB4.js} +22 -21
  200. package/chunks/{terminal-image-renderer-G343P2RV.js → terminal-image-renderer-TEBO6ONY.js} +22 -21
  201. package/chunks/{theme-manager-Z3RIT7DB.js → theme-manager-3CIFH2JV.js} +22 -21
  202. package/chunks/{todoWrite-U2R4NVF4.js → todoWrite-ATS62CAP.js} +1 -1
  203. package/chunks/{tool-search-5R2OE4C7.js → tool-search-IJX5JHJB.js} +9 -7
  204. package/chunks/{total-session-admission-4KBHMQQ2.js → total-session-admission-XBK2NVRV.js} +26 -25
  205. package/chunks/{trustedFolders-LK6T4XC7.js → trustedFolders-OOFNLRWK.js} +23 -22
  206. package/chunks/{update-relaunch-UBKROIC6.js → update-relaunch-EIG7EYAQ.js} +5 -5
  207. package/chunks/{updateCheck-W4Y2GFSD.js → updateCheck-KYDCBLSF.js} +25 -24
  208. package/chunks/{useAutoAcceptIndicator-C7BEICBF.js → useAutoAcceptIndicator-RFX3KNBN.js} +31 -30
  209. package/chunks/{validateNonInterActiveAuth-LTEI2TB6.js → validateNonInterActiveAuth-MZXSAITU.js} +56 -54
  210. package/chunks/{version-G5A5DGVS.js → version-PJC6ZNXV.js} +1 -1
  211. package/chunks/{web-fetch-RTEQTR5Z.js → web-fetch-XXICVGKQ.js} +11 -8
  212. package/chunks/{web-search-5OXHEZPV.js → web-search-LHPM6QWC.js} +2 -2
  213. package/chunks/{workflow-ISQJHPG2.js → workflow-4CUO2BV7.js} +139 -37
  214. package/chunks/{workspace-providers-status-2ZPZPUPZ.js → workspace-providers-status-G4MUGH3X.js} +32 -31
  215. package/chunks/{workspace-registration-store-CYNY6IP6.js → workspace-registration-store-QMDMFWBE.js} +1 -1
  216. package/chunks/{workspace-registry-34GTUUHB.js → workspace-registry-FKBB4MZK.js} +26 -25
  217. package/chunks/{workspace-service-XCDQLE2Y.js → workspace-service-TIDTTA65.js} +33 -32
  218. package/chunks/{workspace-skills-status-RS4O7AIJ.js → workspace-skills-status-LBC2TZKM.js} +30 -29
  219. package/chunks/{workspace-trust-reconciler-AYGXC7A3.js → workspace-trust-reconciler-4KJ567XP.js} +33 -32
  220. package/chunks/{write-file-EWXKVVXF.js → write-file-R6LAEER5.js} +22 -21
  221. package/chunks/{zh-TW-SQ4HTSCW.js → zh-TW-LVLBK4KF.js} +8 -0
  222. package/chunks/{zh-LMSTK4WD.js → zh-UBMWS2BJ.js} +8 -0
  223. package/chunks/{zoom-image-4BFYJ3HG.js → zoom-image-XLCK6DDK.js} +14 -11
  224. package/cli.js +13 -13
  225. package/locales/ca.js +13 -0
  226. package/locales/de.js +12 -0
  227. package/locales/en.js +11 -0
  228. package/locales/fr.js +13 -0
  229. package/locales/ja.js +13 -0
  230. package/locales/pt.js +12 -0
  231. package/locales/ru.js +12 -0
  232. package/locales/zh-TW.js +11 -0
  233. package/locales/zh.js +11 -0
  234. package/package.json +3 -3
  235. package/web-shell/assets/{arc-CgOpDKvm.js → arc-DItbX0DI.js} +1 -1
  236. package/web-shell/assets/{architectureDiagram-3BPJPVTR-0Ag_m34F.js → architectureDiagram-3BPJPVTR-CmnIlH8y.js} +1 -1
  237. package/web-shell/assets/{blockDiagram-GPEHLZMM-IwTwFau0.js → blockDiagram-GPEHLZMM-pObnB9kw.js} +1 -1
  238. package/web-shell/assets/{c4Diagram-AAUBKEIU-DLa5GUv8.js → c4Diagram-AAUBKEIU-BNBmMS0Y.js} +1 -1
  239. package/web-shell/assets/channel-hZnMfWA9.js +1 -0
  240. package/web-shell/assets/{chunk-2J33WTMH-DcYP-WFG.js → chunk-2J33WTMH-Dz4JBOO6.js} +1 -1
  241. package/web-shell/assets/{chunk-4BX2VUAB-C8MVPMiQ.js → chunk-4BX2VUAB-Cz2GnvAR.js} +1 -1
  242. package/web-shell/assets/{chunk-55IACEB6-BUi4Yfv3.js → chunk-55IACEB6-CC6kOQYx.js} +1 -1
  243. package/web-shell/assets/{chunk-727SXJPM-Cy3Su2YY.js → chunk-727SXJPM-Z4lY4gbh.js} +1 -1
  244. package/web-shell/assets/{chunk-AQP2D5EJ-Dp8Teqv6.js → chunk-AQP2D5EJ-Yz0hZr3D.js} +1 -1
  245. package/web-shell/assets/{chunk-FMBD7UC4-BDTDM-4j.js → chunk-FMBD7UC4-nKmTWTv9.js} +1 -1
  246. package/web-shell/assets/{chunk-ND2GUHAM-7HfDt0r2.js → chunk-ND2GUHAM-CjZz0f6Y.js} +1 -1
  247. package/web-shell/assets/{chunk-QZHKN3VN-BIBU0uCF.js → chunk-QZHKN3VN-Bab3FpuS.js} +1 -1
  248. package/web-shell/assets/classDiagram-4FO5ZUOK-BRnxm8DX.js +1 -0
  249. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BRnxm8DX.js +1 -0
  250. package/web-shell/assets/{cose-bilkent-S5V4N54A-DRLdcg9p.js → cose-bilkent-S5V4N54A-BuSAGFox.js} +1 -1
  251. package/web-shell/assets/{dagre-BM42HDAG-DCCgDwqW.js → dagre-BM42HDAG-CRZXTg3g.js} +1 -1
  252. package/web-shell/assets/{diagram-2AECGRRQ-CsBTBmk3.js → diagram-2AECGRRQ-BFx1Ayrz.js} +1 -1
  253. package/web-shell/assets/{diagram-5GNKFQAL-C9qjH8Lt.js → diagram-5GNKFQAL-B2hMZ3gS.js} +1 -1
  254. package/web-shell/assets/{diagram-KO2AKTUF-Brjs_lj2.js → diagram-KO2AKTUF-DKxAQLmc.js} +1 -1
  255. package/web-shell/assets/{diagram-LMA3HP47-DtiWCl_F.js → diagram-LMA3HP47-Bo1xGqVY.js} +1 -1
  256. package/web-shell/assets/{diagram-OG6HWLK6-DmfKLkBT.js → diagram-OG6HWLK6-B9NG78d-.js} +1 -1
  257. package/web-shell/assets/{erDiagram-TEJ5UH35-Bve_4deH.js → erDiagram-TEJ5UH35-DltQKiqQ.js} +1 -1
  258. package/web-shell/assets/{flowDiagram-I6XJVG4X-C2_kXCcV.js → flowDiagram-I6XJVG4X-5xXGmS4I.js} +1 -1
  259. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BSBIjiTF.js → ganttDiagram-6RSMTGT7-bhGL5n0l.js} +1 -1
  260. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CyebwI55.js → gitGraphDiagram-PVQCEYII-ZYnz9hgh.js} +1 -1
  261. package/web-shell/assets/{index-d0yfnV1M.js → index-CBBeUArD.js} +1 -1
  262. package/web-shell/assets/index-CbgU-jUo.css +5 -0
  263. package/web-shell/assets/index-_nhzXqab.js +1750 -0
  264. package/web-shell/assets/{infoDiagram-5YYISTIA-CSDGnWxU.js → infoDiagram-5YYISTIA-Cg-jamQf.js} +1 -1
  265. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BK4jU13p.js → ishikawaDiagram-YF4QCWOH-CcmvKlyq.js} +1 -1
  266. package/web-shell/assets/{journeyDiagram-JHISSGLW-D_W6j-oF.js → journeyDiagram-JHISSGLW-BRsOQZp1.js} +1 -1
  267. package/web-shell/assets/{kanban-definition-UN3LZRKU-C7xf-SdC.js → kanban-definition-UN3LZRKU-xW-dmEHK.js} +1 -1
  268. package/web-shell/assets/{linear-DQmzxpxd.js → linear-ClBfEZH2.js} +1 -1
  269. package/web-shell/assets/{mermaid.core-9P7AGOLG.js → mermaid.core-D65NDkzc.js} +5 -5
  270. package/web-shell/assets/{mindmap-definition-RKZ34NQL-DgcgMyPk.js → mindmap-definition-RKZ34NQL-CyvFslYa.js} +1 -1
  271. package/web-shell/assets/{pieDiagram-4H26LBE5-3wWGb9eG.js → pieDiagram-4H26LBE5-BwSefMyG.js} +1 -1
  272. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BeCXnQw9.js → quadrantDiagram-W4KKPZXB-GqBJspFS.js} +1 -1
  273. package/web-shell/assets/{requirementDiagram-4Y6WPE33-Bi1UOHDz.js → requirementDiagram-4Y6WPE33-B137PlTJ.js} +1 -1
  274. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-lrLUjjbb.js → sankeyDiagram-5OEKKPKP-maHkkt8i.js} +1 -1
  275. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-BFuqKz6Q.js → sequenceDiagram-3UESZ5HK-DJ1mRaG3.js} +1 -1
  276. package/web-shell/assets/{stateDiagram-AJRCARHV-8DemQLhu.js → stateDiagram-AJRCARHV-aRmP7Q4i.js} +1 -1
  277. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Db39gvZ_.js +1 -0
  278. package/web-shell/assets/{timeline-definition-PNZ67QCA-uzEuVQXg.js → timeline-definition-PNZ67QCA-CIQ3BRPA.js} +1 -1
  279. package/web-shell/assets/{vennDiagram-CIIHVFJN-BQTeZ_-o.js → vennDiagram-CIIHVFJN-DR9VPd5h.js} +1 -1
  280. package/web-shell/assets/{wardley-L42UT6IY-B6yM5Im7.js → wardley-L42UT6IY-ZcfIbT4D.js} +1 -1
  281. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-ChM8bmgn.js → wardleyDiagram-YWT4CUSO-D0jgPi4T.js} +1 -1
  282. package/web-shell/assets/{xychartDiagram-2RQKCTM6-oNG6HyB1.js → xychartDiagram-2RQKCTM6-BGWU4s5o.js} +1 -1
  283. package/web-shell/index.html +2 -2
  284. package/chunks/chunk-MPHPFVKK.js +0 -48
  285. package/chunks/chunk-RLKC46YT.js +0 -3582
  286. package/chunks/chunk-UPDOZBWO.js +0 -358
  287. package/web-shell/assets/channel-BrGVBa2L.js +0 -1
  288. package/web-shell/assets/classDiagram-4FO5ZUOK-B5TUzJzI.js +0 -1
  289. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B5TUzJzI.js +0 -1
  290. package/web-shell/assets/index-CIDsgxTe.js +0 -1792
  291. package/web-shell/assets/index-DiQnWi_E.css +0 -5
  292. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DhM5ixYd.js +0 -1
  293. /package/chunks/{chunk-NTTBXH7U.js → chunk-UGK4K2N2.js} +0 -0
@@ -20,13 +20,13 @@ import {
20
20
  shouldSuppressRememberErrorDetails,
21
21
  workspaceMemoryFailureCode,
22
22
  workspaceMemoryFailureDiagnostics
23
- } from "./chunk-ZZO74WKW.js";
23
+ } from "./chunk-ZXEAEZFN.js";
24
24
  import {
25
25
  deriveWebSocketBase,
26
26
  openQwenAsrRealtimeStream,
27
27
  openVoiceStream,
28
28
  openVoiceStreamWithRetry
29
- } from "./chunk-AXN7UPYQ.js";
29
+ } from "./chunk-WSSH2BNO.js";
30
30
  import {
31
31
  SetupGithubError,
32
32
  collectSessionData,
@@ -38,15 +38,15 @@ import {
38
38
  toJson,
39
39
  toJsonl,
40
40
  toMarkdown
41
- } from "./chunk-RLKC46YT.js";
41
+ } from "./chunk-EOCQCNV4.js";
42
42
  import {
43
43
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
44
44
  ObservedChannelContactStore
45
- } from "./chunk-BZ263IKX.js";
45
+ } from "./chunk-OVY67CYC.js";
46
46
  import {
47
47
  escapeAnsiCtrlCodes
48
- } from "./chunk-4NFY2S7N.js";
49
- import "./chunk-3U3VAL47.js";
48
+ } from "./chunk-E7REAOTN.js";
49
+ import "./chunk-57KOJ2KZ.js";
50
50
  import "./chunk-2MIN6GRR.js";
51
51
  import "./chunk-QHTIBUWB.js";
52
52
  import "./chunk-3Z43GZUQ.js";
@@ -62,11 +62,13 @@ import {
62
62
  CLIENT_ID_RE,
63
63
  ClientMcpSenderRegistry,
64
64
  ConversationRuntimeOwnershipError,
65
+ CredentialStore,
65
66
  DeviceFlowRegistry,
66
67
  MAX_CLIENT_ID_LENGTH,
67
68
  MAX_CONCURRENT_VOICE_SESSIONS,
68
69
  MAX_SERVER_NAME_LENGTH,
69
70
  MAX_TOOL_NAME_LENGTH,
71
+ MutableOriginAllowlist,
70
72
  PathMutexRegistry,
71
73
  QWEN_CDP_MCP_COMMAND_ENV,
72
74
  TooManyActiveDeviceFlowsError,
@@ -88,7 +90,6 @@ import {
88
90
  createManagedScratchDirectory,
89
91
  createMutationGate,
90
92
  createRateLimiter,
91
- denyBrowserOriginCors,
92
93
  detectFromLoopback,
93
94
  getAdvertisedServeFeatures,
94
95
  getDeferredRuntimeRequestTiming,
@@ -99,6 +100,8 @@ import {
99
100
  isBrowserAutomationMcpAvailable,
100
101
  isDeepHealthQuery,
101
102
  isScratchRootCompatible,
103
+ listenerIdentityOf,
104
+ listenerIdentityOfSocket,
102
105
  parseAllowOriginPatterns,
103
106
  parseAndValidateWorkspaceClientId,
104
107
  parseClientIdHeader,
@@ -107,6 +110,7 @@ import {
107
110
  parseMaxQueuedQuery,
108
111
  parseOptionalWorkspaceCwd,
109
112
  parsePermissionVoteBody,
113
+ requestWasAuthenticated,
110
114
  requireSessionId,
111
115
  resolveAcpHttpEnabled,
112
116
  resolveCdpMcpCommand,
@@ -116,9 +120,11 @@ import {
116
120
  sendJsonBodyParserError,
117
121
  setDeviceFlowRegistry,
118
122
  setRateLimiter,
123
+ singleTokenCredentials,
124
+ tagListener,
119
125
  unsafeRevealSecret,
120
126
  validateMcpRuntimeServerName
121
- } from "./chunk-O565M6A4.js";
127
+ } from "./chunk-UYDGFWIJ.js";
122
128
  import "./chunk-VGHZT6JR.js";
123
129
  import {
124
130
  isLoopbackBind,
@@ -129,7 +135,7 @@ import "./chunk-UXEO7E3V.js";
129
135
  import {
130
136
  evaluateDaemonWorkspaceTrust,
131
137
  readDaemonTrustPolicySnapshot
132
- } from "./chunk-XIT3GURH.js";
138
+ } from "./chunk-S6CXQKDD.js";
133
139
  import {
134
140
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
135
141
  MAX_WORKSPACE_SKILL_NAME_LENGTH,
@@ -143,14 +149,14 @@ import {
143
149
  validateWorkspaceSkillName,
144
150
  validateWorkspaceVoiceState,
145
151
  voiceSettingsScopeToWire
146
- } from "./chunk-EZ5RP345.js";
152
+ } from "./chunk-E5RS7LF4.js";
147
153
  import {
148
154
  PermissionRulesValidationError,
149
155
  buildPermissionSettings,
150
156
  isPermissionRuleType,
151
157
  normalizePermissionRules,
152
158
  readPermissionRuleSet
153
- } from "./chunk-7UXUJ5T3.js";
159
+ } from "./chunk-SBRIBTYN.js";
154
160
  import {
155
161
  assertVoiceBaseUrlNetworkAllowed,
156
162
  isStreamingVoiceModel,
@@ -158,12 +164,12 @@ import {
158
164
  resolveVoiceTranscriptionConfig,
159
165
  sanitizeVoiceErrorMessage,
160
166
  transcribeVoiceAudio
161
- } from "./chunk-6ORZ2EDC.js";
167
+ } from "./chunk-PPTM4O4R.js";
162
168
  import {
163
169
  isVoiceEnabled,
164
170
  isVoiceMode,
165
171
  readVoiceModel
166
- } from "./chunk-QIH2HAEN.js";
172
+ } from "./chunk-7OCSX7FC.js";
167
173
  import "./chunk-WGHHA7ZH.js";
168
174
  import {
169
175
  createTotalSessionAdmissionController
@@ -184,18 +190,18 @@ import {
184
190
  } from "./chunk-4JRM2BSM.js";
185
191
  import {
186
192
  assertValidChannelSecretUpdates
187
- } from "./chunk-PP4FUZNV.js";
193
+ } from "./chunk-55PIFSP2.js";
188
194
  import {
189
195
  createDaemonStatusProvider
190
- } from "./chunk-OOQUVWIG.js";
191
- import "./chunk-NTTBXH7U.js";
192
- import "./chunk-XHRY7BXD.js";
196
+ } from "./chunk-6PDOHRN6.js";
197
+ import "./chunk-UGK4K2N2.js";
198
+ import "./chunk-G6FFFICU.js";
193
199
  import {
194
200
  SessionArtifactAuthorizationError,
195
201
  SessionArtifactValidationError,
196
202
  createAcpSessionBridge,
197
203
  parseSessionSource
198
- } from "./chunk-LJQAUZMR.js";
204
+ } from "./chunk-VGAAAMRD.js";
199
205
  import {
200
206
  EVENT_SCHEMA_VERSION,
201
207
  EventBus,
@@ -205,17 +211,17 @@ import "./chunk-WCCLLK7X.js";
205
211
  import "./chunk-OCPBI7J5.js";
206
212
  import {
207
213
  createWorkspaceProvidersStatusProvider
208
- } from "./chunk-YEYY7TEP.js";
214
+ } from "./chunk-P425IVUK.js";
209
215
  import {
210
216
  getAuthTypeFromEnv,
211
217
  resolveCliGenerationConfig
212
- } from "./chunk-ZYYTZUI2.js";
218
+ } from "./chunk-ISRHAMNL.js";
213
219
  import {
214
220
  snapshotProcessEnv
215
- } from "./chunk-NM5V5OVW.js";
221
+ } from "./chunk-GV3OIADZ.js";
216
222
  import {
217
223
  createWorkspaceSkillsStatusProvider
218
- } from "./chunk-OY5RNSV4.js";
224
+ } from "./chunk-OSAFWBNR.js";
219
225
  import "./chunk-BGXZBI5B.js";
220
226
  import "./chunk-Z4X5MTRT.js";
221
227
  import {
@@ -234,32 +240,32 @@ import {
234
240
  import {
235
241
  daemonObservedContactsPath,
236
242
  loadChannelsConfig
237
- } from "./chunk-TUGSVUJB.js";
238
- import "./chunk-QV5YN5YD.js";
243
+ } from "./chunk-2JXDFSVE.js";
244
+ import "./chunk-HGPMOXLZ.js";
239
245
  import "./chunk-57OAHC2Y.js";
240
246
  import {
241
247
  parseChannelWebhookConfigLenient
242
- } from "./chunk-OD2WU5QY.js";
248
+ } from "./chunk-NRPXRNN4.js";
243
249
  import "./chunk-45NQKMYB.js";
244
250
  import {
245
251
  supportedChannelCatalog
246
- } from "./chunk-A4QRWUDE.js";
252
+ } from "./chunk-5IYS4WWR.js";
247
253
  import "./chunk-V6WHFGST.js";
248
254
  import {
249
255
  getStableLiveDiscoveryBaseDir
250
- } from "./chunk-TS6625XH.js";
256
+ } from "./chunk-5MK45KZ3.js";
251
257
  import {
252
258
  LIVE_HOST_BUNDLE_ID,
253
259
  LIVE_HOST_PROTOCOL_VERSION,
254
260
  LIVE_INPUT_AUDIO_EPOCH_BYTES
255
261
  } from "./chunk-NKLP3DCK.js";
256
- import "./chunk-NHDR76JX.js";
262
+ import "./chunk-BQWNIPTE.js";
257
263
  import {
258
264
  STATUS_SCHEMA_VERSION,
259
265
  SessionRestoreTimeoutError,
260
266
  createIdleWorkspaceMemoryStatus,
261
267
  mapDomainErrorToErrorKind
262
- } from "./chunk-QNQAPSN2.js";
268
+ } from "./chunk-UC67T4SF.js";
263
269
  import "./chunk-K6KS3LTN.js";
264
270
  import "./chunk-FC4KQFCS.js";
265
271
  import "./chunk-T3CHYWJZ.js";
@@ -270,13 +276,13 @@ import {
270
276
  WorkspaceRegistrationStoreLimitError,
271
277
  normalizeWorkspaceDisplayName,
272
278
  workspaceRegistrationId
273
- } from "./chunk-JNDY2MDR.js";
279
+ } from "./chunk-BOJNAPUE.js";
274
280
  import {
275
281
  CHANNEL_PROMPT_META_KEY,
276
282
  DAEMON_PROMPT_DISPLAY_TEXT_META_KEY,
277
283
  REQUESTED_SESSION_ID_META_KEY,
278
284
  gradeActiveWorkCoverage
279
- } from "./chunk-S5DWMTHO.js";
285
+ } from "./chunk-WP4WIUOJ.js";
280
286
  import {
281
287
  BranchWhilePromptActiveError,
282
288
  BridgeChannelQuarantinedError,
@@ -356,26 +362,26 @@ import {
356
362
  getWritableScopes,
357
363
  loadSettings,
358
364
  validateSettingValue
359
- } from "./chunk-A267JX7H.js";
365
+ } from "./chunk-OLZSWUZR.js";
360
366
  import "./chunk-RKUWKYED.js";
361
- import "./chunk-E23IPNGS.js";
367
+ import "./chunk-YFPZ3NNC.js";
362
368
  import "./chunk-GOXKNSDZ.js";
363
369
  import "./chunk-IDS7MSUP.js";
364
370
  import {
365
371
  detectSystemLanguage,
366
372
  resolveLanguageSetting
367
- } from "./chunk-HUTNYWBG.js";
373
+ } from "./chunk-IOTPI425.js";
368
374
  import {
369
375
  SUPPORTED_LANGUAGES,
370
376
  resolveSupportedLanguage
371
377
  } from "./chunk-5EJZE3FP.js";
372
- import "./chunk-MC4TLKEI.js";
373
- import "./chunk-MS7GNABG.js";
374
- import "./chunk-CU6GJD55.js";
378
+ import "./chunk-SGLPDKRT.js";
379
+ import "./chunk-CXJHQVEK.js";
380
+ import "./chunk-6DFPR7CS.js";
375
381
  import "./chunk-WZMH7II3.js";
376
382
  import {
377
383
  getWorkspaceTrustStatus
378
- } from "./chunk-IWPYVAO2.js";
384
+ } from "./chunk-YXC7JYUI.js";
379
385
  import "./chunk-NPQ5ZKRP.js";
380
386
  import {
381
387
  isWithinRoot as isWithinRoot2
@@ -448,12 +454,13 @@ import {
448
454
  resolveBranchName,
449
455
  resolveProviderProtocol,
450
456
  shouldShowStep,
457
+ sleepInhibitor,
451
458
  stripTerminalControlSequences,
452
459
  watchRepoBranch,
453
460
  writeWorkspaceContextFile,
454
461
  writeWorktreeSession,
455
462
  writeWorktreeSessionMarker
456
- } from "./chunk-4S5337WV.js";
463
+ } from "./chunk-XC377TLN.js";
457
464
  import "./chunk-GOFAQQZA.js";
458
465
  import "./chunk-5M6IDOMF.js";
459
466
  import "./chunk-TWPJO254.js";
@@ -461,12 +468,12 @@ import "./chunk-CQ35AJ4Z.js";
461
468
  import {
462
469
  MAX_JOBS,
463
470
  nextDurableFireMs
464
- } from "./chunk-DGZEMW5R.js";
465
- import "./chunk-WSH6GRKG.js";
466
- import "./chunk-CKSJECTU.js";
467
- import "./chunk-OVZPVYZB.js";
471
+ } from "./chunk-FS5NGKWC.js";
472
+ import "./chunk-SLILKYV2.js";
473
+ import "./chunk-NVRMCWTP.js";
474
+ import "./chunk-AKBOLMUF.js";
468
475
  import "./chunk-6PVPNMXU.js";
469
- import "./chunk-5EYKMUUY.js";
476
+ import "./chunk-SR2LYSMT.js";
470
477
  import {
471
478
  nextFireTime,
472
479
  parseCron
@@ -479,8 +486,8 @@ import {
479
486
  readCronTasks,
480
487
  taskHasLegacyCondition,
481
488
  updateCronTasks
482
- } from "./chunk-Y3YCSWG5.js";
483
- import "./chunk-UPDOZBWO.js";
489
+ } from "./chunk-OBJYN4MX.js";
490
+ import "./chunk-2C6HJMG3.js";
484
491
  import "./chunk-O6GEWCJA.js";
485
492
  import "./chunk-T26EAKDL.js";
486
493
  import "./chunk-ZPJWUGCS.js";
@@ -488,13 +495,13 @@ import "./chunk-CPBF7KYF.js";
488
495
  import {
489
496
  APPROVAL_MODES
490
497
  } from "./chunk-RWDNJBWN.js";
491
- import "./chunk-25EYDK42.js";
498
+ import "./chunk-WPVUOVYX.js";
492
499
  import "./chunk-MIPFDQAF.js";
493
500
  import "./chunk-MLXTMF7H.js";
494
501
  import "./chunk-KV27IEHM.js";
495
502
  import "./chunk-E3DYKPYZ.js";
496
- import "./chunk-OMLJNPBE.js";
497
- import "./chunk-OXCMMLED.js";
503
+ import "./chunk-4ZMS3JCR.js";
504
+ import "./chunk-DGJ7O55J.js";
498
505
  import {
499
506
  addDaemonRequestAttribute,
500
507
  captureDaemonTelemetryContext,
@@ -506,7 +513,7 @@ import {
506
513
  recordDaemonHttpResponse,
507
514
  runWithDaemonTelemetryContext,
508
515
  withDaemonRequestSpan
509
- } from "./chunk-TIGA2IVL.js";
516
+ } from "./chunk-OO4FKHLO.js";
510
517
  import "./chunk-SAH4BD2J.js";
511
518
  import "./chunk-XLLKYULU.js";
512
519
  import "./chunk-PT4I7NBA.js";
@@ -529,7 +536,7 @@ import {
529
536
  isDeviceAuthorizationSuccess,
530
537
  isDeviceTokenPending,
531
538
  isDeviceTokenSuccess
532
- } from "./chunk-GMIEIY3Y.js";
539
+ } from "./chunk-I3N2Z25H.js";
533
540
  import "./chunk-NAVJD2PQ.js";
534
541
  import "./chunk-ROIYNTHJ.js";
535
542
  import "./chunk-2B2BF7P7.js";
@@ -537,13 +544,18 @@ import "./chunk-P3QQPMQA.js";
537
544
  import "./chunk-YZHRN3CF.js";
538
545
  import "./chunk-FAAUPSY2.js";
539
546
  import "./chunk-KM73TBQ4.js";
540
- import "./chunk-MPHPFVKK.js";
541
547
  import "./chunk-AXMWHKXA.js";
542
548
  import "./chunk-GLCZKT5V.js";
543
549
  import "./chunk-DJ2GSRLV.js";
544
550
  import "./chunk-QFJ5JHQR.js";
545
551
  import "./chunk-CR3C7WXL.js";
546
552
  import "./chunk-XWRJCPHC.js";
553
+ import {
554
+ parseLineTolerant,
555
+ read
556
+ } from "./chunk-KC4WMLZO.js";
557
+ import "./chunk-YRLW2MSX.js";
558
+ import "./chunk-VGC4I5JJ.js";
547
559
  import {
548
560
  CursorNotAtLineBoundaryError,
549
561
  LargeNonUtf8TextError,
@@ -551,29 +563,26 @@ import {
551
563
  decodeBufferWithEncodingInfoAsync,
552
564
  getAllGeminiMdFilenames,
553
565
  isUtf8CompatibleEncoding,
554
- isWithinRoot,
555
- parseLineTolerant,
556
- read
557
- } from "./chunk-RVOJ2FBP.js";
558
- import "./chunk-YRLW2MSX.js";
559
- import "./chunk-VGC4I5JJ.js";
566
+ isWithinRoot
567
+ } from "./chunk-3PWCMXIR.js";
560
568
  import "./chunk-CHHABXPE.js";
561
569
  import "./chunk-MA2HEDVP.js";
562
570
  import "./chunk-XUJNK7Y6.js";
563
571
  import "./chunk-6HY6IF3Z.js";
564
- import "./chunk-4PKCUT7F.js";
572
+ import "./chunk-QIHHJKXT.js";
565
573
  import "./chunk-F6WFNA7U.js";
566
- import "./chunk-46UV252V.js";
574
+ import "./chunk-WZAD4ZNJ.js";
567
575
  import "./chunk-FPGTNKCP.js";
576
+ import "./chunk-YHC2EYYG.js";
568
577
  import "./chunk-CPHEPGAO.js";
569
- import "./chunk-P7MPQI75.js";
570
- import "./chunk-FDGGZIYW.js";
578
+ import "./chunk-DVR7XKO5.js";
579
+ import "./chunk-YECDICIO.js";
571
580
  import {
572
581
  redactUrlCredentials,
573
582
  stripAnsiAndControl
574
- } from "./chunk-EL5SXY3T.js";
583
+ } from "./chunk-XT4RKHVE.js";
575
584
  import "./chunk-HHJLM3WQ.js";
576
- import "./chunk-K5IDV3PC.js";
585
+ import "./chunk-D34RDOLP.js";
577
586
  import {
578
587
  FatalConfigError,
579
588
  Storage,
@@ -584,7 +593,8 @@ import {
584
593
  import "./chunk-VOQXFAY5.js";
585
594
  import {
586
595
  writeStderrLine,
587
- writeStderrLineSafe
596
+ writeStderrLineSafe,
597
+ writeStdoutLineSafe
588
598
  } from "./chunk-KGJGEEVR.js";
589
599
  import "./chunk-75DOP5OR.js";
590
600
  import "./chunk-DMTGGOSA.js";
@@ -607,12 +617,435 @@ import {
607
617
 
608
618
  // packages/cli/src/serve/server.ts
609
619
  init_esbuild_shims();
610
- var import_express6 = __toESM(require_express(), 1);
620
+ var import_express7 = __toESM(require_express(), 1);
611
621
  import * as path18 from "node:path";
612
622
 
623
+ // packages/cli/src/serve/local-control/index.ts
624
+ init_esbuild_shims();
625
+
626
+ // packages/cli/src/serve/local-control/lan-interfaces.ts
627
+ init_esbuild_shims();
628
+ import { networkInterfaces } from "node:os";
629
+ function isLanIpv4(address) {
630
+ const octets = address.split(".").map((part) => Number(part));
631
+ if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o))) {
632
+ return false;
633
+ }
634
+ const [a, b] = octets;
635
+ if (a === 10) return true;
636
+ if (a === 172 && b >= 16 && b <= 31) return true;
637
+ if (a === 192 && b === 168) return true;
638
+ if (a === 169 && b === 254) return true;
639
+ return false;
640
+ }
641
+ __name(isLanIpv4, "isLanIpv4");
642
+ function isSoftwareNetwork(interfaceName) {
643
+ if (/vpn/i.test(interfaceName)) return true;
644
+ return /(^|[\s_.-])(utun|tun|tap|ppp|ipsec|wg|wireguard|tailscale|zerotier|zt[a-z0-9]*|hamachi|nordlynx|proton|wintun|docker|veth[0-9a-f]+|vmnet|vboxnet|vethernet|virtualbox|host[- ]only|podman|cni|lxcbr|lxdbr|flannel|virbr|br-[0-9a-f]+|bridge\d|anyconnect|globalprotect|pulse[\s-]secure|forticlient|fortinet|ivanti|cisco[\s_-]secure|citrix|sonicwall|cloudflare)(\d|[\s_.-]|$)/i.test(
645
+ interfaceName
646
+ );
647
+ }
648
+ __name(isSoftwareNetwork, "isSoftwareNetwork");
649
+ function listLanCandidates(interfaces = networkInterfaces()) {
650
+ const candidates = [];
651
+ for (const [interfaceName, addresses] of Object.entries(interfaces).sort()) {
652
+ if (isSoftwareNetwork(interfaceName)) continue;
653
+ for (const address of addresses ?? []) {
654
+ if (address.family !== "IPv4" || address.internal) continue;
655
+ if (!isLanIpv4(address.address)) continue;
656
+ candidates.push({ interfaceName, address: address.address });
657
+ }
658
+ }
659
+ return candidates;
660
+ }
661
+ __name(listLanCandidates, "listLanCandidates");
662
+ var NoLanInterfaceError = class extends Error {
663
+ static {
664
+ __name(this, "NoLanInterfaceError");
665
+ }
666
+ code = "no_lan_interface";
667
+ constructor() {
668
+ super(
669
+ "No private IPv4 address is available. Local Control needs the host to be on a local network (Wi-Fi or Ethernet)."
670
+ );
671
+ this.name = "NoLanInterfaceError";
672
+ }
673
+ };
674
+ var AmbiguousLanInterfaceError = class extends Error {
675
+ static {
676
+ __name(this, "AmbiguousLanInterfaceError");
677
+ }
678
+ code = "ambiguous_lan_interface";
679
+ candidates;
680
+ constructor(candidates) {
681
+ super(
682
+ "Multiple local networks are available; choose which one to expose: " + candidates.map((c) => `${c.interfaceName} (${c.address})`).join(", ")
683
+ );
684
+ this.name = "AmbiguousLanInterfaceError";
685
+ this.candidates = candidates;
686
+ }
687
+ };
688
+ var UnknownLanInterfaceError = class extends Error {
689
+ static {
690
+ __name(this, "UnknownLanInterfaceError");
691
+ }
692
+ code = "unknown_lan_interface";
693
+ constructor(requested) {
694
+ super(
695
+ `${requested} is not a private IPv4 address on this host right now. The network may have changed since the list was fetched.`
696
+ );
697
+ this.name = "UnknownLanInterfaceError";
698
+ }
699
+ };
700
+ function selectLanAddress(preferredAddress, interfaces = networkInterfaces()) {
701
+ const candidates = listLanCandidates(interfaces);
702
+ if (candidates.length === 0) throw new NoLanInterfaceError();
703
+ if (preferredAddress !== void 0) {
704
+ const match = candidates.find((c) => c.address === preferredAddress);
705
+ if (!match) throw new UnknownLanInterfaceError(preferredAddress);
706
+ return match;
707
+ }
708
+ if (candidates.length > 1) throw new AmbiguousLanInterfaceError(candidates);
709
+ return candidates[0];
710
+ }
711
+ __name(selectLanAddress, "selectLanAddress");
712
+
713
+ // packages/cli/src/serve/local-control/service.ts
714
+ init_esbuild_shims();
715
+ import { randomBytes, randomUUID } from "node:crypto";
716
+ import { readFileSync } from "node:fs";
717
+ import { createServer } from "node:http";
718
+ import { createServer as createSecureServer } from "node:https";
719
+ var CORS_KEY = "local-control";
720
+ var MAX_CONNECTIONS = 64;
721
+ var HEADERS_TIMEOUT_MS = 1e4;
722
+ var KEEP_ALIVE_TIMEOUT_MS = 5e3;
723
+ var REQUEST_TIMEOUT_MS = 30 * 6e4;
724
+ var InvalidLocalControlTargetError = class extends Error {
725
+ static {
726
+ __name(this, "InvalidLocalControlTargetError");
727
+ }
728
+ code = "invalid_local_control_target";
729
+ constructor() {
730
+ super("Local Control target must be a valid URL target.");
731
+ this.name = "InvalidLocalControlTargetError";
732
+ }
733
+ };
734
+ var LocalControlService = class {
735
+ static {
736
+ __name(this, "LocalControlService");
737
+ }
738
+ #deps;
739
+ #server;
740
+ #token;
741
+ #selected;
742
+ #sleep;
743
+ #url;
744
+ #transition = Promise.resolve();
745
+ constructor(deps) {
746
+ this.#deps = deps;
747
+ }
748
+ get active() {
749
+ return this.#server !== void 0;
750
+ }
751
+ status() {
752
+ if (!this.#server || !this.#token || !this.#selected) {
753
+ return { active: false };
754
+ }
755
+ return {
756
+ active: true,
757
+ url: this.#url,
758
+ interfaceName: this.#selected.interfaceName,
759
+ address: this.#selected.address,
760
+ port: this.#deps.getPort(),
761
+ sleepInhibited: this.#sleep !== void 0 && sleepInhibitor.isRunning(),
762
+ encrypted: this.#deps.tlsPaths !== void 0
763
+ };
764
+ }
765
+ /**
766
+ * Bring the LAN listener up. Enabling while already active is a no-op that
767
+ * returns the existing status rather than re-minting: a second scan of the
768
+ * same QR must keep working, and silently invalidating the token the user is
769
+ * mid-pairing with would be indistinguishable from a bug.
770
+ */
771
+ async enable(options = {}) {
772
+ return this.#serialize(() => this.#enable(options));
773
+ }
774
+ async #enable(options) {
775
+ if (this.active) return this.status();
776
+ const selected = selectLanAddress(options.address);
777
+ const port = this.#deps.getPort();
778
+ const authority = `${selected.address}:${port}`;
779
+ const token = mintPairingToken();
780
+ const tls = this.#deps.tlsPaths;
781
+ const scheme = tls ? "https" : "http";
782
+ const origin = new URL(`${scheme}://${authority}`).origin;
783
+ const url = buildPairedUrl(scheme, authority, token.secret, options.target);
784
+ const server = tls ? createSecureServer(
785
+ { cert: readFileSync(tls.cert), key: readFileSync(tls.key) },
786
+ this.#deps.app
787
+ ) : createServer(this.#deps.app);
788
+ server.maxConnections = MAX_CONNECTIONS;
789
+ server.headersTimeout = HEADERS_TIMEOUT_MS;
790
+ server.requestTimeout = REQUEST_TIMEOUT_MS;
791
+ server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS;
792
+ tagListener(server, { kind: "local-control", authority, origin });
793
+ this.#deps.credentials.addPairingToken(token.id, token.secret);
794
+ this.#deps.originAllowlist.add(CORS_KEY, origin);
795
+ try {
796
+ this.#deps.attachWebSocket(server);
797
+ await listen(server, port, selected.address);
798
+ } catch (error2) {
799
+ this.#deps.detachWebSocket(server);
800
+ this.#deps.credentials.revokePairingToken(token.id);
801
+ this.#deps.originAllowlist.remove(CORS_KEY);
802
+ throw error2;
803
+ }
804
+ server.on("error", (error2) => {
805
+ writeStderrLine(
806
+ `qwen serve: Local Control listener error: ${error2.message}`
807
+ );
808
+ });
809
+ this.#server = server;
810
+ this.#token = token;
811
+ this.#selected = selected;
812
+ this.#url = url;
813
+ this.#sleep = sleepInhibitor.acquire("Qwen Code Local Control is active");
814
+ return this.status();
815
+ }
816
+ /**
817
+ * Take the LAN listener down and invalidate its credential.
818
+ *
819
+ * Revocation happens first and unconditionally. If closing the socket fails
820
+ * or hangs, the outcome is a listener that accepts connections no credential
821
+ * can authenticate — inert. The reverse order would leave a live, reachable
822
+ * listener with a valid token if teardown failed partway.
823
+ */
824
+ async disable() {
825
+ return this.#serialize(() => this.#disable());
826
+ }
827
+ async #disable() {
828
+ const server = this.#server;
829
+ const token = this.#token;
830
+ this.#server = void 0;
831
+ this.#token = void 0;
832
+ this.#selected = void 0;
833
+ this.#url = void 0;
834
+ if (token) this.#deps.credentials.revokePairingToken(token.id);
835
+ this.#deps.originAllowlist.remove(CORS_KEY);
836
+ this.#sleep?.release();
837
+ this.#sleep = void 0;
838
+ if (server) {
839
+ this.#deps.detachWebSocket(server);
840
+ await close(server);
841
+ }
842
+ return { active: false };
843
+ }
844
+ /**
845
+ * Called from the daemon's drain path. Local Control must not outlive the
846
+ * daemon that owns it: a listener surviving drain would hold the port and
847
+ * keep answering with a token nothing can revoke anymore.
848
+ */
849
+ async dispose() {
850
+ await this.disable();
851
+ }
852
+ async #serialize(operation) {
853
+ const previous = this.#transition;
854
+ let release;
855
+ this.#transition = new Promise((resolve7) => {
856
+ release = resolve7;
857
+ });
858
+ await previous;
859
+ try {
860
+ return await operation();
861
+ } finally {
862
+ release();
863
+ }
864
+ }
865
+ };
866
+ function mintPairingToken() {
867
+ const secret = randomBytes(32).toString("base64url");
868
+ return { id: randomUUID(), secret };
869
+ }
870
+ __name(mintPairingToken, "mintPairingToken");
871
+ function buildPairedUrl(scheme, authority, secret, target) {
872
+ const url = new URL(`${scheme}://${authority}`);
873
+ if (target) {
874
+ let resolved;
875
+ try {
876
+ resolved = new URL(target, url);
877
+ } catch {
878
+ throw new InvalidLocalControlTargetError();
879
+ }
880
+ url.pathname = resolved.pathname;
881
+ url.search = resolved.search;
882
+ }
883
+ url.hash = `token=${encodeURIComponent(secret)}`;
884
+ return url.toString();
885
+ }
886
+ __name(buildPairedUrl, "buildPairedUrl");
887
+ function listen(server, port, host) {
888
+ return new Promise((resolve7, reject) => {
889
+ const onError = /* @__PURE__ */ __name((error2) => {
890
+ server.removeListener("listening", onListening);
891
+ reject(error2);
892
+ }, "onError");
893
+ const onListening = /* @__PURE__ */ __name(() => {
894
+ server.removeListener("error", onError);
895
+ resolve7();
896
+ }, "onListening");
897
+ server.once("error", onError);
898
+ server.once("listening", onListening);
899
+ server.listen(port, host);
900
+ });
901
+ }
902
+ __name(listen, "listen");
903
+ function close(server) {
904
+ return new Promise((resolve7) => {
905
+ server.closeAllConnections?.();
906
+ server.close(() => resolve7());
907
+ });
908
+ }
909
+ __name(close, "close");
910
+
911
+ // packages/cli/src/serve/routes/workspace-local-control.ts
912
+ init_esbuild_shims();
913
+ async function withUiData(status) {
914
+ let qrText;
915
+ if (status.url) {
916
+ try {
917
+ const { default: qrcode } = await import("./main-PXAUXNF2.js");
918
+ qrcode.setErrorLevel("Q");
919
+ qrcode.generate(status.url, { small: true }, (code) => {
920
+ qrText = code.trimEnd();
921
+ });
922
+ } catch {
923
+ qrText = void 0;
924
+ }
925
+ }
926
+ return { ...status, qrText, interfaces: listLanCandidates() };
927
+ }
928
+ __name(withUiData, "withUiData");
929
+ function presentStatus(req, ui) {
930
+ if (requestWasAuthenticated(req)) return ui;
931
+ const { url: _url, qrText: _qrText, ...rest } = ui;
932
+ return { ...rest, urlRedacted: ui.url !== void 0 };
933
+ }
934
+ __name(presentStatus, "presentStatus");
935
+ function requirePrimaryListener(req, res) {
936
+ if (listenerIdentityOf(req).kind === "primary") return true;
937
+ res.status(403).json({
938
+ error: "Local Control can only be enabled from the machine running the daemon.",
939
+ code: "local_control_remote_enable_denied"
940
+ });
941
+ return false;
942
+ }
943
+ __name(requirePrimaryListener, "requirePrimaryListener");
944
+ function registerWorkspaceLocalControlRoutes(app, deps) {
945
+ app.get("/workspace/local-control", async (req, res) => {
946
+ res.status(200).json(presentStatus(req, await withUiData(deps.service.status())));
947
+ });
948
+ app.post(
949
+ "/workspace/local-control/enable",
950
+ deps.mutate(),
951
+ async (req, res) => {
952
+ if (!requirePrimaryListener(req, res)) return;
953
+ if (deps.webShellAvailable === false) {
954
+ res.status(409).json({
955
+ error: "Local Control requires the Web Shell.",
956
+ code: "local_control_web_shell_unavailable"
957
+ });
958
+ return;
959
+ }
960
+ if (deps.primaryBindHostname !== void 0 && !isLoopbackBind(deps.primaryBindHostname)) {
961
+ res.status(409).json({
962
+ error: "Local Control requires the daemon to be bound to loopback; restart it with --hostname 127.0.0.1.",
963
+ code: "local_control_non_loopback_bind"
964
+ });
965
+ return;
966
+ }
967
+ if (deps.isDaemonDraining?.()) {
968
+ res.status(503).json({
969
+ error: "Daemon is shutting down.",
970
+ code: "daemon_draining"
971
+ });
972
+ return;
973
+ }
974
+ const body = deps.safeBody(req) ?? {};
975
+ try {
976
+ const ui = await withUiData(
977
+ await deps.service.enable({
978
+ address: typeof body.address === "string" ? body.address : void 0,
979
+ target: typeof body.target === "string" ? body.target : void 0
980
+ })
981
+ );
982
+ if (!requestWasAuthenticated(req) && ui.url) {
983
+ writeStdoutLineSafe(
984
+ `qwen serve: Local Control pairing URL: ${ui.url}`
985
+ );
986
+ }
987
+ res.status(200).json(presentStatus(req, ui));
988
+ } catch (error2) {
989
+ sendEnableError(res, error2);
990
+ }
991
+ }
992
+ );
993
+ app.post(
994
+ "/workspace/local-control/disable",
995
+ deps.mutate(),
996
+ async (req, res) => {
997
+ if (listenerIdentityOf(req).kind === "local-control") {
998
+ queueMicrotask(() => {
999
+ void deps.service.disable().catch((error2) => {
1000
+ writeStderrLine(
1001
+ `qwen serve: Local Control disable failed: ${error2 instanceof Error ? error2.message : String(error2)}`
1002
+ );
1003
+ });
1004
+ });
1005
+ res.status(200).json({ active: false });
1006
+ return;
1007
+ }
1008
+ res.status(200).json(
1009
+ presentStatus(req, await withUiData(await deps.service.disable()))
1010
+ );
1011
+ }
1012
+ );
1013
+ }
1014
+ __name(registerWorkspaceLocalControlRoutes, "registerWorkspaceLocalControlRoutes");
1015
+ function sendEnableError(res, error2) {
1016
+ if (error2 instanceof AmbiguousLanInterfaceError) {
1017
+ res.status(409).json({
1018
+ error: error2.message,
1019
+ code: error2.code,
1020
+ interfaces: error2.candidates
1021
+ });
1022
+ return;
1023
+ }
1024
+ if (error2 instanceof NoLanInterfaceError) {
1025
+ res.status(409).json({ error: error2.message, code: error2.code });
1026
+ return;
1027
+ }
1028
+ if (error2 instanceof UnknownLanInterfaceError) {
1029
+ res.status(409).json({
1030
+ error: error2.message,
1031
+ code: error2.code,
1032
+ interfaces: listLanCandidates()
1033
+ });
1034
+ return;
1035
+ }
1036
+ if (error2 instanceof InvalidLocalControlTargetError) {
1037
+ res.status(400).json({ error: error2.message, code: error2.code });
1038
+ return;
1039
+ }
1040
+ res.status(500).json({
1041
+ error: error2 instanceof Error ? error2.message : String(error2),
1042
+ code: "local_control_enable_failed"
1043
+ });
1044
+ }
1045
+ __name(sendEnableError, "sendEnableError");
1046
+
613
1047
  // packages/cli/src/serve/acp-http/index.ts
614
1048
  init_esbuild_shims();
615
- import { createHash as createHash3, timingSafeEqual } from "node:crypto";
616
1049
 
617
1050
  // packages/cli/src/serve/acp-http/dispatch.ts
618
1051
  init_esbuild_shims();
@@ -1131,6 +1564,7 @@ function createAuditPublisher(deps) {
1131
1564
  if (record.sizeBytes !== void 0) payload.sizeBytes = record.sizeBytes;
1132
1565
  if (record.truncated) payload.truncated = true;
1133
1566
  if (record.matchedIgnore) payload.matchedIgnore = record.matchedIgnore;
1567
+ if (record.operation !== void 0) payload.operation = record.operation;
1134
1568
  if (record.pattern !== void 0 && includeRawPaths) {
1135
1569
  payload.pattern = record.pattern;
1136
1570
  }
@@ -1177,7 +1611,7 @@ __name(createAuditPublisher, "createAuditPublisher");
1177
1611
 
1178
1612
  // packages/cli/src/serve/fs/workspace-file-system.ts
1179
1613
  init_esbuild_shims();
1180
- import { createHash as createHash2, randomBytes } from "node:crypto";
1614
+ import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
1181
1615
  import { constants as fsConstants, promises as fsp2 } from "node:fs";
1182
1616
  import * as path4 from "node:path";
1183
1617
 
@@ -1238,6 +1672,11 @@ function assertCursorMatchesFile(cursor, stats, path19) {
1238
1672
  __name(assertCursorMatchesFile, "assertCursorMatchesFile");
1239
1673
 
1240
1674
  // packages/cli/src/serve/fs/workspace-file-system.ts
1675
+ var OWNER_ONLY_NEW_FILE_MODE = 384;
1676
+ function resolveNewFileModeBits(policy, umask) {
1677
+ return policy === "system" ? 438 & ~(umask ?? process.umask()) : OWNER_ONLY_NEW_FILE_MODE;
1678
+ }
1679
+ __name(resolveNewFileModeBits, "resolveNewFileModeBits");
1241
1680
  function createWorkspaceFileSystemFactory(deps) {
1242
1681
  const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
1243
1682
  if (boundWorkspaces.length === 0) {
@@ -1263,6 +1702,7 @@ function createWorkspaceFileSystemFactory(deps) {
1263
1702
  });
1264
1703
  const lowFs = new StandardFileSystemService();
1265
1704
  const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
1705
+ const newFileMode = deps.newFileMode ?? "owner";
1266
1706
  const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
1267
1707
  primaryWorkspace,
1268
1708
  workspaces,
@@ -1271,7 +1711,8 @@ function createWorkspaceFileSystemFactory(deps) {
1271
1711
  ctx,
1272
1712
  lowFs,
1273
1713
  pathLocks,
1274
- generationGuard: deps.generationGuard
1714
+ generationGuard: deps.generationGuard,
1715
+ newFileMode
1275
1716
  }), "forRequest");
1276
1717
  return {
1277
1718
  assertCanWrite() {
@@ -1304,7 +1745,8 @@ function createWorkspaceFileSystemFactory(deps) {
1304
1745
  audit,
1305
1746
  ctx,
1306
1747
  pathLocks,
1307
- generationGuard: deps.generationGuard
1748
+ generationGuard: deps.generationGuard,
1749
+ newFileMode
1308
1750
  });
1309
1751
  return;
1310
1752
  } catch (outsideErr) {
@@ -1343,6 +1785,7 @@ async function writeSameHostToolTextOutsideWorkspace(deps) {
1343
1785
  content,
1344
1786
  mode: "overwrite",
1345
1787
  meta,
1788
+ newFileModeBits: resolveNewFileModeBits(deps.newFileMode),
1346
1789
  assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1347
1790
  });
1348
1791
  deps.audit.recordAccess(deps.ctx, {
@@ -1862,6 +2305,7 @@ var WorkspaceFileSystemImpl = class {
1862
2305
  mode: opts.mode,
1863
2306
  expectedHash: opts.expectedHash,
1864
2307
  meta,
2308
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
1865
2309
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1866
2310
  });
1867
2311
  const verdict = this.ignoreVerdict(p, "file");
@@ -1924,6 +2368,7 @@ var WorkspaceFileSystemImpl = class {
1924
2368
  content,
1925
2369
  mode: "overwrite",
1926
2370
  meta,
2371
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
1927
2372
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1928
2373
  });
1929
2374
  const verdict = this.ignoreVerdict(p, "file");
@@ -2035,6 +2480,7 @@ var WorkspaceFileSystemImpl = class {
2035
2480
  mode: "replace",
2036
2481
  expectedHash: opts.expectedHash,
2037
2482
  meta,
2483
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
2038
2484
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2039
2485
  });
2040
2486
  const verdict = this.ignoreVerdict(p, "file");
@@ -2098,6 +2544,7 @@ var WorkspaceFileSystemImpl = class {
2098
2544
  content: next,
2099
2545
  mode: "overwrite",
2100
2546
  meta: mergeWriteMeta(snapshot.meta, {}),
2547
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
2101
2548
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2102
2549
  });
2103
2550
  const verdict = this.ignoreVerdict(p, "file");
@@ -2149,6 +2596,36 @@ var WorkspaceFileSystemImpl = class {
2149
2596
  });
2150
2597
  }
2151
2598
  }
2599
+ async mkdir(p, opts) {
2600
+ const start = performance.now();
2601
+ try {
2602
+ this.deps.generationGuard?.assertOpen();
2603
+ assertTrustedForIntent(this.deps.trusted, "write");
2604
+ const out = await this.deps.pathLocks.runExclusive(
2605
+ p,
2606
+ async () => {
2607
+ await ensureResolvedDirectory(p, {
2608
+ recursive: opts?.recursive ?? false,
2609
+ assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2610
+ });
2611
+ this.deps.generationGuard?.assertOpen();
2612
+ const verdict = this.ignoreVerdict(p, "directory");
2613
+ this.deps.audit.recordAccess(this.deps.ctx, {
2614
+ intent: "write",
2615
+ absolute: p,
2616
+ durationMs: performance.now() - start,
2617
+ sizeBytes: 0,
2618
+ operation: "mkdir",
2619
+ matchedIgnore: verdict.ignored ? verdict.category : void 0
2620
+ });
2621
+ return void 0;
2622
+ }
2623
+ );
2624
+ return out;
2625
+ } catch (err) {
2626
+ throw this.recordAndWrap(err, "write", p);
2627
+ }
2628
+ }
2152
2629
  /**
2153
2630
  * Coerce an arbitrary thrown value into an `FsError`, emit the
2154
2631
  * matching `fs.denied` audit event, and return the typed error
@@ -2632,10 +3109,82 @@ async function atomicWriteTextResolvedFile(input) {
2632
3109
  buf,
2633
3110
  mode: input.mode,
2634
3111
  expectedHash: input.expectedHash,
3112
+ newFileModeBits: input.newFileModeBits,
2635
3113
  assertGenerationOpen: input.assertGenerationOpen
2636
3114
  });
2637
3115
  }
2638
3116
  __name(atomicWriteTextResolvedFile, "atomicWriteTextResolvedFile");
3117
+ async function ensureResolvedDirectory(target, opts) {
3118
+ const assertRealDirectory = /* @__PURE__ */ __name(async (p) => {
3119
+ const st = await fsp2.lstat(p);
3120
+ if (st.isSymbolicLink()) {
3121
+ throw new FsError("symlink_escape", `directory path is a symlink: ${p}`, {
3122
+ hint: "re-resolve the target after detecting symlink swaps"
3123
+ });
3124
+ }
3125
+ if (!st.isDirectory()) {
3126
+ throw new FsError(
3127
+ "parse_error",
3128
+ `path exists and is not a directory: ${p}`
3129
+ );
3130
+ }
3131
+ }, "assertRealDirectory");
3132
+ const assertParentNotSymlink = /* @__PURE__ */ __name(async (p) => {
3133
+ const parent = path4.dirname(p);
3134
+ const st = await fsp2.lstat(parent);
3135
+ if (st.isSymbolicLink()) {
3136
+ throw new FsError(
3137
+ "symlink_escape",
3138
+ `directory parent is a symlink: ${parent}`,
3139
+ { hint: "re-resolve the target after detecting symlink swaps" }
3140
+ );
3141
+ }
3142
+ }, "assertParentNotSymlink");
3143
+ try {
3144
+ await assertRealDirectory(target);
3145
+ return;
3146
+ } catch (err) {
3147
+ if (isFsError(err)) throw err;
3148
+ if (err.code !== "ENOENT") throw err;
3149
+ }
3150
+ if (!opts.recursive) {
3151
+ opts.assertGenerationOpen();
3152
+ await assertParentNotSymlink(target);
3153
+ try {
3154
+ await fsp2.mkdir(target, { mode: 493 });
3155
+ } catch (err) {
3156
+ if (err.code !== "EEXIST") throw err;
3157
+ }
3158
+ await assertRealDirectory(target);
3159
+ return;
3160
+ }
3161
+ const missing = [];
3162
+ let current = target;
3163
+ while (true) {
3164
+ try {
3165
+ await assertRealDirectory(current);
3166
+ break;
3167
+ } catch (err) {
3168
+ if (isFsError(err)) throw err;
3169
+ if (err.code !== "ENOENT") throw err;
3170
+ missing.push(current);
3171
+ const parent = path4.dirname(current);
3172
+ if (parent === current) throw err;
3173
+ current = parent;
3174
+ }
3175
+ }
3176
+ for (const entry of missing.reverse()) {
3177
+ opts.assertGenerationOpen();
3178
+ await assertParentNotSymlink(entry);
3179
+ try {
3180
+ await fsp2.mkdir(entry, { mode: 493 });
3181
+ } catch (err) {
3182
+ if (err.code !== "EEXIST") throw err;
3183
+ }
3184
+ await assertRealDirectory(entry);
3185
+ }
3186
+ }
3187
+ __name(ensureResolvedDirectory, "ensureResolvedDirectory");
2639
3188
  async function atomicPublishResolvedFile(input) {
2640
3189
  const target = input.target;
2641
3190
  const parent = path4.dirname(target);
@@ -2651,7 +3200,7 @@ async function atomicPublishResolvedFile(input) {
2651
3200
  `parent path is not a directory: ${parent}`
2652
3201
  );
2653
3202
  }
2654
- const tmpSuffix = `.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
3203
+ const tmpSuffix = `.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
2655
3204
  const tmpNameMaxBytes = 255;
2656
3205
  const tmpBaseMaxBytes = tmpNameMaxBytes - 1 - Buffer.byteLength(tmpSuffix, "utf-8");
2657
3206
  let tmpBase = path4.basename(target);
@@ -2679,7 +3228,10 @@ async function atomicPublishResolvedFile(input) {
2679
3228
  mode: input.mode,
2680
3229
  expectedHash: input.expectedHash
2681
3230
  });
2682
- await chmodHandleBestEffort(tempHandle, targetState.mode ?? 384);
3231
+ await chmodHandleBestEffort(
3232
+ tempHandle,
3233
+ targetState.mode ?? input.newFileModeBits ?? OWNER_ONLY_NEW_FILE_MODE
3234
+ );
2683
3235
  await assertTempPathMatchesStat(tmpPath, tempStat);
2684
3236
  await tempHandle.close();
2685
3237
  tempHandle = void 0;
@@ -4658,7 +5210,7 @@ __name(registerWorkspaceQualifiedVoiceRoutes, "registerWorkspaceQualifiedVoiceRo
4658
5210
 
4659
5211
  // packages/cli/src/serve/workspace-remember.ts
4660
5212
  init_esbuild_shims();
4661
- import { randomUUID } from "node:crypto";
5213
+ import { randomUUID as randomUUID2 } from "node:crypto";
4662
5214
  var debugLogger = createDebugLogger("WORKSPACE_REMEMBER");
4663
5215
  function requireTrustedWorkspace(deps, res) {
4664
5216
  if (deps.isWorkspaceTrusted?.() !== false) return true;
@@ -4688,7 +5240,7 @@ function nowIso() {
4688
5240
  }
4689
5241
  __name(nowIso, "nowIso");
4690
5242
  function createMemoryTaskId(kind) {
4691
- return `${kind}-${randomUUID()}`;
5243
+ return `${kind}-${randomUUID2()}`;
4692
5244
  }
4693
5245
  __name(createMemoryTaskId, "createMemoryTaskId");
4694
5246
  function touchedScopesFromTopics(topics) {
@@ -8114,6 +8666,7 @@ async function deleteDaemonSessionIfOrphan(params) {
8114
8666
  if (result.kind === "error") {
8115
8667
  throw result.error;
8116
8668
  }
8669
+ bridge.markSessionCatalogChanged();
8117
8670
  return true;
8118
8671
  }
8119
8672
  __name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
@@ -9231,11 +9784,20 @@ var AcpDispatcher = class {
9231
9784
  archiveStates
9232
9785
  });
9233
9786
  }
9787
+ // Combined invalidate-and-mark for catalog mutations whose conservative
9788
+ // finally-semantics match (delete/archive/unarchive). The revision advance
9789
+ // always follows the cache invalidation so a newly exposed version never
9790
+ // precedes it. Exact no-op paths (e.g. metadata rename) gate the mark on
9791
+ // an actual change via the bridge instead of using this helper.
9792
+ invalidateSessionListsAndMarkCatalog(archiveStates) {
9793
+ this.invalidateSessionLists(archiveStates);
9794
+ this.bridge.markSessionCatalogChanged();
9795
+ }
9234
9796
  async runWithSessionListInvalidation(archiveStates, mutation) {
9235
9797
  try {
9236
9798
  return await mutation();
9237
9799
  } finally {
9238
- this.invalidateSessionLists(archiveStates);
9800
+ this.invalidateSessionListsAndMarkCatalog(archiveStates);
9239
9801
  }
9240
9802
  }
9241
9803
  removeOrphanSession(sessionId, removePersistedSession = false, runtime = this.getSessionRuntimeContext()) {
@@ -10718,6 +11280,7 @@ var AcpDispatcher = class {
10718
11280
  ..."groupId" in params ? { groupId: params["groupId"] } : {},
10719
11281
  ..."color" in params ? { color: params["color"] } : {}
10720
11282
  });
11283
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10721
11284
  this.replyConn(conn, id, { sessionId, ...organization });
10722
11285
  });
10723
11286
  return;
@@ -10736,6 +11299,7 @@ var AcpDispatcher = class {
10736
11299
  name: params["name"],
10737
11300
  color: params["color"]
10738
11301
  });
11302
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10739
11303
  assertGenerationOpen?.();
10740
11304
  this.replyConn(conn, id, { group });
10741
11305
  return;
@@ -10753,6 +11317,7 @@ var AcpDispatcher = class {
10753
11317
  ..."color" in params ? { color: params["color"] } : {},
10754
11318
  ..."order" in params ? { order: params["order"] } : {}
10755
11319
  });
11320
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10756
11321
  assertGenerationOpen?.();
10757
11322
  this.replyConn(conn, id, { group });
10758
11323
  return;
@@ -10766,6 +11331,9 @@ var AcpDispatcher = class {
10766
11331
  const deleted = await createSessionOrganizationService(workspaceCwd).deleteGroup(
10767
11332
  groupId
10768
11333
  );
11334
+ if (deleted) {
11335
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
11336
+ }
10769
11337
  assertGenerationOpen?.();
10770
11338
  this.replyConn(conn, id, { deleted });
10771
11339
  return;
@@ -12869,7 +13437,7 @@ var AcpDispatcher = class {
12869
13437
 
12870
13438
  // packages/cli/src/serve/acp-http/connection-registry.ts
12871
13439
  init_esbuild_shims();
12872
- import { randomUUID as randomUUID2 } from "node:crypto";
13440
+ import { randomUUID as randomUUID3 } from "node:crypto";
12873
13441
  var DEFAULT_MAX_CONNECTIONS = 64;
12874
13442
  var AcpConnection = class {
12875
13443
  constructor(connectionId, fromLoopback, onAbandonPending, onDetachSession, preAttachBudget = new AcpPreAttachBudget(), onFatalConnection, maxFramesPerConnection = ACP_PRE_ATTACH_MAX_FRAMES_PER_CONNECTION, maxPayloadBytesPerConnection = ACP_PRE_ATTACH_MAX_PAYLOAD_BYTES_PER_CONNECTION, onPreAttachGuardFailure) {
@@ -12880,8 +13448,8 @@ var AcpConnection = class {
12880
13448
  this.maxFramesPerConnection = maxFramesPerConnection;
12881
13449
  this.maxPayloadBytesPerConnection = maxPayloadBytesPerConnection;
12882
13450
  this.onPreAttachGuardFailure = onPreAttachGuardFailure;
12883
- this.connectionId = connectionId ?? randomUUID2();
12884
- this.clientId = randomUUID2();
13451
+ this.connectionId = connectionId ?? randomUUID3();
13452
+ this.clientId = randomUUID3();
12885
13453
  this.fromLoopback = fromLoopback;
12886
13454
  }
12887
13455
  static {
@@ -15985,9 +16553,15 @@ function mountAcpHttp(app, bridge, opts) {
15985
16553
  }
15986
16554
  let wss;
15987
16555
  let upgradeListener;
15988
- let upgradeServer;
16556
+ const upgradeServers = /* @__PURE__ */ new Set();
16557
+ const upgradeCredentials = opts.credentials ?? singleTokenCredentials(opts.token);
15989
16558
  function setupWebSocket(httpServer) {
15990
- if (disposed || wss) return;
16559
+ if (disposed || upgradeServers.has(httpServer)) return;
16560
+ if (wss) {
16561
+ upgradeServers.add(httpServer);
16562
+ httpServer.on("upgrade", upgradeListener);
16563
+ return;
16564
+ }
15991
16565
  wss = new import_websocket_server.default({
15992
16566
  noServer: true,
15993
16567
  maxPayload: 10 * 1024 * 1024,
@@ -16007,8 +16581,7 @@ function mountAcpHttp(app, bridge, opts) {
16007
16581
  return false;
16008
16582
  }, "handleProtocols")
16009
16583
  });
16010
- upgradeServer = httpServer;
16011
- const expectedTokenHash = opts.token ? createHash3("sha256").update(opts.token).digest() : void 0;
16584
+ upgradeServers.add(httpServer);
16012
16585
  upgradeListener = /* @__PURE__ */ __name((req, socket, head) => {
16013
16586
  if (disposed) {
16014
16587
  socket.destroy();
@@ -16036,8 +16609,18 @@ function mountAcpHttp(app, bridge, opts) {
16036
16609
  return;
16037
16610
  }
16038
16611
  const fromLoopback = isLoopbackSocket(socket);
16039
- if (fromLoopback) {
16040
- const host = (req.headers["host"] ?? "").toLowerCase();
16612
+ const upgradeListenerIdentity = listenerIdentityOfSocket(socket);
16613
+ const host = (req.headers["host"] ?? "").toLowerCase();
16614
+ if (upgradeListenerIdentity.kind === "local-control") {
16615
+ const authority = upgradeListenerIdentity.authority;
16616
+ const browserHost = upgradeListenerIdentity.origin === void 0 ? void 0 : new URL(upgradeListenerIdentity.origin).host.toLowerCase();
16617
+ if (authority === void 0 || host !== authority && host !== browserHost) {
16618
+ logReject(`host-not-allowed ${host || "(missing)"}`);
16619
+ socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
16620
+ socket.destroy();
16621
+ return;
16622
+ }
16623
+ } else if (fromLoopback) {
16041
16624
  const allowed = /* @__PURE__ */ new Set([
16042
16625
  `localhost:${localPort}`,
16043
16626
  `127.0.0.1:${localPort}`,
@@ -16062,7 +16645,8 @@ function mountAcpHttp(app, bridge, opts) {
16062
16645
  try {
16063
16646
  const isLoopbackOrigin = isSameLoopbackOrigin(origin, localPort);
16064
16647
  const isAllowlistedOrigin = opts.allowedOrigins !== void 0 && opts.allowedOrigins.origins.has(origin.toLowerCase());
16065
- if (!isLoopbackOrigin && !isAllowlistedOrigin) {
16648
+ const isListenerOrigin = upgradeListenerIdentity.kind === "local-control" && upgradeListenerIdentity.origin === origin.toLowerCase();
16649
+ if (!isLoopbackOrigin && !isAllowlistedOrigin && !isListenerOrigin) {
16066
16650
  logReject(`origin-not-allowed ${origin}`);
16067
16651
  socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
16068
16652
  socket.destroy();
@@ -16075,10 +16659,9 @@ function mountAcpHttp(app, bridge, opts) {
16075
16659
  return;
16076
16660
  }
16077
16661
  }
16078
- if (opts.token) {
16079
- const credentials = extractUpgradeBearer(req);
16080
- const actual = credentials ? createHash3("sha256").update(credentials).digest() : void 0;
16081
- if (!actual || !expectedTokenHash || actual.length !== expectedTokenHash.length || !timingSafeEqual(expectedTokenHash, actual)) {
16662
+ if (!upgradeCredentials.isOpen(upgradeListenerIdentity)) {
16663
+ const presented = extractUpgradeBearer(req);
16664
+ if (!presented || !upgradeCredentials.verify(presented, upgradeListenerIdentity)) {
16082
16665
  logReject("auth-mismatch");
16083
16666
  socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
16084
16667
  socket.destroy();
@@ -16587,10 +17170,12 @@ function mountAcpHttp(app, bridge, opts) {
16587
17170
  dispose: /* @__PURE__ */ __name(() => {
16588
17171
  if (disposed) return;
16589
17172
  disposed = true;
16590
- if (upgradeServer && upgradeListener) {
16591
- upgradeServer.removeListener("upgrade", upgradeListener);
17173
+ if (upgradeListener) {
17174
+ for (const server of upgradeServers) {
17175
+ server.removeListener("upgrade", upgradeListener);
17176
+ }
17177
+ upgradeServers.clear();
16592
17178
  upgradeListener = void 0;
16593
- upgradeServer = void 0;
16594
17179
  }
16595
17180
  registry.dispose();
16596
17181
  opts.workspaceRememberLane.dispose();
@@ -16730,6 +17315,17 @@ function mountAcpHttp(app, bridge, opts) {
16730
17315
  }, "getSnapshot"),
16731
17316
  attachServer(server) {
16732
17317
  setupWebSocket(server);
17318
+ },
17319
+ detachServer(server) {
17320
+ if (!upgradeServers.delete(server)) return;
17321
+ if (upgradeListener) server.removeListener("upgrade", upgradeListener);
17322
+ if (!wss) return;
17323
+ for (const client of wss.clients) {
17324
+ const clientSocket = client._socket;
17325
+ if (clientSocket?.server === server) {
17326
+ client.terminate();
17327
+ }
17328
+ }
16733
17329
  }
16734
17330
  };
16735
17331
  }
@@ -20777,6 +21373,7 @@ __name(registerWorkspaceQualifiedFileWriteRoutes, "registerWorkspaceQualifiedFil
20777
21373
  var MAX_CONCURRENT_UPLOADS = 4;
20778
21374
  var MAX_UPLOAD_FILENAME_BYTES = 255;
20779
21375
  var NUMBERED_CANDIDATE_CAP = 1e3;
21376
+ var MAX_UPLOAD_DIR_DEPTH = 64;
20780
21377
  var uploadGateLeases = /* @__PURE__ */ new WeakMap();
20781
21378
  function createUploadConcurrencyGate(max = MAX_CONCURRENT_UPLOADS) {
20782
21379
  let active = 0;
@@ -20934,6 +21531,14 @@ function fileUploadAdmission(deps, opts) {
20934
21531
  sendParseError(res, ROUTE2, "`path` must name a file");
20935
21532
  return;
20936
21533
  }
21534
+ if (dir.split("/").filter(Boolean).length > MAX_UPLOAD_DIR_DEPTH) {
21535
+ sendParseError(
21536
+ res,
21537
+ ROUTE2,
21538
+ `directory path exceeds ${MAX_UPLOAD_DIR_DEPTH} components`
21539
+ );
21540
+ return;
21541
+ }
20937
21542
  if (queryPath.includes("\0")) {
20938
21543
  sendParseError(res, ROUTE2, "path must not contain null bytes");
20939
21544
  return;
@@ -20979,10 +21584,11 @@ function fileUploadAdmission(deps, opts) {
20979
21584
  dirStat = await fs9.stat(resolvedDir);
20980
21585
  } catch (err) {
20981
21586
  if (isFsError(err) && err.kind === "path_not_found") {
20982
- sendParseError(res, ROUTE2, "parent directory does not exist");
20983
- return;
21587
+ await fs9.mkdir(resolvedDir, { recursive: true });
21588
+ dirStat = await fs9.stat(resolvedDir);
21589
+ } else {
21590
+ throw err;
20984
21591
  }
20985
- throw err;
20986
21592
  }
20987
21593
  if (dirStat.kind !== "directory") {
20988
21594
  sendParseError(res, ROUTE2, "parent path is not a directory");
@@ -21531,6 +22137,24 @@ var legacySessionTelemetryRoutes = [
21531
22137
  attribution: "handler_resolved",
21532
22138
  route: "POST /session/:id/continue"
21533
22139
  },
22140
+ {
22141
+ method: "POST",
22142
+ path: "/session/:id/media",
22143
+ attribution: "handler_resolved",
22144
+ route: "POST /session/:id/media"
22145
+ },
22146
+ {
22147
+ method: "GET",
22148
+ path: "/session/:id/media/:mediaId",
22149
+ attribution: "handler_resolved",
22150
+ route: "GET /session/:id/media/:mediaId"
22151
+ },
22152
+ {
22153
+ method: "DELETE",
22154
+ path: "/session/:id/media/:mediaId",
22155
+ attribution: "handler_resolved",
22156
+ route: "DELETE /session/:id/media/:mediaId"
22157
+ },
21534
22158
  {
21535
22159
  method: "POST",
21536
22160
  path: "/session/:id/prompt",
@@ -21651,6 +22275,18 @@ var legacySessionTelemetryRoutes = [
21651
22275
  attribution: "handler_resolved",
21652
22276
  route: "DELETE /session/:id/pending-prompts/:promptId"
21653
22277
  },
22278
+ {
22279
+ method: "GET",
22280
+ path: "/session/:id/turns/current",
22281
+ attribution: "handler_resolved",
22282
+ route: "GET /session/:id/turns/current"
22283
+ },
22284
+ {
22285
+ method: "GET",
22286
+ path: "/session/:id/turns/:promptId",
22287
+ attribution: "handler_resolved",
22288
+ route: "GET /session/:id/turns/:promptId"
22289
+ },
21654
22290
  {
21655
22291
  method: "POST",
21656
22292
  path: "/session/:id/shell",
@@ -21779,6 +22415,9 @@ function resolveDaemonTelemetryRoute(req) {
21779
22415
  if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions$/.test(path19)) {
21780
22416
  return { route: "GET /workspace/:id/sessions" };
21781
22417
  }
22418
+ if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions\/live-state$/.test(path19)) {
22419
+ return { route: "GET /workspaces/:workspace/sessions/live-state" };
22420
+ }
21782
22421
  if (req.method === "GET" && /^\/workspace\/[^/]+\/session-info$/.test(path19)) {
21783
22422
  return { route: "GET /workspace/:id/session-info" };
21784
22423
  }
@@ -22212,6 +22851,7 @@ init_esbuild_shims();
22212
22851
  import * as crypto3 from "node:crypto";
22213
22852
  import * as fs6 from "node:fs";
22214
22853
  import * as path12 from "node:path";
22854
+ var import_express4 = __toESM(require_express(), 1);
22215
22855
 
22216
22856
  // packages/cli/src/serve/server/prompt-deadline.ts
22217
22857
  init_esbuild_shims();
@@ -24036,6 +24676,45 @@ var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 2 * SESSION_TRANSCRIPT_MAX_EXPANDE
24036
24676
  var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
24037
24677
  var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
24038
24678
  var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
24679
+ var MEDIA_CONTENT_MAX_BLOCKS = 256;
24680
+ function isSvgMimeType(mimeType) {
24681
+ return mimeType?.split(";", 1)[0]?.trim().toLowerCase() === "image/svg+xml";
24682
+ }
24683
+ __name(isSvgMimeType, "isSvgMimeType");
24684
+ function parseMediaContentBlock(block) {
24685
+ if (typeof block !== "object" || block === null || Array.isArray(block)) {
24686
+ return { valid: false, code: "not-object" };
24687
+ }
24688
+ const record = block;
24689
+ const type = record["type"];
24690
+ const data = record["data"];
24691
+ const mediaId = record["mediaId"];
24692
+ const mimeType = record["mimeType"];
24693
+ const size = record["size"];
24694
+ const inline = typeof data === "string" && data.length > 0;
24695
+ const reference = typeof mediaId === "string" && mediaId.length > 0 && typeof size === "number" && Number.isSafeInteger(size) && size > 0;
24696
+ if (type !== "image" || inline === reference || typeof mimeType !== "string" || !mimeType.startsWith(`${type}/`)) {
24697
+ return { valid: false, code: "invalid-shape" };
24698
+ }
24699
+ if (isSvgMimeType(mimeType)) {
24700
+ return { valid: false, code: "svg" };
24701
+ }
24702
+ return {
24703
+ valid: true,
24704
+ block: inline ? { type, data, mimeType } : { type, mediaId, mimeType, size }
24705
+ };
24706
+ }
24707
+ __name(parseMediaContentBlock, "parseMediaContentBlock");
24708
+ function mediaBlockParseError(code, entryLabel) {
24709
+ if (code === "not-object") {
24710
+ return `each ${entryLabel} must be a media content block`;
24711
+ }
24712
+ if (code === "svg") {
24713
+ return "SVG images are not supported";
24714
+ }
24715
+ return `each ${entryLabel} must be an image block with either \`data\`, or \`mediaId\` and \`size\`, plus a matching \`mimeType\``;
24716
+ }
24717
+ __name(mediaBlockParseError, "mediaBlockParseError");
24039
24718
  var PRIMARY_ONLY_LIVE_SESSION_ROUTES = ["POST /session/:id/cd"];
24040
24719
  var PRIMARY_OR_INTERNAL_LIVE_SESSION_ROUTES = [
24041
24720
  "POST /session/:id/branch",
@@ -24243,11 +24922,15 @@ function registerSessionRoutes(app, deps) {
24243
24922
  archiveStates
24244
24923
  });
24245
24924
  }, "invalidateSessionLists");
24925
+ const invalidateSessionListsAndMarkCatalog = /* @__PURE__ */ __name((runtime, archiveStates) => {
24926
+ invalidateSessionLists(runtime, archiveStates);
24927
+ runtime.bridge.markSessionCatalogChanged();
24928
+ }, "invalidateSessionListsAndMarkCatalog");
24246
24929
  const runWithSessionListInvalidation = /* @__PURE__ */ __name(async (runtime, archiveStates, mutation) => {
24247
24930
  try {
24248
24931
  return await mutation();
24249
24932
  } finally {
24250
- invalidateSessionLists(runtime, archiveStates);
24933
+ invalidateSessionListsAndMarkCatalog(runtime, archiveStates);
24251
24934
  }
24252
24935
  }, "runWithSessionListInvalidation");
24253
24936
  const requestedSessionIdAdmission = deps.requestedSessionIdAdmission ?? createRequestedSessionIdAdmission({
@@ -26459,8 +27142,10 @@ function registerSessionRoutes(app, deps) {
26459
27142
  if (!result.attached) {
26460
27143
  const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
26461
27144
  if (killed) {
26462
- await createWorkspaceRuntimeSessionService(runtime).removeSession(result.sessionId).catch(() => {
26463
- });
27145
+ const removed = await createWorkspaceRuntimeSessionService(
27146
+ runtime
27147
+ ).removeSession(result.sessionId).catch(() => false);
27148
+ if (removed) runtime.bridge.markSessionCatalogChanged();
26464
27149
  }
26465
27150
  } else {
26466
27151
  await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
@@ -26470,11 +27155,12 @@ function registerSessionRoutes(app, deps) {
26470
27155
  }
26471
27156
  if (!res.writable) {
26472
27157
  if (!result.attached) {
26473
- runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
26474
- if (!killed) return void 0;
26475
- return createWorkspaceRuntimeSessionService(
27158
+ runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then(async (killed) => {
27159
+ if (!killed) return;
27160
+ const removed = await createWorkspaceRuntimeSessionService(
26476
27161
  runtime
26477
27162
  ).removeSession(result.sessionId);
27163
+ if (removed) runtime.bridge.markSessionCatalogChanged();
26478
27164
  }).catch(() => {
26479
27165
  });
26480
27166
  } else {
@@ -27061,6 +27747,103 @@ function registerSessionRoutes(app, deps) {
27061
27747
  }
27062
27748
  )
27063
27749
  );
27750
+ app.post(
27751
+ "/session/:id/media",
27752
+ mutate(),
27753
+ import_express4.default.raw({ type: "image/*", limit: "8mb" }),
27754
+ (error2, _req, res, next) => {
27755
+ if (error2 && typeof error2 === "object" && "status" in error2 && error2.status === 413) {
27756
+ res.status(413).json({ error: "Request body too large (max 8 MiB)" });
27757
+ return;
27758
+ }
27759
+ next(error2);
27760
+ },
27761
+ withOwnerMutableSession(
27762
+ "POST /session/:id/media",
27763
+ async (req, res, sessionId, runtime) => {
27764
+ const contentType = req.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
27765
+ if (isSvgMimeType(contentType)) {
27766
+ res.status(415).json({ error: "SVG uploads are not supported" });
27767
+ return;
27768
+ }
27769
+ if (!contentType || !contentType.startsWith("image/") || !Buffer.isBuffer(req.body) || req.body.byteLength === 0) {
27770
+ res.status(400).json({
27771
+ error: "request body must contain image/* bytes with a matching Content-Type"
27772
+ });
27773
+ return;
27774
+ }
27775
+ const clientId = parseClientIdHeader(req, res);
27776
+ if (clientId === null) return;
27777
+ try {
27778
+ const reference = await runtime.bridge.storeSessionMedia(
27779
+ sessionId,
27780
+ req.body,
27781
+ contentType,
27782
+ clientId !== void 0 ? { clientId } : void 0
27783
+ );
27784
+ res.status(201).json(reference);
27785
+ } catch (error2) {
27786
+ if (error2 instanceof RangeError) {
27787
+ res.status(413).json({ error: error2.message });
27788
+ return;
27789
+ }
27790
+ throw error2;
27791
+ }
27792
+ }
27793
+ )
27794
+ );
27795
+ app.get(
27796
+ "/session/:id/media/:mediaId",
27797
+ withOwnerReadSession(
27798
+ "GET /session/:id/media/:mediaId",
27799
+ async (req, res, sessionId, runtime) => {
27800
+ const mediaId = req.params["mediaId"];
27801
+ if (!mediaId) {
27802
+ res.status(400).json({ error: "`mediaId` is required" });
27803
+ return;
27804
+ }
27805
+ const clientId = parseClientIdHeader(req, res);
27806
+ if (clientId === null) return;
27807
+ const media = await runtime.bridge.readSessionMedia(
27808
+ sessionId,
27809
+ mediaId,
27810
+ clientId !== void 0 ? { clientId } : void 0
27811
+ );
27812
+ if (!media) {
27813
+ res.status(404).json({ error: "session media not found" });
27814
+ return;
27815
+ }
27816
+ res.setHeader("Content-Type", media.mimeType);
27817
+ res.setHeader("Content-Length", String(media.data.byteLength));
27818
+ res.setHeader("Cache-Control", "private, max-age=300");
27819
+ res.setHeader("Content-Disposition", "attachment");
27820
+ res.setHeader("X-Content-Type-Options", "nosniff");
27821
+ res.status(200).send(media.data);
27822
+ }
27823
+ )
27824
+ );
27825
+ app.delete(
27826
+ "/session/:id/media/:mediaId",
27827
+ mutate(),
27828
+ withOwnerMutableSession(
27829
+ "DELETE /session/:id/media/:mediaId",
27830
+ async (req, res, sessionId, runtime) => {
27831
+ const mediaId = req.params["mediaId"];
27832
+ if (!mediaId) {
27833
+ res.status(400).json({ error: "`mediaId` is required" });
27834
+ return;
27835
+ }
27836
+ const clientId = parseClientIdHeader(req, res);
27837
+ if (clientId === null) return;
27838
+ const removed = await runtime.bridge.removeSessionMedia(
27839
+ sessionId,
27840
+ mediaId,
27841
+ clientId !== void 0 ? { clientId } : void 0
27842
+ );
27843
+ res.status(200).json({ removed });
27844
+ }
27845
+ )
27846
+ );
27064
27847
  app.post(
27065
27848
  "/session/:id/prompt",
27066
27849
  mutate(),
@@ -27084,6 +27867,25 @@ function registerSessionRoutes(app, deps) {
27084
27867
  });
27085
27868
  return;
27086
27869
  }
27870
+ const mediaBlockCount = prompt.filter(
27871
+ (item) => item["type"] !== "text"
27872
+ ).length;
27873
+ if (mediaBlockCount > MEDIA_CONTENT_MAX_BLOCKS) {
27874
+ res.status(400).json({
27875
+ error: `\`prompt\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
27876
+ });
27877
+ return;
27878
+ }
27879
+ for (const item of prompt) {
27880
+ if (item["type"] !== "image") continue;
27881
+ const parsed = parseMediaContentBlock(item);
27882
+ if (!parsed.valid) {
27883
+ res.status(400).json({
27884
+ error: mediaBlockParseError(parsed.code, "`prompt` image block")
27885
+ });
27886
+ return;
27887
+ }
27888
+ }
27087
27889
  const rawRequestDeadline = body["deadlineMs"];
27088
27890
  let requestDeadlineMs;
27089
27891
  if (rawRequestDeadline !== void 0 && rawRequestDeadline !== null) {
@@ -27638,6 +28440,113 @@ function registerSessionRoutes(app, deps) {
27638
28440
  }
27639
28441
  )
27640
28442
  );
28443
+ app.patch(
28444
+ "/workspaces/:workspace/session/:id/metadata",
28445
+ mutate({ strict: true }),
28446
+ async (req, res) => {
28447
+ const route = "PATCH /workspaces/:workspace/session/:id/metadata";
28448
+ const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
28449
+ if (!runtime) return;
28450
+ const sessionId = requireSessionId(req, res);
28451
+ if (sessionId === null) return;
28452
+ const clientId = parseClientIdHeader(req, res);
28453
+ if (clientId === null) return;
28454
+ const rawDisplayName = safeBody(req)["displayName"];
28455
+ if (typeof rawDisplayName !== "string") {
28456
+ res.status(400).json({
28457
+ error: "`displayName` must be a string",
28458
+ code: "invalid_metadata",
28459
+ field: "displayName"
28460
+ });
28461
+ return;
28462
+ }
28463
+ try {
28464
+ const displayName = rawDisplayName.slice(0, 256);
28465
+ if (displayName.trim() === "") {
28466
+ throw new InvalidSessionMetadataError(
28467
+ "displayName",
28468
+ "must not be empty"
28469
+ );
28470
+ }
28471
+ if (Array.from(displayName).some((character) => {
28472
+ const code = character.charCodeAt(0);
28473
+ return code <= 31 || code === 127;
28474
+ })) {
28475
+ throw new InvalidSessionMetadataError(
28476
+ "displayName",
28477
+ "must not contain control characters"
28478
+ );
28479
+ }
28480
+ await archiveCoordinator.runExclusiveMany([sessionId], async () => {
28481
+ const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
28482
+ assertRuntimeGenerationOpen?.();
28483
+ const liveOwner = workspaceRegistry.resolveLiveSessionOwner(sessionId);
28484
+ if (liveOwner.kind === "unavailable") {
28485
+ sendWorkspaceRuntimeUnavailable(res);
28486
+ return;
28487
+ }
28488
+ if (liveOwner.kind === "ambiguous") {
28489
+ sendAmbiguousSessionOwner(
28490
+ res,
28491
+ route,
28492
+ sessionId,
28493
+ liveOwner.runtimes
28494
+ );
28495
+ return;
28496
+ }
28497
+ if (liveOwner.kind === "found" && liveOwner.runtime.workspaceCwd !== runtime.workspaceCwd) {
28498
+ sendSessionWorkspaceConflict(
28499
+ res,
28500
+ route,
28501
+ sessionId,
28502
+ runtime,
28503
+ liveOwner.runtime
28504
+ );
28505
+ return;
28506
+ }
28507
+ await runWithWorkspaceRuntimeStorage(runtime, async () => {
28508
+ let effective;
28509
+ try {
28510
+ effective = runtime.bridge.updateSessionMetadata(
28511
+ sessionId,
28512
+ { displayName },
28513
+ clientId !== void 0 ? { clientId } : void 0
28514
+ );
28515
+ assertRuntimeGenerationOpen?.();
28516
+ } catch (err) {
28517
+ if (!(err instanceof SessionNotFoundError)) throw err;
28518
+ const service = createWorkspaceRuntimeSessionService(runtime);
28519
+ const location = await service.getSessionLocation(sessionId);
28520
+ assertRuntimeGenerationOpen?.();
28521
+ if (location === "conflict") {
28522
+ throw new SessionConflictError(sessionId);
28523
+ }
28524
+ const renamed = location ? await service.renameSession(
28525
+ sessionId,
28526
+ displayName,
28527
+ "manual",
28528
+ location
28529
+ ) : false;
28530
+ assertRuntimeGenerationOpen?.();
28531
+ if (!renamed) {
28532
+ throw new SessionNotFoundError(sessionId);
28533
+ }
28534
+ runtime.bridge.markSessionCatalogChanged();
28535
+ effective = { displayName: displayName || void 0 };
28536
+ }
28537
+ invalidateSessionLists(runtime, ["active", "archived"]);
28538
+ res.status(200).json({ sessionId, ...effective });
28539
+ });
28540
+ });
28541
+ } catch (err) {
28542
+ sendBridgeError2(res, err, {
28543
+ route,
28544
+ sessionId,
28545
+ workspaceCwd: runtime.workspaceCwd
28546
+ });
28547
+ }
28548
+ }
28549
+ );
27641
28550
  const handleSessionOrganizationUpdate = /* @__PURE__ */ __name(async (req, res, target) => {
27642
28551
  const sessionId = requireSessionId(req, res);
27643
28552
  if (sessionId === null) return;
@@ -27705,6 +28614,10 @@ function registerSessionRoutes(app, deps) {
27705
28614
  ...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
27706
28615
  ...rawColor !== void 0 ? { color: rawColor } : {}
27707
28616
  });
28617
+ invalidateSessionListsAndMarkCatalog(runtime, [
28618
+ "active",
28619
+ "archived"
28620
+ ]);
27708
28621
  res.status(200).json({ sessionId, ...organization });
27709
28622
  });
27710
28623
  })()
@@ -27767,6 +28680,7 @@ function registerSessionRoutes(app, deps) {
27767
28680
  color: body["color"]
27768
28681
  })
27769
28682
  );
28683
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27770
28684
  res.status(201).json({ group });
27771
28685
  } catch (err) {
27772
28686
  if (sendSessionOrganizationError(res, err)) return;
@@ -27794,6 +28708,7 @@ function registerSessionRoutes(app, deps) {
27794
28708
  }
27795
28709
  )
27796
28710
  );
28711
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27797
28712
  res.status(200).json({ group });
27798
28713
  } catch (err) {
27799
28714
  if (sendSessionOrganizationError(res, err)) return;
@@ -27816,6 +28731,9 @@ function registerSessionRoutes(app, deps) {
27816
28731
  req.params["groupId"] ?? ""
27817
28732
  )
27818
28733
  );
28734
+ if (deleted) {
28735
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
28736
+ }
27819
28737
  res.status(200).json({ deleted });
27820
28738
  } catch (err) {
27821
28739
  if (sendSessionOrganizationError(res, err)) return;
@@ -27856,6 +28774,7 @@ function registerSessionRoutes(app, deps) {
27856
28774
  color: body["color"]
27857
28775
  })
27858
28776
  );
28777
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27859
28778
  res.status(201).json({ group });
27860
28779
  } catch (err) {
27861
28780
  if (sendSessionOrganizationError(res, err)) return;
@@ -27883,6 +28802,7 @@ function registerSessionRoutes(app, deps) {
27883
28802
  }
27884
28803
  )
27885
28804
  );
28805
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27886
28806
  res.status(200).json({ group });
27887
28807
  } catch (err) {
27888
28808
  if (sendSessionOrganizationError(res, err)) return;
@@ -27904,6 +28824,9 @@ function registerSessionRoutes(app, deps) {
27904
28824
  req.params["groupId"] ?? ""
27905
28825
  )
27906
28826
  );
28827
+ if (deleted) {
28828
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
28829
+ }
27907
28830
  res.status(200).json({ deleted });
27908
28831
  } catch (err) {
27909
28832
  if (sendSessionOrganizationError(res, err)) return;
@@ -28089,6 +29012,35 @@ function registerSessionRoutes(app, deps) {
28089
29012
  "/workspaces/:workspace/sessions",
28090
29013
  listWorkspaceSessionsHandler("workspace")
28091
29014
  );
29015
+ const lastExposedCatalogVersions = /* @__PURE__ */ new WeakMap();
29016
+ app.get("/workspaces/:workspace/sessions/live-state", async (req, res) => {
29017
+ const route = "GET /workspaces/:workspace/sessions/live-state";
29018
+ const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
29019
+ if (runtime === null) return;
29020
+ const assertRuntimeOpen = captureRuntimeGenerationAssertion(runtime);
29021
+ const bridge = runtime.bridge;
29022
+ try {
29023
+ assertRuntimeOpen?.();
29024
+ const catalogVersion = bridge.getSessionCatalogVersion();
29025
+ const lastExposed = lastExposedCatalogVersions.get(bridge);
29026
+ if (lastExposed === void 0 || lastExposed.generation !== catalogVersion.generation || lastExposed.revision !== catalogVersion.revision) {
29027
+ invalidateSessionLists(runtime, ["active", "archived"]);
29028
+ }
29029
+ const sessions = bridge.listWorkspaceSessions(runtime.workspaceCwd).map((session) => ({
29030
+ sessionId: session.sessionId,
29031
+ clientCount: session.clientCount,
29032
+ hasActivePrompt: session.hasActivePrompt,
29033
+ isWaitingForPermission: session.isWaitingForPermission ?? false,
29034
+ isWaitingForUserQuestion: session.isWaitingForUserQuestion ?? false
29035
+ }));
29036
+ assertRuntimeOpen?.();
29037
+ lastExposedCatalogVersions.set(bridge, catalogVersion);
29038
+ res.setHeader("Cache-Control", "no-store");
29039
+ res.status(200).json({ v: 1, catalogVersion, sessions });
29040
+ } catch (err) {
29041
+ sendBridgeError2(res, err, { route });
29042
+ }
29043
+ });
28092
29044
  const workspaceSessionInfoHandler = /* @__PURE__ */ __name((paramName) => async (req, res) => {
28093
29045
  const route = paramName === "workspace" ? "GET /workspaces/:workspace/session-info" : "GET /workspace/:id/session-info";
28094
29046
  const runtime = resolveRuntimeForCatalogRoute(req, res, paramName, route);
@@ -28257,9 +29209,36 @@ function registerSessionRoutes(app, deps) {
28257
29209
  const message = body["message"];
28258
29210
  const messageId = body["messageId"];
28259
29211
  const trimmed = typeof message === "string" ? message.trim() : "";
28260
- if (trimmed.length === 0) {
29212
+ const rawContent = body["content"];
29213
+ let mediaBlocks;
29214
+ if (rawContent !== void 0) {
29215
+ if (!Array.isArray(rawContent) || rawContent.length === 0) {
29216
+ res.status(400).json({
29217
+ error: "`content` must be a non-empty array of media blocks"
29218
+ });
29219
+ return;
29220
+ }
29221
+ if (rawContent.length > MEDIA_CONTENT_MAX_BLOCKS) {
29222
+ res.status(400).json({
29223
+ error: `\`content\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
29224
+ });
29225
+ return;
29226
+ }
29227
+ mediaBlocks = [];
29228
+ for (const block of rawContent) {
29229
+ const parsed = parseMediaContentBlock(block);
29230
+ if (!parsed.valid) {
29231
+ res.status(400).json({
29232
+ error: mediaBlockParseError(parsed.code, "`content` entry")
29233
+ });
29234
+ return;
29235
+ }
29236
+ mediaBlocks.push(parsed.block);
29237
+ }
29238
+ }
29239
+ if (trimmed.length === 0 && mediaBlocks === void 0) {
28261
29240
  res.status(400).json({
28262
- error: "`message` is required and must be a non-empty string"
29241
+ error: "`message` must be a non-empty string, or `content` must carry at least one media block"
28263
29242
  });
28264
29243
  return;
28265
29244
  }
@@ -28281,7 +29260,8 @@ function registerSessionRoutes(app, deps) {
28281
29260
  sessionId,
28282
29261
  trimmed,
28283
29262
  clientId !== void 0 ? { clientId } : void 0,
28284
- typeof messageId === "string" ? messageId : void 0
29263
+ typeof messageId === "string" ? messageId : void 0,
29264
+ mediaBlocks ? { content: mediaBlocks } : void 0
28285
29265
  );
28286
29266
  res.status(200).json(result);
28287
29267
  }
@@ -28373,6 +29353,73 @@ function registerSessionRoutes(app, deps) {
28373
29353
  }
28374
29354
  )
28375
29355
  );
29356
+ app.get("/session/:id/turns/current", (req, res) => {
29357
+ const sessionId = requireSessionId(req, res);
29358
+ if (sessionId === null) return;
29359
+ const runtime = resolveLiveSessionRuntime(
29360
+ sessionId,
29361
+ res,
29362
+ "GET /session/:id/turns/current"
29363
+ );
29364
+ if (!runtime) return;
29365
+ const clientId = parseClientIdHeader(req, res);
29366
+ if (clientId === null) return;
29367
+ void (async () => {
29368
+ try {
29369
+ const status = await runtime.bridge.getSessionTurnStatus(
29370
+ sessionId,
29371
+ clientId !== void 0 ? { clientId } : void 0
29372
+ );
29373
+ res.status(200).json(status);
29374
+ } catch (err) {
29375
+ sendBridgeError2(res, err, {
29376
+ route: "GET /session/:id/turns/current",
29377
+ sessionId
29378
+ });
29379
+ }
29380
+ })();
29381
+ });
29382
+ app.get("/session/:id/turns/:promptId", (req, res) => {
29383
+ const sessionId = requireSessionId(req, res);
29384
+ if (sessionId === null) return;
29385
+ const runtime = resolveLiveSessionRuntime(
29386
+ sessionId,
29387
+ res,
29388
+ "GET /session/:id/turns/:promptId"
29389
+ );
29390
+ if (!runtime) return;
29391
+ const promptId = req.params["promptId"];
29392
+ if (!promptId) {
29393
+ res.status(400).json({ error: "`promptId` route parameter is required" });
29394
+ return;
29395
+ }
29396
+ const clientId = parseClientIdHeader(req, res);
29397
+ if (clientId === null) return;
29398
+ void (async () => {
29399
+ try {
29400
+ const status = await runtime.bridge.getSessionTurnStatus(
29401
+ sessionId,
29402
+ clientId !== void 0 ? { clientId } : void 0,
29403
+ promptId
29404
+ );
29405
+ if (!status) {
29406
+ res.status(404).json({
29407
+ error: `Prompt ${promptId} not found in session ${sessionId}`,
29408
+ code: "prompt_not_found",
29409
+ sessionId,
29410
+ promptId
29411
+ });
29412
+ return;
29413
+ }
29414
+ res.status(200).json(status);
29415
+ } catch (err) {
29416
+ sendBridgeError2(res, err, {
29417
+ route: "GET /session/:id/turns/:promptId",
29418
+ sessionId
29419
+ });
29420
+ }
29421
+ })();
29422
+ });
28376
29423
  app.post(
28377
29424
  "/session/:id/shell",
28378
29425
  mutate({ strict: true }),
@@ -28634,10 +29681,10 @@ async function teardownBoundSession(target, sessionId) {
28634
29681
  } else if (target.bridge) {
28635
29682
  await target.bridge.closeSession(sessionId).catch(() => {
28636
29683
  });
28637
- await new SessionService(target.workspaceCwd, {
29684
+ const removed = await new SessionService(target.workspaceCwd, {
28638
29685
  runtimeBaseDir: target.runtimeBaseDir
28639
- }).removeSession(sessionId).catch(() => {
28640
- });
29686
+ }).removeSession(sessionId).catch(() => false);
29687
+ if (removed) target.bridge.markSessionCatalogChanged?.();
28641
29688
  }
28642
29689
  }
28643
29690
  __name(teardownBoundSession, "teardownBoundSession");
@@ -29523,7 +30570,7 @@ __name(parseNameField, "parseNameField");
29523
30570
 
29524
30571
  // packages/cli/src/serve/routes/channel-notify.ts
29525
30572
  init_esbuild_shims();
29526
- import { randomUUID as randomUUID6 } from "node:crypto";
30573
+ import { randomUUID as randomUUID7 } from "node:crypto";
29527
30574
  function sendDeliveryError(res, error2) {
29528
30575
  if (!isChannelDeliveryError(error2)) {
29529
30576
  res.status(502).json({
@@ -29544,7 +30591,7 @@ function parseNotifyBody(body) {
29544
30591
  );
29545
30592
  }
29546
30593
  return normalizeChannelDelivery(
29547
- randomUUID6(),
30594
+ randomUUID7(),
29548
30595
  parseChannelDelivery(body["delivery"]),
29549
30596
  body["text"]
29550
30597
  );
@@ -29863,9 +30910,10 @@ function startScheduledTaskKeepalive(opts) {
29863
30910
  const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
29864
30911
  const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
29865
30912
  await bridge.closeSession(sessionId);
29866
- await new SessionService(boundWorkspace, {
30913
+ const removed = await new SessionService(boundWorkspace, {
29867
30914
  runtimeBaseDir: opts.runtimeBaseDir
29868
30915
  }).removeSession(sessionId);
30916
+ if (removed) bridge.markSessionCatalogChanged?.();
29869
30917
  });
29870
30918
  const reviveState = /* @__PURE__ */ new Map();
29871
30919
  const reviving = /* @__PURE__ */ new Set();
@@ -31443,7 +32491,7 @@ __name(registerWorkspaceQualifiedSettingsRoutes, "registerWorkspaceQualifiedSett
31443
32491
 
31444
32492
  // packages/cli/src/serve/routes/sse-events.ts
31445
32493
  init_esbuild_shims();
31446
- import { randomUUID as randomUUID7 } from "node:crypto";
32494
+ import { randomUUID as randomUUID8 } from "node:crypto";
31447
32495
  import { performance as performance2 } from "node:perf_hooks";
31448
32496
 
31449
32497
  // packages/cli/src/serve/server/error-response.ts
@@ -31561,6 +32609,10 @@ function sendBridgeError(res, err, ctx, daemonLog) {
31561
32609
  return;
31562
32610
  }
31563
32611
  if (sendGenerationClosedError(res, err)) return;
32612
+ if (err instanceof Error && "code" in err && (err.code === "session_media_gone" || err.code === "invalid_session_media_reference")) {
32613
+ res.status(err.code === "session_media_gone" ? 410 : 400).json({ error: err.message, code: err.code });
32614
+ return;
32615
+ }
31564
32616
  if (err instanceof SessionWriterError) {
31565
32617
  res.status(err.httpStatus).json({
31566
32618
  error: err.message,
@@ -32132,7 +33184,7 @@ function registerSseEventsRoutes(app, deps) {
32132
33184
  app.get("/session/:id/events", async (req, res) => {
32133
33185
  const sessionId = req.params["id"];
32134
33186
  const diagnosticSessionId = boundedDiagnosticString(sessionId);
32135
- const streamId = randomUUID7();
33187
+ const streamId = randomUUID8();
32136
33188
  const clientId = parseSseClientId(req.headers["x-qwen-client-id"]);
32137
33189
  const connectReason = parseSseConnectReason(req.query["connectReason"]);
32138
33190
  const previousStreamId = parsePreviousSseStreamId(
@@ -33154,6 +34206,19 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
33154
34206
  init_esbuild_shims();
33155
34207
  import * as path15 from "node:path";
33156
34208
  var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
34209
+ var NEW_FILE_MODE_ENV_VAR = "QWEN_SERVE_NEW_FILE_MODE";
34210
+ function parseNewFileModePolicy(env = process.env) {
34211
+ const raw = env[NEW_FILE_MODE_ENV_VAR];
34212
+ if (raw === void 0 || raw.trim() === "") return "owner";
34213
+ const normalized = raw.trim().toLowerCase();
34214
+ if (normalized === "system") return "system";
34215
+ if (normalized === "owner" || normalized === "0600") return "owner";
34216
+ writeStderrLine(
34217
+ `qwen serve: ignoring invalid ${NEW_FILE_MODE_ENV_VAR}=${raw} (expected 'system' or 'owner'); new files keep the 0600 default`
34218
+ );
34219
+ return "owner";
34220
+ }
34221
+ __name(parseNewFileModePolicy, "parseNewFileModePolicy");
33157
34222
  function createDefaultFsAuditEmit() {
33158
34223
  const WARN_EVERY = 100;
33159
34224
  let droppedCount = 0;
@@ -33181,6 +34246,7 @@ function resolveBridgeFsFactory(input) {
33181
34246
  emit: input.emit ?? createDefaultFsAuditEmit(),
33182
34247
  pathLocks: input.pathLocks,
33183
34248
  generationGuard: input.generationGuard,
34249
+ newFileMode: input.newFileMode ?? parseNewFileModePolicy(),
33184
34250
  ...input.customIgnoreFiles !== void 0 ? { customIgnoreFiles: input.customIgnoreFiles } : {}
33185
34251
  });
33186
34252
  }
@@ -33503,9 +34569,9 @@ __name(setupDeviceFlowRegistry, "setupDeviceFlowRegistry");
33503
34569
 
33504
34570
  // packages/cli/src/serve/server/error-handlers.ts
33505
34571
  init_esbuild_shims();
33506
- var import_express4 = __toESM(require_express(), 1);
34572
+ var import_express5 = __toESM(require_express(), 1);
33507
34573
  function installJsonBodyParser(app) {
33508
- app.use(import_express4.default.json({ limit: "10mb" }));
34574
+ app.use(import_express5.default.json({ limit: "10mb" }));
33509
34575
  app.use((err, _req, res, next) => {
33510
34576
  if (sendJsonBodyParserError(res, err)) return;
33511
34577
  next(err);
@@ -38355,8 +39421,8 @@ __name(registerWorkspaceQualifiedSkillsRoutes, "registerWorkspaceQualifiedSkills
38355
39421
 
38356
39422
  // packages/cli/src/serve/routes/channel-webhooks.ts
38357
39423
  init_esbuild_shims();
38358
- var import_express5 = __toESM(require_express(), 1);
38359
- import { createHash as createHash4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
39424
+ var import_express6 = __toESM(require_express(), 1);
39425
+ import { createHash as createHash3, timingSafeEqual } from "node:crypto";
38360
39426
  var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
38361
39427
  "__proto__",
38362
39428
  "constructor",
@@ -38404,7 +39470,7 @@ function registerChannelWebhookRoutes(app, deps) {
38404
39470
  locals.channelWebhook = { channelName, source, sourceConfig };
38405
39471
  next();
38406
39472
  },
38407
- import_express5.default.json({ limit: "1mb" }),
39473
+ import_express6.default.json({ limit: "1mb" }),
38408
39474
  async (req, res) => {
38409
39475
  const locals = res.locals;
38410
39476
  const webhook = locals.channelWebhook;
@@ -38518,9 +39584,9 @@ function matchesWebhookSecret(candidate, expected) {
38518
39584
  if (typeof candidate !== "string") {
38519
39585
  return false;
38520
39586
  }
38521
- const expectedDigest = createHash4("sha256").update(expected).digest();
38522
- const candidateDigest = createHash4("sha256").update(candidate).digest();
38523
- return timingSafeEqual2(expectedDigest, candidateDigest);
39587
+ const expectedDigest = createHash3("sha256").update(expected).digest();
39588
+ const candidateDigest = createHash3("sha256").update(candidate).digest();
39589
+ return timingSafeEqual(expectedDigest, candidateDigest);
38524
39590
  }
38525
39591
  __name(matchesWebhookSecret, "matchesWebhookSecret");
38526
39592
  function readPayload(body, res) {
@@ -38599,7 +39665,7 @@ init_esbuild_shims();
38599
39665
 
38600
39666
  // packages/cli/src/serve/live/live-host-coordinator.ts
38601
39667
  init_esbuild_shims();
38602
- import { randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
39668
+ import { randomUUID as randomUUID9, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
38603
39669
  var DEFAULT_HELLO_TIMEOUT_MS = 5e3;
38604
39670
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
38605
39671
  var DEFAULT_HEARTBEAT_TIMEOUT_MS = 15e3;
@@ -38776,7 +39842,7 @@ __name(projectStatusForHost, "projectStatusForHost");
38776
39842
  var LiveHostCoordinator = class {
38777
39843
  constructor(options) {
38778
39844
  this.options = options;
38779
- this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID8();
39845
+ this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID9();
38780
39846
  this.handlers = options.handlers ?? {};
38781
39847
  this.now = options.now ?? Date.now;
38782
39848
  this.helloTimeoutMs = options.helloTimeoutMs ?? DEFAULT_HELLO_TIMEOUT_MS;
@@ -38845,7 +39911,7 @@ var LiveHostCoordinator = class {
38845
39911
  attachHost(socket, daemonNonce) {
38846
39912
  const expectedNonce = Buffer.from(this.daemonInstanceNonce);
38847
39913
  const presentedNonce = Buffer.from(daemonNonce ?? "");
38848
- if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual3(expectedNonce, presentedNonce)) {
39914
+ if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual2(expectedNonce, presentedNonce)) {
38849
39915
  socket.close(4003, "Invalid daemon instance nonce.");
38850
39916
  return;
38851
39917
  }
@@ -38968,7 +40034,7 @@ var LiveHostCoordinator = class {
38968
40034
  startCall(mode) {
38969
40035
  const call = {
38970
40036
  epoch: ++this.nextEpoch,
38971
- callId: randomUUID8(),
40037
+ callId: randomUUID9(),
38972
40038
  mode,
38973
40039
  state: "starting",
38974
40040
  pendingPermission: false,
@@ -39027,7 +40093,7 @@ var LiveHostCoordinator = class {
39027
40093
  new Error("Qwen Live Host must be connected to change the shortcut.")
39028
40094
  );
39029
40095
  }
39030
- const requestId = randomUUID8();
40096
+ const requestId = randomUUID9();
39031
40097
  return new Promise((resolve7, reject) => {
39032
40098
  const timer = setTimeout(() => {
39033
40099
  this.rejectPendingShortcut(
@@ -39117,7 +40183,7 @@ var LiveHostCoordinator = class {
39117
40183
  )
39118
40184
  );
39119
40185
  }
39120
- const requestId = randomUUID8();
40186
+ const requestId = randomUUID9();
39121
40187
  return new Promise((resolve7, reject) => {
39122
40188
  const timer = setTimeout(() => {
39123
40189
  this.pendingAppshots.delete(requestId);
@@ -39457,7 +40523,7 @@ var LiveHostCoordinator = class {
39457
40523
  this.disconnectHost(lease, 4008, "Live Host heartbeat timed out.");
39458
40524
  return;
39459
40525
  }
39460
- const pingId = randomUUID8();
40526
+ const pingId = randomUUID9();
39461
40527
  lease.pingId = pingId;
39462
40528
  this.sendHost({ type: "host.ping", pingId });
39463
40529
  }
@@ -39725,7 +40791,7 @@ init_esbuild_shims();
39725
40791
 
39726
40792
  // packages/cli/src/serve/live/live-setup-controller.ts
39727
40793
  init_esbuild_shims();
39728
- import { randomUUID as randomUUID10 } from "node:crypto";
40794
+ import { randomUUID as randomUUID11 } from "node:crypto";
39729
40795
 
39730
40796
  // packages/cli/src/serve/live/provider-credentials.ts
39731
40797
  init_esbuild_shims();
@@ -39823,7 +40889,7 @@ __name(resolveLiveProviderCredential, "resolveLiveProviderCredential");
39823
40889
 
39824
40890
  // packages/cli/src/serve/live/qwen-realtime-session.ts
39825
40891
  init_esbuild_shims();
39826
- import { randomUUID as randomUUID9 } from "node:crypto";
40892
+ import { randomUUID as randomUUID10 } from "node:crypto";
39827
40893
  var QWEN_REALTIME_LIMITS = {
39828
40894
  maxInputAudioFrameBytes: 64 * 1024,
39829
40895
  maxOutputAudioFrameBytes: 256 * 1024,
@@ -40238,7 +41304,7 @@ function openQwenRealtimeSession(config, callbacks = {}, deps = {}) {
40238
41304
  const sendJson = /* @__PURE__ */ __name((body) => {
40239
41305
  if (terminal || closedByClient || ws.readyState !== ws.OPEN) return false;
40240
41306
  try {
40241
- ws.send(JSON.stringify({ event_id: randomUUID9(), ...body }));
41307
+ ws.send(JSON.stringify({ event_id: randomUUID10(), ...body }));
40242
41308
  return true;
40243
41309
  } catch (error2) {
40244
41310
  fail(
@@ -41601,7 +42667,7 @@ async function validateCredential(credential) {
41601
42667
  apiKey: credential.apiKey,
41602
42668
  model: credential.realtimeModel,
41603
42669
  voice: credential.voice,
41604
- callEpoch: `setup-${randomUUID10()}`
42670
+ callEpoch: `setup-${randomUUID11()}`
41605
42671
  });
41606
42672
  session.close({ discardPendingInput: true });
41607
42673
  }
@@ -41908,7 +42974,7 @@ __name(registerLiveSetupRoutes, "registerLiveSetupRoutes");
41908
42974
  // packages/cli/src/serve/live/live-host-installer.ts
41909
42975
  init_esbuild_shims();
41910
42976
  import { execFile as execFile3 } from "node:child_process";
41911
- import { createHash as createHash5, randomUUID as randomUUID11 } from "node:crypto";
42977
+ import { createHash as createHash4, randomUUID as randomUUID12 } from "node:crypto";
41912
42978
  import * as fs7 from "node:fs";
41913
42979
  import * as fsp5 from "node:fs/promises";
41914
42980
  import * as os2 from "node:os";
@@ -42083,7 +43149,7 @@ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
42083
43149
  });
42084
43150
  throw new Error("Live Host download size does not match its manifest.");
42085
43151
  }
42086
- const hash = createHash5("sha256");
43152
+ const hash = createHash4("sha256");
42087
43153
  let received = 0;
42088
43154
  const guard = new Transform({
42089
43155
  transform(chunk, _encoding, callback) {
@@ -42139,8 +43205,8 @@ async function installLatestHost(currentArchitecture, onStatus) {
42139
43205
  const archivePath = path16.join(temporaryDirectory, "Qwen-Live-Host.zip");
42140
43206
  const extractedPath = path16.join(temporaryDirectory, "extracted");
42141
43207
  const candidatePath = path16.join(extractedPath, LIVE_HOST_APP_NAME);
42142
- const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID11()}.app`;
42143
- const backupPath = `/Applications/.Qwen Live Host.backup-${randomUUID11()}.app`;
43208
+ const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID12()}.app`;
43209
+ const backupPath = `/Applications/.Qwen Live Host.backup-${randomUUID12()}.app`;
42144
43210
  let movedExisting = false;
42145
43211
  let installedCandidate = false;
42146
43212
  try {
@@ -42288,7 +43354,7 @@ var LiveHostInstaller = class {
42288
43354
 
42289
43355
  // packages/cli/src/serve/live/live-session-coordinator.ts
42290
43356
  init_esbuild_shims();
42291
- import { createHash as createHash6, randomUUID as randomUUID12 } from "node:crypto";
43357
+ import { createHash as createHash5, randomUUID as randomUUID13 } from "node:crypto";
42292
43358
  import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync2 } from "node:fs";
42293
43359
  import { join as join12 } from "node:path";
42294
43360
 
@@ -42663,7 +43729,7 @@ function openLiveAudioCapture(source, identifier) {
42663
43729
  );
42664
43730
  const stream = createWriteStream2(path19, { flags: "wx", mode: 384 });
42665
43731
  stream.on("error", () => void 0);
42666
- return { source, path: path19, stream, hash: createHash6("sha256"), bytes: 0 };
43732
+ return { source, path: path19, stream, hash: createHash5("sha256"), bytes: 0 };
42667
43733
  } catch {
42668
43734
  return void 0;
42669
43735
  }
@@ -43018,7 +44084,7 @@ var LiveSessionCoordinator = class {
43018
44084
  context.speechInProgress = true;
43019
44085
  context.inputCommitPending = true;
43020
44086
  context.inputAwaitingResponse = false;
43021
- const partialItemId = itemId ?? `partial:${randomUUID12()}`;
44087
+ const partialItemId = itemId ?? `partial:${randomUUID13()}`;
43022
44088
  context.activePartialInputItemId = partialItemId;
43023
44089
  if (!context.partialInputTranscripts.has(partialItemId)) {
43024
44090
  context.partialInputTranscripts.set(partialItemId, "");
@@ -43048,7 +44114,7 @@ var LiveSessionCoordinator = class {
43048
44114
  }, "onInputCommitted"),
43049
44115
  onInputTranscriptDelta: /* @__PURE__ */ __name(({ itemId, text }) => {
43050
44116
  if (this.isCurrentSocket(context, generation)) {
43051
- const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID12()}`;
44117
+ const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID13()}`;
43052
44118
  context.activePartialInputItemId = partialItemId;
43053
44119
  context.partialInputTranscripts.set(partialItemId, text);
43054
44120
  this.options.host.setTranscript?.(context.epoch, text);
@@ -43058,7 +44124,7 @@ var LiveSessionCoordinator = class {
43058
44124
  if (this.isCurrentSocket(context, generation)) {
43059
44125
  context.speechInProgress = false;
43060
44126
  context.inputCommitPending = false;
43061
- const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID12()}`;
44127
+ const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID13()}`;
43062
44128
  context.partialInputTranscripts.delete(completedItemId);
43063
44129
  if (context.activePartialInputItemId === completedItemId) {
43064
44130
  context.activePartialInputItemId = void 0;
@@ -43774,9 +44840,10 @@ var LiveSessionCoordinator = class {
43774
44840
  if (!sessionClosed) return;
43775
44841
  if (removeFreshTranscript) {
43776
44842
  try {
43777
- await new SessionService(runtime.workspaceCwd).removeSession(
43778
- session.sessionId
43779
- );
44843
+ const transcriptRemoved = await new SessionService(
44844
+ runtime.workspaceCwd
44845
+ ).removeSession(session.sessionId);
44846
+ if (transcriptRemoved) bridge.markSessionCatalogChanged();
43780
44847
  } catch {
43781
44848
  }
43782
44849
  }
@@ -43789,7 +44856,7 @@ var LiveSessionCoordinator = class {
43789
44856
  const runtime = context.runtime;
43790
44857
  if (!runtime) throw new Error("Conversation workspace is unavailable.");
43791
44858
  const bridge = runtime.bridge;
43792
- const promptId = randomUUID12();
44859
+ const promptId = randomUUID13();
43793
44860
  const lastEventId = bridge.getSessionLastEventId(locator.sessionId);
43794
44861
  const turnAbort = new AbortController();
43795
44862
  this.inFlightTurnAborts.add(turnAbort);
@@ -44106,7 +45173,7 @@ var LiveSessionCoordinator = class {
44106
45173
 
44107
45174
  // packages/cli/src/serve/live/live-task-service.ts
44108
45175
  init_esbuild_shims();
44109
- import { randomUUID as randomUUID13 } from "node:crypto";
45176
+ import { randomUUID as randomUUID14 } from "node:crypto";
44110
45177
  var DEFAULT_LIST_LIMIT = 20;
44111
45178
  var DEFAULT_READ_TURN_LIMIT = 3;
44112
45179
  var DEFAULT_WAIT_TIMEOUT_MS = 12e4;
@@ -44823,7 +45890,7 @@ var LiveTaskService = class {
44823
45890
  { sessionId, prompt: [{ type: "text", text: prompt }] },
44824
45891
  void 0,
44825
45892
  {
44826
- promptId: randomUUID13(),
45893
+ promptId: randomUUID14(),
44827
45894
  onPromptAdmitted: /* @__PURE__ */ __name(() => {
44828
45895
  admitted = true;
44829
45896
  onAdmitted?.();
@@ -44889,10 +45956,11 @@ var LiveTaskService = class {
44889
45956
  removed = false;
44890
45957
  }
44891
45958
  if (removed) {
44892
- await runWithWorkspaceRuntimeStorage(
45959
+ const persistedRemoved = await runWithWorkspaceRuntimeStorage(
44893
45960
  runtime,
44894
- () => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => void 0)
45961
+ () => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => false)
44895
45962
  );
45963
+ if (persistedRemoved) runtime.bridge.markSessionCatalogChanged();
44896
45964
  }
44897
45965
  if (projectless && removed) {
44898
45966
  await this.options.discardEmptyConversationDirectory(session.sessionId).catch(() => void 0);
@@ -45078,7 +46146,7 @@ var ConversationRuntimeManager = class {
45078
46146
 
45079
46147
  // packages/cli/src/serve/conversations/conversation-runtime-ownership.ts
45080
46148
  init_esbuild_shims();
45081
- import { randomUUID as randomUUID14 } from "node:crypto";
46149
+ import { randomUUID as randomUUID15 } from "node:crypto";
45082
46150
  import { constants as fsConstants2 } from "node:fs";
45083
46151
  import * as fs8 from "node:fs/promises";
45084
46152
  import * as path17 from "node:path";
@@ -45214,16 +46282,20 @@ async function readOwnerRecord(ownerPath) {
45214
46282
  process.platform === "win32" ? fsConstants2.O_RDONLY : fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW
45215
46283
  );
45216
46284
  } catch (error2) {
45217
- throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
46285
+ if (error2.code === "ELOOP") {
46286
+ throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
46287
+ }
46288
+ throw error2;
45218
46289
  }
45219
46290
  try {
45220
46291
  const handleStat = await handle.stat();
45221
46292
  if (!handleStat.isFile() || handleStat.nlink !== 1 || handleStat.dev !== pathStat.dev || handleStat.ino !== pathStat.ino || handleStat.size !== pathStat.size || process.platform !== "win32" && ((handleStat.mode & 511) !== 384 || typeof process.getuid === "function" && handleStat.uid !== process.getuid())) {
45222
46293
  throw new UnsafeOwnershipStateError();
45223
46294
  }
46295
+ const serialized = await handle.readFile("utf8");
45224
46296
  let parsed;
45225
46297
  try {
45226
- parsed = JSON.parse(await handle.readFile("utf8"));
46298
+ parsed = JSON.parse(serialized);
45227
46299
  } catch (error2) {
45228
46300
  throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
45229
46301
  }
@@ -45349,7 +46421,7 @@ var FileConversationRuntimeOwnership = class {
45349
46421
  await this.commitRecord(identity, void 0);
45350
46422
  }
45351
46423
  }, "commitOwner");
45352
- const liveDiscovery = await import("./discovery-ORA5J7YP.js");
46424
+ const liveDiscovery = await import("./discovery-X2NV535U.js");
45353
46425
  const handoff = await liveDiscovery.handoffLiveDiscoveryOwner(
45354
46426
  this.stableBaseDir,
45355
46427
  this.current,
@@ -45466,7 +46538,7 @@ var FileConversationRuntimeOwnership = class {
45466
46538
  async commitRecord(identity, expected) {
45467
46539
  const temporaryPath = path17.join(
45468
46540
  this.ownerDirectory,
45469
- `.runtime-owner.${this.current.pid}.${randomUUID14()}.tmp`
46541
+ `.runtime-owner.${this.current.pid}.${randomUUID15()}.tmp`
45470
46542
  );
45471
46543
  let handle;
45472
46544
  let renamed = false;
@@ -45646,7 +46718,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
45646
46718
  "createServeApp: runtime replacement/removal requires deps.getSessionBridges so session-id admission can inspect draining generations."
45647
46719
  );
45648
46720
  }
45649
- const app = (0, import_express6.default)();
46721
+ const app = (0, import_express7.default)();
45650
46722
  const serveAppLifecycle = installServeAppLifecycle(
45651
46723
  app,
45652
46724
  deps.serveAppLifecycle
@@ -46307,18 +47379,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46307
47379
  app.locals.stopWorkspaceGitState = () => workspaceGitState.dispose();
46308
47380
  app.locals.stopWorkspaceGitStateForWorkspace = (workspaceCwd) => workspaceGitState.disposeWorkspace(workspaceCwd);
46309
47381
  const workspaceQualifiedAcpEnabled = acpHttpEnabledAtBoot;
46310
- if (opts.allowOrigins && opts.allowOrigins.length > 0) {
46311
- const parsedAllowOrigins = parseAllowOriginPatterns(opts.allowOrigins);
46312
- if (parsedAllowOrigins.allowAny && !opts.token) {
46313
- throw new Error(
46314
- `Refusing to start with --allow-origin '*' but no bearer token configured. '*' admits any cross-origin browser to the API; without a token, any local page can drive the daemon. Set a token or list specific origins instead of '*'.`
46315
- );
46316
- }
46317
- app.use(allowOriginCors(parsedAllowOrigins));
46318
- } else {
46319
- app.use(denyBrowserOriginCors);
47382
+ const parsedAllowOrigins = parseAllowOriginPatterns(opts.allowOrigins ?? []);
47383
+ if (parsedAllowOrigins.allowAny && !opts.token) {
47384
+ throw new Error(
47385
+ `Refusing to start with --allow-origin '*' but no bearer token configured. '*' admits any cross-origin browser to the API; without a token, any local page can drive the daemon. Set a token or list specific origins instead of '*'.`
47386
+ );
46320
47387
  }
47388
+ const originAllowlist = new MutableOriginAllowlist(parsedAllowOrigins);
47389
+ app.use(allowOriginCors(originAllowlist));
46321
47390
  app.use(hostAllowlist(opts.hostname, getPort));
47391
+ const credentials = new CredentialStore(opts.token);
47392
+ const authenticate = bearerAuth(credentials);
46322
47393
  const rateLimiter = installRateLimiter(app, opts, daemonLog, {
46323
47394
  mount: false,
46324
47395
  workspaceQualifiedAcpEnabled
@@ -46330,6 +47401,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46330
47401
  getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
46331
47402
  });
46332
47403
  if (healthRoutes.exposeHealthPreAuth) {
47404
+ app.use("/health", (req, res, next) => {
47405
+ if (listenerIdentityOf(req).kind === "local-control") {
47406
+ authenticate(req, res, next);
47407
+ return;
47408
+ }
47409
+ next();
47410
+ });
46333
47411
  healthRoutes.register(app);
46334
47412
  }
46335
47413
  installAccessLogMiddleware(app, daemonLog);
@@ -46373,7 +47451,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46373
47451
  daemonLog
46374
47452
  });
46375
47453
  }
46376
- app.use(bearerAuth(opts.token));
47454
+ app.use(authenticate);
46377
47455
  if (rateLimiter) {
46378
47456
  app.use(rateLimiter.middleware);
46379
47457
  }
@@ -47151,6 +48229,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
47151
48229
  fsFactory: primaryRouteFileSystemFactory,
47152
48230
  deviceFlowRegistry,
47153
48231
  token: opts.token,
48232
+ // The WS upgrade bypasses Express middleware, so it needs the same
48233
+ // listener-scoped credentials the REST gate uses — otherwise the
48234
+ // `qwen-bearer.*` subprotocol would be a way around the scoping.
48235
+ credentials,
47154
48236
  // Mirror the REST CORS allowlist onto the WS CSRF wall so an
47155
48237
  // explicitly permitted origin (e.g. the extension's
47156
48238
  // `chrome-extension://<id>`) can open the reverse tool channel.
@@ -47222,6 +48304,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
47222
48304
  if (acpHandleRef.current) {
47223
48305
  app.locals["acpHandle"] = acpHandleRef.current;
47224
48306
  }
48307
+ const localControlService = new LocalControlService({
48308
+ app,
48309
+ credentials,
48310
+ originAllowlist,
48311
+ // Resolved through the ref on each call rather than captured so Local
48312
+ // Control cannot attach to a stale ACP mount.
48313
+ attachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.attachServer(server), "attachWebSocket"),
48314
+ detachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.detachServer(server), "detachWebSocket"),
48315
+ getPort,
48316
+ tlsPaths: opts.tlsCert && opts.tlsKey ? { cert: opts.tlsCert, key: opts.tlsKey } : void 0
48317
+ });
48318
+ app.locals["localControlService"] = localControlService;
48319
+ registerWorkspaceLocalControlRoutes(app, {
48320
+ service: localControlService,
48321
+ mutate,
48322
+ safeBody,
48323
+ isDaemonDraining: deps.isChannelControlDraining,
48324
+ webShellAvailable: Boolean(webShellDir),
48325
+ primaryBindHostname: opts.hostname
48326
+ });
47225
48327
  if (webShellDir) {
47226
48328
  mountWebShellSpaFallback(app, webShellDir, webShellFrameAncestors);
47227
48329
  }