@qwen-code/qwen-code 0.20.2-jobbench-no-todo-write.0 → 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-WBRBHD2M.js → StandaloneSessionPicker-BIRMPLRD.js} +66 -58
  7. package/chunks/{acp-startup-profiler-N3RHHXJ3.js → acp-startup-profiler-RV3IV562.js} +2 -2
  8. package/chunks/{acpAgent-BBQZ33CA.js → acpAgent-6J2U72PQ.js} +706 -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-SSCNEHZZ.js → build-RV63TIRH.js} +2 -3
  16. package/chunks/{ca-N6VVUFVB.js → ca-25EDXPFZ.js} +2 -0
  17. package/chunks/{channel-worker-group-LFBT7K64.js → channel-worker-group-2ZD7TVAT.js} +7 -6
  18. package/chunks/{channel-worker-manager-3RUPERG2.js → channel-worker-manager-4OA4BCGB.js} +189 -29
  19. package/chunks/{channel-worker-supervisor-A3KVATD3.js → channel-worker-supervisor-V7KCFJTS.js} +6 -5
  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-B2HSPMD4.js → chunk-2NH6DYI4.js} +12 -12
  24. package/chunks/chunk-2SCDWPXI.js +246 -0
  25. package/chunks/{chunk-JK26TQON.js → chunk-2X55UKQE.js} +3 -3
  26. package/chunks/{chunk-7VUQQBR7.js → chunk-3QMGYBFN.js} +2 -65
  27. package/chunks/{chunk-UMCULC5M.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-GPMVHZP4.js → chunk-4WIZGAH3.js} +7 -7
  31. package/chunks/{chunk-CI3GWKGJ.js → chunk-55DJUCI2.js} +87 -29
  32. package/chunks/{chunk-QNLNLENL.js → chunk-5I2IWRSH.js} +2 -2
  33. package/chunks/{chunk-D7WXIW7H.js → chunk-5NBDS5S6.js} +145 -5
  34. package/chunks/{chunk-E4IMU4Y5.js → chunk-63P4EL5V.js} +1 -1
  35. package/chunks/chunk-6FGBXPWM.js +293 -0
  36. package/chunks/{chunk-NEEB7UEN.js → chunk-6GMVPFB2.js} +153 -72
  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-77OZOGPT.js → chunk-7JURR4JT.js} +1 -1
  40. package/chunks/{chunk-4MWNZNJ4.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-B3I77W5J.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-7TLUW4ZE.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-H4A4A2SY.js → chunk-CIKQ7KKO.js} +4625 -8645
  52. package/chunks/{chunk-QZJY47IE.js → chunk-D3UEZIQH.js} +7 -5
  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-6NRFYMKG.js → chunk-EBJQ6AXW.js} +11 -10
  58. package/chunks/{chunk-HABKX6LY.js → chunk-EPDRMGT4.js} +164 -17
  59. package/chunks/{chunk-P2BQZ7H7.js → chunk-ETSW4KLJ.js} +2 -2
  60. package/chunks/{chunk-KHOVYUHX.js → chunk-FNQ6T3CV.js} +20 -3
  61. package/chunks/{chunk-64EG42HV.js → chunk-FQK6JAFG.js} +72 -23
  62. package/chunks/{chunk-L6U47G5P.js → chunk-FSITMZJH.js} +8 -8
  63. package/chunks/{chunk-6RLROE6G.js → chunk-GLWP3FDB.js} +80 -15
  64. package/chunks/{chunk-CXIOPXRR.js → chunk-GSN55ZRI.js} +5 -5
  65. package/chunks/{chunk-LVA5OHQO.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-NXE6SQIV.js → chunk-IJTOWOD7.js} +14 -3
  69. package/chunks/chunk-IKCX4CCL.js +469 -0
  70. package/chunks/{chunk-7SSWNGEJ.js → chunk-IKYJHJNF.js} +3 -3
  71. package/chunks/{chunk-64XKYOXK.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-SVIMKSEI.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-7PIL2BYF.js → chunk-JVPM2ULZ.js} +6 -6
  78. package/chunks/{chunk-KBB5O3JO.js → chunk-JXJFVC6E.js} +37 -18
  79. package/chunks/chunk-JZA3JUDJ.js +82 -0
  80. package/chunks/{chunk-45PO6ZIS.js → chunk-K36B6G2O.js} +5 -5
  81. package/chunks/{chunk-GPSKDNEE.js → chunk-K4XWPEWB.js} +4 -4
  82. package/chunks/{chunk-K7EUPLIP.js → chunk-KIM5GUMA.js} +654 -117
  83. package/chunks/{chunk-42W5BDEY.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-26CBI4DC.js → chunk-LB6DUZ26.js} +259 -67
  88. package/chunks/chunk-LEH5C7FV.js +232 -0
  89. package/chunks/{chunk-UTGFTJ2H.js → chunk-LH2BYDQ5.js} +6 -4
  90. package/chunks/{chunk-QKTHJXCS.js → chunk-LK7CHLVP.js} +79 -2
  91. package/chunks/{chunk-V7WNRZL7.js → chunk-LKEJ26GS.js} +11 -11
  92. package/chunks/{chunk-6VPLV3L3.js → chunk-LQIW3YFY.js} +227 -41
  93. package/chunks/chunk-LS77BEZP.js +405 -0
  94. package/chunks/{chunk-5WDRI7US.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-CJQ3FZ2G.js → chunk-MVSUYZDT.js} +4 -4
  99. package/chunks/{chunk-6FZYKBKV.js → chunk-MZAXJAUM.js} +1 -1
  100. package/chunks/{chunk-32L4D2O2.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-6S5HSCOI.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-4SCOLXTD.js → chunk-PC6JANNU.js} +5 -5
  108. package/chunks/{chunk-IWALV67J.js → chunk-PHOF65IG.js} +4300 -1284
  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-5XORMWA2.js → chunk-PSOO6YXD.js} +18 -15
  113. package/chunks/{chunk-X6N25LXS.js → chunk-PWTZEM3C.js} +2 -2
  114. package/chunks/{chunk-GSX6P2JW.js → chunk-PWVFN2LF.js} +1 -1
  115. package/chunks/{chunk-AHX6AKPD.js → chunk-Q4M4MDQ4.js} +2 -2
  116. package/chunks/{chunk-3EHJ44GG.js → chunk-QAF7NMK7.js} +1 -1
  117. package/chunks/{chunk-WSYKDFYR.js → chunk-R5AFZNQW.js} +5 -5
  118. package/chunks/{chunk-63DJBU32.js → chunk-RF3EXIHJ.js} +39 -18
  119. package/chunks/{chunk-4K7VDKAD.js → chunk-RHLZR4E5.js} +1 -1
  120. package/chunks/{chunk-SXPSOMQ4.js → chunk-RIBKPMRP.js} +220 -141
  121. package/chunks/{chunk-RVLZCXEE.js → chunk-RWTEFFPU.js} +82 -3
  122. package/chunks/{chunk-ZUTM4LHM.js → chunk-RZIX2G32.js} +1 -1
  123. package/chunks/{chunk-ZKBNRL6O.js → chunk-SQCQ4KO2.js} +336 -404
  124. package/chunks/{chunk-THJNPLI4.js → chunk-TARRHLLG.js} +1 -0
  125. package/chunks/{chunk-RHYFF54J.js → chunk-TEHGS6UP.js} +50 -21
  126. package/chunks/{chunk-ACQJPDDS.js → chunk-TGILQ3YH.js} +8 -8
  127. package/chunks/{chunk-Q2YKNMLS.js → chunk-TOFQCPDC.js} +43 -10
  128. package/chunks/{chunk-ACZIBDYD.js → chunk-TPRQ7RZH.js} +587 -176
  129. package/chunks/{chunk-T4TZQJ7W.js → chunk-TWPJO254.js} +5 -16
  130. package/chunks/{chunk-7MWABCXU.js → chunk-U7M2DMGW.js} +3 -3
  131. package/chunks/{chunk-KQQ757OQ.js → chunk-UDX5OBWR.js} +41 -9
  132. package/chunks/{chunk-SRPZG4ER.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-TDDFEPBX.js → chunk-VIA5XA4U.js} +5 -2
  137. package/chunks/{chunk-3BJDQVE6.js → chunk-VRYUBFMC.js} +1 -1
  138. package/chunks/{chunk-PLQODS7F.js → chunk-VULLI6WQ.js} +172 -6
  139. package/chunks/{chunk-GN45XAAU.js → chunk-WCXCRJYB.js} +1 -1
  140. package/chunks/{chunk-2LI23QA6.js → chunk-X5XDDSSH.js} +1 -1
  141. package/chunks/{chunk-O32RMIMO.js → chunk-Y34KJKDC.js} +1 -1
  142. package/chunks/{chunk-7ZD5EKXE.js → chunk-YBL3QUDD.js} +2 -2
  143. package/chunks/{chunk-H4AR2JQF.js → chunk-YH6G52F2.js} +3 -3
  144. package/chunks/{chunk-3G3UUMRS.js → chunk-YPE6A4GC.js} +2 -2
  145. package/chunks/{chunk-3F2JUWCH.js → chunk-YX324OPW.js} +1 -1
  146. package/chunks/{chunk-CGIDQG6J.js → chunk-Z2BC6UJ5.js} +3 -3
  147. package/chunks/{chunk-QLJUC7TG.js → chunk-ZD6UTE4A.js} +1 -1
  148. package/chunks/{chunk-ZPWJZHJ2.js → chunk-ZFDTEDCF.js} +6 -6
  149. package/chunks/chunk-ZJHVAS7M.js +289 -0
  150. package/chunks/{chunk-XAGLQITN.js → chunk-ZNAUOR2I.js} +15 -12
  151. package/chunks/{chunk-T2L47JJK.js → chunk-ZOIFNCKL.js} +4 -4
  152. package/chunks/{computer-use-RZ3UUWYW.js → computer-use-SOQ4E3VX.js} +43 -34
  153. package/chunks/{config-utils-SQUBZEQM.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-EQG73FT6.js → create-sub-session-QRJLW5BV.js} +43 -34
  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-XRSKQPHQ.js → edit-OBDSQURM.js} +43 -34
  171. package/chunks/{en-USMCCJAJ.js → en-MTWBNGDO.js} +15 -0
  172. package/chunks/{enter-worktree-WAHCWE6I.js → enter-worktree-U6MRPQ2P.js} +43 -34
  173. package/chunks/{enterPlanMode-QIOYLDCF.js → enterPlanMode-BC5QUZZ2.js} +43 -34
  174. package/chunks/{environment-T3FXCDJI.js → environment-W5UFC2CH.js} +46 -37
  175. package/chunks/errors-M7CLORXH.js +88 -0
  176. package/chunks/{exit-worktree-RHVTLX6T.js → exit-worktree-DGNYMECB.js} +43 -34
  177. package/chunks/{exitPlanMode-UATOE2GQ.js → exitPlanMode-GXTBWQAR.js} +43 -34
  178. package/chunks/{fast-path-J3RHOYSZ.js → fast-path-JJZFJANL.js} +6 -6
  179. package/chunks/{fast-path-settings-XB3CPUJT.js → fast-path-settings-WQJU2LAT.js} +2 -2
  180. package/chunks/{fr-WVHEBDDB.js → fr-45RLL55O.js} +1 -0
  181. package/chunks/{gemini-P72OGOH6.js → gemini-QS36EBZV.js} +133 -102
  182. package/chunks/{geminiContentGenerator-F6EG5FXF.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-WHASQZRX.js → glob-V7R3PSK3.js} +43 -34
  189. package/chunks/{grep-LS7AADJ3.js → grep-QYPSK7OP.js} +43 -34
  190. package/chunks/handleAutoUpdate-6DBEZYPV.js +81 -0
  191. package/chunks/{i18n-IMVASWIF.js → i18n-VUJJZIMU.js} +44 -35
  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-L6UY7OM7.js → managed-npm-update-JYEMMXA3.js} +94 -37
  206. package/chunks/mcp-6DBDJPFU.js +83 -0
  207. package/chunks/{monitor-DXYFB5QD.js → monitor-R3ODH5U6.js} +45 -35
  208. package/chunks/node-UUDY34IG.js +305 -0
  209. package/chunks/nonInteractiveCli-MOYCYBBU.js +141 -0
  210. package/chunks/{notebook-edit-KGD7YJEA.js → notebook-edit-BNOK452R.js} +43 -34
  211. package/chunks/{openaiContentGenerator-C74A2XAU.js → openaiContentGenerator-WMCU3O2H.js} +27 -17
  212. package/chunks/pidfile-TFRZZZIO.js +86 -0
  213. package/chunks/{processUtils-GUT5B4R6.js → processUtils-RT7UNCC2.js} +2 -2
  214. package/chunks/{pt-OK455PLH.js → pt-22Q3FP73.js} +1 -0
  215. package/chunks/{qwenContentGenerator-PT46FQPA.js → qwenContentGenerator-HHCRK4SX.js} +56 -41
  216. package/chunks/{qwenOAuth2-S7DZHUUU.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-QO4PT5NV.js → run-qwen-serve-FU6HEM4J.js} +276 -62
  224. package/chunks/{runtime-EOTXBUM6.js → runtime-XXRRTNP6.js} +55 -44
  225. package/chunks/{scheduler-MAIQ2PHR.js → scheduler-G2ZS2Z7E.js} +43 -34
  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-CBCC3XQC.js → server-4UMH7OIZ.js} +2348 -396
  232. package/chunks/{session-RQUEFQDL.js → session-K3O3Q2SV.js} +107 -88
  233. package/chunks/{settings-QHXCJDSR.js → settings-CR2EWTBA.js} +53 -44
  234. package/chunks/shell-HH3PF3A2.js +83 -0
  235. package/chunks/{skill-WHSGTGKP.js → skill-I3SDA4MB.js} +17 -15
  236. package/chunks/spawnChannel-RWNDBXGA.js +82 -0
  237. package/chunks/{src-F3HKX47D.js → src-GE4TTTML.js} +290 -171
  238. package/chunks/{standalone-update-BKLONSVI.js → standalone-update-Q6WFRZZQ.js} +45 -36
  239. package/chunks/{startInteractiveUI-TNJ37X5W.js → startInteractiveUI-SLZGHRPH.js} +736 -298
  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-LUHJ7ZCC.js → team-create-YJALH5D2.js} +44 -35
  246. package/chunks/{team-delete-BB3CG3QF.js → team-delete-QE2UXJL7.js} +7 -7
  247. package/chunks/{team-plan-approval-X3DYRL6L.js → team-plan-approval-34QFYKGN.js} +43 -34
  248. package/chunks/theme-manager-SWRILQHI.js +77 -0
  249. package/chunks/todoWrite-VQ7FKOHL.js +358 -0
  250. package/chunks/{tool-search-BAWOETUY.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-4UEOIKOF.js → trustedFolders-KHXHY6PY.js} +44 -35
  255. package/chunks/{update-relaunch-WDWABT5P.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-OKUE3JLF.js → validateNonInterActiveAuth-3R223G3R.js} +91 -81
  259. package/chunks/{version-GMUULLWB.js → version-HS7YSFHV.js} +1 -1
  260. package/chunks/{web-fetch-JBWTMPFN.js → web-fetch-NKCSG7ZE.js} +18 -16
  261. package/chunks/{web-search-27COJHJT.js → web-search-S62WAP4S.js} +13 -27
  262. package/chunks/{workflow-5L37J7YF.js → workflow-QAGU5RU4.js} +44 -35
  263. package/chunks/workspace-providers-status-QSVZUETE.js +86 -0
  264. package/chunks/{workspace-registration-store-TYPYXIP6.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-HNWBEL5H.js +0 -77
  333. package/chunks/agent-KTMY6SF3.js +0 -72
  334. package/chunks/agent-headless-HJ56ZZOW.js +0 -66
  335. package/chunks/bridge-AMC5AD7W.js +0 -80
  336. package/chunks/chunk-CBOQ3HY7.js +0 -2019
  337. package/chunks/chunk-UHGNAWHK.js +0 -6928
  338. package/chunks/contextCommand-PW4GINQU.js +0 -71
  339. package/chunks/daemon-status-provider-3IWTBWQ3.js +0 -79
  340. package/chunks/earlyInputCapture-TYNI3B6E.js +0 -73
  341. package/chunks/errors-QAWTJTAW.js +0 -79
  342. package/chunks/handleAutoUpdate-V5A3JHOG.js +0 -72
  343. package/chunks/initializer-JJLF5JCJ.js +0 -77
  344. package/chunks/installationInfo-LAWMHQAG.js +0 -71
  345. package/chunks/list-L2ECB6UM.js +0 -80
  346. package/chunks/loadedSettingsAdapter-RLMZ4Z3E.js +0 -74
  347. package/chunks/mcp-E4O7Z6FO.js +0 -74
  348. package/chunks/nonInteractiveCli-GU2UKULE.js +0 -131
  349. package/chunks/pidfile-IWQWZNZV.js +0 -77
  350. package/chunks/read-file-ZOCXW4AD.js +0 -31
  351. package/chunks/resumeHistoryUtils-TJWRDE2L.js +0 -83
  352. package/chunks/ripGrep-OFKAW2VE.js +0 -64
  353. package/chunks/serve-UB4CF67Q.js +0 -80
  354. package/chunks/shell-RPK7EAOC.js +0 -74
  355. package/chunks/spawnChannel-IUP3ZNMT.js +0 -73
  356. package/chunks/theme-manager-ALL7F4CJ.js +0 -68
  357. package/chunks/total-session-admission-PLONPNXI.js +0 -74
  358. package/chunks/updateCheck-PVROE4GR.js +0 -87
  359. package/chunks/useAutoAcceptIndicator-6BNLNN5S.js +0 -85
  360. package/chunks/workspace-providers-status-2U3IF4TX.js +0 -77
  361. package/chunks/workspace-registry-DLQDDDIF.js +0 -78
  362. package/chunks/workspace-service-7K3LF4QX.js +0 -89
  363. package/chunks/workspace-skills-status-4DOZ3DBS.js +0 -76
  364. package/chunks/write-file-PTPXDKZ3.js +0 -64
  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-SXPSOMQ4.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,17 +33,66 @@ import {
30
33
  toJson,
31
34
  toJsonl,
32
35
  toMarkdown
33
- } from "./chunk-6NRFYMKG.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-RS7MT2QG.js";
39
- import "./chunk-GN45XAAU.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";
91
+ import {
92
+ createSingleWorkspaceRegistry,
93
+ createWorkspaceSessionOwnerIndex
94
+ } from "./chunk-UGYMA4EI.js";
95
+ import "./chunk-GRC5HGPI.js";
44
96
  import {
45
97
  CAPABILITIES_SCHEMA_VERSION,
46
98
  CLIENT_ID_HEADER,
@@ -98,102 +150,33 @@ import {
98
150
  setRateLimiter,
99
151
  unsafeRevealSecret,
100
152
  validateMcpRuntimeServerName
101
- } from "./chunk-NXE6SQIV.js";
153
+ } from "./chunk-IJTOWOD7.js";
102
154
  import {
103
155
  isLoopbackBind
104
156
  } from "./chunk-RXFQM6FQ.js";
105
- import {
106
- createDaemonStatusProvider
107
- } from "./chunk-SVIMKSEI.js";
108
- import "./chunk-LXXMOYPL.js";
109
- import "./chunk-CJQ3FZ2G.js";
110
- import "./chunk-E5Z2AVNV.js";
111
- import {
112
- createWorkspaceProvidersStatusProvider
113
- } from "./chunk-L6U47G5P.js";
114
- import {
115
- getAuthTypeFromEnv,
116
- resolveCliGenerationConfig
117
- } from "./chunk-42W5BDEY.js";
118
- import {
119
- snapshotProcessEnv
120
- } from "./chunk-P2BQZ7H7.js";
121
- import {
122
- createWorkspaceSkillsStatusProvider
123
- } from "./chunk-B3I77W5J.js";
124
- import "./chunk-2W3OOD4W.js";
125
- import {
126
- EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
127
- MAX_WORKSPACE_SKILL_NAME_LENGTH,
128
- WorkspaceSkillManagementError,
129
- WorkspaceVoiceError,
130
- buildWorkspaceVoiceSettingsWrites,
131
- buildWorkspaceVoiceStatus,
132
- createDaemonWorkspaceService,
133
- hasConfiguredBatchVoiceTranscriptionModel,
134
- transcribeWorkspaceVoiceAudio,
135
- validateWorkspaceSkillName,
136
- validateWorkspaceVoiceState,
137
- voiceSettingsScopeToWire
138
- } from "./chunk-ACQJPDDS.js";
139
- import {
140
- PermissionRulesValidationError,
141
- buildPermissionSettings,
142
- isPermissionRuleType,
143
- normalizePermissionRules,
144
- readPermissionRuleSet
145
- } from "./chunk-3BJDQVE6.js";
146
- import {
147
- assertVoiceBaseUrlNetworkAllowed,
148
- isStreamingVoiceModel,
149
- resolveVoiceStreamConfig,
150
- resolveVoiceTranscriptionConfig,
151
- sanitizeVoiceErrorMessage,
152
- transcribeVoiceAudio
153
- } from "./chunk-LVA5OHQO.js";
154
- import {
155
- isVoiceEnabled,
156
- isVoiceMode,
157
- readVoiceModel
158
- } from "./chunk-7ZD5EKXE.js";
159
- import "./chunk-QLJUC7TG.js";
160
- import {
161
- WorkspacePermissionRulesSessionRequiredError,
162
- WorkspaceSettingsPartialPersistError,
163
- WorkspaceSkillNotFoundError,
164
- WorkspaceSkillNotToggleableError
165
- } from "./chunk-OA4JVLSA.js";
166
- import {
167
- createTotalSessionAdmissionController
168
- } from "./chunk-VYPFXUCB.js";
169
- import {
170
- createSingleWorkspaceRegistry,
171
- createWorkspaceSessionOwnerIndex
172
- } from "./chunk-UGYMA4EI.js";
173
- import "./chunk-GRC5HGPI.js";
174
157
  import {
175
158
  daemonObservedContactsPath,
176
159
  loadChannelsConfig
177
- } from "./chunk-5XORMWA2.js";
178
- import "./chunk-4SCOLXTD.js";
160
+ } from "./chunk-PSOO6YXD.js";
161
+ import "./chunk-PC6JANNU.js";
179
162
  import "./chunk-57OAHC2Y.js";
