@qwen-code/qwen-code 0.21.13 → 0.21.14-nightly.20260822.7a4566cb3b

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 (400) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +15 -7
  2. package/bundled/qc-helper/docs/extension/introduction.md +2 -0
  3. package/bundled/qc-helper/docs/features/_meta.ts +1 -0
  4. package/bundled/qc-helper/docs/features/channels/dingtalk.md +1 -1
  5. package/bundled/qc-helper/docs/features/code-review.md +25 -3
  6. package/bundled/qc-helper/docs/features/commands.md +120 -8
  7. package/bundled/qc-helper/docs/features/markdown-rendering.md +6 -0
  8. package/bundled/qc-helper/docs/features/sub-agents.md +3 -3
  9. package/bundled/qc-helper/docs/features/terminal-images.md +50 -0
  10. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
  11. package/bundled/qc-helper/docs/qwen-serve.md +21 -4
  12. package/bundled/review/SKILL.md +113 -62
  13. package/chunks/MaxSizedBox-NCWYES5B.js +98 -0
  14. package/chunks/{StandaloneSessionPicker-KEGXNUG6.js → StandaloneSessionPicker-A4V4F64Y.js} +80 -79
  15. package/chunks/{acp-startup-profiler-NMDXYGDN.js → acp-startup-profiler-DDVSJKJK.js} +2 -2
  16. package/chunks/{acpAgent-XPES32S7.js → acpAgent-YYRH7HTQ.js} +1094 -278
  17. package/chunks/{agent-DPTOZFEM.js → agent-NEM254CJ.js} +52 -51
  18. package/chunks/agent-headless-AVFYIRPV.js +88 -0
  19. package/chunks/{anthropicContentGenerator-G7BVXTKN.js → anthropicContentGenerator-IWFTSBSV.js} +25 -25
  20. package/chunks/{artifact-tool-GEXTOPVO.js → artifact-tool-SBXMTVCB.js} +3 -3
  21. package/chunks/{askUserQuestion-B33XRSB7.js → askUserQuestion-KEQJRFD6.js} +3 -3
  22. package/chunks/{bridge-YNQBAA4Z.js → bridge-2CGOUO25.js} +59 -57
  23. package/chunks/{ca-4CQ6MYNQ.js → ca-SLZJD6QH.js} +8 -0
  24. package/chunks/{channel-management-service-GWY2GAIC.js → channel-management-service-FUJ2EFTF.js} +1 -1
  25. package/chunks/channel-settings-store-AZKNHHDC.js +103 -0
  26. package/chunks/{channel-worker-group-7LXCMZ77.js → channel-worker-group-CTE54QL6.js} +8 -7
  27. package/chunks/{channel-worker-manager-RYEME4ZZ.js → channel-worker-manager-4EHTD3T4.js} +8 -7
  28. package/chunks/{channel-worker-supervisor-OEVWBHGT.js → channel-worker-supervisor-F6I6WSWW.js} +6 -5
  29. package/chunks/{chunk-KD5BOPLP.js → chunk-2G4QF4VI.js} +125 -31
  30. package/chunks/{chunk-BHILXOC3.js → chunk-2MTIAN5Z.js} +3 -3
  31. package/chunks/{chunk-A4QRWUDE.js → chunk-2NWPB6T4.js} +6 -6
  32. package/chunks/{chunk-KV27IEHM.js → chunk-2TRNCJK4.js} +1 -1
  33. package/chunks/{chunk-EL5SXY3T.js → chunk-32CHFLGV.js} +198 -23
  34. package/chunks/{chunk-5CVO7YES.js → chunk-36OF5PRW.js} +1 -1
  35. package/chunks/{chunk-X26JYGTD.js → chunk-37BZSWEV.js} +1 -1
  36. package/chunks/{chunk-WFSTRPRO.js → chunk-3CLIDIVQ.js} +3 -3
  37. package/chunks/{chunk-A267JX7H.js → chunk-3HWN4E7N.js} +18 -18
  38. package/chunks/{chunk-ZYYTZUI2.js → chunk-3LYGXZ2H.js} +3 -3
  39. package/chunks/chunk-3SIGAHUX.js +3969 -0
  40. package/chunks/{chunk-BVJS5BSP.js → chunk-3XD4PT3B.js} +1 -1
  41. package/chunks/{chunk-6QFDQMQX.js → chunk-3ZFJUBTP.js} +1 -1
  42. package/chunks/{chunk-HUTNYWBG.js → chunk-45UD2TU4.js} +19 -11
  43. package/chunks/{chunk-4W5U2TUT.js → chunk-4F5WV4RF.js} +4 -4
  44. package/chunks/{chunk-I3G5JWBV.js → chunk-4GP3MNQ2.js} +2695 -1524
  45. package/chunks/{chunk-V26NVGAU.js → chunk-4MIDDJLJ.js} +8 -3
  46. package/chunks/{chunk-TS6625XH.js → chunk-5MK45KZ3.js} +9 -5
  47. package/chunks/{chunk-V57QC6WW.js → chunk-5OTMZVPL.js} +11 -9
  48. package/chunks/{chunk-MC4TLKEI.js → chunk-5PHLBWBL.js} +3 -3
  49. package/chunks/chunk-64LXOKG4.js +367 -0
  50. package/chunks/{chunk-6HY6IF3Z.js → chunk-6NFAEG54.js} +22 -2
  51. package/chunks/{chunk-TIGA2IVL.js → chunk-6NJIPX6W.js} +10 -298
  52. package/chunks/{chunk-MRMJCLIY.js → chunk-6RB2S4QP.js} +3 -3
  53. package/chunks/chunk-6S2OXVJT.js +369 -0
  54. package/chunks/{chunk-O4D7SPJN.js → chunk-6U46RZ25.js} +3 -3
  55. package/chunks/{chunk-JOOFMXGF.js → chunk-6UDHEIUT.js} +6 -6
  56. package/chunks/{chunk-VOQXFAY5.js → chunk-74TONY4F.js} +286 -0
  57. package/chunks/{chunk-LJQAUZMR.js → chunk-7CPJMZVJ.js} +1627 -180
  58. package/chunks/{chunk-T3CHYWJZ.js → chunk-7E7UCJHS.js} +100 -4
  59. package/chunks/{chunk-YZHRN3CF.js → chunk-7IV52LTO.js} +2 -2
  60. package/chunks/{chunk-4PKCUT7F.js → chunk-7JDGSJQH.js} +7 -7
  61. package/chunks/{chunk-GO7STP6N.js → chunk-7VITNOH6.js} +4 -4
  62. package/chunks/{chunk-CU6GJD55.js → chunk-7WLFSDLG.js} +1 -1
  63. package/chunks/{chunk-4WKAA4KS.js → chunk-A4N4FTMH.js} +1 -11
  64. package/chunks/{chunk-BUQDLC2G.js → chunk-A5F2YNO6.js} +3 -3
  65. package/chunks/{chunk-OY5RNSV4.js → chunk-AGCLK4G7.js} +3 -3
  66. package/chunks/{chunk-IA2K2HJE.js → chunk-AP3B7LKD.js} +2 -2
  67. package/chunks/{chunk-Y3YCSWG5.js → chunk-AZF6SME3.js} +2 -2
  68. package/chunks/{chunk-QFJ5JHQR.js → chunk-C72BXMJ5.js} +1 -1
  69. package/chunks/chunk-CETB5XY4.js +3654 -0
  70. package/chunks/{chunk-AA2BEKV3.js → chunk-CTAP6PO3.js} +3 -3
  71. package/chunks/{chunk-MS7GNABG.js → chunk-CXJHQVEK.js} +8 -0
  72. package/chunks/{chunk-QF2NHSPB.js → chunk-D534POS2.js} +274 -225
  73. package/chunks/{chunk-UKMR3CKV.js → chunk-D7QQ6RUB.js} +24 -9
  74. package/chunks/{chunk-DXIBNLBZ.js → chunk-DB2OKNTU.js} +2 -2
  75. package/chunks/{chunk-DGZEMW5R.js → chunk-DJEHYM4H.js} +3 -3
  76. package/chunks/{chunk-O565M6A4.js → chunk-DRVS6K7A.js} +260 -16
  77. package/chunks/{chunk-U3VNBPUO.js → chunk-DV4375RD.js} +5 -5
  78. package/chunks/{chunk-OXCMMLED.js → chunk-E63A23D7.js} +3 -3
  79. package/chunks/{chunk-4NFY2S7N.js → chunk-E7REAOTN.js} +15 -0
  80. package/chunks/{chunk-6ORZ2EDC.js → chunk-EW2IQ3ID.js} +3 -3
  81. package/chunks/{chunk-DGK6P3BQ.js → chunk-EXVK5R7X.js} +13 -13
  82. package/chunks/{chunk-NWNEANAT.js → chunk-FOGQO4FG.js} +953 -660
  83. package/chunks/{chunk-3U3VAL47.js → chunk-FV6PXZRO.js} +1 -1
  84. package/chunks/{chunk-76J3IJ3M.js → chunk-FX5TGHDE.js} +8 -8
  85. package/chunks/{chunk-QIH2HAEN.js → chunk-GXG4PYQB.js} +1 -1
  86. package/chunks/{chunk-FDGGZIYW.js → chunk-HDKCKCYO.js} +3 -3
  87. package/chunks/{chunk-RIAABG2K.js → chunk-HERHU33B.js} +2 -2
  88. package/chunks/{chunk-ZYBBISBY.js → chunk-HETN3NE2.js} +18 -15
  89. package/chunks/{chunk-XIT3GURH.js → chunk-HGBACZGD.js} +3 -3
  90. package/chunks/{chunk-UZPM4XHR.js → chunk-HGH7DXNI.js} +29 -8
  91. package/chunks/{chunk-CHHABXPE.js → chunk-HIK2OF33.js} +1 -1
  92. package/chunks/{chunk-FC4KQFCS.js → chunk-HMJ2P3SV.js} +1 -1
  93. package/chunks/chunk-HRVMTN37.js +26 -0
  94. package/chunks/{chunk-PQ36L4F5.js → chunk-HZZGYJIP.js} +1 -1
  95. package/chunks/{chunk-PT4I7NBA.js → chunk-I432KXWD.js} +1 -1
  96. package/chunks/{chunk-3EZLLVDF.js → chunk-IBJ5S45N.js} +3 -3
  97. package/chunks/{chunk-A4MFR4C5.js → chunk-IO257NUD.js} +3 -5
  98. package/chunks/{chunk-MIPFDQAF.js → chunk-ISJMN3ML.js} +1 -1
  99. package/chunks/chunk-IWOWEENB.js +9169 -0
  100. package/chunks/{chunk-XHRY7BXD.js → chunk-J6SIP2IT.js} +4 -4
  101. package/chunks/{chunk-OD2WU5QY.js → chunk-J7JQXYVL.js} +1 -1
  102. package/chunks/{chunk-NEFOOD54.js → chunk-J7VPB2HF.js} +4 -4
  103. package/chunks/{chunk-P7MPQI75.js → chunk-JGUBDRBC.js} +2 -2
  104. package/chunks/{chunk-SXCOEJO4.js → chunk-JOLJTKIG.js} +1 -1
  105. package/chunks/{chunk-NTTBXH7U.js → chunk-JS73NNWF.js} +8 -0
  106. package/chunks/{chunk-QRCNA3SR.js → chunk-JXLPQTMW.js} +50 -70
  107. package/chunks/{chunk-NNHNLJ2X.js → chunk-K2MSGB3W.js} +317 -72
  108. package/chunks/{chunk-KBXKR5R2.js → chunk-K52PZNU4.js} +1 -1
  109. package/chunks/{chunk-OOQUVWIG.js → chunk-K5OIW3I7.js} +4 -4
  110. package/chunks/{chunk-SOORFWKY.js → chunk-KSPRQSB4.js} +1 -1
  111. package/chunks/{chunk-WSH6GRKG.js → chunk-KVGR4MCF.js} +3 -3
  112. package/chunks/{chunk-6YKYPVDV.js → chunk-LC5M7YVE.js} +4 -4
  113. package/chunks/{chunk-M6NDLY2T.js → chunk-LD5VIJ7S.js} +1 -1
  114. package/chunks/{chunk-OMLJNPBE.js → chunk-LDGWX737.js} +84 -4
  115. package/chunks/{chunk-FAAUPSY2.js → chunk-LI4YHTQK.js} +1 -1
  116. package/chunks/{chunk-CXAOG665.js → chunk-LIKIJAUH.js} +2 -2
  117. package/chunks/chunk-LJZSMWOH.js +18 -0
  118. package/chunks/{chunk-BKPPWD33.js → chunk-M2IL2RTA.js} +22 -2
  119. package/chunks/{chunk-N5YPT6PH.js → chunk-MHOY756Q.js} +25 -13
  120. package/chunks/{chunk-YP5KH5Y7.js → chunk-ND7NOI4P.js} +1 -1
  121. package/chunks/{chunk-AW4TRXOC.js → chunk-NP2LV67M.js} +1 -1
  122. package/chunks/{chunk-GGDBMYGZ.js → chunk-NQB52P65.js} +5 -5
  123. package/chunks/{chunk-E3DYKPYZ.js → chunk-NUGZAFR2.js} +3 -3
  124. package/chunks/{chunk-GMIEIY3Y.js → chunk-O5BDEWBC.js} +3 -3
  125. package/chunks/{chunk-GDXET5XU.js → chunk-O5Z7EB6Y.js} +3 -3
  126. package/chunks/{chunk-5EYKMUUY.js → chunk-OTXXOZKW.js} +1 -1
  127. package/chunks/{chunk-M732YJPW.js → chunk-PALTIYXB.js} +6 -6
  128. package/chunks/{chunk-7UXUJ5T3.js → chunk-PLECQWDB.js} +1 -1
  129. package/chunks/{chunk-MLPXSYXR.js → chunk-PMIKPGDF.js} +66 -32
  130. package/chunks/{chunk-IWPYVAO2.js → chunk-PSQJ24ZZ.js} +3 -3
  131. package/chunks/{chunk-CPHEPGAO.js → chunk-PZRUV52H.js} +2 -2
  132. package/chunks/{chunk-PP4FUZNV.js → chunk-Q7RPLE33.js} +2 -2
  133. package/chunks/{chunk-S5DWMTHO.js → chunk-QQUVPMMZ.js} +2 -0
  134. package/chunks/{chunk-JUEPY766.js → chunk-RNGTMHKN.js} +3 -3
  135. package/chunks/{chunk-TUGSVUJB.js → chunk-ROV6B34L.js} +6 -6
  136. package/chunks/{chunk-RVOJ2FBP.js → chunk-RPJOOK6N.js} +1576 -10633
  137. package/chunks/{chunk-AXN7UPYQ.js → chunk-RQJJZQOH.js} +2 -2
  138. package/chunks/{chunk-AFSG32D5.js → chunk-RRRCWDFO.js} +1 -1
  139. package/chunks/{chunk-2M55OBEB.js → chunk-S3G6YFQC.js} +1 -1
  140. package/chunks/{chunk-4S5337WV.js → chunk-SVU5KGR7.js} +6527 -3314
  141. package/chunks/chunk-TBVSALA3.js +1109 -0
  142. package/chunks/{chunk-QUGAUQGJ.js → chunk-TBWQLLFO.js} +2 -0
  143. package/chunks/{chunk-AS5IN4GK.js → chunk-THK3QUU6.js} +5 -5
  144. package/chunks/{chunk-JNDY2MDR.js → chunk-TLDZKNZP.js} +1 -1
  145. package/chunks/{chunk-ZZO74WKW.js → chunk-TNAIZBPQ.js} +115 -28
  146. package/chunks/{chunk-3Z43GZUQ.js → chunk-TXASDT2M.js} +1 -1
  147. package/chunks/{chunk-CZBYX5MY.js → chunk-U53XZHAE.js} +1 -1
  148. package/chunks/{chunk-HIBNSEJE.js → chunk-UDG5EZJI.js} +0 -2
  149. package/chunks/{chunk-QNQAPSN2.js → chunk-URN2JIAQ.js} +4 -1
  150. package/chunks/{chunk-EZ5RP345.js → chunk-UYQTX2P6.js} +44 -13
  151. package/chunks/{chunk-BZ263IKX.js → chunk-UZPYR3EV.js} +1 -1
  152. package/chunks/{chunk-YZOSNW4R.js → chunk-VFACN2CE.js} +1 -1
  153. package/chunks/{chunk-RWDNJBWN.js → chunk-VLRBJ24J.js} +2 -2
  154. package/chunks/{chunk-NHDR76JX.js → chunk-VMJL7RH6.js} +4 -4
  155. package/chunks/{chunk-E23IPNGS.js → chunk-VOTDAZR7.js} +35 -6
  156. package/chunks/{chunk-XLLKYULU.js → chunk-VSNPOSDN.js} +2 -2
  157. package/chunks/{chunk-25EYDK42.js → chunk-VUMLT7E5.js} +2 -2
  158. package/chunks/{chunk-H4A72DE5.js → chunk-W4CRPSC5.js} +1 -1
  159. package/chunks/{chunk-NM5V5OVW.js → chunk-WJJYJVQE.js} +3 -3
  160. package/chunks/{chunk-ROIYNTHJ.js → chunk-WRT324N6.js} +3 -3
  161. package/chunks/chunk-WZAD4ZNJ.js +59 -0
  162. package/chunks/{chunk-SG7ZP5PG.js → chunk-WZDM44SB.js} +4 -4
  163. package/chunks/{chunk-JE7KQ2UP.js → chunk-XIQ5HQ2F.js} +469 -77
  164. package/chunks/{chunk-QV5YN5YD.js → chunk-XJOHLP2A.js} +5 -5
  165. package/chunks/{chunk-XUJNK7Y6.js → chunk-XL5K4SVK.js} +1 -1
  166. package/chunks/{chunk-CKSJECTU.js → chunk-XZJKSETB.js} +9 -5
  167. package/chunks/{chunk-YEYY7TEP.js → chunk-Y2FEAXLP.js} +7 -7
  168. package/chunks/{chunk-2B2BF7P7.js → chunk-YDJRMQU4.js} +3 -3
  169. package/chunks/{chunk-46UV252V.js → chunk-YHC2EYYG.js} +35 -38
  170. package/chunks/{chunk-OVZPVYZB.js → chunk-YMVFIYHV.js} +96 -18
  171. package/chunks/{chunk-WGHHA7ZH.js → chunk-Z3JMO2CH.js} +1 -1
  172. package/chunks/{chunk-MA2HEDVP.js → chunk-ZRYQMWEP.js} +3 -3
  173. package/chunks/{chunk-IGGGG5CX.js → chunk-ZTAT23TL.js} +15948 -10201
  174. package/chunks/{computer-use-77C5FHMW.js → computer-use-H2T7IFYX.js} +55 -54
  175. package/chunks/{config-utils-IVHRSXWI.js → config-utils-3DY73VIJ.js} +2 -2
  176. package/chunks/contextCommand-5AAZFFFV.js +94 -0
  177. package/chunks/{core-runtime-7VMIKUTG.js → core-runtime-JWFNKO2S.js} +57 -55
  178. package/chunks/{create-sub-session-2L5MQRN4.js → create-sub-session-33HIYIJE.js} +58 -56
  179. package/chunks/{create-sub-session-KRQULJE6.js → create-sub-session-XBCVGNFU.js} +6 -4
  180. package/chunks/{cron-create-H7UEPDSN.js → cron-create-IKA56DAF.js} +5 -5
  181. package/chunks/{cron-delete-6SZK7YFM.js → cron-delete-K5Q62EGH.js} +5 -5
  182. package/chunks/{cron-list-H25JIHEZ.js → cron-list-QBFGAMP7.js} +5 -5
  183. package/chunks/{daemon-2KTG7ZBN.js → daemon-NNCQ3HWT.js} +806 -147
  184. package/chunks/{daemon-git-worktree-guard-DXYIMWFT.js → daemon-git-worktree-guard-6233JAPJ.js} +54 -53
  185. package/chunks/daemon-status-provider-3EI2KALQ.js +104 -0
  186. package/chunks/daemon-trust-policy-QWWU7CON.js +100 -0
  187. package/chunks/{daemon-trust-policy-monitor-RYYGCQ3J.js → daemon-trust-policy-monitor-FH7GBAKN.js} +60 -59
  188. package/chunks/{de-UBEBKG6V.js → de-AH4LGCF5.js} +8 -0
  189. package/chunks/{deferred-core-runtime-3SGXFXEQ.js → deferred-core-runtime-EDUZQRME.js} +52 -51
  190. package/chunks/{discovery-ORA5J7YP.js → discovery-X2NV535U.js} +1 -1
  191. package/chunks/{display-image-ON3EYFRD.js → display-image-OEJMJV3S.js} +5 -5
  192. package/chunks/{dist-YEPL4RAW.js → dist-5EV2G6MC.js} +2 -3
  193. package/chunks/{dist-MAQXAQ2Y.js → dist-EQ3Q5XHX.js} +45337 -32756
  194. package/chunks/{dist-WJ4BHIEW.js → dist-ESS34DHC.js} +72 -0
  195. package/chunks/{dist-JWMKPWT5.js → dist-EUOUPUFO.js} +3 -4
  196. package/chunks/{dist-IYYN3RUT.js → dist-UOFRXJT6.js} +2798 -1250
  197. package/chunks/{earlyInputCapture-KJMLFVQV.js → earlyInputCapture-VSP42LUR.js} +53 -52
  198. package/chunks/{edit-I4LQFAEC.js → edit-ZTLO5ASX.js} +60 -58
  199. package/chunks/{en-X6YV7GME.js → en-MD3GP5YL.js} +8 -0
  200. package/chunks/{enter-worktree-YNPOJSRH.js → enter-worktree-TMTPDS2S.js} +55 -54
  201. package/chunks/{enterPlanMode-XCPK62ER.js → enterPlanMode-UBAXFMYI.js} +55 -54
  202. package/chunks/{environment-S7CTIHMX.js → environment-C2CZN7CB.js} +55 -54
  203. package/chunks/{errors-7HB2AIDS.js → errors-ZUNFQINF.js} +54 -53
  204. package/chunks/{exit-worktree-AIIY7SR6.js → exit-worktree-572NWEPJ.js} +55 -54
  205. package/chunks/exitPlanMode-QTIXFGZT.js +86 -0
  206. package/chunks/{fast-path-NDJV3ZFJ.js → fast-path-CEEVHQL3.js} +3 -3
  207. package/chunks/{fast-path-settings-LNOFM2YP.js → fast-path-settings-WHX3J3ZI.js} +2 -2
  208. package/chunks/{fr-VENTC2BS.js → fr-ZEML2JWS.js} +8 -0
  209. package/chunks/{gemini-RSUFP5OE.js → gemini-I2YR6GMS.js} +114 -112
  210. package/chunks/{geminiContentGenerator-SQ5XBPZ7.js → geminiContentGenerator-GQWNDZQF.js} +7 -7
  211. package/chunks/getMachineId-bsd-FBOAYNSY.js +48 -0
  212. package/chunks/{getMachineId-bsd-FG7IUY6U.js → getMachineId-bsd-YH7RURBZ.js} +4 -4
  213. package/chunks/{getMachineId-darwin-GLCJI2RA.js → getMachineId-darwin-H6USQYNI.js} +4 -4
  214. package/chunks/getMachineId-darwin-RNJLJUXY.js +47 -0
  215. package/chunks/{getMachineId-linux-O6OPPAKO.js → getMachineId-linux-HF2N63ET.js} +3 -3
  216. package/chunks/getMachineId-linux-UEVRAIAB.js +41 -0
  217. package/chunks/getMachineId-unsupported-FWXYJ7HW.js +31 -0
  218. package/chunks/{getMachineId-unsupported-S6CKYVGC.js → getMachineId-unsupported-NYA5DXRB.js} +3 -3
  219. package/chunks/getMachineId-win-LRVGMHLW.js +50 -0
  220. package/chunks/{getMachineId-win-X5SRNEH7.js → getMachineId-win-SMEGY2DW.js} +4 -4
  221. package/chunks/{glob-J4RUJAHX.js → glob-XFBL2RVT.js} +58 -57
  222. package/chunks/{goal-tools-VHTNVOKK.js → goal-tools-TLJCE7YZ.js} +6 -6
  223. package/chunks/{grep-VJWPLFOT.js → grep-U675LEXE.js} +55 -54
  224. package/chunks/handleAutoUpdate-R6RUCIA2.js +97 -0
  225. package/chunks/{i18n-RM5YOICI.js → i18n-SJCZDZ4C.js} +53 -52
  226. package/chunks/{image-gen-EXECB5XM.js → image-gen-6VY7CA7C.js} +14 -14
  227. package/chunks/initializer-CRDZXJOG.js +101 -0
  228. package/chunks/installationInfo-EW3NEJDZ.js +95 -0
  229. package/chunks/{ja-QHT4EQTO.js → ja-UM5B2HMD.js} +8 -0
  230. package/chunks/{keychain-token-storage-3XFJ5ZB2.js → keychain-token-storage-MTFTAESK.js} +3 -3
  231. package/chunks/list-TZEMTXDH.js +104 -0
  232. package/chunks/{list-agents-OSVDFI6S.js → list-agents-43XUEXJV.js} +6 -6
  233. package/chunks/loadedSettingsAdapter-47DG424L.js +98 -0
  234. package/chunks/{loggingContentGenerator-WF4ZOJEZ.js → loggingContentGenerator-77C6O5VW.js} +31 -29
  235. package/chunks/{loop-wakeup-WQS6JYAG.js → loop-wakeup-E54KDUXC.js} +6 -6
  236. package/chunks/{ls-D3HUFHDP.js → ls-CGL2UC3H.js} +7 -7
  237. package/chunks/{lsp-3QDDJTCS.js → lsp-5IKUO5DX.js} +3 -3
  238. package/chunks/{managed-npm-update-E7IW6N7V.js → managed-npm-update-AJ5GZRUA.js} +53 -52
  239. package/chunks/mcp-AQK656Y4.js +98 -0
  240. package/chunks/{monitor-EE2UYMGE.js → monitor-UDZXKYT3.js} +55 -54
  241. package/chunks/nonInteractiveCli-6NC3NLZM.js +166 -0
  242. package/chunks/{notebook-edit-NTDY4QDU.js → notebook-edit-G6WZI2YT.js} +59 -57
  243. package/chunks/{openaiContentGenerator-YNFVJMRJ.js → openaiContentGenerator-IHVHP3VB.js} +32 -32
  244. package/chunks/{pidfile-4XSFLYBZ.js → pidfile-EBKS2HBK.js} +53 -52
  245. package/chunks/{processUtils-WDA2MJFD.js → processUtils-B7M35ZLR.js} +2 -2
  246. package/chunks/prompt-terminal-ledger-5JYOPOII.js +93 -0
  247. package/chunks/{pt-VL3I5RNY.js → pt-5BMJ3XYH.js} +8 -0
  248. package/chunks/{qwenContentGenerator-434M7QKY.js → qwenContentGenerator-WCJPPTED.js} +59 -58
  249. package/chunks/{qwenOAuth2-GMYZOO6A.js → qwenOAuth2-S2CLBSEZ.js} +10 -10
  250. package/chunks/read-file-WFM53FTW.js +33 -0
  251. package/chunks/{read-mcp-resource-XD54ZQMC.js → read-mcp-resource-XYES2B42.js} +3 -3
  252. package/chunks/{record-artifact-SEYFJEJF.js → record-artifact-W3IBTGL7.js} +10 -6
  253. package/chunks/{resumeHistoryUtils-EVG3WYK2.js → resumeHistoryUtils-CK4ZC6YO.js} +59 -58
  254. package/chunks/ripGrep-B3PBLEQ3.js +86 -0
  255. package/chunks/{ru-4RCKL4PY.js → ru-6GL66ORV.js} +8 -0
  256. package/chunks/{run-qwen-serve-3QSGRXAN.js → run-qwen-serve-DC5RXI6N.js} +537 -185
  257. package/chunks/{runtime-5MLLZ7DC.js → runtime-UVEETF54.js} +63 -62
  258. package/chunks/{scheduler-RPBJ63CH.js → scheduler-MWT3UMVN.js} +54 -53
  259. package/chunks/{sdk-exporters-grpc-54L4LS5L.js → sdk-exporters-grpc-6J5CKOMO.js} +194 -75
  260. package/chunks/{sdk-exporters-http-XUVP63H6.js → sdk-exporters-http-Q3YZ4752.js} +40 -45
  261. package/chunks/{sdk-impl-YXUEN2Z2.js → sdk-impl-BOMCAN2Z.js} +7211 -5454
  262. package/chunks/{send-message-VZENRWRH.js → send-message-J4VT46OI.js} +8 -8
  263. package/chunks/{serve-HS3XLPXU.js → serve-AKM75GTE.js} +60 -61
  264. package/chunks/{server-TC4A7AAZ.js → server-KU7XIDVT.js} +2221 -399
  265. package/chunks/{session-UBOFXVMN.js → session-DKVYIRWN.js} +108 -105
  266. package/chunks/{settings-D5644OM5.js → settings-NS3PXZDP.js} +63 -62
  267. package/chunks/{shell-3PZULQQV.js → shell-UXCNM2OK.js} +52 -51
  268. package/chunks/{skill-PEVVXQ3L.js → skill-KV7YCCTM.js} +30 -28
  269. package/chunks/{skill-settings-J65JKKES.js → skill-settings-EXW7ESWJ.js} +59 -58
  270. package/chunks/{spawnChannel-IYGXRHSQ.js → spawnChannel-FCP44P4V.js} +55 -54
  271. package/chunks/{standalone-update-IFM53PE7.js → standalone-update-RGW3B2DX.js} +55 -54
  272. package/chunks/{startInteractiveUI-3AVH7L6H.js → startInteractiveUI-UZMF2BIJ.js} +615 -392
  273. package/chunks/{syntheticOutput-7GWFIDXT.js → syntheticOutput-JAXMIMZP.js} +4 -4
  274. package/chunks/{task-create-FCBDX7UH.js → task-create-I2H322E4.js} +12 -12
  275. package/chunks/{task-list-YIYIUFUA.js → task-list-3OLIWFTQ.js} +21 -7
  276. package/chunks/{task-stop-X37KYTKB.js → task-stop-JAUY6MSY.js} +3 -3
  277. package/chunks/{task-update-MYPFVOVM.js → task-update-B3XO4CPI.js} +87 -16
  278. package/chunks/{team-create-ZAIA7KAV.js → team-create-77XY3KAE.js} +56 -56
  279. package/chunks/{team-delete-6UMU4XLS.js → team-delete-Q7GE7RRI.js} +6 -6
  280. package/chunks/{team-plan-approval-UNIUS7OD.js → team-plan-approval-TAQANDQG.js} +55 -54
  281. package/chunks/{terminal-image-renderer-G343P2RV.js → terminal-image-renderer-V4LIF5NS.js} +54 -53
  282. package/chunks/theme-manager-KKBAJ574.js +90 -0
  283. package/chunks/{todoWrite-U2R4NVF4.js → todoWrite-FJJTY2TI.js} +7 -7
  284. package/chunks/{tool-search-5R2OE4C7.js → tool-search-GZJYRK4I.js} +25 -24
  285. package/chunks/{total-session-admission-4KBHMQQ2.js → total-session-admission-NIBNWXHE.js} +59 -57
  286. package/chunks/{trustedFolders-LK6T4XC7.js → trustedFolders-7GEI2NYC.js} +53 -52
  287. package/chunks/{undici-PYHBDDPN.js → undici-S7WJSKGJ.js} +962 -391
  288. package/chunks/{update-relaunch-UBKROIC6.js → update-relaunch-OA3OEBMD.js} +5 -5
  289. package/chunks/{updateCheck-W4Y2GFSD.js → updateCheck-QVHQEVIY.js} +56 -55
  290. package/chunks/{useAutoAcceptIndicator-C7BEICBF.js → useAutoAcceptIndicator-WZ27J7NY.js} +64 -63
  291. package/chunks/{validateNonInterActiveAuth-LTEI2TB6.js → validateNonInterActiveAuth-OXJA2JWG.js} +99 -96
  292. package/chunks/{version-G5A5DGVS.js → version-KJO64WD7.js} +1 -1
  293. package/chunks/{web-fetch-RTEQTR5Z.js → web-fetch-CC5INI2R.js} +25 -23
  294. package/chunks/{web-search-5OXHEZPV.js → web-search-MOAUAN6N.js} +18 -18
  295. package/chunks/{web-shell-static-O73YPVVC.js → web-shell-static-3NUTRHAH.js} +4 -5
  296. package/chunks/{workflow-ISQJHPG2.js → workflow-BN2ZEJMK.js} +366 -105
  297. package/chunks/workspace-providers-status-R5QTZFK3.js +101 -0
  298. package/chunks/{workspace-registration-store-CYNY6IP6.js → workspace-registration-store-WMSLM36M.js} +1 -1
  299. package/chunks/{workspace-registry-34GTUUHB.js → workspace-registry-J3RUCXH6.js} +59 -57
  300. package/chunks/{workspace-service-XCDQLE2Y.js → workspace-service-JJZFPKM4.js} +66 -65
  301. package/chunks/workspace-skills-status-DRIOZRIA.js +101 -0
  302. package/chunks/{workspace-trust-reconciler-AYGXC7A3.js → workspace-trust-reconciler-YAYSN6CX.js} +69 -67
  303. package/chunks/write-file-7HXHFFOY.js +88 -0
  304. package/chunks/{zh-TW-SQ4HTSCW.js → zh-TW-LVLBK4KF.js} +8 -0
  305. package/chunks/{zh-LMSTK4WD.js → zh-UBMWS2BJ.js} +8 -0
  306. package/chunks/{zoom-image-4BFYJ3HG.js → zoom-image-EFMQMU4G.js} +24 -22
  307. package/cli.js +15 -15
  308. package/locales/ca.js +13 -0
  309. package/locales/de.js +12 -0
  310. package/locales/en.js +11 -0
  311. package/locales/fr.js +13 -0
  312. package/locales/ja.js +13 -0
  313. package/locales/pt.js +12 -0
  314. package/locales/ru.js +12 -0
  315. package/locales/zh-TW.js +11 -0
  316. package/locales/zh.js +11 -0
  317. package/package.json +3 -3
  318. package/web-shell/assets/{arc-CgOpDKvm.js → arc-BCP1f-bN.js} +1 -1
  319. package/web-shell/assets/{architectureDiagram-3BPJPVTR-0Ag_m34F.js → architectureDiagram-3BPJPVTR-D-6ajMay.js} +1 -1
  320. package/web-shell/assets/{blockDiagram-GPEHLZMM-IwTwFau0.js → blockDiagram-GPEHLZMM-CcLlnVnf.js} +1 -1
  321. package/web-shell/assets/{c4Diagram-AAUBKEIU-DLa5GUv8.js → c4Diagram-AAUBKEIU-C_Sp9UwQ.js} +1 -1
  322. package/web-shell/assets/channel-BcImYzbA.js +1 -0
  323. package/web-shell/assets/{chunk-2J33WTMH-DcYP-WFG.js → chunk-2J33WTMH-CG0ngvo9.js} +1 -1
  324. package/web-shell/assets/{chunk-4BX2VUAB-C8MVPMiQ.js → chunk-4BX2VUAB-D43LsVdk.js} +1 -1
  325. package/web-shell/assets/{chunk-55IACEB6-BUi4Yfv3.js → chunk-55IACEB6-BqNIn5rz.js} +1 -1
  326. package/web-shell/assets/{chunk-727SXJPM-Cy3Su2YY.js → chunk-727SXJPM-BSHmO08Y.js} +1 -1
  327. package/web-shell/assets/{chunk-AQP2D5EJ-Dp8Teqv6.js → chunk-AQP2D5EJ-CMUbr5tQ.js} +1 -1
  328. package/web-shell/assets/{chunk-FMBD7UC4-BDTDM-4j.js → chunk-FMBD7UC4-Cm6JflnZ.js} +1 -1
  329. package/web-shell/assets/{chunk-ND2GUHAM-7HfDt0r2.js → chunk-ND2GUHAM-CBR39YQZ.js} +1 -1
  330. package/web-shell/assets/{chunk-QZHKN3VN-BIBU0uCF.js → chunk-QZHKN3VN-CWnqaLb-.js} +1 -1
  331. package/web-shell/assets/classDiagram-4FO5ZUOK-OWx0rDRW.js +1 -0
  332. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-OWx0rDRW.js +1 -0
  333. package/web-shell/assets/{cose-bilkent-S5V4N54A-DRLdcg9p.js → cose-bilkent-S5V4N54A-DJlTdnfD.js} +1 -1
  334. package/web-shell/assets/{dagre-BM42HDAG-DCCgDwqW.js → dagre-BM42HDAG-1AFN1uVc.js} +1 -1
  335. package/web-shell/assets/{diagram-2AECGRRQ-CsBTBmk3.js → diagram-2AECGRRQ-gC0GGNSW.js} +1 -1
  336. package/web-shell/assets/{diagram-5GNKFQAL-C9qjH8Lt.js → diagram-5GNKFQAL-CPmRPT1s.js} +1 -1
  337. package/web-shell/assets/{diagram-KO2AKTUF-Brjs_lj2.js → diagram-KO2AKTUF-atigp6Hr.js} +1 -1
  338. package/web-shell/assets/{diagram-LMA3HP47-DtiWCl_F.js → diagram-LMA3HP47-BJnJFSRQ.js} +1 -1
  339. package/web-shell/assets/{diagram-OG6HWLK6-DmfKLkBT.js → diagram-OG6HWLK6-CyvJ4fG2.js} +1 -1
  340. package/web-shell/assets/{erDiagram-TEJ5UH35-Bve_4deH.js → erDiagram-TEJ5UH35-CZac_jT6.js} +1 -1
  341. package/web-shell/assets/{flowDiagram-I6XJVG4X-C2_kXCcV.js → flowDiagram-I6XJVG4X-pd-LQxWB.js} +1 -1
  342. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BSBIjiTF.js → ganttDiagram-6RSMTGT7-CvB1at7l.js} +1 -1
  343. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CyebwI55.js → gitGraphDiagram-PVQCEYII-B5Y6nkil.js} +1 -1
  344. package/web-shell/assets/index-Bg3DAn8Z.js +1788 -0
  345. package/web-shell/assets/{index-d0yfnV1M.js → index-Bj3ZSUHL.js} +1 -1
  346. package/web-shell/assets/index-mp32EO88.css +5 -0
  347. package/web-shell/assets/{infoDiagram-5YYISTIA-CSDGnWxU.js → infoDiagram-5YYISTIA-BdyWvU4P.js} +1 -1
  348. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BK4jU13p.js → ishikawaDiagram-YF4QCWOH-CaHbUdvN.js} +1 -1
  349. package/web-shell/assets/{journeyDiagram-JHISSGLW-D_W6j-oF.js → journeyDiagram-JHISSGLW-DR9F3FpG.js} +1 -1
  350. package/web-shell/assets/{kanban-definition-UN3LZRKU-C7xf-SdC.js → kanban-definition-UN3LZRKU-BoEUbkw2.js} +1 -1
  351. package/web-shell/assets/{linear-DQmzxpxd.js → linear-DUbfzV4T.js} +1 -1
  352. package/web-shell/assets/{mermaid.core-9P7AGOLG.js → mermaid.core-CLLkPcpD.js} +5 -5
  353. package/web-shell/assets/{mindmap-definition-RKZ34NQL-DgcgMyPk.js → mindmap-definition-RKZ34NQL-FuKI3Stt.js} +1 -1
  354. package/web-shell/assets/{pieDiagram-4H26LBE5-3wWGb9eG.js → pieDiagram-4H26LBE5-CVAHL7l5.js} +1 -1
  355. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BeCXnQw9.js → quadrantDiagram-W4KKPZXB-BkGi5fRj.js} +1 -1
  356. package/web-shell/assets/{requirementDiagram-4Y6WPE33-Bi1UOHDz.js → requirementDiagram-4Y6WPE33-B5ghV8-K.js} +1 -1
  357. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-lrLUjjbb.js → sankeyDiagram-5OEKKPKP-CKFbVhkQ.js} +1 -1
  358. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-BFuqKz6Q.js → sequenceDiagram-3UESZ5HK-C5P9ujPd.js} +1 -1
  359. package/web-shell/assets/{stateDiagram-AJRCARHV-8DemQLhu.js → stateDiagram-AJRCARHV-CsDn-Rez.js} +1 -1
  360. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DpGKD1ez.js +1 -0
  361. package/web-shell/assets/{timeline-definition-PNZ67QCA-uzEuVQXg.js → timeline-definition-PNZ67QCA-B6oLBkTr.js} +1 -1
  362. package/web-shell/assets/{vennDiagram-CIIHVFJN-BQTeZ_-o.js → vennDiagram-CIIHVFJN-DvtBkYwp.js} +1 -1
  363. package/web-shell/assets/{wardley-L42UT6IY-B6yM5Im7.js → wardley-L42UT6IY-D2UwTX16.js} +1 -1
  364. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-ChM8bmgn.js → wardleyDiagram-YWT4CUSO-FnnfCxYI.js} +1 -1
  365. package/web-shell/assets/{xychartDiagram-2RQKCTM6-oNG6HyB1.js → xychartDiagram-2RQKCTM6-C1SaMQ7d.js} +1 -1
  366. package/web-shell/index.html +2 -2
  367. package/chunks/MaxSizedBox-UQALOVVT.js +0 -97
  368. package/chunks/agent-headless-GJCQMURW.js +0 -87
  369. package/chunks/channel-settings-store-WNWYFHG7.js +0 -102
  370. package/chunks/chunk-AZQ3DT76.js +0 -10017
  371. package/chunks/chunk-CR3C7WXL.js +0 -113
  372. package/chunks/chunk-K5IDV3PC.js +0 -519
  373. package/chunks/chunk-MPHPFVKK.js +0 -48
  374. package/chunks/chunk-RLKC46YT.js +0 -3582
  375. package/chunks/chunk-UPDOZBWO.js +0 -358
  376. package/chunks/contextCommand-PJ77GBWL.js +0 -93
  377. package/chunks/daemon-status-provider-ZDOYJCU6.js +0 -102
  378. package/chunks/daemon-trust-policy-E67OYUK2.js +0 -99
  379. package/chunks/exitPlanMode-R4JY7V2O.js +0 -85
  380. package/chunks/handleAutoUpdate-POCX2MNB.js +0 -94
  381. package/chunks/initializer-Z2AFGBNR.js +0 -100
  382. package/chunks/installationInfo-4I5FXNMH.js +0 -92
  383. package/chunks/list-ZMBFIGZA.js +0 -103
  384. package/chunks/loadedSettingsAdapter-T6TV4YJ7.js +0 -97
  385. package/chunks/mcp-6UNYX4HG.js +0 -97
  386. package/chunks/nonInteractiveCli-WAY237O4.js +0 -163
  387. package/chunks/read-file-TAFBKMNI.js +0 -32
  388. package/chunks/ripGrep-WOEK2PXS.js +0 -85
  389. package/chunks/theme-manager-Z3RIT7DB.js +0 -89
  390. package/chunks/undici-3FJYTMOF.js +0 -25914
  391. package/chunks/workspace-providers-status-2ZPZPUPZ.js +0 -100
  392. package/chunks/workspace-skills-status-RS4O7AIJ.js +0 -100
  393. package/chunks/write-file-EWXKVVXF.js +0 -87
  394. package/web-shell/assets/channel-BrGVBa2L.js +0 -1
  395. package/web-shell/assets/classDiagram-4FO5ZUOK-B5TUzJzI.js +0 -1
  396. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B5TUzJzI.js +0 -1
  397. package/web-shell/assets/index-CIDsgxTe.js +0 -1792
  398. package/web-shell/assets/index-DiQnWi_E.css +0 -5
  399. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DhM5ixYd.js +0 -1
  400. package/chunks/{dist-BROOP2EG.js → dist-LZO24N3E.js} +1 -1
