@qwen-code/qwen-code 0.20.2-headless-image-routing.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +5 -0
  2. package/bundled/qc-helper/docs/features/sub-agents.md +23 -5
  3. package/bundled/qc-helper/docs/integration-github-action.md +9 -9
  4. package/bundled/review/SKILL.md +7 -3
  5. package/chunks/MaxSizedBox-5DPPWPGT.js +85 -0
  6. package/chunks/{StandaloneSessionPicker-PLQQB22E.js → StandaloneSessionPicker-BIRMPLRD.js} +66 -59
  7. package/chunks/{acp-startup-profiler-N3RHHXJ3.js → acp-startup-profiler-RV3IV562.js} +2 -2
  8. package/chunks/{acpAgent-AIVK2EM5.js → acpAgent-6J2U72PQ.js} +705 -182
  9. package/chunks/agent-6ODUANDO.js +81 -0
  10. package/chunks/agent-headless-7BYQTMHW.js +75 -0
  11. package/chunks/{anthropicContentGenerator-HGWAHO24.js → anthropicContentGenerator-75BKLTSP.js} +117 -43
  12. package/chunks/{artifact-tool-56T5IMBP.js → artifact-tool-Y5T7GG7F.js} +3 -3
  13. package/chunks/{askUserQuestion-E25OBIC2.js → askUserQuestion-2H6747FR.js} +3 -3
  14. package/chunks/bridge-ZUB64FAE.js +90 -0
  15. package/chunks/{build-GHIZ4MSZ.js → build-RV63TIRH.js} +2 -3
  16. package/chunks/{ca-N6VVUFVB.js → ca-25EDXPFZ.js} +2 -0
  17. package/chunks/{channel-worker-group-QZV2SP5U.js → channel-worker-group-2ZD7TVAT.js} +8 -7
  18. package/chunks/{channel-worker-manager-3GMAU45H.js → channel-worker-manager-4OA4BCGB.js} +190 -30
  19. package/chunks/{channel-worker-supervisor-QCXSXCRY.js → channel-worker-supervisor-V7KCFJTS.js} +7 -6
  20. package/chunks/{chunk-TYQMGACW.js → chunk-22C7BQ6D.js} +508 -10967
  21. package/chunks/chunk-2JZBVYTU.js +452 -0
  22. package/chunks/{chunk-H2XVO6NE.js → chunk-2MIN6GRR.js} +1 -1
  23. package/chunks/{chunk-4DWTDZGS.js → chunk-2NH6DYI4.js} +12 -12
  24. package/chunks/chunk-2SCDWPXI.js +246 -0
  25. package/chunks/{chunk-QE4KFTBS.js → chunk-2X55UKQE.js} +3 -3
  26. package/chunks/{chunk-QBUDF33N.js → chunk-3QMGYBFN.js} +1 -1
  27. package/chunks/{chunk-3OAKYHRG.js → chunk-3RN6GBKS.js} +1 -1
  28. package/chunks/{chunk-QR6U5QPP.js → chunk-3SJ43L4W.js} +4 -0
  29. package/chunks/chunk-46UV252V.js +128 -0
  30. package/chunks/{chunk-GHRSKGHF.js → chunk-4WIZGAH3.js} +7 -7
  31. package/chunks/{chunk-CAS7CB3T.js → chunk-55DJUCI2.js} +87 -29
  32. package/chunks/{chunk-QNLNLENL.js → chunk-5I2IWRSH.js} +2 -2
  33. package/chunks/{chunk-H24SOJIQ.js → chunk-5NBDS5S6.js} +147 -7
  34. package/chunks/{chunk-E4IMU4Y5.js → chunk-63P4EL5V.js} +1 -1
  35. package/chunks/chunk-6FGBXPWM.js +293 -0
  36. package/chunks/{chunk-FFFM6NJV.js → chunk-6GMVPFB2.js} +155 -73
  37. package/chunks/{chunk-KWK7UE6L.js → chunk-6OUGMXDC.js} +6 -6
  38. package/chunks/{chunk-QRUIS3DN.js → chunk-6PEXNQTX.js} +22 -1
  39. package/chunks/{chunk-FZPTCQY7.js → chunk-7JURR4JT.js} +1 -1
  40. package/chunks/{chunk-Q6NAKZTA.js → chunk-7MVVZO4N.js} +4 -4
  41. package/chunks/{chunk-6ZBPS62S.js → chunk-7ZCNENPP.js} +1 -1
  42. package/chunks/{chunk-6X4GWOPW.js → chunk-A5L3JMUA.js} +1 -1
  43. package/chunks/{chunk-YO2XRXY6.js → chunk-ACY3A37B.js} +3 -3
  44. package/chunks/chunk-AMDSOFFV.js +10860 -0
  45. package/chunks/{chunk-RV4C2ZFG.js → chunk-BIQWWWJN.js} +1 -1
  46. package/chunks/{chunk-ZHERRXZJ.js → chunk-BJX6ZSUK.js} +4 -4
  47. package/chunks/chunk-BK2UNYWD.js +29 -0
  48. package/chunks/{chunk-FRPDJNK3.js → chunk-BKHWX6I2.js} +3 -3
  49. package/chunks/chunk-BPJSQIJX.js +100 -0
  50. package/chunks/{chunk-M7WBGLYP.js → chunk-BULDBTYC.js} +2 -0
  51. package/chunks/{chunk-ZDP2Y2AL.js → chunk-CIKQ7KKO.js} +4625 -8645
  52. package/chunks/{chunk-PEJWA3QQ.js → chunk-D3UEZIQH.js} +4 -2
  53. package/chunks/chunk-DHHOYAPR.js +1462 -0
  54. package/chunks/{chunk-LESHKUWF.js → chunk-DLWL3Z7A.js} +5 -3
  55. package/chunks/{chunk-XHATNRQA.js → chunk-DP3IHZGG.js} +0 -2
  56. package/chunks/chunk-E5TUC6CA.js +479 -0
  57. package/chunks/{chunk-JC26SJ5Y.js → chunk-EBJQ6AXW.js} +13 -12
  58. package/chunks/{chunk-RCWKCN2Z.js → chunk-EPDRMGT4.js} +164 -17
  59. package/chunks/{chunk-FUFCALSJ.js → chunk-ETSW4KLJ.js} +2 -2
  60. package/chunks/{chunk-KHOVYUHX.js → chunk-FNQ6T3CV.js} +20 -3
  61. package/chunks/{chunk-SP5WRGVG.js → chunk-FQK6JAFG.js} +72 -23
  62. package/chunks/{chunk-NWZY2SPY.js → chunk-FSITMZJH.js} +8 -8
  63. package/chunks/{chunk-6RLROE6G.js → chunk-GLWP3FDB.js} +80 -15
  64. package/chunks/{chunk-KPBVP6SL.js → chunk-GSN55ZRI.js} +5 -5
  65. package/chunks/{chunk-MLYGPZGU.js → chunk-H4SBPHSA.js} +3 -3
  66. package/chunks/chunk-H5FFA6TH.js +902 -0
  67. package/chunks/{chunk-TDKQP3M6.js → chunk-HIJQF5B5.js} +1 -1
  68. package/chunks/{chunk-5G3ZVADU.js → chunk-IJTOWOD7.js} +17 -6
  69. package/chunks/chunk-IKCX4CCL.js +469 -0
  70. package/chunks/{chunk-LPEONXNV.js → chunk-IKYJHJNF.js} +3 -3
  71. package/chunks/{chunk-DTZY2SH2.js → chunk-IO3IX5Q4.js} +1 -1
  72. package/chunks/{chunk-RS7MT2QG.js → chunk-IPUUTYMV.js} +2 -4
  73. package/chunks/{chunk-XU457J4V.js → chunk-IRH27ZC2.js} +2 -2
  74. package/chunks/{chunk-46DK772E.js → chunk-J24WCGIN.js} +4 -4
  75. package/chunks/{chunk-4LVZNIDO.js → chunk-J56UI34H.js} +4 -13
  76. package/chunks/{chunk-TJTKSVIV.js → chunk-JLU636DO.js} +5 -1
  77. package/chunks/{chunk-RKWX4CMO.js → chunk-JVPM2ULZ.js} +6 -6
  78. package/chunks/{chunk-ENPCQK44.js → chunk-JXJFVC6E.js} +37 -18
  79. package/chunks/{chunk-NABLFI57.js → chunk-JZA3JUDJ.js} +1 -1
  80. package/chunks/{chunk-CGLQAVZE.js → chunk-K36B6G2O.js} +5 -5
  81. package/chunks/{chunk-GPSKDNEE.js → chunk-K4XWPEWB.js} +4 -4
  82. package/chunks/{chunk-QOZOIPSF.js → chunk-KIM5GUMA.js} +650 -113
  83. package/chunks/{chunk-JZSM2IZ3.js → chunk-KMQ33DO4.js} +7 -5
  84. package/chunks/{chunk-E2UVIFI2.js → chunk-KRXPRVGL.js} +0 -1
  85. package/chunks/{chunk-WHGVTP7Q.js → chunk-L26JL52R.js} +3 -3
  86. package/chunks/{chunk-7Z6JQEL6.js → chunk-L5UHQJTJ.js} +1 -1
  87. package/chunks/{chunk-O2XSCRCS.js → chunk-LB6DUZ26.js} +259 -67
  88. package/chunks/chunk-LEH5C7FV.js +232 -0
  89. package/chunks/{chunk-RWV32G2M.js → chunk-LH2BYDQ5.js} +6 -4
  90. package/chunks/{chunk-QKTHJXCS.js → chunk-LK7CHLVP.js} +79 -2
  91. package/chunks/{chunk-VRRF3GW5.js → chunk-LKEJ26GS.js} +11 -11
  92. package/chunks/{chunk-SQFXI7VK.js → chunk-LQIW3YFY.js} +227 -41
  93. package/chunks/chunk-LS77BEZP.js +405 -0
  94. package/chunks/{chunk-BSHD62QJ.js → chunk-M4FMGVY4.js} +3 -3
  95. package/chunks/{chunk-57FIIFJN.js → chunk-M5JM7OSF.js} +1 -1
  96. package/chunks/{chunk-7362QS5B.js → chunk-MB4MZHMJ.js} +80 -37
  97. package/chunks/{chunk-4K56OJFJ.js → chunk-MUP3T3AD.js} +1 -1
  98. package/chunks/{chunk-3HFNGB2O.js → chunk-MVSUYZDT.js} +4 -4
  99. package/chunks/{chunk-T5IO6FZ4.js → chunk-MZAXJAUM.js} +1 -1
  100. package/chunks/{chunk-QKNXKTZX.js → chunk-NH6KE4JX.js} +3 -3
  101. package/chunks/chunk-NIBLUX3Y.js +934 -0
  102. package/chunks/{chunk-OQB4EXO4.js → chunk-NL7LTRLR.js} +1 -1
  103. package/chunks/{chunk-CS2FSS7W.js → chunk-OFDOK3VM.js} +5 -5
  104. package/chunks/{chunk-LIZRAKPB.js → chunk-OHNBB4XR.js} +1 -1
  105. package/chunks/{chunk-MDZTPSXO.js → chunk-OKY7HXPG.js} +2 -2
  106. package/chunks/{chunk-NHDKSOEY.js → chunk-P3QQPMQA.js} +5 -5
  107. package/chunks/{chunk-7THPNISK.js → chunk-PC6JANNU.js} +5 -5
  108. package/chunks/{chunk-OTQ6PSZC.js → chunk-PHOF65IG.js} +3498 -1030
  109. package/chunks/{chunk-OQ5SYCPE.js → chunk-PJIZUQVC.js} +2 -2
  110. package/chunks/{chunk-5DTTYNB7.js → chunk-PQNHRFJC.js} +16 -3
  111. package/chunks/{chunk-YM3SZTH4.js → chunk-PR75REBZ.js} +18 -1
  112. package/chunks/{chunk-RECUEJ7B.js → chunk-PSOO6YXD.js} +18 -15
  113. package/chunks/{chunk-X6N25LXS.js → chunk-PWTZEM3C.js} +2 -2
  114. package/chunks/{chunk-5NJTNQUW.js → chunk-PWVFN2LF.js} +1 -1
  115. package/chunks/{chunk-7AUH6A4T.js → chunk-Q4M4MDQ4.js} +2 -2
  116. package/chunks/{chunk-EZPB6S2I.js → chunk-QAF7NMK7.js} +1 -1
  117. package/chunks/{chunk-5GI55PF5.js → chunk-R5AFZNQW.js} +5 -5
  118. package/chunks/{chunk-T5B5NQZX.js → chunk-RF3EXIHJ.js} +47 -60
  119. package/chunks/{chunk-4K7VDKAD.js → chunk-RHLZR4E5.js} +1 -1
  120. package/chunks/{chunk-TJDW42MV.js → chunk-RIBKPMRP.js} +220 -141
  121. package/chunks/{chunk-RVLZCXEE.js → chunk-RWTEFFPU.js} +82 -3
  122. package/chunks/{chunk-L5QZGCRH.js → chunk-RZIX2G32.js} +1 -1
  123. package/chunks/{chunk-LLKWRXSS.js → chunk-SQCQ4KO2.js} +350 -418
  124. package/chunks/{chunk-THJNPLI4.js → chunk-TARRHLLG.js} +1 -0
  125. package/chunks/{chunk-XCXYRDHB.js → chunk-TEHGS6UP.js} +47 -18
  126. package/chunks/{chunk-PQIVAWXN.js → chunk-TGILQ3YH.js} +8 -8
  127. package/chunks/{chunk-Q2YKNMLS.js → chunk-TOFQCPDC.js} +43 -10
  128. package/chunks/{chunk-L3KUB6XM.js → chunk-TPRQ7RZH.js} +586 -242
  129. package/chunks/{chunk-T4TZQJ7W.js → chunk-TWPJO254.js} +5 -16
  130. package/chunks/{chunk-HIP6TVWA.js → chunk-U7M2DMGW.js} +3 -3
  131. package/chunks/{chunk-ACW3VNUE.js → chunk-UDX5OBWR.js} +41 -9
  132. package/chunks/{chunk-LW2FUYBN.js → chunk-USTWD7QV.js} +6 -4
  133. package/chunks/{chunk-NPQDJGKU.js → chunk-UUUTRMI2.js} +1 -1
  134. package/chunks/chunk-UW5EOVUN.js +249 -0
  135. package/chunks/{chunk-6IL7KRLE.js → chunk-VAK25FTU.js} +1 -1
  136. package/chunks/{chunk-O4BHWVUD.js → chunk-VIA5XA4U.js} +5 -2
  137. package/chunks/{chunk-EBXZ2YGV.js → chunk-VRYUBFMC.js} +1 -1
  138. package/chunks/{chunk-TWVE5ZS5.js → chunk-VULLI6WQ.js} +172 -6
  139. package/chunks/{chunk-LNDD3IML.js → chunk-WCXCRJYB.js} +1 -1
  140. package/chunks/{chunk-2LI23QA6.js → chunk-X5XDDSSH.js} +1 -1
  141. package/chunks/{chunk-Q35QUZDQ.js → chunk-Y34KJKDC.js} +1 -1
  142. package/chunks/{chunk-7NR2AIK6.js → chunk-YBL3QUDD.js} +2 -2
  143. package/chunks/{chunk-H4AR2JQF.js → chunk-YH6G52F2.js} +3 -3
  144. package/chunks/{chunk-MBOJHHPI.js → chunk-YPE6A4GC.js} +2 -2
  145. package/chunks/{chunk-3EK5ZOUQ.js → chunk-YX324OPW.js} +1 -1
  146. package/chunks/{chunk-4PTLZ3NX.js → chunk-Z2BC6UJ5.js} +3 -3
  147. package/chunks/{chunk-QLJUC7TG.js → chunk-ZD6UTE4A.js} +1 -1
  148. package/chunks/{chunk-LX3COOXF.js → chunk-ZFDTEDCF.js} +6 -6
  149. package/chunks/chunk-ZJHVAS7M.js +289 -0
  150. package/chunks/{chunk-4OWXOUYF.js → chunk-ZNAUOR2I.js} +15 -12
  151. package/chunks/{chunk-T2L47JJK.js → chunk-ZOIFNCKL.js} +4 -4
  152. package/chunks/{computer-use-2VIV73WK.js → computer-use-SOQ4E3VX.js} +43 -35
  153. package/chunks/{config-utils-FYTBZLCJ.js → config-utils-7V7GGIW6.js} +3 -3
  154. package/chunks/contextCommand-JLHYA34Z.js +80 -0
  155. package/chunks/{create-sub-session-AZ77LBL3.js → create-sub-session-IWW2IZ2T.js} +3 -3
  156. package/chunks/{create-sub-session-XDHHC2P4.js → create-sub-session-QRJLW5BV.js} +43 -35
  157. package/chunks/{cron-create-KTWJM7QT.js → cron-create-YIID5XAW.js} +6 -6
  158. package/chunks/{cron-delete-2P3I5ULL.js → cron-delete-ZVHYCEP2.js} +5 -5
  159. package/chunks/{cron-list-PXDPGEDQ.js → cron-list-XEGS463Q.js} +5 -5
  160. package/chunks/{daemon-RAPSDJH7.js → daemon-YO6433NF.js} +350 -53
  161. package/chunks/daemon-status-provider-2233Q37D.js +89 -0
  162. package/chunks/{de-4IBXM7CN.js → de-HGRCYDEJ.js} +1 -0
  163. package/chunks/{dist-UIFWIFRO.js → dist-46NQKLTW.js} +2 -2
  164. package/chunks/{dist-XRYV6TJP.js → dist-AIKFMUKK.js} +50 -4
  165. package/chunks/{dist-XBJVSWS2.js → dist-BBLXMS3N.js} +14 -2
  166. package/chunks/{dist-OMW6WDEO.js → dist-F6IBUDR4.js} +40 -9
  167. package/chunks/{dist-PJLG2XYX.js → dist-WEAHOXDM.js} +1 -1
  168. package/chunks/{dist-OAV7LJGJ.js → dist-YFNEUWSE.js} +26 -2
  169. package/chunks/earlyInputCapture-A7NDU3PF.js +82 -0
  170. package/chunks/{edit-CS6SFEXC.js → edit-OBDSQURM.js} +43 -35
  171. package/chunks/{en-USMCCJAJ.js → en-MTWBNGDO.js} +15 -0
  172. package/chunks/{enter-worktree-LMAL75DY.js → enter-worktree-U6MRPQ2P.js} +43 -35
  173. package/chunks/{enterPlanMode-WVJB4DSS.js → enterPlanMode-BC5QUZZ2.js} +43 -35
  174. package/chunks/{environment-6YHC4JAJ.js → environment-W5UFC2CH.js} +46 -38
  175. package/chunks/errors-M7CLORXH.js +88 -0
  176. package/chunks/{exit-worktree-KPFD742L.js → exit-worktree-DGNYMECB.js} +43 -35
  177. package/chunks/{exitPlanMode-UEJS6CDY.js → exitPlanMode-GXTBWQAR.js} +43 -35
  178. package/chunks/{fast-path-G2N4NRCA.js → fast-path-JJZFJANL.js} +6 -6
  179. package/chunks/{fast-path-settings-DAOVFADC.js → fast-path-settings-WQJU2LAT.js} +2 -2
  180. package/chunks/{fr-WVHEBDDB.js → fr-45RLL55O.js} +1 -0
  181. package/chunks/{gemini-2MDVIOVT.js → gemini-QS36EBZV.js} +132 -102
  182. package/chunks/{geminiContentGenerator-ZXTDBMFR.js → geminiContentGenerator-AG4KB6CV.js} +14 -8
  183. package/chunks/{getMachineId-bsd-QFVLPUPT.js → getMachineId-bsd-V7W3GODC.js} +1 -1
  184. package/chunks/{getMachineId-darwin-DGMQQE2E.js → getMachineId-darwin-TDO75DQP.js} +1 -1
  185. package/chunks/{getMachineId-linux-R4Z6CSWC.js → getMachineId-linux-TF43WQT2.js} +1 -1
  186. package/chunks/{getMachineId-unsupported-Z3SBVBUV.js → getMachineId-unsupported-ZGUO3TXT.js} +1 -1
  187. package/chunks/{getMachineId-win-SCK5UFDT.js → getMachineId-win-ECFYZZFQ.js} +1 -1
  188. package/chunks/{glob-562XFLIZ.js → glob-V7R3PSK3.js} +43 -35
  189. package/chunks/{grep-MGEFBDQK.js → grep-QYPSK7OP.js} +43 -35
  190. package/chunks/handleAutoUpdate-6DBEZYPV.js +81 -0
  191. package/chunks/{i18n-R6HJENXA.js → i18n-VUJJZIMU.js} +44 -36
  192. package/chunks/image-gen-Z3VPGKRC.js +240 -0
  193. package/chunks/initializer-UWAK5U5O.js +86 -0
  194. package/chunks/installationInfo-6O2YAA52.js +80 -0
  195. package/chunks/{ja-KY4ROZTE.js → ja-B7DF7DFG.js} +1 -0
  196. package/chunks/{keychain-token-storage-6ACJDYIB.js → keychain-token-storage-MDTG3WRM.js} +3 -3
  197. package/chunks/{kittyProtocolDetector-HCNNKJTI.js → kittyProtocolDetector-MBRTDRBK.js} +5 -3
  198. package/chunks/list-GB4ESM3T.js +89 -0
  199. package/chunks/list-agents-5KJJHR6I.js +80 -0
  200. package/chunks/loadedSettingsAdapter-OT6JVQ7U.js +83 -0
  201. package/chunks/loggingContentGenerator-HS3S5H3Q.js +1077 -0
  202. package/chunks/{loop-wakeup-RNMRVA66.js → loop-wakeup-FXKNNYSY.js} +7 -7
  203. package/chunks/{ls-J2ZI5XYK.js → ls-NTK6VOQJ.js} +5 -5
  204. package/chunks/{lsp-UMS3NUB5.js → lsp-2JI24STP.js} +3 -3
  205. package/chunks/{managed-npm-update-4KNYSOYC.js → managed-npm-update-JYEMMXA3.js} +94 -38
  206. package/chunks/mcp-6DBDJPFU.js +83 -0
  207. package/chunks/{monitor-DMHKE4SW.js → monitor-R3ODH5U6.js} +45 -36
  208. package/chunks/node-UUDY34IG.js +305 -0
  209. package/chunks/nonInteractiveCli-MOYCYBBU.js +141 -0
  210. package/chunks/{notebook-edit-35SJGEOR.js → notebook-edit-BNOK452R.js} +43 -35
  211. package/chunks/{openaiContentGenerator-5LPAFXPF.js → openaiContentGenerator-WMCU3O2H.js} +27 -17
  212. package/chunks/pidfile-TFRZZZIO.js +86 -0
  213. package/chunks/{processUtils-GM2I55KF.js → processUtils-RT7UNCC2.js} +2 -2
  214. package/chunks/{pt-OK455PLH.js → pt-22Q3FP73.js} +1 -0
  215. package/chunks/{qwenContentGenerator-HKOYNP7H.js → qwenContentGenerator-HHCRK4SX.js} +56 -42
  216. package/chunks/{qwenOAuth2-NUUYC3V5.js → qwenOAuth2-OWLB5AKH.js} +14 -27
  217. package/chunks/read-file-APMO3PSX.js +31 -0
  218. package/chunks/{read-mcp-resource-F6HYMDUY.js → read-mcp-resource-4DKQWGHD.js} +3 -3
  219. package/chunks/{record-artifact-7GCFLDD7.js → record-artifact-RQKFYO5B.js} +3 -3
  220. package/chunks/resumeHistoryUtils-6KRYEAWZ.js +91 -0
  221. package/chunks/ripGrep-BEJDEDXW.js +73 -0
  222. package/chunks/{ru-7SPDGMGD.js → ru-FZCNZHDC.js} +1 -0
  223. package/chunks/{run-qwen-serve-5VH3F4NW.js → run-qwen-serve-FU6HEM4J.js} +271 -57
  224. package/chunks/{runtime-OH77YH7W.js → runtime-XXRRTNP6.js} +55 -45
  225. package/chunks/{scheduler-WJQSLCSV.js → scheduler-G2ZS2Z7E.js} +43 -35
  226. package/chunks/{sdk-exporters-grpc-ETLH47EP.js → sdk-exporters-grpc-AK3LGHNO.js} +3 -3
  227. package/chunks/{sdk-exporters-http-T3POX73F.js → sdk-exporters-http-FYBSUCPD.js} +6 -6
  228. package/chunks/{sdk-impl-NSLPDH6I.js → sdk-impl-GMVPB7NB.js} +6 -6
  229. package/chunks/{send-message-PYIJ2PZL.js → send-message-Q6OOR6BR.js} +46 -9
  230. package/chunks/serve-7BSTXJ4T.js +89 -0
  231. package/chunks/{server-E4N4AI6Z.js → server-4UMH7OIZ.js} +2362 -411
  232. package/chunks/{session-5YUWIOQE.js → session-K3O3Q2SV.js} +105 -87
  233. package/chunks/{settings-YY7ZSFO7.js → settings-CR2EWTBA.js} +53 -45
  234. package/chunks/shell-HH3PF3A2.js +83 -0
  235. package/chunks/{skill-PAIDX3EU.js → skill-I3SDA4MB.js} +17 -16
  236. package/chunks/spawnChannel-RWNDBXGA.js +82 -0
  237. package/chunks/{src-IZXLJI5M.js → src-GE4TTTML.js} +302 -184
  238. package/chunks/{standalone-update-X675JVBL.js → standalone-update-Q6WFRZZQ.js} +45 -37
  239. package/chunks/{startInteractiveUI-ND2IVBU3.js → startInteractiveUI-SLZGHRPH.js} +747 -310
  240. package/chunks/{syntheticOutput-H7RTI5KL.js → syntheticOutput-I3757IWH.js} +4 -4
  241. package/chunks/{task-create-7474AJJD.js → task-create-N7WQSGYA.js} +10 -10
  242. package/chunks/{task-list-633HGOIB.js → task-list-FOPULZEP.js} +7 -7
  243. package/chunks/{task-stop-MNUGHPIA.js → task-stop-H6RHXFVQ.js} +4 -4
  244. package/chunks/{task-update-66GQB5LI.js → task-update-M57TFZJT.js} +10 -10
  245. package/chunks/{team-create-2DEYNMMN.js → team-create-YJALH5D2.js} +46 -38
  246. package/chunks/{team-delete-BB3CG3QF.js → team-delete-QE2UXJL7.js} +7 -7
  247. package/chunks/{team-plan-approval-65AVAOCT.js → team-plan-approval-34QFYKGN.js} +43 -35
  248. package/chunks/theme-manager-SWRILQHI.js +77 -0
  249. package/chunks/{todoWrite-KRAUN54W.js → todoWrite-VQ7FKOHL.js} +5 -5
  250. package/chunks/{tool-search-ZQP3SMTV.js → tool-search-NF7GB6LE.js} +16 -16
  251. package/chunks/total-session-admission-DLHHHLD3.js +84 -0
  252. package/chunks/{tree-sitter-FS4VPMZA.js → tree-sitter-4D7QS7F6.js} +1 -1
  253. package/chunks/{tree-sitter-bash-6B46JJCV.js → tree-sitter-bash-VEJGF5XF.js} +1 -1
  254. package/chunks/{trustedFolders-LURI52LP.js → trustedFolders-KHXHY6PY.js} +44 -36
  255. package/chunks/{update-relaunch-BPWFIDLM.js → update-relaunch-WBUZJC5O.js} +5 -5
  256. package/chunks/updateCheck-RKL6M5XN.js +92 -0
  257. package/chunks/useAutoAcceptIndicator-CFQ5BUJL.js +93 -0
  258. package/chunks/{validateNonInterActiveAuth-HWD6Y22I.js → validateNonInterActiveAuth-3R223G3R.js} +89 -80
  259. package/chunks/{version-OD4JAFG7.js → version-HS7YSFHV.js} +1 -1
  260. package/chunks/{web-fetch-RFBKNU24.js → web-fetch-NKCSG7ZE.js} +18 -16
  261. package/chunks/{web-search-AKTVS5YZ.js → web-search-S62WAP4S.js} +13 -27
  262. package/chunks/{workflow-VZVCOSZN.js → workflow-QAGU5RU4.js} +44 -36
  263. package/chunks/workspace-providers-status-QSVZUETE.js +86 -0
  264. package/chunks/{workspace-registration-store-Q5SFJSX4.js → workspace-registration-store-24JMHDGF.js} +2 -2
  265. package/chunks/workspace-registry-UT4RBNBM.js +88 -0
  266. package/chunks/workspace-service-JFWRUS4V.js +98 -0
  267. package/chunks/workspace-skills-status-ZBBKJOI2.js +85 -0
  268. package/chunks/write-file-VHIXW5M7.js +73 -0
  269. package/chunks/{zh-WY5DWYZD.js → zh-LUIGBD55.js} +15 -0
  270. package/chunks/{zh-TW-BM47YBFH.js → zh-TW-F5KG2IYD.js} +15 -0
  271. package/cli-entry.js +10 -1
  272. package/cli.js +13 -13
  273. package/locales/ca.js +2 -0
  274. package/locales/de.js +1 -0
  275. package/locales/en.js +25 -0
  276. package/locales/fr.js +1 -0
  277. package/locales/ja.js +1 -0
  278. package/locales/pt.js +1 -0
  279. package/locales/ru.js +1 -0
  280. package/locales/zh-TW.js +23 -0
  281. package/locales/zh.js +23 -0
  282. package/package.json +3 -3
  283. package/web-shell/assets/{arc-BWFm0SI0.js → arc-DcbWnB9T.js} +1 -1
  284. package/web-shell/assets/{architectureDiagram-3BPJPVTR-CZ_yL-DQ.js → architectureDiagram-3BPJPVTR-kMMF5sud.js} +1 -1
  285. package/web-shell/assets/{blockDiagram-GPEHLZMM-B9F9mJvG.js → blockDiagram-GPEHLZMM-Htl9vTJS.js} +1 -1
  286. package/web-shell/assets/{c4Diagram-AAUBKEIU-BUdwJW5f.js → c4Diagram-AAUBKEIU-BnZnm0mQ.js} +1 -1
  287. package/web-shell/assets/channel-Cq7YKtfC.js +1 -0
  288. package/web-shell/assets/{chunk-2J33WTMH-w4cF-qlF.js → chunk-2J33WTMH-DziB7kDG.js} +1 -1
  289. package/web-shell/assets/{chunk-4BX2VUAB-BXwURxHJ.js → chunk-4BX2VUAB-CmkD8daw.js} +1 -1
  290. package/web-shell/assets/{chunk-55IACEB6-Gem3LalC.js → chunk-55IACEB6-CHAd9A_U.js} +1 -1
  291. package/web-shell/assets/{chunk-727SXJPM-A3ddVojI.js → chunk-727SXJPM-Dqaam3fE.js} +1 -1
  292. package/web-shell/assets/{chunk-AQP2D5EJ-CjHZ5L_R.js → chunk-AQP2D5EJ-D_-saBYM.js} +1 -1
  293. package/web-shell/assets/{chunk-FMBD7UC4-CKgdgcpv.js → chunk-FMBD7UC4-B9r_veWD.js} +1 -1
  294. package/web-shell/assets/{chunk-ND2GUHAM-Cn2Dykjb.js → chunk-ND2GUHAM-B3EaCSpL.js} +1 -1
  295. package/web-shell/assets/{chunk-QZHKN3VN--0SyraC5.js → chunk-QZHKN3VN-CYq8x9mn.js} +1 -1
  296. package/web-shell/assets/classDiagram-4FO5ZUOK-CQ9aC1Tg.js +1 -0
  297. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CQ9aC1Tg.js +1 -0
  298. package/web-shell/assets/{cose-bilkent-S5V4N54A-CphhAity.js → cose-bilkent-S5V4N54A-D0ng4uiB.js} +1 -1
  299. package/web-shell/assets/{dagre-BM42HDAG-DU--jiKp.js → dagre-BM42HDAG-DCZollQv.js} +1 -1
  300. package/web-shell/assets/{diagram-2AECGRRQ-BzvuZw1Y.js → diagram-2AECGRRQ-Dfk2pWS0.js} +1 -1
  301. package/web-shell/assets/{diagram-5GNKFQAL-D84-49Y0.js → diagram-5GNKFQAL-kX38ltWR.js} +1 -1
  302. package/web-shell/assets/{diagram-KO2AKTUF-DQTq-3_3.js → diagram-KO2AKTUF-CJz2vsXh.js} +1 -1
  303. package/web-shell/assets/{diagram-LMA3HP47-8FTrshzN.js → diagram-LMA3HP47-BvMLZm_7.js} +1 -1
  304. package/web-shell/assets/{diagram-OG6HWLK6-BCjpDBCm.js → diagram-OG6HWLK6-l7kfStkO.js} +1 -1
  305. package/web-shell/assets/{erDiagram-TEJ5UH35-BtRObkmg.js → erDiagram-TEJ5UH35-BSVa8GGT.js} +1 -1
  306. package/web-shell/assets/{flowDiagram-I6XJVG4X-DTrW6oxy.js → flowDiagram-I6XJVG4X-CoawKIXH.js} +1 -1
  307. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BgPNSW6j.js → ganttDiagram-6RSMTGT7-DFUDH0zF.js} +1 -1
  308. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BTclNgGV.js → gitGraphDiagram-PVQCEYII-Y2pvpT4e.js} +1 -1
  309. package/web-shell/assets/{index-CxA7AqY6.js → index-D0GX0zZf.js} +1 -1
  310. package/web-shell/assets/index-D9haPt0X.css +5 -0
  311. package/web-shell/assets/index-ckX9Pq5k.js +1230 -0
  312. package/web-shell/assets/{infoDiagram-5YYISTIA-DCE4AJt2.js → infoDiagram-5YYISTIA-CU8_zLiX.js} +1 -1
  313. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-C8iE6q4Y.js → ishikawaDiagram-YF4QCWOH-AVQiV0DU.js} +1 -1
  314. package/web-shell/assets/{journeyDiagram-JHISSGLW-C_dxdyEc.js → journeyDiagram-JHISSGLW-DQ0VSKa3.js} +1 -1
  315. package/web-shell/assets/{kanban-definition-UN3LZRKU-Dw3n1u3w.js → kanban-definition-UN3LZRKU-BqnWqsE_.js} +1 -1
  316. package/web-shell/assets/{linear-C2BF2zJ9.js → linear-BkoihsaA.js} +1 -1
  317. package/web-shell/assets/{mermaid.core-CGTQU3MA.js → mermaid.core-5RJs-31j.js} +5 -5
  318. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BVFZm9ZC.js → mindmap-definition-RKZ34NQL-D33Bxnpd.js} +1 -1
  319. package/web-shell/assets/{pieDiagram-4H26LBE5-Cc-TNN3n.js → pieDiagram-4H26LBE5-BuEAw3BH.js} +1 -1
  320. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-CgW3Rzsi.js → quadrantDiagram-W4KKPZXB-Kox_usEq.js} +1 -1
  321. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BAaj0Y3B.js → requirementDiagram-4Y6WPE33-CNjeUif0.js} +1 -1
  322. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-XJWmekxS.js → sankeyDiagram-5OEKKPKP-BCd2OL_U.js} +1 -1
  323. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CtRc_0wf.js → sequenceDiagram-3UESZ5HK-CF2ZTsz0.js} +1 -1
  324. package/web-shell/assets/{stateDiagram-AJRCARHV-WCnvMGy5.js → stateDiagram-AJRCARHV-qenSzHtm.js} +1 -1
  325. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-B7W4zlCr.js +1 -0
  326. package/web-shell/assets/{timeline-definition-PNZ67QCA-C9cRx49L.js → timeline-definition-PNZ67QCA-B5DyWdgs.js} +1 -1
  327. package/web-shell/assets/{vennDiagram-CIIHVFJN-BvXOCEt-.js → vennDiagram-CIIHVFJN-DqP4I_o_.js} +1 -1
  328. package/web-shell/assets/{wardley-L42UT6IY-ByafGtzu.js → wardley-L42UT6IY-CJe2e4mg.js} +1 -1
  329. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-CozAnw8x.js → wardleyDiagram-YWT4CUSO-BMDSw-Rr.js} +1 -1
  330. package/web-shell/assets/{xychartDiagram-2RQKCTM6-Camu9Qvq.js → xychartDiagram-2RQKCTM6-BTVZYkxD.js} +1 -1
  331. package/web-shell/index.html +17 -13
  332. package/chunks/MaxSizedBox-3XQIBACV.js +0 -78
  333. package/chunks/agent-QXD5NSKA.js +0 -73
  334. package/chunks/agent-headless-4VXR2TBK.js +0 -67
  335. package/chunks/bridge-GIBRSPE6.js +0 -81
  336. package/chunks/chunk-CBOQ3HY7.js +0 -2019
  337. package/chunks/chunk-MA6GYKK7.js +0 -6928
  338. package/chunks/contextCommand-XQU7KLIH.js +0 -72
  339. package/chunks/daemon-status-provider-KQVNB4VA.js +0 -80
  340. package/chunks/earlyInputCapture-WP5SA3KH.js +0 -74
  341. package/chunks/errors-JEYPXX4S.js +0 -80
  342. package/chunks/handleAutoUpdate-2VJPAW43.js +0 -73
  343. package/chunks/initializer-UOX67ZFQ.js +0 -78
  344. package/chunks/installationInfo-NQNY34X3.js +0 -72
  345. package/chunks/list-2Z7KS7ZF.js +0 -81
  346. package/chunks/loadedSettingsAdapter-LIYY3LE4.js +0 -75
  347. package/chunks/mcp-AJ4QW3JA.js +0 -75
  348. package/chunks/nonInteractiveCli-PUSO5QF6.js +0 -134
  349. package/chunks/pidfile-EH2JW2PB.js +0 -78
  350. package/chunks/read-file-JZ5VXILQ.js +0 -31
  351. package/chunks/resumeHistoryUtils-Z3HG4WKM.js +0 -84
  352. package/chunks/ripGrep-JNLJCT2B.js +0 -65
  353. package/chunks/serve-NN5FXWR6.js +0 -81
  354. package/chunks/shell-FXT3NVC6.js +0 -75
  355. package/chunks/spawnChannel-XAWLXNOD.js +0 -74
  356. package/chunks/theme-manager-2WZHPK2M.js +0 -69
  357. package/chunks/total-session-admission-HULB2TEQ.js +0 -75
  358. package/chunks/updateCheck-D4ESCHBJ.js +0 -88
  359. package/chunks/useAutoAcceptIndicator-CBNLOF2P.js +0 -86
  360. package/chunks/workspace-providers-status-TJTVHORI.js +0 -78
  361. package/chunks/workspace-registry-H6VM5WXK.js +0 -79
  362. package/chunks/workspace-service-ZNKD3I2J.js +0 -90
  363. package/chunks/workspace-skills-status-OOBIXADG.js +0 -77
  364. package/chunks/write-file-CAKK5IAO.js +0 -65
  365. package/web-shell/assets/channel-DiLlxxIf.js +0 -1
  366. package/web-shell/assets/classDiagram-4FO5ZUOK-CkylTdM4.js +0 -1
  367. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CkylTdM4.js +0 -1
  368. package/web-shell/assets/index-CGtQqOIa.css +0 -5
  369. package/web-shell/assets/index-TtM0hVjU.js +0 -1207
  370. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-D1gzH2Ue.js +0 -1