180
163
  import {
181
- parseChannelWebhookConfigLenient
182
- } from "./chunk-GPMVHZP4.js";
183
- import "./chunk-6ZBPS62S.js";
184
- import "./chunk-V6WHFGST.js";
164
+ createDaemonStatusProvider
165
+ } from "./chunk-J24WCGIN.js";
166
+ import "./chunk-LXXMOYPL.js";
167
+ import "./chunk-MVSUYZDT.js";
168
+ import "./chunk-E5Z2AVNV.js";
185
169
  import {
186
170
  SessionArtifactAuthorizationError,
187
171
  SessionArtifactValidationError,
188
172
  createAcpSessionBridge,
189
173
  parseSessionSource
190
- } from "./chunk-K7EUPLIP.js";
174
+ } from "./chunk-KIM5GUMA.js";
191
175
  import {
192
176
  EVENT_SCHEMA_VERSION,
177
+ EventBus,
193
178
  SubscriberLimitExceededError
194
- } from "./chunk-6RLROE6G.js";
195
- import "./chunk-COH43MRJ.js";
196
- import "./chunk-QR6U5QPP.js";
179
+ } from "./chunk-GLWP3FDB.js";
197
180
  import {
198
181
  BranchWhilePromptActiveError,
199
182
  CancelSentinelCollisionError,
@@ -227,33 +210,72 @@ import {
227
210
  WorkspaceInitSymlinkError,
228
211
  WorkspaceMismatchError
229
212
  } from "./chunk-UH3WSE5L.js";
230
- import "./chunk-77OZOGPT.js";
213
+ import "./chunk-COH43MRJ.js";
214
+ import "./chunk-3SJ43L4W.js";
215
+ import "./chunk-7JURR4JT.js";
216
+ import {
217
+ createWorkspaceProvidersStatusProvider
218
+ } from "./chunk-FSITMZJH.js";
219
+ import {
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";
231
230
  import {
232
231
  STATUS_SCHEMA_VERSION,
233
232
  createIdleWorkspaceMemoryStatus,
234
233
  mapDomainErrorToErrorKind
235
- } from "./chunk-TDDFEPBX.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";
242
+ import {
243
+ MAX_REGISTERED_WORKSPACES,
244
+ WorkspaceDisplayNameValidationError,
245
+ WorkspaceRegistrationStoreCommittedError,
246
+ WorkspaceRegistrationStoreLimitError,
247
+ normalizeWorkspaceDisplayName,
248
+ workspaceRegistrationId
249
+ } from "./chunk-Q4M4MDQ4.js";
250
+ import {
251
+ MAX_WORKSPACE_PATH_LENGTH,
252
+ canonicalizeWorkspace,
253
+ canonicalizeWorkspaces,
254
+ translateAndCheckAbsoluteWorkspacePath
255
+ } from "./chunk-2RFKHEXL.js";
236
256
  import {
257
+ ChannelDeliveryError,
237
258
  MAX_CHANNEL_STARTUP_FAILURES,
238
259
  MAX_CHANNEL_STARTUP_FAILURE_CHANNEL_LENGTH,
239
260
  MAX_CHANNEL_STARTUP_FAILURE_CODE_LENGTH,
240
261
  MAX_CHANNEL_STARTUP_FAILURE_MESSAGE_LENGTH,
241
262
  QWEN_SERVER_TOKEN_ENV,
263
+ isChannelDeliveryError,
242
264
  isChannelWebhookEnqueueError,
243
265
  normalizeWorkerDiagnostic
244
- } from "./chunk-QKTHJXCS.js";
266
+ } from "./chunk-LK7CHLVP.js";
245
267
  import {
246
268
  normalizeServeChannelSelection
247
- } from "./chunk-TJTKSVIV.js";
269
+ } from "./chunk-JLU636DO.js";
270
+ import "./chunk-BK2UNYWD.js";
248
271
  import {
249
272
  redactLogCredentials
250
273
  } from "./chunk-M5GB774H.js";
251
- import "./chunk-WBL3FJEU.js";
252
- import "./chunk-T2NCM2ET.js";
253
274
  import {
254
275
  sanitizeLogText
255
- } from "./chunk-RVLZCXEE.js";
276
+ } from "./chunk-RWTEFFPU.js";
256
277
  import "./chunk-UDXSXLER.js";