@@ -10,6 +10,7 @@ import {
10
10
  formatWorkspaceMemoryForgetSummary,
11
11
  isCompatibleLiveSessionSource,
12
12
  isReservedLiveSessionSource,
13
+ isReservedStandaloneSessionSource,
13
14
  isValidServerName,
14
15
  normalizeChannelDelivery,
15
16
  parseChannelDelivery,
@@ -20,13 +21,13 @@ import {
20
21
  shouldSuppressRememberErrorDetails,
21
22
  workspaceMemoryFailureCode,
22
23
  workspaceMemoryFailureDiagnostics
23
- } from "./chunk-ZZO74WKW.js";
24
+ } from "./chunk-TNAIZBPQ.js";
24
25
  import {
25
26
  deriveWebSocketBase,
26
27
  openQwenAsrRealtimeStream,
27
28
  openVoiceStream,
28
29
  openVoiceStreamWithRetry
29
- } from "./chunk-AXN7UPYQ.js";
30
+ } from "./chunk-RQJJZQOH.js";
30
31
  import {
31
32
  SetupGithubError,
32
33
  collectSessionData,
@@ -38,18 +39,18 @@ import {
38
39
  toJson,
39
40
  toJsonl,
40
41
  toMarkdown
41
- } from "./chunk-RLKC46YT.js";
42
+ } from "./chunk-3SIGAHUX.js";
42
43
  import {
43
44
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
44
45
  ObservedChannelContactStore
45
- } from "./chunk-BZ263IKX.js";
46
+ } from "./chunk-UZPYR3EV.js";
47
+ import "./chunk-FV6PXZRO.js";
46
48
  import {
47
49
  escapeAnsiCtrlCodes
48
- } from "./chunk-4NFY2S7N.js";
49
- import "./chunk-3U3VAL47.js";
50
+ } from "./chunk-E7REAOTN.js";
50
51
  import "./chunk-2MIN6GRR.js";
51
52
  import "./chunk-QHTIBUWB.js";
52
- import "./chunk-3Z43GZUQ.js";
53
+ import "./chunk-TXASDT2M.js";
53
54
  import {
54
55
  ACP_PRE_ATTACH_MAX_FRAMES_GLOBAL,
55
56
  ACP_PRE_ATTACH_MAX_FRAMES_PER_CONNECTION,
@@ -62,11 +63,13 @@ import {
62
63
  CLIENT_ID_RE,
63
64
  ClientMcpSenderRegistry,
64
65
  ConversationRuntimeOwnershipError,
66
+ CredentialStore,
65
67
  DeviceFlowRegistry,
66
68
  MAX_CLIENT_ID_LENGTH,
67
69
  MAX_CONCURRENT_VOICE_SESSIONS,
68
70
  MAX_SERVER_NAME_LENGTH,
69
71
  MAX_TOOL_NAME_LENGTH,
72
+ MutableOriginAllowlist,
70
73
  PathMutexRegistry,
71
74
  QWEN_CDP_MCP_COMMAND_ENV,
72
75
  TooManyActiveDeviceFlowsError,
@@ -88,7 +91,8 @@ import {
88
91
  createManagedScratchDirectory,
89
92
  createMutationGate,
90
93
  createRateLimiter,
91
- denyBrowserOriginCors,
94
+ daemonInboundTraceIdContext,
95
+ daemonTelemetryResponseContext,
92
96
  detectFromLoopback,
93
97
  getAdvertisedServeFeatures,
94
98
  getDeferredRuntimeRequestTiming,
@@ -99,6 +103,8 @@ import {
99
103
  isBrowserAutomationMcpAvailable,
100
104
  isDeepHealthQuery,
101
105
  isScratchRootCompatible,
106
+ listenerIdentityOf,
107
+ listenerIdentityOfSocket,
102
108
  parseAllowOriginPatterns,
103
109
  parseAndValidateWorkspaceClientId,
104
110
  parseClientIdHeader,
@@ -107,6 +113,7 @@ import {
107
113
  parseMaxQueuedQuery,
108
114
  parseOptionalWorkspaceCwd,
109
115
  parsePermissionVoteBody,
116
+ requestWasAuthenticated,
110
117
  requireSessionId,
111
118
  resolveAcpHttpEnabled,
112
119
  resolveCdpMcpCommand,
@@ -116,9 +123,11 @@ import {
116
123
  sendJsonBodyParserError,
117
124
  setDeviceFlowRegistry,
118
125
  setRateLimiter,
126
+ singleTokenCredentials,
127
+ tagListener,
119
128
  unsafeRevealSecret,
120
129
  validateMcpRuntimeServerName
121
- } from "./chunk-O565M6A4.js";
130
+ } from "./chunk-DRVS6K7A.js";
122
131
  import "./chunk-VGHZT6JR.js";
123
132
  import {
124
133
  isLoopbackBind,
@@ -126,10 +135,38 @@ import {
126
135
  parseCallerSuppliedSessionId
127
136
  } from "./chunk-TQOF5KBL.js";
128
137
  import "./chunk-UXEO7E3V.js";
138
+ import {
139
+ WorkspaceGenerationClosedError,
140
+ createSingleWorkspaceRegistry,
141
+ createWorkspaceSessionOwnerIndex
142
+ } from "./chunk-K3LPAED5.js";
143
+ import {
144
+ isInternalWorkspaceRuntime
145
+ } from "./chunk-NYWWQ437.js";
146
+ import {
147
+ assertValidChannelSecretUpdates
148
+ } from "./chunk-Q7RPLE33.js";
149
+ import {
150
+ createWorkspaceSkillsStatusProvider
151
+ } from "./chunk-AGCLK4G7.js";
152
+ import "./chunk-BGXZBI5B.js";
153
+ import {
154
+ isServeDebugMode,
155
+ mountWebShellAssets,
156
+ mountWebShellSpaFallback
157
+ } from "./chunk-KSPRQSB4.js";
158
+ import {
159
+ require_express
160
+ } from "./chunk-O5Z7EB6Y.js";
129
161
  import {
130
162
  evaluateDaemonWorkspaceTrust,
131
163
  readDaemonTrustPolicySnapshot
132
- } from "./chunk-XIT3GURH.js";
164
+ } from "./chunk-HGBACZGD.js";
165
+ import {
166
+ readRecentPromptTerminals,
167
+ reconcileDanglingPromptTerminals,
168
+ withPromptTerminals
169
+ } from "./chunk-64LXOKG4.js";
133
170
  import {
134
171
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
135
172
  MAX_WORKSPACE_SKILL_NAME_LENGTH,
@@ -143,14 +180,14 @@ import {
143
180
  validateWorkspaceSkillName,
144
181
  validateWorkspaceVoiceState,
145
182
  voiceSettingsScopeToWire
146
- } from "./chunk-EZ5RP345.js";
183
+ } from "./chunk-UYQTX2P6.js";
147
184
  import {
148
185
  PermissionRulesValidationError,
149
186
  buildPermissionSettings,
150
187
  isPermissionRuleType,
151
188
  normalizePermissionRules,
152
189
  readPermissionRuleSet
153
- } from "./chunk-7UXUJ5T3.js";
190
+ } from "./chunk-PLECQWDB.js";
154
191
  import {
155
192
  assertVoiceBaseUrlNetworkAllowed,
156
193
  isStreamingVoiceModel,
@@ -158,24 +195,22 @@ import {
158
195
  resolveVoiceTranscriptionConfig,
159
196
  sanitizeVoiceErrorMessage,
160
197
  transcribeVoiceAudio
161
- } from "./chunk-6ORZ2EDC.js";
198
+ } from "./chunk-EW2IQ3ID.js";
162
199
  import {
163
200
  isVoiceEnabled,
164
201
  isVoiceMode,
165
202
  readVoiceModel
166
- } from "./chunk-QIH2HAEN.js";
167
- import "./chunk-WGHHA7ZH.js";
203
+ } from "./chunk-GXG4PYQB.js";
204
+ import "./chunk-Z3JMO2CH.js";
205
+ import "./chunk-Z4X5MTRT.js";
206
+ import {
207
+ WorkspacePermissionRulesSessionRequiredError,
208
+ WorkspaceSettingsPartialPersistError,
209
+ mapWorkspaceSkillToggleError
210
+ } from "./chunk-Z7VOMGDC.js";
168
211
  import {
169
212
  createTotalSessionAdmissionController
170
213
  } from "./chunk-X2UOOG5V.js";
171
- import {
172
- WorkspaceGenerationClosedError,
173
- createSingleWorkspaceRegistry,
174
- createWorkspaceSessionOwnerIndex
175
- } from "./chunk-K3LPAED5.js";
176
- import {
177
- isInternalWorkspaceRuntime
178
- } from "./chunk-NYWWQ437.js";
179
214
  import "./chunk-OIBUG24X.js";
180
215
  import {
181
216
  MAX_SESSION_RESTORE_TIMEOUT_MS,
@@ -183,19 +218,24 @@ import {
183
218
  restoreRetryAfterSeconds
184
219
  } from "./chunk-4JRM2BSM.js";
185
220
  import {
186
- assertValidChannelSecretUpdates
187
- } from "./chunk-PP4FUZNV.js";
221
+ getStableLiveDiscoveryBaseDir
222
+ } from "./chunk-5MK45KZ3.js";
223
+ import {
224
+ LIVE_HOST_BUNDLE_ID,
225
+ LIVE_HOST_PROTOCOL_VERSION,
226
+ LIVE_INPUT_AUDIO_EPOCH_BYTES
227
+ } from "./chunk-NKLP3DCK.js";
188
228
  import {
189
229
  createDaemonStatusProvider
190
- } from "./chunk-OOQUVWIG.js";
191
- import "./chunk-NTTBXH7U.js";
192
- import "./chunk-XHRY7BXD.js";
230
+ } from "./chunk-K5OIW3I7.js";
231
+ import "./chunk-JS73NNWF.js";
232
+ import "./chunk-J6SIP2IT.js";
193
233
  import {
194
234
  SessionArtifactAuthorizationError,
195
235
  SessionArtifactValidationError,
196
236
  createAcpSessionBridge,
197
237
  parseSessionSource
198
- } from "./chunk-LJQAUZMR.js";
238
+ } from "./chunk-7CPJMZVJ.js";
199
239
  import {
200
240
  EVENT_SCHEMA_VERSION,
201
241
  EventBus,
@@ -203,66 +243,38 @@ import {
203
243
  } from "./chunk-7U5G6JXI.js";
204
244
  import "./chunk-WCCLLK7X.js";
205
245
  import "./chunk-OCPBI7J5.js";
246
+ import "./chunk-VMJL7RH6.js";
206
247
  import {
207
248
  createWorkspaceProvidersStatusProvider
208
- } from "./chunk-YEYY7TEP.js";
249
+ } from "./chunk-Y2FEAXLP.js";
209
250
  import {
210
251
  getAuthTypeFromEnv,
211
252
  resolveCliGenerationConfig
212
- } from "./chunk-ZYYTZUI2.js";
253
+ } from "./chunk-3LYGXZ2H.js";
213
254
  import {
214
255
  snapshotProcessEnv
215
- } from "./chunk-NM5V5OVW.js";
216
- import {
217
- createWorkspaceSkillsStatusProvider
218
- } from "./chunk-OY5RNSV4.js";
219
- import "./chunk-BGXZBI5B.js";
220
- import "./chunk-Z4X5MTRT.js";
221
- import {
222
- WorkspacePermissionRulesSessionRequiredError,
223
- WorkspaceSettingsPartialPersistError,
224
- mapWorkspaceSkillToggleError
225
- } from "./chunk-Z7VOMGDC.js";
226
- import {
227
- isServeDebugMode,
228
- mountWebShellAssets,
229
- mountWebShellSpaFallback
230
- } from "./chunk-SOORFWKY.js";
256
+ } from "./chunk-WJJYJVQE.js";
231
257
  import {
232
- require_express
233
- } from "./chunk-GDXET5XU.js";
258
+ STATUS_SCHEMA_VERSION,
259
+ SessionRestoreTimeoutError,
260
+ createIdleWorkspaceMemoryStatus,
261
+ mapDomainErrorToErrorKind
262
+ } from "./chunk-URN2JIAQ.js";
263
+ import "./chunk-HMJ2P3SV.js";
234
264
  import {
235
265
  daemonObservedContactsPath,
236
266
  loadChannelsConfig
237
- } from "./chunk-TUGSVUJB.js";
238
- import "./chunk-QV5YN5YD.js";
267
+ } from "./chunk-ROV6B34L.js";
268
+ import "./chunk-XJOHLP2A.js";
239
269
  import "./chunk-57OAHC2Y.js";
240
270
  import {
241
271
  parseChannelWebhookConfigLenient
242
- } from "./chunk-OD2WU5QY.js";
272
+ } from "./chunk-J7JQXYVL.js";
243
273
  import "./chunk-45NQKMYB.js";
244
274
  import {
245
275
  supportedChannelCatalog
246
- } from "./chunk-A4QRWUDE.js";
276
+ } from "./chunk-2NWPB6T4.js";
247
277
  import "./chunk-V6WHFGST.js";
248
- import {
249
- getStableLiveDiscoveryBaseDir
250
- } from "./chunk-TS6625XH.js";
251
- import {
252
- LIVE_HOST_BUNDLE_ID,
253
- LIVE_HOST_PROTOCOL_VERSION,
254
- LIVE_INPUT_AUDIO_EPOCH_BYTES
255
- } from "./chunk-NKLP3DCK.js";
256
- import "./chunk-NHDR76JX.js";
257
- import {
258
- STATUS_SCHEMA_VERSION,
259
- SessionRestoreTimeoutError,
260
- createIdleWorkspaceMemoryStatus,
261
- mapDomainErrorToErrorKind
262
- } from "./chunk-QNQAPSN2.js";
263
- import "./chunk-K6KS3LTN.js";
264
- import "./chunk-FC4KQFCS.js";
265
- import "./chunk-T3CHYWJZ.js";
266
278
  import {
267
279
  MAX_REGISTERED_WORKSPACES,
268
280
  WorkspaceDisplayNameValidationError,
@@ -270,13 +282,13 @@ import {
270
282
  WorkspaceRegistrationStoreLimitError,
271
283
  normalizeWorkspaceDisplayName,
272
284
  workspaceRegistrationId
273
- } from "./chunk-JNDY2MDR.js";
285
+ } from "./chunk-TLDZKNZP.js";
274
286
  import {
275
287
  CHANNEL_PROMPT_META_KEY,
276
288
  DAEMON_PROMPT_DISPLAY_TEXT_META_KEY,
277
289
  REQUESTED_SESSION_ID_META_KEY,
278
290
  gradeActiveWorkCoverage
279
- } from "./chunk-S5DWMTHO.js";
291
+ } from "./chunk-QQUVPMMZ.js";
280
292
  import {
281
293
  BranchWhilePromptActiveError,
282
294
  BridgeChannelQuarantinedError,
@@ -330,23 +342,25 @@ import {
330
342
  QWEN_SERVER_TOKEN_ENV,
331
343
  isChannelDeliveryError,
332
344
  isChannelWebhookEnqueueError
333
- } from "./chunk-YP5KH5Y7.js";
345
+ } from "./chunk-ND7NOI4P.js";
334
346
  import {
335
347
  normalizeWorkerDiagnostic
336
348
  } from "./chunk-A6NRNRKE.js";
337
349
  import {
338
350
  normalizeServeChannelSelection
339
351
  } from "./chunk-ALMR3E6Q.js";
340
- import "./chunk-HIBNSEJE.js";
352
+ import "./chunk-UDG5EZJI.js";
353
+ import "./chunk-3VUENPWF.js";
341
354
  import {
342
355
  redactLogCredentials
343
356
  } from "./chunk-M5GB774H.js";
344
- import "./chunk-3VUENPWF.js";
357
+ import "./chunk-5HBA2Z7V.js";
358
+ import "./chunk-K6KS3LTN.js";
359
+ import "./chunk-7E7UCJHS.js";
345
360
  import {
346
361
  sanitizeLogText
347
362
  } from "./chunk-AW27A43Y.js";
348
363
  import "./chunk-IW6RQPQB.js";
349
- import "./chunk-5HBA2Z7V.js";
350
364
  import {
351
365
  getDialogSettingKeys,
352
366
  getModelProvidersOwnerScope,
@@ -356,30 +370,31 @@ import {
356
370
  getWritableScopes,
357
371
  loadSettings,
358
372
  validateSettingValue
359
- } from "./chunk-A267JX7H.js";
373
+ } from "./chunk-3HWN4E7N.js";
374
+ import "./chunk-VOTDAZR7.js";
360
375
  import "./chunk-RKUWKYED.js";
361
- import "./chunk-E23IPNGS.js";
362
- import "./chunk-GOXKNSDZ.js";
363
- import "./chunk-IDS7MSUP.js";
364
376
  import {
365
377
  detectSystemLanguage,
366
378
  resolveLanguageSetting
367
- } from "./chunk-HUTNYWBG.js";
379
+ } from "./chunk-45UD2TU4.js";
368
380
  import {
369
381
  SUPPORTED_LANGUAGES,
370
382
  resolveSupportedLanguage
371
383
  } from "./chunk-5EJZE3FP.js";
372
- import "./chunk-MC4TLKEI.js";
373
- import "./chunk-MS7GNABG.js";
374
- import "./chunk-CU6GJD55.js";
384
+ import "./chunk-5PHLBWBL.js";
385
+ import "./chunk-GOXKNSDZ.js";
386
+ import "./chunk-IDS7MSUP.js";
387
+ import "./chunk-CXJHQVEK.js";
388
+ import "./chunk-7WLFSDLG.js";
375
389
  import "./chunk-WZMH7II3.js";
376
390
  import {
377
391
  getWorkspaceTrustStatus
378
- } from "./chunk-IWPYVAO2.js";
392
+ } from "./chunk-PSQJ24ZZ.js";
379
393
  import "./chunk-NPQ5ZKRP.js";
380
394
  import {
381
395
  isWithinRoot as isWithinRoot2
382
396
  } from "./chunk-MR3PXB6E.js";