@@ -8,21 +8,24 @@ import {
8
8
  formatWorkspaceMemoryDreamSummary,
9
9
  formatWorkspaceMemoryForgetSummary,
10
10
  isValidServerName,
11
+ normalizeChannelDelivery,
12
+ parseChannelDelivery,
11
13
  redactMcpServersSetting,
12
14
  replayTranscriptRecordPage,
13
15
  restoreRedactedMcpServersSetting,
14
16
  shouldSuppressRememberErrorDetails,
15
17
  workspaceMemoryFailureCode,
16
18
  workspaceMemoryFailureDiagnostics
17
- } from "./chunk-TJDW42MV.js";
19
+ } from "./chunk-RIBKPMRP.js";
18
20
  import {
19
21
  openQwenAsrRealtimeStream,
20
22
  openVoiceStream,
21
23
  openVoiceStreamWithRetry
22
- } from "./chunk-ZHERRXZJ.js";
24
+ } from "./chunk-BJX6ZSUK.js";
23
25
  import {
24
26
  SetupGithubError,
25
27
  collectSessionData,
28
+ createTranscriptMessageUpdate,
26
29
  generateExportFilename,
27
30
  normalizeSessionData,
28
31
  setupGithub,
@@ -30,21 +33,66 @@ import {
30
33
  toJson,
31
34
  toJsonl,
32
35
  toMarkdown
33
- } from "./chunk-JC26SJ5Y.js";
36
+ } from "./chunk-EBJQ6AXW.js";
34
37
  import {
35
38
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
36
39
  ObservedChannelContactStore
37
- } from "./chunk-4K7VDKAD.js";
38
- import "./chunk-LNDD3IML.js";
39
- import "./chunk-RS7MT2QG.js";
40
- import "./chunk-H2XVO6NE.js";
40
+ } from "./chunk-RHLZR4E5.js";
41
+ import "./chunk-IPUUTYMV.js";
42
+ import "./chunk-WCXCRJYB.js";
43
+ import "./chunk-2MIN6GRR.js";
41
44
  import "./chunk-QHTIBUWB.js";
42
45
  import "./chunk-QTERJVPZ.js";
43
46
  import "./chunk-3Z43GZUQ.js";
47
+ import {
48
+ EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
49
+ MAX_WORKSPACE_SKILL_NAME_LENGTH,
50
+ WorkspaceSkillManagementError,
51
+ WorkspaceVoiceError,
52
+ buildWorkspaceVoiceSettingsWrites,
53
+ buildWorkspaceVoiceStatus,
54
+ createDaemonWorkspaceService,
55
+ hasConfiguredBatchVoiceTranscriptionModel,
56
+ transcribeWorkspaceVoiceAudio,
57
+ validateWorkspaceSkillName,
58
+ validateWorkspaceVoiceState,
59
+ voiceSettingsScopeToWire
60
+ } from "./chunk-TGILQ3YH.js";
61
+ import {
62
+ PermissionRulesValidationError,
63
+ buildPermissionSettings,
64
+ isPermissionRuleType,
65
+ normalizePermissionRules,
66
+ readPermissionRuleSet
67
+ } from "./chunk-VRYUBFMC.js";
68
+ import {
69
+ assertVoiceBaseUrlNetworkAllowed,
70
+ isStreamingVoiceModel,
71
+ resolveVoiceStreamConfig,
72
+ resolveVoiceTranscriptionConfig,
73
+ sanitizeVoiceErrorMessage,
74
+ transcribeVoiceAudio
75
+ } from "./chunk-H4SBPHSA.js";
76
+ import {
77
+ isVoiceEnabled,
78
+ isVoiceMode,
79
+ readVoiceModel
80
+ } from "./chunk-YBL3QUDD.js";
81
+ import "./chunk-ZD6UTE4A.js";
82
+ import {
83
+ WorkspacePermissionRulesSessionRequiredError,
84
+ WorkspaceSettingsPartialPersistError,
85
+ WorkspaceSkillNotFoundError,
86
+ WorkspaceSkillNotToggleableError
87
+ } from "./chunk-OA4JVLSA.js";
88
+ import {
89
+ createTotalSessionAdmissionController
90
+ } from "./chunk-VYPFXUCB.js";
44
91
  import {
45
92
  createSingleWorkspaceRegistry,
46
93
  createWorkspaceSessionOwnerIndex
47
94
  } from "./chunk-UGYMA4EI.js";
95
+ import "./chunk-GRC5HGPI.js";
48
96
  import {
49
97
  CAPABILITIES_SCHEMA_VERSION,
50
98
  CLIENT_ID_HEADER,
@@ -102,87 +150,33 @@ import {
102
150
  setRateLimiter,
103
151
  unsafeRevealSecret,
104
152
  validateMcpRuntimeServerName
105
- } from "./chunk-5G3ZVADU.js";
153
+ } from "./chunk-IJTOWOD7.js";
106
154
  import {
107
155
  isLoopbackBind
108
156
  } from "./chunk-RXFQM6FQ.js";
157
+ import {
158
+ daemonObservedContactsPath,
159
+ loadChannelsConfig
160
+ } from "./chunk-PSOO6YXD.js";
161
+ import "./chunk-PC6JANNU.js";
162
+ import "./chunk-57OAHC2Y.js";
109
163
  import {
110
164
  createDaemonStatusProvider
111
- } from "./chunk-46DK772E.js";
165
+ } from "./chunk-J24WCGIN.js";
112
166
  import "./chunk-LXXMOYPL.js";
113
- import "./chunk-3HFNGB2O.js";
167
+ import "./chunk-MVSUYZDT.js";
114
168
  import "./chunk-E5Z2AVNV.js";
115
- import {
116
- createWorkspaceProvidersStatusProvider
117
- } from "./chunk-NWZY2SPY.js";
118
- import {
119
- getAuthTypeFromEnv,
120
- resolveCliGenerationConfig
121
- } from "./chunk-JZSM2IZ3.js";
122
- import {
123
- snapshotProcessEnv
124
- } from "./chunk-FUFCALSJ.js";
125
- import {
126
- createWorkspaceSkillsStatusProvider
127
- } from "./chunk-YO2XRXY6.js";
128
- import "./chunk-2W3OOD4W.js";
129
- import {
130
- EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
131
- MAX_WORKSPACE_SKILL_NAME_LENGTH,
132
- WorkspaceSkillManagementError,
133
- WorkspaceVoiceError,
134
- buildWorkspaceVoiceSettingsWrites,
135
- buildWorkspaceVoiceStatus,
136
- createDaemonWorkspaceService,
137
- hasConfiguredBatchVoiceTranscriptionModel,
138
- transcribeWorkspaceVoiceAudio,
139
- validateWorkspaceSkillName,
140
- validateWorkspaceVoiceState,
141
- voiceSettingsScopeToWire
142
- } from "./chunk-PQIVAWXN.js";
143
- import {
144
- PermissionRulesValidationError,
145
- buildPermissionSettings,
146
- isPermissionRuleType,
147
- normalizePermissionRules,
148
- readPermissionRuleSet
149
- } from "./chunk-EBXZ2YGV.js";
150
- import {
151
- assertVoiceBaseUrlNetworkAllowed,
152
- isStreamingVoiceModel,
153
- resolveVoiceStreamConfig,
154
- resolveVoiceTranscriptionConfig,
155
- sanitizeVoiceErrorMessage,
156
- transcribeVoiceAudio
157
- } from "./chunk-MLYGPZGU.js";
158
- import {
159
- isVoiceEnabled,
160
- isVoiceMode,
161
- readVoiceModel
162
- } from "./chunk-7NR2AIK6.js";
163
- import "./chunk-QLJUC7TG.js";
164
- import {
165
- WorkspacePermissionRulesSessionRequiredError,
166
- WorkspaceSettingsPartialPersistError,
167
- WorkspaceSkillNotFoundError,
168
- WorkspaceSkillNotToggleableError
169
- } from "./chunk-OA4JVLSA.js";
170
- import {
171
- createTotalSessionAdmissionController
172
- } from "./chunk-VYPFXUCB.js";
173
- import "./chunk-GRC5HGPI.js";
174
169
  import {
175
170
  SessionArtifactAuthorizationError,
176
171
  SessionArtifactValidationError,
177
172
  createAcpSessionBridge,
178
173
  parseSessionSource
179
- } from "./chunk-QOZOIPSF.js";
174
+ } from "./chunk-KIM5GUMA.js";
180
175
  import {
181
176
  EVENT_SCHEMA_VERSION,
177
+ EventBus,
182
178
  SubscriberLimitExceededError
183
- } from "./chunk-6RLROE6G.js";
184
- import "./chunk-COH43MRJ.js";
185
- import "./chunk-QR6U5QPP.js";
179
+ } from "./chunk-GLWP3FDB.js";
186
180
  import {
187
181
  BranchWhilePromptActiveError,
188
182
  CancelSentinelCollisionError,
@@ -216,24 +210,35 @@ import {
216
210
  WorkspaceInitSymlinkError,
217
211
  WorkspaceMismatchError
218
212
  } from "./chunk-UH3WSE5L.js";
219
- import "./chunk-WBL3FJEU.js";
213
+ import "./chunk-COH43MRJ.js";
214
+ import "./chunk-3SJ43L4W.js";
215
+ import "./chunk-7JURR4JT.js";
220
216
  import {
221
- daemonObservedContactsPath,
222
- loadChannelsConfig
223
- } from "./chunk-RECUEJ7B.js";
224
- import "./chunk-7THPNISK.js";
225
- import "./chunk-57OAHC2Y.js";
217
+ createWorkspaceProvidersStatusProvider
218
+ } from "./chunk-FSITMZJH.js";
226
219
  import {
227
- parseChannelWebhookConfigLenient
228
- } from "./chunk-GHRSKGHF.js";
229
- import "./chunk-6ZBPS62S.js";
230
- import "./chunk-V6WHFGST.js";
231
- import "./chunk-FZPTCQY7.js";
220
+ getAuthTypeFromEnv,
221
+ resolveCliGenerationConfig
222
+ } from "./chunk-KMQ33DO4.js";
223
+ import {
224
+ snapshotProcessEnv
225
+ } from "./chunk-ETSW4KLJ.js";
226
+ import {
227
+ createWorkspaceSkillsStatusProvider
228
+ } from "./chunk-ACY3A37B.js";
229
+ import "./chunk-2W3OOD4W.js";
232
230
  import {
233
231
  STATUS_SCHEMA_VERSION,
234
232
  createIdleWorkspaceMemoryStatus,
235
233
  mapDomainErrorToErrorKind
236
- } from "./chunk-O4BHWVUD.js";
234
+ } from "./chunk-VIA5XA4U.js";
235
+ import "./chunk-WBL3FJEU.js";
236
+ import "./chunk-T2NCM2ET.js";
237
+ import {
238
+ parseChannelWebhookConfigLenient
239
+ } from "./chunk-4WIZGAH3.js";
240
+ import "./chunk-7ZCNENPP.js";
241
+ import "./chunk-V6WHFGST.js";
237
242
  import {
238
243
  MAX_REGISTERED_WORKSPACES,
239
244
  WorkspaceDisplayNameValidationError,
@@ -241,7 +246,7 @@ import {
241
246
  WorkspaceRegistrationStoreLimitError,
242
247
  normalizeWorkspaceDisplayName,
243
248
  workspaceRegistrationId
244
- } from "./chunk-7AUH6A4T.js";
249
+ } from "./chunk-Q4M4MDQ4.js";
245
250
  import {
246
251
  MAX_WORKSPACE_PATH_LENGTH,
247
252
  canonicalizeWorkspace,
@@ -249,26 +254,28 @@ import {
249
254
  translateAndCheckAbsoluteWorkspacePath
250
255
  } from "./chunk-2RFKHEXL.js";
251
256
  import {
257
+ ChannelDeliveryError,
252
258
  MAX_CHANNEL_STARTUP_FAILURES,
253
259
  MAX_CHANNEL_STARTUP_FAILURE_CHANNEL_LENGTH,
254
260
  MAX_CHANNEL_STARTUP_FAILURE_CODE_LENGTH,
255
261
  MAX_CHANNEL_STARTUP_FAILURE_MESSAGE_LENGTH,
256
262
  QWEN_SERVER_TOKEN_ENV,
263
+ isChannelDeliveryError,
257
264
  isChannelWebhookEnqueueError,
258
265
  normalizeWorkerDiagnostic
259
- } from "./chunk-QKTHJXCS.js";
266
+ } from "./chunk-LK7CHLVP.js";
260
267
  import {
261
268
  normalizeServeChannelSelection
262
- } from "./chunk-TJTKSVIV.js";
269
+ } from "./chunk-JLU636DO.js";
270
+ import "./chunk-BK2UNYWD.js";
263
271
  import {
264
272
  redactLogCredentials
265
273
  } from "./chunk-M5GB774H.js";
266
- import "./chunk-5HBA2Z7V.js";
267
- import "./chunk-T2NCM2ET.js";
268
274
  import {
269
275
  sanitizeLogText
270
- } from "./chunk-RVLZCXEE.js";
276
+ } from "./chunk-RWTEFFPU.js";
271
277
  import "./chunk-UDXSXLER.js";
278
+ import "./chunk-5HBA2Z7V.js";
272
279
  import {
273
280
  getDialogSettingKeys,
274
281
  getModelProvidersOwnerScope,
@@ -278,23 +285,23 @@ import {
278
285
  getWritableScopes,
279
286
  loadSettings,
280
287
  validateSettingValue
281
- } from "./chunk-XCXYRDHB.js";
288
+ } from "./chunk-TEHGS6UP.js";
282
289
  import "./chunk-RKUWKYED.js";
290
+ import "./chunk-GOXKNSDZ.js";
291
+ import "./chunk-IDS7MSUP.js";
283
292
  import {
284
293
  SUPPORTED_LANGUAGES,
285
294
  detectSystemLanguage,
286
295
  resolveLanguageSetting,
287
296
  resolveSupportedLanguage
288
- } from "./chunk-VRRF3GW5.js";
289
- import "./chunk-RWV32G2M.js";
290
- import "./chunk-GOXKNSDZ.js";
291
- import "./chunk-IDS7MSUP.js";
292
- import "./chunk-QRUIS3DN.js";
293
- import "./chunk-3EK5ZOUQ.js";
297
+ } from "./chunk-LKEJ26GS.js";
298
+ import "./chunk-LH2BYDQ5.js";
299
+ import "./chunk-6PEXNQTX.js";
300
+ import "./chunk-YX324OPW.js";
294
301
  import "./chunk-VJNBRRZG.js";
295
302
  import {
296
303
  getWorkspaceTrustStatus
297
- } from "./chunk-4PTLZ3NX.js";
304
+ } from "./chunk-Z2BC6UJ5.js";
298
305
  import "./chunk-ALGGS7UH.js";
299
306
  import {
300
307
  isWithinRoot as isWithinRoot2
@@ -345,10 +352,12 @@ import {
345
352
  fetchGitDiffHunksForFile,
346
353
  fetchGitLog,
347
354
  getGitWorkingTreeStatus,
355
+ getSubagentSessionDir,
348
356
  glob,
349
357
  loadIgnoreRules,
350
358
  loadUsageHistoryWithLive,
351
359
  parseInstallSource,
360
+ readAgentMeta,
352
361
  readWorktreeSession,
353
362
  redactUrlCredentials,
354
363
  resolveBranchName,
@@ -360,23 +369,19 @@ import {
360
369
  writeWorkspaceContextFile,
361
370
  writeWorktreeSession,
362
371
  writeWorktreeSessionMarker
363
- } from "./chunk-OTQ6PSZC.js";
364
- import "./chunk-T4TZQJ7W.js";
365
- import "./chunk-H6XPXXMH.js";
372
+ } from "./chunk-PHOF65IG.js";
366
373
  import "./chunk-5M6IDOMF.js";
367
- import "./chunk-T2L47JJK.js";
368
- import "./chunk-GPSKDNEE.js";
369
- import "./chunk-X6N25LXS.js";
370
- import "./chunk-E2UVIFI2.js";
371
- import "./chunk-T5IO6FZ4.js";
374
+ import "./chunk-TWPJO254.js";
375
+ import "./chunk-H6XPXXMH.js";
376
+ import "./chunk-K4XWPEWB.js";
372
377
  import {
373
378
  MAX_JOBS,
374
379
  nextDurableFireMs
375
- } from "./chunk-Q2YKNMLS.js";
380
+ } from "./chunk-TOFQCPDC.js";
376
381
  import {
377
382
  nextFireTime,
378
383
  parseCron
379
- } from "./chunk-XU457J4V.js";
384
+ } from "./chunk-IRH27ZC2.js";
380
385
  import "./chunk-VDDGDZMA.js";