278
+ import "./chunk-5HBA2Z7V.js";
257
279
  import {
258
280
  getDialogSettingKeys,
259
281
  getModelProvidersOwnerScope,
@@ -263,38 +285,23 @@ import {
263
285
  getWritableScopes,
264
286
  loadSettings,
265
287
  validateSettingValue
266
- } from "./chunk-RHYFF54J.js";
288
+ } from "./chunk-TEHGS6UP.js";
267
289
  import "./chunk-RKUWKYED.js";
290
+ import "./chunk-GOXKNSDZ.js";
291
+ import "./chunk-IDS7MSUP.js";
268
292
  import {
269
293
  SUPPORTED_LANGUAGES,
270
294
  detectSystemLanguage,
271
295
  resolveLanguageSetting,
272
296
  resolveSupportedLanguage
273
- } from "./chunk-V7WNRZL7.js";
274
- import "./chunk-UTGFTJ2H.js";
275
- import "./chunk-GOXKNSDZ.js";
276
- import "./chunk-QRUIS3DN.js";
277
- import {
278
- MAX_REGISTERED_WORKSPACES,
279
- WorkspaceDisplayNameValidationError,
280
- WorkspaceRegistrationStoreCommittedError,
281
- WorkspaceRegistrationStoreLimitError,
282
- normalizeWorkspaceDisplayName,
283
- workspaceRegistrationId
284
- } from "./chunk-AHX6AKPD.js";
285
- import {
286
- MAX_WORKSPACE_PATH_LENGTH,
287
- canonicalizeWorkspace,
288
- canonicalizeWorkspaces,
289
- translateAndCheckAbsoluteWorkspacePath
290
- } from "./chunk-2RFKHEXL.js";
291
- import "./chunk-5HBA2Z7V.js";
292
- import "./chunk-IDS7MSUP.js";
293
- import "./chunk-3F2JUWCH.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-CGIDQG6J.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,22 +369,19 @@ import {
360
369
  writeWorkspaceContextFile,
361
370
  writeWorktreeSession,
362
371
  writeWorktreeSessionMarker
363
- } from "./chunk-IWALV67J.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-GPSKDNEE.js";
368
- import "./chunk-T2L47JJK.js";
369
- import "./chunk-X6N25LXS.js";
370
- import "./chunk-E2UVIFI2.js";
374
+ import "./chunk-TWPJO254.js";
375
+ import "./chunk-H6XPXXMH.js";
376
+ import "./chunk-K4XWPEWB.js";
371
377
  import {
372
378
  MAX_JOBS,
373
379
  nextDurableFireMs
374
- } from "./chunk-Q2YKNMLS.js";
380
+ } from "./chunk-TOFQCPDC.js";
375
381
  import {
376
382
  nextFireTime,
377
383
  parseCron
378
- } from "./chunk-XU457J4V.js";
384
+ } from "./chunk-IRH27ZC2.js";
379
385
  import "./chunk-VDDGDZMA.js";
380
386
  import {
381
387
  appendCronRun,
@@ -384,22 +390,27 @@ import {
384
390
  readCronTasks,
385
391
  taskHasLegacyCondition,
386
392
  updateCronTasks
387
- } from "./chunk-KHOVYUHX.js";
388
- import "./chunk-SZRN75WQ.js";
393
+ } from "./chunk-FNQ6T3CV.js";
394
+ import "./chunk-ZOIFNCKL.js";
395
+ import "./chunk-PWTZEM3C.js";
396
+ import "./chunk-KRXPRVGL.js";
389
397
  import "./chunk-6PVPNMXU.js";
390
- import "./chunk-6FZYKBKV.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-7VUQQBR7.js";
393
- import "./chunk-LIZRAKPB.js";
394
402
  import {
395
403
  APPROVAL_MODES,
396
404
  SubagentError,
397
405
  SubagentErrorCode
398
- } from "./chunk-WHGVTP7Q.js";
406
+ } from "./chunk-L26JL52R.js";
399
407
  import "./chunk-6AM5D4ME.js";
408
+ import "./chunk-JZA3JUDJ.js";
409
+ import "./chunk-3QMGYBFN.js";
400
410
  import "./chunk-JCW2R7WC.js";
401
- import "./chunk-57FIIFJN.js";
402
- import "./chunk-HTO4JFDZ.js";
411
+ import "./chunk-M5JM7OSF.js";
412
+ import "./chunk-OHNBB4XR.js";
413
+ import "./chunk-E5TUC6CA.js";
403
414
  import {
404
415
  QwenOAuth2Client,
405
416
  QwenOAuthPollError,
@@ -408,57 +419,69 @@ import {
408
419
  isDeviceAuthorizationSuccess,
409
420
  isDeviceTokenPending,
410
421
  isDeviceTokenSuccess
411
- } from "./chunk-HABKX6LY.js";
422
+ } from "./chunk-EPDRMGT4.js";
412
423
  import "./chunk-JESCGQM3.js";
413
- import "./chunk-32L4D2O2.js";
414
- import "./chunk-SRPZG4ER.js";
424
+ import "./chunk-NH6KE4JX.js";
425
+ import "./chunk-USTWD7QV.js";
415
426
  import "./chunk-XVNQMZ2I.js";
416
- import "./chunk-CR3C7WXL.js";
417
427
  import "./chunk-FODK6UMO.js";
418
428
  import "./chunk-GLNBDYUX.js";
419
429
  import "./chunk-DJ2GSRLV.js";
430
+ import "./chunk-ZJHVAS7M.js";
420
431
  import {
421
432
  addDaemonRequestAttribute,
422
- decodeBufferWithEncodingInfo,
423
433
  emitDaemonLog,
424
- getAllGeminiMdFilenames,
425
434
  hashDaemonWorkspace,
426
- isBinaryFile,
427
- isWithinRoot,
428
435
  recordDaemonBridgeError,
429
436
  recordDaemonError,
430
437
  recordDaemonHttpRequest,
431
438
  recordDaemonHttpResponse,
432
439
  withDaemonRequestSpan
433
- } from "./chunk-H4A4A2SY.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";
434
454
  import "./chunk-VGC4I5JJ.js";
435
- import "./chunk-4K56OJFJ.js";
436
- import "./chunk-CBOQ3HY7.js";
455
+ import "./chunk-MUP3T3AD.js";
456
+ import "./chunk-IKCX4CCL.js";
457
+ import "./chunk-46UV252V.js";
437
458
  import "./chunk-A4UCTEB5.js";
438
459
  import "./chunk-XWRJCPHC.js";
439
- import "./chunk-QNLNLENL.js";
440
- import "./chunk-6X4GWOPW.js";
441
- import "./chunk-TYQMGACW.js";
442
- import {
443
- import_websocket_server
444
- } from "./chunk-TYAMGABM.js";
445
- import "./chunk-FCMNKVXT.js";
446
- 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";
447
465
  import "./chunk-HTR4WV6U.js";
448
- import "./chunk-M7WBGLYP.js";
466
+ import "./chunk-BULDBTYC.js";
449
467
  import "./chunk-U7ZFW55U.js";
450
- import "./chunk-NPQDJGKU.js";
451
- import "./chunk-YM3SZTH4.js";
468
+ import "./chunk-UUUTRMI2.js";
469
+ import "./chunk-PR75REBZ.js";
452
470
  import {
453
471
  FatalConfigError,
454
472
  Storage,
455
473
  createDebugLogger,
456
474
  runWithoutDebugLogSession
457
- } from "./chunk-OQB4EXO4.js";
475
+ } from "./chunk-NL7LTRLR.js";
458
476
  import "./chunk-75DOP5OR.js";
459
477
  import "./chunk-DMTGGOSA.js";
460
478
  import "./chunk-YQ3U5MUC.js";
461
- 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";
462
485
  import {
463
486
  init_esbuild_shims
464
487
  } from "./chunk-5O2XNYP6.js";