397
+ import "./chunk-LJZSMWOH.js";
383
398
  import {
384
399
  ALL_PROVIDERS,
385
400
  BTW_MAX_INPUT_LENGTH,
@@ -388,6 +403,7 @@ import {
388
403
  ClientMcpRegistrar,
389
404
  DEFAULT_LOG_LIMIT,
390
405
  ExtensionManager,
406
+ ExtensionNotUpdatableError,
391
407
  GITHUB_PR_ERROR_MESSAGE_MAX,
392
408
  GROUP_COLOR_OPTIONS,
393
409
  GitWorktreeService,
@@ -401,6 +417,7 @@ import {
401
417
  SESSION_TRANSCRIPT_MAX_LIMIT,
402
418
  SESSION_TRANSCRIPT_MAX_PAGE_BYTES,
403
419
  SESSION_WRITER_RPC_CODES,
420
+ SessionIdCaseConflictError,
404
421
  SessionOrganizationError,
405
422
  SessionOrganizationService,
406
423
  SessionService,
@@ -437,6 +454,7 @@ import {
437
454
  gitPull,
438
455
  gitPush,
439
456
  glob,
457
+ isSupportedArchiveUrl,
440
458
  isValidCheckoutRef,
441
459
  isValidRefName,
442
460
  loadIgnoreRules,
@@ -448,25 +466,26 @@ import {
448
466
  resolveBranchName,
449
467
  resolveProviderProtocol,
450
468
  shouldShowStep,
469
+ sleepInhibitor,
451
470
  stripTerminalControlSequences,
452
471
  watchRepoBranch,
453
472
  writeWorkspaceContextFile,
454
473
  writeWorktreeSession,
455
474
  writeWorktreeSessionMarker
456
- } from "./chunk-4S5337WV.js";
475
+ } from "./chunk-SVU5KGR7.js";
457
476
  import "./chunk-GOFAQQZA.js";
458
- import "./chunk-5M6IDOMF.js";
459
477
  import "./chunk-TWPJO254.js";
460
478
  import "./chunk-CQ35AJ4Z.js";
479
+ import "./chunk-5M6IDOMF.js";
480
+ import "./chunk-KVGR4MCF.js";
481
+ import "./chunk-XZJKSETB.js";
482
+ import "./chunk-YMVFIYHV.js";
483
+ import "./chunk-6PVPNMXU.js";
484
+ import "./chunk-OTXXOZKW.js";
461
485
  import {
462
486
  MAX_JOBS,
463
487
  nextDurableFireMs
464
- } from "./chunk-DGZEMW5R.js";
465
- import "./chunk-WSH6GRKG.js";
466
- import "./chunk-CKSJECTU.js";
467
- import "./chunk-OVZPVYZB.js";
468
- import "./chunk-6PVPNMXU.js";
469
- import "./chunk-5EYKMUUY.js";
488
+ } from "./chunk-DJEHYM4H.js";
470
489
  import {
471
490
  nextFireTime,
472
491
  parseCron
@@ -479,71 +498,72 @@ import {
479
498
  readCronTasks,
480
499
  taskHasLegacyCondition,
481
500
  updateCronTasks
482
- } from "./chunk-Y3YCSWG5.js";
483
- import "./chunk-UPDOZBWO.js";
501
+ } from "./chunk-AZF6SME3.js";
502
+ import "./chunk-TBVSALA3.js";
484
503
  import "./chunk-O6GEWCJA.js";
485
504
  import "./chunk-T26EAKDL.js";
486
- import "./chunk-ZPJWUGCS.js";
487
505
  import "./chunk-CPBF7KYF.js";
506
+ import "./chunk-VUMLT7E5.js";
507
+ import "./chunk-ISJMN3ML.js";
508
+ import "./chunk-2TRNCJK4.js";
509
+ import "./chunk-NUGZAFR2.js";
510
+ import {
511
+ parseGoalControlRequest
512
+ } from "./chunk-LDGWX737.js";
488
513
  import {
489
514
  APPROVAL_MODES
490
- } from "./chunk-RWDNJBWN.js";
491
- import "./chunk-25EYDK42.js";
492
- import "./chunk-MIPFDQAF.js";
515
+ } from "./chunk-VLRBJ24J.js";
516
+ import "./chunk-ZPJWUGCS.js";
493
517
  import "./chunk-MLXTMF7H.js";
494
- import "./chunk-KV27IEHM.js";
495
- import "./chunk-E3DYKPYZ.js";
496
- import "./chunk-OMLJNPBE.js";
497
- import "./chunk-OXCMMLED.js";
518
+ import {
519
+ QwenOAuth2Client,
520
+ QwenOAuthPollError,
521
+ cacheQwenCredentials,
522
+ generatePKCEPair,
523
+ isDeviceAuthorizationSuccess,
524
+ isDeviceTokenPending,
525
+ isDeviceTokenSuccess
526
+ } from "./chunk-O5BDEWBC.js";
527
+ import "./chunk-NAVJD2PQ.js";
528
+ import "./chunk-WRT324N6.js";
529
+ import "./chunk-YDJRMQU4.js";
530
+ import "./chunk-KM73TBQ4.js";
531
+ import "./chunk-E63A23D7.js";
532
+ import {
533
+ recordDaemonBridgeError,
534
+ recordDaemonHttpRequest
535
+ } from "./chunk-6NJIPX6W.js";
536
+ import "./chunk-P3QQPMQA.js";
498
537
  import {
499
538
  addDaemonRequestAttribute,
500
539
  captureDaemonTelemetryContext,
501
540
  emitDaemonLog,
541
+ extractDaemonHttpTraceContext,
542
+ extractInboundTraceId,
502
543
  hashDaemonWorkspace,
503
- recordDaemonBridgeError,
504
544
  recordDaemonError,
505
- recordDaemonHttpRequest,
506
545
  recordDaemonHttpResponse,
507
546
  runWithDaemonTelemetryContext,
508
547
  withDaemonRequestSpan
509
- } from "./chunk-TIGA2IVL.js";
548
+ } from "./chunk-6S2OXVJT.js";
549
+ import "./chunk-XWRJCPHC.js";
510
550
  import "./chunk-SAH4BD2J.js";
511
- import "./chunk-XLLKYULU.js";
512
- import "./chunk-PT4I7NBA.js";
551
+ import "./chunk-VSNPOSDN.js";
552
+ import "./chunk-I432KXWD.js";
513
553
  import "./chunk-S6LOFUVP.js";
514
- import "./chunk-2J3OJGTL.js";
515
- import {
516
- SubagentError,
517
- SubagentErrorCode
518
- } from "./chunk-SG7ZP5PG.js";
519
- import "./chunk-K623ENWT.js";
520
- import {
521
- escapeXml
522
- } from "./chunk-AQ37AY7B.js";
523
- import "./chunk-KBXKR5R2.js";
524
- import {
525
- QwenOAuth2Client,
526
- QwenOAuthPollError,
527
- cacheQwenCredentials,
528
- generatePKCEPair,
529
- isDeviceAuthorizationSuccess,
530
- isDeviceTokenPending,
531
- isDeviceTokenSuccess
532
- } from "./chunk-GMIEIY3Y.js";
533
- import "./chunk-NAVJD2PQ.js";
534
- import "./chunk-ROIYNTHJ.js";
535
- import "./chunk-2B2BF7P7.js";
536
- import "./chunk-P3QQPMQA.js";
537
- import "./chunk-YZHRN3CF.js";
538
- import "./chunk-FAAUPSY2.js";
539
- import "./chunk-KM73TBQ4.js";
540
- import "./chunk-MPHPFVKK.js";
554
+ import "./chunk-7IV52LTO.js";
541
555
  import "./chunk-AXMWHKXA.js";
542
- import "./chunk-GLCZKT5V.js";
543
556
  import "./chunk-DJ2GSRLV.js";
544
- import "./chunk-QFJ5JHQR.js";
545
- import "./chunk-CR3C7WXL.js";
546
- import "./chunk-XWRJCPHC.js";
557
+ import "./chunk-2J3OJGTL.js";
558
+ import "./chunk-LI4YHTQK.js";
559
+ import "./chunk-GLCZKT5V.js";
560
+ import "./chunk-C72BXMJ5.js";
561
+ import {
562
+ parseLineTolerant,
563
+ read
564
+ } from "./chunk-RPJOOK6N.js";
565
+ import "./chunk-YRLW2MSX.js";
566
+ import "./chunk-VGC4I5JJ.js";
547
567
  import {
548
568
  CursorNotAtLineBoundaryError,
549
569
  LargeNonUtf8TextError,
@@ -551,40 +571,47 @@ import {
551
571
  decodeBufferWithEncodingInfoAsync,
552
572
  getAllGeminiMdFilenames,
553
573
  isUtf8CompatibleEncoding,
554
- isWithinRoot,
555
- parseLineTolerant,
556
- read
557
- } from "./chunk-RVOJ2FBP.js";
558
- import "./chunk-YRLW2MSX.js";
559
- import "./chunk-VGC4I5JJ.js";
560
- import "./chunk-CHHABXPE.js";
561
- import "./chunk-MA2HEDVP.js";
562
- import "./chunk-XUJNK7Y6.js";
563
- import "./chunk-6HY6IF3Z.js";
564
- import "./chunk-4PKCUT7F.js";
574
+ isWithinRoot
575
+ } from "./chunk-IWOWEENB.js";
576
+ import "./chunk-HIK2OF33.js";
577
+ import "./chunk-ZRYQMWEP.js";
578
+ import "./chunk-7JDGSJQH.js";
565
579
  import "./chunk-F6WFNA7U.js";
566
- import "./chunk-46UV252V.js";
580
+ import "./chunk-WZAD4ZNJ.js";
567
581
  import "./chunk-FPGTNKCP.js";
568
- import "./chunk-CPHEPGAO.js";
569
- import "./chunk-P7MPQI75.js";
570
- import "./chunk-FDGGZIYW.js";
582
+ import "./chunk-YHC2EYYG.js";
583
+ import "./chunk-PZRUV52H.js";
584
+ import "./chunk-JGUBDRBC.js";
585
+ import "./chunk-HDKCKCYO.js";
586
+ import "./chunk-HHJLM3WQ.js";
571
587
  import {
588
+ isTelemetrySdkInitialized,
572
589
  redactUrlCredentials,
573
590
  stripAnsiAndControl
574
- } from "./chunk-EL5SXY3T.js";
575
- import "./chunk-HHJLM3WQ.js";
576
- import "./chunk-K5IDV3PC.js";
591
+ } from "./chunk-32CHFLGV.js";
592
+ import "./chunk-74TONY4F.js";
593
+ import "./chunk-XL5K4SVK.js";
594
+ import {
595
+ SubagentError,
596
+ SubagentErrorCode
597
+ } from "./chunk-WZDM44SB.js";
598
+ import "./chunk-K623ENWT.js";
599
+ import {
600
+ escapeXml
601
+ } from "./chunk-AQ37AY7B.js";
602
+ import "./chunk-K52PZNU4.js";
603
+ import "./chunk-6NFAEG54.js";
577
604
  import {
578
605
  FatalConfigError,
579
606
  Storage,
580
607
  createDebugLogger,
581
608
  getErrorMessage,
582
609
  runWithoutDebugLogSession
583
- } from "./chunk-BUQDLC2G.js";
584
- import "./chunk-VOQXFAY5.js";
610
+ } from "./chunk-A5F2YNO6.js";
585
611
  import {
586
612
  writeStderrLine,
587
- writeStderrLineSafe
613
+ writeStderrLineSafe,
614
+ writeStdoutLineSafe
588
615
  } from "./chunk-KGJGEEVR.js";
589
616
  import "./chunk-75DOP5OR.js";
590
617
  import "./chunk-DMTGGOSA.js";
@@ -596,7 +623,7 @@ import {
596
623
  } from "./chunk-TYAMGABM.js";
597
624
  import "./chunk-FCMNKVXT.js";
598
625
  import "./chunk-AMDSOFFV.js";
599
- import "./chunk-QUGAUQGJ.js";
626
+ import "./chunk-TBWQLLFO.js";
600
627
  import {
601
628
  init_esbuild_shims
602
629
  } from "./chunk-5O2XNYP6.js";
@@ -607,12 +634,435 @@ import {
607
634
 
608
635
  // packages/cli/src/serve/server.ts
609
636
  init_esbuild_shims();
610
- var import_express6 = __toESM(require_express(), 1);
637
+ var import_express7 = __toESM(require_express(), 1);
611
638
  import * as path18 from "node:path";
612
639
 
640
+ // packages/cli/src/serve/local-control/index.ts
641
+ init_esbuild_shims();
642
+
643
+ // packages/cli/src/serve/local-control/lan-interfaces.ts
644
+ init_esbuild_shims();
645
+ import { networkInterfaces } from "node:os";
646
+ function isLanIpv4(address) {
647
+ const octets = address.split(".").map((part) => Number(part));
648
+ if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o))) {
649
+ return false;
650
+ }
651
+ const [a, b] = octets;
652
+ if (a === 10) return true;
653
+ if (a === 172 && b >= 16 && b <= 31) return true;
654
+ if (a === 192 && b === 168) return true;
655
+ if (a === 169 && b === 254) return true;
656
+ return false;
657
+ }
658
+ __name(isLanIpv4, "isLanIpv4");
659
+ function isSoftwareNetwork(interfaceName) {
660
+ if (/vpn/i.test(interfaceName)) return true;
661
+ 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(
662
+ interfaceName
663
+ );
664
+ }
665
+ __name(isSoftwareNetwork, "isSoftwareNetwork");
666
+ function listLanCandidates(interfaces = networkInterfaces()) {
667
+ const candidates = [];
668
+ for (const [interfaceName, addresses] of Object.entries(interfaces).sort()) {
669
+ if (isSoftwareNetwork(interfaceName)) continue;
670
+ for (const address of addresses ?? []) {
671
+ if (address.family !== "IPv4" || address.internal) continue;
672
+ if (!isLanIpv4(address.address)) continue;
673
+ candidates.push({ interfaceName, address: address.address });
674
+ }
675
+ }
676
+ return candidates;
677
+ }
678
+ __name(listLanCandidates, "listLanCandidates");
679
+ var NoLanInterfaceError = class extends Error {
680
+ static {
681
+ __name(this, "NoLanInterfaceError");
682
+ }
683
+ code = "no_lan_interface";
684
+ constructor() {
685
+ super(
686
+ "No private IPv4 address is available. Local Control needs the host to be on a local network (Wi-Fi or Ethernet)."
687
+ );
688
+ this.name = "NoLanInterfaceError";
689
+ }
690
+ };
691
+ var AmbiguousLanInterfaceError = class extends Error {
692
+ static {
693
+ __name(this, "AmbiguousLanInterfaceError");
694
+ }
695
+ code = "ambiguous_lan_interface";
696
+ candidates;
697
+ constructor(candidates) {
698
+ super(
699
+ "Multiple local networks are available; choose which one to expose: " + candidates.map((c) => `${c.interfaceName} (${c.address})`).join(", ")
700
+ );
701
+ this.name = "AmbiguousLanInterfaceError";
702
+ this.candidates = candidates;
703
+ }
704
+ };
705
+ var UnknownLanInterfaceError = class extends Error {
706
+ static {
707
+ __name(this, "UnknownLanInterfaceError");
708
+ }
709
+ code = "unknown_lan_interface";
710
+ constructor(requested) {
711
+ super(
712
+ `${requested} is not a private IPv4 address on this host right now. The network may have changed since the list was fetched.`
713
+ );
714
+ this.name = "UnknownLanInterfaceError";
715
+ }
716
+ };
717
+ function selectLanAddress(preferredAddress, interfaces = networkInterfaces()) {
718
+ const candidates = listLanCandidates(interfaces);
719
+ if (candidates.length === 0) throw new NoLanInterfaceError();
720
+ if (preferredAddress !== void 0) {
721
+ const match = candidates.find((c) => c.address === preferredAddress);
722
+ if (!match) throw new UnknownLanInterfaceError(preferredAddress);
723
+ return match;
724
+ }
725
+ if (candidates.length > 1) throw new AmbiguousLanInterfaceError(candidates);
726
+ return candidates[0];
727
+ }
728
+ __name(selectLanAddress, "selectLanAddress");
729
+
730
+ // packages/cli/src/serve/local-control/service.ts
731
+ init_esbuild_shims();
732
+ import { randomBytes, randomUUID } from "node:crypto";
733
+ import { readFileSync } from "node:fs";
734
+ import { createServer } from "node:http";
735
+ import { createServer as createSecureServer } from "node:https";
736
+ var CORS_KEY = "local-control";
737
+ var MAX_CONNECTIONS = 64;
738
+ var HEADERS_TIMEOUT_MS = 1e4;
739
+ var KEEP_ALIVE_TIMEOUT_MS = 5e3;
740
+ var REQUEST_TIMEOUT_MS = 30 * 6e4;
741
+ var InvalidLocalControlTargetError = class extends Error {
742
+ static {
743
+ __name(this, "InvalidLocalControlTargetError");
744
+ }
745
+ code = "invalid_local_control_target";
746
+ constructor() {
747
+ super("Local Control target must be a valid URL target.");
748
+ this.name = "InvalidLocalControlTargetError";
749
+ }
750
+ };
751
+ var LocalControlService = class {
752
+ static {
753
+ __name(this, "LocalControlService");
754
+ }
755
+ #deps;
756
+ #server;
757
+ #token;
758
+ #selected;
759
+ #sleep;
760
+ #url;
761
+ #transition = Promise.resolve();
762
+ constructor(deps) {
763
+ this.#deps = deps;
764
+ }
765
+ get active() {
766
+ return this.#server !== void 0;
767
+ }
768
+ status() {
769
+ if (!this.#server || !this.#token || !this.#selected) {
770
+ return { active: false };
771
+ }
772
+ return {
773
+ active: true,
774
+ url: this.#url,
775
+ interfaceName: this.#selected.interfaceName,
776
+ address: this.#selected.address,
777
+ port: this.#deps.getPort(),
778
+ sleepInhibited: this.#sleep !== void 0 && sleepInhibitor.isRunning(),
779
+ encrypted: this.#deps.tlsPaths !== void 0
780
+ };
781
+ }
782
+ /**
783
+ * Bring the LAN listener up. Enabling while already active is a no-op that
784
+ * returns the existing status rather than re-minting: a second scan of the
785
+ * same QR must keep working, and silently invalidating the token the user is
786
+ * mid-pairing with would be indistinguishable from a bug.
787
+ */
788
+ async enable(options = {}) {
789
+ return this.#serialize(() => this.#enable(options));
790
+ }
791
+ async #enable(options) {
792
+ if (this.active) return this.status();
793
+ const selected = selectLanAddress(options.address);
794
+ const port = this.#deps.getPort();
795
+ const authority = `${selected.address}:${port}`;
796
+ const token = mintPairingToken();
797
+ const tls = this.#deps.tlsPaths;
798
+ const scheme = tls ? "https" : "http";
799
+ const origin = new URL(`${scheme}://${authority}`).origin;
800
+ const url = buildPairedUrl(scheme, authority, token.secret, options.target);
801
+ const server = tls ? createSecureServer(
802
+ { cert: readFileSync(tls.cert), key: readFileSync(tls.key) },
803
+ this.#deps.app
804
+ ) : createServer(this.#deps.app);
805
+ server.maxConnections = MAX_CONNECTIONS;
806
+ server.headersTimeout = HEADERS_TIMEOUT_MS;
807
+ server.requestTimeout = REQUEST_TIMEOUT_MS;
808
+ server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS;
809
+ tagListener(server, { kind: "local-control", authority, origin });
810
+ this.#deps.credentials.addPairingToken(token.id, token.secret);
811
+ this.#deps.originAllowlist.add(CORS_KEY, origin);
812
+ try {
813
+ this.#deps.attachWebSocket(server);
814
+ await listen(server, port, selected.address);
815
+ } catch (error2) {
816
+ this.#deps.detachWebSocket(server);
817
+ this.#deps.credentials.revokePairingToken(token.id);
818
+ this.#deps.originAllowlist.remove(CORS_KEY);
819
+ throw error2;
820
+ }
821
+ server.on("error", (error2) => {
822
+ writeStderrLine(
823
+ `qwen serve: Local Control listener error: ${error2.message}`
824
+ );
825
+ });
826
+ this.#server = server;
827
+ this.#token = token;
828
+ this.#selected = selected;
829
+ this.#url = url;
830
+ this.#sleep = sleepInhibitor.acquire("Qwen Code Local Control is active");
831
+ return this.status();
832
+ }
833
+ /**
834
+ * Take the LAN listener down and invalidate its credential.
835
+ *
836
+ * Revocation happens first and unconditionally. If closing the socket fails
837
+ * or hangs, the outcome is a listener that accepts connections no credential
838
+ * can authenticate — inert. The reverse order would leave a live, reachable
839
+ * listener with a valid token if teardown failed partway.
840
+ */
841
+ async disable() {
842
+ return this.#serialize(() => this.#disable());
843
+ }
844
+ async #disable() {
845
+ const server = this.#server;
846
+ const token = this.#token;
847
+ this.#server = void 0;
848
+ this.#token = void 0;
849
+ this.#selected = void 0;
850
+ this.#url = void 0;
851
+ if (token) this.#deps.credentials.revokePairingToken(token.id);
852
+ this.#deps.originAllowlist.remove(CORS_KEY);
853
+ this.#sleep?.release();
854
+ this.#sleep = void 0;
855
+ if (server) {
856
+ this.#deps.detachWebSocket(server);
857
+ await close(server);
858
+ }
859
+ return { active: false };
860
+ }
861
+ /**
862
+ * Called from the daemon's drain path. Local Control must not outlive the
863
+ * daemon that owns it: a listener surviving drain would hold the port and
864
+ * keep answering with a token nothing can revoke anymore.
865
+ */
866
+ async dispose() {
867
+ await this.disable();
868
+ }
869
+ async #serialize(operation) {
870
+ const previous = this.#transition;
871
+ let release;
872
+ this.#transition = new Promise((resolve7) => {
873
+ release = resolve7;
874
+ });
875
+ await previous;
876
+ try {
877
+ return await operation();
878
+ } finally {
879
+ release();
880
+ }
881
+ }
882
+ };
883
+ function mintPairingToken() {
884
+ const secret = randomBytes(32).toString("base64url");
885
+ return { id: randomUUID(), secret };
886
+ }
887
+ __name(mintPairingToken, "mintPairingToken");
888
+ function buildPairedUrl(scheme, authority, secret, target) {
889
+ const url = new URL(`${scheme}://${authority}`);
890
+ if (target) {
891
+ let resolved;
892
+ try {
893
+ resolved = new URL(target, url);
894
+ } catch {
895
+ throw new InvalidLocalControlTargetError();
896
+ }
897
+ url.pathname = resolved.pathname;
898
+ url.search = resolved.search;
899
+ }
900
+ url.hash = `token=${encodeURIComponent(secret)}`;
901
+ return url.toString();
902
+ }
903
+ __name(buildPairedUrl, "buildPairedUrl");
904
+ function listen(server, port, host) {
905
+ return new Promise((resolve7, reject) => {
906
+ const onError = /* @__PURE__ */ __name((error2) => {
907
+ server.removeListener("listening", onListening);
908
+ reject(error2);
909
+ }, "onError");
910
+ const onListening = /* @__PURE__ */ __name(() => {
911
+ server.removeListener("error", onError);
912
+ resolve7();
913
+ }, "onListening");
914
+ server.once("error", onError);
915
+ server.once("listening", onListening);
916
+ server.listen(port, host);
917
+ });
918
+ }
919
+ __name(listen, "listen");
920
+ function close(server) {
921
+ return new Promise((resolve7) => {
922
+ server.closeAllConnections?.();
923
+ server.close(() => resolve7());
924
+ });
925
+ }
926
+ __name(close, "close");
927
+
928
+ // packages/cli/src/serve/routes/workspace-local-control.ts
929
+ init_esbuild_shims();
930
+ async function withUiData(status) {
931
+ let qrText;
932
+ if (status.url) {
933
+ try {
934
+ const { default: qrcode } = await import("./main-PXAUXNF2.js");
935
+ qrcode.setErrorLevel("Q");
936
+ qrcode.generate(status.url, { small: true }, (code) => {
937
+ qrText = code.trimEnd();
938
+ });
939
+ } catch {
940
+ qrText = void 0;
941
+ }
942
+ }
943
+ return { ...status, qrText, interfaces: listLanCandidates() };
944
+ }
945
+ __name(withUiData, "withUiData");
946
+ function presentStatus(req, ui) {
947
+ if (requestWasAuthenticated(req)) return ui;
948
+ const { url: _url, qrText: _qrText, ...rest } = ui;
949
+ return { ...rest, urlRedacted: ui.url !== void 0 };
950
+ }
951
+ __name(presentStatus, "presentStatus");
952
+ function requirePrimaryListener(req, res) {
953
+ if (listenerIdentityOf(req).kind === "primary") return true;
954
+ res.status(403).json({
955
+ error: "Local Control can only be enabled from the machine running the daemon.",
956
+ code: "local_control_remote_enable_denied"
957
+ });
958
+ return false;
959
+ }
960
+ __name(requirePrimaryListener, "requirePrimaryListener");
961
+ function registerWorkspaceLocalControlRoutes(app, deps) {
962
+ app.get("/workspace/local-control", async (req, res) => {
963
+ res.status(200).json(presentStatus(req, await withUiData(deps.service.status())));
964
+ });
965
+ app.post(
966
+ "/workspace/local-control/enable",
967
+ deps.mutate(),
968
+ async (req, res) => {
969
+ if (!requirePrimaryListener(req, res)) return;
970
+ if (deps.webShellAvailable === false) {
971
+ res.status(409).json({
972
+ error: "Local Control requires the Web Shell.",
973
+ code: "local_control_web_shell_unavailable"
974
+ });
975
+ return;
976
+ }
977
+ if (deps.primaryBindHostname !== void 0 && !isLoopbackBind(deps.primaryBindHostname)) {
978
+ res.status(409).json({
979
+ error: "Local Control requires the daemon to be bound to loopback; restart it with --hostname 127.0.0.1.",
980
+ code: "local_control_non_loopback_bind"
981
+ });
982
+ return;
983
+ }
984
+ if (deps.isDaemonDraining?.()) {
985
+ res.status(503).json({
986
+ error: "Daemon is shutting down.",
987
+ code: "daemon_draining"
988
+ });
989
+ return;
990
+ }
991
+ const body = deps.safeBody(req) ?? {};
992
+ try {
993
+ const ui = await withUiData(
994
+ await deps.service.enable({
995
+ address: typeof body.address === "string" ? body.address : void 0,
996
+ target: typeof body.target === "string" ? body.target : void 0
997
+ })
998
+ );
999
+ if (!requestWasAuthenticated(req) && ui.url) {
1000
+ writeStdoutLineSafe(
1001
+ `qwen serve: Local Control pairing URL: ${ui.url}`
1002
+ );
1003
+ }
1004
+ res.status(200).json(presentStatus(req, ui));
1005
+ } catch (error2) {
1006
+ sendEnableError(res, error2);
1007
+ }
1008
+ }
1009
+ );
1010
+ app.post(
1011
+ "/workspace/local-control/disable",
1012
+ deps.mutate(),
1013
+ async (req, res) => {
1014
+ if (listenerIdentityOf(req).kind === "local-control") {
1015
+ queueMicrotask(() => {
1016
+ void deps.service.disable().catch((error2) => {
1017
+ writeStderrLine(
1018
+ `qwen serve: Local Control disable failed: ${error2 instanceof Error ? error2.message : String(error2)}`
1019
+ );
1020
+ });
1021
+ });
1022
+ res.status(200).json({ active: false });
1023
+ return;
1024
+ }
1025
+ res.status(200).json(
1026
+ presentStatus(req, await withUiData(await deps.service.disable()))
1027
+ );
1028
+ }
1029
+ );
1030
+ }
1031
+ __name(registerWorkspaceLocalControlRoutes, "registerWorkspaceLocalControlRoutes");
1032
+ function sendEnableError(res, error2) {
1033
+ if (error2 instanceof AmbiguousLanInterfaceError) {
1034
+ res.status(409).json({
1035
+ error: error2.message,
1036
+ code: error2.code,
1037
+ interfaces: error2.candidates
1038
+ });
1039
+ return;
1040
+ }
1041
+ if (error2 instanceof NoLanInterfaceError) {
1042
+ res.status(409).json({ error: error2.message, code: error2.code });
1043
+ return;
1044
+ }
1045
+ if (error2 instanceof UnknownLanInterfaceError) {
1046
+ res.status(409).json({
1047
+ error: error2.message,
1048
+ code: error2.code,
1049
+ interfaces: listLanCandidates()
1050
+ });
1051
+ return;
1052
+ }
1053
+ if (error2 instanceof InvalidLocalControlTargetError) {
1054
+ res.status(400).json({ error: error2.message, code: error2.code });
1055
+ return;
1056
+ }
1057
+ res.status(500).json({
1058
+ error: error2 instanceof Error ? error2.message : String(error2),
1059
+ code: "local_control_enable_failed"
1060
+ });
1061
+ }
1062
+ __name(sendEnableError, "sendEnableError");
1063
+
613
1064
  // packages/cli/src/serve/acp-http/index.ts
614
1065
  init_esbuild_shims();
615
- import { createHash as createHash3, timingSafeEqual } from "node:crypto";
616
1066
 
617
1067
  // packages/cli/src/serve/acp-http/dispatch.ts
618
1068
  init_esbuild_shims();