381
386
  import {
382
387
  appendCronRun,
@@ -385,22 +390,27 @@ import {
385
390
  readCronTasks,
386
391
  taskHasLegacyCondition,
387
392
  updateCronTasks
388
- } from "./chunk-KHOVYUHX.js";
389
- import "./chunk-SZRN75WQ.js";
393
+ } from "./chunk-FNQ6T3CV.js";
394
+ import "./chunk-ZOIFNCKL.js";
395
+ import "./chunk-PWTZEM3C.js";
396
+ import "./chunk-KRXPRVGL.js";
390
397
  import "./chunk-6PVPNMXU.js";
398
+ import "./chunk-MZAXJAUM.js";
399
+ import "./chunk-SZRN75WQ.js";
400
+ import "./chunk-HTO4JFDZ.js";
391
401
  import "./chunk-CPBF7KYF.js";
392
- import "./chunk-NABLFI57.js";
393
- import "./chunk-QBUDF33N.js";
394
- import "./chunk-LIZRAKPB.js";
395
402
  import {
396
403
  APPROVAL_MODES,
397
404
  SubagentError,
398
405
  SubagentErrorCode
399
- } from "./chunk-WHGVTP7Q.js";
406
+ } from "./chunk-L26JL52R.js";
400
407
  import "./chunk-6AM5D4ME.js";
408
+ import "./chunk-JZA3JUDJ.js";
409
+ import "./chunk-3QMGYBFN.js";
401
410
  import "./chunk-JCW2R7WC.js";
402
- import "./chunk-57FIIFJN.js";
403
- import "./chunk-HTO4JFDZ.js";
411
+ import "./chunk-M5JM7OSF.js";
412
+ import "./chunk-OHNBB4XR.js";
413
+ import "./chunk-E5TUC6CA.js";
404
414
  import {
405
415
  QwenOAuth2Client,
406
416
  QwenOAuthPollError,
@@ -409,57 +419,69 @@ import {
409
419
  isDeviceAuthorizationSuccess,
410
420
  isDeviceTokenPending,
411
421
  isDeviceTokenSuccess
412
- } from "./chunk-RCWKCN2Z.js";
422
+ } from "./chunk-EPDRMGT4.js";
413
423
  import "./chunk-JESCGQM3.js";
414
- import "./chunk-QKNXKTZX.js";
415
- import "./chunk-LW2FUYBN.js";
424
+ import "./chunk-NH6KE4JX.js";
425
+ import "./chunk-USTWD7QV.js";
416
426
  import "./chunk-XVNQMZ2I.js";
417
- import "./chunk-CR3C7WXL.js";
418
427
  import "./chunk-FODK6UMO.js";
419
428
  import "./chunk-GLNBDYUX.js";
420
429
  import "./chunk-DJ2GSRLV.js";
430
+ import "./chunk-ZJHVAS7M.js";
421
431
  import {
422
432
  addDaemonRequestAttribute,
423
- decodeBufferWithEncodingInfo,
424
433
  emitDaemonLog,
425
- getAllGeminiMdFilenames,
426
434
  hashDaemonWorkspace,
427
- isBinaryFile,
428
- isWithinRoot,
429
435
  recordDaemonBridgeError,
430
436
  recordDaemonError,
431
437
  recordDaemonHttpRequest,
432
438
  recordDaemonHttpResponse,
433
439
  withDaemonRequestSpan
434
- } from "./chunk-ZDP2Y2AL.js";
440
+ } from "./chunk-NIBLUX3Y.js";
441
+ import "./chunk-BPJSQIJX.js";
442
+ import "./chunk-P3QQPMQA.js";
443
+ import "./chunk-6FGBXPWM.js";
444
+ import "./chunk-LS77BEZP.js";
445
+ import "./chunk-CR3C7WXL.js";
446
+ import {
447
+ decodeBufferWithEncodingInfo,
448
+ getAllGeminiMdFilenames,
449
+ isBinaryFile,
450
+ isWithinRoot,
451
+ parseLineTolerant,
452
+ read
453
+ } from "./chunk-CIKQ7KKO.js";
435
454
  import "./chunk-VGC4I5JJ.js";
436
- import "./chunk-4K56OJFJ.js";
437
- import "./chunk-CBOQ3HY7.js";
455
+ import "./chunk-MUP3T3AD.js";
456
+ import "./chunk-IKCX4CCL.js";
457
+ import "./chunk-46UV252V.js";
438
458
  import "./chunk-A4UCTEB5.js";
439
459
  import "./chunk-XWRJCPHC.js";
440
- import "./chunk-QNLNLENL.js";
441
- import "./chunk-6X4GWOPW.js";
442
- import "./chunk-TYQMGACW.js";
443
- import {
444
- import_websocket_server
445
- } from "./chunk-TYAMGABM.js";
446
- import "./chunk-FCMNKVXT.js";
447
- import "./chunk-7362QS5B.js";
460
+ import "./chunk-UW5EOVUN.js";
461
+ import "./chunk-2JZBVYTU.js";
462
+ import "./chunk-5I2IWRSH.js";
463
+ import "./chunk-A5L3JMUA.js";
464
+ import "./chunk-MB4MZHMJ.js";
448
465
  import "./chunk-HTR4WV6U.js";
449
- import "./chunk-M7WBGLYP.js";
466
+ import "./chunk-BULDBTYC.js";
450
467
  import "./chunk-U7ZFW55U.js";
451
- import "./chunk-NPQDJGKU.js";
452
- import "./chunk-YM3SZTH4.js";
468
+ import "./chunk-UUUTRMI2.js";
469
+ import "./chunk-PR75REBZ.js";
453
470
  import {
454
471
  FatalConfigError,
455
472
  Storage,
456
473
  createDebugLogger,
457
474
  runWithoutDebugLogSession
458
- } from "./chunk-OQB4EXO4.js";
475
+ } from "./chunk-NL7LTRLR.js";
459
476
  import "./chunk-75DOP5OR.js";
460
477
  import "./chunk-DMTGGOSA.js";
461
478
  import "./chunk-YQ3U5MUC.js";
462
- import "./chunk-THJNPLI4.js";
479
+ import {
480
+ import_websocket_server
481
+ } from "./chunk-TYAMGABM.js";
482
+ import "./chunk-FCMNKVXT.js";
483
+ import "./chunk-AMDSOFFV.js";
484
+ import "./chunk-TARRHLLG.js";
463
485
  import {
464
486
  init_esbuild_shims
465
487
  } from "./chunk-5O2XNYP6.js";