@@ -650,9 +673,9 @@ async function findExistingAncestor(absolute) {
650
673
  let current = absolute;
651
674
  const tailParts = [];
652
675
  for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
653
- let stat2 = null;
676
+ let stat3 = null;
654
677
  try {
655
- stat2 = await fsp.stat(current);
678
+ stat3 = await fsp.stat(current);
656
679
  } catch (err) {
657
680
  const code = err?.code;
658
681
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -660,8 +683,8 @@ async function findExistingAncestor(absolute) {
660
683
  throw err;
661
684
  }
662
685
  }
663
- if (stat2) {
664
- if (tailParts.length > 0 && !stat2.isDirectory()) {
686
+ if (stat3) {
687
+ if (tailParts.length > 0 && !stat3.isDirectory()) {
665
688
  throw new FsError(
666
689
  "parse_error",
667
690
  `path component is not a directory: ${absolute}`,
@@ -734,7 +757,7 @@ async function resolveWithinWorkspace(input, boundWorkspaces, intent) {
734
757
  boundCanonicals
735
758
  );
736
759
  if (boundCanonical !== void 0) {
737
- 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) => {
738
761
  if (lstatErr.code === "ENOENT" || lstatErr.code === "ENOTDIR") {
739
762
  return false;
740
763
  }
@@ -1225,8 +1248,8 @@ var WorkspaceFileSystemImpl = class {
1225
1248
  const toRead = Math.min(maxBytes, available);
1226
1249
  buf = Buffer.allocUnsafe(toRead);
1227
1250
  if (toRead > 0) {
1228
- const read = await fh.read(buf, 0, toRead, offset);
1229
- 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);
1230
1253
  }
1231
1254
  const afterRead = await fh.stat();
1232
1255
  assertSameFile(st, afterRead, p, "read");
@@ -1767,17 +1790,17 @@ var WorkspaceFileSystemImpl = class {
1767
1790
  * for their `sendFsError` serializer.
1768
1791
  */
1769
1792
  recordAndWrap(err, intent, input) {
1770
- const fs5 = wrapAsFsError(err);
1793
+ const fs6 = wrapAsFsError(err);
1771
1794
  this.deps.audit.recordDenied(this.deps.ctx, {
1772
1795
  intent,
1773
1796
  input,
1774
- errorKind: fs5.kind,
1775
- hint: fs5.hint,
1797
+ errorKind: fs6.kind,
1798
+ hint: fs6.hint,
1776
1799
  // Quote the underlying OS / FsError message so audit
1777
1800
  // consumers debugging a production incident can see the
1778
1801
  // actual cause (errno text, byte counts, glob pattern,
1779
1802
  // etc.) rather than just `errorKind` + `hint`.
1780
- message: fs5.message,
1803
+ message: fs6.message,
1781
1804
  // For glob denials (parse_error pattern rejection,
1782
1805
  // catastrophic walk failures) the input IS the pattern
1783
1806
  // already; surfacing it on the dedicated `pattern` field
@@ -1786,7 +1809,7 @@ var WorkspaceFileSystemImpl = class {
1786
1809
  // branching on intent.
1787
1810
  pattern: intent === "glob" ? input : void 0
1788
1811
  });
1789
- return fs5;
1812
+ return fs6;
1790
1813
  }
1791
1814
  };
1792
1815
  var CONTENT_HASH_RE = /^sha256:[0-9a-f]{64}$/;
@@ -1894,9 +1917,9 @@ async function readStableRegularFileBuffer(p, pre) {
1894
1917
  const out = Buffer.alloc(opened.size);
1895
1918
  let offset = 0;
1896
1919
  while (offset < opened.size) {
1897
- const read = await fh.read(out, offset, opened.size - offset, offset);
1898
- if (read.bytesRead === 0) break;
1899
- 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;
1900
1923
  }
1901
1924
  const afterRead = await fh.stat();
1902
1925
  assertSameFile(opened, afterRead, p, "read");
@@ -2151,15 +2174,15 @@ async function hashRegularFileAtPath(p, pre) {
2151
2174
  const buf = Buffer.allocUnsafe(64 * 1024);
2152
2175
  let offset = 0;
2153
2176
  while (offset < opened.size) {
2154
- const read = await fh.read(
2177
+ const read2 = await fh.read(
2155
2178
  buf,
2156
2179
  0,
2157
2180
  Math.min(buf.length, opened.size - offset),
2158
2181
  offset
2159
2182
  );
2160
- if (read.bytesRead === 0) break;
2161
- hash.update(buf.subarray(0, read.bytesRead));
2162
- offset += read.bytesRead;
2183
+ if (read2.bytesRead === 0) break;
2184
+ hash.update(buf.subarray(0, read2.bytesRead));
2185
+ offset += read2.bytesRead;
2163
2186
  }
2164
2187
  } finally {
2165
2188
  await fh.close();
@@ -2523,12 +2546,12 @@ __name(applyReadHeaders, "applyReadHeaders");
2523
2546
  function sendFsError(res, err, route) {
2524
2547
  applyReadHeaders(res);
2525
2548
  if (isFsError(err)) {
2526
- const fs5 = err;
2527
- res.status(fs5.status).json({
2528
- errorKind: fs5.kind,
2529
- error: fs5.message,
2530
- hint: fs5.hint,
2531
- 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
2532
2555
  });
2533
2556
  return;
2534
2557
  }
@@ -2630,13 +2653,13 @@ async function handleGetFile(req, res, deps) {
2630
2653
  });
2631
2654
  return;
2632
2655
  }
2633
- const fs5 = factory.forRequest({
2656
+ const fs6 = factory.forRequest({
2634
2657
  originatorClientId: clientId ?? void 0,
2635
2658
  route: ROUTE2
2636
2659
  });
2637
2660
  try {
2638
- const resolved = await fs5.resolve(queryPath, "read");
2639
- 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 });
2640
2663
  const returnedBytes = Buffer.byteLength(out.content, "utf-8");
2641
2664
  applyReadHeaders(res);
2642
2665
  res.status(200).json({
@@ -2690,13 +2713,13 @@ async function handleGetFileBytes(req, res, deps) {
2690
2713
  });
2691
2714
  return;
2692
2715
  }
2693
- const fs5 = factory.forRequest({
2716
+ const fs6 = factory.forRequest({
2694
2717
  originatorClientId: clientId ?? void 0,
2695
2718
  route: ROUTE2
2696
2719
  });
2697
2720
  try {
2698
- const resolved = await fs5.resolve(queryPath, "read");
2699
- const out = await fs5.readBytesWindow(resolved, {
2721
+ const resolved = await fs6.resolve(queryPath, "read");
2722
+ const out = await fs6.readBytesWindow(resolved, {
2700
2723
  offset: offset ?? 0,
2701
2724
  maxBytes: maxBytes ?? DEFAULT_FILE_BYTES_MAX_BYTES
2702
2725
  });
@@ -2724,13 +2747,13 @@ async function handleGetStat(req, res, deps) {
2724
2747
  if (clientId === null) return;
2725
2748
  const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
2726
2749
  if (queryPath === null) return;
2727
- const fs5 = factory.forRequest({
2750
+ const fs6 = factory.forRequest({
2728
2751
  originatorClientId: clientId ?? void 0,
2729
2752
  route: ROUTE2
2730
2753
  });
2731
2754
  try {
2732
- const resolved = await fs5.resolve(queryPath, "stat");
2733
- const st = await fs5.stat(resolved);
2755
+ const resolved = await fs6.resolve(queryPath, "stat");
2756
+ const st = await fs6.stat(resolved);
2734
2757
  applyReadHeaders(res);
2735
2758
  res.status(200).json({
2736
2759
  kind: "stat",
@@ -2753,13 +2776,13 @@ async function handleGetList(req, res, deps) {
2753
2776
  const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
2754
2777
  if (queryPath === null) return;
2755
2778
  const includeIgnored = parseBoolFlag(req.query["includeIgnored"]);
2756
- const fs5 = factory.forRequest({
2779
+ const fs6 = factory.forRequest({
2757
2780
  originatorClientId: clientId ?? void 0,
2758
2781
  route: ROUTE2
2759
2782
  });
2760
2783
  try {
2761
- const resolved = await fs5.resolve(queryPath, "list");
2762
- const entries = await fs5.list(resolved, {
2784
+ const resolved = await fs6.resolve(queryPath, "list");
2785
+ const entries = await fs6.list(resolved, {
2763
2786
  includeIgnored,
2764
2787
  maxEntries: MAX_LIST_ENTRIES + 1
2765
2788
  });
@@ -2812,15 +2835,15 @@ async function handleGetGlob(req, res, deps) {
2812
2835
  }
2813
2836
  const cwdRaw = req.query["cwd"];
2814
2837
  const cwdString = typeof cwdRaw === "string" && cwdRaw.length > 0 ? cwdRaw : void 0;
2815
- const fs5 = factory.forRequest({
2838
+ const fs6 = factory.forRequest({
2816
2839
  originatorClientId: clientId ?? void 0,
2817
2840
  route: ROUTE2
2818
2841
  });
2819
2842
  const start = performance.now();
2820
2843
  try {
2821
- const cwdResolved = cwdString ? await fs5.resolve(cwdString, "list") : void 0;
2844
+ const cwdResolved = cwdString ? await fs6.resolve(cwdString, "list") : void 0;
2822
2845
  const cap = maxResults ?? DEFAULT_GLOB_MAX_RESULTS;
2823
- const probe = await fs5.glob(pattern, {
2846
+ const probe = await fs6.glob(pattern, {
2824
2847
  cwd: cwdResolved,
2825
2848
  includeIgnored,
2826
2849
  maxResults: cap + 1
@@ -2994,7 +3017,7 @@ function validateClientId(clientId, deps, res) {
2994
3017
  }
2995
3018
  __name(validateClientId, "validateClientId");
2996
3019
  function createSetupGithubFileOps(factory, route, originatorClientId) {
2997
- const fs5 = factory.forRequest({
3020
+ const fs6 = factory.forRequest({
2998
3021
  route,
2999
3022
  ...originatorClientId ? { originatorClientId } : {}
3000
3023
  });
@@ -3017,14 +3040,14 @@ function createSetupGithubFileOps(factory, route, originatorClientId) {
3017
3040
  ]);
3018
3041
  },
3019
3042
  async writeTextFile(_gitRepoRoot, relativePath, content) {
3020
- const resolved = await fs5.resolve(relativePath, "write");
3021
- const out = await fs5.writeTextOverwrite(resolved, content);
3043
+ const resolved = await fs6.resolve(relativePath, "write");
3044
+ const out = await fs6.writeTextOverwrite(resolved, content);
3022
3045
  return { sizeBytes: out.sizeBytes };
3023
3046
  },
3024
3047
  async readTextFile(_gitRepoRoot, relativePath) {
3025
3048
  try {
3026
- const resolved = await fs5.resolve(relativePath, "read");
3027
- const out = await fs5.readText(resolved);
3049
+ const resolved = await fs6.resolve(relativePath, "read");
3050
+ const out = await fs6.readText(resolved);
3028
3051
  return out.content;
3029
3052
  } catch (error2) {
3030
3053
  if (isFsError(error2) && error2.kind === "path_not_found") {
@@ -3045,15 +3068,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
3045
3068
  checkedSegments.push(segment);
3046
3069
  const label = `Workspace path "${checkedSegments.join("/")}"`;
3047
3070
  try {
3048
- const stat2 = await fsp3.lstat(current);
3049
- if (stat2.isSymbolicLink()) {
3071
+ const stat3 = await fsp3.lstat(current);
3072
+ if (stat3.isSymbolicLink()) {
3050
3073
  throw new SetupGithubError(
3051
3074
  "github_setup_invalid_workspace",
3052
3075
  `${label} must not be a symlink.`,
3053
3076
  400
3054
3077
  );
3055
3078
  }
3056
- if (!stat2.isDirectory()) {
3079
+ if (!stat3.isDirectory()) {
3057
3080
  throw new SetupGithubError(
3058
3081
  "github_setup_invalid_workspace",
3059
3082
  `${label} must be a directory.`,
@@ -3090,15 +3113,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
3090
3113
  }
3091
3114
  __name(ensureDirectoryWithoutSymlink, "ensureDirectoryWithoutSymlink");
3092
3115
  async function assertDirectoryWithoutSymlink(target, label) {
3093
- const stat2 = await fsp3.lstat(target);
3094
- if (stat2.isSymbolicLink()) {
3116
+ const stat3 = await fsp3.lstat(target);
3117
+ if (stat3.isSymbolicLink()) {
3095
3118
  throw new SetupGithubError(
3096
3119
  "github_setup_invalid_workspace",
3097
3120
  `${label} must not be a symlink.`,
3098
3121
  400
3099
3122
  );
3100
3123
  }
3101
- if (!stat2.isDirectory()) {
3124
+ if (!stat3.isDirectory()) {
3102
3125
  throw new SetupGithubError(
3103
3126
  "github_setup_invalid_workspace",
3104
3127
  `${label} must be a directory.`,
@@ -4739,12 +4762,12 @@ async function collectWorkspaceMemoryStatus(boundWorkspace) {
4739
4762
  for (const filename of filenames) {
4740
4763
  const candidate = path8.join(globalDir, filename);
4741
4764
  try {
4742
- const stat2 = await fs.stat(candidate);
4743
- if (stat2.isFile()) {
4765
+ const stat3 = await fs.stat(candidate);
4766
+ if (stat3.isFile()) {
4744
4767
  files.push({
4745
4768
  absolutePath: candidate,
4746
4769
  scope: "global",
4747
- bytes: stat2.size
4770
+ bytes: stat3.size
4748
4771
  });
4749
4772
  }
4750
4773
  } catch (err) {
@@ -4788,12 +4811,12 @@ async function walkWorkspaceForMemory(start, filenames, errors) {
4788
4811
  for (const filename of filenames) {
4789
4812
  const candidate = path8.join(start, filename);
4790
4813
  try {
4791
- const stat2 = await fs.stat(candidate);
4792
- if (stat2.isFile()) {
4814
+ const stat3 = await fs.stat(candidate);
4815
+ if (stat3.isFile()) {
4793
4816
  out.push({
4794
4817
  absolutePath: candidate,
4795
4818
  scope: "workspace",
4796
- bytes: stat2.size
4819
+ bytes: stat3.size
4797
4820
  });
4798
4821
  }
4799
4822
  } catch (err) {
@@ -4819,6 +4842,7 @@ __name(isEnoent, "isEnoent");
4819
4842
  // packages/cli/src/serve/workspace-agents.ts
4820
4843
  init_esbuild_shims();
4821
4844
  import { promises as fs2 } from "node:fs";
4845
+ import { isDeepStrictEqual } from "node:util";
4822
4846
  var AGENT_TYPE_PATTERN = /^[\p{L}\p{N}_-]+$/u;
4823
4847
  var AGENT_TYPE_MAX_LENGTH = 64;
4824
4848
  var AGENT_TYPE_MIN_LENGTH = 2;
@@ -4826,6 +4850,27 @@ var MAX_DESCRIPTION_BYTES = 256 * 1024;
4826
4850
  var MAX_SYSTEM_PROMPT_BYTES = 256 * 1024;
4827
4851
  var MAX_TOOLS_ENTRIES = 256;
4828
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
+ ];
4829
4874
  function mountWorkspaceAgentsRoutes(app, deps) {
4830
4875
  const manager = createDaemonSubagentManager(deps.boundWorkspace);
4831
4876
  app.get("/workspace/agents", async (_req, res) => {
@@ -4864,7 +4909,11 @@ function mountWorkspaceAgentsRoutes(app, deps) {
4864
4909
  return;
4865
4910
  }
4866
4911
  const level = scope === "workspace" ? "project" : "user";
4867
- const config = parseAgentConfig(body, level, res);
4912
+ const config = parseAgentConfig(
4913
+ restoreAgentMcpServerSecrets(body, deps.boundWorkspace, level),
4914
+ level,
4915
+ res
4916
+ );
4868
4917
  if (!config) return;
4869
4918
  const collision = await manager.loadSubagent(config.name, level);
4870
4919
  if (collision) {
@@ -4980,7 +5029,9 @@ function mountWorkspaceAgentsRoutes(app, deps) {
4980
5029
  const agentType = validateAgentType(req, res);
4981
5030
  if (agentType === null) return;
4982
5031
  try {
4983
- 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);
4984
5035
  if (!config) {
4985
5036
  res.status(404).json({
4986
5037
  error: `Subagent "${agentType}" not found`,
@@ -5009,9 +5060,6 @@ function mountWorkspaceAgentsRoutes(app, deps) {
5009
5060
  const clientIdResult = resolveOriginatorClientId(deps, req, res);
5010
5061
  if (clientIdResult === null) return;
5011
5062
  const originatorClientId = clientIdResult;
5012
- const body = deps.safeBody(req);
5013
- const updates = parseAgentUpdates(body, res);
5014
- if (!updates) return;
5015
5063
  const preferredLevel = parseScopeQuery(req, res);
5016
5064
  if (preferredLevel === null) return;
5017
5065
  const existing = await manager.loadSubagent(agentType, preferredLevel);
@@ -5026,6 +5074,14 @@ function mountWorkspaceAgentsRoutes(app, deps) {
5026
5074
  if (assertMutableLevel(existing, agentType, res)) {
5027
5075
  return;
5028
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;
5029
5085
  if (Object.keys(updates).length === 0) {
5030
5086
  res.status(400).json({
5031
5087
  error: "`POST /workspace/agents/:agentType` requires at least one updatable field in the body",
@@ -5269,7 +5325,11 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5269
5325
  const level = parseWorkspaceOnlyAgentBodyScope(body, res);
5270
5326
  if (level === null) return;
5271
5327
  const manager = createDaemonSubagentManager(runtime.workspaceCwd);
5272
- const config = parseAgentConfig(body, level, res);
5328
+ const config = parseAgentConfig(
5329
+ restoreAgentMcpServerSecrets(body, runtime.workspaceCwd, level),
5330
+ level,
5331
+ res
5332
+ );
5273
5333
  if (!config) return;
5274
5334
  const collision = await manager.loadSubagent(config.name, level);
5275
5335
  if (collision) {
@@ -5358,9 +5418,6 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5358
5418
  const clientIdResult = resolveOriginatorClientId(routeDeps, req, res);
5359
5419
  if (clientIdResult === null) return;
5360
5420
  const originatorClientId = clientIdResult;
5361
- const body = deps.safeBody(req);
5362
- const updates = parseAgentUpdates(body, res);
5363
- if (!updates) return;
5364
5421
  const manager = createDaemonSubagentManager(runtime.workspaceCwd);
5365
5422
  const existing = await manager.loadSubagent(agentType, scopedLevel);
5366
5423
  if (!existing) {
@@ -5372,6 +5429,14 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
5372
5429
  return;
5373
5430
  }
5374
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;
5375
5440
  if (Object.keys(updates).length === 0) {
5376
5441
  res.status(400).json({
5377
5442
  error: "`POST /workspaces/:workspace/agents/:agentType` requires at least one updatable field in the body",
@@ -5627,6 +5692,22 @@ function rejectWorkspaceQualifiedAgentScope(scope, res) {
5627
5692
  return null;
5628
5693
  }
5629
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");
5630
5711
  function sendCreateAgentError(res, err, name) {
5631
5712
  if (!(err instanceof SubagentError)) return false;
5632
5713
  if (err.code === SubagentErrorCode.ALREADY_EXISTS) {
@@ -5768,22 +5849,73 @@ function parseAgentConfig(body, level, res) {
5768
5849
  if (tools !== void 0) config.tools = tools;
5769
5850
  if (disallowedTools !== void 0) config.disallowedTools = disallowedTools;
5770
5851
  if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
5771
- 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
+ }
5772
5858
  if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
5773
- 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
+ }
5774
5868
  if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
5775
5869
  return void 0;
5776
5870
  }
5777
5871
  if (typeof body["approvalMode"] === "string") {
5778
- if (!APPROVAL_MODES.includes(body["approvalMode"])) {
5779
- res.status(422).json({
5780
- error: `\`approvalMode\` must be one of ${JSON.stringify(APPROVAL_MODES)}`,
5781
- code: "invalid_config"
5782
- });
5783
- 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
+ );
5784
5877
  }
5785
5878
  config.approvalMode = body["approvalMode"];
5786
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
+ }
5787
5919
  if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
5788
5920
  return void 0;
5789
5921
  }
@@ -5853,24 +5985,87 @@ function parseAgentUpdates(body, res) {
5853
5985
  updates.disallowedTools = disallowedTools;
5854
5986
  }
5855
5987
  }
5856
- if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
5857
- if (typeof body["model"] === "string") updates.model = body["model"];
5858
- if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
5859
- if (typeof body["color"] === "string") updates.color = body["color"];
5860
- if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
5988
+ if (body["model"] === null) {
5989
+ updates.model = void 0;
5990
+ } else if (rejectIfPresentWrongType(body, "model", "string", res)) {
5861
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();
5862
5997
  }
5863
- if (typeof body["approvalMode"] === "string") {
5864
- if (!APPROVAL_MODES.includes(body["approvalMode"])) {
5865
- res.status(422).json({
5866
- error: `\`approvalMode\` must be one of ${JSON.stringify(APPROVAL_MODES)}`,
5867
- code: "invalid_config"
5868
- });
5869
- 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
+ );
5870
6021
  }
5871
6022
  updates.approvalMode = body["approvalMode"];
5872
6023
  }
5873
- if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
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
+ }
6068
+ if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
5874
6069
  return void 0;
5875
6070
  }
5876
6071
  if (typeof body["background"] === "boolean") {
@@ -5910,6 +6105,43 @@ function parseStringArray(value, field, res) {
5910
6105
  return value;
5911
6106
  }
5912
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");
5913
6145
  function rejectIfPresentWrongType(body, key, expected, res) {
5914
6146
  if (!(key in body)) return false;
5915
6147
  if (typeof body[key] === expected) return false;
@@ -5933,13 +6165,31 @@ function isNoOpUpdate(existing, updates) {
5933
6165
  if (updates.disallowedTools !== void 0 && !shallowArrayEqual(updates.disallowedTools, existing.disallowedTools)) {
5934
6166
  return false;
5935
6167
  }
5936
- 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) {
5937
6181
  return false;
5938
6182
  }
5939
- 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
+ )) {
5940
6187
  return false;
5941
6188
  }
5942
- 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
+ )) {
5943
6193
  return false;
5944
6194
  }
5945
6195
  if (updates.background !== void 0 && updates.background !== existing.background) {
@@ -5958,6 +6208,19 @@ function isNoOpUpdate(existing, updates) {
5958
6208
  return true;
5959
6209
  }
5960
6210
  __name(isNoOpUpdate, "isNoOpUpdate");
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");
5961
6224
  function shallowArrayEqual(a, b) {
5962
6225
  if (a === b) return true;
5963
6226
  if (!a || !b) return false;
@@ -6010,10 +6273,30 @@ function toSummary(config) {
6010
6273
  isBuiltin: config.isBuiltin === true || config.level === "builtin",
6011
6274
  hasTools: Array.isArray(config.tools) && config.tools.length > 0
6012
6275
  };
6276
+ if (config.tools) summary.tools = [...config.tools];
6277
+ if (config.disallowedTools) {
6278
+ summary.disallowedTools = [...config.disallowedTools];
6279
+ }
6013
6280
  if (config.model) summary.model = config.model;
6014
6281
  if (config.color) summary.color = config.color;
6015
6282
  if (config.background !== void 0) summary.background = config.background;
6016
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
+ }
6017
6300
  if (config.extensionName) summary.extensionName = config.extensionName;
6018
6301
  if (config.filePath) summary.filePath = config.filePath;
6019
6302
  return summary;
@@ -6024,20 +6307,10 @@ function toDetail(config) {
6024
6307
  ...toSummary(config),
6025
6308
  systemPrompt: config.systemPrompt
6026
6309
  };
6027
- if (config.tools) detail.tools = [...config.tools];
6028
- if (config.disallowedTools) {
6029
- detail.disallowedTools = [...config.disallowedTools];
6030
- }
6031
- if (config.runConfig) {
6032
- const runConfig = {};
6033
- if (typeof config.runConfig.max_time_minutes === "number") {
6034
- runConfig.max_time_minutes = config.runConfig.max_time_minutes;
6035
- }
6036
- if (typeof config.runConfig.max_turns === "number") {
6037
- runConfig.max_turns = config.runConfig.max_turns;
6038
- }
6039
- detail.runConfig = runConfig;
6310
+ if (config.mcpServers) {
6311
+ detail.mcpServers = redactMcpServersSetting(config.mcpServers);
6040
6312
  }
6313
+ if (config.hooks) detail.hooks = config.hooks;
6041
6314
  return detail;
6042
6315
  }
6043
6316
  __name(toDetail, "toDetail");
@@ -9045,7 +9318,7 @@ var AcpDispatcher = class {
9045
9318
  );
9046
9319
  return;
9047
9320
  }
9048
- const fs5 = this.fsFactory.forRequest({
9321
+ const fs6 = this.fsFactory.forRequest({
9049
9322
  originatorClientId: conn.clientId,
9050
9323
  route: `ACP ${method}`
9051
9324
  });
@@ -9097,8 +9370,8 @@ var AcpDispatcher = class {
9097
9370
  );
9098
9371
  return;
9099
9372
  }
9100
- const resolved = await fs5.resolve(p, "read");
9101
- 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 });
9102
9375
  this.replyConn(conn, id, {
9103
9376
  path: p,
9104
9377
  content: out.content,
@@ -9120,7 +9393,7 @@ var AcpDispatcher = class {
9120
9393
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9121
9394
  return;
9122
9395
  }
9123
- const fs5 = this.fsFactory.forRequest({
9396
+ const fs6 = this.fsFactory.forRequest({
9124
9397
  originatorClientId: conn.clientId,
9125
9398
  route: `ACP ${method}`
9126
9399
  });
@@ -9156,8 +9429,8 @@ var AcpDispatcher = class {
9156
9429
  );
9157
9430
  return;
9158
9431
  }
9159
- const resolved = await fs5.resolve(p, "read");
9160
- 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 });
9161
9434
  this.replyConn(conn, id, { path: p, ...buf });
9162
9435
  return;
9163
9436
  }
@@ -9175,12 +9448,12 @@ var AcpDispatcher = class {
9175
9448
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9176
9449
  return;
9177
9450
  }
9178
- const fs5 = this.fsFactory.forRequest({
9451
+ const fs6 = this.fsFactory.forRequest({
9179
9452
  originatorClientId: conn.clientId,
9180
9453
  route: `ACP ${method}`
9181
9454
  });
9182
- const resolved = await fs5.resolve(p, "read");
9183
- const result = await fs5.stat(resolved);
9455
+ const resolved = await fs6.resolve(p, "read");
9456
+ const result = await fs6.stat(resolved);
9184
9457
  this.replyConn(conn, id, { path: p, ...result });
9185
9458
  return;
9186
9459
  }
@@ -9198,13 +9471,13 @@ var AcpDispatcher = class {
9198
9471
  conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
9199
9472
  return;
9200
9473
  }
9201
- const fs5 = this.fsFactory.forRequest({
9474
+ const fs6 = this.fsFactory.forRequest({
9202
9475
  originatorClientId: conn.clientId,
9203
9476
  route: `ACP ${method}`
9204
9477
  });
9205
- const resolved = await fs5.resolve(p, "read");
9478
+ const resolved = await fs6.resolve(p, "read");
9206
9479
  const MAX_LIST = 2e3;
9207
- const entries = await fs5.list(resolved, { maxEntries: MAX_LIST + 1 });
9480
+ const entries = await fs6.list(resolved, { maxEntries: MAX_LIST + 1 });
9208
9481
  const truncated = entries.length > MAX_LIST;
9209
9482
  this.replyConn(conn, id, {
9210
9483
  path: p,
@@ -9229,7 +9502,7 @@ var AcpDispatcher = class {
9229
9502
  );
9230
9503
  return;
9231
9504
  }
9232
- const fs5 = this.fsFactory.forRequest({
9505
+ const fs6 = this.fsFactory.forRequest({
9233
9506
  originatorClientId: conn.clientId,
9234
9507
  route: `ACP ${method}`
9235
9508
  });
@@ -9249,7 +9522,7 @@ var AcpDispatcher = class {
9249
9522
  );
9250
9523
  return;
9251
9524
  }
9252
- const matches = await fs5.glob(pattern, {
9525
+ const matches = await fs6.glob(pattern, {
9253
9526
  maxResults: maxResults + 1
9254
9527
  });
9255
9528
  const truncated = matches.length > maxResults;
@@ -9281,11 +9554,11 @@ var AcpDispatcher = class {
9281
9554
  );
9282
9555
  return;
9283
9556
  }
9284
- const fs5 = this.fsFactory.forRequest({
9557
+ const fs6 = this.fsFactory.forRequest({
9285
9558
  originatorClientId: conn.clientId,
9286
9559
  route: `ACP ${method}`
9287
9560
  });
9288
- const resolved = await fs5.resolve(p, "write");
9561
+ const resolved = await fs6.resolve(p, "write");
9289
9562
  if (Buffer.byteLength(params["content"], "utf8") > 10 * 1024 * 1024) {
9290
9563
  if (id !== void 0)
9291
9564
  conn.sendConn(
@@ -9293,7 +9566,7 @@ var AcpDispatcher = class {
9293
9566
  );
9294
9567
  return;
9295
9568
  }
9296
- await fs5.writeTextOverwrite(resolved, params["content"]);
9569
+ await fs6.writeTextOverwrite(resolved, params["content"]);
9297
9570
  this.replyConn(conn, id, { ok: true, path: p });
9298
9571
  return;
9299
9572
  }
@@ -9322,12 +9595,12 @@ var AcpDispatcher = class {
9322
9595
  );
9323
9596
  return;
9324
9597
  }
9325
- const fs5 = this.fsFactory.forRequest({
9598
+ const fs6 = this.fsFactory.forRequest({
9326
9599
  originatorClientId: conn.clientId,
9327
9600
  route: `ACP ${method}`
9328
9601
  });
9329
- const resolved = await fs5.resolve(p, "write");
9330
- const result = await fs5.edit(
9602
+ const resolved = await fs6.resolve(p, "write");
9603
+ const result = await fs6.edit(
9331
9604
  resolved,
9332
9605
  params["oldText"],
9333
9606
  params["newText"]
@@ -9871,11 +10144,24 @@ var AcpDispatcher = class {
9871
10144
  }
9872
10145
  }
9873
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
+ }
9874
10160
  /**
9875
10161
  * Bind a session-scoped SSE stream to the bridge's event stream,
9876
10162
  * translating each `BridgeEvent` into a JSON-RPC frame (design §4.2).
9877
10163
  */
9878
- async pumpSessionEvents(conn, sessionId, signal, lastEventId) {
10164
+ async pumpSessionEvents(conn, sessionId, signal, lastEventId, epoch) {
9879
10165
  try {
9880
10166
  let lastDeliveredId = lastEventId ?? 0;
9881
10167
  let sawEviction = false;
@@ -9883,6 +10169,11 @@ var AcpDispatcher = class {
9883
10169
  if (conn.hasInitialReplayPending(sessionId)) {
9884
10170
  const snapshot = this.bridge.getSessionReplaySnapshot(sessionId);
9885
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
+ }
9886
10177
  const snapshotEvents = [
9887
10178
  ...snapshot.compactedTurns,
9888
10179
  ...snapshot.liveJournal
@@ -9915,7 +10206,8 @@ var AcpDispatcher = class {
9915
10206
  }
9916
10207
  const iterable = this.bridge.subscribeEvents(sessionId, {
9917
10208
  signal,
9918
- ...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {}
10209
+ ...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {},
10210
+ ...epoch !== void 0 ? { epoch } : {}
9919
10211
  });
9920
10212
  for await (const event of iterable) {
9921
10213
  if (signal.aborted) break;
@@ -11028,6 +11320,17 @@ function parseLastEventId2(raw, logPrefix = "") {
11028
11320
  return n;
11029
11321
  }
11030
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");
11031
11334
 
11032
11335
  // packages/cli/src/serve/acp-http/client-mcp-ws.ts
11033
11336
  init_esbuild_shims();
@@ -12391,11 +12694,19 @@ function mountAcpHttp(app, bridge, opts) {
12391
12694
  },
12392
12695
  () => conn.touch()
12393
12696
  );
12394
- stream.open();
12395
12697
  const lastEventId = parseLastEventId2(
12396
12698
  headerOf(req, "last-event-id"),
12397
12699
  "/acp "
12398
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();
12399
12710
  conn.attachSessionStream(sessionId, stream, ac, lastEventId);
12400
12711
  const onPumpSettled = /* @__PURE__ */ __name(() => {
12401
12712
  if (stream.isClosed) {
@@ -12411,7 +12722,7 @@ function mountAcpHttp(app, bridge, opts) {
12411
12722
  );
12412
12723
  }
12413
12724
  }, "onPumpSettled");
12414
- 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) => {
12415
12726
  writeStderrLine(
12416
12727
  `qwen serve: ${mount.routeLabel} event pump error (${logSafe(sessionId)}, lastEventId=${lastEventId ?? "none"}): ${logSafe(err instanceof Error ? err.message : String(err))}`
12417
12728
  );
@@ -13864,6 +14175,130 @@ function mountWebShellSpaFallback(app, webShellDir, frameAncestors = []) {
13864
14175
  }
13865
14176
  __name(mountWebShellSpaFallback, "mountWebShellSpaFallback");
13866
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
+
13867
14302
  // packages/cli/src/serve/routes/daemon-status.ts
13868
14303
  init_esbuild_shims();
13869
14304
  function registerDaemonStatusRoutes(app, deps) {
@@ -17518,13 +17953,13 @@ async function handlePostFileWrite(req, res, deps) {
17518
17953
  req
17519
17954
  );
17520
17955
  if (originatorClientId === null) return;
17521
- const fs5 = factory.forRequest({
17956
+ const fs6 = factory.forRequest({
17522
17957
  originatorClientId,
17523
17958
  route: ROUTE2
17524
17959
  });
17525
17960
  try {
17526
- const resolved = await fs5.resolve(queryPath, "write");
17527
- const out = await fs5.writeTextAtomic(resolved, content, {
17961
+ const resolved = await fs6.resolve(queryPath, "write");
17962
+ const out = await fs6.writeTextAtomic(resolved, content, {
17528
17963
  mode,
17529
17964
  ...expectedHash ? { expectedHash } : {},
17530
17965
  ...bom !== void 0 ? { bom } : {},
@@ -17577,13 +18012,13 @@ async function handlePostFileEdit(req, res, deps) {
17577
18012
  req
17578
18013
  );
17579
18014
  if (originatorClientId === null) return;
17580
- const fs5 = factory.forRequest({
18015
+ const fs6 = factory.forRequest({
17581
18016
  originatorClientId,
17582
18017
  route: ROUTE2
17583
18018
  });
17584
18019
  try {
17585
- const resolved = await fs5.resolve(queryPath, "edit");
17586
- 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, {
17587
18022
  expectedHash
17588
18023
  });
17589
18024
  applyReadHeaders(res);
@@ -17911,6 +18346,18 @@ var legacySessionTelemetryRoutes = [
17911
18346
  attribution: "handler_resolved",
17912
18347
  route: "GET /session/:id/tasks"
17913
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
+ },
17914
18361
  {
17915
18362
  method: "GET",
17916
18363
  path: "/session/:id/lsp",
@@ -18593,7 +19040,7 @@ __name(registerPermissionRoutes, "registerPermissionRoutes");
18593
19040
  // packages/cli/src/serve/routes/session.ts
18594
19041
  init_esbuild_shims();
18595
19042
  import * as crypto3 from "node:crypto";
18596
- import * as fs3 from "node:fs";
19043
+ import * as fs4 from "node:fs";
18597
19044
  import * as path10 from "node:path";
18598
19045
 
18599
19046
  // packages/cli/src/serve/server/prompt-deadline.ts
@@ -18886,7 +19333,17 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
18886
19333
  organization
18887
19334
  )
18888
19335
  );
18889
- } 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
+ ) {
18890
19347
  bySessionId.set(
18891
19348
  live.sessionId,
18892
19349
  applyOrganization(
@@ -18968,7 +19425,13 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
18968
19425
  live.sessionId,
18969
19426
  mergeLiveSessionSummary(existing, live)
18970
19427
  );
18971
- } 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
+ ) {
18972
19435
  bySessionId.set(live.sessionId, {
18973
19436
  ...live,
18974
19437
  createdAt: live.createdAt,
@@ -19071,7 +19534,14 @@ async function listWorkspaceSessionsForResponse(bridge, workspaceCwd, options, r
19071
19534
  const existing = bySessionId.get(live.sessionId);
19072
19535
  if (existing) {
19073
19536
  bySessionId.set(live.sessionId, mergeLiveSessionSummary(existing, live));
19074
- } 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))) {
19075
19545
  bySessionId.set(live.sessionId, {
19076
19546
  ...live,
19077
19547
  createdAt: live.createdAt,
@@ -19199,73 +19669,811 @@ async function exportSessionTranscript(params) {
19199
19669
  }
19200
19670
  __name(exportSessionTranscript, "exportSessionTranscript");
19201
19671
 
19202
- // packages/cli/src/serve/routes/session.ts
19203
- var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
19204
- var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
19205
- var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
19206
- var GENERATION_HEARTBEAT_MS = 15e3;
19207
- var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
19208
- "POST /session/:id/branch",
19209
- "POST /session/:id/fork",
19210
- "POST /session/:id/cd"
19211
- ];
19212
- function isPrimaryOnlyLiveSessionRoute(route) {
19213
- return PRIMARY_ONLY_LIVE_SESSION_ROUTES.includes(
19214
- route
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;
19688
+ }
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
+ }
19215
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
19715
+ });
19216
19716
  }
19217
- __name(isPrimaryOnlyLiveSessionRoute, "isPrimaryOnlyLiveSessionRoute");
19218
- function formatGenerationSse(event, data) {
19219
- return `event: ${event}
19220
- data: ${JSON.stringify({ v: 1, ...data })}
19221
-
19222
- `;
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
+ });
19223
19723
  }
19224
- __name(formatGenerationSse, "formatGenerationSse");
19225
- function writeGenerationSseChunk(res, chunk) {
19226
- if (res.destroyed) {
19227
- return Promise.reject(new Error("Generation SSE connection destroyed"));
19228
- }
19229
- const writable = res.write(chunk);
19230
- const flush = res.flush;
19231
- flush?.call(res);
19232
- if (writable) {
19233
- return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
19234
- }
19235
- return new Promise((resolve6, reject) => {
19236
- const cleanup = /* @__PURE__ */ __name(() => {
19237
- res.off("drain", onDrain);
19238
- res.off("close", onClose);
19239
- res.off("error", onError);
19240
- }, "cleanup");
19241
- const onDrain = /* @__PURE__ */ __name(() => {
19242
- cleanup();
19243
- resolve6();
19244
- }, "onDrain");
19245
- const onClose = /* @__PURE__ */ __name(() => {
19246
- cleanup();
19247
- reject(new Error("Generation SSE connection closed"));
19248
- }, "onClose");
19249
- const onError = /* @__PURE__ */ __name((error2) => {
19250
- cleanup();
19251
- reject(error2);
19252
- }, "onError");
19253
- res.once("drain", onDrain);
19254
- res.once("close", onClose);
19255
- res.once("error", onError);
19256
- if (res.destroyed) onClose();
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
19257
19729
  });
19258
19730
  }
19259
- __name(writeGenerationSseChunk, "writeGenerationSseChunk");
19260
- function isReadOnlyWorkspaceInspection(runtime) {
19261
- return !runtime.primary && !runtime.trusted;
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
19746
+ });
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
+ };
19262
19813
  }
19263
- __name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
19264
- function runWorkspaceInspectionWithLogPolicy(runtime, read) {
19265
- return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read) : read();
19814
+ __name(findToolCallMetrics, "findToolCallMetrics");
19815
+ function encodePart(value) {
19816
+ return Buffer.from(value, "utf8").toString("base64url");
19266
19817
  }
19267
- __name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
19268
- function requireSessionArtifactClientId(clientId, res) {
19818
+ __name(encodePart, "encodePart");
19819
+ function decodePart(value) {
19820
+ try {
19821
+ return Buffer.from(value, "base64url").toString("utf8");
19822
+ } catch {
19823
+ return void 0;
19824
+ }
19825
+ }
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");
19834
+ }
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) {
19269
20477
  if (clientId !== void 0) return true;
19270
20478
  res.status(403).json({
19271
20479
  error: "Session artifact access requires a session-bound client id",
@@ -19425,11 +20633,40 @@ function registerSessionRoutes(app, deps) {
19425
20633
  sendBridgeError: sendBridgeError2,
19426
20634
  daemonLog,
19427
20635
  promptDeadlineMs,
19428
- sessionShellCommandEnabled
20636
+ sessionShellCommandEnabled,
20637
+ virtualSubagentSessions
19429
20638
  } = deps;
19430
20639
  const LANGUAGE_CODES = deps.languageCodes;
19431
20640
  const transcriptCursorMasterKey = crypto3.randomBytes(32);
19432
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");
19433
20670
  const getTranscriptCursorCodec = /* @__PURE__ */ __name((runtime) => {
19434
20671
  const canonicalCwd = canonicalizeWorkspace(runtime.workspaceCwd);
19435
20672
  const cacheKey = `${runtime.workspaceId}\0${canonicalCwd}`;
@@ -20010,6 +21247,138 @@ function registerSessionRoutes(app, deps) {
20010
21247
  }
20011
21248
  const clientId = parseClientIdHeader(req, res);
20012
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
+ }
20013
21382
  let worktreeMeta;
20014
21383
  const rawWorktree = body["worktree"];
20015
21384
  if (rawWorktree !== void 0 && rawWorktree !== null) {
@@ -20081,7 +21450,8 @@ function registerSessionRoutes(app, deps) {
20081
21450
  ...approvalMode !== void 0 ? { approvalMode } : {},
20082
21451
  ...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
20083
21452
  ...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
20084
- ...worktreeMeta ? { worktree: worktreeMeta } : {}
21453
+ ...worktreeMeta ? { worktree: worktreeMeta } : {},
21454
+ ...branchMeta ? { branch: branchMeta } : {}
20085
21455
  });
20086
21456
  if (daemonLog) {
20087
21457
  daemonLog.info(
@@ -20112,12 +21482,30 @@ function registerSessionRoutes(app, deps) {
20112
21482
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
20113
21483
  });
20114
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);
20115
21496
  }
20116
21497
  } catch {
21498
+ if (branchMeta) {
21499
+ activeBranchSessions.set(workspaceCwd, session.sessionId);
21500
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21501
+ }
20117
21502
  }
20118
21503
  } else {
20119
21504
  runtime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
20120
21505
  });
21506
+ if (branchMeta) {
21507
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21508
+ }
20121
21509
  }
20122
21510
  return;
20123
21511
  }
@@ -20182,18 +21570,79 @@ function registerSessionRoutes(app, deps) {
20182
21570
  return;
20183
21571
  }
20184
21572
  }
21573
+ if (branchMeta) {
21574
+ activeBranchSessions.set(workspaceCwd, session.sessionId);
21575
+ inFlightBranchWorkspaces.delete(workspaceCwd);
21576
+ }
20185
21577
  res.status(200).json(session);
20186
21578
  } catch (err) {
20187
21579
  if (worktreeMeta) {
20188
21580
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
20189
21581
  });
20190
21582
  }
21583
+ if (branchMeta) {
21584
+ await rollbackBranchCreation(
21585
+ workspaceCwd,
21586
+ branchMeta,
21587
+ branchBaseCommit,
21588
+ daemonLog
21589
+ );
21590
+ }
20191
21591
  sendBridgeError2(res, err, { route: "POST /session" });
20192
21592
  }
20193
21593
  });
20194
21594
  const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
20195
21595
  const sessionId = requireSessionId(req, res);
20196
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
+ }
20197
21646
  const body = safeBody(req);
20198
21647
  const route = `POST /session/:id/${action}`;
20199
21648
  let resolvedRuntime;
@@ -20283,7 +21732,7 @@ function registerSessionRoutes(app, deps) {
20283
21732
  path10.join(workspaceCwd, ".qwen", "worktrees")
20284
21733
  ];
20285
21734
  try {
20286
- realTarget = fs3.realpathSync(sidecar.worktreePath);
21735
+ realTarget = fs4.realpathSync(sidecar.worktreePath);
20287
21736
  let repoTop = null;
20288
21737
  try {
20289
21738
  repoTop = await new GitWorktreeService(
@@ -20296,7 +21745,7 @@ function registerSessionRoutes(app, deps) {
20296
21745
  }
20297
21746
  const contained = candidateRoots.some((root) => {
20298
21747
  try {
20299
- const realRoot = fs3.realpathSync(root);
21748
+ const realRoot = fs4.realpathSync(root);
20300
21749
  const rel = path10.relative(realRoot, realTarget);
20301
21750
  return !rel.startsWith("..") && !path10.isAbsolute(rel);
20302
21751
  } catch {
@@ -20339,18 +21788,124 @@ function registerSessionRoutes(app, deps) {
20339
21788
  }
20340
21789
  }
20341
21790
  }
20342
- 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);
20343
21847
  } catch (err) {
20344
- 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,
20345
21876
  route,
20346
- sessionId
21877
+ res,
21878
+ workspaceRegistry,
21879
+ daemonLog
20347
21880
  });
20348
- } finally {
20349
- 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
+ }
20350
21907
  }
20351
- }, "restoreSessionHandler");
20352
- app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
20353
- app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
21908
+ );
20354
21909
  app.post(
20355
21910
  "/session/:id/branch",
20356
21911
  mutate(),
@@ -20650,6 +22205,28 @@ function registerSessionRoutes(app, deps) {
20650
22205
  });
20651
22206
  app.get(
20652
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
+ },
20653
22230
  withOwnerReadSession(
20654
22231
  "GET /session/:id/context",
20655
22232
  async (_req, res, sessionId, runtime) => {
@@ -20681,6 +22258,28 @@ function registerSessionRoutes(app, deps) {
20681
22258
  );
20682
22259
  app.get(
20683
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
+ },
20684
22283
  withOwnerReadSession(
20685
22284
  "GET /session/:id/supported-commands",
20686
22285
  async (_req, res, sessionId, runtime) => {
@@ -20902,10 +22501,32 @@ function registerSessionRoutes(app, deps) {
20902
22501
  }
20903
22502
  const clientId = parseClientIdHeader(req, res);
20904
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
+ }
20905
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
+ }
20906
22525
  const forwardedBody = { ...body };
20907
22526
  delete forwardedBody["deadlineMs"];
22527
+ delete forwardedBody["delivery"];
20908
22528
  const lastEventId = ownerBridge.getSessionLastEventId(sessionId);
22529
+ const eventEpoch = ownerBridge.getSessionEventEpoch(sessionId);
20909
22530
  addDaemonRequestAttribute("qwen-code.prompt_id", promptId);
20910
22531
  const abort = new AbortController();
20911
22532
  let responseFinished = false;
@@ -20935,10 +22556,21 @@ function registerSessionRoutes(app, deps) {
20935
22556
  {
20936
22557
  ...clientId !== void 0 ? { clientId } : {},
20937
22558
  promptId,
20938
- ...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
+ } : {}
20939
22566
  }
20940
22567
  );
20941
22568
  } catch (err) {
22569
+ deps.channelDeliveryAuthorizations?.revokePrompt(
22570
+ runtime.workspaceCwd,
22571
+ sessionId,
22572
+ promptId
22573
+ );
20942
22574
  res.off("close", onResClose);
20943
22575
  res.off("finish", onResFinish);
20944
22576
  if (daemonLog && err instanceof PromptQueueFullError) {
@@ -20983,12 +22615,23 @@ function registerSessionRoutes(app, deps) {
20983
22615
  );
20984
22616
  }
20985
22617
  }
20986
- ).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(() => {
20987
22630
  });
20988
22631
  if (daemonLog) {
20989
22632
  daemonLog.info("prompt enqueued", { sessionId, promptId, clientId });
20990
22633
  }
20991
- res.status(202).json({ promptId, lastEventId });
22634
+ res.status(202).json({ promptId, lastEventId, eventEpoch });
20992
22635
  }
20993
22636
  )
20994
22637
  );
@@ -21077,6 +22720,29 @@ function registerSessionRoutes(app, deps) {
21077
22720
  app.post(
21078
22721
  "/session/:id/heartbeat",
21079
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
+ },
21080
22746
  withOwnerMutableSession(
21081
22747
  "POST /session/:id/heartbeat",
21082
22748
  (req, res, sessionId, runtime) => {
@@ -21093,6 +22759,25 @@ function registerSessionRoutes(app, deps) {
21093
22759
  app.post(
21094
22760
  "/session/:id/detach",
21095
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
+ },
21096
22781
  withOwnerMutableSession(
21097
22782
  "POST /session/:id/detach",
21098
22783
  async (req, res, sessionId, runtime) => {
@@ -21145,6 +22830,7 @@ function registerSessionRoutes(app, deps) {
21145
22830
  clientId !== void 0 ? { clientId } : void 0
21146
22831
  )
21147
22832
  );
22833
+ clearBranchSessionEntry(sessionId);
21148
22834
  res.status(204).end();
21149
22835
  } catch (err) {
21150
22836
  sendBridgeError2(res, err, {
@@ -21171,6 +22857,9 @@ function registerSessionRoutes(app, deps) {
21171
22857
  );
21172
22858
  }, "onError")
21173
22859
  });
22860
+ for (const removedId of result.removed) {
22861
+ clearBranchSessionEntry(removedId);
22862
+ }
21174
22863
  res.status(200).json(result);
21175
22864
  } catch (err) {
21176
22865
  sendBridgeError2(res, err, { route: "POST /sessions/delete" });
@@ -21245,6 +22934,9 @@ function registerSessionRoutes(app, deps) {
21245
22934
  );
21246
22935
  }, "onError")
21247
22936
  });
22937
+ for (const removedId of result.removed) {
22938
+ clearBranchSessionEntry(removedId);
22939
+ }
21248
22940
  res.status(200).json(result);
21249
22941
  } catch (err) {
21250
22942
  sendBridgeError2(res, err, { route });
@@ -22175,7 +23867,8 @@ function toView(task) {
22175
23867
  sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
22176
23868
  // Absent runs (tool-created / never-fired) normalizes to [] so the client
22177
23869
  // never special-cases undefined.
22178
- runs: Array.isArray(task.runs) ? task.runs : []
23870
+ runs: Array.isArray(task.runs) ? task.runs : [],
23871
+ ...task.delivery !== void 0 ? { delivery: task.delivery } : {}
22179
23872
  };
22180
23873
  }
22181
23874
  __name(toView, "toView");
@@ -22208,7 +23901,13 @@ function canonicalCron(cron) {
22208
23901
  }
22209
23902
  __name(canonicalCron, "canonicalCron");
22210
23903
  function registerScheduledTaskCrudRoutes(app, deps) {
22211
- const { prefix, resolveTarget, mutate, safeBody: safeBody2 } = deps;
23904
+ const {
23905
+ prefix,
23906
+ resolveTarget,
23907
+ mutate,
23908
+ safeBody: safeBody2,
23909
+ channelDeliveryAuthorizations
23910
+ } = deps;
22212
23911
  const base = `${prefix}/scheduled-tasks`;
22213
23912
  app.get(base, async (req, res) => {
22214
23913
  const target = resolveTarget(req, res);
@@ -22285,6 +23984,16 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22285
23984
  });
22286
23985
  return;
22287
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
+ }
22288
23997
  const removedField = findRemovedTaskField(body);
22289
23998
  if (removedField) {
22290
23999
  res.status(400).json(removedFieldError(removedField));
@@ -22341,6 +24050,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22341
24050
  // minute the task was created — same guard cronScheduler.create uses.
22342
24051
  lastFiredAt: now - now % 6e4,
22343
24052
  enabled,
24053
+ ...delivery !== void 0 ? { delivery } : {},
22344
24054
  ...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
22345
24055
  ...nameResult.value !== void 0 ? { name: nameResult.value } : {}
22346
24056
  };
@@ -22380,6 +24090,15 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22380
24090
  });
22381
24091
  return;
22382
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
+ }
22383
24102
  res.status(201).json(toView(task));
22384
24103
  });
22385
24104
  app.patch(`${base}/:id`, mutate(), async (req, res) => {
@@ -22394,6 +24113,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22394
24113
  const body = safeBody2(req);
22395
24114
  const patch = {};
22396
24115
  let clearName = false;
24116
+ let clearDelivery = false;
22397
24117
  const removedPatchField = findRemovedTaskField(body);
22398
24118
  if (removedPatchField) {
22399
24119
  res.status(400).json(removedFieldError(removedPatchField));
@@ -22458,7 +24178,20 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22458
24178
  }
22459
24179
  patch.enabled = body["enabled"];
22460
24180
  }
22461
- 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) {
22462
24195
  res.status(400).json({
22463
24196
  error: "No updatable fields provided",
22464
24197
  code: "empty_patch"
@@ -22485,6 +24218,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22485
24218
  }
22486
24219
  const next = { ...current, ...patch };
22487
24220
  if (clearName) delete next.name;
24221
+ if (clearDelivery) delete next.delivery;
22488
24222
  const justReEnabled = current.enabled === false && patch.enabled === true;
22489
24223
  const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
22490
24224
  const becameRecurring = patch.recurring === true && current.recurring !== true;
@@ -22539,6 +24273,22 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22539
24273
  } catch {
22540
24274
  }
22541
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
+ }
22542
24292
  res.status(200).json(toView(updated));
22543
24293
  });
22544
24294
  app.delete(`${base}/:id`, mutate(), async (req, res) => {
@@ -22581,6 +24331,13 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22581
24331
  await bridge.closeSession(boundSessionId).catch(() => {
22582
24332
  });
22583
24333
  }
24334
+ if (boundSessionId) {
24335
+ channelDeliveryAuthorizations?.revokeScheduledTask(
24336
+ workspaceCwd,
24337
+ boundSessionId,
24338
+ id
24339
+ );
24340
+ }
22584
24341
  res.status(200).json({ deleted: true, id });
22585
24342
  });
22586
24343
  app.post(`${base}/:id/run`, mutate(), async (req, res) => {
@@ -22661,17 +24418,30 @@ function registerScheduledTaskCrudRoutes(app, deps) {
22661
24418
  }
22662
24419
  __name(registerScheduledTaskCrudRoutes, "registerScheduledTaskCrudRoutes");
22663
24420
  function registerScheduledTasksRoutes(app, deps) {
22664
- const { boundWorkspace, mutate, safeBody: safeBody2, bridge } = deps;
24421
+ const {
24422
+ boundWorkspace,
24423
+ mutate,
24424
+ safeBody: safeBody2,
24425
+ bridge,
24426
+ channelDeliveryAuthorizations
24427
+ } = deps;
22665
24428
  registerScheduledTaskCrudRoutes(app, {
22666
24429
  prefix: "",
22667
24430
  resolveTarget: /* @__PURE__ */ __name(() => ({ workspaceCwd: boundWorkspace, bridge }), "resolveTarget"),
22668
24431
  mutate,
22669
- safeBody: safeBody2
24432
+ safeBody: safeBody2,
24433
+ channelDeliveryAuthorizations
22670
24434
  });
22671
24435
  }
22672
24436
  __name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
22673
24437
  function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
22674
- const { workspaceRegistry, mutate, safeBody: safeBody2, manageScheduledTaskSessions } = deps;
24438
+ const {
24439
+ workspaceRegistry,
24440
+ mutate,
24441
+ safeBody: safeBody2,
24442
+ manageScheduledTaskSessions,
24443
+ channelDeliveryAuthorizations
24444
+ } = deps;
22675
24445
  registerScheduledTaskCrudRoutes(app, {
22676
24446
  prefix: "/workspaces/:workspace",
22677
24447
  resolveTarget: /* @__PURE__ */ __name((req, res) => {
@@ -22690,7 +24460,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
22690
24460
  };
22691
24461
  }, "resolveTarget"),
22692
24462
  mutate,
22693
- safeBody: safeBody2
24463
+ safeBody: safeBody2,
24464
+ channelDeliveryAuthorizations
22694
24465
  });
22695
24466
  }
22696
24467
  __name(registerWorkspaceQualifiedScheduledTasksRoutes, "registerWorkspaceQualifiedScheduledTasksRoutes");
@@ -22720,6 +24491,77 @@ function parseNameField(raw) {
22720
24491
  }
22721
24492
  __name(parseNameField, "parseNameField");
22722
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
+
22723
24565
  // packages/cli/src/serve/routes/goals.ts
22724
24566
  init_esbuild_shims();
22725
24567
  var PROBE_CONCURRENCY = 10;
@@ -22988,6 +24830,11 @@ function startScheduledTaskKeepalive(opts) {
22988
24830
  log.debug("keepalive: readCronTasks failed, skipping this pass", err);
22989
24831
  return;
22990
24832
  }
24833
+ try {
24834
+ opts.onTasksRead?.(tasks);
24835
+ } catch (err) {
24836
+ log.debug("keepalive: onTasksRead failed", err);
24837
+ }
22991
24838
  for (const sessionId of collectBoundSessionIds(tasks)) {
22992
24839
  try {
22993
24840
  bridge.recordHeartbeat(sessionId);
@@ -23117,6 +24964,11 @@ async function rehydrateScheduledTaskSessions(deps) {
23117
24964
  log.debug("rehydrate: readCronTasks failed", err);
23118
24965
  return { loaded: [], failed: [] };
23119
24966
  }
24967
+ try {
24968
+ deps.onTasksRead?.(tasks);
24969
+ } catch (err) {
24970
+ log.debug("rehydrate: onTasksRead failed", err);
24971
+ }
23120
24972
  const sessionIds = collectBoundSessionIds(tasks);
23121
24973
  const loaded = [];
23122
24974
  const failed = [];
@@ -23476,6 +25328,7 @@ function createServeFeatures(deps) {
23476
25328
  persistSettingAvailable,
23477
25329
  sessionArtifactsPersistenceAvailable,
23478
25330
  sessionGenerationAvailable,
25331
+ workspaceGenerationAvailable,
23479
25332
  reloadAvailable,
23480
25333
  channelReloadAvailable,
23481
25334
  channelControlAvailable,
@@ -23512,6 +25365,7 @@ function createServeFeatures(deps) {
23512
25365
  sessionShellCommandEnabled,
23513
25366
  sessionArtifactsPersistenceAvailable,
23514
25367
  sessionGenerationAvailable: sessionGenerationAvailable(),
25368
+ workspaceGenerationAvailable: workspaceGenerationAvailable(),
23515
25369
  rateLimit: opts.rateLimit === true,
23516
25370
  reloadAvailable,
23517
25371
  channelReloadAvailable: channelReloadAvailable(),
@@ -24857,16 +26711,19 @@ data: ${dataJson}
24857
26711
  __name(formatSseFrame, "formatSseFrame");
24858
26712
  function registerSseEventsRoutes(app, deps) {
24859
26713
  const { workspaceRegistry, daemonLog, sendBridgeError: sendBridgeError2, writerIdleTimeoutMs } = deps;
24860
- app.get("/session/:id/events", (req, res) => {
26714
+ app.get("/session/:id/events", async (req, res) => {
24861
26715
  const sessionId = req.params["id"];
24862
26716
  const lastEventId = parseLastEventId(req.headers["last-event-id"]);
26717
+ const eventEpoch = parseEventEpochHeader(req.headers["x-qwen-event-epoch"]);
24863
26718
  const maxQueued = parseMaxQueuedQuery(req.query["maxQueued"], res);
24864
26719
  if (maxQueued === null) return;
24865
26720
  let iter;
26721
+ let busEpoch;
24866
26722
  const abort = new AbortController();
24867
26723
  try {
26724
+ const virtualKey = parseVirtualSubagentSessionId(sessionId);
24868
26725
  const runtime = requireSessionRuntime({
24869
- sessionId,
26726
+ sessionId: virtualKey?.parentSessionId ?? sessionId,
24870
26727
  route: "GET /session/:id/events",
24871
26728
  res,
24872
26729
  workspaceRegistry,
@@ -24874,13 +26731,33 @@ function registerSseEventsRoutes(app, deps) {
24874
26731
  });
24875
26732
  if (!runtime) return;
24876
26733
  const snapshot = req.query["snapshot"] === "1";
24877
- const iterable = runtime.bridge.subscribeEvents(sessionId, {
26734
+ const iterable = virtualKey ? await deps.virtualSubagentSessions?.subscribe(runtime, sessionId, {
24878
26735
  signal: abort.signal,
24879
26736
  lastEventId,
26737
+ ...maxQueued !== void 0 ? { maxQueued } : {}
26738
+ }) : runtime.bridge.subscribeEvents(sessionId, {
26739
+ signal: abort.signal,
26740
+ lastEventId,
26741
+ ...eventEpoch !== void 0 ? { epoch: eventEpoch } : {},
24880
26742
  ...maxQueued !== void 0 ? { maxQueued } : {},
24881
26743
  ...snapshot ? { snapshot: true } : {}
24882
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
+ }
24883
26753
  iter = iterable[Symbol.asyncIterator]();
26754
+ if (!virtualKey) {
26755
+ try {
26756
+ busEpoch = runtime.bridge.getSessionEventEpoch(sessionId);
26757
+ } catch {
26758
+ busEpoch = void 0;
26759
+ }
26760
+ }
24884
26761
  } catch (err) {
24885
26762
  if (err instanceof SubscriberLimitExceededError) {
24886
26763
  writeStderrLine(
@@ -24920,6 +26797,9 @@ function registerSseEventsRoutes(app, deps) {
24920
26797
  res.setHeader("Cache-Control", "no-cache, no-transform");
24921
26798
  res.setHeader("Connection", "keep-alive");
24922
26799
  res.setHeader("X-Accel-Buffering", "no");
26800
+ if (busEpoch !== void 0) {
26801
+ res.setHeader("X-Qwen-Event-Epoch", busEpoch);
26802
+ }
24923
26803
  res.flushHeaders();
24924
26804
  activeSseCount++;
24925
26805
  let sseCounted = true;
@@ -25045,7 +26925,7 @@ function registerSseEventsRoutes(app, deps) {
25045
26925
  const data = next.value.data;
25046
26926
  const gap = typeof data.earliestAvailableId === "number" && typeof data.lastDeliveredId === "number" ? data.earliestAvailableId - data.lastDeliveredId - 1 : void 0;
25047
26927
  writeStderrLine(
25048
- `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.`
25049
26929
  );
25050
26930
  }
25051
26931
  await writeWithBackpressure(formatSseFrame(next.value));
@@ -26033,7 +27913,7 @@ __name(registerWorkspaceQualifiedLifecycleRoutes, "registerWorkspaceQualifiedLif
26033
27913
 
26034
27914
  // packages/cli/src/serve/routes/workspace-management.ts
26035
27915
  init_esbuild_shims();
26036
- import { readdir, stat } from "node:fs/promises";
27916
+ import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
26037
27917
  import { realpathSync as realpathSync2 } from "node:fs";
26038
27918
  import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute7, join as join8, resolve as resolve4, sep as sep3 } from "node:path";
26039
27919
  var MAX_PATH_SUGGESTIONS = 50;
@@ -26255,7 +28135,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26255
28135
  const suggestions = [];
26256
28136
  let truncated = false;
26257
28137
  try {
26258
- const entries = await readdir(dir, { withFileTypes: true });
28138
+ const entries = await readdir2(dir, { withFileTypes: true });
26259
28139
  entries.sort((a, b) => a.name.localeCompare(b.name));
26260
28140
  for (const entry of entries) {
26261
28141
  if (entry.name.startsWith(".") && !filter.startsWith(".")) continue;
@@ -26265,7 +28145,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26265
28145
  let isDir = entry.isDirectory();
26266
28146
  if (!isDir && entry.isSymbolicLink()) {
26267
28147
  try {
26268
- isDir = (await stat(join8(dir, entry.name))).isDirectory();
28148
+ isDir = (await stat2(join8(dir, entry.name))).isDirectory();
26269
28149
  } catch {
26270
28150
  continue;
26271
28151
  }
@@ -26385,7 +28265,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
26385
28265
  return;
26386
28266
  }
26387
28267
  try {
26388
- const s = await stat(canonical);
28268
+ const s = await stat2(canonical);
26389
28269
  if (!s.isDirectory()) {
26390
28270
  res.status(400).json({
26391
28271
  error: "Path is not a directory",
@@ -27188,7 +29068,7 @@ __name(registerWorkspaceManagementRoutes, "registerWorkspaceManagementRoutes");
27188
29068
 
27189
29069
  // packages/cli/src/serve/routes/workspace-git.ts
27190
29070
  init_esbuild_shims();
27191
- import * as fs4 from "node:fs";
29071
+ import * as fs5 from "node:fs";
27192
29072
  import * as path14 from "node:path";
27193
29073
  function registerWorkspaceGitRoutes(app, deps) {
27194
29074
  app.get("/workspace/git", async (_req, res) => {
@@ -27215,8 +29095,8 @@ function registerWorkspaceQualifiedGitRoutes(app, deps) {
27215
29095
  let gitCwd = runtime.workspaceCwd;
27216
29096
  if (typeof rawCwd === "string" && rawCwd.length > 0) {
27217
29097
  try {
27218
- const resolved = fs4.realpathSync(path14.resolve(rawCwd));
27219
- const root = fs4.realpathSync(runtime.workspaceCwd);
29098
+ const resolved = fs5.realpathSync(path14.resolve(rawCwd));
29099
+ const root = fs5.realpathSync(runtime.workspaceCwd);
27220
29100
  const rel = path14.relative(root, resolved);
27221
29101
  if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
27222
29102
  gitCwd = resolved;
@@ -27640,6 +29520,38 @@ var WorkspaceGitState = class {
27640
29520
 
27641
29521
  // packages/cli/src/serve/routes/workspace-mcp-control.ts
27642
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");
27643
29555
  function registerWorkspaceMcpControlRoutes(app, deps) {
27644
29556
  const {
27645
29557
  boundWorkspace,
@@ -27666,9 +29578,11 @@ function registerWorkspaceMcpControlRoutes(app, deps) {
27666
29578
  app.post(
27667
29579
  "/workspace/mcp/reload",
27668
29580
  mutate({ strict: true }),
27669
- async (_req, res) => {
29581
+ async (req, res) => {
29582
+ const options = parseMcpReloadOptions(safeBody2(req), res);
29583
+ if (!options) return;
27670
29584
  try {
27671
- const result = await bridge.reloadWorkspaceMcp();
29585
+ const result = await bridge.reloadWorkspaceMcp(options);
27672
29586
  res.status(202).json(result);
27673
29587
  } catch (err) {
27674
29588
  sendBridgeError2(res, err, { route: "POST /workspace/mcp/reload" });
@@ -27873,9 +29787,11 @@ function registerWorkspaceQualifiedMcpControlRoutes(app, deps) {
27873
29787
  res
27874
29788
  );
27875
29789
  if (!runtime) return;
29790
+ const options = parseMcpReloadOptions(deps.safeBody(req), res);
29791
+ if (!options) return;
27876
29792
  const route = "POST /workspaces/:workspace/mcp/reload";
27877
29793
  try {
27878
- const result = await runtime.bridge.reloadWorkspaceMcp();
29794
+ const result = await runtime.bridge.reloadWorkspaceMcp(options);
27879
29795
  res.status(202).json(result);
27880
29796
  } catch (err) {
27881
29797
  deps.sendBridgeError(res, err, { route });
@@ -29250,6 +31166,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29250
31166
  (runtime) => runtime.bridge.generateSessionContent !== void 0
29251
31167
  );
29252
31168
  }, "sessionGenerationAvailable"),
31169
+ workspaceGenerationAvailable: /* @__PURE__ */ __name(() => primaryBridge.generateWorkspaceContent !== void 0, "workspaceGenerationAvailable"),
29253
31170
  // Registry injection supplies the primary workspace service through the
29254
31171
  // runtime, so it has the same reload surface as legacy deps.workspace.
29255
31172
  reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
@@ -29543,6 +31460,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29543
31460
  maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
29544
31461
  languageCodes
29545
31462
  });
31463
+ registerChannelNotifyRoutes(app, {
31464
+ boundWorkspace: primaryBoundWorkspace,
31465
+ workspaceRegistry,
31466
+ mutate,
31467
+ safeBody,
31468
+ deliverChannelMessage: deps.deliverChannelMessage
31469
+ });
29546
31470
  registerWorkspaceStatusRoutes(app, {
29547
31471
  boundWorkspace: primaryBoundWorkspace,
29548
31472
  bridge: primaryBridge,
@@ -29608,6 +31532,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29608
31532
  parseClientId: parseClientIdHeader,
29609
31533
  safeBody
29610
31534
  });
31535
+ mountWorkspaceGenerationRoutes(app, {
31536
+ bridge: primaryBridge,
31537
+ mutate,
31538
+ parseClientId: parseClientIdHeader,
31539
+ safeBody
31540
+ });
29611
31541
  mountWorkspaceQualifiedAgentsRoutes(app, {
29612
31542
  workspaceRegistry,
29613
31543
  mutate,
@@ -29784,6 +31714,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29784
31714
  allowPrivateAuthBaseUrl: opts.allowPrivateAuthBaseUrl === true,
29785
31715
  installAuthProvider: deps.installAuthProvider
29786
31716
  });
31717
+ const virtualSubagentSessions = new VirtualSubagentSessions();
29787
31718
  registerSessionRoutes(app, {
29788
31719
  boundWorkspace: primaryBoundWorkspace,
29789
31720
  bridge: primaryBridge,
@@ -29792,9 +31723,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29792
31723
  mutate,
29793
31724
  sendBridgeError: sendBridgeError2,
29794
31725
  daemonLog,
31726
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
29795
31727
  promptDeadlineMs: opts.promptDeadlineMs,
29796
31728
  sessionShellCommandEnabled,
29797
- languageCodes
31729
+ languageCodes,
31730
+ virtualSubagentSessions
29798
31731
  });
29799
31732
  registerWorkspaceMcpControlRoutes(app, {
29800
31733
  boundWorkspace: primaryBoundWorkspace,
@@ -29886,7 +31819,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29886
31819
  boundWorkspace: primaryBoundWorkspace,
29887
31820
  mutate,
29888
31821
  safeBody,
29889
- bridge: deps.manageScheduledTaskSessions ? bridge : void 0
31822
+ bridge: deps.manageScheduledTaskSessions ? bridge : void 0,
31823
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
29890
31824
  });
29891
31825
  registerGoalsRoutes(app, {
29892
31826
  boundWorkspace: primaryBoundWorkspace,
@@ -29896,16 +31830,32 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29896
31830
  workspaceRegistry,
29897
31831
  mutate,
29898
31832
  safeBody,
29899
- manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true
31833
+ manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
31834
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
29900
31835
  });
29901
31836
  registerUsageStatsRoutes(app);
29902
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");
29903
31852
  const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
29904
31853
  const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
29905
31854
  const rehydrateWorkspace = /* @__PURE__ */ __name((taskBridge, workspaceCwd) => {
29906
31855
  void rehydrateScheduledTaskSessions({
29907
31856
  bridge: taskBridge,
29908
31857
  boundWorkspace: workspaceCwd,
31858
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(workspaceCwd, tasks), "onTasksRead"),
29909
31859
  onError: /* @__PURE__ */ __name((sessionId, err) => {
29910
31860
  process.stderr.write(
29911
31861
  `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
@@ -29930,7 +31880,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29930
31880
  const keepalive = startScheduledTaskKeepalive({
29931
31881
  bridge: runtime.bridge,
29932
31882
  boundWorkspace: runtime.workspaceCwd,
29933
- intervalMs: keepaliveIntervalMs
31883
+ intervalMs: keepaliveIntervalMs,
31884
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
29934
31885
  });
29935
31886
  rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
29936
31887
  keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
@@ -29960,7 +31911,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
29960
31911
  workspaceRegistry,
29961
31912
  daemonLog,
29962
31913
  writerIdleTimeoutMs: opts.writerIdleTimeoutMs,
29963
- sendBridgeError: sendBridgeError2
31914
+ sendBridgeError: sendBridgeError2,
31915
+ virtualSubagentSessions
29964
31916
  });
29965
31917
  acpHandleRef.current = mountAcpHttp(app, primaryBridge, {
29966
31918
  boundWorkspace: primaryBoundWorkspace,