@@ -1131,6 +1581,7 @@ function createAuditPublisher(deps) {
1131
1581
  if (record.sizeBytes !== void 0) payload.sizeBytes = record.sizeBytes;
1132
1582
  if (record.truncated) payload.truncated = true;
1133
1583
  if (record.matchedIgnore) payload.matchedIgnore = record.matchedIgnore;
1584
+ if (record.operation !== void 0) payload.operation = record.operation;
1134
1585
  if (record.pattern !== void 0 && includeRawPaths) {
1135
1586
  payload.pattern = record.pattern;
1136
1587
  }
@@ -1177,7 +1628,7 @@ __name(createAuditPublisher, "createAuditPublisher");
1177
1628
 
1178
1629
  // packages/cli/src/serve/fs/workspace-file-system.ts
1179
1630
  init_esbuild_shims();
1180
- import { createHash as createHash2, randomBytes } from "node:crypto";
1631
+ import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
1181
1632
  import { constants as fsConstants, promises as fsp2 } from "node:fs";
1182
1633
  import * as path4 from "node:path";
1183
1634
 
@@ -1238,6 +1689,11 @@ function assertCursorMatchesFile(cursor, stats, path19) {
1238
1689
  __name(assertCursorMatchesFile, "assertCursorMatchesFile");
1239
1690
 
1240
1691
  // packages/cli/src/serve/fs/workspace-file-system.ts
1692
+ var OWNER_ONLY_NEW_FILE_MODE = 384;
1693
+ function resolveNewFileModeBits(policy, umask) {
1694
+ return policy === "system" ? 438 & ~(umask ?? process.umask()) : OWNER_ONLY_NEW_FILE_MODE;
1695
+ }
1696
+ __name(resolveNewFileModeBits, "resolveNewFileModeBits");
1241
1697
  function createWorkspaceFileSystemFactory(deps) {
1242
1698
  const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
1243
1699
  if (boundWorkspaces.length === 0) {
@@ -1263,6 +1719,7 @@ function createWorkspaceFileSystemFactory(deps) {
1263
1719
  });
1264
1720
  const lowFs = new StandardFileSystemService();
1265
1721
  const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
1722
+ const newFileMode = deps.newFileMode ?? "owner";
1266
1723
  const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
1267
1724
  primaryWorkspace,
1268
1725
  workspaces,
@@ -1271,7 +1728,8 @@ function createWorkspaceFileSystemFactory(deps) {
1271
1728
  ctx,
1272
1729
  lowFs,
1273
1730
  pathLocks,
1274
- generationGuard: deps.generationGuard
1731
+ generationGuard: deps.generationGuard,
1732
+ newFileMode
1275
1733
  }), "forRequest");
1276
1734
  return {
1277
1735
  assertCanWrite() {
@@ -1304,7 +1762,8 @@ function createWorkspaceFileSystemFactory(deps) {
1304
1762
  audit,
1305
1763
  ctx,
1306
1764
  pathLocks,
1307
- generationGuard: deps.generationGuard
1765
+ generationGuard: deps.generationGuard,
1766
+ newFileMode
1308
1767
  });
1309
1768
  return;
1310
1769
  } catch (outsideErr) {
@@ -1343,6 +1802,7 @@ async function writeSameHostToolTextOutsideWorkspace(deps) {
1343
1802
  content,
1344
1803
  mode: "overwrite",
1345
1804
  meta,
1805
+ newFileModeBits: resolveNewFileModeBits(deps.newFileMode),
1346
1806
  assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1347
1807
  });
1348
1808
  deps.audit.recordAccess(deps.ctx, {
@@ -1862,6 +2322,7 @@ var WorkspaceFileSystemImpl = class {
1862
2322
  mode: opts.mode,
1863
2323
  expectedHash: opts.expectedHash,
1864
2324
  meta,
2325
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
1865
2326
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1866
2327
  });
1867
2328
  const verdict = this.ignoreVerdict(p, "file");
@@ -1924,6 +2385,7 @@ var WorkspaceFileSystemImpl = class {
1924
2385
  content,
1925
2386
  mode: "overwrite",
1926
2387
  meta,
2388
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
1927
2389
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1928
2390
  });
1929
2391
  const verdict = this.ignoreVerdict(p, "file");
@@ -2035,6 +2497,7 @@ var WorkspaceFileSystemImpl = class {
2035
2497
  mode: "replace",
2036
2498
  expectedHash: opts.expectedHash,
2037
2499
  meta,
2500
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
2038
2501
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2039
2502
  });
2040
2503
  const verdict = this.ignoreVerdict(p, "file");
@@ -2098,6 +2561,7 @@ var WorkspaceFileSystemImpl = class {
2098
2561
  content: next,
2099
2562
  mode: "overwrite",
2100
2563
  meta: mergeWriteMeta(snapshot.meta, {}),
2564
+ newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
2101
2565
  assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2102
2566
  });
2103
2567
  const verdict = this.ignoreVerdict(p, "file");
@@ -2149,6 +2613,36 @@ var WorkspaceFileSystemImpl = class {
2149
2613
  });
2150
2614
  }
2151
2615
  }
2616
+ async mkdir(p, opts) {
2617
+ const start = performance.now();
2618
+ try {
2619
+ this.deps.generationGuard?.assertOpen();
2620
+ assertTrustedForIntent(this.deps.trusted, "write");
2621
+ const out = await this.deps.pathLocks.runExclusive(
2622
+ p,
2623
+ async () => {
2624
+ await ensureResolvedDirectory(p, {
2625
+ recursive: opts?.recursive ?? false,
2626
+ assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
2627
+ });
2628
+ this.deps.generationGuard?.assertOpen();
2629
+ const verdict = this.ignoreVerdict(p, "directory");
2630
+ this.deps.audit.recordAccess(this.deps.ctx, {
2631
+ intent: "write",
2632
+ absolute: p,
2633
+ durationMs: performance.now() - start,
2634
+ sizeBytes: 0,
2635
+ operation: "mkdir",
2636
+ matchedIgnore: verdict.ignored ? verdict.category : void 0
2637
+ });
2638
+ return void 0;
2639
+ }
2640
+ );
2641
+ return out;
2642
+ } catch (err) {
2643
+ throw this.recordAndWrap(err, "write", p);
2644
+ }
2645
+ }
2152
2646
  /**
2153
2647
  * Coerce an arbitrary thrown value into an `FsError`, emit the
2154
2648
  * matching `fs.denied` audit event, and return the typed error
@@ -2632,10 +3126,82 @@ async function atomicWriteTextResolvedFile(input) {
2632
3126
  buf,
2633
3127
  mode: input.mode,
2634
3128
  expectedHash: input.expectedHash,
3129
+ newFileModeBits: input.newFileModeBits,
2635
3130
  assertGenerationOpen: input.assertGenerationOpen
2636
3131
  });
2637
3132
  }
2638
3133
  __name(atomicWriteTextResolvedFile, "atomicWriteTextResolvedFile");
3134
+ async function ensureResolvedDirectory(target, opts) {
3135
+ const assertRealDirectory = /* @__PURE__ */ __name(async (p) => {
3136
+ const st = await fsp2.lstat(p);
3137
+ if (st.isSymbolicLink()) {
3138
+ throw new FsError("symlink_escape", `directory path is a symlink: ${p}`, {
3139
+ hint: "re-resolve the target after detecting symlink swaps"
3140
+ });
3141
+ }
3142
+ if (!st.isDirectory()) {
3143
+ throw new FsError(
3144
+ "parse_error",
3145
+ `path exists and is not a directory: ${p}`
3146
+ );
3147
+ }
3148
+ }, "assertRealDirectory");
3149
+ const assertParentNotSymlink = /* @__PURE__ */ __name(async (p) => {
3150
+ const parent = path4.dirname(p);
3151
+ const st = await fsp2.lstat(parent);
3152
+ if (st.isSymbolicLink()) {
3153
+ throw new FsError(
3154
+ "symlink_escape",
3155
+ `directory parent is a symlink: ${parent}`,
3156
+ { hint: "re-resolve the target after detecting symlink swaps" }
3157
+ );
3158
+ }
3159
+ }, "assertParentNotSymlink");
3160
+ try {
3161
+ await assertRealDirectory(target);
3162
+ return;
3163
+ } catch (err) {
3164
+ if (isFsError(err)) throw err;
3165
+ if (err.code !== "ENOENT") throw err;
3166
+ }
3167
+ if (!opts.recursive) {
3168
+ opts.assertGenerationOpen();
3169
+ await assertParentNotSymlink(target);
3170
+ try {
3171
+ await fsp2.mkdir(target, { mode: 493 });
3172
+ } catch (err) {
3173
+ if (err.code !== "EEXIST") throw err;
3174
+ }
3175
+ await assertRealDirectory(target);
3176
+ return;
3177
+ }
3178
+ const missing = [];
3179
+ let current = target;
3180
+ while (true) {
3181
+ try {
3182
+ await assertRealDirectory(current);
3183
+ break;
3184
+ } catch (err) {
3185
+ if (isFsError(err)) throw err;
3186
+ if (err.code !== "ENOENT") throw err;
3187
+ missing.push(current);
3188
+ const parent = path4.dirname(current);
3189
+ if (parent === current) throw err;
3190
+ current = parent;
3191
+ }
3192
+ }
3193
+ for (const entry of missing.reverse()) {
3194
+ opts.assertGenerationOpen();
3195
+ await assertParentNotSymlink(entry);
3196
+ try {
3197
+ await fsp2.mkdir(entry, { mode: 493 });
3198
+ } catch (err) {
3199
+ if (err.code !== "EEXIST") throw err;
3200
+ }
3201
+ await assertRealDirectory(entry);
3202
+ }
3203
+ }
3204
+ __name(ensureResolvedDirectory, "ensureResolvedDirectory");
2639
3205
  async function atomicPublishResolvedFile(input) {
2640
3206
  const target = input.target;
2641
3207
  const parent = path4.dirname(target);
@@ -2651,7 +3217,7 @@ async function atomicPublishResolvedFile(input) {
2651
3217
  `parent path is not a directory: ${parent}`
2652
3218
  );
2653
3219
  }
2654
- const tmpSuffix = `.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
3220
+ const tmpSuffix = `.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
2655
3221
  const tmpNameMaxBytes = 255;
2656
3222
  const tmpBaseMaxBytes = tmpNameMaxBytes - 1 - Buffer.byteLength(tmpSuffix, "utf-8");
2657
3223
  let tmpBase = path4.basename(target);
@@ -2679,7 +3245,10 @@ async function atomicPublishResolvedFile(input) {
2679
3245
  mode: input.mode,
2680
3246
  expectedHash: input.expectedHash
2681
3247
  });
2682
- await chmodHandleBestEffort(tempHandle, targetState.mode ?? 384);
3248
+ await chmodHandleBestEffort(
3249
+ tempHandle,
3250
+ targetState.mode ?? input.newFileModeBits ?? OWNER_ONLY_NEW_FILE_MODE
3251
+ );
2683
3252
  await assertTempPathMatchesStat(tmpPath, tempStat);
2684
3253
  await tempHandle.close();
2685
3254
  tempHandle = void 0;