@@ -651,9 +673,9 @@ async function findExistingAncestor(absolute) {
651
673
  let current = absolute;
652
674
  const tailParts = [];
653
675
  for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
654
- let stat2 = null;
676
+ let stat3 = null;
655
677
  try {
656
- stat2 = await fsp.stat(current);
678
+ stat3 = await fsp.stat(current);
657
679
  } catch (err) {
658
680
  const code = err?.code;
659
681
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -661,8 +683,8 @@ async function findExistingAncestor(absolute) {
661
683
  throw err;
662
684
  }
663
685
  }
664
- if (stat2) {
665
- if (tailParts.length > 0 && !stat2.isDirectory()) {
686
+ if (stat3) {
687
+ if (tailParts.length > 0 && !stat3.isDirectory()) {
666
688
  throw new FsError(
667
689
  "parse_error",
668
690
  `path component is not a directory: ${absolute}`,
@@ -735,7 +757,7 @@ async function resolveWithinWorkspace(input, boundWorkspaces, intent) {
735
757
  boundCanonicals
736
758
  );
737
759
  if (boundCanonical !== void 0) {
738
- const finalPathIsSymlink = await fsp.lstat(absolute).then((stat2) => stat2.isSymbolicLink()).catch((lstatErr) => {
760
+ const finalPathIsSymlink = await fsp.lstat(absolute).then((stat3) => stat3.isSymbolicLink()).catch((lstatErr) => {
739
761
  if (lstatErr.code === "ENOENT" || lstatErr.code === "ENOTDIR") {
740
762
  return false;
741
763
  }
@@ -1226,8 +1248,8 @@ var WorkspaceFileSystemImpl = class {
1226
1248
  const toRead = Math.min(maxBytes, available);
1227
1249
  buf = Buffer.allocUnsafe(toRead);
1228
1250
  if (toRead > 0) {
1229
- const read = await fh.read(buf, 0, toRead, offset);
1230
- buf = read.bytesRead === toRead ? buf : buf.subarray(0, read.bytesRead);
1251
+ const read2 = await fh.read(buf, 0, toRead, offset);
1252
+ buf = read2.bytesRead === toRead ? buf : buf.subarray(0, read2.bytesRead);
1231
1253
  }
1232
1254
  const afterRead = await fh.stat();
1233
1255
  assertSameFile(st, afterRead, p, "read");
@@ -1768,17 +1790,17 @@ var WorkspaceFileSystemImpl = class {
1768
1790
  * for their `sendFsError` serializer.
1769
1791
  */
1770
1792
  recordAndWrap(err, intent, input) {
1771
- const fs5 = wrapAsFsError(err);
1793
+ const fs6 = wrapAsFsError(err);
1772
1794
  this.deps.audit.recordDenied(this.deps.ctx, {
1773
1795
  intent,
1774
1796
  input,
1775
- errorKind: fs5.kind,
1776
- hint: fs5.hint,
1797
+ errorKind: fs6.kind,
1798
+ hint: fs6.hint,
1777
1799
  // Quote the underlying OS / FsError message so audit
1778
1800
  // consumers debugging a production incident can see the
1779
1801
  // actual cause (errno text, byte counts, glob pattern,
1780
1802
  // etc.) rather than just `errorKind` + `hint`.
1781
- message: fs5.message,
1803
+ message: fs6.message,
1782
1804
  // For glob denials (parse_error pattern rejection,
1783
1805
  // catastrophic walk failures) the input IS the pattern
1784
1806
  // already; surfacing it on the dedicated `pattern` field
@@ -1787,7 +1809,7 @@ var WorkspaceFileSystemImpl = class {
1787
1809
  // branching on intent.
1788
1810
  pattern: intent === "glob" ? input : void 0
1789
1811
  });
1790
- return fs5;
1812
+ return fs6;
1791
1813
  }
1792
1814
  };
1793
1815
  var CONTENT_HASH_RE = /^sha256:[0-9a-f]{64}$/;
@@ -1895,9 +1917,9 @@ async function readStableRegularFileBuffer(p, pre) {
1895
1917
  const out = Buffer.alloc(opened.size);
1896
1918
  let offset = 0;
1897
1919
  while (offset < opened.size) {
1898
- const read = await fh.read(out, offset, opened.size - offset, offset);
1899
- if (read.bytesRead === 0) break;
1900
- offset += read.bytesRead;
1920
+ const read2 = await fh.read(out, offset, opened.size - offset, offset);
1921
+ if (read2.bytesRead === 0) break;
1922
+ offset += read2.bytesRead;
1901
1923
  }
1902
1924
  const afterRead = await fh.stat();
1903
1925
  assertSameFile(opened, afterRead, p, "read");
@@ -2152,15 +2174,15 @@ async function hashRegularFileAtPath(p, pre) {
2152
2174
  const buf = Buffer.allocUnsafe(64 * 1024);
2153
2175
  let offset = 0;
2154
2176
  while (offset < opened.size) {
2155
- const read = await fh.read(
2177
+ const read2 = await fh.read(
2156
2178
  buf,
2157
2179
  0,
2158
2180
  Math.min(buf.length, opened.size - offset),
2159
2181
  offset
2160
2182
  );
2161
- if (read.bytesRead === 0) break;
2162
- hash.update(buf.subarray(0, read.bytesRead));
2163
- offset += read.bytesRead;
2183
+ if (read2.bytesRead === 0) break;
2184
+ hash.update(buf.subarray(0, read2.bytesRead));
2185
+ offset += read2.bytesRead;
2164
2186
  }
2165
2187
  } finally {
2166
2188
  await fh.close();
@@ -2524,12 +2546,12 @@ __name(applyReadHeaders, "applyReadHeaders");
2524
2546
  function sendFsError(res, err, route) {
2525
2547
  applyReadHeaders(res);
2526
2548
  if (isFsError(err)) {
2527
- const fs5 = err;
2528
- res.status(fs5.status).json({
2529
- errorKind: fs5.kind,
2530
- error: fs5.message,
2531
- hint: fs5.hint,
2532
- status: fs5.status
2549
+ const fs6 = err;
2550
+ res.status(fs6.status).json({
2551
+ errorKind: fs6.kind,
2552
+ error: fs6.message,
2553
+ hint: fs6.hint,
2554
+ status: fs6.status
2533
2555
  });
2534
2556
  return;
2535
2557
  }
@@ -2631,13 +2653,13 @@ async function handleGetFile(req, res, deps) {
2631
2653
  });
2632
2654
  return;
2633
2655
  }
2634
- const fs5 = factory.forRequest({
2656
+ const fs6 = factory.forRequest({
2635
2657
  originatorClientId: clientId ?? void 0,
2636
2658
  route: ROUTE2
2637
2659
  });
2638
2660
  try {
2639
- const resolved = await fs5.resolve(queryPath, "read");
2640
- const out = await fs5.readText(resolved, { maxBytes, line, limit });
2661
+ const resolved = await fs6.resolve(queryPath, "read");
2662
+ const out = await fs6.readText(resolved, { maxBytes, line, limit });
2641
2663
  const returnedBytes = Buffer.byteLength(out.content, "utf-8");
2642
2664
  applyReadHeaders(res);
2643
2665
  res.status(200).json({
@@ -2691,13 +2713,13 @@ async function handleGetFileBytes(req, res, deps) {
2691
2713
  });
2692
2714
  return;
2693
2715
  }
2694
- const fs5 = factory.forRequest({
2716
+ const fs6 = factory.forRequest({
2695
2717
  originatorClientId: clientId ?? void 0,
2696
2718
  route: ROUTE2
2697
2719
  });
2698
2720
  try {
2699
- const resolved = await fs5.resolve(queryPath, "read");
2700
- const out = await fs5.readBytesWindow(resolved, {
2721
+ const resolved = await fs6.resolve(queryPath, "read");
2722
+ const out = await fs6.readBytesWindow(resolved, {
2701
2723
  offset: offset ?? 0,
2702
2724
  maxBytes: maxBytes ?? DEFAULT_FILE_BYTES_MAX_BYTES
2703
2725
  });
@@ -2725,13 +2747,13 @@ async function handleGetStat(req, res, deps) {
2725
2747
  if (clientId === null) return;
2726
2748
  const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
2727
2749
  if (queryPath === null) return;
2728
- const fs5 = factory.forRequest({
2750
+ const fs6 = factory.forRequest({
2729
2751
  originatorClientId: clientId ?? void 0,
2730
2752
  route: ROUTE2
2731
2753
  });
2732
2754
  try {
2733
- const resolved = await fs5.resolve(queryPath, "stat");
2734
- const st = await fs5.stat(resolved);
2755
+ const resolved = await fs6.resolve(queryPath, "stat");
2756
+ const st = await fs6.stat(resolved);
2735
2757
  applyReadHeaders(res);
2736
2758
  res.status(200).json({
2737
2759
  kind: "stat",
@@ -2754,13 +2776,13 @@ async function handleGetList(req, res, deps) {
2754
2776
  const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
2755
2777
  if (queryPath === null) return;
2756
2778
  const includeIgnored = parseBoolFlag(req.query["includeIgnored"]);
2757
- const fs5 = factory.forRequest({
2779
+ const fs6 = factory.forRequest({
2758
2780
  originatorClientId: clientId ?? void 0,
2759
2781
  route: ROUTE2
2760
2782
  });
2761
2783
  try {
2762
- const resolved = await fs5.resolve(queryPath, "list");
2763
- const entries = await fs5.list(resolved, {
2784
+ const resolved = await fs6.resolve(queryPath, "list");
2785
+ const entries = await fs6.list(resolved, {
2764
2786
  includeIgnored,
2765
2787
  maxEntries: MAX_LIST_ENTRIES + 1
2766
2788
  });
@@ -2813,15 +2835,15 @@ async function handleGetGlob(req, res, deps) {
2813
2835
  }
2814
2836
  const cwdRaw = req.query["cwd"];
2815
2837
  const cwdString = typeof cwdRaw === "string" && cwdRaw.length > 0 ? cwdRaw : void 0;
2816
- const fs5 = factory.forRequest({
2838
+ const fs6 = factory.forRequest({
2817
2839
  originatorClientId: clientId ?? void 0,
2818
2840
  route: ROUTE2
2819
2841
  });
2820
2842
  const start = performance.now();
2821
2843
  try {
2822
- const cwdResolved = cwdString ? await fs5.resolve(cwdString, "list") : void 0;
2844
+ const cwdResolved = cwdString ? await fs6.resolve(cwdString, "list") : void 0;
2823
2845
  const cap = maxResults ?? DEFAULT_GLOB_MAX_RESULTS;
2824
- const probe = await fs5.glob(pattern, {
2846
+ const probe = await fs6.glob(pattern, {
2825
2847
  cwd: cwdResolved,
2826
2848
  includeIgnored,
2827
2849
  maxResults: cap + 1
@@ -2995,7 +3017,7 @@ function validateClientId(clientId, deps, res) {
2995
3017
  }
2996
3018
  __name(validateClientId, "validateClientId");
2997
3019
  function createSetupGithubFileOps(factory, route, originatorClientId) {
2998
- const fs5 = factory.forRequest({
3020
+ const fs6 = factory.forRequest({
2999
3021
  route,
3000
3022
  ...originatorClientId ? { originatorClientId } : {}
3001
3023
  });
@@ -3018,14 +3040,14 @@ function createSetupGithubFileOps(factory, route, originatorClientId) {
3018
3040
  ]);
3019
3041
  },
3020
3042
  async writeTextFile(_gitRepoRoot, relativePath, content) {
3021
- const resolved = await fs5.resolve(relativePath, "write");
3022
- const out = await fs5.writeTextOverwrite(resolved, content);
3043
+ const resolved = await fs6.resolve(relativePath, "write");
3044
+ const out = await fs6.writeTextOverwrite(resolved, content);
3023
3045
  return { sizeBytes: out.sizeBytes };
3024
3046
  },
3025
3047
  async readTextFile(_gitRepoRoot, relativePath) {
3026
3048
  try {
3027
- const resolved = await fs5.resolve(relativePath, "read");
3028
- const out = await fs5.readText(resolved);
3049
+ const resolved = await fs6.resolve(relativePath, "read");
3050
+ const out = await fs6.readText(resolved);
3029
3051
  return out.content;
3030
3052
  } catch (error2) {
3031
3053
  if (isFsError(error2) && error2.kind === "path_not_found") {
@@ -3046,15 +3068,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
3046
3068
  checkedSegments.push(segment);
3047
3069
  const label = `Workspace path "${checkedSegments.join("/")}"`;
3048
3070
  try {
3049
- const stat2 = await fsp3.lstat(current);
3050
- if (stat2.isSymbolicLink()) {
3071
+ const stat3 = await fsp3.lstat(current);
3072
+ if (stat3.isSymbolicLink()) {
3051
3073
  throw new SetupGithubError(
3052
3074
  "github_setup_invalid_workspace",
3053
3075
  `${label} must not be a symlink.`,
3054
3076
  400
3055
3077
  );
3056
3078
  }
3057
- if (!stat2.isDirectory()) {
3079
+ if (!stat3.isDirectory()) {
3058
3080
  throw new SetupGithubError(
3059
3081
  "github_setup_invalid_workspace",
3060
3082
  `${label} must be a directory.`,
@@ -3091,15 +3113,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
3091
3113
  }
3092
3114
  __name(ensureDirectoryWithoutSymlink, "ensureDirectoryWithoutSymlink");
3093
3115
  async function assertDirectoryWithoutSymlink(target, label) {
3094
- const stat2 = await fsp3.lstat(target);
3095
- if (stat2.isSymbolicLink()) {
3116
+ const stat3 = await fsp3.lstat(target);
3117
+ if (stat3.isSymbolicLink()) {
3096
3118
  throw new SetupGithubError(
3097
3119
  "github_setup_invalid_workspace",
3098
3120
  `${label} must not be a symlink.`,
3099
3121
  400
3100
3122
  );
3101
3123
  }
3102
- if (!stat2.isDirectory()) {
3124
+ if (!stat3.isDirectory()) {
3103
3125
  throw new SetupGithubError(
3104
3126
  "github_setup_invalid_workspace",
3105
3127
  `${label} must be a directory.`,
@@ -4740,12 +4762,12 @@ async function collectWorkspaceMemoryStatus(boundWorkspace) {
4740
4762
  for (const filename of filenames) {
4741
4763
  const candidate = path8.join(globalDir, filename);
4742
4764
  try {
4743
- const stat2 = await fs.stat(candidate);
4744
- if (stat2.isFile()) {
4765
+ const stat3 = await fs.stat(candidate);
4766
+ if (stat3.isFile()) {
4745
4767
  files.push({
4746
4768
  absolutePath: candidate,
4747
4769
  scope: "global",
4748
- bytes: stat2.size
4770
+ bytes: stat3.size
4749
4771
  });
4750
4772
  }
4751
4773
  } catch (err) {
@@ -4789,12 +4811,12 @@ async function walkWorkspaceForMemory(start, filenames, errors) {
4789
4811
  for (const filename of filenames) {
4790
4812
  const candidate = path8.join(start, filename);
4791
4813
  try {
4792
- const stat2 = await fs.stat(candidate);
4793
- if (stat2.isFile()) {
4814
+ const stat3 = await fs.stat(candidate);
4815
+ if (stat3.isFile()) {
4794
4816
  out.push({
4795
4817
  absolutePath: candidate,
4796
4818
  scope: "workspace",
4797
- bytes: stat2.size
4819
+ bytes: stat3.size
4798
4820
  });
4799
4821
  }
4800
4822
  } catch (err) {
@@ -4820,6 +4842,7 @@ __name(isEnoent, "isEnoent");
4820
4842
  // packages/cli/src/serve/workspace-agents.ts
4821
4843
  init_esbuild_shims();
4822
4844
  import { promises as fs2 } from "node:fs";
4845
+ import { isDeepStrictEqual } from "node:util";
4823
4846
  var AGENT_TYPE_PATTERN = /^[\p{L}\p{N}_-]+$/u;
4824
4847
  var AGENT_TYPE_MAX_LENGTH = 64;
4825
4848
  var AGENT_TYPE_MIN_LENGTH = 2;
@@ -4827,6 +4850,27 @@ var MAX_DESCRIPTION_BYTES = 256 * 1024;
4827
4850
  var MAX_SYSTEM_PROMPT_BYTES = 256 * 1024;
4828
4851
  var MAX_TOOLS_ENTRIES = 256;
4829
4852
  var MAX_TOOL_ID_LENGTH = 256;
4853
+ var MAX_RECORD_ENTRIES = 128;
4854
+ var SUBAGENT_APPROVAL_MODES = [...APPROVAL_MODES, "bubble"];
4855
+ var SUBAGENT_PERMISSION_MODES = [
4856
+ "acceptEdits",
4857
+ "auto",
4858
+ "bypassPermissions",
4859
+ "default",
4860
+ "dontAsk",
4861
+ "plan"
4862
+ ];
4863
+ var SUBAGENT_COLORS = [
4864
+ "auto",
4865
+ "red",
4866
+ "blue",
4867
+ "green",
4868
+ "yellow",
4869
+ "purple",
4870
+ "orange",
4871
+ "pink",
4872
+ "cyan"
4873
+ ];
4830
4874
  function mountWorkspaceAgentsRoutes(app, deps) {
4831
4875
  const manager = createDaemonSubagentManager(deps.boundWorkspace);
4832
4876
  app.get("/workspace/agents", async (_req, res) => {
@@ -4865,7 +4909,11 @@ function mountWorkspaceAgentsRoutes(app, deps) {
4865
4909
  return;
4866
4910
  }
4867
4911
  const level = scope === "workspace" ? "project" : "user";
4868
- const config = parseAgentConfig(body, level, res);
4912
+ const config = parseAgentConfig(
4913
+ restoreAgentMcpServerSecrets(body, deps.boundWorkspace, level),
4914
+ level,
4915
+ res
4916
+ );
4869
4917
  if (!config) return;
4870
4918
  const collision = await manager.loadSubagent(config.name, level);
4871
4919
  if (collision) {
@@ -4981,7 +5029,9 @@ function mountWorkspaceAgentsRoutes(app, deps) {
4981
5029
  const agentType = validateAgentType(req, res);
4982
5030
  if (agentType === null) return;
4983
5031
  try {
4984
- const config = await manager.loadSubagent(agentType);
5032
+ const scopedLevel = parseScopeQuery(req, res);
5033
+ if (scopedLevel === null) return;
5034
+ const config = await manager.loadSubagent(agentType, scopedLevel);
4985
5035
  if (!config) {
4986
5036
  res.status(404).json({
4987
5037
  error: `Subagent "${agentType}" not found`,
@@ -5010,9 +5060,6 @@ function mountWorkspaceAgentsRoutes(app, deps) {
5010
5060
  const clientIdResult = resolveOriginatorClientId(deps, req, res);
5011
5061
  if (clientIdResult === null) return;
5012
5062
  const originatorClientId = clientIdResult;
5013
- const body = deps.safeBody(req);
5014
- const updates = parseAgentUpdates(body, res);
5015
- if (!updates) return;
5016
5063
  const preferredLevel = parseScopeQuery(req, res);
5017
5064
  if (preferredLevel === null) return;
5018
5065
  const existing = await manager.loadSubagent(agentType, preferredLevel);
@@ -5027,6 +5074,14 @@ function mountWorkspaceAgentsRoutes(app, deps) {
5027
5074
  if (assertMutableLevel(existing, agentType, res)) {
5028
5075
  return;
5029
5076
  }
5077
+ const body = restoreAgentMcpServerSecrets(
5078
+ deps.safeBody(req),
5079
+ deps.boundWorkspace,
5080
+ existing.level,
5081
+ existing.mcpServers
5082
+ );
5083
+ const updates = parseAgentUpdates(body, res);
5084
+ if (!updates) return;
5030
5085
  if (Object.keys(updates).length === 0) {
5031
5086
  res.status(400).json({
5032
5087
  error: "`POST /workspace/agents/:agentType` requires at least one updatable field in the body",
@@ -5270,7 +5325,11 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5270
5325
  const level = parseWorkspaceOnlyAgentBodyScope(body, res);
5271
5326
  if (level === null) return;
5272
5327
  const manager = createDaemonSubagentManager(runtime.workspaceCwd);
5273
- const config = parseAgentConfig(body, level, res);
5328
+ const config = parseAgentConfig(
5329
+ restoreAgentMcpServerSecrets(body, runtime.workspaceCwd, level),
5330
+ level,
5331
+ res
5332
+ );
5274
5333
  if (!config) return;
5275
5334
  const collision = await manager.loadSubagent(config.name, level);
5276
5335
  if (collision) {
@@ -5359,9 +5418,6 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5359
5418
  const clientIdResult = resolveOriginatorClientId(routeDeps, req, res);
5360
5419
  if (clientIdResult === null) return;
5361
5420
  const originatorClientId = clientIdResult;
5362
- const body = deps.safeBody(req);
5363
- const updates = parseAgentUpdates(body, res);
5364
- if (!updates) return;
5365
5421
  const manager = createDaemonSubagentManager(runtime.workspaceCwd);
5366
5422
  const existing = await manager.loadSubagent(agentType, scopedLevel);
5367
5423
  if (!existing) {
@@ -5373,6 +5429,14 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5373
5429
  return;
5374
5430
  }
5375
5431
  if (assertMutableLevel(existing, agentType, res)) return;
5432
+ const body = restoreAgentMcpServerSecrets(
5433
+ deps.safeBody(req),
5434
+ runtime.workspaceCwd,
5435
+ existing.level,
5436
+ existing.mcpServers
5437
+ );
5438
+ const updates = parseAgentUpdates(body, res);
5439
+ if (!updates) return;
5376
5440
  if (Object.keys(updates).length === 0) {
5377
5441
  res.status(400).json({
5378
5442
  error: "`POST /workspaces/:workspace/agents/:agentType` requires at least one updatable field in the body",
@@ -5628,6 +5692,22 @@ function rejectWorkspaceQualifiedAgentScope(scope, res) {
5628
5692
  return null;
5629
5693
  }
5630
5694
  __name(rejectWorkspaceQualifiedAgentScope, "rejectWorkspaceQualifiedAgentScope");
5695
+ function restoreAgentMcpServerSecrets(body, workspace, level, currentAgentServers) {
5696
+ const incoming = body["mcpServers"];
5697
+ if (typeof incoming !== "object" || incoming === null || Array.isArray(incoming)) {
5698
+ return body;
5699
+ }
5700
+ const settings = loadSettings(workspace);
5701
+ const configuredServers = level === "user" ? settings.user.settings.mcpServers ?? {} : settings.merged.mcpServers ?? {};
5702
+ return {
5703
+ ...body,
5704
+ mcpServers: restoreRedactedMcpServersSetting(incoming, {
5705
+ ...configuredServers,
5706
+ ...currentAgentServers
5707
+ })
5708
+ };
5709
+ }
5710
+ __name(restoreAgentMcpServerSecrets, "restoreAgentMcpServerSecrets");
5631
5711
  function sendCreateAgentError(res, err, name) {
5632
5712
  if (!(err instanceof SubagentError)) return false;
5633
5713
  if (err.code === SubagentErrorCode.ALREADY_EXISTS) {
@@ -5769,22 +5849,73 @@ function parseAgentConfig(body, level, res) {
5769
5849
  if (tools !== void 0) config.tools = tools;
5770
5850
  if (disallowedTools !== void 0) config.disallowedTools = disallowedTools;
5771
5851
  if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
5772
- if (typeof body["model"] === "string") config.model = body["model"];
5852
+ if (typeof body["model"] === "string") {
5853
+ if (!body["model"].trim()) {
5854
+ return sendInvalidConfig(res, "`model` must not be empty when provided");
5855
+ }
5856
+ config.model = body["model"].trim();
5857
+ }
5773
5858
  if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
5774
- if (typeof body["color"] === "string") config.color = body["color"];
5859
+ if (typeof body["color"] === "string") {
5860
+ if (!SUBAGENT_COLORS.includes(body["color"])) {
5861
+ return sendInvalidConfig(
5862
+ res,
5863
+ `\`color\` must be one of ${JSON.stringify(SUBAGENT_COLORS)}`
5864
+ );
5865
+ }
5866
+ config.color = body["color"];
5867
+ }
5775
5868
  if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
5776
5869
  return void 0;
5777
5870
  }
5778
5871
  if (typeof body["approvalMode"] === "string") {
5779
- if (!APPROVAL_MODES.includes(body["approvalMode"])) {
5780
- res.status(422).json({
5781
- error: `\`approvalMode\` must be one of ${JSON.stringify(APPROVAL_MODES)}`,
5782
- code: "invalid_config"
5783
- });
5784
- return void 0;
5872
+ if (!SUBAGENT_APPROVAL_MODES.includes(body["approvalMode"])) {
5873
+ return sendInvalidConfig(
5874
+ res,
5875
+ `\`approvalMode\` must be one of ${JSON.stringify(SUBAGENT_APPROVAL_MODES)}`
5876
+ );
5785
5877
  }
5786
5878
  config.approvalMode = body["approvalMode"];
5787
5879
  }
5880
+ if (rejectIfPresentWrongType(body, "permissionMode", "string", res)) {
5881
+ return void 0;
5882
+ }
5883
+ if (typeof body["permissionMode"] === "string") {
5884
+ if (!SUBAGENT_PERMISSION_MODES.includes(body["permissionMode"])) {
5885
+ return sendInvalidConfig(
5886
+ res,
5887
+ `\`permissionMode\` must be one of ${JSON.stringify(SUBAGENT_PERMISSION_MODES)}`
5888
+ );
5889
+ }
5890
+ config.permissionMode = body["permissionMode"];
5891
+ }
5892
+ if ("maxTurns" in body) {
5893
+ const maxTurns = parseMaxTurns(body["maxTurns"], res);
5894
+ if (maxTurns === null) return void 0;
5895
+ config.maxTurns = maxTurns;
5896
+ }
5897
+ if ("mcpServers" in body) {
5898
+ const mcpServers = parseRecordField(
5899
+ body["mcpServers"],
5900
+ "mcpServers",
5901
+ (value) => typeof value === "object" && value !== null && !Array.isArray(value),
5902
+ "an object of server names to server configuration objects",
5903
+ res
5904
+ );
5905
+ if (mcpServers === null) return void 0;
5906
+ if (Object.keys(mcpServers).length > 0) config.mcpServers = mcpServers;
5907
+ }
5908
+ if ("hooks" in body) {
5909
+ const hooks = parseRecordField(
5910
+ body["hooks"],
5911
+ "hooks",
5912
+ Array.isArray,
5913
+ "an object of hook event names to matcher arrays",
5914
+ res
5915
+ );
5916
+ if (hooks === null) return void 0;
5917
+ if (Object.keys(hooks).length > 0) config.hooks = hooks;
5918
+ }
5788
5919
  if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
5789
5920
  return void 0;
5790
5921
  }
@@ -5854,23 +5985,86 @@ function parseAgentUpdates(body, res) {
5854
5985
  updates.disallowedTools = disallowedTools;
5855
5986
  }
5856
5987
  }
5857
- if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
5858
- if (typeof body["model"] === "string") updates.model = body["model"];
5859
- if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
5860
- if (typeof body["color"] === "string") updates.color = body["color"];
5861
- if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
5988
+ if (body["model"] === null) {
5989
+ updates.model = void 0;
5990
+ } else if (rejectIfPresentWrongType(body, "model", "string", res)) {
5862
5991
  return void 0;
5992
+ } else if (typeof body["model"] === "string") {
5993
+ if (!body["model"].trim()) {
5994
+ return sendInvalidConfig(res, "`model` must not be empty when provided");
5995
+ }
5996
+ updates.model = body["model"].trim();
5863
5997
  }
5864
- if (typeof body["approvalMode"] === "string") {
5865
- if (!APPROVAL_MODES.includes(body["approvalMode"])) {
5866
- res.status(422).json({
5867
- error: `\`approvalMode\` must be one of ${JSON.stringify(APPROVAL_MODES)}`,
5868
- code: "invalid_config"
5869
- });
5870
- return void 0;
5998
+ if (body["color"] === null) {
5999
+ updates.color = void 0;
6000
+ } else if (rejectIfPresentWrongType(body, "color", "string", res)) {
6001
+ return void 0;
6002
+ } else if (typeof body["color"] === "string") {
6003
+ if (!SUBAGENT_COLORS.includes(body["color"])) {
6004
+ return sendInvalidConfig(
6005
+ res,
6006
+ `\`color\` must be one of ${JSON.stringify(SUBAGENT_COLORS)}`
6007
+ );
6008
+ }
6009
+ updates.color = body["color"];
6010
+ }
6011
+ if (body["approvalMode"] === null) {
6012
+ updates.approvalMode = void 0;
6013
+ } else if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
6014
+ return void 0;
6015
+ } else if (typeof body["approvalMode"] === "string") {
6016
+ if (!SUBAGENT_APPROVAL_MODES.includes(body["approvalMode"])) {
6017
+ return sendInvalidConfig(
6018
+ res,
6019
+ `\`approvalMode\` must be one of ${JSON.stringify(SUBAGENT_APPROVAL_MODES)}`
6020
+ );
5871
6021
  }
5872
6022
  updates.approvalMode = body["approvalMode"];
5873
6023
  }
6024
+ if (body["permissionMode"] === null) {
6025
+ updates.permissionMode = void 0;
6026
+ } else if (rejectIfPresentWrongType(body, "permissionMode", "string", res)) {
6027
+ return void 0;
6028
+ } else if (typeof body["permissionMode"] === "string") {
6029
+ if (!SUBAGENT_PERMISSION_MODES.includes(body["permissionMode"])) {
6030
+ return sendInvalidConfig(
6031
+ res,
6032
+ `\`permissionMode\` must be one of ${JSON.stringify(SUBAGENT_PERMISSION_MODES)}`
6033
+ );
6034
+ }
6035
+ updates.permissionMode = body["permissionMode"];
6036
+ }
6037
+ if ("maxTurns" in body) {
6038
+ if (body["maxTurns"] === null) {
6039
+ updates.maxTurns = void 0;
6040
+ } else {
6041
+ const maxTurns = parseMaxTurns(body["maxTurns"], res);
6042
+ if (maxTurns === null) return void 0;
6043
+ updates.maxTurns = maxTurns;
6044
+ }
6045
+ }
6046
+ if ("mcpServers" in body) {
6047
+ const mcpServers = parseRecordField(
6048
+ body["mcpServers"],
6049
+ "mcpServers",
6050
+ (value) => typeof value === "object" && value !== null && !Array.isArray(value),
6051
+ "an object of server names to server configuration objects",
6052
+ res
6053
+ );
6054
+ if (mcpServers === null) return void 0;
6055
+ updates.mcpServers = mcpServers;
6056
+ }
6057
+ if ("hooks" in body) {
6058
+ const hooks = parseRecordField(
6059
+ body["hooks"],
6060
+ "hooks",
6061
+ Array.isArray,
6062
+ "an object of hook event names to matcher arrays",
6063
+ res
6064
+ );
6065
+ if (hooks === null) return void 0;
6066
+ updates.hooks = hooks;
6067
+ }
5874
6068
  if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
5875
6069
  return void 0;
5876
6070
  }
@@ -5911,6 +6105,43 @@ function parseStringArray(value, field, res) {
5911
6105
  return value;
5912
6106
  }
5913
6107
  __name(parseStringArray, "parseStringArray");
6108
+ function sendInvalidConfig(res, error2) {
6109
+ res.status(422).json({ error: error2, code: "invalid_config" });
6110
+ return void 0;
6111
+ }
6112
+ __name(sendInvalidConfig, "sendInvalidConfig");
6113
+ function parseMaxTurns(value, res) {
6114
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
6115
+ sendInvalidConfig(res, "`maxTurns` must be a positive integer");
6116
+ return null;
6117
+ }
6118
+ return value;
6119
+ }
6120
+ __name(parseMaxTurns, "parseMaxTurns");
6121
+ function parseRecordField(value, field, isValidEntry, expected, res) {
6122
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
6123
+ sendInvalidConfig(res, `\`${field}\` must be ${expected}`);
6124
+ return null;
6125
+ }
6126
+ const entries = Object.entries(value);
6127
+ if (entries.length > MAX_RECORD_ENTRIES) {
6128
+ sendInvalidConfig(
6129
+ res,
6130
+ `\`${field}\` exceeds the ${MAX_RECORD_ENTRIES}-entry limit`
6131
+ );
6132
+ return null;
6133
+ }
6134
+ const output = {};
6135
+ for (const [key, entry] of entries) {
6136
+ if (!key || key.length > MAX_TOOL_ID_LENGTH || key === "__proto__" || key === "constructor" || key === "prototype" || !isValidEntry(entry)) {
6137
+ sendInvalidConfig(res, `\`${field}\` must be ${expected}`);
6138
+ return null;
6139
+ }
6140
+ output[key] = entry;
6141
+ }
6142
+ return output;
6143
+ }
6144
+ __name(parseRecordField, "parseRecordField");
5914
6145
  function rejectIfPresentWrongType(body, key, expected, res) {
5915
6146
  if (!(key in body)) return false;
5916
6147
  if (typeof body[key] === expected) return false;
@@ -5934,13 +6165,31 @@ function isNoOpUpdate(existing, updates) {
5934
6165
  if (updates.disallowedTools !== void 0 && !shallowArrayEqual(updates.disallowedTools, existing.disallowedTools)) {
5935
6166
  return false;
5936
6167
  }
5937
- if (updates.model !== void 0 && updates.model !== existing.model) {
6168
+ if ("model" in updates && updates.model !== existing.model) {
6169
+ return false;
6170
+ }
6171
+ if ("color" in updates && updates.color !== existing.color) {
6172
+ return false;
6173
+ }
6174
+ if ("approvalMode" in updates && updates.approvalMode !== existing.approvalMode) {
6175
+ return false;
6176
+ }
6177
+ if ("permissionMode" in updates && updates.permissionMode !== existing.permissionMode) {
6178
+ return false;
6179
+ }
6180
+ if ("maxTurns" in updates && updates.maxTurns !== existing.maxTurns) {
5938
6181
  return false;
5939
6182
  }
5940
- if (updates.color !== void 0 && updates.color !== existing.color) {
6183
+ if (updates.mcpServers !== void 0 && !isDeepStrictEqual(
6184
+ normalizedRecord(updates.mcpServers),
6185
+ normalizedRecord(existing.mcpServers)
6186
+ )) {
5941
6187
  return false;
5942
6188
  }
5943
- if (updates.approvalMode !== void 0 && updates.approvalMode !== existing.approvalMode) {
6189
+ if (updates.hooks !== void 0 && !isDeepStrictEqual(
6190
+ normalizedRecord(updates.hooks),
6191
+ normalizedRecord(existing.hooks)
6192
+ )) {
5944
6193
  return false;
5945
6194
  }
5946
6195
  if (updates.background !== void 0 && updates.background !== existing.background) {
@@ -5959,7 +6208,20 @@ function isNoOpUpdate(existing, updates) {
5959
6208
  return true;
5960
6209
  }
5961
6210
  __name(isNoOpUpdate, "isNoOpUpdate");
5962
- function shallowArrayEqual(a, b) {
6211
+ function normalizedRecord(value) {
6212
+ if (!value || Object.keys(value).length === 0) return void 0;
6213
+ return normalizeRecordValue(value);
6214
+ }
6215
+ __name(normalizedRecord, "normalizedRecord");
6216
+ function normalizeRecordValue(value) {
6217
+ if (Array.isArray(value)) return value.map(normalizeRecordValue);
6218
+ if (typeof value !== "object" || value === null) return value;
6219
+ return Object.fromEntries(
6220
+ Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, normalizeRecordValue(entry)])
6221
+ );
6222
+ }
6223
+ __name(normalizeRecordValue, "normalizeRecordValue");
6224
+ function shallowArrayEqual(a, b) {
5963
6225
  if (a === b) return true;
5964
6226
  if (!a || !b) return false;
5965
6227
  if (a.length !== b.length) return false;
@@ -6011,10 +6273,30 @@ function toSummary(config) {
6011
6273
  isBuiltin: config.isBuiltin === true || config.level === "builtin",
6012
6274
  hasTools: Array.isArray(config.tools) && config.tools.length > 0
6013
6275
  };
6276
+ if (config.tools) summary.tools = [...config.tools];
6277
+ if (config.disallowedTools) {
6278
+ summary.disallowedTools = [...config.disallowedTools];
6279
+ }
6014
6280
  if (config.model) summary.model = config.model;
6015
6281
  if (config.color) summary.color = config.color;
6016
6282
  if (config.background !== void 0) summary.background = config.background;
6017
6283
  if (config.approvalMode) summary.approvalMode = config.approvalMode;
6284
+ if (config.permissionMode) summary.permissionMode = config.permissionMode;
6285
+ if (config.maxTurns !== void 0) summary.maxTurns = config.maxTurns;
6286
+ if (config.mcpServers) {
6287
+ summary.mcpServerNames = Object.keys(config.mcpServers);
6288
+ }
6289
+ if (config.hooks) summary.hookEvents = Object.keys(config.hooks);
6290
+ if (config.runConfig) {
6291
+ const runConfig = {};
6292
+ if (typeof config.runConfig.max_time_minutes === "number") {
6293
+ runConfig.max_time_minutes = config.runConfig.max_time_minutes;
6294
+ }
6295
+ if (typeof config.runConfig.max_turns === "number") {
6296
+ runConfig.max_turns = config.runConfig.max_turns;
6297
+ }
6298
+ summary.runConfig = runConfig;
6299
+ }
6018
6300
  if (config.extensionName) summary.extensionName = config.extensionName;
6019
6301
  if (config.filePath) summary.filePath = config.filePath;
6020
6302
  return summary;
@@ -6025,20 +6307,10 @@ function toDetail(config) {
6025
6307
  ...toSummary(config),
6026
6308
  systemPrompt: config.systemPrompt
6027
6309
  };
6028
- if (config.tools) detail.tools = [...config.tools];
6029
- if (config.disallowedTools) {
6030
- detail.disallowedTools = [...config.disallowedTools];
6031
- }
6032
- if (config.runConfig) {
6033
- const runConfig = {};
6034
- if (typeof config.runConfig.max_time_minutes === "number") {
6035
- runConfig.max_time_minutes = config.runConfig.max_time_minutes;
6036
- }
6037
- if (typeof config.runConfig.max_turns === "number") {
6038
- runConfig.max_turns = config.runConfig.max_turns;
6039
- }
6040
- detail.runConfig = runConfig;
6310
+ if (config.mcpServers) {
6311
+ detail.mcpServers = redactMcpServersSetting(config.mcpServers);
6041
6312
  }
6313
+ if (config.hooks) detail.hooks = config.hooks;
6042
6314
  return detail;
6043
6315
  }
6044
6316
  __name(toDetail, "toDetail");
@@ -9046,7 +9318,7 @@ var AcpDispatcher = class {
9046
9318
  );
9047
9319
  return;
9048
9320
  }
9049
- const fs5 = this.fsFactory.forRequest({
9321
+ const fs6 = this.fsFactory.forRequest({
9050
9322
  originatorClientId: conn.clientId,
9051
9323
  route: `ACP ${method}`
9052
9324
  });
@@ -9098,8 +9370,8 @@ var AcpDispatcher = class {
9098
9370
  );
9099
9371
  return;
9100
9372
  }
9101
- const resolved = await fs5.resolve(p, "read");
9102
- const out = await fs5.readText(resolved, { maxBytes, line, limit });
9373
+ const resolved = await fs6.resolve(p, "read");
9374
+ const out = await fs6.readText(resolved, { maxBytes, line, limit });
9103
9375
  this.replyConn(conn, id, {
9104
9376
  path: p,
9105
9377
  content: out.content,
@@ -9121,7 +9393,7 @@ var AcpDispatcher = class {
9121
9393
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9122
9394
  return;
9123
9395
  }
9124
- const fs5 = this.fsFactory.forRequest({
9396
+ const fs6 = this.fsFactory.forRequest({
9125
9397
  originatorClientId: conn.clientId,
9126
9398
  route: `ACP ${method}`
9127
9399
  });
@@ -9157,8 +9429,8 @@ var AcpDispatcher = class {
9157
9429
  );
9158
9430
  return;
9159
9431
  }
9160
- const resolved = await fs5.resolve(p, "read");
9161
- const buf = await fs5.readBytesWindow(resolved, { offset, maxBytes });
9432
+ const resolved = await fs6.resolve(p, "read");
9433
+ const buf = await fs6.readBytesWindow(resolved, { offset, maxBytes });
9162
9434
  this.replyConn(conn, id, { path: p, ...buf });
9163
9435
  return;
9164
9436
  }
@@ -9176,12 +9448,12 @@ var AcpDispatcher = class {
9176
9448
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9177
9449
  return;
9178
9450
  }
9179
- const fs5 = this.fsFactory.forRequest({
9451
+ const fs6 = this.fsFactory.forRequest({
9180
9452
  originatorClientId: conn.clientId,
9181
9453
  route: `ACP ${method}`
9182
9454
  });
9183
- const resolved = await fs5.resolve(p, "read");
9184
- const result = await fs5.stat(resolved);
9455
+ const resolved = await fs6.resolve(p, "read");
9456
+ const result = await fs6.stat(resolved);
9185
9457
  this.replyConn(conn, id, { path: p, ...result });
9186
9458
  return;
9187
9459
  }
@@ -9199,13 +9471,13 @@ var AcpDispatcher = class {
9199
9471
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9200
9472
  return;
9201
9473
  }
9202
- const fs5 = this.fsFactory.forRequest({
9474
+ const fs6 = this.fsFactory.forRequest({
9203
9475
  originatorClientId: conn.clientId,
9204
9476
  route: `ACP ${method}`
9205
9477
  });
9206
- const resolved = await fs5.resolve(p, "read");
9478
+ const resolved = await fs6.resolve(p, "read");
9207
9479
  const MAX_LIST = 2e3;
9208
- const entries = await fs5.list(resolved, { maxEntries: MAX_LIST + 1 });
9480
+ const entries = await fs6.list(resolved, { maxEntries: MAX_LIST + 1 });
9209
9481
  const truncated = entries.length > MAX_LIST;
9210
9482
  this.replyConn(conn, id, {
9211
9483
  path: p,
@@ -9230,7 +9502,7 @@ var AcpDispatcher = class {
9230
9502
  );
9231
9503
  return;
9232
9504
  }
9233
- const fs5 = this.fsFactory.forRequest({
9505
+ const fs6 = this.fsFactory.forRequest({
9234
9506
  originatorClientId: conn.clientId,
9235
9507
  route: `ACP ${method}`
9236
9508
  });
@@ -9250,7 +9522,7 @@ var AcpDispatcher = class {
9250
9522
  );
9251
9523
  return;
9252
9524
  }
9253
- const matches = await fs5.glob(pattern, {
9525
+ const matches = await fs6.glob(pattern, {
9254
9526
  maxResults: maxResults + 1
9255
9527
  });
9256
9528
  const truncated = matches.length > maxResults;
@@ -9282,11 +9554,11 @@ var AcpDispatcher = class {
9282
9554
  );
9283
9555
  return;
9284
9556
  }
9285
- const fs5 = this.fsFactory.forRequest({
9557
+ const fs6 = this.fsFactory.forRequest({
9286
9558
  originatorClientId: conn.clientId,
9287
9559
  route: `ACP ${method}`
9288
9560
  });
9289
- const resolved = await fs5.resolve(p, "write");
9561
+ const resolved = await fs6.resolve(p, "write");
9290
9562
  if (Buffer.byteLength(params["content"], "utf8") > 10 * 1024 * 1024) {
9291
9563
  if (id !== void 0)
9292
9564
  conn.sendConn(
@@ -9294,7 +9566,7 @@ var AcpDispatcher = class {
9294
9566
  );
9295
9567
  return;
9296
9568
  }
9297
- await fs5.writeTextOverwrite(resolved, params["content"]);
9569
+ await fs6.writeTextOverwrite(resolved, params["content"]);
9298
9570
  this.replyConn(conn, id, { ok: true, path: p });
9299
9571
  return;
9300
9572
  }
@@ -9323,12 +9595,12 @@ var AcpDispatcher = class {
9323
9595
  );
9324
9596
  return;
9325
9597
  }
9326
- const fs5 = this.fsFactory.forRequest({
9598
+ const fs6 = this.fsFactory.forRequest({
9327
9599
  originatorClientId: conn.clientId,
9328
9600
  route: `ACP ${method}`
9329
9601
  });
9330
- const resolved = await fs5.resolve(p, "write");
9331
- const result = await fs5.edit(
9602
+ const resolved = await fs6.resolve(p, "write");
9603
+ const result = await fs6.edit(
9332
9604
  resolved,
9333
9605
  params["oldText"],
9334
9606
  params["newText"]
@@ -9872,11 +10144,24 @@ var AcpDispatcher = class {
9872
10144
  }
9873
10145
  }
9874
10146
  }
10147
+ /**
10148
+ * Current epoch token of the session's event bus, or `undefined` when
10149
+ * the session is unknown (torn down between ownership check and header
10150
+ * write). The `/acp` GET route advertises it as `X-Qwen-Event-Epoch`
10151
+ * BEFORE `stream.open()` flushes headers (DAEMON-001).
10152
+ */
10153
+ getSessionEventEpoch(sessionId) {
10154
+ try {
10155
+ return this.bridge.getSessionEventEpoch(sessionId);
10156
+ } catch {
10157
+ return void 0;
10158
+ }
10159
+ }
9875
10160
  /**
9876
10161
  * Bind a session-scoped SSE stream to the bridge's event stream,
9877
10162
  * translating each `BridgeEvent` into a JSON-RPC frame (design §4.2).
9878
10163
  */
9879
- async pumpSessionEvents(conn, sessionId, signal, lastEventId) {
10164
+ async pumpSessionEvents(conn, sessionId, signal, lastEventId, epoch) {
9880
10165
  try {
9881
10166
  let lastDeliveredId = lastEventId ?? 0;
9882
10167
  let sawEviction = false;
@@ -9884,6 +10169,11 @@ var AcpDispatcher = class {
9884
10169
  if (conn.hasInitialReplayPending(sessionId)) {
9885
10170
  const snapshot = this.bridge.getSessionReplaySnapshot(sessionId);
9886
10171
  if (snapshot) {
10172
+ if (snapshot.degraded) {
10173
+ writeStderrLine(
10174
+ `qwen serve: /acp initial replay used a DEGRADED snapshot (compaction failure) session=${logSafe(sessionId)}; replay may be incomplete`
10175
+ );
10176
+ }
9887
10177
  const snapshotEvents = [
9888
10178
  ...snapshot.compactedTurns,
9889
10179
  ...snapshot.liveJournal
@@ -9916,7 +10206,8 @@ var AcpDispatcher = class {
9916
10206
  }
9917
10207
  const iterable = this.bridge.subscribeEvents(sessionId, {
9918
10208
  signal,
9919
- ...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {}
10209
+ ...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {},
10210
+ ...epoch !== void 0 ? { epoch } : {}
9920
10211
  });
9921
10212
  for await (const event of iterable) {
9922
10213
  if (signal.aborted) break;
@@ -11029,6 +11320,17 @@ function parseLastEventId2(raw, logPrefix = "") {
11029
11320
  return n;
11030
11321
  }
11031
11322
  __name(parseLastEventId2, "parseLastEventId");
11323
+ function parseEventEpochHeader(raw, logPrefix = "") {
11324
+ if (typeof raw !== "string" || raw.length === 0) return void 0;
11325
+ if (raw.length > 64 || !/^[\w-]+$/.test(raw)) {
11326
+ writeStderrLine(
11327
+ `qwen serve: ${logPrefix}rejected X-Qwen-Event-Epoch ${safeLogValue2(raw)} (expected [A-Za-z0-9_-]{1,64})`
11328
+ );
11329
+ return void 0;
11330
+ }
11331
+ return raw;
11332
+ }
11333
+ __name(parseEventEpochHeader, "parseEventEpochHeader");
11032
11334
 
11033
11335
  // packages/cli/src/serve/acp-http/client-mcp-ws.ts
11034
11336
  init_esbuild_shims();
@@ -12392,11 +12694,19 @@ function mountAcpHttp(app, bridge, opts) {
12392
12694
  },
12393
12695
  () => conn.touch()
12394
12696
  );
12395
- stream.open();
12396
12697
  const lastEventId = parseLastEventId2(
12397
12698
  headerOf(req, "last-event-id"),
12398
12699
  "/acp "
12399
12700
  );
12701
+ const eventEpoch = parseEventEpochHeader(
12702
+ headerOf(req, "x-qwen-event-epoch"),
12703
+ "/acp "
12704
+ );
12705
+ const busEpoch = mount.dispatcher.getSessionEventEpoch(sessionId);
12706
+ if (busEpoch !== void 0) {
12707
+ res.setHeader("X-Qwen-Event-Epoch", busEpoch);
12708
+ }
12709
+ stream.open();
12400
12710
  conn.attachSessionStream(sessionId, stream, ac, lastEventId);
12401
12711
  const onPumpSettled = /* @__PURE__ */ __name(() => {
12402
12712
  if (stream.isClosed) {
@@ -12412,7 +12722,7 @@ function mountAcpHttp(app, bridge, opts) {
12412
12722
  );
12413
12723
  }
12414
12724
  }, "onPumpSettled");
12415
- void mount.dispatcher.pumpSessionEvents(conn, sessionId, ac.signal, lastEventId).then(onPumpSettled, (err) => {
12725
+ void mount.dispatcher.pumpSessionEvents(conn, sessionId, ac.signal, lastEventId, eventEpoch).then(onPumpSettled, (err) => {
12416
12726
  writeStderrLine(
12417
12727
  `qwen serve: ${mount.routeLabel} event pump error (${logSafe(sessionId)}, lastEventId=${lastEventId ?? "none"}): ${logSafe(err instanceof Error ? err.message : String(err))}`
12418
12728
  );
@@ -13865,6 +14175,130 @@ function mountWebShellSpaFallback(app, webShellDir, frameAncestors = []) {
13865
14175
  }
13866
14176
  __name(mountWebShellSpaFallback, "mountWebShellSpaFallback");
13867
14177
 
14178
+ // packages/cli/src/serve/workspace-generation.ts
14179
+ init_esbuild_shims();
14180
+
14181
+ // packages/cli/src/serve/generation-sse.ts
14182
+ init_esbuild_shims();
14183
+ var GENERATION_HEARTBEAT_MS = 15e3;
14184
+ function formatGenerationSse(event, data) {
14185
+ return `event: ${event}
14186
+ data: ${JSON.stringify({ v: 1, ...data })}
14187
+
14188
+ `;
14189
+ }
14190
+ __name(formatGenerationSse, "formatGenerationSse");
14191
+ function writeGenerationSseChunk(res, chunk) {
14192
+ if (res.destroyed) {
14193
+ return Promise.reject(new Error("Generation SSE connection destroyed"));
14194
+ }
14195
+ const writable = res.write(chunk);
14196
+ const flush = res.flush;
14197
+ flush?.call(res);
14198
+ if (writable) {
14199
+ return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
14200
+ }
14201
+ return new Promise((resolve6, reject) => {
14202
+ const cleanup = /* @__PURE__ */ __name(() => {
14203
+ res.off("drain", onDrain);
14204
+ res.off("close", onClose);
14205
+ res.off("error", onError);
14206
+ }, "cleanup");
14207
+ const onDrain = /* @__PURE__ */ __name(() => {
14208
+ cleanup();
14209
+ resolve6();
14210
+ }, "onDrain");
14211
+ const onClose = /* @__PURE__ */ __name(() => {
14212
+ cleanup();
14213
+ reject(new Error("Generation SSE connection closed"));
14214
+ }, "onClose");
14215
+ const onError = /* @__PURE__ */ __name((error2) => {
14216
+ cleanup();
14217
+ reject(error2);
14218
+ }, "onError");
14219
+ res.once("drain", onDrain);
14220
+ res.once("close", onClose);
14221
+ res.once("error", onError);
14222
+ if (res.destroyed) onClose();
14223
+ });
14224
+ }
14225
+ __name(writeGenerationSseChunk, "writeGenerationSseChunk");
14226
+
14227
+ // packages/cli/src/serve/workspace-generation.ts
14228
+ function mountWorkspaceGenerationRoutes(app, deps) {
14229
+ app.post("/workspace/generate", deps.mutate(), async (req, res) => {
14230
+ const body = deps.safeBody(req);
14231
+ const prompt = body["prompt"];
14232
+ if (typeof prompt !== "string" || prompt.trim().length === 0 || Buffer.byteLength(prompt, "utf8") > GENERATION_MAX_PROMPT_BYTES) {
14233
+ res.status(400).json({
14234
+ error: `\`prompt\` must be a non-empty string no larger than ${GENERATION_MAX_PROMPT_BYTES} UTF-8 bytes`,
14235
+ code: "invalid_prompt"
14236
+ });
14237
+ return;
14238
+ }
14239
+ const clientId = deps.parseClientId(req, res);
14240
+ if (clientId === null) return;
14241
+ if (!deps.bridge.generateWorkspaceContent) {
14242
+ res.status(501).json({
14243
+ error: "Workspace generation is not supported by this bridge",
14244
+ code: "generation_not_supported"
14245
+ });
14246
+ return;
14247
+ }
14248
+ const abort = new AbortController();
14249
+ let completed = false;
14250
+ const onClose = /* @__PURE__ */ __name(() => {
14251
+ if (!completed) abort.abort();
14252
+ }, "onClose");
14253
+ res.once("close", onClose);
14254
+ const stream = deps.bridge.generateWorkspaceContent(
14255
+ prompt.trim(),
14256
+ abort.signal,
14257
+ clientId
14258
+ );
14259
+ res.status(200);
14260
+ res.setHeader("Content-Type", "text/event-stream");
14261
+ res.setHeader("Cache-Control", "no-cache, no-transform");
14262
+ res.setHeader("Connection", "keep-alive");
14263
+ res.setHeader("X-Accel-Buffering", "no");
14264
+ res.flushHeaders();
14265
+ let writeChain = Promise.resolve();
14266
+ const write = /* @__PURE__ */ __name((chunk) => {
14267
+ writeChain = writeChain.then(() => writeGenerationSseChunk(res, chunk));
14268
+ return writeChain;
14269
+ }, "write");
14270
+ await write(": connected\n\n");
14271
+ const heartbeat = setInterval(() => {
14272
+ void write(": heartbeat\n\n").catch(() => abort.abort());
14273
+ }, GENERATION_HEARTBEAT_MS);
14274
+ heartbeat.unref();
14275
+ try {
14276
+ for await (const event of stream) {
14277
+ await write(formatGenerationSse(event.type, event));
14278
+ }
14279
+ } catch (error2) {
14280
+ if (!abort.signal.aborted && !res.destroyed) {
14281
+ writeStderrLine(
14282
+ `qwen serve: POST /workspace/generate failed: ${error2 instanceof Error ? error2.stack ?? error2.message : String(error2)}`
14283
+ );
14284
+ await write(
14285
+ formatGenerationSse("error", {
14286
+ type: "error",
14287
+ code: "generation_failed",
14288
+ message: "Generation failed"
14289
+ })
14290
+ ).catch(() => void 0);
14291
+ }
14292
+ } finally {
14293
+ completed = true;
14294
+ clearInterval(heartbeat);
14295
+ res.off("close", onClose);
14296
+ if (!res.destroyed) res.end();
14297
+ }
14298
+ });
14299
+ }
14300
+ __name(mountWorkspaceGenerationRoutes, "mountWorkspaceGenerationRoutes");
14301
+
13868
14302
  // packages/cli/src/serve/routes/daemon-status.ts
13869
14303
  init_esbuild_shims();
13870
14304
  function registerDaemonStatusRoutes(app, deps) {
@@ -17519,13 +17953,13 @@ async function handlePostFileWrite(req, res, deps) {
17519
17953
  req
17520
17954
  );
17521
17955
  if (originatorClientId === null) return;
17522
- const fs5 = factory.forRequest({
17956
+ const fs6 = factory.forRequest({
17523
17957
  originatorClientId,
17524
17958
  route: ROUTE2
17525
17959
  });
17526
17960
  try {
17527
- const resolved = await fs5.resolve(queryPath, "write");
17528
- const out = await fs5.writeTextAtomic(resolved, content, {
17961
+ const resolved = await fs6.resolve(queryPath, "write");
17962
+ const out = await fs6.writeTextAtomic(resolved, content, {
17529
17963
  mode,
17530
17964
  ...expectedHash ? { expectedHash } : {},
17531
17965
  ...bom !== void 0 ? { bom } : {},
@@ -17578,13 +18012,13 @@ async function handlePostFileEdit(req, res, deps) {
17578
18012
  req
17579
18013
  );
17580
18014
  if (originatorClientId === null) return;
17581
- const fs5 = factory.forRequest({
18015
+ const fs6 = factory.forRequest({
17582
18016
  originatorClientId,
17583
18017
  route: ROUTE2
17584
18018
  });
17585
18019
  try {
17586
- const resolved = await fs5.resolve(queryPath, "edit");
17587
- const out = await fs5.editAtomic(resolved, oldText, newText, {
18020
+ const resolved = await fs6.resolve(queryPath, "edit");
18021
+ const out = await fs6.editAtomic(resolved, oldText, newText, {
17588
18022
  expectedHash
17589
18023
  });
17590
18024
  applyReadHeaders(res);
@@ -17912,6 +18346,18 @@ var legacySessionTelemetryRoutes = [
17912
18346
  attribution: "handler_resolved",
17913
18347
  route: "GET /session/:id/tasks"
17914
18348
  },
18349
+ {
18350
+ method: "GET",
18351
+ path: "/session/:id/subagents/:toolCallId",
18352
+ attribution: "handler_resolved",
18353
+ route: "GET /session/:id/subagents/:toolCallId"
18354
+ },
18355
+ {
18356
+ method: "POST",
18357
+ path: "/session/:id/subagents/:toolCallId/cancel",
18358
+ attribution: "handler_resolved",
18359
+ route: "POST /session/:id/subagents/:toolCallId/cancel"
18360
+ },
17915
18361
  {
17916
18362
  method: "GET",
17917
18363
  path: "/session/:id/lsp",
@@ -18594,7 +19040,7 @@ __name(registerPermissionRoutes, "registerPermissionRoutes");
18594
19040
  // packages/cli/src/serve/routes/session.ts
18595
19041
  init_esbuild_shims();
18596
19042
  import * as crypto3 from "node:crypto";
18597
- import * as fs3 from "node:fs";
19043
+ import * as fs4 from "node:fs";
18598
19044
  import * as path10 from "node:path";
18599
19045
 
18600
19046
  // packages/cli/src/serve/server/prompt-deadline.ts
@@ -18887,7 +19333,17 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
18887
19333
  organization
18888
19334
  )
18889
19335
  );
18890
- } else if (!await sessionService.sessionExists(live.sessionId)) {
19336
+ } else if (
19337
+ // `listAllPersistedSummaries` already scanned every persisted
19338
+ // session when the scan wasn't truncated, so a `sessionId` missing
19339
+ // from `bySessionId` is definitively new — no disk re-check
19340
+ // needed. Re-checking here raced a session that persists its
19341
+ // first write (e.g. a `displayName` update) between the scan
19342
+ // above and this point: `existing` stayed undefined but
19343
+ // `sessionExists` flipped to true, silently dropping the live
19344
+ // session from the response instead of merging it.
19345
+ !persisted.truncated || !await sessionService.sessionExists(live.sessionId)
19346
+ ) {
18891
19347
  bySessionId.set(
18892
19348
  live.sessionId,
18893
19349
  applyOrganization(
@@ -18969,7 +19425,13 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
18969
19425
  live.sessionId,
18970
19426
  mergeLiveSessionSummary(existing, live)
18971
19427
  );
18972
- } else if (!await sessionService.sessionExists(live.sessionId)) {
19428
+ } else if (
19429
+ // See the matching comment in
19430
+ // `listOrganizedWorkspaceSessionsForResponse`: an untruncated scan
19431
+ // already covers every persisted session, so skip the racy
19432
+ // re-check when nothing was truncated.
19433
+ !persisted.truncated || !await sessionService.sessionExists(live.sessionId)
19434
+ ) {
18973
19435
  bySessionId.set(live.sessionId, {
18974
19436
  ...live,
18975
19437
  createdAt: live.createdAt,
@@ -19072,7 +19534,14 @@ async function listWorkspaceSessionsForResponse(bridge, workspaceCwd, options, r
19072
19534
  const existing = bySessionId.get(live.sessionId);
19073
19535
  if (existing) {
19074
19536
  bySessionId.set(live.sessionId, mergeLiveSessionSummary(existing, live));
19075
- } else if (isFirstPage && !await sessionService.sessionExists(live.sessionId)) {
19537
+ } else if (isFirstPage && // If this is a complete scan (no further pages), a missing
19538
+ // `sessionId` here is definitively new — no disk re-check needed.
19539
+ // Re-checking raced a session that persists its first write (e.g. a
19540
+ // `displayName` update) between the scan above and this point:
19541
+ // `existing` stayed undefined but `sessionExists` flipped to true,
19542
+ // silently dropping the live session from the response instead of
19543
+ // merging it.
19544
+ (persisted.nextCursor == null || !await sessionService.sessionExists(live.sessionId))) {
19076
19545
  bySessionId.set(live.sessionId, {
19077
19546
  ...live,
19078
19547
  createdAt: live.createdAt,
@@ -19200,108 +19669,846 @@ async function exportSessionTranscript(params) {
19200
19669
  }
19201
19670
  __name(exportSessionTranscript, "exportSessionTranscript");
19202
19671
 
19203
- // packages/cli/src/serve/routes/session.ts
19204
- var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
19205
- var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
19206
- var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
19207
- var GENERATION_HEARTBEAT_MS = 15e3;
19208
- var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
19209
- "POST /session/:id/branch",
19210
- "POST /session/:id/fork",
19211
- "POST /session/:id/cd"
19212
- ];
19213
- function isPrimaryOnlyLiveSessionRoute(route) {
19214
- return PRIMARY_ONLY_LIVE_SESSION_ROUTES.includes(
19215
- route
19216
- );
19217
- }
19218
- __name(isPrimaryOnlyLiveSessionRoute, "isPrimaryOnlyLiveSessionRoute");
19219
- function formatGenerationSse(event, data) {
19220
- return `event: ${event}
19221
- data: ${JSON.stringify({ v: 1, ...data })}
19222
-
19223
- `;
19224
- }
19225
- __name(formatGenerationSse, "formatGenerationSse");
19226
- function writeGenerationSseChunk(res, chunk) {
19227
- if (res.destroyed) {
19228
- return Promise.reject(new Error("Generation SSE connection destroyed"));
19229
- }
19230
- const writable = res.write(chunk);
19231
- const flush = res.flush;
19232
- flush?.call(res);
19233
- if (writable) {
19234
- return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
19672
+ // packages/cli/src/serve/server/git-branch-ops.ts
19673
+ init_esbuild_shims();
19674
+ import { execFile } from "node:child_process";
19675
+ import { promisify } from "node:util";
19676
+ var execFileAsync = promisify(execFile);
19677
+ var GIT_BRANCH_TIMEOUT_MS = 3e4;
19678
+ async function branchExists(cwd, name) {
19679
+ try {
19680
+ await execFileAsync(
19681
+ "git",
19682
+ ["rev-parse", "--verify", `refs/heads/${name}`],
19683
+ { cwd, timeout: GIT_BRANCH_TIMEOUT_MS }
19684
+ );
19685
+ return true;
19686
+ } catch {
19687
+ return false;
19235
19688
  }
19236
- return new Promise((resolve6, reject) => {
19237
- const cleanup = /* @__PURE__ */ __name(() => {
19238
- res.off("drain", onDrain);
19239
- res.off("close", onClose);
19240
- res.off("error", onError);
19241
- }, "cleanup");
19242
- const onDrain = /* @__PURE__ */ __name(() => {
19243
- cleanup();
19244
- resolve6();
19245
- }, "onDrain");
19246
- const onClose = /* @__PURE__ */ __name(() => {
19247
- cleanup();
19248
- reject(new Error("Generation SSE connection closed"));
19249
- }, "onClose");
19250
- const onError = /* @__PURE__ */ __name((error2) => {
19251
- cleanup();
19252
- reject(error2);
19253
- }, "onError");
19254
- res.once("drain", onDrain);
19255
- res.once("close", onClose);
19256
- res.once("error", onError);
19257
- if (res.destroyed) onClose();
19689
+ }
19690
+ __name(branchExists, "branchExists");
19691
+ async function isDirtyTree(cwd) {
19692
+ const { stdout } = await execFileAsync(
19693
+ "git",
19694
+ ["status", "--porcelain", "--untracked-files=no"],
19695
+ {
19696
+ cwd,
19697
+ maxBuffer: 10 * 1024 * 1024,
19698
+ timeout: GIT_BRANCH_TIMEOUT_MS
19699
+ }
19700
+ );
19701
+ return stdout.trim().length > 0;
19702
+ }
19703
+ __name(isDirtyTree, "isDirtyTree");
19704
+ async function getHeadCommit(cwd) {
19705
+ return execFileAsync("git", ["rev-parse", "HEAD"], {
19706
+ cwd,
19707
+ timeout: GIT_BRANCH_TIMEOUT_MS
19708
+ }).then(({ stdout }) => stdout.trim()).catch(() => void 0);
19709
+ }
19710
+ __name(getHeadCommit, "getHeadCommit");
19711
+ async function createBranch(cwd, name) {
19712
+ await execFileAsync("git", ["checkout", "-b", name], {
19713
+ cwd,
19714
+ timeout: GIT_BRANCH_TIMEOUT_MS
19258
19715
  });
19259
19716
  }
19260
- __name(writeGenerationSseChunk, "writeGenerationSseChunk");
19261
- function isReadOnlyWorkspaceInspection(runtime) {
19262
- return !runtime.primary && !runtime.trusted;
19717
+ __name(createBranch, "createBranch");
19718
+ async function checkoutRef(cwd, ref) {
19719
+ await execFileAsync("git", ["checkout", ref], {
19720
+ cwd,
19721
+ timeout: GIT_BRANCH_TIMEOUT_MS
19722
+ });
19263
19723
  }
19264
- __name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
19265
- function runWorkspaceInspectionWithLogPolicy(runtime, read) {
19266
- return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read) : read();
19724
+ __name(checkoutRef, "checkoutRef");
19725
+ async function deleteBranch(cwd, name) {
19726
+ await execFileAsync("git", ["branch", "-D", name], {
19727
+ cwd,
19728
+ timeout: GIT_BRANCH_TIMEOUT_MS
19729
+ });
19267
19730
  }
19268
- __name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
19269
- function requireSessionArtifactClientId(clientId, res) {
19270
- if (clientId !== void 0) return true;
19271
- res.status(403).json({
19272
- error: "Session artifact access requires a session-bound client id",
19273
- code: "client_id_required",
19274
- errorKind: "client_id_required"
19731
+ __name(deleteBranch, "deleteBranch");
19732
+
19733
+ // packages/cli/src/serve/virtual-subagent-sessions.ts
19734
+ init_esbuild_shims();
19735
+ import * as fs3 from "node:fs/promises";
19736
+ import { createReadStream } from "node:fs";
19737
+ import readline from "node:readline";
19738
+ var PREFIX = "subagent.";
19739
+ var POLL_INTERVAL_MS = 250;
19740
+ var TARGET_RETENTION_MS = 6e4;
19741
+ async function readFirstUserText(filePath) {
19742
+ const stream = createReadStream(filePath);
19743
+ const lines = readline.createInterface({
19744
+ input: stream,
19745
+ crlfDelay: Infinity
19275
19746
  });
19276
- return false;
19747
+ try {
19748
+ for await (const line of lines) {
19749
+ const trimmed = line.trim();
19750
+ if (!trimmed) continue;
19751
+ for (const record of parseLineTolerant(trimmed, filePath)) {
19752
+ if (record.type !== "user") continue;
19753
+ return record.message?.parts?.find(
19754
+ (part) => typeof part.text === "string"
19755
+ )?.text;
19756
+ }
19757
+ }
19758
+ return void 0;
19759
+ } catch (error2) {
19760
+ if (error2.code === "ENOENT") return void 0;
19761
+ throw error2;
19762
+ } finally {
19763
+ lines.close();
19764
+ stream.destroy();
19765
+ }
19766
+ }
19767
+ __name(readFirstUserText, "readFirstUserText");
19768
+ function asRecord(value) {
19769
+ return typeof value === "object" && value !== null ? value : void 0;
19770
+ }
19771
+ __name(asRecord, "asRecord");
19772
+ function finiteNonNegative(value) {
19773
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
19774
+ }
19775
+ __name(finiteNonNegative, "finiteNonNegative");
19776
+ function normalizeTaskStatus(status) {
19777
+ if (typeof status !== "string") return void 0;
19778
+ if (status === "success") return "completed";
19779
+ if (status === "error") return "failed";
19780
+ if (status === "background") return "running";
19781
+ return status;
19782
+ }
19783
+ __name(normalizeTaskStatus, "normalizeTaskStatus");
19784
+ function isTerminalTaskStatus(status) {
19785
+ return status === "completed" || status === "failed" || status === "cancelled" || status === "canceled";
19786
+ }
19787
+ __name(isTerminalTaskStatus, "isTerminalTaskStatus");
19788
+ function preferTerminalTaskStatus(metricsStatus, selectedStatus) {
19789
+ return !isTerminalTaskStatus(metricsStatus) && isTerminalTaskStatus(selectedStatus) ? selectedStatus : metricsStatus ?? selectedStatus;
19790
+ }
19791
+ __name(preferTerminalTaskStatus, "preferTerminalTaskStatus");
19792
+ function durationBetween(start, end) {
19793
+ if (!end) return void 0;
19794
+ const startTime = Date.parse(start);
19795
+ const endTime = Date.parse(end);
19796
+ return Number.isFinite(startTime) && Number.isFinite(endTime) ? Math.max(0, endTime - startTime) : void 0;
19797
+ }
19798
+ __name(durationBetween, "durationBetween");
19799
+ function findToolCallMetrics(records, toolCallId) {
19800
+ const toolResult = records.find(
19801
+ (record) => record.toolCallResult?.callId === toolCallId
19802
+ )?.toolCallResult;
19803
+ const display = asRecord(toolResult?.resultDisplay);
19804
+ const summary = asRecord(display?.["executionSummary"]);
19805
+ return {
19806
+ status: normalizeTaskStatus(display?.["status"]) ?? normalizeTaskStatus(toolResult?.status),
19807
+ durationMs: finiteNonNegative(summary?.["totalDurationMs"]),
19808
+ totalTokens: finiteNonNegative(summary?.["totalTokens"]) ?? finiteNonNegative(display?.["tokenCount"]),
19809
+ inputTokens: finiteNonNegative(summary?.["inputTokens"]),
19810
+ outputTokens: finiteNonNegative(summary?.["outputTokens"]),
19811
+ cachedTokens: finiteNonNegative(summary?.["cachedTokens"])
19812
+ };
19277
19813
  }
19278
- __name(requireSessionArtifactClientId, "requireSessionArtifactClientId");
19279
- function sendArtifactValidationError(res, err) {
19280
- if (!(err instanceof SessionArtifactValidationError)) {
19281
- return false;
19814
+ __name(findToolCallMetrics, "findToolCallMetrics");
19815
+ function encodePart(value) {
19816
+ return Buffer.from(value, "utf8").toString("base64url");
19817
+ }
19818
+ __name(encodePart, "encodePart");
19819
+ function decodePart(value) {
19820
+ try {
19821
+ return Buffer.from(value, "base64url").toString("utf8");
19822
+ } catch {
19823
+ return void 0;
19282
19824
  }
19283
- res.status(400).json({
19284
- v: 1,
19285
- error: {
19286
- code: err.code,
19287
- message: err.message,
19288
- ...err.field ? { field: err.field } : {}
19289
- }
19290
- });
19291
- return true;
19292
19825
  }
19293
- __name(sendArtifactValidationError, "sendArtifactValidationError");
19294
- function sendSessionOrganizationError(res, err) {
19295
- if (!(err instanceof SessionOrganizationError)) {
19296
- return false;
19826
+ __name(decodePart, "decodePart");
19827
+ function isValidVirtualSessionPart(value) {
19828
+ return /^[a-zA-Z0-9_-]{1,500}$/.test(value);
19829
+ }
19830
+ __name(isValidVirtualSessionPart, "isValidVirtualSessionPart");
19831
+ function createVirtualSubagentSessionId(parentSessionId, agentId) {
19832
+ if (!isValidVirtualSessionPart(parentSessionId) || !isValidVirtualSessionPart(agentId)) {
19833
+ throw new Error("Virtual subagent session ids require valid id parts");
19297
19834
  }
19298
- const status = err.code === "group_name_conflict" ? 409 : err.code === "group_not_found" ? 404 : err.code === "session_organization_store_unreadable" ? 500 : 400;
19299
- res.status(status).json({
19300
- error: err.message,
19301
- code: err.code,
19302
- ...err.field !== void 0 ? { field: err.field } : {}
19303
- });
19304
- return true;
19835
+ return `${PREFIX}${encodePart(parentSessionId)}.${encodePart(agentId)}`;
19836
+ }
19837
+ __name(createVirtualSubagentSessionId, "createVirtualSubagentSessionId");
19838
+ function parseVirtualSubagentSessionId(sessionId) {
19839
+ if (!sessionId.startsWith(PREFIX) || sessionId.length > 2e3) {
19840
+ return void 0;
19841
+ }
19842
+ const parts = sessionId.slice(PREFIX.length).split(".");
19843
+ if (parts.length !== 2) return void 0;
19844
+ const parentSessionId = decodePart(parts[0]);
19845
+ const agentId = decodePart(parts[1]);
19846
+ if (!parentSessionId || !agentId || !isValidVirtualSessionPart(parentSessionId) || !isValidVirtualSessionPart(agentId)) {
19847
+ return void 0;
19848
+ }
19849
+ return { parentSessionId, agentId };
19850
+ }
19851
+ __name(parseVirtualSubagentSessionId, "parseVirtualSubagentSessionId");
19852
+ function replayCursorState(sessionId, position, leafUuid, startTime, lastUpdated) {
19853
+ return {
19854
+ v: 1,
19855
+ sessionId,
19856
+ fileIdentity: { dev: 0, ino: 0 },
19857
+ snapshotSize: position,
19858
+ position,
19859
+ leafUuid,
19860
+ startTime,
19861
+ lastUpdated
19862
+ };
19863
+ }
19864
+ __name(replayCursorState, "replayCursorState");
19865
+ var VirtualSubagentTarget = class _VirtualSubagentTarget {
19866
+ constructor(sessionId, parentSessionId, task, workspaceCwd, onExpired) {
19867
+ this.sessionId = sessionId;
19868
+ this.parentSessionId = parentSessionId;
19869
+ this.task = task;
19870
+ this.workspaceCwd = workspaceCwd;
19871
+ this.onExpired = onExpired;
19872
+ }
19873
+ static {
19874
+ __name(this, "VirtualSubagentTarget");
19875
+ }
19876
+ bus = new EventBus(1024, 8);
19877
+ events = [];
19878
+ snapshotDelivered = false;
19879
+ offset = 0;
19880
+ transcriptIdentity;
19881
+ streamOffset = 0;
19882
+ streamIdentity;
19883
+ streamReady = false;
19884
+ canonicalThroughTimestamp = 0;
19885
+ completedStreamRounds = /* @__PURE__ */ new Set();
19886
+ streamedRounds = /* @__PURE__ */ new Set();
19887
+ streamRunIds = /* @__PURE__ */ new Set();
19888
+ legacyStreamedSinceCanonical = false;
19889
+ replayState;
19890
+ initialized = false;
19891
+ refreshPromise = Promise.resolve();
19892
+ snapshotPromise = Promise.resolve();
19893
+ pollTimer;
19894
+ subscribers = 0;
19895
+ retentionTimer;
19896
+ updateStatus(status) {
19897
+ const wasRunning = this.task.status === "running";
19898
+ this.task.status = status;
19899
+ if (status !== "running" && this.pollTimer) {
19900
+ clearInterval(this.pollTimer);
19901
+ this.pollTimer = void 0;
19902
+ }
19903
+ if (wasRunning && status !== "running") {
19904
+ void this.refreshLive().catch(() => void 0);
19905
+ }
19906
+ }
19907
+ rememberEvent(event) {
19908
+ if (event && !this.snapshotDelivered) this.events.push(event);
19909
+ }
19910
+ resetCanonicalState() {
19911
+ this.offset = 0;
19912
+ this.replayState = void 0;
19913
+ this.canonicalThroughTimestamp = 0;
19914
+ this.completedStreamRounds.clear();
19915
+ this.streamRunIds.clear();
19916
+ this.streamedRounds.clear();
19917
+ this.legacyStreamedSinceCanonical = false;
19918
+ }
19919
+ resetStreamState() {
19920
+ this.streamOffset = 0;
19921
+ this.completedStreamRounds.clear();
19922
+ this.streamRunIds.clear();
19923
+ this.streamedRounds.clear();
19924
+ this.legacyStreamedSinceCanonical = false;
19925
+ }
19926
+ async readNewRecords(endOffset) {
19927
+ let handle;
19928
+ try {
19929
+ handle = await fs3.open(this.task.outputFile, "r");
19930
+ const stat3 = await handle.stat();
19931
+ const identity = `${stat3.dev}:${stat3.ino}`;
19932
+ if (this.transcriptIdentity !== void 0 && this.transcriptIdentity !== identity || stat3.size < this.offset) {
19933
+ this.resetCanonicalState();
19934
+ }
19935
+ this.transcriptIdentity = identity;
19936
+ const size = Math.min(stat3.size, endOffset ?? stat3.size);
19937
+ if (size <= this.offset) return [];
19938
+ const bytes = Buffer.alloc(size - this.offset);
19939
+ const { bytesRead } = await handle.read(
19940
+ bytes,
19941
+ 0,
19942
+ bytes.length,
19943
+ this.offset
19944
+ );
19945
+ const chunk = bytes.subarray(0, bytesRead);
19946
+ const lastNewline = chunk.lastIndexOf(10);
19947
+ if (lastNewline < 0) return [];
19948
+ const complete = chunk.subarray(0, lastNewline + 1);
19949
+ this.offset += complete.length;
19950
+ return complete.toString("utf8").split("\n").flatMap((line) => {
19951
+ const trimmed = line.trim();
19952
+ return trimmed ? parseLineTolerant(trimmed, this.task.outputFile) : [];
19953
+ });
19954
+ } catch (error2) {
19955
+ if (error2.code === "ENOENT") {
19956
+ if (this.transcriptIdentity !== void 0) {
19957
+ this.transcriptIdentity = void 0;
19958
+ this.resetCanonicalState();
19959
+ }
19960
+ return [];
19961
+ }
19962
+ throw error2;
19963
+ } finally {
19964
+ await handle?.close();
19965
+ }
19966
+ }
19967
+ async readStreamUpdates(endOffset) {
19968
+ const replayingExisting = !this.streamReady;
19969
+ this.streamReady = true;
19970
+ const filePath = `${this.task.outputFile}.stream`;
19971
+ let handle;
19972
+ try {
19973
+ handle = await fs3.open(filePath, "r");
19974
+ const stat3 = await handle.stat();
19975
+ const identity = `${stat3.dev}:${stat3.ino}`;
19976
+ if (this.streamIdentity !== void 0 && this.streamIdentity !== identity) {
19977
+ this.resetStreamState();
19978
+ }
19979
+ this.streamIdentity = identity;
19980
+ if (stat3.size < this.streamOffset) this.resetStreamState();
19981
+ const size = Math.min(stat3.size, endOffset ?? stat3.size);
19982
+ if (size <= this.streamOffset) return;
19983
+ const bytes = Buffer.alloc(size - this.streamOffset);
19984
+ const { bytesRead } = await handle.read(
19985
+ bytes,
19986
+ 0,
19987
+ bytes.length,
19988
+ this.streamOffset
19989
+ );
19990
+ const chunk = bytes.subarray(0, bytesRead);
19991
+ const lastNewline = chunk.lastIndexOf(10);
19992
+ if (lastNewline < 0) return;
19993
+ const complete = chunk.subarray(0, lastNewline + 1);
19994
+ this.streamOffset += complete.length;
19995
+ const records = complete.toString("utf8").split("\n").flatMap((line) => {
19996
+ const trimmed = line.trim();
19997
+ return trimmed ? parseLineTolerant(trimmed, filePath) : [];
19998
+ });
19999
+ for (const record of records) {
20000
+ if (record.v !== 1 || typeof record.text !== "string" || typeof record.timestamp !== "number") {
20001
+ continue;
20002
+ }
20003
+ const roundKey = typeof record.runId === "string" && typeof record.round === "number" ? `${record.runId}:${record.round}` : void 0;
20004
+ if (typeof record.runId === "string") {
20005
+ this.streamRunIds.add(record.runId);
20006
+ }
20007
+ if ((roundKey ? this.completedStreamRounds.has(roundKey) : record.timestamp <= this.canonicalThroughTimestamp) || replayingExisting && typeof record.round !== "number") {
20008
+ continue;
20009
+ }
20010
+ const event = this.bus.publish({
20011
+ type: "session_update",
20012
+ data: createTranscriptMessageUpdate({
20013
+ role: "assistant",
20014
+ text: record.text,
20015
+ timestamp: record.timestamp,
20016
+ ...record.thought ? { thought: true } : {}
20017
+ })
20018
+ });
20019
+ this.rememberEvent(event);
20020
+ if (roundKey) this.streamedRounds.add(roundKey);
20021
+ else this.legacyStreamedSinceCanonical = true;
20022
+ }
20023
+ for (const completed of this.completedStreamRounds) {
20024
+ const runId = completed.slice(0, completed.lastIndexOf(":"));
20025
+ if (!this.streamRunIds.has(runId)) {
20026
+ this.completedStreamRounds.delete(completed);
20027
+ }
20028
+ }
20029
+ } catch (error2) {
20030
+ if (error2.code !== "ENOENT") throw error2;
20031
+ this.streamIdentity = void 0;
20032
+ this.streamOffset = 0;
20033
+ this.streamRunIds.clear();
20034
+ this.streamedRounds.clear();
20035
+ this.legacyStreamedSinceCanonical = false;
20036
+ } finally {
20037
+ await handle?.close();
20038
+ }
20039
+ }
20040
+ refreshOnce = /* @__PURE__ */ __name(async (endOffset) => {
20041
+ let records = await this.readNewRecords(endOffset);
20042
+ if (records.length === 0) {
20043
+ this.initialized = true;
20044
+ return;
20045
+ }
20046
+ for (const record of records) {
20047
+ if (record.type === "assistant" && (record.usageMetadata !== void 0 || record.message?.parts?.some((part) => typeof part.text === "string"))) {
20048
+ if (typeof record.agentRunId === "string" && typeof record.agentRound === "number") {
20049
+ this.completedStreamRounds.add(
20050
+ `${record.agentRunId}:${record.agentRound}`
20051
+ );
20052
+ }
20053
+ const timestamp = Date.parse(record.timestamp);
20054
+ if (Number.isFinite(timestamp)) {
20055
+ this.canonicalThroughTimestamp = Math.max(
20056
+ this.canonicalThroughTimestamp,
20057
+ timestamp
20058
+ );
20059
+ }
20060
+ }
20061
+ }
20062
+ if (this.streamedRounds.size > 0 || this.legacyStreamedSinceCanonical) {
20063
+ records = records.filter((record) => {
20064
+ const roundKey = typeof record.agentRunId === "string" && typeof record.agentRound === "number" ? `${record.agentRunId}:${record.agentRound}` : void 0;
20065
+ if (roundKey && this.streamedRounds.delete(roundKey)) return false;
20066
+ if (!this.legacyStreamedSinceCanonical || record.type !== "assistant" || record.message?.parts?.some((part) => part.functionCall)) {
20067
+ return true;
20068
+ }
20069
+ this.legacyStreamedSinceCanonical = false;
20070
+ return false;
20071
+ });
20072
+ if (records.length === 0) {
20073
+ this.initialized = true;
20074
+ return;
20075
+ }
20076
+ }
20077
+ const startTime = records[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
20078
+ const lastUpdated = records[records.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
20079
+ const page = {
20080
+ sessionId: this.sessionId,
20081
+ filePath: this.task.outputFile,
20082
+ records,
20083
+ gaps: [],
20084
+ hasMore: true,
20085
+ replay: this.replayState,
20086
+ startTime,
20087
+ lastUpdated,
20088
+ nextCursorState: replayCursorState(
20089
+ this.sessionId,
20090
+ this.offset,
20091
+ records[records.length - 1]?.uuid ?? "",
20092
+ startTime,
20093
+ lastUpdated
20094
+ )
20095
+ };
20096
+ let nextReplayState;
20097
+ const replay = await replayTranscriptRecordPage({
20098
+ sessionId: this.sessionId,
20099
+ page,
20100
+ encodeCursor: /* @__PURE__ */ __name((state) => {
20101
+ nextReplayState = state.replay;
20102
+ return "virtual-subagent-replay";
20103
+ }, "encodeCursor")
20104
+ });
20105
+ this.replayState = nextReplayState;
20106
+ const inputs = replay.updates.map((update) => ({
20107
+ type: "session_update",
20108
+ data: update
20109
+ }));
20110
+ const published = this.initialized ? inputs.flatMap((input) => {
20111
+ const event = this.bus.publish(input);
20112
+ return event ? [event] : [];
20113
+ }) : this.bus.seedReplayEvents(inputs);
20114
+ if (!this.snapshotDelivered) this.events.push(...published);
20115
+ this.initialized = true;
20116
+ }, "refreshOnce");
20117
+ refreshAt(bounds) {
20118
+ return this.refreshOnce(bounds?.transcript).then(async () => {
20119
+ if (this.task.status === "running") {
20120
+ await this.readStreamUpdates(bounds?.stream);
20121
+ }
20122
+ });
20123
+ }
20124
+ enqueueRefresh(work) {
20125
+ const result = this.refreshPromise.catch(() => void 0).then(work);
20126
+ this.refreshPromise = result.then(
20127
+ () => void 0,
20128
+ () => void 0
20129
+ );
20130
+ return result;
20131
+ }
20132
+ refreshLive() {
20133
+ return this.enqueueRefresh(() => this.refreshAt());
20134
+ }
20135
+ async captureReadBounds() {
20136
+ const size = /* @__PURE__ */ __name(async (filePath) => {
20137
+ try {
20138
+ return (await fs3.stat(filePath)).size;
20139
+ } catch (error2) {
20140
+ if (error2.code === "ENOENT") return 0;
20141
+ throw error2;
20142
+ }
20143
+ }, "size");
20144
+ const [transcript, stream] = await Promise.all([
20145
+ size(this.task.outputFile),
20146
+ size(`${this.task.outputFile}.stream`)
20147
+ ]);
20148
+ return { transcript, stream };
20149
+ }
20150
+ async createSnapshotOnce() {
20151
+ if (!this.snapshotDelivered) {
20152
+ await this.refreshLive();
20153
+ const snapshot = [...this.events];
20154
+ this.events.length = 0;
20155
+ this.snapshotDelivered = true;
20156
+ return { events: snapshot, lastEventId: this.bus.lastEventId };
20157
+ }
20158
+ return this.enqueueRefresh(async () => {
20159
+ const bounds = await this.captureReadBounds();
20160
+ const target = new _VirtualSubagentTarget(
20161
+ this.sessionId,
20162
+ this.parentSessionId,
20163
+ this.task,
20164
+ this.workspaceCwd,
20165
+ () => void 0
20166
+ );
20167
+ await target.refreshAt(bounds);
20168
+ await this.refreshAt(bounds);
20169
+ return {
20170
+ events: [...target.events],
20171
+ lastEventId: this.bus.lastEventId
20172
+ };
20173
+ });
20174
+ }
20175
+ createSnapshot() {
20176
+ const snapshot = this.snapshotPromise.then(() => this.createSnapshotOnce());
20177
+ this.snapshotPromise = snapshot.then(
20178
+ () => void 0,
20179
+ () => void 0
20180
+ );
20181
+ return snapshot;
20182
+ }
20183
+ async load(clientId) {
20184
+ const snapshot = await this.createSnapshot();
20185
+ if (this.subscribers === 0) this.scheduleRetention();
20186
+ return {
20187
+ sessionId: this.sessionId,
20188
+ workspaceCwd: this.workspaceCwd,
20189
+ attached: true,
20190
+ ...clientId ? { clientId } : {},
20191
+ createdAt: new Date(this.task.startTime).toISOString(),
20192
+ hasActivePrompt: this.task.status === "running",
20193
+ state: {},
20194
+ compactedReplay: snapshot.events,
20195
+ liveJournal: [],
20196
+ historyHasMore: false,
20197
+ lastEventId: snapshot.lastEventId
20198
+ };
20199
+ }
20200
+ async *iterate(opts) {
20201
+ if (this.retentionTimer) {
20202
+ clearTimeout(this.retentionTimer);
20203
+ this.retentionTimer = void 0;
20204
+ }
20205
+ this.subscribers++;
20206
+ try {
20207
+ await this.refreshLive();
20208
+ if (!this.snapshotDelivered) {
20209
+ this.events.length = 0;
20210
+ this.snapshotDelivered = true;
20211
+ }
20212
+ if (this.task.status === "running" && !this.pollTimer) {
20213
+ this.pollTimer = setInterval(() => {
20214
+ void this.refreshLive().catch(() => void 0);
20215
+ }, POLL_INTERVAL_MS);
20216
+ this.pollTimer.unref();
20217
+ }
20218
+ yield* this.bus.subscribe(opts);
20219
+ } finally {
20220
+ this.subscribers--;
20221
+ if (this.subscribers === 0) {
20222
+ if (this.pollTimer) clearInterval(this.pollTimer);
20223
+ this.pollTimer = void 0;
20224
+ this.scheduleRetention();
20225
+ }
20226
+ }
20227
+ }
20228
+ subscribe(opts) {
20229
+ return {
20230
+ [Symbol.asyncIterator]: () => this.iterate(opts)
20231
+ };
20232
+ }
20233
+ scheduleRetention() {
20234
+ if (this.retentionTimer) clearTimeout(this.retentionTimer);
20235
+ this.retentionTimer = setTimeout(this.onExpired, TARGET_RETENTION_MS);
20236
+ this.retentionTimer.unref();
20237
+ }
20238
+ };
20239
+ var VirtualSubagentSessions = class {
20240
+ static {
20241
+ __name(this, "VirtualSubagentSessions");
20242
+ }
20243
+ targets = /* @__PURE__ */ new Map();
20244
+ async findTask(runtime, parentSessionId, predicate) {
20245
+ const status = await runtime.bridge.getSessionTasksStatus(parentSessionId);
20246
+ const task = status.tasks.find(
20247
+ (candidate) => candidate.kind === "agent" && typeof candidate.outputFile === "string" && predicate(candidate)
20248
+ );
20249
+ if (task?.kind === "agent" && task.outputFile) {
20250
+ return {
20251
+ id: task.id,
20252
+ title: task.label,
20253
+ outputFile: task.outputFile,
20254
+ status: task.status,
20255
+ startTime: task.startTime,
20256
+ durationMs: task.stats?.durationMs ?? (task.endTime === void 0 ? void 0 : Math.max(0, task.endTime - task.startTime)),
20257
+ totalTokens: task.stats?.totalTokens
20258
+ };
20259
+ }
20260
+ const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
20261
+ const projectDir = Storage.runWithRuntimeBaseDir(
20262
+ runtimeDir,
20263
+ runtime.workspaceCwd,
20264
+ () => new Storage(runtime.workspaceCwd).getProjectDir()
20265
+ );
20266
+ const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
20267
+ let names;
20268
+ try {
20269
+ names = await fs3.readdir(sessionDir);
20270
+ } catch (error2) {
20271
+ if (error2.code === "ENOENT") return void 0;
20272
+ throw error2;
20273
+ }
20274
+ for (const name of names) {
20275
+ if (!name.endsWith(".meta.json")) continue;
20276
+ const metaPath = `${sessionDir}/${name}`;
20277
+ const meta = readAgentMeta(metaPath);
20278
+ if (!meta || !predicate({
20279
+ kind: "agent",
20280
+ id: meta.agentId,
20281
+ toolUseId: meta.toolUseId,
20282
+ outputFile: metaPath.slice(0, -".meta.json".length) + ".jsonl"
20283
+ })) {
20284
+ continue;
20285
+ }
20286
+ return {
20287
+ id: meta.agentId,
20288
+ title: meta.description || meta.agentType,
20289
+ outputFile: metaPath.slice(0, -".meta.json".length) + ".jsonl",
20290
+ status: meta.status ?? "completed",
20291
+ startTime: Number.isFinite(Date.parse(meta.createdAt)) ? Date.parse(meta.createdAt) : Date.now(),
20292
+ durationMs: durationBetween(meta.createdAt, meta.lastUpdatedAt)
20293
+ };
20294
+ }
20295
+ return void 0;
20296
+ }
20297
+ async findLegacyTaskByToolCall(runtime, parentSessionId, toolCallId) {
20298
+ const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
20299
+ const projectDir = Storage.runWithRuntimeBaseDir(
20300
+ runtimeDir,
20301
+ runtime.workspaceCwd,
20302
+ () => new Storage(runtime.workspaceCwd).getProjectDir()
20303
+ );
20304
+ const parentRecords = await read(
20305
+ `${projectDir}/chats/${parentSessionId}.jsonl`
20306
+ );
20307
+ let root;
20308
+ for (const record of parentRecords) {
20309
+ for (const part of record.message?.parts ?? []) {
20310
+ const call = part.functionCall;
20311
+ if (call?.id !== toolCallId || call.name !== "agent") continue;
20312
+ const args = call.args;
20313
+ root = {
20314
+ timestamp: Date.parse(record.timestamp),
20315
+ ...typeof args?.["description"] === "string" ? { description: args["description"] } : {},
20316
+ ...typeof args?.["prompt"] === "string" ? { prompt: args["prompt"] } : {},
20317
+ ...typeof args?.["subagent_type"] === "string" ? { agentType: args["subagent_type"] } : {}
20318
+ };
20319
+ break;
20320
+ }
20321
+ if (root) break;
20322
+ }
20323
+ if (!root) return void 0;
20324
+ const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
20325
+ let names;
20326
+ try {
20327
+ names = await fs3.readdir(sessionDir);
20328
+ } catch (error2) {
20329
+ if (error2.code === "ENOENT") return void 0;
20330
+ throw error2;
20331
+ }
20332
+ const candidates = [];
20333
+ for (const name of names) {
20334
+ if (!name.endsWith(".meta.json")) continue;
20335
+ const metaPath = `${sessionDir}/${name}`;
20336
+ const meta = readAgentMeta(metaPath);
20337
+ if (!meta) continue;
20338
+ const outputFile = metaPath.slice(0, -".meta.json".length) + ".jsonl";
20339
+ const launchPrompt = await readFirstUserText(outputFile);
20340
+ let score = 0;
20341
+ if (root.prompt && launchPrompt === root.prompt) score += 8;
20342
+ if (root.description && meta.description === root.description) score += 4;
20343
+ if (root.agentType && meta.agentType === root.agentType) score += 2;
20344
+ const startTime = Date.parse(meta.createdAt);
20345
+ const delta = Math.abs(startTime - root.timestamp);
20346
+ if (Number.isFinite(delta) && delta <= 6e4) score += 1;
20347
+ if (score === 0) continue;
20348
+ candidates.push({
20349
+ id: meta.agentId,
20350
+ title: meta.description || meta.agentType,
20351
+ outputFile,
20352
+ status: meta.status ?? "completed",
20353
+ startTime: Number.isFinite(startTime) ? startTime : Date.now(),
20354
+ durationMs: durationBetween(meta.createdAt, meta.lastUpdatedAt),
20355
+ score,
20356
+ delta
20357
+ });
20358
+ }
20359
+ candidates.sort((a, b) => b.score - a.score || a.delta - b.delta);
20360
+ const selected = candidates[0];
20361
+ if (!selected) return void 0;
20362
+ const metrics = findToolCallMetrics(parentRecords, toolCallId);
20363
+ return {
20364
+ ...selected,
20365
+ status: preferTerminalTaskStatus(metrics.status, selected.status),
20366
+ durationMs: metrics.durationMs ?? selected.durationMs,
20367
+ totalTokens: metrics.totalTokens ?? selected.totalTokens,
20368
+ inputTokens: metrics.inputTokens ?? selected.inputTokens,
20369
+ outputTokens: metrics.outputTokens ?? selected.outputTokens,
20370
+ cachedTokens: metrics.cachedTokens ?? selected.cachedTokens
20371
+ };
20372
+ }
20373
+ async readParentToolCallMetrics(runtime, parentSessionId, toolCallId) {
20374
+ const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
20375
+ const projectDir = Storage.runWithRuntimeBaseDir(
20376
+ runtimeDir,
20377
+ runtime.workspaceCwd,
20378
+ () => new Storage(runtime.workspaceCwd).getProjectDir()
20379
+ );
20380
+ const records = await read(
20381
+ `${projectDir}/chats/${parentSessionId}.jsonl`
20382
+ );
20383
+ return findToolCallMetrics(records, toolCallId);
20384
+ }
20385
+ async resolve(runtime, parentSessionId, toolCallId) {
20386
+ let task = await this.findTask(
20387
+ runtime,
20388
+ parentSessionId,
20389
+ (candidate) => candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
20390
+ );
20391
+ const metrics = task && task.status !== "running" ? await this.readParentToolCallMetrics(
20392
+ runtime,
20393
+ parentSessionId,
20394
+ toolCallId
20395
+ ) : void 0;
20396
+ task ??= await this.findLegacyTaskByToolCall(
20397
+ runtime,
20398
+ parentSessionId,
20399
+ toolCallId
20400
+ );
20401
+ if (!task) return void 0;
20402
+ const sessionId = createVirtualSubagentSessionId(parentSessionId, task.id);
20403
+ const status = task.status;
20404
+ this.targets.get(`${runtime.workspaceId}:${sessionId}`)?.updateStatus(status);
20405
+ return {
20406
+ sessionId,
20407
+ taskId: task.id,
20408
+ title: task.title,
20409
+ status,
20410
+ durationMs: metrics?.durationMs ?? task.durationMs,
20411
+ totalTokens: metrics?.totalTokens ?? task.totalTokens,
20412
+ inputTokens: metrics?.inputTokens ?? task.inputTokens,
20413
+ outputTokens: metrics?.outputTokens ?? task.outputTokens,
20414
+ cachedTokens: metrics?.cachedTokens ?? task.cachedTokens
20415
+ };
20416
+ }
20417
+ async getTarget(runtime, sessionId) {
20418
+ const targetKey = `${runtime.workspaceId}:${sessionId}`;
20419
+ const cached = this.targets.get(targetKey);
20420
+ if (cached) return cached;
20421
+ const key = parseVirtualSubagentSessionId(sessionId);
20422
+ if (!key) return void 0;
20423
+ const task = await this.findTask(
20424
+ runtime,
20425
+ key.parentSessionId,
20426
+ (candidate) => candidate.id === key.agentId
20427
+ );
20428
+ if (!task) return void 0;
20429
+ const existing = this.targets.get(targetKey);
20430
+ if (existing) return existing;
20431
+ const target = new VirtualSubagentTarget(
20432
+ sessionId,
20433
+ key.parentSessionId,
20434
+ task,
20435
+ runtime.workspaceCwd,
20436
+ () => this.targets.delete(targetKey)
20437
+ );
20438
+ this.targets.set(targetKey, target);
20439
+ return target;
20440
+ }
20441
+ async load(runtime, sessionId, clientId) {
20442
+ return (await this.getTarget(runtime, sessionId))?.load(clientId);
20443
+ }
20444
+ async subscribe(runtime, sessionId, opts) {
20445
+ return (await this.getTarget(runtime, sessionId))?.subscribe(opts);
20446
+ }
20447
+ };
20448
+
20449
+ // packages/cli/src/serve/routes/session.ts
20450
+ var GIT_RESERVED_BRANCH = "HEAD";
20451
+ var MAX_BRANCH_NAME_BYTES = 1e3;
20452
+ var MAX_BRANCH_COMPONENT_BYTES = 200;
20453
+ var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
20454
+ var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
20455
+ var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
20456
+ var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
20457
+ var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
20458
+ "POST /session/:id/branch",
20459
+ "POST /session/:id/fork",
20460
+ "POST /session/:id/cd"
20461
+ ];
20462
+ function isPrimaryOnlyLiveSessionRoute(route) {
20463
+ return PRIMARY_ONLY_LIVE_SESSION_ROUTES.includes(
20464
+ route
20465
+ );
20466
+ }
20467
+ __name(isPrimaryOnlyLiveSessionRoute, "isPrimaryOnlyLiveSessionRoute");
20468
+ function isReadOnlyWorkspaceInspection(runtime) {
20469
+ return !runtime.primary && !runtime.trusted;
20470
+ }
20471
+ __name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
20472
+ function runWorkspaceInspectionWithLogPolicy(runtime, read2) {
20473
+ return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read2) : read2();
20474
+ }
20475
+ __name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
20476
+ function requireSessionArtifactClientId(clientId, res) {
20477
+ if (clientId !== void 0) return true;
20478
+ res.status(403).json({
20479
+ error: "Session artifact access requires a session-bound client id",
20480
+ code: "client_id_required",
20481
+ errorKind: "client_id_required"
20482
+ });
20483
+ return false;
20484
+ }
20485
+ __name(requireSessionArtifactClientId, "requireSessionArtifactClientId");
20486
+ function sendArtifactValidationError(res, err) {
20487
+ if (!(err instanceof SessionArtifactValidationError)) {
20488
+ return false;
20489
+ }
20490
+ res.status(400).json({
20491
+ v: 1,
20492
+ error: {
20493
+ code: err.code,
20494
+ message: err.message,
20495
+ ...err.field ? { field: err.field } : {}
20496
+ }
20497
+ });
20498
+ return true;
20499
+ }
20500
+ __name(sendArtifactValidationError, "sendArtifactValidationError");
20501
+ function sendSessionOrganizationError(res, err) {
20502
+ if (!(err instanceof SessionOrganizationError)) {
20503
+ return false;
20504
+ }
20505
+ const status = err.code === "group_name_conflict" ? 409 : err.code === "group_not_found" ? 404 : err.code === "session_organization_store_unreadable" ? 500 : 400;
20506
+ res.status(status).json({
20507
+ error: err.message,
20508
+ code: err.code,
20509
+ ...err.field !== void 0 ? { field: err.field } : {}
20510
+ });
20511
+ return true;
19305
20512
  }
19306
20513
  __name(sendSessionOrganizationError, "sendSessionOrganizationError");
19307
20514
  function parseTranscriptLimitQuery(rawLimit, res) {
@@ -19426,11 +20633,40 @@ function registerSessionRoutes(app, deps) {
19426
20633
  sendBridgeError: sendBridgeError2,
19427
20634
  daemonLog,
19428
20635
  promptDeadlineMs,
19429
- sessionShellCommandEnabled
20636
+ sessionShellCommandEnabled,
20637
+ virtualSubagentSessions
19430
20638
  } = deps;
19431
20639
  const LANGUAGE_CODES = deps.languageCodes;
19432
20640
  const transcriptCursorMasterKey = crypto3.randomBytes(32);
19433
20641
  const transcriptCursorCodecs = /* @__PURE__ */ new Map();
20642
+ const activeBranchSessions = /* @__PURE__ */ new Map();
20643
+ const inFlightBranchWorkspaces = /* @__PURE__ */ new Set();
20644
+ const clearBranchSessionEntry = /* @__PURE__ */ __name((sessionId) => {
20645
+ for (const [cwd, sid] of activeBranchSessions) {
20646
+ if (sid === sessionId) {
20647
+ activeBranchSessions.delete(cwd);
20648
+ }
20649
+ }
20650
+ }, "clearBranchSessionEntry");
20651
+ const rollbackBranchCreation = /* @__PURE__ */ __name(async (cwd, meta, baseCommit, log2) => {
20652
+ activeBranchSessions.delete(cwd);
20653
+ inFlightBranchWorkspaces.delete(cwd);
20654
+ const baseRestored = await checkoutRef(
20655
+ cwd,
20656
+ meta.baseBranch === "HEAD" && baseCommit ? baseCommit : meta.baseBranch
20657
+ ).then(() => true).catch((rollbackErr) => {
20658
+ log2?.warn("branch rollback checkout failed", {
20659
+ error: rollbackErr
20660
+ });
20661
+ return false;
20662
+ });
20663
+ if (!baseRestored) return;
20664
+ await deleteBranch(cwd, meta.name).catch((rollbackErr) => {
20665
+ log2?.warn("branch rollback delete failed", {
20666
+ error: rollbackErr
20667
+ });
20668
+ });
20669
+ }, "rollbackBranchCreation");
19434
20670
  const getTranscriptCursorCodec = /* @__PURE__ */ __name((runtime) => {
19435
20671
  const canonicalCwd = canonicalizeWorkspace(runtime.workspaceCwd);
19436
20672
  const cacheKey = `${runtime.workspaceId}\0${canonicalCwd}`;
@@ -20011,6 +21247,138 @@ function registerSessionRoutes(app, deps) {
20011
21247
  }
20012
21248
  const clientId = parseClientIdHeader(req, res);
20013
21249
  if (clientId === null) return;
21250
+ let branchMeta;
21251
+ let branchBaseCommit;
21252
+ const rawBranch = body["branch"];
21253
+ if (rawBranch !== void 0 && rawBranch !== null) {
21254
+ if (body["worktree"] !== void 0 && body["worktree"] !== null) {
21255
+ res.status(400).json({
21256
+ error: "`branch` and `worktree` are mutually exclusive",
21257
+ code: "branch_and_worktree_conflict"
21258
+ });
21259
+ return;
21260
+ }
21261
+ if (typeof rawBranch !== "object" || Array.isArray(rawBranch)) {
21262
+ res.status(400).json({
21263
+ error: '`branch` must be an object (e.g. `{"name":"feat/my-feature"}`)',
21264
+ code: "invalid_branch"
21265
+ });
21266
+ return;
21267
+ }
21268
+ const branchReq = rawBranch;
21269
+ const branchName = branchReq["name"];
21270
+ if (typeof branchName !== "string" || branchName.length === 0) {
21271
+ res.status(400).json({
21272
+ error: "`branch.name` must be a non-empty string",
21273
+ code: "branch_invalid_name"
21274
+ });
21275
+ return;
21276
+ }
21277
+ if (/[^\p{L}\p{N}._/-]/u.test(branchName) || branchName.includes("..") || branchName.includes("//") || branchName.startsWith(".") || branchName.startsWith("-") || branchName.startsWith("/") || branchName.endsWith("/") || branchName.endsWith(".") || branchName.endsWith(".git") || branchName.includes("@{") || branchName.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")) || branchName.toUpperCase() === GIT_RESERVED_BRANCH || Buffer.byteLength(branchName, "utf8") > MAX_BRANCH_NAME_BYTES || branchName.split("/").some(
21278
+ (c) => Buffer.byteLength(c, "utf8") > MAX_BRANCH_COMPONENT_BYTES
21279
+ )) {
21280
+ res.status(400).json({
21281
+ error: `Invalid branch name: ${branchName}`,
21282
+ code: "branch_invalid_name"
21283
+ });
21284
+ return;
21285
+ }
21286
+ const existingBranchSession = activeBranchSessions.get(workspaceCwd);
21287
+ if (existingBranchSession) {
21288
+ try {
21289
+ runtime.bridge.getSessionSummary(existingBranchSession);
21290
+ res.status(409).json({
21291
+ error: "A branch session is already active for this workspace",
21292
+ code: "branch_session_conflict",
21293
+ existingSessionId: existingBranchSession
21294
+ });
21295
+ return;
21296
+ } catch {
21297
+ activeBranchSessions.delete(workspaceCwd);
21298
+ }
21299
+ }
21300
+ const sharedCheckoutSession = runtime.bridge.listWorkspaceSessions(workspaceCwd).find((session) => !session.worktree && session.clientCount > 0);
21301
+ if (sharedCheckoutSession) {
21302
+ res.status(409).json({
21303
+ error: "Another session is already active in this workspace; creating a branch would move its shared checkout",
21304
+ code: "branch_session_conflict",
21305
+ existingSessionId: sharedCheckoutSession.sessionId
21306
+ });
21307
+ return;
21308
+ }
21309
+ let wtService;
21310
+ try {
21311
+ wtService = new GitWorktreeService(workspaceCwd);
21312
+ } catch {
21313
+ res.status(500).json({
21314
+ error: "Failed to initialize git service",
21315
+ code: "branch_init_failed"
21316
+ });
21317
+ return;
21318
+ }
21319
+ if (!await wtService.isGitRepository()) {
21320
+ res.status(400).json({
21321
+ error: "Branch creation requires a git repository",
21322
+ code: "branch_not_git_repo"
21323
+ });
21324
+ return;
21325
+ }
21326
+ if (await branchExists(workspaceCwd, branchName)) {
21327
+ res.status(409).json({
21328
+ error: `Branch "${branchName}" already exists`,
21329
+ code: "branch_already_exists"
21330
+ });
21331
+ return;
21332
+ }
21333
+ let dirty;
21334
+ try {
21335
+ dirty = await isDirtyTree(workspaceCwd);
21336
+ } catch {
21337
+ res.status(500).json({
21338
+ error: "Failed to check working tree status",
21339
+ code: "branch_status_failed"
21340
+ });
21341
+ return;
21342
+ }
21343
+ if (dirty) {
21344
+ res.status(409).json({
21345
+ error: "Uncommitted changes detected. Commit or stash first.",
21346
+ code: "branch_dirty_tree"
21347
+ });
21348
+ return;
21349
+ }
21350
+ const baseCommit = await getHeadCommit(workspaceCwd);
21351
+ const baseBranch = await wtService.getCurrentBranch().catch(() => "HEAD");
21352
+ if (inFlightBranchWorkspaces.has(workspaceCwd) || activeBranchSessions.has(workspaceCwd)) {
21353
+ res.status(409).json({
21354
+ error: "A branch session is already being created for this workspace",
21355
+ code: "branch_session_conflict"
21356
+ });
21357
+ return;
21358
+ }
21359
+ inFlightBranchWorkspaces.add(workspaceCwd);
21360
+ try {
21361
+ await createBranch(workspaceCwd, branchName);
21362
+ } catch (checkoutErr) {
21363
+ daemonLog?.warn("branch checkout failed", {
21364
+ error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
21365
+ });
21366
+ await rollbackBranchCreation(
21367
+ workspaceCwd,
21368
+ { name: branchName, baseBranch },
21369
+ baseCommit,
21370
+ daemonLog
21371
+ );
21372
+ res.status(500).json({
21373
+ error: "Failed to create branch",
21374
+ code: "branch_checkout_failed"
21375
+ });
21376
+ return;
21377
+ }
21378
+ branchMeta = { name: branchName, baseBranch };
21379
+ branchBaseCommit = baseCommit;
21380
+ sessionScope = "thread";
21381
+ }
20014
21382
  let worktreeMeta;
20015
21383
  const rawWorktree = body["worktree"];
20016
21384
  if (rawWorktree !== void 0 && rawWorktree !== null) {
@@ -20082,7 +21450,8 @@ function registerSessionRoutes(app, deps) {
20082
21450
  ...approvalMode !== void 0 ? { approvalMode } : {},
20083
21451
  ...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
20084
21452
  ...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
20085
- ...worktreeMeta ? { worktree: worktreeMeta } : {}
21453
+ ...worktreeMeta ? { worktree: worktreeMeta } : {},
21454
+ ...branchMeta ? { branch: branchMeta } : {}
20086
21455
  });
20087
21456
  if (daemonLog) {
20088
21457
  daemonLog.info(
@@ -20113,12 +21482,30 @@ function registerSessionRoutes(app, deps) {
20113
21482
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
20114
21483
  });
20115
21484
  }
21485
+ if (branchMeta) {
21486
+ await rollbackBranchCreation(
21487
+ workspaceCwd,
21488
+ branchMeta,
21489
+ branchBaseCommit,
21490
+ daemonLog
21491
+ );
21492
+ }
21493
+ } else if (branchMeta) {
21494
+ activeBranchSessions.set(workspaceCwd, session.sessionId);
21495
+ inFlightBranchWorkspaces.delete(workspaceCwd);
20116
21496
  }
20117
21497
  } catch {
21498
+ if (branchMeta) {
21499
+ activeBranchSessions.set(workspaceCwd, session.sessionId);
21500
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21501
+ }
20118
21502
  }
20119
21503
  } else {
20120
21504
  runtime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
20121
21505
  });
21506
+ if (branchMeta) {
21507
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21508
+ }
20122
21509
  }
20123
21510
  return;
20124
21511
  }
@@ -20183,18 +21570,79 @@ function registerSessionRoutes(app, deps) {
20183
21570
  return;
20184
21571
  }
20185
21572
  }
21573
+ if (branchMeta) {
21574
+ activeBranchSessions.set(workspaceCwd, session.sessionId);
21575
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21576
+ }
20186
21577
  res.status(200).json(session);
20187
21578
  } catch (err) {
20188
21579
  if (worktreeMeta) {
20189
21580
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
20190
21581
  });
20191
21582
  }
21583
+ if (branchMeta) {
21584
+ await rollbackBranchCreation(
21585
+ workspaceCwd,
21586
+ branchMeta,
21587
+ branchBaseCommit,
21588
+ daemonLog
21589
+ );
21590
+ }
20192
21591
  sendBridgeError2(res, err, { route: "POST /session" });
20193
21592
  }
20194
21593
  });
20195
21594
  const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
20196
21595
  const sessionId = requireSessionId(req, res);
20197
21596
  if (!sessionId) return;
21597
+ const virtualKey = parseVirtualSubagentSessionId(sessionId);
21598
+ if (virtualKey) {
21599
+ const route2 = `POST /session/:id/${action}`;
21600
+ if (action !== "load") {
21601
+ res.status(400).json({
21602
+ error: `Virtual subagent sessions do not support ${action}`,
21603
+ code: "unsupported_action",
21604
+ sessionId
21605
+ });
21606
+ return;
21607
+ }
21608
+ if (!virtualSubagentSessions) {
21609
+ res.status(404).json({
21610
+ error: `No session with id "${sessionId}"`,
21611
+ code: "session_not_found",
21612
+ sessionId
21613
+ });
21614
+ return;
21615
+ }
21616
+ const runtime2 = requireSessionRuntime({
21617
+ sessionId: virtualKey.parentSessionId,
21618
+ route: route2,
21619
+ res,
21620
+ workspaceRegistry,
21621
+ daemonLog
21622
+ });
21623
+ if (!runtime2) return;
21624
+ const clientId2 = parseClientIdHeader(req, res);
21625
+ if (clientId2 === null) return;
21626
+ try {
21627
+ const session = await virtualSubagentSessions.load(
21628
+ runtime2,
21629
+ sessionId,
21630
+ clientId2
21631
+ );
21632
+ if (!session) {
21633
+ res.status(404).json({
21634
+ error: "Subagent session not found",
21635
+ code: "session_not_found",
21636
+ sessionId
21637
+ });
21638
+ return;
21639
+ }
21640
+ res.status(200).json(session);
21641
+ } catch (err) {
21642
+ sendBridgeError2(res, err, { route: route2, sessionId });
21643
+ }
21644
+ return;
21645
+ }
20198
21646
  const body = safeBody(req);
20199
21647
  const route = `POST /session/:id/${action}`;
20200
21648
  let resolvedRuntime;
@@ -20284,7 +21732,7 @@ function registerSessionRoutes(app, deps) {
20284
21732
  path10.join(workspaceCwd, ".qwen", "worktrees")
20285
21733
  ];
20286
21734
  try {
20287
- realTarget = fs3.realpathSync(sidecar.worktreePath);
21735
+ realTarget = fs4.realpathSync(sidecar.worktreePath);
20288
21736
  let repoTop = null;
20289
21737
  try {
20290
21738
  repoTop = await new GitWorktreeService(
@@ -20297,7 +21745,7 @@ function registerSessionRoutes(app, deps) {
20297
21745
  }
20298
21746
  const contained = candidateRoots.some((root) => {
20299
21747
  try {
20300
- const realRoot = fs3.realpathSync(root);
21748
+ const realRoot = fs4.realpathSync(root);
20301
21749
  const rel = path10.relative(realRoot, realTarget);
20302
21750
  return !rel.startsWith("..") && !path10.isAbsolute(rel);
20303
21751
  } catch {
@@ -20340,18 +21788,124 @@ function registerSessionRoutes(app, deps) {
20340
21788
  }
20341
21789
  }
20342
21790
  }
20343
- res.status(200).json(session);
21791
+ res.status(200).json(session);
21792
+ } catch (err) {
21793
+ sendBridgeError2(res, err, {
21794
+ route,
21795
+ sessionId
21796
+ });
21797
+ } finally {
21798
+ releaseRestoreOwner();
21799
+ }
21800
+ }, "restoreSessionHandler");
21801
+ app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
21802
+ app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
21803
+ app.get("/session/:id/subagents/:toolCallId", async (req, res) => {
21804
+ const route = "GET /session/:id/subagents/:toolCallId";
21805
+ const sessionId = requireSessionId(req, res);
21806
+ if (!sessionId) return;
21807
+ if (!virtualSubagentSessions) {
21808
+ res.status(404).json({
21809
+ error: `No session with id "${sessionId}"`,
21810
+ code: "session_not_found",
21811
+ sessionId
21812
+ });
21813
+ return;
21814
+ }
21815
+ const toolCallId = req.params["toolCallId"];
21816
+ if (!toolCallId || toolCallId.length > 500) {
21817
+ res.status(400).json({
21818
+ error: "`toolCallId` must be a non-empty tool call id",
21819
+ code: "invalid_tool_call_id"
21820
+ });
21821
+ return;
21822
+ }
21823
+ const runtime = requireSessionRuntime({
21824
+ sessionId,
21825
+ route,
21826
+ res,
21827
+ workspaceRegistry,
21828
+ daemonLog
21829
+ });
21830
+ if (!runtime) return;
21831
+ try {
21832
+ const resolved = await virtualSubagentSessions.resolve(
21833
+ runtime,
21834
+ sessionId,
21835
+ toolCallId
21836
+ );
21837
+ if (!resolved) {
21838
+ res.status(404).json({
21839
+ error: "Subagent session not found",
21840
+ code: "session_not_found",
21841
+ sessionId,
21842
+ toolCallId
21843
+ });
21844
+ return;
21845
+ }
21846
+ res.status(200).set("Cache-Control", "no-store").json(resolved);
20344
21847
  } catch (err) {
20345
- sendBridgeError2(res, err, {
21848
+ sendBridgeError2(res, err, { route, sessionId });
21849
+ }
21850
+ });
21851
+ app.post(
21852
+ "/session/:id/subagents/:toolCallId/cancel",
21853
+ mutate(),
21854
+ async (req, res) => {
21855
+ const route = "POST /session/:id/subagents/:toolCallId/cancel";
21856
+ const sessionId = requireSessionId(req, res);
21857
+ if (!sessionId) return;
21858
+ if (!virtualSubagentSessions) {
21859
+ res.status(404).json({
21860
+ error: `No session with id "${sessionId}"`,
21861
+ code: "session_not_found",
21862
+ sessionId
21863
+ });
21864
+ return;
21865
+ }
21866
+ const toolCallId = req.params["toolCallId"];
21867
+ if (!toolCallId || toolCallId.length > 500) {
21868
+ res.status(400).json({
21869
+ error: "`toolCallId` must be a non-empty tool call id",
21870
+ code: "invalid_tool_call_id"
21871
+ });
21872
+ return;
21873
+ }
21874
+ const runtime = requireSessionRuntime({
21875
+ sessionId,
20346
21876
  route,
20347
- sessionId
21877
+ res,
21878
+ workspaceRegistry,
21879
+ daemonLog
20348
21880
  });
20349
- } finally {
20350
- releaseRestoreOwner();
21881
+ if (!runtime) return;
21882
+ try {
21883
+ const resolved = await virtualSubagentSessions.resolve(
21884
+ runtime,
21885
+ sessionId,
21886
+ toolCallId
21887
+ );
21888
+ if (!resolved) {
21889
+ res.status(404).json({
21890
+ error: "Subagent session not found",
21891
+ code: "session_not_found",
21892
+ sessionId,
21893
+ toolCallId
21894
+ });
21895
+ return;
21896
+ }
21897
+ res.status(200).json(
21898
+ await runtime.bridge.cancelSessionTask(
21899
+ sessionId,
21900
+ resolved.taskId,
21901
+ "agent"
21902
+ )
21903
+ );
21904
+ } catch (err) {
21905
+ sendBridgeError2(res, err, { route, sessionId });
21906
+ }
20351
21907
  }
20352
- }, "restoreSessionHandler");
20353
- app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
20354
- app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
21908
+ );
20355
21909
  app.post(
20356
21910
  "/session/:id/branch",
20357
21911
  mutate(),
@@ -20651,6 +22205,28 @@ function registerSessionRoutes(app, deps) {
20651
22205
  });
20652
22206
  app.get(
20653
22207
  "/session/:id/context",
22208
+ (req, res, next) => {
22209
+ const sessionId = req.params["id"];
22210
+ const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
22211
+ if (!sessionId || !key) {
22212
+ next();
22213
+ return;
22214
+ }
22215
+ const runtime = requireSessionRuntime({
22216
+ sessionId: key.parentSessionId,
22217
+ route: "GET /session/:id/context",
22218
+ res,
22219
+ workspaceRegistry,
22220
+ daemonLog
22221
+ });
22222
+ if (!runtime) return;
22223
+ res.status(200).json({
22224
+ v: 1,
22225
+ sessionId,
22226
+ workspaceCwd: runtime.workspaceCwd,
22227
+ state: {}
22228
+ });
22229
+ },
20654
22230
  withOwnerReadSession(
20655
22231
  "GET /session/:id/context",
20656
22232
  async (_req, res, sessionId, runtime) => {
@@ -20682,6 +22258,28 @@ function registerSessionRoutes(app, deps) {
20682
22258
  );
20683
22259
  app.get(
20684
22260
  "/session/:id/supported-commands",
22261
+ (req, res, next) => {
22262
+ const sessionId = req.params["id"];
22263
+ const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
22264
+ if (!sessionId || !key) {
22265
+ next();
22266
+ return;
22267
+ }
22268
+ const runtime = requireSessionRuntime({
22269
+ sessionId: key.parentSessionId,
22270
+ route: "GET /session/:id/supported-commands",
22271
+ res,
22272
+ workspaceRegistry,
22273
+ daemonLog
22274
+ });
22275
+ if (!runtime) return;
22276
+ res.status(200).json({
22277
+ v: 1,
22278
+ sessionId,
22279
+ availableCommands: [],
22280
+ availableSkills: []
22281
+ });
22282
+ },
20685
22283
  withOwnerReadSession(
20686
22284
  "GET /session/:id/supported-commands",
20687
22285
  async (_req, res, sessionId, runtime) => {
@@ -20903,10 +22501,32 @@ function registerSessionRoutes(app, deps) {
20903
22501
  }
20904
22502
  const clientId = parseClientIdHeader(req, res);
20905
22503
  if (clientId === null) return;
22504
+ let delivery;
22505
+ if (body["delivery"] !== void 0) {
22506
+ try {
22507
+ delivery = parseChannelDelivery(body["delivery"]);
22508
+ } catch (err) {
22509
+ if (!isChannelDeliveryError(err)) throw err;
22510
+ res.status(400).json({ error: err.message, code: err.code });
22511
+ return;
22512
+ }
22513
+ }
20906
22514
  const promptId = crypto3.randomUUID();
22515
+ if (delivery && deps.channelDeliveryAuthorizations) {
22516
+ deps.channelDeliveryAuthorizations.authorizePrompt(
22517
+ runtime.workspaceCwd,
22518
+ {
22519
+ sessionId,
22520
+ deliveryId: promptId,
22521
+ target: delivery.target
22522
+ }
22523
+ );
22524
+ }
20907
22525
  const forwardedBody = { ...body };
20908
22526
  delete forwardedBody["deadlineMs"];
22527
+ delete forwardedBody["delivery"];
20909
22528
  const lastEventId = ownerBridge.getSessionLastEventId(sessionId);
22529
+ const eventEpoch = ownerBridge.getSessionEventEpoch(sessionId);
20910
22530
  addDaemonRequestAttribute("qwen-code.prompt_id", promptId);
20911
22531
  const abort = new AbortController();
20912
22532
  let responseFinished = false;
@@ -20936,10 +22556,21 @@ function registerSessionRoutes(app, deps) {
20936
22556
  {
20937
22557
  ...clientId !== void 0 ? { clientId } : {},
20938
22558
  promptId,
20939
- ...effectiveDeadlineMs !== void 0 ? { deadlineMs: effectiveDeadlineMs } : {}
22559
+ ...effectiveDeadlineMs !== void 0 ? { deadlineMs: effectiveDeadlineMs } : {},
22560
+ ...delivery !== void 0 ? {
22561
+ channelDelivery: {
22562
+ deliveryId: promptId,
22563
+ target: delivery.target
22564
+ }
22565
+ } : {}
20940
22566
  }
20941
22567
  );
20942
22568
  } catch (err) {
22569
+ deps.channelDeliveryAuthorizations?.revokePrompt(
22570
+ runtime.workspaceCwd,
22571
+ sessionId,
22572
+ promptId
22573
+ );
20943
22574
  res.off("close", onResClose);
20944
22575
  res.off("finish", onResFinish);
20945
22576
  if (daemonLog && err instanceof PromptQueueFullError) {
@@ -20984,12 +22615,23 @@ function registerSessionRoutes(app, deps) {
20984
22615
  );
20985
22616
  }
20986
22617
  }
20987
- ).catch(() => {
22618
+ ).finally(() => {
22619
+ if (delivery && deps.channelDeliveryAuthorizations) {
22620
+ const revokeTimer = setTimeout(() => {
22621
+ deps.channelDeliveryAuthorizations?.revokePrompt(
22622
+ runtime.workspaceCwd,
22623
+ sessionId,
22624
+ promptId
22625
+ );
22626
+ }, CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS);
22627
+ revokeTimer.unref();
22628
+ }
22629
+ }).catch(() => {
20988
22630
  });
20989
22631
  if (daemonLog) {
20990
22632
  daemonLog.info("prompt enqueued", { sessionId, promptId, clientId });
20991
22633
  }
20992
- res.status(202).json({ promptId, lastEventId });
22634
+ res.status(202).json({ promptId, lastEventId, eventEpoch });
20993
22635
  }
20994
22636
  )
20995
22637
  );
@@ -21078,6 +22720,29 @@ function registerSessionRoutes(app, deps) {
21078
22720
  app.post(
21079
22721
  "/session/:id/heartbeat",
21080
22722
  mutate(),
22723
+ (req, res, next) => {
22724
+ const sessionId = req.params["id"];
22725
+ const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
22726
+ if (!sessionId || !key) {
22727
+ next();
22728
+ return;
22729
+ }
22730
+ const runtime = requireSessionRuntime({
22731
+ sessionId: key.parentSessionId,
22732
+ route: "POST /session/:id/heartbeat",
22733
+ res,
22734
+ workspaceRegistry,
22735
+ daemonLog
22736
+ });
22737
+ if (!runtime) return;
22738
+ const clientId = parseClientIdHeader(req, res);
22739
+ if (clientId === null) return;
22740
+ res.status(200).json({
22741
+ sessionId,
22742
+ ...clientId ? { clientId } : {},
22743
+ lastSeenAt: Date.now()
22744
+ });
22745
+ },
21081
22746
  withOwnerMutableSession(
21082
22747
  "POST /session/:id/heartbeat",
21083
22748
  (req, res, sessionId, runtime) => {
@@ -21094,6 +22759,25 @@ function registerSessionRoutes(app, deps) {
21094
22759
  app.post(
21095
22760
  "/session/:id/detach",
21096
22761
  mutate(),
22762
+ (req, res, next) => {
22763
+ const sessionId = req.params["id"];
22764
+ const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
22765
+ if (!sessionId || !key) {
22766
+ next();
22767
+ return;
22768
+ }
22769
+ const runtime = requireSessionRuntime({
22770
+ sessionId: key.parentSessionId,
22771
+ route: "POST /session/:id/detach",
22772
+ res,
22773
+ workspaceRegistry,
22774
+ daemonLog
22775
+ });
22776
+ if (!runtime) return;
22777
+ const clientId = parseClientIdHeader(req, res);
22778
+ if (clientId === null) return;
22779
+ res.status(204).end();
22780
+ },
21097
22781
  withOwnerMutableSession(
21098
22782
  "POST /session/:id/detach",
21099
22783
  async (req, res, sessionId, runtime) => {
@@ -21146,6 +22830,7 @@ function registerSessionRoutes(app, deps) {
21146
22830
  clientId !== void 0 ? { clientId } : void 0
21147
22831
  )
21148
22832
  );
22833
+ clearBranchSessionEntry(sessionId);
21149
22834
  res.status(204).end();
21150
22835
  } catch (err) {
21151
22836
  sendBridgeError2(res, err, {
@@ -21172,6 +22857,9 @@ function registerSessionRoutes(app, deps) {
21172
22857
  );
21173
22858
  }, "onError")
21174
22859
  });
22860
+ for (const removedId of result.removed) {
22861
+ clearBranchSessionEntry(removedId);
22862
+ }
21175
22863
  res.status(200).json(result);
21176
22864
  } catch (err) {
21177
22865
  sendBridgeError2(res, err, { route: "POST /sessions/delete" });
@@ -21246,6 +22934,9 @@ function registerSessionRoutes(app, deps) {
21246
22934
  );
21247
22935
  }, "onError")
21248
22936
  });
22937
+ for (const removedId of result.removed) {
22938
+ clearBranchSessionEntry(removedId);
22939
+ }
21249
22940
  res.status(200).json(result);
21250
22941
  } catch (err) {
21251
22942
  sendBridgeError2(res, err, { route });
@@ -22176,7 +23867,8 @@ function toView(task) {
22176
23867
  sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
22177
23868
  // Absent runs (tool-created / never-fired) normalizes to [] so the client
22178
23869
  // never special-cases undefined.
22179
- runs: Array.isArray(task.runs) ? task.runs : []
23870
+ runs: Array.isArray(task.runs) ? task.runs : [],
23871
+ ...task.delivery !== void 0 ? { delivery: task.delivery } : {}
22180
23872
  };
22181
23873
  }
22182
23874
  __name(toView, "toView");
@@ -22209,7 +23901,13 @@ function canonicalCron(cron) {
22209
23901
  }
22210
23902
  __name(canonicalCron, "canonicalCron");
22211
23903
  function registerScheduledTaskCrudRoutes(app, deps) {
22212
- const { prefix, resolveTarget, mutate, safeBody: safeBody2 } = deps;
23904
+ const {
23905
+ prefix,
23906
+ resolveTarget,
23907
+ mutate,
23908
+ safeBody: safeBody2,
23909
+ channelDeliveryAuthorizations
23910
+ } = deps;
22213
23911
  const base = `${prefix}/scheduled-tasks`;
22214
23912
  app.get(base, async (req, res) => {
22215
23913
  const target = resolveTarget(req, res);
@@ -22286,6 +23984,16 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22286
23984
  });
22287
23985
  return;
22288
23986
  }
23987
+ let delivery;
23988
+ if (body["delivery"] !== void 0) {
23989
+ try {
23990
+ delivery = parseChannelDelivery(body["delivery"]);
23991
+ } catch (err) {
23992
+ if (!isChannelDeliveryError(err)) throw err;
23993
+ res.status(400).json({ error: err.message, code: err.code });
23994
+ return;
23995
+ }
23996
+ }
22289
23997
  const removedField = findRemovedTaskField(body);
22290
23998
  if (removedField) {
22291
23999
  res.status(400).json(removedFieldError(removedField));
@@ -22342,6 +24050,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22342
24050
  // minute the task was created — same guard cronScheduler.create uses.
22343
24051
  lastFiredAt: now - now % 6e4,
22344
24052
  enabled,
24053
+ ...delivery !== void 0 ? { delivery } : {},
22345
24054
  ...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
22346
24055
  ...nameResult.value !== void 0 ? { name: nameResult.value } : {}
22347
24056
  };
@@ -22381,6 +24090,15 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22381
24090
  });
22382
24091
  return;
22383
24092
  }
24093
+ if (task.delivery && task.sessionId) {
24094
+ channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
24095
+ sessionId: task.sessionId,
24096
+ taskId: task.id,
24097
+ target: task.delivery.target,
24098
+ recurring: task.recurring,
24099
+ lastFiredAt: task.lastFiredAt ?? void 0
24100
+ });
24101
+ }
22384
24102
  res.status(201).json(toView(task));
22385
24103
  });
22386
24104
  app.patch(`${base}/:id`, mutate(), async (req, res) => {
@@ -22395,6 +24113,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22395
24113
  const body = safeBody2(req);
22396
24114
  const patch = {};
22397
24115
  let clearName = false;
24116
+ let clearDelivery = false;
22398
24117
  const removedPatchField = findRemovedTaskField(body);
22399
24118
  if (removedPatchField) {
22400
24119
  res.status(400).json(removedFieldError(removedPatchField));
@@ -22459,7 +24178,20 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22459
24178
  }
22460
24179
  patch.enabled = body["enabled"];
22461
24180
  }
22462
- if (Object.keys(patch).length === 0 && !clearName) {
24181
+ if ("delivery" in body) {
24182
+ if (body["delivery"] === null) {
24183
+ clearDelivery = true;
24184
+ } else {
24185
+ try {
24186
+ patch.delivery = parseChannelDelivery(body["delivery"]);
24187
+ } catch (err) {
24188
+ if (!isChannelDeliveryError(err)) throw err;
24189
+ res.status(400).json({ error: err.message, code: err.code });
24190
+ return;
24191
+ }
24192
+ }
24193
+ }
24194
+ if (Object.keys(patch).length === 0 && !clearName && !clearDelivery) {
22463
24195
  res.status(400).json({
22464
24196
  error: "No updatable fields provided",
22465
24197
  code: "empty_patch"
@@ -22486,6 +24218,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22486
24218
  }
22487
24219
  const next = { ...current, ...patch };
22488
24220
  if (clearName) delete next.name;
24221
+ if (clearDelivery) delete next.delivery;
22489
24222
  const justReEnabled = current.enabled === false && patch.enabled === true;
22490
24223
  const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
22491
24224
  const becameRecurring = patch.recurring === true && current.recurring !== true;
@@ -22540,6 +24273,22 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22540
24273
  } catch {
22541
24274
  }
22542
24275
  }
24276
+ if (updated.delivery && updated.sessionId) {
24277
+ channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
24278
+ sessionId: updated.sessionId,
24279
+ taskId: updated.id,
24280
+ target: updated.delivery.target,
24281
+ recurring: updated.recurring,
24282
+ lastFiredAt: updated.lastFiredAt ?? void 0
24283
+ });
24284
+ }
24285
+ if (clearDelivery && updated.sessionId) {
24286
+ channelDeliveryAuthorizations?.revokeScheduledTask(
24287
+ workspaceCwd,
24288
+ updated.sessionId,
24289
+ updated.id
24290
+ );
24291
+ }
22543
24292
  res.status(200).json(toView(updated));
22544
24293
  });
22545
24294
  app.delete(`${base}/:id`, mutate(), async (req, res) => {
@@ -22582,6 +24331,13 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22582
24331
  await bridge.closeSession(boundSessionId).catch(() => {
22583
24332
  });
22584
24333
  }
24334
+ if (boundSessionId) {
24335
+ channelDeliveryAuthorizations?.revokeScheduledTask(
24336
+ workspaceCwd,
24337
+ boundSessionId,
24338
+ id
24339
+ );
24340
+ }
22585
24341
  res.status(200).json({ deleted: true, id });
22586
24342
  });
22587
24343
  app.post(`${base}/:id/run`, mutate(), async (req, res) => {
@@ -22662,17 +24418,30 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22662
24418
  }
22663
24419
  __name(registerScheduledTaskCrudRoutes, "registerScheduledTaskCrudRoutes");
22664
24420
  function registerScheduledTasksRoutes(app, deps) {
22665
- const { boundWorkspace, mutate, safeBody: safeBody2, bridge } = deps;
24421
+ const {
24422
+ boundWorkspace,
24423
+ mutate,
24424
+ safeBody: safeBody2,
24425
+ bridge,
24426
+ channelDeliveryAuthorizations
24427
+ } = deps;
22666
24428
  registerScheduledTaskCrudRoutes(app, {
22667
24429
  prefix: "",
22668
24430
  resolveTarget: /* @__PURE__ */ __name(() => ({ workspaceCwd: boundWorkspace, bridge }), "resolveTarget"),
22669
24431
  mutate,
22670
- safeBody: safeBody2
24432
+ safeBody: safeBody2,
24433
+ channelDeliveryAuthorizations
22671
24434
  });
22672
24435
  }
22673
24436
  __name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
22674
24437
  function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
22675
- const { workspaceRegistry, mutate, safeBody: safeBody2, manageScheduledTaskSessions } = deps;
24438
+ const {
24439
+ workspaceRegistry,
24440
+ mutate,
24441
+ safeBody: safeBody2,
24442
+ manageScheduledTaskSessions,
24443
+ channelDeliveryAuthorizations
24444
+ } = deps;
22676
24445
  registerScheduledTaskCrudRoutes(app, {
22677
24446
  prefix: "/workspaces/:workspace",
22678
24447
  resolveTarget: /* @__PURE__ */ __name((req, res) => {
@@ -22691,7 +24460,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
22691
24460
  };
22692
24461
  }, "resolveTarget"),
22693
24462
  mutate,
22694
- safeBody: safeBody2
24463
+ safeBody: safeBody2,
24464
+ channelDeliveryAuthorizations
22695
24465
  });
22696
24466
  }
22697
24467
  __name(registerWorkspaceQualifiedScheduledTasksRoutes, "registerWorkspaceQualifiedScheduledTasksRoutes");
@@ -22721,6 +24491,77 @@ function parseNameField(raw) {
22721
24491
  }
22722
24492
  __name(parseNameField, "parseNameField");
22723
24493
 
24494
+ // packages/cli/src/serve/routes/channel-notify.ts
24495
+ init_esbuild_shims();
24496
+ import { randomUUID as randomUUID6 } from "node:crypto";
24497
+ function sendDeliveryError(res, error2) {
24498
+ if (!isChannelDeliveryError(error2)) {
24499
+ res.status(502).json({
24500
+ error: "Channel delivery failed.",
24501
+ code: "channel_delivery_failed"
24502
+ });
24503
+ return;
24504
+ }
24505
+ const status = error2.code === "channel_delivery_invalid" ? 400 : error2.code === "channel_delivery_timeout" ? 504 : error2.code === "channel_worker_unavailable" || error2.code === "channel_delivery_queue_full" ? 503 : 502;
24506
+ res.status(status).json({ error: error2.message, code: error2.code });
24507
+ }
24508
+ __name(sendDeliveryError, "sendDeliveryError");
24509
+ function parseNotifyBody(body) {
24510
+ if (!Object.keys(body).every((key) => key === "text" || key === "delivery")) {
24511
+ throw new ChannelDeliveryError(
24512
+ "channel_delivery_invalid",
24513
+ "Invalid channel notification."
24514
+ );
24515
+ }
24516
+ return normalizeChannelDelivery(
24517
+ randomUUID6(),
24518
+ parseChannelDelivery(body["delivery"]),
24519
+ body["text"]
24520
+ );
24521
+ }
24522
+ __name(parseNotifyBody, "parseNotifyBody");
24523
+ function registerChannelNotifyRoutes(app, deps) {
24524
+ const deliver = /* @__PURE__ */ __name(async (workspaceCwd, req, res) => {
24525
+ try {
24526
+ if (!deps.deliverChannelMessage) {
24527
+ throw new ChannelDeliveryError(
24528
+ "channel_worker_unavailable",
24529
+ "Channel worker is not running."
24530
+ );
24531
+ }
24532
+ const request2 = parseNotifyBody(deps.safeBody(req));
24533
+ await deps.deliverChannelMessage(workspaceCwd, request2);
24534
+ res.status(200).json({ delivered: true, deliveryId: request2.deliveryId });
24535
+ } catch (error2) {
24536
+ sendDeliveryError(res, error2);
24537
+ }
24538
+ }, "deliver");
24539
+ app.post(
24540
+ "/workspace/notify",
24541
+ deps.mutate({ strict: true }),
24542
+ async (req, res) => {
24543
+ if (!requireTrustedWorkspaceRuntime(deps.workspaceRegistry.primary, res)) {
24544
+ return;
24545
+ }
24546
+ await deliver(deps.boundWorkspace, req, res);
24547
+ }
24548
+ );
24549
+ app.post(
24550
+ "/workspaces/:workspace/notify",
24551
+ deps.mutate({ strict: true }),
24552
+ async (req, res) => {
24553
+ const runtime = resolveWorkspaceRuntimeFromParam(
24554
+ deps.workspaceRegistry,
24555
+ req,
24556
+ res
24557
+ );
24558
+ if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res)) return;
24559
+ await deliver(runtime.workspaceCwd, req, res);
24560
+ }
24561
+ );
24562
+ }
24563
+ __name(registerChannelNotifyRoutes, "registerChannelNotifyRoutes");
24564
+
22724
24565
  // packages/cli/src/serve/routes/goals.ts
22725
24566
  init_esbuild_shims();
22726
24567
  var PROBE_CONCURRENCY = 10;
@@ -22989,6 +24830,11 @@ function startScheduledTaskKeepalive(opts) {
22989
24830
  log.debug("keepalive: readCronTasks failed, skipping this pass", err);
22990
24831
  return;
22991
24832
  }
24833
+ try {
24834
+ opts.onTasksRead?.(tasks);
24835
+ } catch (err) {
24836
+ log.debug("keepalive: onTasksRead failed", err);
24837
+ }
22992
24838
  for (const sessionId of collectBoundSessionIds(tasks)) {
22993
24839
  try {
22994
24840
  bridge.recordHeartbeat(sessionId);
@@ -23118,6 +24964,11 @@ async function rehydrateScheduledTaskSessions(deps) {
23118
24964
  log.debug("rehydrate: readCronTasks failed", err);
23119
24965
  return { loaded: [], failed: [] };
23120
24966
  }
24967
+ try {
24968
+ deps.onTasksRead?.(tasks);
24969
+ } catch (err) {
24970
+ log.debug("rehydrate: onTasksRead failed", err);
24971
+ }
23121
24972
  const sessionIds = collectBoundSessionIds(tasks);
23122
24973
  const loaded = [];
23123
24974
  const failed = [];
@@ -23477,6 +25328,7 @@ function createServeFeatures(deps) {
23477
25328
  persistSettingAvailable,
23478
25329
  sessionArtifactsPersistenceAvailable,
23479
25330
  sessionGenerationAvailable,
25331
+ workspaceGenerationAvailable,
23480
25332
  reloadAvailable,
23481
25333
  channelReloadAvailable,
23482
25334
  channelControlAvailable,
@@ -23513,6 +25365,7 @@ function createServeFeatures(deps) {
23513
25365
  sessionShellCommandEnabled,
23514
25366
  sessionArtifactsPersistenceAvailable,
23515
25367
  sessionGenerationAvailable: sessionGenerationAvailable(),
25368
+ workspaceGenerationAvailable: workspaceGenerationAvailable(),
23516
25369
  rateLimit: opts.rateLimit === true,
23517
25370
  reloadAvailable,
23518
25371
  channelReloadAvailable: channelReloadAvailable(),
@@ -24858,16 +26711,19 @@ data: ${dataJson}
24858
26711
  __name(formatSseFrame, "formatSseFrame");
24859
26712
  function registerSseEventsRoutes(app, deps) {
24860
26713
  const { workspaceRegistry, daemonLog, sendBridgeError: sendBridgeError2, writerIdleTimeoutMs } = deps;
24861
- app.get("/session/:id/events", (req, res) => {
26714
+ app.get("/session/:id/events", async (req, res) => {
24862
26715
  const sessionId = req.params["id"];
24863
26716
  const lastEventId = parseLastEventId(req.headers["last-event-id"]);
26717
+ const eventEpoch = parseEventEpochHeader(req.headers["x-qwen-event-epoch"]);
24864
26718
  const maxQueued = parseMaxQueuedQuery(req.query["maxQueued"], res);
24865
26719
  if (maxQueued === null) return;
24866
26720
  let iter;
26721
+ let busEpoch;
24867
26722
  const abort = new AbortController();
24868
26723
  try {
26724
+ const virtualKey = parseVirtualSubagentSessionId(sessionId);
24869
26725
  const runtime = requireSessionRuntime({
24870
- sessionId,
26726
+ sessionId: virtualKey?.parentSessionId ?? sessionId,
24871
26727
  route: "GET /session/:id/events",
24872
26728
  res,
24873
26729
  workspaceRegistry,
@@ -24875,13 +26731,33 @@ function registerSseEventsRoutes(app, deps) {
24875
26731
  });
24876
26732
  if (!runtime) return;
24877
26733
  const snapshot = req.query["snapshot"] === "1";
24878
- const iterable = runtime.bridge.subscribeEvents(sessionId, {
26734
+ const iterable = virtualKey ? await deps.virtualSubagentSessions?.subscribe(runtime, sessionId, {
24879
26735
  signal: abort.signal,
24880
26736
  lastEventId,
26737
+ ...maxQueued !== void 0 ? { maxQueued } : {}
26738
+ }) : runtime.bridge.subscribeEvents(sessionId, {
26739
+ signal: abort.signal,
26740
+ lastEventId,
26741
+ ...eventEpoch !== void 0 ? { epoch: eventEpoch } : {},
24881
26742
  ...maxQueued !== void 0 ? { maxQueued } : {},
24882
26743
  ...snapshot ? { snapshot: true } : {}
24883
26744
  });
26745
+ if (!iterable) {
26746
+ res.status(404).json({
26747
+ error: "Subagent session not found",
26748
+ code: "session_not_found",
26749
+ sessionId
26750
+ });
26751
+ return;
26752
+ }
24884
26753
  iter = iterable[Symbol.asyncIterator]();
26754
+ if (!virtualKey) {
26755
+ try {
26756
+ busEpoch = runtime.bridge.getSessionEventEpoch(sessionId);
26757
+ } catch {
26758
+ busEpoch = void 0;
26759
+ }
26760
+ }
24885
26761
  } catch (err) {
24886
26762
  if (err instanceof SubscriberLimitExceededError) {
24887
26763
  writeStderrLine(
@@ -24921,6 +26797,9 @@ function registerSseEventsRoutes(app, deps) {
24921
26797
  res.setHeader("Cache-Control", "no-cache, no-transform");
24922
26798
  res.setHeader("Connection", "keep-alive");
24923
26799
  res.setHeader("X-Accel-Buffering", "no");
26800
+ if (busEpoch !== void 0) {
26801
+ res.setHeader("X-Qwen-Event-Epoch", busEpoch);
26802
+ }
24924
26803
  res.flushHeaders();
24925
26804
  activeSseCount++;
24926
26805
  let sseCounted = true;
@@ -25046,7 +26925,7 @@ function registerSseEventsRoutes(app, deps) {
25046
26925
  const data = next.value.data;
25047
26926
  const gap = typeof data.earliestAvailableId === "number" && typeof data.lastDeliveredId === "number" ? data.earliestAvailableId - data.lastDeliveredId - 1 : void 0;
25048
26927
  writeStderrLine(
25049
- `qwen serve: SSE ring eviction detected (session ${sessionId}): lastEventId=${data.lastDeliveredId ?? "?"}, earliestInRing=${data.earliestAvailableId ?? "?"}, gap=${gap ?? "?"} events, reason=${data.reason ?? "?"}. Consumer must call loadSession to recover.`
26928
+ `qwen serve: SSE ring eviction detected (session ${sessionId}): lastEventId=${data.lastDeliveredId ?? "?"}, earliestInRing=${data.earliestAvailableId ?? "?"}, gap=${gap ?? "?"} events, reason=${data.reason ?? "?"}` + (typeof data.detail === "string" ? `, detail=${data.detail}` : "") + `. Consumer must call loadSession to recover.`
25050
26929
  );
25051
26930
  }
25052
26931
  await writeWithBackpressure(formatSseFrame(next.value));
@@ -26034,7 +27913,7 @@ __name(registerWorkspaceQualifiedLifecycleRoutes, "registerWorkspaceQualifiedLif
26034
27913
 
26035
27914
  // packages/cli/src/serve/routes/workspace-management.ts
26036
27915
  init_esbuild_shims();
26037
- import { readdir, stat } from "node:fs/promises";
27916
+ import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
26038
27917
  import { realpathSync as realpathSync2 } from "node:fs";
26039
27918
  import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute7, join as join8, resolve as resolve4, sep as sep3 } from "node:path";
26040
27919
  var MAX_PATH_SUGGESTIONS = 50;
@@ -26256,7 +28135,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26256
28135
  const suggestions = [];
26257
28136
  let truncated = false;
26258
28137
  try {
26259
- const entries = await readdir(dir, { withFileTypes: true });
28138
+ const entries = await readdir2(dir, { withFileTypes: true });
26260
28139
  entries.sort((a, b) => a.name.localeCompare(b.name));
26261
28140
  for (const entry of entries) {
26262
28141
  if (entry.name.startsWith(".") && !filter.startsWith(".")) continue;
@@ -26266,7 +28145,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26266
28145
  let isDir = entry.isDirectory();
26267
28146
  if (!isDir && entry.isSymbolicLink()) {
26268
28147
  try {
26269
- isDir = (await stat(join8(dir, entry.name))).isDirectory();
28148
+ isDir = (await stat2(join8(dir, entry.name))).isDirectory();
26270
28149
  } catch {
26271
28150
  continue;
26272
28151
  }
@@ -26386,7 +28265,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26386
28265
  return;
26387
28266
  }
26388
28267
  try {
26389
- const s = await stat(canonical);
28268
+ const s = await stat2(canonical);
26390
28269
  if (!s.isDirectory()) {
26391
28270
  res.status(400).json({
26392
28271
  error: "Path is not a directory",
@@ -27189,7 +29068,7 @@ __name(registerWorkspaceManagementRoutes, "registerWorkspaceManagementRoutes");
27189
29068
 
27190
29069
  // packages/cli/src/serve/routes/workspace-git.ts
27191
29070
  init_esbuild_shims();
27192
- import * as fs4 from "node:fs";
29071
+ import * as fs5 from "node:fs";
27193
29072
  import * as path14 from "node:path";
27194
29073
  function registerWorkspaceGitRoutes(app, deps) {
27195
29074
  app.get("/workspace/git", async (_req, res) => {
@@ -27216,8 +29095,8 @@ function registerWorkspaceQualifiedGitRoutes(app, deps) {
27216
29095
  let gitCwd = runtime.workspaceCwd;
27217
29096
  if (typeof rawCwd === "string" && rawCwd.length > 0) {
27218
29097
  try {
27219
- const resolved = fs4.realpathSync(path14.resolve(rawCwd));
27220
- const root = fs4.realpathSync(runtime.workspaceCwd);
29098
+ const resolved = fs5.realpathSync(path14.resolve(rawCwd));
29099
+ const root = fs5.realpathSync(runtime.workspaceCwd);
27221
29100
  const rel = path14.relative(root, resolved);
27222
29101
  if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
27223
29102
  gitCwd = resolved;
@@ -27641,6 +29520,38 @@ var WorkspaceGitState = class {
27641
29520
 
27642
29521
  // packages/cli/src/serve/routes/workspace-mcp-control.ts
27643
29522
  init_esbuild_shims();
29523
+ function parseMcpReloadOptions(body, res) {
29524
+ const forceReconnectAll = body["forceReconnectAll"];
29525
+ if (forceReconnectAll !== void 0 && typeof forceReconnectAll !== "boolean") {
29526
+ res.status(400).json({
29527
+ error: "`forceReconnectAll` must be a boolean",
29528
+ code: "invalid_force_reconnect_all_flag"
29529
+ });
29530
+ return null;
29531
+ }
29532
+ const forceReconnectWhich = body["forceReconnectWhich"];
29533
+ if (forceReconnectWhich !== void 0 && (!Array.isArray(forceReconnectWhich) || forceReconnectWhich.some(
29534
+ (serverName) => typeof serverName !== "string" || serverName.length === 0
29535
+ ))) {
29536
+ res.status(400).json({
29537
+ error: "`forceReconnectWhich` must be an array of server names",
29538
+ code: "invalid_force_reconnect_which"
29539
+ });
29540
+ return null;
29541
+ }
29542
+ if (forceReconnectAll === true && forceReconnectWhich !== void 0) {
29543
+ res.status(400).json({
29544
+ error: "`forceReconnectAll` and `forceReconnectWhich` cannot be used together",
29545
+ code: "conflicting_force_reconnect_options"
29546
+ });
29547
+ return null;
29548
+ }
29549
+ return {
29550
+ forceReconnectAll,
29551
+ forceReconnectWhich
29552
+ };
29553
+ }
29554
+ __name(parseMcpReloadOptions, "parseMcpReloadOptions");
27644
29555
  function registerWorkspaceMcpControlRoutes(app, deps) {
27645
29556
  const {
27646
29557
  boundWorkspace,
@@ -27667,9 +29578,11 @@ function registerWorkspaceMcpControlRoutes(app, deps) {
27667
29578
  app.post(
27668
29579
  "/workspace/mcp/reload",
27669
29580
  mutate({ strict: true }),
27670
- async (_req, res) => {
29581
+ async (req, res) => {
29582
+ const options = parseMcpReloadOptions(safeBody2(req), res);
29583
+ if (!options) return;
27671
29584
  try {
27672
- const result = await bridge.reloadWorkspaceMcp();
29585
+ const result = await bridge.reloadWorkspaceMcp(options);
27673
29586
  res.status(202).json(result);
27674
29587
  } catch (err) {
27675
29588
  sendBridgeError2(res, err, { route: "POST /workspace/mcp/reload" });
@@ -27874,9 +29787,11 @@ function registerWorkspaceQualifiedMcpControlRoutes(app, deps) {
27874
29787
  res
27875
29788
  );
27876
29789
  if (!runtime) return;
29790
+ const options = parseMcpReloadOptions(deps.safeBody(req), res);
29791
+ if (!options) return;
27877
29792
  const route = "POST /workspaces/:workspace/mcp/reload";
27878
29793
  try {
27879
- const result = await runtime.bridge.reloadWorkspaceMcp();
29794
+ const result = await runtime.bridge.reloadWorkspaceMcp(options);
27880
29795
  res.status(202).json(result);
27881
29796
  } catch (err) {
27882
29797
  deps.sendBridgeError(res, err, { route });
@@ -29251,6 +31166,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29251
31166
  (runtime) => runtime.bridge.generateSessionContent !== void 0
29252
31167
  );
29253
31168
  }, "sessionGenerationAvailable"),
31169
+ workspaceGenerationAvailable: /* @__PURE__ */ __name(() => primaryBridge.generateWorkspaceContent !== void 0, "workspaceGenerationAvailable"),
29254
31170
  // Registry injection supplies the primary workspace service through the
29255
31171
  // runtime, so it has the same reload surface as legacy deps.workspace.
29256
31172
  reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
@@ -29544,6 +31460,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29544
31460
  maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
29545
31461
  languageCodes
29546
31462
  });
31463
+ registerChannelNotifyRoutes(app, {
31464
+ boundWorkspace: primaryBoundWorkspace,
31465
+ workspaceRegistry,
31466
+ mutate,
31467
+ safeBody,
31468
+ deliverChannelMessage: deps.deliverChannelMessage
31469
+ });
29547
31470
  registerWorkspaceStatusRoutes(app, {
29548
31471
  boundWorkspace: primaryBoundWorkspace,
29549
31472
  bridge: primaryBridge,
@@ -29609,6 +31532,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29609
31532
  parseClientId: parseClientIdHeader,
29610
31533
  safeBody
29611
31534
  });
31535
+ mountWorkspaceGenerationRoutes(app, {
31536
+ bridge: primaryBridge,
31537
+ mutate,
31538
+ parseClientId: parseClientIdHeader,
31539
+ safeBody
31540
+ });
29612
31541
  mountWorkspaceQualifiedAgentsRoutes(app, {
29613
31542
  workspaceRegistry,
29614
31543
  mutate,
@@ -29785,6 +31714,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29785
31714
  allowPrivateAuthBaseUrl: opts.allowPrivateAuthBaseUrl === true,
29786
31715
  installAuthProvider: deps.installAuthProvider
29787
31716
  });
31717
+ const virtualSubagentSessions = new VirtualSubagentSessions();
29788
31718
  registerSessionRoutes(app, {
29789
31719
  boundWorkspace: primaryBoundWorkspace,
29790
31720
  bridge: primaryBridge,
@@ -29793,9 +31723,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29793
31723
  mutate,
29794
31724
  sendBridgeError: sendBridgeError2,
29795
31725
  daemonLog,
31726
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
29796
31727
  promptDeadlineMs: opts.promptDeadlineMs,
29797
31728
  sessionShellCommandEnabled,
29798
- languageCodes
31729
+ languageCodes,
31730
+ virtualSubagentSessions
29799
31731
  });
29800
31732
  registerWorkspaceMcpControlRoutes(app, {
29801
31733
  boundWorkspace: primaryBoundWorkspace,
@@ -29887,7 +31819,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29887
31819
  boundWorkspace: primaryBoundWorkspace,
29888
31820
  mutate,
29889
31821
  safeBody,
29890
- bridge: deps.manageScheduledTaskSessions ? bridge : void 0
31822
+ bridge: deps.manageScheduledTaskSessions ? bridge : void 0,
31823
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
29891
31824
  });
29892
31825
  registerGoalsRoutes(app, {
29893
31826
  boundWorkspace: primaryBoundWorkspace,
@@ -29897,16 +31830,32 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29897
31830
  workspaceRegistry,
29898
31831
  mutate,
29899
31832
  safeBody,
29900
- manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true
31833
+ manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
31834
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
29901
31835
  });
29902
31836
  registerUsageStatsRoutes(app);
29903
31837
  if (deps.manageScheduledTaskSessions) {
31838
+ const registerScheduledTaskAuthorizations = /* @__PURE__ */ __name((workspaceCwd, tasks) => {
31839
+ const authorizations = deps.channelDeliveryAuthorizations;
31840
+ if (!authorizations) return;
31841
+ for (const task of tasks) {
31842
+ if (!task.delivery || !task.sessionId) continue;
31843
+ authorizations.registerScheduledTask(workspaceCwd, {
31844
+ sessionId: task.sessionId,
31845
+ taskId: task.id,
31846
+ target: task.delivery.target,
31847
+ recurring: task.recurring,
31848
+ ...typeof task.lastFiredAt === "number" ? { lastFiredAt: task.lastFiredAt } : {}
31849
+ });
31850
+ }
31851
+ }, "registerScheduledTaskAuthorizations");
29904
31852
  const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
29905
31853
  const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
29906
31854
  const rehydrateWorkspace = /* @__PURE__ */ __name((taskBridge, workspaceCwd) => {
29907
31855
  void rehydrateScheduledTaskSessions({
29908
31856
  bridge: taskBridge,
29909
31857
  boundWorkspace: workspaceCwd,
31858
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(workspaceCwd, tasks), "onTasksRead"),
29910
31859
  onError: /* @__PURE__ */ __name((sessionId, err) => {
29911
31860
  process.stderr.write(
29912
31861
  `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
@@ -29931,7 +31880,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29931
31880
  const keepalive = startScheduledTaskKeepalive({
29932
31881
  bridge: runtime.bridge,
29933
31882
  boundWorkspace: runtime.workspaceCwd,
29934
- intervalMs: keepaliveIntervalMs
31883
+ intervalMs: keepaliveIntervalMs,
31884
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
29935
31885
  });
29936
31886
  rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
29937
31887
  keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
@@ -29961,7 +31911,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29961
31911
  workspaceRegistry,
29962
31912
  daemonLog,
29963
31913
  writerIdleTimeoutMs: opts.writerIdleTimeoutMs,
29964
- sendBridgeError: sendBridgeError2
31914
+ sendBridgeError: sendBridgeError2,
31915
+ virtualSubagentSessions
29965
31916
  });
29966
31917
  acpHandleRef.current = mountAcpHttp(app, primaryBridge, {
29967
31918
  boundWorkspace: primaryBoundWorkspace,