@@ -4658,7 +5227,7 @@ __name(registerWorkspaceQualifiedVoiceRoutes, "registerWorkspaceQualifiedVoiceRo
4658
5227
 
4659
5228
  // packages/cli/src/serve/workspace-remember.ts
4660
5229
  init_esbuild_shims();
4661
- import { randomUUID } from "node:crypto";
5230
+ import { randomUUID as randomUUID2 } from "node:crypto";
4662
5231
  var debugLogger = createDebugLogger("WORKSPACE_REMEMBER");
4663
5232
  function requireTrustedWorkspace(deps, res) {
4664
5233
  if (deps.isWorkspaceTrusted?.() !== false) return true;
@@ -4688,7 +5257,7 @@ function nowIso() {
4688
5257
  }
4689
5258
  __name(nowIso, "nowIso");
4690
5259
  function createMemoryTaskId(kind) {
4691
- return `${kind}-${randomUUID()}`;
5260
+ return `${kind}-${randomUUID2()}`;
4692
5261
  }
4693
5262
  __name(createMemoryTaskId, "createMemoryTaskId");
4694
5263
  function touchedScopesFromTopics(topics) {
@@ -5446,11 +6015,13 @@ var RequestedSessionIdAdmissionError = class extends Error {
5446
6015
  name = "RequestedSessionIdAdmissionError";
5447
6016
  };
5448
6017
  async function persistedSessionExists(sessionService, sessionId) {
5449
- if (await sessionService.getSessionLocation(sessionId) !== void 0) {
5450
- return true;
5451
- }
5452
- if (await sessionService.findSessionIdIgnoringCase?.(sessionId) !== void 0) {
5453
- return true;
6018
+ try {
6019
+ if (await sessionService.findSessionIdIgnoringCase(sessionId) !== void 0) {
6020
+ return true;
6021
+ }
6022
+ } catch (error2) {
6023
+ if (error2 instanceof SessionIdCaseConflictError) return true;
6024
+ throw error2;
5454
6025
  }
5455
6026
  for (const state of ["active", "archived"]) {
5456
6027
  try {
@@ -7759,8 +8330,13 @@ var SessionArchiveCoordinator = class {
7759
8330
  maintenanceSealed = false;
7760
8331
  activeMaintenance = 0;
7761
8332
  maintenanceDrain;
8333
+ // Lock keys are canonicalized like every other session-id lookup: batch
8334
+ // delete/archive/unarchive lock raw caller spellings while restore locks
8335
+ // the request spelling, and on a case-insensitive filesystem both reach
8336
+ // the same transcript file — uncanonicalized keys would let a differently
8337
+ // cased caller id slip past a held guard and unlink it mid-restore.
7762
8338
  assertNotTransitioning(sessionId) {
7763
- if (this.exclusive.has(sessionId)) {
8339
+ if (this.exclusive.has(normalizeSessionIdForLookup(sessionId))) {
7764
8340
  throw new SessionArchivingError(sessionId);
7765
8341
  }
7766
8342
  }
@@ -7768,7 +8344,9 @@ var SessionArchiveCoordinator = class {
7768
8344
  if (this.maintenanceSealed) {
7769
8345
  throw new DaemonDrainingError();
7770
8346
  }
7771
- const uniqueSessionIds = [...new Set(sessionIds)];
8347
+ const uniqueSessionIds = [
8348
+ ...new Set(sessionIds.map(normalizeSessionIdForLookup))
8349
+ ];
7772
8350
  for (const sessionId of uniqueSessionIds) {
7773
8351
  this.assertNotTransitioning(sessionId);
7774
8352
  if ((this.shared.get(sessionId) ?? 0) > 0) {
@@ -7810,7 +8388,9 @@ var SessionArchiveCoordinator = class {
7810
8388
  if (this.maintenanceSealed) {
7811
8389
  throw new DaemonDrainingError();
7812
8390
  }
7813
- const uniqueSessionIds = [...new Set(sessionIds)];
8391
+ const uniqueSessionIds = [
8392
+ ...new Set(sessionIds.map(normalizeSessionIdForLookup))
8393
+ ];
7814
8394
  for (const sessionId of uniqueSessionIds) {
7815
8395
  this.assertNotTransitioning(sessionId);
7816
8396
  }
@@ -8004,7 +8584,9 @@ async function deleteDaemonSessions(params) {
8004
8584
  coordinatorLockHeld = false,
8005
8585
  onError
8006
8586
  } = params;
8007
- const uniqueSessionIds = [...new Set(sessionIds)];
8587
+ const uniqueSessionIds = [
8588
+ ...new Set(sessionIds.map(normalizeSessionIdForLookup))
8589
+ ];
8008
8590
  if (!coordinatorLockHeld) {
8009
8591
  for (const sessionId of uniqueSessionIds) {
8010
8592
  coordinator.assertNotTransitioning(sessionId);
@@ -8014,22 +8596,40 @@ async function deleteDaemonSessions(params) {
8014
8596
  uniqueSessionIds.map(async (sessionId) => {
8015
8597
  try {
8016
8598
  const mutateSession = /* @__PURE__ */ __name(async () => {
8599
+ const removePersistedSession = /* @__PURE__ */ __name(async () => {
8600
+ const result = await deletePersistedSessionWithLease(
8601
+ service,
8602
+ sessionId
8603
+ );
8604
+ if (result.kind === "error") {
8605
+ onError?.({
8606
+ phase: "remove",
8607
+ sessionId,
8608
+ error: errorMessage(result.error)
8609
+ });
8610
+ return result;
8611
+ }
8612
+ try {
8613
+ await bridge.deleteSessionAttachments(sessionId);
8614
+ return result;
8615
+ } catch (error2) {
8616
+ onError?.({
8617
+ phase: "delete",
8618
+ sessionId,
8619
+ error: errorMessage(error2)
8620
+ });
8621
+ return {
8622
+ kind: "error",
8623
+ error: error2,
8624
+ mutationApplied: result.mutationApplied
8625
+ };
8626
+ }
8627
+ }, "removePersistedSession");
8017
8628
  try {
8018
8629
  await bridge.closeSession(sessionId);
8019
8630
  } catch (error2) {
8020
8631
  if (isSessionNotFoundError(error2)) {
8021
- const result2 = await deletePersistedSessionWithLease(
8022
- service,
8023
- sessionId
8024
- );
8025
- if (result2.kind === "error") {
8026
- onError?.({
8027
- phase: "remove",
8028
- sessionId,
8029
- error: errorMessage(result2.error)
8030
- });
8031
- }
8032
- return result2;
8632
+ return await removePersistedSession();
8033
8633
  }
8034
8634
  onError?.({
8035
8635
  phase: "close",
@@ -8042,18 +8642,7 @@ async function deleteDaemonSessions(params) {
8042
8642
  mutationApplied: false
8043
8643
  };
8044
8644
  }
8045
- const result = await deletePersistedSessionWithLease(
8046
- service,
8047
- sessionId
8048
- );
8049
- if (result.kind === "error") {
8050
- onError?.({
8051
- phase: "remove",
8052
- sessionId,
8053
- error: errorMessage(result.error)
8054
- });
8055
- }
8056
- return result;
8645
+ return await removePersistedSession();
8057
8646
  }, "mutateSession");
8058
8647
  return await (coordinatorLockHeld ? mutateSession() : coordinator.runExclusiveMany([sessionId], mutateSession));
8059
8648
  } catch (error2) {
@@ -8114,6 +8703,7 @@ async function deleteDaemonSessionIfOrphan(params) {
8114
8703
  if (result.kind === "error") {
8115
8704
  throw result.error;
8116
8705
  }
8706
+ bridge.markSessionCatalogChanged();
8117
8707
  return true;
8118
8708
  }
8119
8709
  __name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
@@ -8193,7 +8783,9 @@ async function archiveDaemonSessions(params) {
8193
8783
  coordinator,
8194
8784
  coordinatorLockHeld = false
8195
8785
  } = params;
8196
- const uniqueSessionIds = [...new Set(sessionIds)];
8786
+ const uniqueSessionIds = [
8787
+ ...new Set(sessionIds.map(normalizeSessionIdForLookup))
8788
+ ];
8197
8789
  if (!coordinatorLockHeld) {
8198
8790
  for (const sessionId of uniqueSessionIds) {
8199
8791
  coordinator.assertNotTransitioning(sessionId);
@@ -8335,7 +8927,9 @@ async function unarchiveDaemonSessions(params) {
8335
8927
  coordinator,
8336
8928
  coordinatorLockHeld = false
8337
8929
  } = params;
8338
- const uniqueSessionIds = [...new Set(sessionIds)];
8930
+ const uniqueSessionIds = [
8931
+ ...new Set(sessionIds.map(normalizeSessionIdForLookup))
8932
+ ];
8339
8933
  if (!coordinatorLockHeld) {
8340
8934
  for (const sessionId of uniqueSessionIds) {
8341
8935
  coordinator.assertNotTransitioning(sessionId);
@@ -9123,6 +9717,15 @@ function toRpcError(err) {
9123
9717
  sessionId: err.sessionId
9124
9718
  }
9125
9719
  };
9720
+ case "SessionIdCaseConflictError":
9721
+ return {
9722
+ code: RPC.INTERNAL_ERROR,
9723
+ message: errMsg(err),
9724
+ data: {
9725
+ errorKind: "session_conflict",
9726
+ sessionId: err.sessionId
9727
+ }
9728
+ };
9126
9729
  case "SessionArchivingError":
9127
9730
  return {
9128
9731
  code: RPC.INTERNAL_ERROR,
@@ -9231,11 +9834,20 @@ var AcpDispatcher = class {
9231
9834
  archiveStates
9232
9835
  });
9233
9836
  }
9837
+ // Combined invalidate-and-mark for catalog mutations whose conservative
9838
+ // finally-semantics match (delete/archive/unarchive). The revision advance
9839
+ // always follows the cache invalidation so a newly exposed version never
9840
+ // precedes it. Exact no-op paths (e.g. metadata rename) gate the mark on
9841
+ // an actual change via the bridge instead of using this helper.
9842
+ invalidateSessionListsAndMarkCatalog(archiveStates) {
9843
+ this.invalidateSessionLists(archiveStates);
9844
+ this.bridge.markSessionCatalogChanged();
9845
+ }
9234
9846
  async runWithSessionListInvalidation(archiveStates, mutation) {
9235
9847
  try {
9236
9848
  return await mutation();
9237
9849
  } finally {
9238
- this.invalidateSessionLists(archiveStates);
9850
+ this.invalidateSessionListsAndMarkCatalog(archiveStates);
9239
9851
  }
9240
9852
  }
9241
9853
  removeOrphanSession(sessionId, removePersistedSession = false, runtime = this.getSessionRuntimeContext()) {
@@ -9710,6 +10322,19 @@ var AcpDispatcher = class {
9710
10322
  return;
9711
10323
  }
9712
10324
  const sessionRuntime = this.getSessionRuntimeContext();
10325
+ if (isReservedStandaloneSessionSource({
10326
+ sourceType: typeof params["sourceType"] === "string" ? params["sourceType"] : void 0
10327
+ })) {
10328
+ conn.sendConn(
10329
+ error(
10330
+ id,
10331
+ RPC.INVALID_PARAMS,
10332
+ "The requested session source is reserved for daemon-owned standalone sessions.",
10333
+ { errorKind: "reserved_session_source" }
10334
+ )
10335
+ );
10336
+ return;
10337
+ }
9713
10338
  const source = parseSessionSource(
9714
10339
  params["sourceType"],
9715
10340
  params["sourceId"]
@@ -9843,23 +10468,54 @@ var AcpDispatcher = class {
9843
10468
  }
9844
10469
  );
9845
10470
  try {
10471
+ const guardSessionService = new SessionService(cwd, {
10472
+ runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
10473
+ });
10474
+ let persistedGuardId;
10475
+ try {
10476
+ persistedGuardId = await guardSessionService.findSessionIdIgnoringCase(sessionId);
10477
+ } catch (error2) {
10478
+ if (error2 instanceof SessionIdCaseConflictError && await guardSessionService.getSessionLocation(
10479
+ error2.candidateSessionId ?? sessionId
10480
+ ) === "conflict") {
10481
+ throw new SessionConflictError(sessionId);
10482
+ }
10483
+ throw error2;
10484
+ }
9846
10485
  const restored = await this.archiveCoordinator.runSharedMany(
9847
10486
  [sessionId],
9848
10487
  async () => {
9849
10488
  assertGenerationOpen?.();
10489
+ const sessionService = new SessionService(cwd, {
10490
+ runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
10491
+ });
10492
+ let storageSessionId = persistedGuardId ?? sessionId;
10493
+ let persistedSessionId;
10494
+ try {
10495
+ persistedSessionId = await sessionService.findSessionIdIgnoringCase(sessionId);
10496
+ } catch (error2) {
10497
+ if (error2 instanceof SessionIdCaseConflictError && await sessionService.getSessionLocation(
10498
+ error2.candidateSessionId ?? sessionId
10499
+ ) === "conflict") {
10500
+ throw new SessionConflictError(sessionId);
10501
+ }
10502
+ throw error2;
10503
+ }
10504
+ if (persistedSessionId) {
10505
+ storageSessionId = persistedSessionId;
10506
+ } else if (this.liveSessionIsolation) {
10507
+ throw new SessionNotFoundError(sessionId);
10508
+ }
9850
10509
  await assertSessionLoadable(
9851
10510
  cwd,
9852
- sessionId,
10511
+ storageSessionId,
9853
10512
  sessionRuntime.sessionRuntimeBaseDir
9854
10513
  );
9855
- const sessionService = new SessionService(cwd, {
9856
- runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
9857
- });
9858
10514
  const metadata = this.liveSessionIsolation ? await readLoadableLiveConversationMetadata(
9859
- sessionId,
9860
- (candidateId) => sessionService.readCreationMetadata(candidateId)
9861
- ) : await sessionService.readCreationMetadata(sessionId);
9862
- if (metadata === void 0) {
10515
+ storageSessionId,
10516
+ sessionService
10517
+ ) : await sessionService.readCreationMetadata(storageSessionId);
10518
+ if (metadata === void 0 || this.liveSessionIsolation !== void 0 && isReservedStandaloneSessionSource(metadata)) {
9863
10519
  throw new SessionNotFoundError(sessionId);
9864
10520
  }
9865
10521
  const liveConversationCwd = this.liveSessionIsolation ? await this.liveSessionIsolation.materializeConversationDirectory(
@@ -10718,6 +11374,7 @@ var AcpDispatcher = class {
10718
11374
  ..."groupId" in params ? { groupId: params["groupId"] } : {},
10719
11375
  ..."color" in params ? { color: params["color"] } : {}
10720
11376
  });
11377
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10721
11378
  this.replyConn(conn, id, { sessionId, ...organization });
10722
11379
  });
10723
11380
  return;
@@ -10736,6 +11393,7 @@ var AcpDispatcher = class {
10736
11393
  name: params["name"],
10737
11394
  color: params["color"]
10738
11395
  });
11396
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10739
11397
  assertGenerationOpen?.();
10740
11398
  this.replyConn(conn, id, { group });
10741
11399
  return;
@@ -10753,6 +11411,7 @@ var AcpDispatcher = class {
10753
11411
  ..."color" in params ? { color: params["color"] } : {},
10754
11412
  ..."order" in params ? { order: params["order"] } : {}
10755
11413
  });
11414
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
10756
11415
  assertGenerationOpen?.();
10757
11416
  this.replyConn(conn, id, { group });
10758
11417
  return;
@@ -10766,6 +11425,9 @@ var AcpDispatcher = class {
10766
11425
  const deleted = await createSessionOrganizationService(workspaceCwd).deleteGroup(
10767
11426
  groupId
10768
11427
  );
11428
+ if (deleted) {
11429
+ this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
11430
+ }
10769
11431
  assertGenerationOpen?.();
10770
11432
  this.replyConn(conn, id, { deleted });
10771
11433
  return;
@@ -12869,7 +13531,7 @@ var AcpDispatcher = class {
12869
13531
 
12870
13532
  // packages/cli/src/serve/acp-http/connection-registry.ts
12871
13533
  init_esbuild_shims();
12872
- import { randomUUID as randomUUID2 } from "node:crypto";
13534
+ import { randomUUID as randomUUID3 } from "node:crypto";
12873
13535
  var DEFAULT_MAX_CONNECTIONS = 64;
12874
13536
  var AcpConnection = class {
12875
13537
  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 +13542,8 @@ var AcpConnection = class {
12880
13542
  this.maxFramesPerConnection = maxFramesPerConnection;
12881
13543
  this.maxPayloadBytesPerConnection = maxPayloadBytesPerConnection;
12882
13544
  this.onPreAttachGuardFailure = onPreAttachGuardFailure;
12883
- this.connectionId = connectionId ?? randomUUID2();
12884
- this.clientId = randomUUID2();
13545
+ this.connectionId = connectionId ?? randomUUID3();
13546
+ this.clientId = randomUUID3();
12885
13547
  this.fromLoopback = fromLoopback;
12886
13548
  }
12887
13549
  static {
@@ -15985,9 +16647,15 @@ function mountAcpHttp(app, bridge, opts) {
15985
16647
  }
15986
16648
  let wss;
15987
16649
  let upgradeListener;
15988
- let upgradeServer;
16650
+ const upgradeServers = /* @__PURE__ */ new Set();
16651
+ const upgradeCredentials = opts.credentials ?? singleTokenCredentials(opts.token);
15989
16652
  function setupWebSocket(httpServer) {
15990
- if (disposed || wss) return;
16653
+ if (disposed || upgradeServers.has(httpServer)) return;
16654
+ if (wss) {
16655
+ upgradeServers.add(httpServer);
16656
+ httpServer.on("upgrade", upgradeListener);
16657
+ return;
16658
+ }
15991
16659
  wss = new import_websocket_server.default({
15992
16660
  noServer: true,
15993
16661
  maxPayload: 10 * 1024 * 1024,
@@ -16007,8 +16675,7 @@ function mountAcpHttp(app, bridge, opts) {
16007
16675
  return false;
16008
16676
  }, "handleProtocols")
16009
16677
  });
16010
- upgradeServer = httpServer;
16011
- const expectedTokenHash = opts.token ? createHash3("sha256").update(opts.token).digest() : void 0;
16678
+ upgradeServers.add(httpServer);
16012
16679
  upgradeListener = /* @__PURE__ */ __name((req, socket, head) => {
16013
16680
  if (disposed) {
16014
16681
  socket.destroy();
@@ -16036,8 +16703,18 @@ function mountAcpHttp(app, bridge, opts) {
16036
16703
  return;
16037
16704
  }
16038
16705
  const fromLoopback = isLoopbackSocket(socket);
16039
- if (fromLoopback) {
16040
- const host = (req.headers["host"] ?? "").toLowerCase();
16706
+ const upgradeListenerIdentity = listenerIdentityOfSocket(socket);
16707
+ const host = (req.headers["host"] ?? "").toLowerCase();
16708
+ if (upgradeListenerIdentity.kind === "local-control") {
16709
+ const authority = upgradeListenerIdentity.authority;
16710
+ const browserHost = upgradeListenerIdentity.origin === void 0 ? void 0 : new URL(upgradeListenerIdentity.origin).host.toLowerCase();
16711
+ if (authority === void 0 || host !== authority && host !== browserHost) {
16712
+ logReject(`host-not-allowed ${host || "(missing)"}`);
16713
+ socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
16714
+ socket.destroy();
16715
+ return;
16716
+ }
16717
+ } else if (fromLoopback) {
16041
16718
  const allowed = /* @__PURE__ */ new Set([
16042
16719
  `localhost:${localPort}`,
16043
16720
  `127.0.0.1:${localPort}`,
@@ -16062,7 +16739,8 @@ function mountAcpHttp(app, bridge, opts) {
16062
16739
  try {
16063
16740
  const isLoopbackOrigin = isSameLoopbackOrigin(origin, localPort);
16064
16741
  const isAllowlistedOrigin = opts.allowedOrigins !== void 0 && opts.allowedOrigins.origins.has(origin.toLowerCase());
16065
- if (!isLoopbackOrigin && !isAllowlistedOrigin) {
16742
+ const isListenerOrigin = upgradeListenerIdentity.kind === "local-control" && upgradeListenerIdentity.origin === origin.toLowerCase();
16743
+ if (!isLoopbackOrigin && !isAllowlistedOrigin && !isListenerOrigin) {
16066
16744
  logReject(`origin-not-allowed ${origin}`);
16067
16745
  socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
16068
16746
  socket.destroy();
@@ -16075,10 +16753,9 @@ function mountAcpHttp(app, bridge, opts) {
16075
16753
  return;
16076
16754
  }
16077
16755
  }
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)) {
16756
+ if (!upgradeCredentials.isOpen(upgradeListenerIdentity)) {
16757
+ const presented = extractUpgradeBearer(req);
16758
+ if (!presented || !upgradeCredentials.verify(presented, upgradeListenerIdentity)) {
16082
16759
  logReject("auth-mismatch");
16083
16760
  socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
16084
16761
  socket.destroy();
@@ -16587,10 +17264,12 @@ function mountAcpHttp(app, bridge, opts) {
16587
17264
  dispose: /* @__PURE__ */ __name(() => {
16588
17265
  if (disposed) return;
16589
17266
  disposed = true;
16590
- if (upgradeServer && upgradeListener) {
16591
- upgradeServer.removeListener("upgrade", upgradeListener);
17267
+ if (upgradeListener) {
17268
+ for (const server of upgradeServers) {
17269
+ server.removeListener("upgrade", upgradeListener);
17270
+ }
17271
+ upgradeServers.clear();
16592
17272
  upgradeListener = void 0;
16593
- upgradeServer = void 0;
16594
17273
  }
16595
17274
  registry.dispose();
16596
17275
  opts.workspaceRememberLane.dispose();
@@ -16730,6 +17409,17 @@ function mountAcpHttp(app, bridge, opts) {
16730
17409
  }, "getSnapshot"),
16731
17410
  attachServer(server) {
16732
17411
  setupWebSocket(server);
17412
+ },
17413
+ detachServer(server) {
17414
+ if (!upgradeServers.delete(server)) return;
17415
+ if (upgradeListener) server.removeListener("upgrade", upgradeListener);
17416
+ if (!wss) return;
17417
+ for (const client of wss.clients) {
17418
+ const clientSocket = client._socket;
17419
+ if (clientSocket?.server === server) {
17420
+ client.terminate();
17421
+ }
17422
+ }
16733
17423
  }
16734
17424
  };
16735
17425
  }
@@ -18752,7 +19442,7 @@ function createExtensionsController(deps) {
18752
19442
  version: ext.version,
18753
19443
  isActive: ext.isActive,
18754
19444
  path: ext.path,
18755
- ...ext.installMetadata?.source ? {
19445
+ ...ext.installMetadata?.source && ext.installMetadata.type !== "snapshot" ? {
18756
19446
  source: redactExtensionDisplaySource(
18757
19447
  ext.installMetadata.source
18758
19448
  )
@@ -18761,7 +19451,8 @@ function createExtensionsController(deps) {
18761
19451
  ...ext.installMetadata?.originSource ? { originSource: ext.installMetadata.originSource } : {},
18762
19452
  ...ext.installMetadata?.ref ? { ref: ext.installMetadata.ref } : {},
18763
19453
  ...ext.installMetadata?.autoUpdate !== void 0 ? { autoUpdate: ext.installMetadata.autoUpdate } : {},
18764
- updateState: ext.installMetadata ? "unknown" : "not updatable",
19454
+ ...ext.installMetadata?.type === "snapshot" ? { credentialPersistence: "one_time" } : ext.installMetadata?.credentialPersistence === "stored" ? { credentialPersistence: "stored" } : {},
19455
+ updateState: ext.installMetadata?.type === "snapshot" ? "not updatable" : ext.installMetadata ? "unknown" : "not updatable",
18765
19456
  capabilities,
18766
19457
  details: {
18767
19458
  mcpServers: ext.mcpServers ? Object.keys(ext.mcpServers) : [],
@@ -18811,6 +19502,7 @@ var EXTENSION_INTERACTION_DEADLINE_MS = 10 * 6e4;
18811
19502
  var EXTENSION_INTERACTIVE_PREPARE_DEADLINE_MS = EXTENSION_PREPARE_DEADLINE_MS + EXTENSION_INTERACTION_DEADLINE_MS;
18812
19503
  var EXTENSION_UPDATE_CHECK_DEADLINE_MS = 2 * 6e4;
18813
19504
  var EXTENSION_ARCHIVE_UPLOAD_LIMIT = "10mb";
19505
+ var MAX_EXTENSION_BATCH_SIZE = 100;
18814
19506
  var extensionArchiveBodyParser = import_express2.default.raw({
18815
19507
  type: "application/octet-stream",
18816
19508
  limit: EXTENSION_ARCHIVE_UPLOAD_LIMIT
@@ -18851,6 +19543,32 @@ var parseExtensionScope = /* @__PURE__ */ __name((body, res) => {
18851
19543
  }
18852
19544
  return scope === "user" ? "User" /* User */ : "Workspace" /* Workspace */;
18853
19545
  }, "parseExtensionScope");
19546
+ var parseExtensionBatchNames = /* @__PURE__ */ __name((req, res, safeBody2) => {
19547
+ const rawNames = safeBody2(req)["extensionNames"];
19548
+ if (!Array.isArray(rawNames) || rawNames.length === 0 || rawNames.length > MAX_EXTENSION_BATCH_SIZE || !rawNames.every((name) => typeof name === "string")) {
19549
+ res.status(400).json({
19550
+ error: `\`extensionNames\` must be a non-empty string array (max ${MAX_EXTENSION_BATCH_SIZE})`,
19551
+ code: "invalid_extension_names"
19552
+ });
19553
+ return void 0;
19554
+ }
19555
+ const names = [];
19556
+ const seen = /* @__PURE__ */ new Set();
19557
+ for (const name of rawNames) {
19558
+ if (!/^[a-zA-Z0-9-_.]+$/.test(name)) {
19559
+ res.status(400).json({
19560
+ error: `Invalid extension name "${name}"`,
19561
+ code: "invalid_extension_name"
19562
+ });
19563
+ return void 0;
19564
+ }
19565
+ const normalizedName = name.toLowerCase();
19566
+ if (seen.has(normalizedName)) continue;
19567
+ seen.add(normalizedName);
19568
+ names.push(name);
19569
+ }
19570
+ return names;
19571
+ }, "parseExtensionBatchNames");
18854
19572
  var parseExtensionRegistryUrl = /* @__PURE__ */ __name((value, res) => {
18855
19573
  let parsed;
18856
19574
  try {
@@ -18891,23 +19609,76 @@ var parsePotentialSourceUrl = /* @__PURE__ */ __name((source) => {
18891
19609
  }
18892
19610
  }
18893
19611
  }, "parsePotentialSourceUrl");
18894
- var validateExtensionSourceHost = /* @__PURE__ */ __name((source, res) => {
19612
+ var parseExtensionInstallSource = /* @__PURE__ */ __name((source, persistence, res) => {
19613
+ if (persistence !== void 0 && persistence !== "stored" && persistence !== "one_time") {
19614
+ res.status(400).json({
19615
+ error: '`credentialPersistence` must be "stored" or "one_time"'
19616
+ });
19617
+ return null;
19618
+ }
18895
19619
  const parsed = parsePotentialSourceUrl(source);
18896
- if (!parsed) return true;
18897
- if (parsed.username || parsed.password) {
18898
- res.status(400).json({ error: "`source` must not include credentials" });
18899
- return false;
19620
+ if (!parsed) {
19621
+ if (persistence !== void 0) {
19622
+ res.status(400).json({
19623
+ error: "`credentialPersistence` requires source URL credentials"
19624
+ });
19625
+ return null;
19626
+ }
19627
+ return { source };
18900
19628
  }
18901
19629
  if (isBlockedAuthProviderHost(parsed.hostname)) {
18902
19630
  res.status(400).json({ error: "`source` host is not allowed" });
18903
- return false;
19631
+ return null;
18904
19632
  }
18905
19633
  if (parsed.protocol !== "https:") {
18906
19634
  res.status(400).json({ error: "`source` must use https" });
18907
- return false;
19635
+ return null;
18908
19636
  }
18909
- return true;
18910
- }, "validateExtensionSourceHost");
19637
+ const authority = /^[a-z][a-z\d+.-]*:\/\/([^/?#]*)/i.exec(source)?.[1];
19638
+ const hasUserInfo = !!parsed.username || !!parsed.password || authority?.includes("@") === true;
19639
+ if (!hasUserInfo) {
19640
+ if (persistence !== void 0) {
19641
+ res.status(400).json({
19642
+ error: "`credentialPersistence` requires source URL credentials"
19643
+ });
19644
+ return null;
19645
+ }
19646
+ return { source };
19647
+ }
19648
+ const hasControlCharacter = /* @__PURE__ */ __name((value) => Array.from(value).some((character) => {
19649
+ const code = character.charCodeAt(0);
19650
+ return code <= 31 || code >= 127 && code <= 159;
19651
+ }), "hasControlCharacter");
19652
+ if (hasControlCharacter(source)) {
19653
+ res.status(400).json({ error: "`source` credentials are invalid" });
19654
+ return null;
19655
+ }
19656
+ let username;
19657
+ let password;
19658
+ try {
19659
+ username = decodeURIComponent(parsed.username);
19660
+ password = decodeURIComponent(parsed.password);
19661
+ } catch {
19662
+ res.status(400).json({ error: "`source` credentials are invalid" });
19663
+ return null;
19664
+ }
19665
+ const invalidText = /* @__PURE__ */ __name((value, maxBytes) => Buffer.byteLength(value, "utf8") > maxBytes || hasControlCharacter(value), "invalidText");
19666
+ if (!username && !password || invalidText(username, 256) || invalidText(password, 4096)) {
19667
+ res.status(400).json({ error: "`source` credentials are invalid" });
19668
+ return null;
19669
+ }
19670
+ parsed.username = "";
19671
+ parsed.password = "";
19672
+ const credentialPersistence = persistence ?? "one_time";
19673
+ return {
19674
+ source: parsed.toString(),
19675
+ gitCredential: {
19676
+ username,
19677
+ password,
19678
+ persistence: credentialPersistence
19679
+ }
19680
+ };
19681
+ }, "parseExtensionInstallSource");
18911
19682
  var validateExtensionSourceMetadata = /* @__PURE__ */ __name((installMetadata) => {
18912
19683
  if (installMetadata.type !== "git") return true;
18913
19684
  const parsed = parsePotentialSourceUrl(installMetadata.source);
@@ -19424,6 +20195,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19424
20195
  const allowPreRelease = body["allowPreRelease"];
19425
20196
  const registry = body["registry"];
19426
20197
  const consent = body["consent"];
20198
+ const credentialPersistence = body["credentialPersistence"];
19427
20199
  if (!source || typeof source !== "string") {
19428
20200
  res.status(400).json({ error: "Missing or invalid source" });
19429
20201
  return;
@@ -19448,7 +20220,6 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19448
20220
  res.status(400).json({ error: "`registry` must be a string" });
19449
20221
  return;
19450
20222
  }
19451
- const sourceValue = source;
19452
20223
  const refValue = typeof ref === "string" ? ref : void 0;
19453
20224
  const autoUpdateValue = typeof autoUpdate === "boolean" ? autoUpdate : void 0;
19454
20225
  const allowPreReleaseValue = typeof allowPreRelease === "boolean" ? allowPreRelease : void 0;
@@ -19461,7 +20232,25 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19461
20232
  });
19462
20233
  return;
19463
20234
  }
19464
- if (!validateExtensionSourceHost(sourceValue, res)) {
20235
+ const parsedSource = parseExtensionInstallSource(
20236
+ source,
20237
+ credentialPersistence,
20238
+ res
20239
+ );
20240
+ if (!parsedSource) return;
20241
+ const sourceValue = parsedSource.source;
20242
+ body["source"] = sourceValue;
20243
+ const gitCredential = parsedSource.gitCredential;
20244
+ if (gitCredential?.persistence === "one_time" && autoUpdateValue) {
20245
+ res.status(400).json({
20246
+ error: "`autoUpdate` is not supported with one-time credentials"
20247
+ });
20248
+ return;
20249
+ }
20250
+ if (gitCredential && isSupportedArchiveUrl(sourceValue)) {
20251
+ res.status(400).json({
20252
+ error: "Git credentials require an HTTPS Git install source."
20253
+ });
19465
20254
  return;
19466
20255
  }
19467
20256
  const localSource = /^[A-Za-z]:[\\/]/.test(sourceValue) || sourceValue.startsWith("/") || sourceValue.startsWith(".");
@@ -19511,7 +20300,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19511
20300
  }
19512
20301
  ctrl.runQueuedExtensionMutation(
19513
20302
  "install",
19514
- { source: sourceValue },
20303
+ gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
19515
20304
  res,
19516
20305
  async (extensionManager, _signal, context, operationId) => {
19517
20306
  const prepared = await context.prepare(async (signal) => {
@@ -19523,6 +20312,11 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19523
20312
  "Only GitHub, Git, and npm extension installs are supported over the daemon endpoint."
19524
20313
  );
19525
20314
  }
20315
+ if (gitCredential && installMetadata.type !== "git" && installMetadata.type !== "github-release") {
20316
+ throw new Error(
20317
+ "Git credentials require an HTTPS Git install source."
20318
+ );
20319
+ }
19526
20320
  if (installMetadata.type === "npm" && refValue) {
19527
20321
  throw new Error("--ref is not applicable for npm extensions.");
19528
20322
  }
@@ -19547,7 +20341,8 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19547
20341
  },
19548
20342
  initialActivation: { scope: "user" },
19549
20343
  requestConsent: /* @__PURE__ */ __name(() => Promise.resolve(), "requestConsent"),
19550
- signal
20344
+ signal,
20345
+ ...gitCredential ? { gitCredential } : {}
19551
20346
  });
19552
20347
  });
19553
20348
  try {
@@ -19559,9 +20354,13 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19559
20354
  );
19560
20355
  return {
19561
20356
  status: "installed",
19562
- source: sourceValue,
20357
+ ...gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
19563
20358
  name: committed.identity.name,
19564
- version: committed.version
20359
+ version: committed.version,
20360
+ ...gitCredential ? {
20361
+ credentialPersistence: gitCredential.persistence,
20362
+ ...prepared.credentialStorage ? { credentialStorage: prepared.credentialStorage } : {}
20363
+ } : {}
19565
20364
  };
19566
20365
  } finally {
19567
20366
  await extensionManager.disposePreparedExtension(prepared);
@@ -19934,6 +20733,17 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19934
20733
  }
19935
20734
  return state;
19936
20735
  }, "parseActivationState");
20736
+ const parseWorkspaceBatchActivationState = /* @__PURE__ */ __name((req, res) => {
20737
+ const state = safeBody2(req)["state"];
20738
+ if (state !== "enabled" && state !== "disabled" && state !== "inherit") {
20739
+ res.status(400).json({
20740
+ error: '`state` must be "enabled", "disabled", or "inherit"',
20741
+ code: "invalid_extension_activation"
20742
+ });
20743
+ return null;
20744
+ }
20745
+ return state;
20746
+ }, "parseWorkspaceBatchActivationState");
19937
20747
  const sendOperation = /* @__PURE__ */ __name((req, res, route, manager, operation, failureContext, run2, options = {}) => {
19938
20748
  if (!primaryController.validateExtensionMutationClient(req, res, {
19939
20749
  requireClientId: false,
@@ -19972,6 +20782,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19972
20782
  name: extension.name,
19973
20783
  version: extension.version,
19974
20784
  ...extension.installMetadata?.type ? { installType: extension.installMetadata.type } : {},
20785
+ ...extension.installMetadata?.type === "snapshot" ? { credentialPersistence: "one_time" } : extension.installMetadata?.credentialPersistence === "stored" ? { credentialPersistence: "stored" } : {},
19975
20786
  defaultActivation: policy?.defaultActivation ?? "enabled",
19976
20787
  workspaceOverrideCount: Object.values(
19977
20788
  policy?.workspaceOverrides ?? {}
@@ -19999,6 +20810,43 @@ function registerWorkspaceExtensionRoutes(app, deps) {
19999
20810
  }
20000
20811
  res.status(200).json(operation);
20001
20812
  });
20813
+ app.put("/extensions/activation", mutate({ strict: true }), (req, res) => {
20814
+ const names = parseExtensionBatchNames(req, res, safeBody2);
20815
+ if (!names) return;
20816
+ const state = parseActivationState(req, res);
20817
+ if (!state) return;
20818
+ const manager = primaryController.createExtensionManager(
20819
+ boundWorkspace,
20820
+ true
20821
+ );
20822
+ sendOperation(
20823
+ req,
20824
+ res,
20825
+ "PUT /extensions/activation",
20826
+ manager,
20827
+ "set_default_activation_batch",
20828
+ {},
20829
+ async (extensionManager, _signal, context) => {
20830
+ await context.commit(
20831
+ async (onCommitted) => await extensionManager.setExtensionDefaultActivations(
20832
+ names,
20833
+ state,
20834
+ onCommitted
20835
+ )
20836
+ );
20837
+ return {
20838
+ status: "updated",
20839
+ results: names.map((name) => ({
20840
+ name,
20841
+ defaultActivation: state
20842
+ }))
20843
+ };
20844
+ },
20845
+ {
20846
+ ...workspaceRegistry ? { refreshRuntimes: /* @__PURE__ */ __name(() => workspaceRegistry.listAll(), "refreshRuntimes") } : {}
20847
+ }
20848
+ );
20849
+ });
20002
20850
  app.put(
20003
20851
  "/extensions/:extensionId/activation",
20004
20852
  mutate({ strict: true }),
@@ -20048,6 +20896,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20048
20896
  const autoUpdate = body["autoUpdate"];
20049
20897
  const allowPreRelease = body["allowPreRelease"];
20050
20898
  const registry = body["registry"];
20899
+ const credentialPersistence = body["credentialPersistence"];
20051
20900
  if (typeof source !== "string" || !source) {
20052
20901
  res.status(400).json({ error: "Missing or invalid source" });
20053
20902
  return;
@@ -20080,7 +20929,27 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20080
20929
  });
20081
20930
  return;
20082
20931
  }
20083
- if (!validateExtensionSourceHost(source, res)) return;
20932
+ const parsedSource = parseExtensionInstallSource(
20933
+ source,
20934
+ credentialPersistence,
20935
+ res
20936
+ );
20937
+ if (!parsedSource) return;
20938
+ const sourceValue = parsedSource.source;
20939
+ body["source"] = sourceValue;
20940
+ const gitCredential = parsedSource.gitCredential;
20941
+ if (gitCredential?.persistence === "one_time" && autoUpdate === true) {
20942
+ res.status(400).json({
20943
+ error: "`autoUpdate` is not supported with one-time credentials"
20944
+ });
20945
+ return;
20946
+ }
20947
+ if (gitCredential && isSupportedArchiveUrl(sourceValue)) {
20948
+ res.status(400).json({
20949
+ error: "Git credentials require an HTTPS Git install source."
20950
+ });
20951
+ return;
20952
+ }
20084
20953
  if (!activation || typeof activation !== "object") {
20085
20954
  res.status(400).json({ error: "Missing initial activation" });
20086
20955
  return;
@@ -20119,10 +20988,10 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20119
20988
  "POST /extensions/install",
20120
20989
  manager,
20121
20990
  "install",
20122
- { source },
20991
+ gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
20123
20992
  async (extensionManager, _signal, context) => {
20124
20993
  const prepared = await context.prepare(async (signal) => {
20125
- const metadata = await parseInstallSource(source, {
20994
+ const metadata = await parseInstallSource(sourceValue, {
20126
20995
  networkPolicy: "public"
20127
20996
  });
20128
20997
  if (metadata.type !== "git" && metadata.type !== "github-release" && metadata.type !== "npm") {
@@ -20130,6 +20999,11 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20130
20999
  "Only GitHub, Git, and npm extension installs are supported over the daemon endpoint."
20131
21000
  );
20132
21001
  }
21002
+ if (gitCredential && metadata.type !== "git" && metadata.type !== "github-release") {
21003
+ throw new Error(
21004
+ "Git credentials require an HTTPS Git install source."
21005
+ );
21006
+ }
20133
21007
  if (!validateExtensionSourceMetadata(metadata)) {
20134
21008
  throw new Error("`source` host is not allowed");
20135
21009
  }
@@ -20154,7 +21028,8 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20154
21028
  requestConsent: /* @__PURE__ */ __name(() => Promise.resolve(), "requestConsent"),
20155
21029
  cwd: boundWorkspace,
20156
21030
  initialActivation,
20157
- signal
21031
+ signal,
21032
+ ...gitCredential ? { gitCredential } : {}
20158
21033
  });
20159
21034
  });
20160
21035
  try {
@@ -20166,9 +21041,13 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20166
21041
  );
20167
21042
  return {
20168
21043
  status: "installed",
20169
- source,
21044
+ ...gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
20170
21045
  name: committed.identity.name,
20171
- version: committed.version
21046
+ version: committed.version,
21047
+ ...gitCredential ? {
21048
+ credentialPersistence: gitCredential.persistence,
21049
+ ...prepared.credentialStorage ? { credentialStorage: prepared.credentialStorage } : {}
21050
+ } : {}
20172
21051
  };
20173
21052
  } finally {
20174
21053
  await extensionManager.disposePreparedExtension(prepared);
@@ -20235,9 +21114,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20235
21114
  if (!extension)
20236
21115
  throw new Error(`Extension "${extensionId}" not found`);
20237
21116
  if (extension.installMetadata?.type !== "git" && extension.installMetadata?.type !== "archive-url" && extension.installMetadata?.type !== "github-release" && extension.installMetadata?.type !== "npm") {
20238
- throw new Error(
20239
- `Extension "${extension.name}" is not remotely updatable.`
20240
- );
21117
+ throw new ExtensionNotUpdatableError(extension.name);
20241
21118
  }
20242
21119
  const preparedResult = await context.prepare(
20243
21120
  async (signal) => await extensionManager.prepareExtensionUpdate({
@@ -20299,7 +21176,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20299
21176
  );
20300
21177
  const snapshot = await manager.getExtensionStoreSnapshot();
20301
21178
  const policy = snapshot.extensions[extensionId];
20302
- if (!policy) {
21179
+ if (!policy || policy.declarationOnly) {
20303
21180
  res.status(204).end();
20304
21181
  return;
20305
21182
  }
@@ -20373,6 +21250,57 @@ function registerWorkspaceExtensionRoutes(app, deps) {
20373
21250
  });
20374
21251
  }
20375
21252
  });
21253
+ app.put(
21254
+ "/workspaces/:workspace/extensions/activation",
21255
+ mutate({ strict: true }),
21256
+ (req, res) => {
21257
+ const runtime = resolveWorkspaceRuntimeFromParam(registry, req, res);
21258
+ if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res)) return;
21259
+ const names = parseExtensionBatchNames(req, res, safeBody2);
21260
+ if (!names) return;
21261
+ const state = parseWorkspaceBatchActivationState(req, res);
21262
+ if (!state) return;
21263
+ const manager = primaryController.createExtensionManager(
21264
+ runtime.workspaceCwd,
21265
+ true
21266
+ );
21267
+ sendOperation(
21268
+ req,
21269
+ res,
21270
+ "PUT /workspaces/:workspace/extensions/activation",
21271
+ manager,
21272
+ "set_workspace_activation_batch",
21273
+ {},
21274
+ async (extensionManager, _signal, context) => {
21275
+ const snapshot = await context.commit(
21276
+ async (onCommitted) => await extensionManager.setExtensionWorkspaceActivations(
21277
+ names,
21278
+ runtime.workspaceCwd,
21279
+ state,
21280
+ onCommitted
21281
+ )
21282
+ );
21283
+ return {
21284
+ status: "updated",
21285
+ updated: snapshot.updated,
21286
+ results: names.map((name) => ({
21287
+ name,
21288
+ workspaceActivation: state === "inherit" ? null : state,
21289
+ effectiveActivation: extensionManager.getExtensionActivationForNameFromSnapshot(
21290
+ name,
21291
+ snapshot,
21292
+ runtime.workspaceCwd
21293
+ ).effective
21294
+ }))
21295
+ };
21296
+ },
21297
+ {
21298
+ refreshRuntimes: [runtime],
21299
+ assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
21300
+ }
21301
+ );
21302
+ }
21303
+ );
20376
21304
  app.put(
20377
21305
  "/workspaces/:workspace/extensions/:extensionId/activation",
20378
21306
  mutate({ strict: true }),
@@ -20777,6 +21705,7 @@ __name(registerWorkspaceQualifiedFileWriteRoutes, "registerWorkspaceQualifiedFil
20777
21705
  var MAX_CONCURRENT_UPLOADS = 4;
20778
21706
  var MAX_UPLOAD_FILENAME_BYTES = 255;
20779
21707
  var NUMBERED_CANDIDATE_CAP = 1e3;
21708
+ var MAX_UPLOAD_DIR_DEPTH = 64;
20780
21709
  var uploadGateLeases = /* @__PURE__ */ new WeakMap();
20781
21710
  function createUploadConcurrencyGate(max = MAX_CONCURRENT_UPLOADS) {
20782
21711
  let active = 0;
@@ -20934,6 +21863,14 @@ function fileUploadAdmission(deps, opts) {
20934
21863
  sendParseError(res, ROUTE2, "`path` must name a file");
20935
21864
  return;
20936
21865
  }
21866
+ if (dir.split("/").filter(Boolean).length > MAX_UPLOAD_DIR_DEPTH) {
21867
+ sendParseError(
21868
+ res,
21869
+ ROUTE2,
21870
+ `directory path exceeds ${MAX_UPLOAD_DIR_DEPTH} components`
21871
+ );
21872
+ return;
21873
+ }
20937
21874
  if (queryPath.includes("\0")) {
20938
21875
  sendParseError(res, ROUTE2, "path must not contain null bytes");
20939
21876
  return;
@@ -20979,10 +21916,11 @@ function fileUploadAdmission(deps, opts) {
20979
21916
  dirStat = await fs9.stat(resolvedDir);
20980
21917
  } catch (err) {
20981
21918
  if (isFsError(err) && err.kind === "path_not_found") {
20982
- sendParseError(res, ROUTE2, "parent directory does not exist");
20983
- return;
21919
+ await fs9.mkdir(resolvedDir, { recursive: true });
21920
+ dirStat = await fs9.stat(resolvedDir);
21921
+ } else {
21922
+ throw err;
20984
21923
  }
20985
- throw err;
20986
21924
  }
20987
21925
  if (dirStat.kind !== "directory") {
20988
21926
  sendParseError(res, ROUTE2, "parent path is not a directory");
@@ -21380,6 +22318,7 @@ init_esbuild_shims();
21380
22318
 
21381
22319
  // packages/cli/src/serve/server/telemetry.ts
21382
22320
  init_esbuild_shims();
22321
+ import { performance as performance2 } from "node:perf_hooks";
21383
22322
  var legacySessionTelemetryRoutes = [
21384
22323
  {
21385
22324
  method: "POST",
@@ -21519,6 +22458,18 @@ var legacySessionTelemetryRoutes = [
21519
22458
  attribution: "handler_resolved",
21520
22459
  route: "POST /session/:id/tasks/:taskId/cancel"
21521
22460
  },
22461
+ {
22462
+ method: "POST",
22463
+ path: "/session/:id/goal",
22464
+ attribution: "handler_resolved",
22465
+ route: "POST /session/:id/goal"
22466
+ },
22467
+ {
22468
+ method: "GET",
22469
+ path: "/session/:id/goal",
22470
+ attribution: "handler_resolved",
22471
+ route: "GET /session/:id/goal"
22472
+ },
21522
22473
  {
21523
22474
  method: "POST",
21524
22475
  path: "/session/:id/goal/clear",
@@ -21531,6 +22482,24 @@ var legacySessionTelemetryRoutes = [
21531
22482
  attribution: "handler_resolved",
21532
22483
  route: "POST /session/:id/continue"
21533
22484
  },
22485
+ {
22486
+ method: "POST",
22487
+ path: "/session/:id/attachments",
22488
+ attribution: "handler_resolved",
22489
+ route: "POST /session/:id/attachments"
22490
+ },
22491
+ {
22492
+ method: "GET",
22493
+ path: "/session/:id/attachments/:attachmentId",
22494
+ attribution: "handler_resolved",
22495
+ route: "GET /session/:id/attachments/:attachmentId"
22496
+ },
22497
+ {
22498
+ method: "DELETE",
22499
+ path: "/session/:id/attachments/:attachmentId",
22500
+ attribution: "handler_resolved",
22501
+ route: "DELETE /session/:id/attachments/:attachmentId"
22502
+ },
21534
22503
  {
21535
22504
  method: "POST",
21536
22505
  path: "/session/:id/prompt",
@@ -21651,6 +22620,18 @@ var legacySessionTelemetryRoutes = [
21651
22620
  attribution: "handler_resolved",
21652
22621
  route: "DELETE /session/:id/pending-prompts/:promptId"
21653
22622
  },
22623
+ {
22624
+ method: "GET",
22625
+ path: "/session/:id/turns/current",
22626
+ attribution: "handler_resolved",
22627
+ route: "GET /session/:id/turns/current"
22628
+ },
22629
+ {
22630
+ method: "GET",
22631
+ path: "/session/:id/turns/:promptId",
22632
+ attribution: "handler_resolved",
22633
+ route: "GET /session/:id/turns/:promptId"
22634
+ },
21654
22635
  {
21655
22636
  method: "POST",
21656
22637
  path: "/session/:id/shell",
@@ -21706,7 +22687,6 @@ var legacySessionTelemetryRoutes = [
21706
22687
  route: "POST /session/:id/a2ui-action"
21707
22688
  }
21708
22689
  ];
21709
- var daemonTelemetryResponseContext = Symbol("daemonTelemetryResponseContext");
21710
22690
  function decodePathSegment(value) {
21711
22691
  try {
21712
22692
  return decodeURIComponent(value);
@@ -21779,6 +22759,9 @@ function resolveDaemonTelemetryRoute(req) {
21779
22759
  if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions$/.test(path19)) {
21780
22760
  return { route: "GET /workspace/:id/sessions" };
21781
22761
  }
22762
+ if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions\/live-state$/.test(path19)) {
22763
+ return { route: "GET /workspaces/:workspace/sessions/live-state" };
22764
+ }
21782
22765
  if (req.method === "GET" && /^\/workspace\/[^/]+\/session-info$/.test(path19)) {
21783
22766
  return { route: "GET /workspace/:id/session-info" };
21784
22767
  }
@@ -21930,8 +22913,34 @@ function resolveDaemonTelemetryRoute(req) {
21930
22913
  return void 0;
21931
22914
  }
21932
22915
  __name(resolveDaemonTelemetryRoute, "resolveDaemonTelemetryRoute");
22916
+ var TRACEPARENT_BREADCRUMB_BURST = 60;
22917
+ var TRACEPARENT_BREADCRUMB_REFILL_PER_SECOND = 2;
22918
+ function daemonInboundTraceIdCaptureMiddleware(req, res, next) {
22919
+ try {
22920
+ const inboundTraceId = extractInboundTraceId(req.headers);
22921
+ if (inboundTraceId !== void 0) {
22922
+ res[daemonInboundTraceIdContext] = inboundTraceId;
22923
+ }
22924
+ } catch {
22925
+ }
22926
+ next();
22927
+ }
22928
+ __name(daemonInboundTraceIdCaptureMiddleware, "daemonInboundTraceIdCaptureMiddleware");
21933
22929
  function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
21934
22930
  const workspaceHashByCwd = /* @__PURE__ */ new Map();
22931
+ let breadcrumbTokens = TRACEPARENT_BREADCRUMB_BURST;
22932
+ let breadcrumbRefillBaseline = performance2.now();
22933
+ const acquireBreadcrumbToken = /* @__PURE__ */ __name(() => {
22934
+ const now = Math.max(performance2.now(), breadcrumbRefillBaseline);
22935
+ breadcrumbTokens = Math.min(
22936
+ TRACEPARENT_BREADCRUMB_BURST,
22937
+ breadcrumbTokens + (now - breadcrumbRefillBaseline) / 1e3 * TRACEPARENT_BREADCRUMB_REFILL_PER_SECOND
22938
+ );
22939
+ breadcrumbRefillBaseline = now;
22940
+ if (breadcrumbTokens < 1) return false;
22941
+ breadcrumbTokens -= 1;
22942
+ return true;
22943
+ }, "acquireBreadcrumbToken");
21935
22944
  const resolveWorkspaceHash = /* @__PURE__ */ __name((workspaceCwd) => {
21936
22945
  const existing = workspaceHashByCwd.get(workspaceCwd);
21937
22946
  if (existing !== void 0) return existing;
@@ -21960,10 +22969,39 @@ function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
21960
22969
  const clientId = rawClientId !== void 0 && rawClientId !== "" && rawClientId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawClientId) ? rawClientId : void 0;
21961
22970
  const deferredRuntime = getDeferredRuntimeRequestTiming(req);
21962
22971
  const startMs = deferredRuntime?.startedAt.getTime() ?? Date.now();
22972
+ let parentContext;
22973
+ if (isTelemetrySdkInitialized()) {
22974
+ try {
22975
+ parentContext = extractDaemonHttpTraceContext(req.headers);
22976
+ } catch {
22977
+ parentContext = void 0;
22978
+ }
22979
+ try {
22980
+ const inboundTraceparent = req.headers?.["traceparent"];
22981
+ if (!parentContext && typeof inboundTraceparent === "string" && inboundTraceparent.length > 0 && acquireBreadcrumbToken()) {
22982
+ emitDaemonLog(
22983
+ "Rejected invalid inbound traceparent header.",
22984
+ {
22985
+ "http.route": route.route,
22986
+ "http.request.header.traceparent": sanitizeLogText(
22987
+ inboundTraceparent,
22988
+ 128
22989
+ )
22990
+ },
22991
+ {
22992
+ eventName: "qwen-code.daemon.traceparent.invalid",
22993
+ severityNumber: 5
22994
+ // SeverityNumber.DEBUG
22995
+ }
22996
+ );
22997
+ }
22998
+ } catch {
22999
+ }
23000
+ }
21963
23001
  const telemetryRes = res;
21964
23002
  if (route.attribution === "handler_resolved") {
21965
23003
  try {
21966
- telemetryRes[daemonTelemetryResponseContext] = {};
23004
+ telemetryRes[daemonTelemetryResponseContext] ??= {};
21967
23005
  } catch {
21968
23006
  }
21969
23007
  }
@@ -21975,6 +23013,7 @@ function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
21975
23013
  ...sessionId ? { sessionId } : {},
21976
23014
  ...route.permissionRequestId ? { permissionRequestId: route.permissionRequestId } : {},
21977
23015
  ...clientId ? { clientId } : {},
23016
+ ...parentContext ? { parentContext } : {},
21978
23017
  ...deferredRuntime?.waitMs !== void 0 ? {
21979
23018
  startTime: deferredRuntime.startedAt,
21980
23019
  deferredRuntimeWaitMs: deferredRuntime.waitMs,
@@ -22212,6 +23251,7 @@ init_esbuild_shims();
22212
23251
  import * as crypto3 from "node:crypto";
22213
23252
  import * as fs6 from "node:fs";
22214
23253
  import * as path12 from "node:path";
23254
+ var import_express4 = __toESM(require_express(), 1);
22215
23255
 
22216
23256
  // packages/cli/src/serve/server/prompt-deadline.ts
22217
23257
  init_esbuild_shims();
@@ -22409,10 +23449,27 @@ var PersistedSessionListCache = class {
22409
23449
  }
22410
23450
  };
22411
23451
 
23452
+ // packages/cli/src/serve/server/activity-timestamp.ts
23453
+ init_esbuild_shims();
23454
+ function laterActivityTimestamp(live, persisted) {
23455
+ const liveTime = live === void 0 ? Number.NaN : Date.parse(live);
23456
+ const persistedTime = persisted === void 0 ? Number.NaN : Date.parse(persisted);
23457
+ const liveValid = Number.isFinite(liveTime);
23458
+ const persistedValid = Number.isFinite(persistedTime);
23459
+ if (liveValid && persistedValid) {
23460
+ return liveTime >= persistedTime ? live : persisted;
23461
+ }
23462
+ if (liveValid) return live;
23463
+ if (persistedValid) return persisted;
23464
+ return live ?? persisted;
23465
+ }
23466
+ __name(laterActivityTimestamp, "laterActivityTimestamp");
23467
+
22412
23468
  // packages/cli/src/serve/server/session-list.ts
22413
23469
  var DEFAULT_SESSION_PAGE_SIZE = 20;
22414
23470
  var MAX_SESSION_PAGE_SIZE = 100;
22415
23471
  var MAX_ORGANIZED_SESSIONS = 5e4;
23472
+ var MAX_EMITTED_CURSOR_SESSION_IDS = 64;
22416
23473
  var PERSISTED_SESSION_LIST_CACHE_TTL_MS = 2e3;
22417
23474
  var persistedSessionListCache = new PersistedSessionListCache(
22418
23475
  PERSISTED_SESSION_LIST_CACHE_TTL_MS,
@@ -22447,6 +23504,14 @@ function parseSessionCursor(cursor) {
22447
23504
  return parsed;
22448
23505
  }
22449
23506
  __name(parseSessionCursor, "parseSessionCursor");
23507
+ function parseEmittedSessionIds(value) {
23508
+ if (value === void 0) return [];
23509
+ if (!Array.isArray(value) || value.some((id) => typeof id !== "string" || id.length === 0)) {
23510
+ return void 0;
23511
+ }
23512
+ return value;
23513
+ }
23514
+ __name(parseEmittedSessionIds, "parseEmittedSessionIds");
22450
23515
  function parseOrganizedCursor(cursor, expected) {
22451
23516
  if (cursor === "") return void 0;
22452
23517
  try {
@@ -22456,15 +23521,26 @@ function parseOrganizedCursor(cursor, expected) {
22456
23521
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof last !== "object" || last === null || Array.isArray(last) || typeof last.isPinned !== "boolean" || typeof last.activityTime !== "number" || !Number.isFinite(last.activityTime) || typeof last.sessionId !== "string" || last.sessionId.length === 0 || parsed.group !== expected.group || parsed.archiveState !== expected.archiveState || parsed.sourceType !== expected.sourceType || parsed.sourceId !== expected.sourceId) {
22457
23522
  throw new Error("invalid organized cursor");
22458
23523
  }
22459
- return last;
23524
+ const emitted = parseEmittedSessionIds(parsed.emitted);
23525
+ if (emitted === void 0) {
23526
+ throw new Error("invalid organized cursor");
23527
+ }
23528
+ return { last, emitted };
22460
23529
  } catch {
22461
23530
  throw new InvalidCursorError(cursor, "organized");
22462
23531
  }
22463
23532
  }
22464
23533
  __name(parseOrganizedCursor, "parseOrganizedCursor");
22465
- function encodeOrganizedCursor(last, group, archiveState, sourceType, sourceId) {
23534
+ function encodeOrganizedCursor(last, group, archiveState, sourceType, sourceId, emitted = []) {
22466
23535
  return Buffer.from(
22467
- JSON.stringify({ group, archiveState, sourceType, sourceId, last }),
23536
+ JSON.stringify({
23537
+ group,
23538
+ archiveState,
23539
+ sourceType,
23540
+ sourceId,
23541
+ last,
23542
+ ...emitted.length > 0 ? { emitted } : {}
23543
+ }),
22468
23544
  "utf8"
22469
23545
  ).toString("base64url");
22470
23546
  }
@@ -22505,7 +23581,16 @@ function parseMetadataSessionCursor(cursor, expected) {
22505
23581
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof last !== "object" || last === null || Array.isArray(last) || typeof last.activityTime !== "number" || !Number.isFinite(last.activityTime) || typeof last.sessionId !== "string" || last.sessionId.length === 0 || parsed.parentSessionId !== expected.parentSessionId || parsed.sourceType !== expected.sourceType || parsed.sourceId !== expected.sourceId || parsed.archiveState !== expected.archiveState) {
22506
23582
  throw new Error("invalid metadata cursor");
22507
23583
  }
22508
- return { activityTime: last.activityTime, sessionId: last.sessionId };
23584
+ const emitted = parseEmittedSessionIds(
23585
+ parsed.emitted
23586
+ );
23587
+ if (emitted === void 0) {
23588
+ throw new Error("invalid metadata cursor");
23589
+ }
23590
+ return {
23591
+ last: { activityTime: last.activityTime, sessionId: last.sessionId },
23592
+ emitted
23593
+ };
22509
23594
  } catch {
22510
23595
  throw new InvalidCursorError(
22511
23596
  cursor,
@@ -22514,9 +23599,14 @@ function parseMetadataSessionCursor(cursor, expected) {
22514
23599
  }
22515
23600
  }
22516
23601
  __name(parseMetadataSessionCursor, "parseMetadataSessionCursor");
22517
- function encodeMetadataSessionCursor(last, filter, archiveState) {
23602
+ function encodeMetadataSessionCursor(last, filter, archiveState, emitted = []) {
22518
23603
  return Buffer.from(
22519
- JSON.stringify({ ...filter, archiveState, last }),
23604
+ JSON.stringify({
23605
+ ...filter,
23606
+ archiveState,
23607
+ last,
23608
+ ...emitted.length > 0 ? { emitted } : {}
23609
+ }),
22520
23610
  "utf8"
22521
23611
  ).toString("base64url");
22522
23612
  }
@@ -22576,7 +23666,7 @@ function mergeLiveSessionSummary(existing, live) {
22576
23666
  parentSessionId: existing.parentSessionId ?? live.parentSessionId,
22577
23667
  sourceType: existing.sourceType ?? live.sourceType,
22578
23668
  sourceId: existing.sourceType !== void 0 ? existing.sourceId : live.sourceId,
22579
- updatedAt: live.updatedAt ?? existing.updatedAt,
23669
+ updatedAt: laterActivityTimestamp(live.updatedAt, existing.updatedAt),
22580
23670
  clientCount: live.clientCount,
22581
23671
  hasActivePrompt: live.hasActivePrompt,
22582
23672
  isArchived: false
@@ -22726,6 +23816,36 @@ function compareOrganizedCursorKeys(a, b) {
22726
23816
  return a.sessionId.localeCompare(b.sessionId);
22727
23817
  }
22728
23818
  __name(compareOrganizedCursorKeys, "compareOrganizedCursorKeys");
23819
+ function nextEmittedSessionIds(options) {
23820
+ const candidates = new Set(options.carried);
23821
+ for (const row of options.page) {
23822
+ if (options.liveSessionIds.has(row.sessionId)) {
23823
+ candidates.add(row.sessionId);
23824
+ }
23825
+ }
23826
+ const kept = [];
23827
+ for (const sessionId of candidates) {
23828
+ const row = options.listedById.get(sessionId);
23829
+ if (!row) {
23830
+ kept.push({ sessionId, persistedTime: Number.NEGATIVE_INFINITY });
23831
+ continue;
23832
+ }
23833
+ const persistedTime = options.persistedTimeById.get(sessionId);
23834
+ if (persistedTime === void 0) {
23835
+ kept.push({ sessionId, persistedTime: Number.NEGATIVE_INFINITY });
23836
+ continue;
23837
+ }
23838
+ if (options.reenters(row, persistedTime)) {
23839
+ kept.push({ sessionId, persistedTime });
23840
+ }
23841
+ }
23842
+ if (kept.length > MAX_EMITTED_CURSOR_SESSION_IDS) {
23843
+ kept.sort((a, b) => a.persistedTime - b.persistedTime);
23844
+ kept.length = MAX_EMITTED_CURSOR_SESSION_IDS;
23845
+ }
23846
+ return kept.map((entry) => entry.sessionId);
23847
+ }
23848
+ __name(nextEmittedSessionIds, "nextEmittedSessionIds");
22729
23849
  function applyOrganization(session, organization) {
22730
23850
  return {
22731
23851
  ...session,
@@ -22752,12 +23872,14 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
22752
23872
  "group"
22753
23873
  );
22754
23874
  }
22755
- const cursorKey = options.cursor !== void 0 ? parseOrganizedCursor(options.cursor, {
23875
+ const cursor = options.cursor !== void 0 ? parseOrganizedCursor(options.cursor, {
22756
23876
  group,
22757
23877
  archiveState,
22758
23878
  sourceType: options.sourceType,
22759
23879
  sourceId: options.sourceId
22760
23880
  }) : void 0;
23881
+ const cursorKey = cursor?.last;
23882
+ const emittedBeforePage = new Set(cursor?.emitted ?? []);
22761
23883
  const isFirstPage = cursorKey === void 0;
22762
23884
  let liveMergeFailed = false;
22763
23885
  const bySessionId = /* @__PURE__ */ new Map();
@@ -22779,10 +23901,18 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
22779
23901
  )
22780
23902
  );
22781
23903
  }
22782
- if (readOptions.mergeLive !== false && archiveState !== "archived" && isFirstPage) {
23904
+ const persistedTimeById = new Map(
23905
+ persisted.sessions.map((session) => [
23906
+ session.sessionId,
23907
+ getSummaryActivityTime(session)
23908
+ ])
23909
+ );
23910
+ const liveSessionIds = /* @__PURE__ */ new Set();
23911
+ if (readOptions.mergeLive !== false && archiveState !== "archived") {
22783
23912
  try {
22784
23913
  const liveSessions = bridge.listWorkspaceSessions(workspaceCwd);
22785
23914
  for (const live of liveSessions) {
23915
+ liveSessionIds.add(live.sessionId);
22786
23916
  const existing = bySessionId.get(live.sessionId);
22787
23917
  const organization = snapshot.sessions.get(live.sessionId);
22788
23918
  if (existing) {
@@ -22794,7 +23924,9 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
22794
23924
  )
22795
23925
  );
22796
23926
  } else if (
22797
- // `listAllPersistedSummaries` already scanned every persisted
23927
+ // A live-only row has no persisted key to page by, so it stays a
23928
+ // first-page-only insertion as before.
23929
+ isFirstPage && // `listAllPersistedSummaries` already scanned every persisted
22798
23930
  // session when the scan wasn't truncated, so a `sessionId` missing
22799
23931
  // from `bySessionId` is definitively new — no disk re-check
22800
23932
  // needed. Re-checking here raced a session that persists its
@@ -22802,9 +23934,9 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
22802
23934
  // above and this point: `existing` stayed undefined but
22803
23935
  // `sessionExists` flipped to true, silently dropping the live
22804
23936
  // session from the response instead of merging it.
22805
- !persisted.truncated || !await (readOptions.signal ? sessionService.sessionExists(live.sessionId, {
23937
+ (!persisted.truncated || !await (readOptions.signal ? sessionService.sessionExists(live.sessionId, {
22806
23938
  signal: readOptions.signal
22807
- }) : sessionService.sessionExists(live.sessionId))
23939
+ }) : sessionService.sessionExists(live.sessionId)))
22808
23940
  ) {
22809
23941
  bySessionId.set(
22810
23942
  live.sessionId,
@@ -22847,19 +23979,52 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
22847
23979
  filtered.sort((a, b) => compareOrganizedSessions(activityTimeById, a, b));
22848
23980
  readOptions.signal?.throwIfAborted();
22849
23981
  const afterCursor = cursorKey === void 0 ? filtered : filtered.filter(
22850
- (session) => compareOrganizedCursorKeys(
22851
- cursorKey,
22852
- getOrganizedCursorKey(activityTimeById, session)
22853
- ) < 0
23982
+ (session) => (
23983
+ // A row already emitted at a live-derived key stays excluded even
23984
+ // if its key regressed behind the cursor (live retirement, or a
23985
+ // live-only row that persisted mid-pass).
23986
+ !emittedBeforePage.has(session.sessionId) && compareOrganizedCursorKeys(
23987
+ cursorKey,
23988
+ getOrganizedCursorKey(activityTimeById, session)
23989
+ ) < 0
23990
+ )
22854
23991
  );
22855
23992
  const page = afterCursor.slice(0, pageSize);
22856
- const nextCursor = page.length < afterCursor.length ? encodeOrganizedCursor(
22857
- getOrganizedCursorKey(activityTimeById, page[page.length - 1]),
22858
- group,
22859
- archiveState,
22860
- options.sourceType,
22861
- options.sourceId
22862
- ) : void 0;
23993
+ let nextCursor;
23994
+ if (page.length < afterCursor.length) {
23995
+ const boundary = getOrganizedCursorKey(
23996
+ activityTimeById,
23997
+ page[page.length - 1]
23998
+ );
23999
+ const emitted = nextEmittedSessionIds({
24000
+ carried: emittedBeforePage,
24001
+ page,
24002
+ liveSessionIds,
24003
+ listedById: new Map(
24004
+ filtered.map((session) => [session.sessionId, session])
24005
+ ),
24006
+ persistedTimeById,
24007
+ // `isPinned` is re-read from the organization snapshot on every page
24008
+ // request, so a pin flip between fetches can move the persisted key
24009
+ // across the pinned/unpinned blocks. Keep the identity while the key
24010
+ // could re-enter under either state.
24011
+ reenters: /* @__PURE__ */ __name((row, persistedTime) => [true, false].some(
24012
+ (isPinned) => compareOrganizedCursorKeys(boundary, {
24013
+ isPinned,
24014
+ activityTime: persistedTime,
24015
+ sessionId: row.sessionId
24016
+ }) < 0
24017
+ ), "reenters")
24018
+ });
24019
+ nextCursor = encodeOrganizedCursor(
24020
+ boundary,
24021
+ group,
24022
+ archiveState,
24023
+ options.sourceType,
24024
+ options.sourceId,
24025
+ emitted
24026
+ );
24027
+ }
22863
24028
  return {
22864
24029
  sessions: page,
22865
24030
  ...nextCursor !== void 0 ? { nextCursor } : {},
@@ -22884,10 +24049,18 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
22884
24049
  for (const session of persisted.sessions) {
22885
24050
  bySessionId.set(session.sessionId, clonePersistedSummary(session));
22886
24051
  }
24052
+ const persistedTimeById = new Map(
24053
+ persisted.sessions.map((session) => [
24054
+ session.sessionId,
24055
+ getSummaryActivityTime(session)
24056
+ ])
24057
+ );
24058
+ const liveSessionIds = /* @__PURE__ */ new Set();
22887
24059
  let liveMergeFailed = false;
22888
24060
  if (readOptions.mergeLive !== false && archiveState !== "archived") {
22889
24061
  try {
22890
24062
  for (const live of bridge.listWorkspaceSessions(workspaceCwd)) {
24063
+ liveSessionIds.add(live.sessionId);
22891
24064
  const existing = bySessionId.get(live.sessionId);
22892
24065
  if (existing) {
22893
24066
  bySessionId.set(
@@ -22929,22 +24102,46 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
22929
24102
  )
22930
24103
  );
22931
24104
  readOptions.signal?.throwIfAborted();
22932
- const cursorKey = options.cursor !== void 0 && options.cursor !== "" ? parseMetadataSessionCursor(options.cursor, {
24105
+ const cursor = options.cursor !== void 0 && options.cursor !== "" ? parseMetadataSessionCursor(options.cursor, {
22933
24106
  ...filter,
22934
24107
  archiveState
22935
24108
  }) : void 0;
24109
+ const cursorKey = cursor?.last;
24110
+ const emittedBeforePage = new Set(cursor?.emitted ?? []);
22936
24111
  const afterCursor = cursorKey === void 0 ? matches : matches.filter(
22937
- (session) => compareLiveSessionCursorKeys(
22938
- cursorKey,
22939
- getLiveSessionCursorKey(session)
22940
- ) < 0
24112
+ (session) => (
24113
+ // See the organized path: exclude rows already emitted at a
24114
+ // live-derived key whose key regressed behind the cursor.
24115
+ !emittedBeforePage.has(session.sessionId) && compareLiveSessionCursorKeys(
24116
+ cursorKey,
24117
+ getLiveSessionCursorKey(session)
24118
+ ) < 0
24119
+ )
22941
24120
  );
22942
24121
  const page = afterCursor.slice(0, pageSize);
22943
- const nextCursor = page.length < afterCursor.length ? encodeMetadataSessionCursor(
22944
- getLiveSessionCursorKey(page[page.length - 1]),
22945
- filter,
22946
- archiveState
22947
- ) : void 0;
24122
+ let nextCursor;
24123
+ if (page.length < afterCursor.length) {
24124
+ const boundary = getLiveSessionCursorKey(page[page.length - 1]);
24125
+ const emitted = nextEmittedSessionIds({
24126
+ carried: emittedBeforePage,
24127
+ page,
24128
+ liveSessionIds,
24129
+ listedById: new Map(
24130
+ matches.map((session) => [session.sessionId, session])
24131
+ ),
24132
+ persistedTimeById,
24133
+ reenters: /* @__PURE__ */ __name((row, persistedTime) => compareLiveSessionCursorKeys(boundary, {
24134
+ activityTime: persistedTime,
24135
+ sessionId: row.sessionId
24136
+ }) < 0, "reenters")
24137
+ });
24138
+ nextCursor = encodeMetadataSessionCursor(
24139
+ boundary,
24140
+ filter,
24141
+ archiveState,
24142
+ emitted
24143
+ );
24144
+ }
22948
24145
  return {
22949
24146
  sessions: page,
22950
24147
  ...nextCursor !== void 0 ? { nextCursor } : {},
@@ -24036,6 +25233,58 @@ var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 2 * SESSION_TRANSCRIPT_MAX_EXPANDE
24036
25233
  var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
24037
25234
  var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
24038
25235
  var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
25236
+ var MEDIA_CONTENT_MAX_BLOCKS = 256;
25237
+ function isSvgMimeType(mimeType) {
25238
+ return mimeType?.split(";", 1)[0]?.trim().toLowerCase() === "image/svg+xml";
25239
+ }
25240
+ __name(isSvgMimeType, "isSvgMimeType");
25241
+ function parseMediaContentBlock(block) {
25242
+ if (typeof block !== "object" || block === null || Array.isArray(block)) {
25243
+ return { valid: false, code: "not-object" };
25244
+ }
25245
+ const record = block;
25246
+ const type = record["type"];
25247
+ const data = record["data"];
25248
+ const attachmentId = record["attachmentId"];
25249
+ const mimeType = record["mimeType"];
25250
+ const size = record["size"];
25251
+ const inline = typeof data === "string" && data.length > 0;
25252
+ const reference = typeof attachmentId === "string" && attachmentId.length > 0 && typeof size === "number" && Number.isSafeInteger(size) && size >= 0 && (type !== "image" || size > 0);
25253
+ if (type === "resource" && !reference) {
25254
+ const resource = record["resource"];
25255
+ if (typeof resource !== "object" || resource === null) {
25256
+ return { valid: false, code: "invalid-shape" };
25257
+ }
25258
+ const value = resource;
25259
+ const hasText = typeof value["text"] === "string";
25260
+ const hasBlob = typeof value["blob"] === "string";
25261
+ if (typeof value["uri"] !== "string" || value["uri"].length === 0 || hasText === hasBlob) {
25262
+ return { valid: false, code: "invalid-shape" };
25263
+ }
25264
+ return { valid: true, block };
25265
+ }
25266
+ if (type !== "image" && type !== "resource" || (type === "image" ? inline === reference : inline || !reference) || typeof mimeType !== "string" || type === "image" && !mimeType.startsWith("image/")) {
25267
+ return { valid: false, code: "invalid-shape" };
25268
+ }
25269
+ if (type === "image" && isSvgMimeType(mimeType)) {
25270
+ return { valid: false, code: "svg" };
25271
+ }
25272
+ return {
25273
+ valid: true,
25274
+ block: inline ? { type, data, mimeType } : { type, attachmentId, mimeType, size }
25275
+ };
25276
+ }
25277
+ __name(parseMediaContentBlock, "parseMediaContentBlock");
25278
+ function mediaBlockParseError(code, entryLabel) {
25279
+ if (code === "not-object") {
25280
+ return `each ${entryLabel} must be a media content block`;
25281
+ }
25282
+ if (code === "svg") {
25283
+ return "SVG images are not supported";
25284
+ }
25285
+ return `each ${entryLabel} must be an inline content block or carry \`attachmentId\`, \`size\`, and \`mimeType\``;
25286
+ }
25287
+ __name(mediaBlockParseError, "mediaBlockParseError");
24039
25288
  var PRIMARY_ONLY_LIVE_SESSION_ROUTES = ["POST /session/:id/cd"];
24040
25289
  var PRIMARY_OR_INTERNAL_LIVE_SESSION_ROUTES = [
24041
25290
  "POST /session/:id/branch",
@@ -24243,11 +25492,15 @@ function registerSessionRoutes(app, deps) {
24243
25492
  archiveStates
24244
25493
  });
24245
25494
  }, "invalidateSessionLists");
25495
+ const invalidateSessionListsAndMarkCatalog = /* @__PURE__ */ __name((runtime, archiveStates) => {
25496
+ invalidateSessionLists(runtime, archiveStates);
25497
+ runtime.bridge.markSessionCatalogChanged();
25498
+ }, "invalidateSessionListsAndMarkCatalog");
24246
25499
  const runWithSessionListInvalidation = /* @__PURE__ */ __name(async (runtime, archiveStates, mutation) => {
24247
25500
  try {
24248
25501
  return await mutation();
24249
25502
  } finally {
24250
- invalidateSessionLists(runtime, archiveStates);
25503
+ invalidateSessionListsAndMarkCatalog(runtime, archiveStates);
24251
25504
  }
24252
25505
  }, "runWithSessionListInvalidation");
24253
25506
  const requestedSessionIdAdmission = deps.requestedSessionIdAdmission ?? createRequestedSessionIdAdmission({
@@ -24617,7 +25870,7 @@ function registerSessionRoutes(app, deps) {
24617
25870
  }
24618
25871
  const metadata = await readLoadableLiveConversationMetadata(
24619
25872
  sessionId,
24620
- (candidateId) => service.readCreationMetadata(candidateId)
25873
+ service
24621
25874
  );
24622
25875
  if (!metadata) throw new SessionNotFoundError(sessionId);
24623
25876
  }
@@ -24941,10 +26194,7 @@ function registerSessionRoutes(app, deps) {
24941
26194
  if (location !== "active") return false;
24942
26195
  if (!isInternalWorkspaceRuntime(runtime)) return true;
24943
26196
  const service = createWorkspaceRuntimeSessionService(runtime);
24944
- return await readLoadableLiveConversationMetadata(
24945
- sessionId,
24946
- (candidateId) => service.readCreationMetadata(candidateId)
24947
- ) !== void 0;
26197
+ return await readLoadableLiveConversationMetadata(sessionId, service) !== void 0;
24948
26198
  }, "activeInRuntime");
24949
26199
  const throwMissingActiveTranscript = /* @__PURE__ */ __name(() => {
24950
26200
  if (hasCursor) {
@@ -25140,7 +26390,7 @@ function registerSessionRoutes(app, deps) {
25140
26390
  if (!exists) continue;
25141
26391
  const metadata = await readLoadableLiveConversationMetadata(
25142
26392
  sessionId,
25143
- (candidateId) => service.readCreationMetadata(candidateId)
26393
+ service
25144
26394
  );
25145
26395
  if (!assertCurrentInternalGeneration(entry, generation, res)) {
25146
26396
  return void 0;
@@ -25227,7 +26477,7 @@ function registerSessionRoutes(app, deps) {
25227
26477
  if (!exists) continue;
25228
26478
  const metadata = await readLoadableLiveConversationMetadata(
25229
26479
  sessionId,
25230
- (candidateId) => service.readCreationMetadata(candidateId)
26480
+ service
25231
26481
  );
25232
26482
  if (!assertCurrentInternalGeneration(entry, generation2, res)) {
25233
26483
  return void 0;
@@ -25281,7 +26531,7 @@ function registerSessionRoutes(app, deps) {
25281
26531
  }
25282
26532
  const metadata = await readLoadableLiveConversationMetadata(
25283
26533
  sessionId,
25284
- (candidateId) => service.readCreationMetadata(candidateId)
26534
+ service
25285
26535
  );
25286
26536
  if (!metadata) {
25287
26537
  throw new SessionNotFoundError(sessionId);
@@ -25481,6 +26731,15 @@ function registerSessionRoutes(app, deps) {
25481
26731
  }
25482
26732
  const approvalMode = parseOptionalApprovalMode(body, res);
25483
26733
  if (approvalMode === null) return;
26734
+ if (isReservedStandaloneSessionSource({
26735
+ sourceType: typeof body["sourceType"] === "string" ? body["sourceType"] : void 0
26736
+ })) {
26737
+ res.status(400).json({
26738
+ error: "The requested session source is reserved for daemon-owned standalone sessions.",
26739
+ code: "reserved_session_source"
26740
+ });
26741
+ return;
26742
+ }
25484
26743
  const source = parseSessionSource(body["sourceType"], body["sourceId"]);
25485
26744
  if ("error" in source) {
25486
26745
  res.status(400).json({
@@ -26051,24 +27310,54 @@ function registerSessionRoutes(app, deps) {
26051
27310
  throw error2;
26052
27311
  }
26053
27312
  }
27313
+ let restoredStorageSessionId = sessionId;
26054
27314
  try {
27315
+ const guardSessionService = createWorkspaceRuntimeSessionService(runtime);
27316
+ try {
27317
+ await guardSessionService.findSessionIdIgnoringCase(sessionId);
27318
+ } catch (error2) {
27319
+ if (error2 instanceof SessionIdCaseConflictError && await guardSessionService.getSessionLocation(
27320
+ error2.candidateSessionId ?? sessionId
27321
+ ) === "conflict") {
27322
+ throw new SessionConflictError(sessionId);
27323
+ }
27324
+ throw error2;
27325
+ }
26055
27326
  const session = await archiveCoordinator.runSharedMany(
26056
27327
  [sessionId],
26057
27328
  async () => {
27329
+ const sessionService = createWorkspaceRuntimeSessionService(runtime);
27330
+ let persistedSessionId;
27331
+ try {
27332
+ persistedSessionId = await sessionService.findSessionIdIgnoringCase(sessionId);
27333
+ } catch (error2) {
27334
+ if (error2 instanceof SessionIdCaseConflictError && await sessionService.getSessionLocation(
27335
+ error2.candidateSessionId ?? sessionId
27336
+ ) === "conflict") {
27337
+ throw new SessionConflictError(sessionId);
27338
+ }
27339
+ throw error2;
27340
+ }
27341
+ if (persistedSessionId) {
27342
+ restoredStorageSessionId = persistedSessionId;
27343
+ } else if (isInternalWorkspaceRuntime(runtime)) {
27344
+ throw new SessionNotFoundError(sessionId);
27345
+ }
26058
27346
  const location = await assertSessionLoadable(
26059
27347
  workspaceCwd,
26060
- sessionId,
27348
+ restoredStorageSessionId,
26061
27349
  runtime.sessionRuntimeBaseDir
26062
27350
  );
26063
27351
  if (location === void 0 && isInternalWorkspaceRuntime(runtime)) {
26064
27352
  throw new SessionNotFoundError(sessionId);
26065
27353
  }
26066
- const sessionService = createWorkspaceRuntimeSessionService(runtime);
26067
27354
  const metadata = runtime.provenance === "live-conversation" ? await readLoadableLiveConversationMetadata(
26068
- sessionId,
26069
- (candidateId) => sessionService.readCreationMetadata(candidateId)
26070
- ) : await sessionService.readCreationMetadata(sessionId);
26071
- if (metadata === void 0) {
27355
+ restoredStorageSessionId,
27356
+ sessionService
27357
+ ) : await sessionService.readCreationMetadata(
27358
+ restoredStorageSessionId
27359
+ );
27360
+ if (metadata === void 0 || isInternalWorkspaceRuntime(runtime) && isReservedStandaloneSessionSource(metadata)) {
26072
27361
  throw new SessionNotFoundError(sessionId);
26073
27362
  }
26074
27363
  assertRuntimeGenerationOpen?.();
@@ -26160,7 +27449,19 @@ function registerSessionRoutes(app, deps) {
26160
27449
  throw error2;
26161
27450
  }
26162
27451
  }
26163
- return restored;
27452
+ if (action === "load" && !restored.attached && !restored.hasActivePrompt && runtime.provenance !== "live-conversation") {
27453
+ try {
27454
+ await reconcileDanglingPromptTerminals(
27455
+ sessionService,
27456
+ sessionId
27457
+ );
27458
+ } catch {
27459
+ }
27460
+ }
27461
+ return withPromptTerminals(
27462
+ restored,
27463
+ action === "load" ? readRecentPromptTerminals(sessionService, sessionId) : void 0
27464
+ );
26164
27465
  }
26165
27466
  );
26166
27467
  try {
@@ -26195,7 +27496,7 @@ function registerSessionRoutes(app, deps) {
26195
27496
  const sidecar = await readWorktreeSession(
26196
27497
  createWorkspaceRuntimeSessionService(
26197
27498
  runtime
26198
- ).getWorktreeSessionPath(sessionId)
27499
+ ).getWorktreeSessionPath(restoredStorageSessionId)
26199
27500
  ).catch(() => null);
26200
27501
  if (sidecar) {
26201
27502
  let realTarget;
@@ -26459,8 +27760,10 @@ function registerSessionRoutes(app, deps) {
26459
27760
  if (!result.attached) {
26460
27761
  const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
26461
27762
  if (killed) {
26462
- await createWorkspaceRuntimeSessionService(runtime).removeSession(result.sessionId).catch(() => {
26463
- });
27763
+ const removed = await createWorkspaceRuntimeSessionService(
27764
+ runtime
27765
+ ).removeSession(result.sessionId).catch(() => false);
27766
+ if (removed) runtime.bridge.markSessionCatalogChanged();
26464
27767
  }
26465
27768
  } else {
26466
27769
  await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
@@ -26470,11 +27773,12 @@ function registerSessionRoutes(app, deps) {
26470
27773
  }
26471
27774
  if (!res.writable) {
26472
27775
  if (!result.attached) {
26473
- runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
26474
- if (!killed) return void 0;
26475
- return createWorkspaceRuntimeSessionService(
27776
+ runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then(async (killed) => {
27777
+ if (!killed) return;
27778
+ const removed = await createWorkspaceRuntimeSessionService(
26476
27779
  runtime
26477
27780
  ).removeSession(result.sessionId);
27781
+ if (removed) runtime.bridge.markSessionCatalogChanged();
26478
27782
  }).catch(() => {
26479
27783
  });
26480
27784
  } else {
@@ -27027,6 +28331,42 @@ function registerSessionRoutes(app, deps) {
27027
28331
  }
27028
28332
  )
27029
28333
  );
28334
+ app.post(
28335
+ "/session/:id/goal",
28336
+ mutate({ strict: true }),
28337
+ withOwnerMutableSession(
28338
+ "POST /session/:id/goal",
28339
+ async (req, res, sessionId, runtime) => {
28340
+ const request2 = parseGoalControlRequest(safeBody(req));
28341
+ if (!request2) {
28342
+ res.status(400).json({
28343
+ error: "Invalid Goal control request",
28344
+ code: "invalid_goal_control_request"
28345
+ });
28346
+ return;
28347
+ }
28348
+ const clientId = parseClientIdHeader(req, res);
28349
+ if (clientId === null) return;
28350
+ res.status(200).json(
28351
+ await runtime.bridge.controlSessionGoal(
28352
+ sessionId,
28353
+ request2,
28354
+ clientId === void 0 ? void 0 : { clientId }
28355
+ )
28356
+ );
28357
+ }
28358
+ )
28359
+ );
28360
+ app.get(
28361
+ "/session/:id/goal",
28362
+ withOwnerReadSession(
28363
+ "GET /session/:id/goal",
28364
+ async (_req, res, sessionId, runtime) => {
28365
+ const goal = await runtime.bridge.getSessionGoal(sessionId);
28366
+ res.status(200).json({ snapshot: goal.snapshot });
28367
+ }
28368
+ )
28369
+ );
27030
28370
  app.post(
27031
28371
  "/session/:id/goal/clear",
27032
28372
  mutate({ strict: true }),
@@ -27061,6 +28401,115 @@ function registerSessionRoutes(app, deps) {
27061
28401
  }
27062
28402
  )
27063
28403
  );
28404
+ app.post(
28405
+ "/session/:id/attachments",
28406
+ mutate(),
28407
+ import_express4.default.raw({ type: "*/*", limit: "8mb" }),
28408
+ (error2, _req, res, next) => {
28409
+ if (error2 && typeof error2 === "object" && "status" in error2 && error2.status === 413) {
28410
+ res.status(413).json({ error: "Request body too large (max 8 MiB)" });
28411
+ return;
28412
+ }
28413
+ next(error2);
28414
+ },
28415
+ withOwnerMutableSession(
28416
+ "POST /session/:id/attachments",
28417
+ async (req, res, sessionId, runtime) => {
28418
+ const name = req.query["name"];
28419
+ const contentType = req.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
28420
+ if (typeof name !== "string" || !contentType || !Buffer.isBuffer(req.body)) {
28421
+ res.status(400).json({
28422
+ error: "request body, Content-Type, and name query parameter are required"
28423
+ });
28424
+ return;
28425
+ }
28426
+ const clientId = parseClientIdHeader(req, res);
28427
+ if (clientId === null) return;
28428
+ if (req.body.length === 0 && [
28429
+ "image/bmp",
28430
+ "image/gif",
28431
+ "image/jpeg",
28432
+ "image/png",
28433
+ "image/webp"
28434
+ ].includes(contentType)) {
28435
+ res.status(400).json({ error: "Image attachments cannot be empty" });
28436
+ return;
28437
+ }
28438
+ try {
28439
+ const reference = await runtime.bridge.storeSessionAttachment(
28440
+ sessionId,
28441
+ req.body,
28442
+ contentType,
28443
+ clientId !== void 0 ? { clientId } : void 0,
28444
+ name
28445
+ );
28446
+ res.status(201).json(reference);
28447
+ } catch (error2) {
28448
+ if (error2 instanceof RangeError) {
28449
+ res.status(413).json({ error: error2.message });
28450
+ return;
28451
+ }
28452
+ if (error2 instanceof TypeError) {
28453
+ res.status(400).json({ error: error2.message });
28454
+ return;
28455
+ }
28456
+ throw error2;
28457
+ }
28458
+ }
28459
+ )
28460
+ );
28461
+ app.get(
28462
+ "/session/:id/attachments/:attachmentId",
28463
+ withOwnerReadSession(
28464
+ "GET /session/:id/attachments/:attachmentId",
28465
+ async (req, res, sessionId, runtime) => {
28466
+ const attachmentId = req.params["attachmentId"];
28467
+ if (!attachmentId) {
28468
+ res.status(400).json({ error: "`attachmentId` is required" });
28469
+ return;
28470
+ }
28471
+ const clientId = parseClientIdHeader(req, res);
28472
+ if (clientId === null) return;
28473
+ const attachment = await runtime.bridge.readSessionAttachment(
28474
+ sessionId,
28475
+ attachmentId,
28476
+ clientId !== void 0 ? { clientId } : void 0
28477
+ );
28478
+ if (!attachment) {
28479
+ res.status(404).json({ error: "session attachment not found" });
28480
+ return;
28481
+ }
28482
+ res.setHeader("Content-Type", attachment.mimeType);
28483
+ res.setHeader("Content-Length", String(attachment.data.byteLength));
28484
+ res.setHeader("Cache-Control", "private, max-age=300");
28485
+ res.setHeader("Content-Disposition", "attachment");
28486
+ res.setHeader("X-Content-Type-Options", "nosniff");
28487
+ res.status(200).send(attachment.data);
28488
+ }
28489
+ )
28490
+ );
28491
+ app.delete(
28492
+ "/session/:id/attachments/:attachmentId",
28493
+ mutate(),
28494
+ withOwnerMutableSession(
28495
+ "DELETE /session/:id/attachments/:attachmentId",
28496
+ async (req, res, sessionId, runtime) => {
28497
+ const attachmentId = req.params["attachmentId"];
28498
+ if (!attachmentId) {
28499
+ res.status(400).json({ error: "`attachmentId` is required" });
28500
+ return;
28501
+ }
28502
+ const clientId = parseClientIdHeader(req, res);
28503
+ if (clientId === null) return;
28504
+ const removed = await runtime.bridge.removeSessionAttachment(
28505
+ sessionId,
28506
+ attachmentId,
28507
+ clientId !== void 0 ? { clientId } : void 0
28508
+ );
28509
+ res.status(200).json({ removed });
28510
+ }
28511
+ )
28512
+ );
27064
28513
  app.post(
27065
28514
  "/session/:id/prompt",
27066
28515
  mutate(),
@@ -27084,6 +28533,25 @@ function registerSessionRoutes(app, deps) {
27084
28533
  });
27085
28534
  return;
27086
28535
  }
28536
+ const mediaBlockCount = prompt.filter(
28537
+ (item) => item["type"] !== "text"
28538
+ ).length;
28539
+ if (mediaBlockCount > MEDIA_CONTENT_MAX_BLOCKS) {
28540
+ res.status(400).json({
28541
+ error: `\`prompt\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
28542
+ });
28543
+ return;
28544
+ }
28545
+ for (const item of prompt) {
28546
+ if (item["type"] !== "image") continue;
28547
+ const parsed = parseMediaContentBlock(item);
28548
+ if (!parsed.valid) {
28549
+ res.status(400).json({
28550
+ error: mediaBlockParseError(parsed.code, "`prompt` image block")
28551
+ });
28552
+ return;
28553
+ }
28554
+ }
27087
28555
  const rawRequestDeadline = body["deadlineMs"];
27088
28556
  let requestDeadlineMs;
27089
28557
  if (rawRequestDeadline !== void 0 && rawRequestDeadline !== null) {
@@ -27638,6 +29106,113 @@ function registerSessionRoutes(app, deps) {
27638
29106
  }
27639
29107
  )
27640
29108
  );
29109
+ app.patch(
29110
+ "/workspaces/:workspace/session/:id/metadata",
29111
+ mutate({ strict: true }),
29112
+ async (req, res) => {
29113
+ const route = "PATCH /workspaces/:workspace/session/:id/metadata";
29114
+ const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
29115
+ if (!runtime) return;
29116
+ const sessionId = requireSessionId(req, res);
29117
+ if (sessionId === null) return;
29118
+ const clientId = parseClientIdHeader(req, res);
29119
+ if (clientId === null) return;
29120
+ const rawDisplayName = safeBody(req)["displayName"];
29121
+ if (typeof rawDisplayName !== "string") {
29122
+ res.status(400).json({
29123
+ error: "`displayName` must be a string",
29124
+ code: "invalid_metadata",
29125
+ field: "displayName"
29126
+ });
29127
+ return;
29128
+ }
29129
+ try {
29130
+ const displayName = rawDisplayName.slice(0, 256);
29131
+ if (displayName.trim() === "") {
29132
+ throw new InvalidSessionMetadataError(
29133
+ "displayName",
29134
+ "must not be empty"
29135
+ );
29136
+ }
29137
+ if (Array.from(displayName).some((character) => {
29138
+ const code = character.charCodeAt(0);
29139
+ return code <= 31 || code === 127;
29140
+ })) {
29141
+ throw new InvalidSessionMetadataError(
29142
+ "displayName",
29143
+ "must not contain control characters"
29144
+ );
29145
+ }
29146
+ await archiveCoordinator.runExclusiveMany([sessionId], async () => {
29147
+ const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
29148
+ assertRuntimeGenerationOpen?.();
29149
+ const liveOwner = workspaceRegistry.resolveLiveSessionOwner(sessionId);
29150
+ if (liveOwner.kind === "unavailable") {
29151
+ sendWorkspaceRuntimeUnavailable(res);
29152
+ return;
29153
+ }
29154
+ if (liveOwner.kind === "ambiguous") {
29155
+ sendAmbiguousSessionOwner(
29156
+ res,
29157
+ route,
29158
+ sessionId,
29159
+ liveOwner.runtimes
29160
+ );
29161
+ return;
29162
+ }
29163
+ if (liveOwner.kind === "found" && liveOwner.runtime.workspaceCwd !== runtime.workspaceCwd) {
29164
+ sendSessionWorkspaceConflict(
29165
+ res,
29166
+ route,
29167
+ sessionId,
29168
+ runtime,
29169
+ liveOwner.runtime
29170
+ );
29171
+ return;
29172
+ }
29173
+ await runWithWorkspaceRuntimeStorage(runtime, async () => {
29174
+ let effective;
29175
+ try {
29176
+ effective = runtime.bridge.updateSessionMetadata(
29177
+ sessionId,
29178
+ { displayName },
29179
+ clientId !== void 0 ? { clientId } : void 0
29180
+ );
29181
+ assertRuntimeGenerationOpen?.();
29182
+ } catch (err) {
29183
+ if (!(err instanceof SessionNotFoundError)) throw err;
29184
+ const service = createWorkspaceRuntimeSessionService(runtime);
29185
+ const location = await service.getSessionLocation(sessionId);
29186
+ assertRuntimeGenerationOpen?.();
29187
+ if (location === "conflict") {
29188
+ throw new SessionConflictError(sessionId);
29189
+ }
29190
+ const renamed = location ? await service.renameSession(
29191
+ sessionId,
29192
+ displayName,
29193
+ "manual",
29194
+ location
29195
+ ) : false;
29196
+ assertRuntimeGenerationOpen?.();
29197
+ if (!renamed) {
29198
+ throw new SessionNotFoundError(sessionId);
29199
+ }
29200
+ runtime.bridge.markSessionCatalogChanged();
29201
+ effective = { displayName: displayName || void 0 };
29202
+ }
29203
+ invalidateSessionLists(runtime, ["active", "archived"]);
29204
+ res.status(200).json({ sessionId, ...effective });
29205
+ });
29206
+ });
29207
+ } catch (err) {
29208
+ sendBridgeError2(res, err, {
29209
+ route,
29210
+ sessionId,
29211
+ workspaceCwd: runtime.workspaceCwd
29212
+ });
29213
+ }
29214
+ }
29215
+ );
27641
29216
  const handleSessionOrganizationUpdate = /* @__PURE__ */ __name(async (req, res, target) => {
27642
29217
  const sessionId = requireSessionId(req, res);
27643
29218
  if (sessionId === null) return;
@@ -27705,6 +29280,10 @@ function registerSessionRoutes(app, deps) {
27705
29280
  ...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
27706
29281
  ...rawColor !== void 0 ? { color: rawColor } : {}
27707
29282
  });
29283
+ invalidateSessionListsAndMarkCatalog(runtime, [
29284
+ "active",
29285
+ "archived"
29286
+ ]);
27708
29287
  res.status(200).json({ sessionId, ...organization });
27709
29288
  });
27710
29289
  })()
@@ -27767,6 +29346,7 @@ function registerSessionRoutes(app, deps) {
27767
29346
  color: body["color"]
27768
29347
  })
27769
29348
  );
29349
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27770
29350
  res.status(201).json({ group });
27771
29351
  } catch (err) {
27772
29352
  if (sendSessionOrganizationError(res, err)) return;
@@ -27794,6 +29374,7 @@ function registerSessionRoutes(app, deps) {
27794
29374
  }
27795
29375
  )
27796
29376
  );
29377
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27797
29378
  res.status(200).json({ group });
27798
29379
  } catch (err) {
27799
29380
  if (sendSessionOrganizationError(res, err)) return;
@@ -27816,6 +29397,9 @@ function registerSessionRoutes(app, deps) {
27816
29397
  req.params["groupId"] ?? ""
27817
29398
  )
27818
29399
  );
29400
+ if (deleted) {
29401
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
29402
+ }
27819
29403
  res.status(200).json({ deleted });
27820
29404
  } catch (err) {
27821
29405
  if (sendSessionOrganizationError(res, err)) return;
@@ -27856,6 +29440,7 @@ function registerSessionRoutes(app, deps) {
27856
29440
  color: body["color"]
27857
29441
  })
27858
29442
  );
29443
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27859
29444
  res.status(201).json({ group });
27860
29445
  } catch (err) {
27861
29446
  if (sendSessionOrganizationError(res, err)) return;
@@ -27883,6 +29468,7 @@ function registerSessionRoutes(app, deps) {
27883
29468
  }
27884
29469
  )
27885
29470
  );
29471
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
27886
29472
  res.status(200).json({ group });
27887
29473
  } catch (err) {
27888
29474
  if (sendSessionOrganizationError(res, err)) return;
@@ -27904,6 +29490,9 @@ function registerSessionRoutes(app, deps) {
27904
29490
  req.params["groupId"] ?? ""
27905
29491
  )
27906
29492
  );
29493
+ if (deleted) {
29494
+ invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
29495
+ }
27907
29496
  res.status(200).json({ deleted });
27908
29497
  } catch (err) {
27909
29498
  if (sendSessionOrganizationError(res, err)) return;
@@ -28089,6 +29678,39 @@ function registerSessionRoutes(app, deps) {
28089
29678
  "/workspaces/:workspace/sessions",
28090
29679
  listWorkspaceSessionsHandler("workspace")
28091
29680
  );
29681
+ const lastExposedCatalogVersions = /* @__PURE__ */ new WeakMap();
29682
+ app.get("/workspaces/:workspace/sessions/live-state", async (req, res) => {
29683
+ const route = "GET /workspaces/:workspace/sessions/live-state";
29684
+ const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
29685
+ if (runtime === null) return;
29686
+ const assertRuntimeOpen = captureRuntimeGenerationAssertion(runtime);
29687
+ const bridge = runtime.bridge;
29688
+ try {
29689
+ assertRuntimeOpen?.();
29690
+ const catalogVersion = bridge.getSessionCatalogVersion();
29691
+ const lastExposed = lastExposedCatalogVersions.get(bridge);
29692
+ if (lastExposed === void 0 || lastExposed.generation !== catalogVersion.generation || lastExposed.revision !== catalogVersion.revision) {
29693
+ invalidateSessionLists(runtime, ["active", "archived"]);
29694
+ }
29695
+ const sessions = bridge.listWorkspaceSessions(runtime.workspaceCwd).map((session) => ({
29696
+ sessionId: session.sessionId,
29697
+ clientCount: session.clientCount,
29698
+ hasActivePrompt: session.hasActivePrompt,
29699
+ isWaitingForPermission: session.isWaitingForPermission ?? false,
29700
+ isWaitingForUserQuestion: session.isWaitingForUserQuestion ?? false,
29701
+ // Bridge-local activity watermark, absent until a running prompt in
29702
+ // this bridge publishes its first terminal. Reading it costs nothing
29703
+ // extra: the summary is already in memory.
29704
+ ...session.updatedAt !== void 0 ? { updatedAt: session.updatedAt } : {}
29705
+ }));
29706
+ assertRuntimeOpen?.();
29707
+ lastExposedCatalogVersions.set(bridge, catalogVersion);
29708
+ res.setHeader("Cache-Control", "no-store");
29709
+ res.status(200).json({ v: 1, catalogVersion, sessions });
29710
+ } catch (err) {
29711
+ sendBridgeError2(res, err, { route });
29712
+ }
29713
+ });
28092
29714
  const workspaceSessionInfoHandler = /* @__PURE__ */ __name((paramName) => async (req, res) => {
28093
29715
  const route = paramName === "workspace" ? "GET /workspaces/:workspace/session-info" : "GET /workspace/:id/session-info";
28094
29716
  const runtime = resolveRuntimeForCatalogRoute(req, res, paramName, route);
@@ -28257,9 +29879,36 @@ function registerSessionRoutes(app, deps) {
28257
29879
  const message = body["message"];
28258
29880
  const messageId = body["messageId"];
28259
29881
  const trimmed = typeof message === "string" ? message.trim() : "";
28260
- if (trimmed.length === 0) {
29882
+ const rawContent = body["content"];
29883
+ let mediaBlocks;
29884
+ if (rawContent !== void 0) {
29885
+ if (!Array.isArray(rawContent) || rawContent.length === 0) {
29886
+ res.status(400).json({
29887
+ error: "`content` must be a non-empty array of media blocks"
29888
+ });
29889
+ return;
29890
+ }
29891
+ if (rawContent.length > MEDIA_CONTENT_MAX_BLOCKS) {
29892
+ res.status(400).json({
29893
+ error: `\`content\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
29894
+ });
29895
+ return;
29896
+ }
29897
+ mediaBlocks = [];
29898
+ for (const block of rawContent) {
29899
+ const parsed = parseMediaContentBlock(block);
29900
+ if (!parsed.valid) {
29901
+ res.status(400).json({
29902
+ error: mediaBlockParseError(parsed.code, "`content` entry")
29903
+ });
29904
+ return;
29905
+ }
29906
+ mediaBlocks.push(parsed.block);
29907
+ }
29908
+ }
29909
+ if (trimmed.length === 0 && mediaBlocks === void 0) {
28261
29910
  res.status(400).json({
28262
- error: "`message` is required and must be a non-empty string"
29911
+ error: "`message` must be a non-empty string, or `content` must carry at least one media block"
28263
29912
  });
28264
29913
  return;
28265
29914
  }
@@ -28281,7 +29930,11 @@ function registerSessionRoutes(app, deps) {
28281
29930
  sessionId,
28282
29931
  trimmed,
28283
29932
  clientId !== void 0 ? { clientId } : void 0,
28284
- typeof messageId === "string" ? messageId : void 0
29933
+ typeof messageId === "string" ? messageId : void 0,
29934
+ {
29935
+ rejectIfIdle: true,
29936
+ ...mediaBlocks ? { content: mediaBlocks } : {}
29937
+ }
28285
29938
  );
28286
29939
  res.status(200).json(result);
28287
29940
  }
@@ -28373,6 +30026,73 @@ function registerSessionRoutes(app, deps) {
28373
30026
  }
28374
30027
  )
28375
30028
  );
30029
+ app.get("/session/:id/turns/current", (req, res) => {
30030
+ const sessionId = requireSessionId(req, res);
30031
+ if (sessionId === null) return;
30032
+ const runtime = resolveLiveSessionRuntime(
30033
+ sessionId,
30034
+ res,
30035
+ "GET /session/:id/turns/current"
30036
+ );
30037
+ if (!runtime) return;
30038
+ const clientId = parseClientIdHeader(req, res);
30039
+ if (clientId === null) return;
30040
+ void (async () => {
30041
+ try {
30042
+ const status = await runtime.bridge.getSessionTurnStatus(
30043
+ sessionId,
30044
+ clientId !== void 0 ? { clientId } : void 0
30045
+ );
30046
+ res.status(200).json(status);
30047
+ } catch (err) {
30048
+ sendBridgeError2(res, err, {
30049
+ route: "GET /session/:id/turns/current",
30050
+ sessionId
30051
+ });
30052
+ }
30053
+ })();
30054
+ });
30055
+ app.get("/session/:id/turns/:promptId", (req, res) => {
30056
+ const sessionId = requireSessionId(req, res);
30057
+ if (sessionId === null) return;
30058
+ const runtime = resolveLiveSessionRuntime(
30059
+ sessionId,
30060
+ res,
30061
+ "GET /session/:id/turns/:promptId"
30062
+ );
30063
+ if (!runtime) return;
30064
+ const promptId = req.params["promptId"];
30065
+ if (!promptId) {
30066
+ res.status(400).json({ error: "`promptId` route parameter is required" });
30067
+ return;
30068
+ }
30069
+ const clientId = parseClientIdHeader(req, res);
30070
+ if (clientId === null) return;
30071
+ void (async () => {
30072
+ try {
30073
+ const status = await runtime.bridge.getSessionTurnStatus(
30074
+ sessionId,
30075
+ clientId !== void 0 ? { clientId } : void 0,
30076
+ promptId
30077
+ );
30078
+ if (!status) {
30079
+ res.status(404).json({
30080
+ error: `Prompt ${promptId} not found in session ${sessionId}`,
30081
+ code: "prompt_not_found",
30082
+ sessionId,
30083
+ promptId
30084
+ });
30085
+ return;
30086
+ }
30087
+ res.status(200).json(status);
30088
+ } catch (err) {
30089
+ sendBridgeError2(res, err, {
30090
+ route: "GET /session/:id/turns/:promptId",
30091
+ sessionId
30092
+ });
30093
+ }
30094
+ })();
30095
+ });
28376
30096
  app.post(
28377
30097
  "/session/:id/shell",
28378
30098
  mutate({ strict: true }),
@@ -28634,10 +30354,10 @@ async function teardownBoundSession(target, sessionId) {
28634
30354
  } else if (target.bridge) {
28635
30355
  await target.bridge.closeSession(sessionId).catch(() => {
28636
30356
  });
28637
- await new SessionService(target.workspaceCwd, {
30357
+ const removed = await new SessionService(target.workspaceCwd, {
28638
30358
  runtimeBaseDir: target.runtimeBaseDir
28639
- }).removeSession(sessionId).catch(() => {
28640
- });
30359
+ }).removeSession(sessionId).catch(() => false);
30360
+ if (removed) target.bridge.markSessionCatalogChanged?.();
28641
30361
  }
28642
30362
  }
28643
30363
  __name(teardownBoundSession, "teardownBoundSession");
@@ -29523,7 +31243,7 @@ __name(parseNameField, "parseNameField");
29523
31243
 
29524
31244
  // packages/cli/src/serve/routes/channel-notify.ts
29525
31245
  init_esbuild_shims();
29526
- import { randomUUID as randomUUID6 } from "node:crypto";
31246
+ import { randomUUID as randomUUID7 } from "node:crypto";
29527
31247
  function sendDeliveryError(res, error2) {
29528
31248
  if (!isChannelDeliveryError(error2)) {
29529
31249
  res.status(502).json({
@@ -29544,7 +31264,7 @@ function parseNotifyBody(body) {
29544
31264
  );
29545
31265
  }
29546
31266
  return normalizeChannelDelivery(
29547
- randomUUID6(),
31267
+ randomUUID7(),
29548
31268
  parseChannelDelivery(body["delivery"]),
29549
31269
  body["text"]
29550
31270
  );
@@ -29649,15 +31369,17 @@ function registerGoalsRoutes(app, deps) {
29649
31369
  continue;
29650
31370
  }
29651
31371
  const { session, goal } = outcome.value;
29652
- if (!goal.active) continue;
31372
+ const record = goal.snapshot.goal;
31373
+ if (!record || record.status === "complete") continue;
29653
31374
  goals.push({
29654
31375
  sessionId: session.sessionId,
29655
31376
  displayName: session.displayName ?? null,
29656
- condition: goal.active.condition,
29657
- iterations: goal.active.iterations,
29658
- setAt: goal.active.setAt,
29659
- ...goal.active.lastReason !== void 0 ? { lastReason: goal.active.lastReason } : {},
29660
- hasActivePrompt: session.hasActivePrompt
31377
+ condition: record.objective,
31378
+ iterations: record.turnCount,
31379
+ setAt: record.createdAt,
31380
+ ...record.lastReason !== void 0 ? { lastReason: record.lastReason } : {},
31381
+ hasActivePrompt: session.hasActivePrompt,
31382
+ snapshot: goal.snapshot
29661
31383
  });
29662
31384
  }
29663
31385
  if (dropped.length > 0) {
@@ -29863,9 +31585,10 @@ function startScheduledTaskKeepalive(opts) {
29863
31585
  const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
29864
31586
  const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
29865
31587
  await bridge.closeSession(sessionId);
29866
- await new SessionService(boundWorkspace, {
31588
+ const removed = await new SessionService(boundWorkspace, {
29867
31589
  runtimeBaseDir: opts.runtimeBaseDir
29868
31590
  }).removeSession(sessionId);
31591
+ if (removed) bridge.markSessionCatalogChanged?.();
29869
31592
  });
29870
31593
  const reviveState = /* @__PURE__ */ new Map();
29871
31594
  const reviving = /* @__PURE__ */ new Set();
@@ -31443,8 +33166,8 @@ __name(registerWorkspaceQualifiedSettingsRoutes, "registerWorkspaceQualifiedSett
31443
33166
 
31444
33167
  // packages/cli/src/serve/routes/sse-events.ts
31445
33168
  init_esbuild_shims();
31446
- import { randomUUID as randomUUID7 } from "node:crypto";
31447
- import { performance as performance2 } from "node:perf_hooks";
33169
+ import { randomUUID as randomUUID8 } from "node:crypto";
33170
+ import { performance as performance3 } from "node:perf_hooks";
31448
33171
 
31449
33172
  // packages/cli/src/serve/server/error-response.ts
31450
33173
  init_esbuild_shims();
@@ -31561,6 +33284,10 @@ function sendBridgeError(res, err, ctx, daemonLog) {
31561
33284
  return;
31562
33285
  }
31563
33286
  if (sendGenerationClosedError(res, err)) return;
33287
+ if (err instanceof Error && "code" in err && (err.code === "session_attachment_gone" || err.code === "invalid_session_attachment_reference")) {
33288
+ res.status(err.code === "session_attachment_gone" ? 410 : 400).json({ error: err.message, code: err.code });
33289
+ return;
33290
+ }
31564
33291
  if (err instanceof SessionWriterError) {
31565
33292
  res.status(err.httpStatus).json({
31566
33293
  error: err.message,
@@ -31725,6 +33452,14 @@ function sendBridgeError(res, err, ctx, daemonLog) {
31725
33452
  });
31726
33453
  return;
31727
33454
  }
33455
+ if (err instanceof SessionIdCaseConflictError) {
33456
+ res.status(409).json({
33457
+ error: err.message,
33458
+ code: "session_conflict",
33459
+ sessionId: err.sessionId
33460
+ });
33461
+ return;
33462
+ }
31728
33463
  if (err instanceof SessionArchivingError) {
31729
33464
  res.set("Retry-After", "5");
31730
33465
  res.status(409).json({
@@ -31886,6 +33621,22 @@ function sendBridgeError(res, err, ctx, daemonLog) {
31886
33621
  });
31887
33622
  return;
31888
33623
  }
33624
+ if (kind === "untrusted_workspace") {
33625
+ res.status(403).json({
33626
+ error: errorMessage2(err),
33627
+ code: kind
33628
+ });
33629
+ return;
33630
+ }
33631
+ if (kind === "goal_conflict" || kind === "goal_invalid_transition" || kind === "goal_persist_failed") {
33632
+ const d = data;
33633
+ res.status(kind === "goal_persist_failed" ? 500 : 409).json({
33634
+ error: errorMessage2(err),
33635
+ code: kind,
33636
+ ...d.current !== void 0 ? { current: d.current } : {}
33637
+ });
33638
+ return;
33639
+ }
31889
33640
  if (kind === "branch_point_invalid") {
31890
33641
  res.status(409).json({
31891
33642
  error: errorMessage2(err),
@@ -32132,7 +33883,7 @@ function registerSseEventsRoutes(app, deps) {
32132
33883
  app.get("/session/:id/events", async (req, res) => {
32133
33884
  const sessionId = req.params["id"];
32134
33885
  const diagnosticSessionId = boundedDiagnosticString(sessionId);
32135
- const streamId = randomUUID7();
33886
+ const streamId = randomUUID8();
32136
33887
  const clientId = parseSseClientId(req.headers["x-qwen-client-id"]);
32137
33888
  const connectReason = parseSseConnectReason(req.query["connectReason"]);
32138
33889
  const previousStreamId = parsePreviousSseStreamId(
@@ -32325,7 +34076,7 @@ function registerSseEventsRoutes(app, deps) {
32325
34076
  });
32326
34077
  return;
32327
34078
  }
32328
- const openedAt = performance2.now();
34079
+ const openedAt = performance3.now();
32329
34080
  let closeReason;
32330
34081
  let terminalCandidate;
32331
34082
  let terminalEventType;
@@ -32344,10 +34095,10 @@ function registerSseEventsRoutes(app, deps) {
32344
34095
  if (activeDrainStartedAt !== void 0) {
32345
34096
  maxDrainWaitMs = Math.max(
32346
34097
  maxDrainWaitMs,
32347
- performance2.now() - activeDrainStartedAt
34098
+ performance3.now() - activeDrainStartedAt
32348
34099
  );
32349
34100
  }
32350
- const durationMs = Math.max(0, performance2.now() - openedAt);
34101
+ const durationMs = Math.max(0, performance3.now() - openedAt);
32351
34102
  const resolvedCloseReason = closeReason ?? terminalCandidate ?? "client_disconnect";
32352
34103
  const closeAttributes = {
32353
34104
  "qwen-code.daemon.sse.duration_ms": durationMs,
@@ -32456,7 +34207,7 @@ function registerSseEventsRoutes(app, deps) {
32456
34207
  if (activeDrainStartedAt === void 0) return;
32457
34208
  maxDrainWaitMs = Math.max(
32458
34209
  maxDrainWaitMs,
32459
- performance2.now() - activeDrainStartedAt
34210
+ performance3.now() - activeDrainStartedAt
32460
34211
  );
32461
34212
  activeDrainStartedAt = void 0;
32462
34213
  }, "settleDrainMeasurement");
@@ -32479,7 +34230,7 @@ function registerSseEventsRoutes(app, deps) {
32479
34230
  return;
32480
34231
  }
32481
34232
  backpressureCount += 1;
32482
- activeDrainStartedAt = performance2.now();
34233
+ activeDrainStartedAt = performance3.now();
32483
34234
  const onDrain = /* @__PURE__ */ __name(() => {
32484
34235
  res.off("close", onClose);
32485
34236
  res.off("error", onError);
@@ -33154,6 +34905,19 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
33154
34905
  init_esbuild_shims();
33155
34906
  import * as path15 from "node:path";
33156
34907
  var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
34908
+ var NEW_FILE_MODE_ENV_VAR = "QWEN_SERVE_NEW_FILE_MODE";
34909
+ function parseNewFileModePolicy(env = process.env) {
34910
+ const raw = env[NEW_FILE_MODE_ENV_VAR];
34911
+ if (raw === void 0 || raw.trim() === "") return "owner";
34912
+ const normalized = raw.trim().toLowerCase();
34913
+ if (normalized === "system") return "system";
34914
+ if (normalized === "owner" || normalized === "0600") return "owner";
34915
+ writeStderrLine(
34916
+ `qwen serve: ignoring invalid ${NEW_FILE_MODE_ENV_VAR}=${raw} (expected 'system' or 'owner'); new files keep the 0600 default`
34917
+ );
34918
+ return "owner";
34919
+ }
34920
+ __name(parseNewFileModePolicy, "parseNewFileModePolicy");
33157
34921
  function createDefaultFsAuditEmit() {
33158
34922
  const WARN_EVERY = 100;
33159
34923
  let droppedCount = 0;
@@ -33181,6 +34945,7 @@ function resolveBridgeFsFactory(input) {
33181
34945
  emit: input.emit ?? createDefaultFsAuditEmit(),
33182
34946
  pathLocks: input.pathLocks,
33183
34947
  generationGuard: input.generationGuard,
34948
+ newFileMode: input.newFileMode ?? parseNewFileModePolicy(),
33184
34949
  ...input.customIgnoreFiles !== void 0 ? { customIgnoreFiles: input.customIgnoreFiles } : {}
33185
34950
  });
33186
34951
  }
@@ -33503,9 +35268,16 @@ __name(setupDeviceFlowRegistry, "setupDeviceFlowRegistry");
33503
35268
 
33504
35269
  // packages/cli/src/serve/server/error-handlers.ts
33505
35270
  init_esbuild_shims();
33506
- var import_express4 = __toESM(require_express(), 1);
35271
+ var import_express5 = __toESM(require_express(), 1);
33507
35272
  function installJsonBodyParser(app) {
33508
- app.use(import_express4.default.json({ limit: "10mb" }));
35273
+ const parseJson = import_express5.default.json({ limit: "10mb" });
35274
+ app.use((req, res, next) => {
35275
+ if (req.method === "POST" && /^\/session\/[^/]+\/attachments\/?$/i.test(req.path)) {
35276
+ next();
35277
+ return;
35278
+ }
35279
+ parseJson(req, res, next);
35280
+ });
33509
35281
  app.use((err, _req, res, next) => {
33510
35282
  if (sendJsonBodyParserError(res, err)) return;
33511
35283
  next(err);
@@ -38355,8 +40127,8 @@ __name(registerWorkspaceQualifiedSkillsRoutes, "registerWorkspaceQualifiedSkills
38355
40127
 
38356
40128
  // packages/cli/src/serve/routes/channel-webhooks.ts
38357
40129
  init_esbuild_shims();
38358
- var import_express5 = __toESM(require_express(), 1);
38359
- import { createHash as createHash4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
40130
+ var import_express6 = __toESM(require_express(), 1);
40131
+ import { createHash as createHash3, timingSafeEqual } from "node:crypto";
38360
40132
  var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
38361
40133
  "__proto__",
38362
40134
  "constructor",
@@ -38404,7 +40176,7 @@ function registerChannelWebhookRoutes(app, deps) {
38404
40176
  locals.channelWebhook = { channelName, source, sourceConfig };
38405
40177
  next();
38406
40178
  },
38407
- import_express5.default.json({ limit: "1mb" }),
40179
+ import_express6.default.json({ limit: "1mb" }),
38408
40180
  async (req, res) => {
38409
40181
  const locals = res.locals;
38410
40182
  const webhook = locals.channelWebhook;
@@ -38518,9 +40290,9 @@ function matchesWebhookSecret(candidate, expected) {
38518
40290
  if (typeof candidate !== "string") {
38519
40291
  return false;
38520
40292
  }
38521
- const expectedDigest = createHash4("sha256").update(expected).digest();
38522
- const candidateDigest = createHash4("sha256").update(candidate).digest();
38523
- return timingSafeEqual2(expectedDigest, candidateDigest);
40293
+ const expectedDigest = createHash3("sha256").update(expected).digest();
40294
+ const candidateDigest = createHash3("sha256").update(candidate).digest();
40295
+ return timingSafeEqual(expectedDigest, candidateDigest);
38524
40296
  }
38525
40297
  __name(matchesWebhookSecret, "matchesWebhookSecret");
38526
40298
  function readPayload(body, res) {
@@ -38599,7 +40371,7 @@ init_esbuild_shims();
38599
40371
 
38600
40372
  // packages/cli/src/serve/live/live-host-coordinator.ts
38601
40373
  init_esbuild_shims();
38602
- import { randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
40374
+ import { randomUUID as randomUUID9, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
38603
40375
  var DEFAULT_HELLO_TIMEOUT_MS = 5e3;
38604
40376
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
38605
40377
  var DEFAULT_HEARTBEAT_TIMEOUT_MS = 15e3;
@@ -38776,7 +40548,7 @@ __name(projectStatusForHost, "projectStatusForHost");
38776
40548
  var LiveHostCoordinator = class {
38777
40549
  constructor(options) {
38778
40550
  this.options = options;
38779
- this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID8();
40551
+ this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID9();
38780
40552
  this.handlers = options.handlers ?? {};
38781
40553
  this.now = options.now ?? Date.now;
38782
40554
  this.helloTimeoutMs = options.helloTimeoutMs ?? DEFAULT_HELLO_TIMEOUT_MS;
@@ -38845,7 +40617,7 @@ var LiveHostCoordinator = class {
38845
40617
  attachHost(socket, daemonNonce) {
38846
40618
  const expectedNonce = Buffer.from(this.daemonInstanceNonce);
38847
40619
  const presentedNonce = Buffer.from(daemonNonce ?? "");
38848
- if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual3(expectedNonce, presentedNonce)) {
40620
+ if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual2(expectedNonce, presentedNonce)) {
38849
40621
  socket.close(4003, "Invalid daemon instance nonce.");
38850
40622
  return;
38851
40623
  }
@@ -38968,7 +40740,7 @@ var LiveHostCoordinator = class {
38968
40740
  startCall(mode) {
38969
40741
  const call = {
38970
40742
  epoch: ++this.nextEpoch,
38971
- callId: randomUUID8(),
40743
+ callId: randomUUID9(),
38972
40744
  mode,
38973
40745
  state: "starting",
38974
40746
  pendingPermission: false,
@@ -39027,7 +40799,7 @@ var LiveHostCoordinator = class {
39027
40799
  new Error("Qwen Live Host must be connected to change the shortcut.")
39028
40800
  );
39029
40801
  }
39030
- const requestId = randomUUID8();
40802
+ const requestId = randomUUID9();
39031
40803
  return new Promise((resolve7, reject) => {
39032
40804
  const timer = setTimeout(() => {
39033
40805
  this.rejectPendingShortcut(
@@ -39117,7 +40889,7 @@ var LiveHostCoordinator = class {
39117
40889
  )
39118
40890
  );
39119
40891
  }
39120
- const requestId = randomUUID8();
40892
+ const requestId = randomUUID9();
39121
40893
  return new Promise((resolve7, reject) => {
39122
40894
  const timer = setTimeout(() => {
39123
40895
  this.pendingAppshots.delete(requestId);
@@ -39457,7 +41229,7 @@ var LiveHostCoordinator = class {
39457
41229
  this.disconnectHost(lease, 4008, "Live Host heartbeat timed out.");
39458
41230
  return;
39459
41231
  }
39460
- const pingId = randomUUID8();
41232
+ const pingId = randomUUID9();
39461
41233
  lease.pingId = pingId;
39462
41234
  this.sendHost({ type: "host.ping", pingId });
39463
41235
  }
@@ -39725,7 +41497,7 @@ init_esbuild_shims();
39725
41497
 
39726
41498
  // packages/cli/src/serve/live/live-setup-controller.ts
39727
41499
  init_esbuild_shims();
39728
- import { randomUUID as randomUUID10 } from "node:crypto";
41500
+ import { randomUUID as randomUUID11 } from "node:crypto";
39729
41501
 
39730
41502
  // packages/cli/src/serve/live/provider-credentials.ts
39731
41503
  init_esbuild_shims();
@@ -39823,7 +41595,7 @@ __name(resolveLiveProviderCredential, "resolveLiveProviderCredential");
39823
41595
 
39824
41596
  // packages/cli/src/serve/live/qwen-realtime-session.ts
39825
41597
  init_esbuild_shims();
39826
- import { randomUUID as randomUUID9 } from "node:crypto";
41598
+ import { randomUUID as randomUUID10 } from "node:crypto";
39827
41599
  var QWEN_REALTIME_LIMITS = {
39828
41600
  maxInputAudioFrameBytes: 64 * 1024,
39829
41601
  maxOutputAudioFrameBytes: 256 * 1024,
@@ -40238,7 +42010,7 @@ function openQwenRealtimeSession(config, callbacks = {}, deps = {}) {
40238
42010
  const sendJson = /* @__PURE__ */ __name((body) => {
40239
42011
  if (terminal || closedByClient || ws.readyState !== ws.OPEN) return false;
40240
42012
  try {
40241
- ws.send(JSON.stringify({ event_id: randomUUID9(), ...body }));
42013
+ ws.send(JSON.stringify({ event_id: randomUUID10(), ...body }));
40242
42014
  return true;
40243
42015
  } catch (error2) {
40244
42016
  fail(
@@ -41601,7 +43373,7 @@ async function validateCredential(credential) {
41601
43373
  apiKey: credential.apiKey,
41602
43374
  model: credential.realtimeModel,
41603
43375
  voice: credential.voice,
41604
- callEpoch: `setup-${randomUUID10()}`
43376
+ callEpoch: `setup-${randomUUID11()}`
41605
43377
  });
41606
43378
  session.close({ discardPendingInput: true });
41607
43379
  }
@@ -41908,7 +43680,7 @@ __name(registerLiveSetupRoutes, "registerLiveSetupRoutes");
41908
43680
  // packages/cli/src/serve/live/live-host-installer.ts
41909
43681
  init_esbuild_shims();
41910
43682
  import { execFile as execFile3 } from "node:child_process";
41911
- import { createHash as createHash5, randomUUID as randomUUID11 } from "node:crypto";
43683
+ import { createHash as createHash4, randomUUID as randomUUID12 } from "node:crypto";
41912
43684
  import * as fs7 from "node:fs";
41913
43685
  import * as fsp5 from "node:fs/promises";
41914
43686
  import * as os2 from "node:os";
@@ -42083,7 +43855,7 @@ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
42083
43855
  });
42084
43856
  throw new Error("Live Host download size does not match its manifest.");
42085
43857
  }
42086
- const hash = createHash5("sha256");
43858
+ const hash = createHash4("sha256");
42087
43859
  let received = 0;
42088
43860
  const guard = new Transform({
42089
43861
  transform(chunk, _encoding, callback) {
@@ -42139,8 +43911,8 @@ async function installLatestHost(currentArchitecture, onStatus) {
42139
43911
  const archivePath = path16.join(temporaryDirectory, "Qwen-Live-Host.zip");
42140
43912
  const extractedPath = path16.join(temporaryDirectory, "extracted");
42141
43913
  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`;
43914
+ const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID12()}.app`;
43915
+ const backupPath = `/Applications/.Qwen Live Host.backup-${randomUUID12()}.app`;
42144
43916
  let movedExisting = false;
42145
43917
  let installedCandidate = false;
42146
43918
  try {
@@ -42288,7 +44060,7 @@ var LiveHostInstaller = class {
42288
44060
 
42289
44061
  // packages/cli/src/serve/live/live-session-coordinator.ts
42290
44062
  init_esbuild_shims();
42291
- import { createHash as createHash6, randomUUID as randomUUID12 } from "node:crypto";
44063
+ import { createHash as createHash5, randomUUID as randomUUID13 } from "node:crypto";
42292
44064
  import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync2 } from "node:fs";
42293
44065
  import { join as join12 } from "node:path";
42294
44066
 
@@ -42663,7 +44435,7 @@ function openLiveAudioCapture(source, identifier) {
42663
44435
  );
42664
44436
  const stream = createWriteStream2(path19, { flags: "wx", mode: 384 });
42665
44437
  stream.on("error", () => void 0);
42666
- return { source, path: path19, stream, hash: createHash6("sha256"), bytes: 0 };
44438
+ return { source, path: path19, stream, hash: createHash5("sha256"), bytes: 0 };
42667
44439
  } catch {
42668
44440
  return void 0;
42669
44441
  }
@@ -43018,7 +44790,7 @@ var LiveSessionCoordinator = class {
43018
44790
  context.speechInProgress = true;
43019
44791
  context.inputCommitPending = true;
43020
44792
  context.inputAwaitingResponse = false;
43021
- const partialItemId = itemId ?? `partial:${randomUUID12()}`;
44793
+ const partialItemId = itemId ?? `partial:${randomUUID13()}`;
43022
44794
  context.activePartialInputItemId = partialItemId;
43023
44795
  if (!context.partialInputTranscripts.has(partialItemId)) {
43024
44796
  context.partialInputTranscripts.set(partialItemId, "");
@@ -43048,7 +44820,7 @@ var LiveSessionCoordinator = class {
43048
44820
  }, "onInputCommitted"),
43049
44821
  onInputTranscriptDelta: /* @__PURE__ */ __name(({ itemId, text }) => {
43050
44822
  if (this.isCurrentSocket(context, generation)) {
43051
- const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID12()}`;
44823
+ const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID13()}`;
43052
44824
  context.activePartialInputItemId = partialItemId;
43053
44825
  context.partialInputTranscripts.set(partialItemId, text);
43054
44826
  this.options.host.setTranscript?.(context.epoch, text);
@@ -43058,7 +44830,7 @@ var LiveSessionCoordinator = class {
43058
44830
  if (this.isCurrentSocket(context, generation)) {
43059
44831
  context.speechInProgress = false;
43060
44832
  context.inputCommitPending = false;
43061
- const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID12()}`;
44833
+ const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID13()}`;
43062
44834
  context.partialInputTranscripts.delete(completedItemId);
43063
44835
  if (context.activePartialInputItemId === completedItemId) {
43064
44836
  context.activePartialInputItemId = void 0;
@@ -43774,9 +45546,10 @@ var LiveSessionCoordinator = class {
43774
45546
  if (!sessionClosed) return;
43775
45547
  if (removeFreshTranscript) {
43776
45548
  try {
43777
- await new SessionService(runtime.workspaceCwd).removeSession(
43778
- session.sessionId
43779
- );
45549
+ const transcriptRemoved = await new SessionService(
45550
+ runtime.workspaceCwd
45551
+ ).removeSession(session.sessionId);
45552
+ if (transcriptRemoved) bridge.markSessionCatalogChanged();
43780
45553
  } catch {
43781
45554
  }
43782
45555
  }
@@ -43789,7 +45562,7 @@ var LiveSessionCoordinator = class {
43789
45562
  const runtime = context.runtime;
43790
45563
  if (!runtime) throw new Error("Conversation workspace is unavailable.");
43791
45564
  const bridge = runtime.bridge;
43792
- const promptId = randomUUID12();
45565
+ const promptId = randomUUID13();
43793
45566
  const lastEventId = bridge.getSessionLastEventId(locator.sessionId);
43794
45567
  const turnAbort = new AbortController();
43795
45568
  this.inFlightTurnAborts.add(turnAbort);
@@ -44106,7 +45879,7 @@ var LiveSessionCoordinator = class {
44106
45879
 
44107
45880
  // packages/cli/src/serve/live/live-task-service.ts
44108
45881
  init_esbuild_shims();
44109
- import { randomUUID as randomUUID13 } from "node:crypto";
45882
+ import { randomUUID as randomUUID14 } from "node:crypto";
44110
45883
  var DEFAULT_LIST_LIMIT = 20;
44111
45884
  var DEFAULT_READ_TURN_LIMIT = 3;
44112
45885
  var DEFAULT_WAIT_TIMEOUT_MS = 12e4;
@@ -44538,7 +46311,10 @@ var LiveTaskService = class {
44538
46311
  cwd: located.summary.workspaceCwd,
44539
46312
  createdAt: epochSeconds(located.summary.createdAt),
44540
46313
  updatedAt: epochSeconds(
44541
- located.summary.updatedAt ?? located.persisted?.conversation.lastUpdated
46314
+ laterActivityTimestamp(
46315
+ located.summary.updatedAt,
46316
+ located.persisted?.conversation.lastUpdated
46317
+ )
44542
46318
  )
44543
46319
  },
44544
46320
  page: {
@@ -44677,7 +46453,10 @@ var LiveTaskService = class {
44677
46453
  ),
44678
46454
  eventId: task.runtime.bridge.getSessionLastEventId(target.threadId)
44679
46455
  } : {},
44680
- updatedAt: task.summary.updatedAt ?? task.persisted?.conversation.lastUpdated
46456
+ updatedAt: laterActivityTimestamp(
46457
+ task.summary.updatedAt,
46458
+ task.persisted?.conversation.lastUpdated
46459
+ )
44681
46460
  });
44682
46461
  const { reset: cursorReset } = decodeCursor(
44683
46462
  target.afterCursor,
@@ -44691,7 +46470,10 @@ var LiveTaskService = class {
44691
46470
  const completedAt = latestTurnRecords.at(-1)?.timestamp ?? task.persisted?.conversation.lastUpdated;
44692
46471
  const failed = task.summary.hasTurnError === true;
44693
46472
  const revision = task.summary.clientCount > 0 ? task.runtime.bridge.getSessionLastEventId(target.threadId) : epochSeconds(
44694
- task.summary.updatedAt ?? task.persisted?.conversation.lastUpdated ?? task.summary.createdAt
46473
+ laterActivityTimestamp(
46474
+ task.summary.updatedAt,
46475
+ task.persisted?.conversation.lastUpdated
46476
+ ) ?? task.summary.createdAt
44695
46477
  );
44696
46478
  return {
44697
46479
  schemaVersion: 1,
@@ -44823,7 +46605,7 @@ var LiveTaskService = class {
44823
46605
  { sessionId, prompt: [{ type: "text", text: prompt }] },
44824
46606
  void 0,
44825
46607
  {
44826
- promptId: randomUUID13(),
46608
+ promptId: randomUUID14(),
44827
46609
  onPromptAdmitted: /* @__PURE__ */ __name(() => {
44828
46610
  admitted = true;
44829
46611
  onAdmitted?.();
@@ -44843,7 +46625,7 @@ var LiveTaskService = class {
44843
46625
  const service = createWorkspaceRuntimeSessionService(task.runtime);
44844
46626
  const metadata = task.runtime.provenance === "live-conversation" ? await readLoadableLiveConversationMetadata(
44845
46627
  task.summary.sessionId,
44846
- (sessionId) => service.readCreationMetadata(sessionId)
46628
+ service
44847
46629
  ) : await service.readCreationMetadata(task.summary.sessionId);
44848
46630
  if (metadata === void 0) {
44849
46631
  throw new SessionNotFoundError(task.summary.sessionId);
@@ -44889,10 +46671,11 @@ var LiveTaskService = class {
44889
46671
  removed = false;
44890
46672
  }
44891
46673
  if (removed) {
44892
- await runWithWorkspaceRuntimeStorage(
46674
+ const persistedRemoved = await runWithWorkspaceRuntimeStorage(
44893
46675
  runtime,
44894
- () => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => void 0)
46676
+ () => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => false)
44895
46677
  );
46678
+ if (persistedRemoved) runtime.bridge.markSessionCatalogChanged();
44896
46679
  }
44897
46680
  if (projectless && removed) {
44898
46681
  await this.options.discardEmptyConversationDirectory(session.sessionId).catch(() => void 0);
@@ -45078,7 +46861,7 @@ var ConversationRuntimeManager = class {
45078
46861
 
45079
46862
  // packages/cli/src/serve/conversations/conversation-runtime-ownership.ts
45080
46863
  init_esbuild_shims();
45081
- import { randomUUID as randomUUID14 } from "node:crypto";
46864
+ import { randomUUID as randomUUID15 } from "node:crypto";
45082
46865
  import { constants as fsConstants2 } from "node:fs";
45083
46866
  import * as fs8 from "node:fs/promises";
45084
46867
  import * as path17 from "node:path";
@@ -45214,16 +46997,20 @@ async function readOwnerRecord(ownerPath) {
45214
46997
  process.platform === "win32" ? fsConstants2.O_RDONLY : fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW
45215
46998
  );
45216
46999
  } catch (error2) {
45217
- throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
47000
+ if (error2.code === "ELOOP") {
47001
+ throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
47002
+ }
47003
+ throw error2;
45218
47004
  }
45219
47005
  try {
45220
47006
  const handleStat = await handle.stat();
45221
47007
  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
47008
  throw new UnsafeOwnershipStateError();
45223
47009
  }
47010
+ const serialized = await handle.readFile("utf8");
45224
47011
  let parsed;
45225
47012
  try {
45226
- parsed = JSON.parse(await handle.readFile("utf8"));
47013
+ parsed = JSON.parse(serialized);
45227
47014
  } catch (error2) {
45228
47015
  throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
45229
47016
  }
@@ -45349,7 +47136,7 @@ var FileConversationRuntimeOwnership = class {
45349
47136
  await this.commitRecord(identity, void 0);
45350
47137
  }
45351
47138
  }, "commitOwner");
45352
- const liveDiscovery = await import("./discovery-ORA5J7YP.js");
47139
+ const liveDiscovery = await import("./discovery-X2NV535U.js");
45353
47140
  const handoff = await liveDiscovery.handoffLiveDiscoveryOwner(
45354
47141
  this.stableBaseDir,
45355
47142
  this.current,
@@ -45466,7 +47253,7 @@ var FileConversationRuntimeOwnership = class {
45466
47253
  async commitRecord(identity, expected) {
45467
47254
  const temporaryPath = path17.join(
45468
47255
  this.ownerDirectory,
45469
- `.runtime-owner.${this.current.pid}.${randomUUID14()}.tmp`
47256
+ `.runtime-owner.${this.current.pid}.${randomUUID15()}.tmp`
45470
47257
  );
45471
47258
  let handle;
45472
47259
  let renamed = false;
@@ -45646,7 +47433,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
45646
47433
  "createServeApp: runtime replacement/removal requires deps.getSessionBridges so session-id admission can inspect draining generations."
45647
47434
  );
45648
47435
  }
45649
- const app = (0, import_express6.default)();
47436
+ const app = (0, import_express7.default)();
45650
47437
  const serveAppLifecycle = installServeAppLifecycle(
45651
47438
  app,
45652
47439
  deps.serveAppLifecycle
@@ -45810,6 +47597,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
45810
47597
  }) : void 0;
45811
47598
  const defaultSessionOwnerIndex = !injectedWorkspaceRegistry ? createWorkspaceSessionOwnerIndex() : void 0;
45812
47599
  const bridge = injectedWorkspaceRegistry?.primary.bridge ?? deps.bridge ?? createAcpSessionBridge({
47600
+ sessionAttachmentsRoot: path18.join(
47601
+ new Storage(boundWorkspace).getProjectTempDir(),
47602
+ "attachments"
47603
+ ),
45813
47604
  maxSessions: opts.maxSessions,
45814
47605
  ...totalSessionAdmission ? { freshSessionAdmission: totalSessionAdmission.admit } : {},
45815
47606
  ...defaultSessionOwnerIndex ? {
@@ -46307,18 +48098,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46307
48098
  app.locals.stopWorkspaceGitState = () => workspaceGitState.dispose();
46308
48099
  app.locals.stopWorkspaceGitStateForWorkspace = (workspaceCwd) => workspaceGitState.disposeWorkspace(workspaceCwd);
46309
48100
  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);
48101
+ const parsedAllowOrigins = parseAllowOriginPatterns(opts.allowOrigins ?? []);
48102
+ if (parsedAllowOrigins.allowAny && !opts.token) {
48103
+ throw new Error(
48104
+ `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 '*'.`
48105
+ );
46320
48106
  }
48107
+ const originAllowlist = new MutableOriginAllowlist(parsedAllowOrigins);
48108
+ app.use(allowOriginCors(originAllowlist));
46321
48109
  app.use(hostAllowlist(opts.hostname, getPort));
48110
+ const credentials = new CredentialStore(opts.token);
48111
+ const authenticate = bearerAuth(credentials);
46322
48112
  const rateLimiter = installRateLimiter(app, opts, daemonLog, {
46323
48113
  mount: false,
46324
48114
  workspaceQualifiedAcpEnabled
@@ -46330,9 +48120,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46330
48120
  getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
46331
48121
  });
46332
48122
  if (healthRoutes.exposeHealthPreAuth) {
48123
+ app.use("/health", (req, res, next) => {
48124
+ if (listenerIdentityOf(req).kind === "local-control") {
48125
+ authenticate(req, res, next);
48126
+ return;
48127
+ }
48128
+ next();
48129
+ });
46333
48130
  healthRoutes.register(app);
46334
48131
  }
46335
48132
  installAccessLogMiddleware(app, daemonLog);
48133
+ app.use(daemonInboundTraceIdCaptureMiddleware);
46336
48134
  const webShellDir = opts.serveWebShell !== false ? deps.webShellDir : void 0;
46337
48135
  const webShellFrameAncestors = opts.allowOrigins && opts.allowOrigins.length > 0 ? [...parseAllowOriginPatterns(opts.allowOrigins).origins].filter(
46338
48136
  (o) => o.startsWith("chrome-extension://") || o.startsWith("moz-extension://")
@@ -46373,7 +48171,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
46373
48171
  daemonLog
46374
48172
  });
46375
48173
  }
46376
- app.use(bearerAuth(opts.token));
48174
+ app.use(authenticate);
46377
48175
  if (rateLimiter) {
46378
48176
  app.use(rateLimiter.middleware);
46379
48177
  }
@@ -47151,6 +48949,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
47151
48949
  fsFactory: primaryRouteFileSystemFactory,
47152
48950
  deviceFlowRegistry,
47153
48951
  token: opts.token,
48952
+ // The WS upgrade bypasses Express middleware, so it needs the same
48953
+ // listener-scoped credentials the REST gate uses — otherwise the
48954
+ // `qwen-bearer.*` subprotocol would be a way around the scoping.
48955
+ credentials,
47154
48956
  // Mirror the REST CORS allowlist onto the WS CSRF wall so an
47155
48957
  // explicitly permitted origin (e.g. the extension's
47156
48958
  // `chrome-extension://<id>`) can open the reverse tool channel.
@@ -47222,6 +49024,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
47222
49024
  if (acpHandleRef.current) {
47223
49025
  app.locals["acpHandle"] = acpHandleRef.current;
47224
49026
  }
49027
+ const localControlService = new LocalControlService({
49028
+ app,
49029
+ credentials,
49030
+ originAllowlist,
49031
+ // Resolved through the ref on each call rather than captured so Local
49032
+ // Control cannot attach to a stale ACP mount.
49033
+ attachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.attachServer(server), "attachWebSocket"),
49034
+ detachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.detachServer(server), "detachWebSocket"),
49035
+ getPort,
49036
+ tlsPaths: opts.tlsCert && opts.tlsKey ? { cert: opts.tlsCert, key: opts.tlsKey } : void 0
49037
+ });
49038
+ app.locals["localControlService"] = localControlService;
49039
+ registerWorkspaceLocalControlRoutes(app, {
49040
+ service: localControlService,
49041
+ mutate,
49042
+ safeBody,
49043
+ isDaemonDraining: deps.isChannelControlDraining,
49044
+ webShellAvailable: Boolean(webShellDir),
49045
+ primaryBindHostname: opts.hostname
49046
+ });
47225
49047
  if (webShellDir) {
47226
49048
  mountWebShellSpaFallback(app, webShellDir, webShellFrameAncestors);
47227
49049
  }