@qwen-code/qwen-code 0.21.1 → 0.21.2

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 (321) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +1 -0
  2. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  3. package/bundled/qc-helper/docs/features/channels/github.md +42 -10
  4. package/bundled/qc-helper/docs/features/channels/gitlab.md +171 -0
  5. package/bundled/qc-helper/docs/features/code-review.md +20 -0
  6. package/bundled/qc-helper/docs/features/hooks.md +20 -0
  7. package/bundled/qc-helper/docs/features/sub-agents.md +22 -8
  8. package/bundled/qc-helper/docs/qwen-serve.md +7 -5
  9. package/bundled/review/SKILL.md +1 -1
  10. package/chunks/{MaxSizedBox-VI3ROJJA.js → MaxSizedBox-TQBQ247P.js} +42 -38
  11. package/chunks/{StandaloneSessionPicker-LYXKD2EV.js → StandaloneSessionPicker-2HPTKCLX.js} +58 -54
  12. package/chunks/{acp-startup-profiler-DFVPFQ6C.js → acp-startup-profiler-2C4A5ZTJ.js} +2 -2
  13. package/chunks/{acpAgent-WN5SRDQO.js → acpAgent-PS6EDGH3.js} +431 -168
  14. package/chunks/{agent-K6ECSM64.js → agent-VDOUB35F.js} +38 -34
  15. package/chunks/{agent-headless-NO4Y2HOE.js → agent-headless-EO53EFS2.js} +38 -34
  16. package/chunks/{anthropicContentGenerator-V2QOGVYD.js → anthropicContentGenerator-OFHSZJBF.js} +6 -6
  17. package/chunks/{artifact-tool-6K6U7XYJ.js → artifact-tool-RDN2W7ND.js} +2 -2
  18. package/chunks/{askUserQuestion-GD2IJJ7I.js → askUserQuestion-OZERWH5R.js} +2 -2
  19. package/chunks/{bridge-3KJEWDNE.js → bridge-W7AZSRZQ.js} +42 -38
  20. package/chunks/{build-S6DO7LMM.js → build-GDBLPA24.js} +1 -1
  21. package/chunks/{channel-management-service-XR7GZSWF.js → channel-management-service-5S7YCWX5.js} +20 -5
  22. package/chunks/{channel-settings-store-HW4FXXUA.js → channel-settings-store-JFVRSNER.js} +44 -40
  23. package/chunks/{channel-worker-group-XDPTDWTX.js → channel-worker-group-OVWGYMZS.js} +5 -5
  24. package/chunks/{channel-worker-manager-YYEHVRRE.js → channel-worker-manager-H55GKOQA.js} +5 -5
  25. package/chunks/{channel-worker-supervisor-74HTWA2G.js → channel-worker-supervisor-CABBXYHK.js} +3 -3
  26. package/chunks/{chunk-UWMLWVCA.js → chunk-2IIJTXYF.js} +26 -10
  27. package/chunks/{chunk-VYOXCEPJ.js → chunk-2KKCCLPT.js} +1 -1
  28. package/chunks/{chunk-T4TXDL7G.js → chunk-2LEOZTBT.js} +36 -24
  29. package/chunks/{chunk-XWWKIXVD.js → chunk-3APUUXRF.js} +1 -1
  30. package/chunks/{chunk-TCIFAA7K.js → chunk-3F2WDAV6.js} +2 -2
  31. package/chunks/{chunk-SGFT55XI.js → chunk-3I6DUGQD.js} +1 -1
  32. package/chunks/{chunk-ZURDMIDR.js → chunk-44F4LBWZ.js} +228 -71
  33. package/chunks/{chunk-GKX7E4CO.js → chunk-45IOTAUS.js} +1 -1
  34. package/chunks/{chunk-6QIGFD5W.js → chunk-4KP2F2TE.js} +1 -1
  35. package/chunks/{chunk-X5WNMMIA.js → chunk-54YCNSK5.js} +4241 -1636
  36. package/chunks/{chunk-P4WOAOJW.js → chunk-56Z7QEAQ.js} +67 -21
  37. package/chunks/{chunk-UPUG4GXM.js → chunk-5NNHICSA.js} +3 -3
  38. package/chunks/{chunk-LGAOC3ZS.js → chunk-675H6PLP.js} +1 -1
  39. package/chunks/{chunk-5KTQXHPY.js → chunk-6CQWRWUC.js} +3 -3
  40. package/chunks/chunk-6FMJLI5M.js +1591 -0
  41. package/chunks/{chunk-GZ3RCT54.js → chunk-6MPDY6ZG.js} +1 -1
  42. package/chunks/{chunk-RCUQIPTN.js → chunk-6PQPKTXP.js} +1 -1
  43. package/chunks/{chunk-KCO4FLFJ.js → chunk-6TAASXWL.js} +3 -3
  44. package/chunks/{chunk-JHNRZMHI.js → chunk-77V3VIKL.js} +9 -9
  45. package/chunks/{chunk-CAPPWD3X.js → chunk-7KAXXBER.js} +3 -3
  46. package/chunks/{chunk-A4COXFB3.js → chunk-7SJN2IWT.js} +5 -5
  47. package/chunks/{chunk-Y4IHBGBP.js → chunk-7ULQIS27.js} +1 -1
  48. package/chunks/{chunk-5MKRTI4T.js → chunk-A7Y5H4TX.js} +4 -4
  49. package/chunks/{chunk-CVHIL5IG.js → chunk-AOHY3QJ3.js} +13 -6
  50. package/chunks/chunk-AQ37AY7B.js +93 -0
  51. package/chunks/{chunk-OCESJA77.js → chunk-AUOULH6Q.js} +45 -45
  52. package/chunks/{chunk-UBEPNVDI.js → chunk-BBIQAX4V.js} +3 -3
  53. package/chunks/{chunk-JSD33JG6.js → chunk-CBBP4BMC.js} +23 -9
  54. package/chunks/{chunk-ZHBO7WVX.js → chunk-CNTR4GR6.js} +1 -1
  55. package/chunks/{chunk-PB3MBFKG.js → chunk-CO2U743O.js} +4 -4
  56. package/chunks/{chunk-XZC5VLBZ.js → chunk-CPZAH673.js} +4 -0
  57. package/chunks/{chunk-T3O2B4XO.js → chunk-CU47KXB5.js} +3 -3
  58. package/chunks/{chunk-2LKVPASC.js → chunk-D4HTUMGX.js} +3 -3
  59. package/chunks/{chunk-BNWB5CYE.js → chunk-D6MDRSZ6.js} +7 -7
  60. package/chunks/{chunk-7BAU433D.js → chunk-DEEABGH2.js} +867 -91
  61. package/chunks/{chunk-52ZSWYEG.js → chunk-DQ2O5QOJ.js} +1 -1
  62. package/chunks/{chunk-WBSMNTSV.js → chunk-DSFHVTWD.js} +2 -2
  63. package/chunks/{chunk-PT722TDT.js → chunk-DUNI4EBW.js} +701 -86
  64. package/chunks/{chunk-UHUSJ6X7.js → chunk-E2BHWIDT.js} +19 -4
  65. package/chunks/{chunk-T2QMKU3R.js → chunk-E2FN6SM7.js} +17 -5
  66. package/chunks/{chunk-W4MIWP6M.js → chunk-E6CJ2SMM.js} +2 -2
  67. package/chunks/{chunk-5ZF5XXTS.js → chunk-EQNUDTL6.js} +2 -2
  68. package/chunks/{chunk-2N7CODY5.js → chunk-EU5TBFJI.js} +2 -2
  69. package/chunks/{chunk-TFRMVU6R.js → chunk-FANRZEAJ.js} +1 -1
  70. package/chunks/{chunk-WBL3FJEU.js → chunk-FC4KQFCS.js} +1 -1
  71. package/chunks/{chunk-GNR2RNMP.js → chunk-FCYYAB4S.js} +2 -2
  72. package/chunks/{chunk-FNMZK765.js → chunk-FJ5WUMUQ.js} +1 -1
  73. package/chunks/{chunk-J7OACQDE.js → chunk-FNDXMN7I.js} +71 -49
  74. package/chunks/{chunk-U3E3UQAA.js → chunk-FS674JW4.js} +3 -3
  75. package/chunks/{chunk-S7W2GKIO.js → chunk-G7XXKQYS.js} +2 -0
  76. package/chunks/{chunk-VWOOBLTY.js → chunk-GJ2GBPBD.js} +2 -2
  77. package/chunks/{chunk-TBBV36Y4.js → chunk-GL4JOZXU.js} +4 -4
  78. package/chunks/{chunk-FTD6DP4T.js → chunk-GURGAJTX.js} +2 -1
  79. package/chunks/{chunk-65PQENQP.js → chunk-H6I4PGRV.js} +5 -5
  80. package/chunks/{chunk-7XATOOE7.js → chunk-HC45LTEN.js} +1 -1
  81. package/chunks/{chunk-VCPIZRYH.js → chunk-HIVKI6O6.js} +7 -7
  82. package/chunks/{chunk-HMRM2A3U.js → chunk-HX6RLYUO.js} +3 -3
  83. package/chunks/{chunk-GZXCZHCT.js → chunk-I3G5JWBV.js} +1 -1
  84. package/chunks/{chunk-2XSLTRFZ.js → chunk-I5BT7ADR.js} +2 -2
  85. package/chunks/{chunk-GATT5TKW.js → chunk-IGTHU3T4.js} +1 -1
  86. package/chunks/{chunk-4G2BISNC.js → chunk-IIUGIWWY.js} +1 -1
  87. package/chunks/{chunk-7I5GTCT4.js → chunk-JCJ7LKNA.js} +5104 -4817
  88. package/chunks/{chunk-657BH7VM.js → chunk-JE2CEOBO.js} +2 -2
  89. package/chunks/{chunk-S3TWXGKA.js → chunk-JE7KQ2UP.js} +4 -2
  90. package/chunks/{chunk-BPZKP57P.js → chunk-JJPKFJBT.js} +3 -3
  91. package/chunks/{chunk-6PE7N3A4.js → chunk-JLZ3RBQG.js} +7 -5
  92. package/chunks/{chunk-2LQTH543.js → chunk-JXVC2PL3.js} +2 -2
  93. package/chunks/{chunk-JCW2R7WC.js → chunk-K623ENWT.js} +3 -79
  94. package/chunks/{chunk-T2NCM2ET.js → chunk-K6KS3LTN.js} +2 -749
  95. package/chunks/{chunk-6RPMI2AB.js → chunk-KR32NIAN.js} +6 -6
  96. package/chunks/{chunk-XBYYDKAZ.js → chunk-KWHKHSIS.js} +8 -7
  97. package/chunks/{chunk-EVKE2FZL.js → chunk-KXDONCPU.js} +4 -4
  98. package/chunks/{chunk-5TBMQLGG.js → chunk-L2E5GFAG.js} +2 -2
  99. package/chunks/{chunk-MHAIJPTD.js → chunk-L32VV3ZJ.js} +12 -12
  100. package/chunks/{chunk-OKF7JF3R.js → chunk-LHKCY7DY.js} +3 -3
  101. package/chunks/{chunk-LW3RFMG7.js → chunk-LOY7RWQG.js} +3 -3
  102. package/chunks/{chunk-AQIDMUGU.js → chunk-LYI2PZDK.js} +1 -1
  103. package/chunks/{chunk-YGF33UXG.js → chunk-MB32MS4U.js} +12 -3
  104. package/chunks/{chunk-Y6AXW2OG.js → chunk-MM7TH7ZM.js} +1 -1
  105. package/chunks/{chunk-2DN4J57Y.js → chunk-N4ACHWNH.js} +1 -1
  106. package/chunks/{chunk-M7OONWYU.js → chunk-NBD76HUW.js} +4 -2
  107. package/chunks/{chunk-A2D5BAVP.js → chunk-NHFEMWAZ.js} +1 -1
  108. package/chunks/{chunk-3EFXSQCM.js → chunk-NTDH4IML.js} +7 -7
  109. package/chunks/chunk-O6GEWCJA.js +21 -0
  110. package/chunks/{chunk-7DXQIJID.js → chunk-OFZKFPYG.js} +3 -3
  111. package/chunks/{chunk-JTV5K7NH.js → chunk-P5VC5USY.js} +1 -1
  112. package/chunks/{chunk-Q43KPN7X.js → chunk-P755N4CS.js} +3 -3
  113. package/chunks/{chunk-XFZYFU3I.js → chunk-PCK4B6LR.js} +1 -1
  114. package/chunks/{chunk-EJGJIBRS.js → chunk-PJOHNFIY.js} +3 -3
  115. package/chunks/{chunk-WUZ7H6DP.js → chunk-PVNQRENX.js} +1 -1
  116. package/chunks/{chunk-LO4ROVP4.js → chunk-PZEXDV3H.js} +106 -8
  117. package/chunks/{chunk-WZRWHXFE.js → chunk-Q3T5KA2V.js} +1 -1
  118. package/chunks/{chunk-QIZKCVM3.js → chunk-Q5WZTTWE.js} +4 -4
  119. package/chunks/{chunk-BGTQCTQW.js → chunk-QARJNL2V.js} +3 -3
  120. package/chunks/{chunk-GXIJHV66.js → chunk-QCXGC7QB.js} +3 -3
  121. package/chunks/{chunk-DZLYR4U3.js → chunk-QDK4F2N5.js} +1 -1
  122. package/chunks/{chunk-NOKIVHOL.js → chunk-QTHQ6Z5X.js} +1 -1
  123. package/chunks/{chunk-A3NDJ5SB.js → chunk-R2XWGR75.js} +2 -2
  124. package/chunks/{chunk-JX27F6QS.js → chunk-RDJOB6S3.js} +1 -1
  125. package/chunks/{chunk-TV64SXKD.js → chunk-RG64CDT2.js} +4 -4
  126. package/chunks/{chunk-JFMA7Y5M.js → chunk-RSVPYAGK.js} +5 -5
  127. package/chunks/{chunk-64LQLPL7.js → chunk-SHN4KHDK.js} +3 -3
  128. package/chunks/chunk-T3CHYWJZ.js +758 -0
  129. package/chunks/{chunk-PONHVBRT.js → chunk-TEGJSJDF.js} +2 -2
  130. package/chunks/{chunk-75GFAX4R.js → chunk-THVU3RNH.js} +1 -1
  131. package/chunks/{record-artifact-XAMSFSW4.js → chunk-TIRRPCFS.js} +22 -7
  132. package/chunks/{chunk-HV26XH34.js → chunk-TTJZAIFP.js} +3 -3
  133. package/chunks/{chunk-JMONIXMJ.js → chunk-TZTAV5RH.js} +1 -1
  134. package/chunks/{chunk-7AEJDLRA.js → chunk-UV6KF7T3.js} +2 -2
  135. package/chunks/{chunk-PLDQBIO6.js → chunk-V25K5ID7.js} +1 -1
  136. package/chunks/{chunk-S4WJVPZW.js → chunk-V4XNUDPE.js} +3 -3
  137. package/chunks/{chunk-2FAK6PNM.js → chunk-VEMNQMHA.js} +2 -2
  138. package/chunks/{chunk-CQL64ESB.js → chunk-VMX5RZQH.js} +12 -10
  139. package/chunks/{chunk-EIF3FXTB.js → chunk-W3UKBMSI.js} +63 -18
  140. package/chunks/{chunk-TDL6LB4K.js → chunk-WWCMSZII.js} +21 -9
  141. package/chunks/{chunk-5YKDXHUY.js → chunk-XP4L6KS3.js} +2 -2
  142. package/chunks/{chunk-RPLGZJV2.js → chunk-XQK4XXTN.js} +1 -1
  143. package/chunks/{chunk-KAMYKP7E.js → chunk-XUGZYLDH.js} +1 -1
  144. package/chunks/{chunk-MR5EAQ5M.js → chunk-YANIWTRZ.js} +1 -1
  145. package/chunks/{chunk-3L2SPEBH.js → chunk-YGE3IXJP.js} +1 -1
  146. package/chunks/{chunk-BCZFQXWK.js → chunk-YUFIEIWC.js} +1 -1
  147. package/chunks/{chunk-75MIQ3LV.js → chunk-Z3S5EMOW.js} +4 -4
  148. package/chunks/{chunk-BMFALVGQ.js → chunk-ZMOJ7ISP.js} +1 -1
  149. package/chunks/{chunk-GEBV2JGB.js → chunk-ZPZ7ZJEE.js} +1 -1
  150. package/chunks/{computer-use-ZTIDHMMA.js → computer-use-5QWCFNKD.js} +38 -34
  151. package/chunks/{config-utils-NYSXDMEQ.js → config-utils-WADIDWGG.js} +4 -4
  152. package/chunks/{contextCommand-2PIEU37Z.js → contextCommand-4Z7T7TUM.js} +40 -36
  153. package/chunks/{core-runtime-3XEYLQFK.js → core-runtime-6N4EFC2Q.js} +38 -34
  154. package/chunks/{create-sub-session-SBYUMSSS.js → create-sub-session-62YZWVAY.js} +2 -2
  155. package/chunks/{create-sub-session-R76FVXCI.js → create-sub-session-AEREHZBQ.js} +38 -34
  156. package/chunks/{cron-create-2QK6TCEC.js → cron-create-6E7GIQTG.js} +4 -4
  157. package/chunks/{cron-delete-FDCDFYMG.js → cron-delete-JD26XY3W.js} +4 -4
  158. package/chunks/{cron-list-XN3WVBTP.js → cron-list-CUWFB44G.js} +4 -4
  159. package/chunks/{daemon-Q2AB5Z23.js → daemon-PCNCI5YU.js} +72 -3
  160. package/chunks/{daemon-status-provider-3XJI6CAL.js → daemon-status-provider-DDF7C5M7.js} +46 -42
  161. package/chunks/{daemon-trust-policy-ILUDTLHD.js → daemon-trust-policy-Q4KSOJTR.js} +43 -39
  162. package/chunks/{daemon-trust-policy-monitor-HS3PKKRO.js → daemon-trust-policy-monitor-V6FTE3IY.js} +43 -39
  163. package/chunks/{deferred-core-runtime-X4QV662U.js → deferred-core-runtime-GHJ5GQHK.js} +38 -34
  164. package/chunks/{dist-BSTVRPMT.js → dist-26BIMQT6.js} +276 -16
  165. package/chunks/{dist-SV7Q3AWJ.js → dist-2PERFI23.js} +12 -9
  166. package/chunks/{dist-DOLYHMXE.js → dist-OAOC5OV4.js} +2 -2
  167. package/chunks/{dist-YGBBMK3Z.js → dist-PVEAFLHY.js} +5 -4
  168. package/chunks/{dist-HVRQ2CFL.js → dist-SL2LUMML.js} +1180 -5
  169. package/chunks/dist-ULIG4M5H.js +13415 -0
  170. package/chunks/{dist-IXQEQWRG.js → dist-WGMNT3JQ.js} +1 -1
  171. package/chunks/{dist-SSU66DM4.js → dist-ZHXOBXDN.js} +1 -1
  172. package/chunks/{earlyInputCapture-XKLZT7ZD.js → earlyInputCapture-TQXLLISD.js} +39 -35
  173. package/chunks/{edit-HHGIOTQ2.js → edit-FJEUV6KZ.js} +38 -34
  174. package/chunks/{enter-worktree-ZN7PUQ46.js → enter-worktree-7GE3TZ4P.js} +38 -34
  175. package/chunks/{enterPlanMode-EIFIDSIV.js → enterPlanMode-KR5TMPCJ.js} +38 -34
  176. package/chunks/{environment-XXQ75D2Q.js → environment-SWL3CMB3.js} +40 -36
  177. package/chunks/{errors-4GMVU7CK.js → errors-XQE7BGZV.js} +40 -36
  178. package/chunks/{exit-worktree-GXMI4ATY.js → exit-worktree-CHKTYNCV.js} +38 -34
  179. package/chunks/{exitPlanMode-34UVY7M6.js → exitPlanMode-QYAG6LWX.js} +38 -34
  180. package/chunks/{fast-path-VPIVA7L6.js → fast-path-Z2K7W6DC.js} +2 -2
  181. package/chunks/{gemini-4BWIK4WD.js → gemini-YU4XKEDG.js} +91 -87
  182. package/chunks/{geminiContentGenerator-3XVV5MSS.js → geminiContentGenerator-ZZX6NBO4.js} +6 -6
  183. package/chunks/{glob-TZ2ABCJG.js → glob-VYF5CXSX.js} +38 -34
  184. package/chunks/goal-tools-HGO6VXPB.js +335 -0
  185. package/chunks/{grep-BEF463NA.js → grep-5DP5ZUTW.js} +38 -34
  186. package/chunks/{handleAutoUpdate-L6ERF36Y.js → handleAutoUpdate-UVBJ56DL.js} +42 -38
  187. package/chunks/{i18n-FMM5FDXR.js → i18n-UQNYHEUD.js} +39 -35
  188. package/chunks/{image-gen-HHVLF7HS.js → image-gen-WHPIZNWF.js} +9 -9
  189. package/chunks/{initializer-625TIAIO.js → initializer-GMIICF4W.js} +44 -40
  190. package/chunks/{installationInfo-6AM4I2Y3.js → installationInfo-4MGG4WVI.js} +39 -35
  191. package/chunks/{keychain-token-storage-72IYCAZV.js → keychain-token-storage-IKO4G53C.js} +2 -2
  192. package/chunks/list-CPN2W334.js +92 -0
  193. package/chunks/{list-agents-R6KDXQR3.js → list-agents-PXJ7ZUFB.js} +2 -2
  194. package/chunks/{loadedSettingsAdapter-SPUTNKAV.js → loadedSettingsAdapter-ZQAV5NDO.js} +43 -39
  195. package/chunks/{loggingContentGenerator-LKOF7XI7.js → loggingContentGenerator-5E7W4IEP.js} +18 -18
  196. package/chunks/{loop-wakeup-3IQKCYAH.js → loop-wakeup-Y26NQZ5I.js} +13 -6
  197. package/chunks/{ls-DKZ37A7N.js → ls-ONQTTMQR.js} +4 -4
  198. package/chunks/{lsp-QNWN7KN3.js → lsp-YGHHRGMD.js} +2 -2
  199. package/chunks/{managed-npm-update-ACQGGIN5.js → managed-npm-update-MKKAXYXA.js} +39 -35
  200. package/chunks/{mcp-SZLHKFJW.js → mcp-V5NTJF6X.js} +43 -39
  201. package/chunks/{monitor-DF52UVHI.js → monitor-CO3ASY6E.js} +38 -34
  202. package/chunks/nonInteractiveCli-ZJYEOO7U.js +148 -0
  203. package/chunks/{notebook-edit-FCWS4XVN.js → notebook-edit-Z7AEE6FM.js} +38 -34
  204. package/chunks/{openaiContentGenerator-7LDK3DCJ.js → openaiContentGenerator-CA3MQOP3.js} +19 -19
  205. package/chunks/{pidfile-6ERW3DF4.js → pidfile-NL7MKDRU.js} +39 -35
  206. package/chunks/{processUtils-COKZAMUP.js → processUtils-PB5K2DYH.js} +2 -2
  207. package/chunks/{qwenContentGenerator-TKWUMR7N.js → qwenContentGenerator-JYFNDCOS.js} +44 -40
  208. package/chunks/{qwenOAuth2-7HMU47SF.js → qwenOAuth2-W2ALKQDD.js} +8 -8
  209. package/chunks/{read-file-X6DRC574.js → read-file-IEOR5H5W.js} +11 -11
  210. package/chunks/{read-mcp-resource-GFTWYXMK.js → read-mcp-resource-U2IJN5HM.js} +2 -2
  211. package/chunks/record-artifact-MGPJ7EG4.js +21 -0
  212. package/chunks/{resumeHistoryUtils-PFPM2GWM.js → resumeHistoryUtils-BNBTP5AS.js} +44 -40
  213. package/chunks/{ripGrep-OWV2IVJC.js → ripGrep-UMQODKEB.js} +38 -34
  214. package/chunks/{run-qwen-serve-TSTCO4XE.js → run-qwen-serve-RN2R6QQW.js} +116 -65
  215. package/chunks/{runtime-DAUPSUKI.js → runtime-QFJ2MJF5.js} +48 -44
  216. package/chunks/{scheduler-KMADMT26.js → scheduler-AMYUFOZI.js} +38 -34
  217. package/chunks/{sdk-exporters-http-WO556XNU.js → sdk-exporters-http-4BQANSJ6.js} +3 -3
  218. package/chunks/{sdk-impl-LPAVACSF.js → sdk-impl-Z4VXWVFX.js} +3 -3
  219. package/chunks/{send-message-SAWK4DZX.js → send-message-PMP4ATVM.js} +6 -11
  220. package/chunks/{serve-NNRWS6F4.js → serve-EIIYJVX3.js} +43 -39
  221. package/chunks/{server-WEH7DVCH.js → server-EP2LLAPD.js} +1768 -712
  222. package/chunks/{session-WXC56V2I.js → session-GMPZBLOW.js} +83 -79
  223. package/chunks/{settings-DJDXFDZ3.js → settings-LN7RNKBS.js} +47 -43
  224. package/chunks/{shell-JN5VRQXD.js → shell-EM2OWU5X.js} +38 -34
  225. package/chunks/{skill-SGXPKJCS.js → skill-T5VPSK73.js} +17 -16
  226. package/chunks/{skill-settings-VJ5PDMZI.js → skill-settings-GMR3GMNY.js} +42 -38
  227. package/chunks/{spawnChannel-ETMJW7YX.js → spawnChannel-YPCU62DI.js} +40 -36
  228. package/chunks/{standalone-update-MK3Z7KBI.js → standalone-update-JAKIM2NF.js} +40 -36
  229. package/chunks/{startInteractiveUI-ZCGIXPGT.js → startInteractiveUI-YETQWGYF.js} +774 -779
  230. package/chunks/{syntheticOutput-355CB6CJ.js → syntheticOutput-D7E6ZFKR.js} +3 -3
  231. package/chunks/{task-create-INGWNUG4.js → task-create-NFCYD43L.js} +10 -9
  232. package/chunks/{task-list-5XNNGTF4.js → task-list-TAVMGEVD.js} +5 -5
  233. package/chunks/{task-stop-4ROAOBXH.js → task-stop-ZDF2UJRM.js} +2 -2
  234. package/chunks/{task-update-CRK5VWWZ.js → task-update-6L7LHGEX.js} +10 -9
  235. package/chunks/{team-create-QQGAJG7P.js → team-create-LFJ6HGNY.js} +38 -34
  236. package/chunks/{team-delete-S2RCXA4P.js → team-delete-DPGGRQBU.js} +5 -5
  237. package/chunks/{team-plan-approval-RT7Q5R6O.js → team-plan-approval-C2KLSDGO.js} +38 -34
  238. package/chunks/{theme-manager-EEWIQJ7J.js → theme-manager-JQ3ZGBP5.js} +39 -35
  239. package/chunks/{todoWrite-7WM3VDMY.js → todoWrite-2UO5G6G6.js} +32 -4
  240. package/chunks/{tool-search-Z3Z4AYKP.js → tool-search-FAZBFRJZ.js} +15 -14
  241. package/chunks/{total-session-admission-44JKRWQD.js → total-session-admission-5CALIVYO.js} +42 -38
  242. package/chunks/{trustedFolders-X2JEIO57.js → trustedFolders-KOPSP44S.js} +39 -35
  243. package/chunks/{update-relaunch-VWNPYDIP.js → update-relaunch-6QL2TICS.js} +5 -5
  244. package/chunks/{updateCheck-KAQH67DV.js → updateCheck-4Q6RIKFW.js} +41 -37
  245. package/chunks/{useAutoAcceptIndicator-JH6BCF7S.js → useAutoAcceptIndicator-Q5BMKZV3.js} +47 -43
  246. package/chunks/{validateNonInterActiveAuth-GIUJ2UFS.js → validateNonInterActiveAuth-GKOC5F6Z.js} +79 -75
  247. package/chunks/{version-BGLYIJUY.js → version-VSATY2LD.js} +1 -1
  248. package/chunks/{web-fetch-OTDU4VQF.js → web-fetch-JCLKL6NL.js} +14 -14
  249. package/chunks/{web-search-FP6SIHPR.js → web-search-DSQTFUBX.js} +8 -8
  250. package/chunks/{workflow-YCIVBYSB.js → workflow-M6QAVKVJ.js} +41 -37
  251. package/chunks/workspace-providers-status-YKLTLMJA.js +89 -0
  252. package/chunks/{workspace-registration-store-OTMS3H4C.js → workspace-registration-store-5DMGKU64.js} +1 -1
  253. package/chunks/{workspace-registry-O63R6IZ4.js → workspace-registry-PTYUSYXX.js} +42 -38
  254. package/chunks/{workspace-service-M6LLHKJ5.js → workspace-service-25ML3T47.js} +48 -44
  255. package/chunks/{workspace-skills-status-C2V7BAIS.js → workspace-skills-status-YKZWOYRX.js} +44 -40
  256. package/chunks/{workspace-trust-reconciler-IBUPOUJN.js → workspace-trust-reconciler-5FI2S3OS.js} +47 -43
  257. package/chunks/write-file-AY7VLP5X.js +78 -0
  258. package/chunks/zoom-image-S4LJZMD5.js +224 -0
  259. package/cli.js +50 -16
  260. package/package.json +3 -3
  261. package/web-shell/assets/{arc-75-Wdeo3.js → arc-xjArKHU2.js} +1 -1
  262. package/web-shell/assets/{architectureDiagram-3BPJPVTR-FKeXQbyP.js → architectureDiagram-3BPJPVTR-BgrQDNYG.js} +1 -1
  263. package/web-shell/assets/{blockDiagram-GPEHLZMM-CY0vc-A3.js → blockDiagram-GPEHLZMM-CXxWC-1_.js} +1 -1
  264. package/web-shell/assets/{c4Diagram-AAUBKEIU-CNP-A-8u.js → c4Diagram-AAUBKEIU-Dx1tLm3v.js} +1 -1
  265. package/web-shell/assets/channel-B1cyk94G.js +1 -0
  266. package/web-shell/assets/{chunk-2J33WTMH-GybS4Gii.js → chunk-2J33WTMH-CBxjogVR.js} +1 -1
  267. package/web-shell/assets/{chunk-4BX2VUAB-02H91V8v.js → chunk-4BX2VUAB-izb-rY5W.js} +1 -1
  268. package/web-shell/assets/{chunk-55IACEB6-D3M-2VT6.js → chunk-55IACEB6-NzLyvSb8.js} +1 -1
  269. package/web-shell/assets/{chunk-727SXJPM-CCu29u4H.js → chunk-727SXJPM-DVyKb0dl.js} +1 -1
  270. package/web-shell/assets/{chunk-AQP2D5EJ-CaFKWgrn.js → chunk-AQP2D5EJ-BtqL7NzB.js} +1 -1
  271. package/web-shell/assets/{chunk-FMBD7UC4-ZZpPqIwQ.js → chunk-FMBD7UC4-iNpdKIO0.js} +1 -1
  272. package/web-shell/assets/{chunk-ND2GUHAM-D22DqGs8.js → chunk-ND2GUHAM-DI7cbFmX.js} +1 -1
  273. package/web-shell/assets/{chunk-QZHKN3VN-Bu85S0fw.js → chunk-QZHKN3VN-3Y_-xFYs.js} +1 -1
  274. package/web-shell/assets/classDiagram-4FO5ZUOK-BpBYZoRE.js +1 -0
  275. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BpBYZoRE.js +1 -0
  276. package/web-shell/assets/{cose-bilkent-S5V4N54A-f1CK1Gwe.js → cose-bilkent-S5V4N54A--raRatZn.js} +1 -1
  277. package/web-shell/assets/{dagre-BM42HDAG-D0Ow8F_n.js → dagre-BM42HDAG-B8SU70mO.js} +1 -1
  278. package/web-shell/assets/{diagram-2AECGRRQ-BPrmTWp8.js → diagram-2AECGRRQ-ewgoakXo.js} +1 -1
  279. package/web-shell/assets/{diagram-5GNKFQAL-HccuFAzy.js → diagram-5GNKFQAL-Bm_JLTnS.js} +1 -1
  280. package/web-shell/assets/{diagram-KO2AKTUF-BrS76mbA.js → diagram-KO2AKTUF-DEIUjUy9.js} +1 -1
  281. package/web-shell/assets/{diagram-LMA3HP47-V7T9lU-5.js → diagram-LMA3HP47-C2Wmrpj-.js} +1 -1
  282. package/web-shell/assets/{diagram-OG6HWLK6-DKidyJMR.js → diagram-OG6HWLK6-CtYe6bFx.js} +1 -1
  283. package/web-shell/assets/{erDiagram-TEJ5UH35-DBadZIkp.js → erDiagram-TEJ5UH35-DfpHcWLV.js} +1 -1
  284. package/web-shell/assets/{flowDiagram-I6XJVG4X-BymfqdNJ.js → flowDiagram-I6XJVG4X-CAiUhio5.js} +1 -1
  285. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DOw340jf.js → ganttDiagram-6RSMTGT7-CYc7ezr4.js} +1 -1
  286. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-_8EiD8sl.js → gitGraphDiagram-PVQCEYII-70lbkcRS.js} +1 -1
  287. package/web-shell/assets/index-C1k3PDuU.css +5 -0
  288. package/web-shell/assets/index-C2GE3DAF.js +74 -0
  289. package/web-shell/assets/index-DZLIXILO.js +1750 -0
  290. package/web-shell/assets/{index-CKIadvET.js → index-Ww86nT9f.js} +1 -1
  291. package/web-shell/assets/{infoDiagram-5YYISTIA-D61KYQBu.js → infoDiagram-5YYISTIA-C7e8DWPa.js} +1 -1
  292. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CsiXSpNx.js → ishikawaDiagram-YF4QCWOH-BYLr2op-.js} +1 -1
  293. package/web-shell/assets/{journeyDiagram-JHISSGLW-Sdfionyh.js → journeyDiagram-JHISSGLW-hEibAHKX.js} +1 -1
  294. package/web-shell/assets/{kanban-definition-UN3LZRKU-C3WI3Cnl.js → kanban-definition-UN3LZRKU-F2rt8Uhp.js} +1 -1
  295. package/web-shell/assets/{linear-Dpigcc62.js → linear-DPhyNezd.js} +1 -1
  296. package/web-shell/assets/{mermaid.core-Ct97pqgW.js → mermaid.core-ZUtnug0n.js} +5 -5
  297. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BzeaN0rB.js → mindmap-definition-RKZ34NQL-DDWcMoi8.js} +1 -1
  298. package/web-shell/assets/{pieDiagram-4H26LBE5-CvjgcbVD.js → pieDiagram-4H26LBE5-CTRKzw1_.js} +1 -1
  299. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BUzgTNdH.js → quadrantDiagram-W4KKPZXB-CAEwYG_z.js} +1 -1
  300. package/web-shell/assets/{requirementDiagram-4Y6WPE33-B7zKlgUQ.js → requirementDiagram-4Y6WPE33-CRjnH9D9.js} +1 -1
  301. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Bb9CQgrT.js → sankeyDiagram-5OEKKPKP-LPQT_sOd.js} +1 -1
  302. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DJ6V7itG.js → sequenceDiagram-3UESZ5HK-Ht2Iqvb0.js} +1 -1
  303. package/web-shell/assets/{stateDiagram-AJRCARHV-IImflERY.js → stateDiagram-AJRCARHV-CIUdqOXu.js} +1 -1
  304. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BmqqQZ6w.js +1 -0
  305. package/web-shell/assets/{timeline-definition-PNZ67QCA-6Q_uWHKh.js → timeline-definition-PNZ67QCA-BcilneZF.js} +1 -1
  306. package/web-shell/assets/{vennDiagram-CIIHVFJN-TmyKyjwv.js → vennDiagram-CIIHVFJN-BljwiiH1.js} +1 -1
  307. package/web-shell/assets/{wardley-L42UT6IY-CRh9uiPv.js → wardley-L42UT6IY-DeKjkYjq.js} +1 -1
  308. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-59TKAW8w.js → wardleyDiagram-YWT4CUSO-L3U1H7KG.js} +1 -1
  309. package/web-shell/assets/{xychartDiagram-2RQKCTM6-GCSUIK2L.js → xychartDiagram-2RQKCTM6-IJnWsgMT.js} +1 -1
  310. package/web-shell/index.html +2 -2
  311. package/chunks/list-L2GA674Y.js +0 -88
  312. package/chunks/nonInteractiveCli-5T7KYKLK.js +0 -144
  313. package/chunks/workspace-providers-status-S35YAIUS.js +0 -85
  314. package/chunks/write-file-3BZC3EAE.js +0 -72
  315. package/chunks/zoom-image-TZ6S2O57.js +0 -351
  316. package/web-shell/assets/channel-DPYMT76A.js +0 -1
  317. package/web-shell/assets/classDiagram-4FO5ZUOK--JstsIgL.js +0 -1
  318. package/web-shell/assets/classDiagram-v2-Q7XG4LA2--JstsIgL.js +0 -1
  319. package/web-shell/assets/index-D1eXNRHe.js +0 -1389
  320. package/web-shell/assets/index-DVLD4CQq.css +0 -5
  321. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CYI_YoNR.js +0 -1
@@ -1,10 +1,5 @@
1
1
  // Force strict mode and setup for ESM
2
2
  "use strict";
3
- import {
4
- openQwenAsrRealtimeStream,
5
- openVoiceStream,
6
- openVoiceStreamWithRetry
7
- } from "./chunk-BCZFQXWK.js";
8
3
  import {
9
4
  GENERATION_MAX_PROMPT_BYTES,
10
5
  MAX_REMEMBER_CONTENT_BYTES,
@@ -21,7 +16,12 @@ import {
21
16
  shouldSuppressRememberErrorDetails,
22
17
  workspaceMemoryFailureCode,
23
18
  workspaceMemoryFailureDiagnostics
24
- } from "./chunk-6PE7N3A4.js";
19
+ } from "./chunk-JLZ3RBQG.js";
20
+ import {
21
+ openQwenAsrRealtimeStream,
22
+ openVoiceStream,
23
+ openVoiceStreamWithRetry
24
+ } from "./chunk-YUFIEIWC.js";
25
25
  import {
26
26
  SetupGithubError,
27
27
  collectSessionData,
@@ -33,13 +33,13 @@ import {
33
33
  toJson,
34
34
  toJsonl,
35
35
  toMarkdown
36
- } from "./chunk-LO4ROVP4.js";
36
+ } from "./chunk-PZEXDV3H.js";
37
37
  import {
38
38
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
39
39
  ObservedChannelContactStore
40
- } from "./chunk-LGAOC3ZS.js";
41
- import "./chunk-XFZYFU3I.js";
40
+ } from "./chunk-675H6PLP.js";
42
41
  import "./chunk-YDLJGZHL.js";
42
+ import "./chunk-PCK4B6LR.js";
43
43
  import "./chunk-2MIN6GRR.js";
44
44
  import "./chunk-QHTIBUWB.js";
45
45
  import "./chunk-QTERJVPZ.js";
@@ -101,14 +101,18 @@ import {
101
101
  setRateLimiter,
102
102
  unsafeRevealSecret,
103
103
  validateMcpRuntimeServerName
104
- } from "./chunk-YGF33UXG.js";
104
+ } from "./chunk-MB32MS4U.js";
105
105
  import {
106
106
  isLoopbackBind
107
107
  } from "./chunk-RXFQM6FQ.js";
108
+ import {
109
+ createWorkspaceSkillsStatusProvider
110
+ } from "./chunk-BBIQAX4V.js";
111
+ import "./chunk-L55JWS76.js";
108
112
  import {
109
113
  evaluateDaemonWorkspaceTrust,
110
114
  readDaemonTrustPolicySnapshot
111
- } from "./chunk-HV26XH34.js";
115
+ } from "./chunk-TTJZAIFP.js";
112
116
  import {
113
117
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
114
118
  MAX_WORKSPACE_SKILL_NAME_LENGTH,
@@ -122,14 +126,14 @@ import {
122
126
  validateWorkspaceSkillName,
123
127
  validateWorkspaceVoiceState,
124
128
  voiceSettingsScopeToWire
125
- } from "./chunk-P4WOAOJW.js";
129
+ } from "./chunk-56Z7QEAQ.js";
126
130
  import {
127
131
  PermissionRulesValidationError,
128
132
  buildPermissionSettings,
129
133
  isPermissionRuleType,
130
134
  normalizePermissionRules,
131
135
  readPermissionRuleSet
132
- } from "./chunk-MR5EAQ5M.js";
136
+ } from "./chunk-YANIWTRZ.js";
133
137
  import {
134
138
  assertVoiceBaseUrlNetworkAllowed,
135
139
  isStreamingVoiceModel,
@@ -137,13 +141,13 @@ import {
137
141
  resolveVoiceTranscriptionConfig,
138
142
  sanitizeVoiceErrorMessage,
139
143
  transcribeVoiceAudio
140
- } from "./chunk-CAPPWD3X.js";
144
+ } from "./chunk-7KAXXBER.js";
141
145
  import {
142
146
  isVoiceEnabled,
143
147
  isVoiceMode,
144
148
  readVoiceModel
145
- } from "./chunk-JTV5K7NH.js";
146
- import "./chunk-ZHBO7WVX.js";
149
+ } from "./chunk-P5VC5USY.js";
150
+ import "./chunk-CNTR4GR6.js";
147
151
  import {
148
152
  WorkspacePermissionRulesSessionRequiredError,
149
153
  WorkspaceSettingsPartialPersistError,
@@ -161,19 +165,19 @@ import {
161
165
  import "./chunk-GRC5HGPI.js";
162
166
  import {
163
167
  assertValidChannelSecretUpdates
164
- } from "./chunk-5ZF5XXTS.js";
168
+ } from "./chunk-EQNUDTL6.js";
165
169
  import {
166
170
  createDaemonStatusProvider
167
- } from "./chunk-TBBV36Y4.js";
171
+ } from "./chunk-GL4JOZXU.js";
168
172
  import "./chunk-VXZBKKQR.js";
169
- import "./chunk-QIZKCVM3.js";
173
+ import "./chunk-Q5WZTTWE.js";
170
174
  import "./chunk-E5Z2AVNV.js";
171
175
  import {
172
176
  SessionArtifactAuthorizationError,
173
177
  SessionArtifactValidationError,
174
178
  createAcpSessionBridge,
175
179
  parseSessionSource
176
- } from "./chunk-ZURDMIDR.js";
180
+ } from "./chunk-44F4LBWZ.js";
177
181
  import {
178
182
  EVENT_SCHEMA_VERSION,
179
183
  EventBus,
@@ -181,41 +185,37 @@ import {
181
185
  } from "./chunk-GLWP3FDB.js";
182
186
  import "./chunk-XCGIMOLN.js";
183
187
  import "./chunk-OCPBI7J5.js";
184
- import "./chunk-KAMYKP7E.js";
188
+ import "./chunk-XUGZYLDH.js";
185
189
  import {
186
190
  createWorkspaceProvidersStatusProvider
187
- } from "./chunk-3EFXSQCM.js";
191
+ } from "./chunk-NTDH4IML.js";
188
192
  import {
189
193
  getAuthTypeFromEnv,
190
194
  resolveCliGenerationConfig
191
- } from "./chunk-KCO4FLFJ.js";
195
+ } from "./chunk-6TAASXWL.js";
192
196
  import {
193
197
  snapshotProcessEnv
194
- } from "./chunk-2FAK6PNM.js";
195
- import {
196
- createWorkspaceSkillsStatusProvider
197
- } from "./chunk-UBEPNVDI.js";
198
- import "./chunk-L55JWS76.js";
198
+ } from "./chunk-VEMNQMHA.js";
199
199
  import {
200
200
  STATUS_SCHEMA_VERSION,
201
201
  createIdleWorkspaceMemoryStatus,
202
202
  mapDomainErrorToErrorKind
203
- } from "./chunk-FTD6DP4T.js";
203
+ } from "./chunk-GURGAJTX.js";
204
204
  import "./chunk-Z4X5MTRT.js";
205
- import "./chunk-WBL3FJEU.js";
205
+ import "./chunk-FC4KQFCS.js";
206
206
  import {
207
207
  daemonObservedContactsPath,
208
208
  loadChannelsConfig
209
- } from "./chunk-BNWB5CYE.js";
210
- import "./chunk-5MKRTI4T.js";
209
+ } from "./chunk-D6MDRSZ6.js";
210
+ import "./chunk-A7Y5H4TX.js";
211
211
  import "./chunk-57OAHC2Y.js";
212
212
  import {
213
213
  parseChannelWebhookConfigLenient
214
- } from "./chunk-2XSLTRFZ.js";
215
- import "./chunk-TFRMVU6R.js";
214
+ } from "./chunk-I5BT7ADR.js";
215
+ import "./chunk-FANRZEAJ.js";
216
216
  import {
217
217
  supportedChannelCatalog
218
- } from "./chunk-XBYYDKAZ.js";
218
+ } from "./chunk-KWHKHSIS.js";
219
219
  import "./chunk-V6WHFGST.js";
220
220
  import {
221
221
  MAX_REGISTERED_WORKSPACES,
@@ -224,8 +224,8 @@ import {
224
224
  WorkspaceRegistrationStoreLimitError,
225
225
  normalizeWorkspaceDisplayName,
226
226
  workspaceRegistrationId
227
- } from "./chunk-AQIDMUGU.js";
228
- import "./chunk-XZC5VLBZ.js";
227
+ } from "./chunk-LYI2PZDK.js";
228
+ import "./chunk-CPZAH673.js";
229
229
  import {
230
230
  BranchWhilePromptActiveError,
231
231
  CancelSentinelCollisionError,
@@ -277,7 +277,7 @@ import {
277
277
  } from "./chunk-U4VTUMMK.js";
278
278
  import {
279
279
  normalizeWorkerDiagnostic
280
- } from "./chunk-GZ3RCT54.js";
280
+ } from "./chunk-6MPDY6ZG.js";
281
281
  import {
282
282
  normalizeServeChannelSelection
283
283
  } from "./chunk-ALMR3E6Q.js";
@@ -286,10 +286,11 @@ import {
286
286
  redactLogCredentials
287
287
  } from "./chunk-M5GB774H.js";
288
288
  import "./chunk-5HBA2Z7V.js";
289
- import "./chunk-T2NCM2ET.js";
289
+ import "./chunk-K6KS3LTN.js";
290
+ import "./chunk-T3CHYWJZ.js";
290
291
  import {
291
292
  sanitizeLogText
292
- } from "./chunk-7I5GTCT4.js";
293
+ } from "./chunk-JCJ7LKNA.js";
293
294
  import "./chunk-UDXSXLER.js";
294
295
  import {
295
296
  getDialogSettingKeys,
@@ -300,27 +301,27 @@ import {
300
301
  getWritableScopes,
301
302
  loadSettings,
302
303
  validateSettingValue
303
- } from "./chunk-EIF3FXTB.js";
304
+ } from "./chunk-W3UKBMSI.js";
304
305
  import "./chunk-RKUWKYED.js";
306
+ import "./chunk-GOXKNSDZ.js";
307
+ import "./chunk-IDS7MSUP.js";
305
308
  import {
306
309
  SUPPORTED_LANGUAGES,
307
310
  detectSystemLanguage,
308
311
  resolveLanguageSetting,
309
312
  resolveSupportedLanguage
310
- } from "./chunk-TCIFAA7K.js";
311
- import "./chunk-2N7CODY5.js";
312
- import "./chunk-GOXKNSDZ.js";
313
- import "./chunk-IDS7MSUP.js";
313
+ } from "./chunk-3F2WDAV6.js";
314
+ import "./chunk-EU5TBFJI.js";
314
315
  import "./chunk-6PEXNQTX.js";
315
- import "./chunk-VYOXCEPJ.js";
316
- import "./chunk-VJNBRRZG.js";
317
316
  import {
318
317
  getWorkspaceTrustStatus
319
- } from "./chunk-Q43KPN7X.js";
318
+ } from "./chunk-P755N4CS.js";
320
319
  import "./chunk-ALGGS7UH.js";
321
320
  import {
322
321
  isWithinRoot as isWithinRoot2
323
322
  } from "./chunk-MR3PXB6E.js";
323
+ import "./chunk-2KKCCLPT.js";
324
+ import "./chunk-VJNBRRZG.js";
324
325
  import {
325
326
  writeStderrLine,
326
327
  writeStderrLineSafe
@@ -398,19 +399,20 @@ import {
398
399
  writeWorkspaceContextFile,
399
400
  writeWorktreeSession,
400
401
  writeWorktreeSessionMarker
401
- } from "./chunk-X5WNMMIA.js";
402
+ } from "./chunk-54YCNSK5.js";
403
+ import "./chunk-5M6IDOMF.js";
402
404
  import "./chunk-TWPJO254.js";
403
405
  import "./chunk-H6XPXXMH.js";
404
- import "./chunk-5M6IDOMF.js";
405
- import "./chunk-UPUG4GXM.js";
406
- import "./chunk-64LQLPL7.js";
407
- import "./chunk-2LQTH543.js";
408
- import "./chunk-KRXPRVGL.js";
409
- import "./chunk-BMFALVGQ.js";
410
406
  import {
411
407
  MAX_JOBS,
412
408
  nextDurableFireMs
413
- } from "./chunk-CVHIL5IG.js";
409
+ } from "./chunk-AOHY3QJ3.js";
410
+ import "./chunk-5NNHICSA.js";
411
+ import "./chunk-SHN4KHDK.js";
412
+ import "./chunk-JXVC2PL3.js";
413
+ import "./chunk-KRXPRVGL.js";
414
+ import "./chunk-6PVPNMXU.js";
415
+ import "./chunk-ZMOJ7ISP.js";
414
416
  import {
415
417
  nextFireTime,
416
418
  parseCron
@@ -423,22 +425,25 @@ import {
423
425
  readCronTasks,
424
426
  taskHasLegacyCondition,
425
427
  updateCronTasks
426
- } from "./chunk-PONHVBRT.js";
428
+ } from "./chunk-TEGJSJDF.js";
429
+ import "./chunk-TIRRPCFS.js";
430
+ import "./chunk-O6GEWCJA.js";
427
431
  import "./chunk-T26EAKDL.js";
428
- import "./chunk-6PVPNMXU.js";
429
432
  import "./chunk-CPBF7KYF.js";
430
- import "./chunk-6QIGFD5W.js";
431
- import "./chunk-XWWKIXVD.js";
432
- import "./chunk-75GFAX4R.js";
433
- import "./chunk-OKF7JF3R.js";
433
+ import "./chunk-4KP2F2TE.js";
434
+ import "./chunk-3APUUXRF.js";
435
+ import "./chunk-THVU3RNH.js";
436
+ import "./chunk-LHKCY7DY.js";
437
+ import "./chunk-6FMJLI5M.js";
434
438
  import {
435
439
  APPROVAL_MODES,
436
440
  SubagentError,
437
441
  SubagentErrorCode
438
- } from "./chunk-JSD33JG6.js";
442
+ } from "./chunk-CBBP4BMC.js";
439
443
  import "./chunk-S6LOFUVP.js";
440
- import "./chunk-JCW2R7WC.js";
441
- import "./chunk-2DN4J57Y.js";
444
+ import "./chunk-K623ENWT.js";
445
+ import "./chunk-AQ37AY7B.js";
446
+ import "./chunk-N4ACHWNH.js";
442
447
  import "./chunk-ZPJWUGCS.js";
443
448
  import {
444
449
  QwenOAuth2Client,
@@ -448,15 +453,15 @@ import {
448
453
  isDeviceAuthorizationSuccess,
449
454
  isDeviceTokenPending,
450
455
  isDeviceTokenSuccess
451
- } from "./chunk-2LKVPASC.js";
456
+ } from "./chunk-D4HTUMGX.js";
452
457
  import "./chunk-NAVJD2PQ.js";
453
- import "./chunk-LW3RFMG7.js";
454
- import "./chunk-W4MIWP6M.js";
458
+ import "./chunk-LOY7RWQG.js";
459
+ import "./chunk-E6CJ2SMM.js";
455
460
  import "./chunk-DGEIYUC3.js";
456
461
  import "./chunk-MPHPFVKK.js";
457
462
  import "./chunk-GLNBDYUX.js";
458
463
  import "./chunk-DJ2GSRLV.js";
459
- import "./chunk-5KTQXHPY.js";
464
+ import "./chunk-6CQWRWUC.js";
460
465
  import {
461
466
  addDaemonRequestAttribute,
462
467
  emitDaemonLog,
@@ -466,40 +471,44 @@ import {
466
471
  recordDaemonHttpRequest,
467
472
  recordDaemonHttpResponse,
468
473
  withDaemonRequestSpan
469
- } from "./chunk-75MIQ3LV.js";
474
+ } from "./chunk-Z3S5EMOW.js";
470
475
  import "./chunk-2J3OJGTL.js";
471
476
  import "./chunk-P3QQPMQA.js";
472
- import "./chunk-RPLGZJV2.js";
477
+ import "./chunk-XQK4XXTN.js";
473
478
  import "./chunk-GLCZKT5V.js";
474
- import "./chunk-DZLYR4U3.js";
479
+ import "./chunk-QDK4F2N5.js";
475
480
  import "./chunk-CR3C7WXL.js";
476
481
  import "./chunk-XWRJCPHC.js";
477
482
  import {
483
+ CursorNotAtLineBoundaryError,
484
+ LargeNonUtf8TextError,
485
+ TextScanBudgetExceededError,
478
486
  decodeBufferWithEncodingInfoAsync,
479
487
  getAllGeminiMdFilenames,
488
+ isUtf8CompatibleEncoding,
480
489
  isWithinRoot,
481
490
  parseLineTolerant,
482
491
  read
483
- } from "./chunk-PT722TDT.js";
492
+ } from "./chunk-DUNI4EBW.js";
484
493
  import "./chunk-VGC4I5JJ.js";
485
- import "./chunk-SGFT55XI.js";
486
- import "./chunk-Y4IHBGBP.js";
487
- import "./chunk-Y6AXW2OG.js";
488
- import "./chunk-VCPIZRYH.js";
494
+ import "./chunk-3I6DUGQD.js";
495
+ import "./chunk-7ULQIS27.js";
496
+ import "./chunk-MM7TH7ZM.js";
497
+ import "./chunk-HIVKI6O6.js";
489
498
  import "./chunk-46UV252V.js";
490
499
  import "./chunk-ZBVS26BY.js";
491
- import "./chunk-WZRWHXFE.js";
492
- import "./chunk-A3NDJ5SB.js";
493
- import "./chunk-7XATOOE7.js";
494
- import "./chunk-BGTQCTQW.js";
500
+ import "./chunk-Q3T5KA2V.js";
501
+ import "./chunk-R2XWGR75.js";
502
+ import "./chunk-HC45LTEN.js";
503
+ import "./chunk-QARJNL2V.js";
495
504
  import "./chunk-W4RQUHY3.js";
496
- import "./chunk-S7W2GKIO.js";
505
+ import "./chunk-G7XXKQYS.js";
497
506
  import {
498
507
  FatalConfigError,
499
508
  Storage,
500
509
  createDebugLogger,
501
510
  runWithoutDebugLogSession
502
- } from "./chunk-UHUSJ6X7.js";
511
+ } from "./chunk-E2BHWIDT.js";
503
512
  import "./chunk-VOQXFAY5.js";
504
513
  import "./chunk-75DOP5OR.js";
505
514
  import "./chunk-DMTGGOSA.js";
@@ -936,7 +945,9 @@ init_esbuild_shims();
936
945
  init_esbuild_shims();
937
946
  import * as path2 from "node:path";
938
947
  var MAX_READ_BYTES = 256 * 1024;
948
+ var MAX_TEXT_SCAN_BYTES = 8 * 1024 * 1024;
939
949
  var MAX_WRITE_BYTES = 5 * 1024 * 1024;
950
+ var BINARY_PROBE_BYTES = 4096;
940
951
  function shouldIgnore(absolute, boundWorkspace, ignore, kind = "file") {
941
952
  const rel = path2.relative(boundWorkspace, absolute);
942
953
  if (rel === "" || rel.startsWith("..")) return { ignored: false };
@@ -1089,6 +1100,64 @@ init_esbuild_shims();
1089
1100
  import { createHash as createHash2, randomBytes } from "node:crypto";
1090
1101
  import { constants as fsConstants, promises as fsp2 } from "node:fs";
1091
1102
  import * as path4 from "node:path";
1103
+
1104
+ // packages/cli/src/serve/fs/text-cursor.ts
1105
+ init_esbuild_shims();
1106
+ var CURSOR_VERSION = 1;
1107
+ var MAX_TEXT_CURSOR_CHARS = 1024;
1108
+ function encodeTextCursor(state) {
1109
+ return Buffer.from(
1110
+ JSON.stringify({ v: CURSOR_VERSION, ...state }),
1111
+ "utf8"
1112
+ ).toString("base64url");
1113
+ }
1114
+ __name(encodeTextCursor, "encodeTextCursor");
1115
+ function decodeTextCursor(cursor) {
1116
+ if (cursor.length === 0 || cursor.length > MAX_TEXT_CURSOR_CHARS) {
1117
+ throw new FsError(
1118
+ "parse_error",
1119
+ `cursor must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
1120
+ { hint: "pass a cursor returned by a previous read" }
1121
+ );
1122
+ }
1123
+ let parsed;
1124
+ try {
1125
+ parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
1126
+ } catch {
1127
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1128
+ hint: "pass a cursor returned by a previous read"
1129
+ });
1130
+ }
1131
+ if (typeof parsed !== "object" || parsed === null) {
1132
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1133
+ hint: "pass a cursor returned by a previous read"
1134
+ });
1135
+ }
1136
+ const raw = parsed;
1137
+ const off = raw["off"];
1138
+ const size = raw["size"];
1139
+ const dev = raw["dev"];
1140
+ const ino = raw["ino"];
1141
+ if (raw["v"] !== CURSOR_VERSION || !Number.isSafeInteger(off) || off < 0 || !Number.isSafeInteger(size) || size < 0 || typeof dev !== "string" || typeof ino !== "string") {
1142
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1143
+ hint: "pass a cursor returned by a previous read"
1144
+ });
1145
+ }
1146
+ return { off, size, dev, ino };
1147
+ }
1148
+ __name(decodeTextCursor, "decodeTextCursor");
1149
+ function assertCursorMatchesFile(cursor, stats, path14) {
1150
+ if (String(stats.dev) !== cursor.dev || String(stats.ino) !== cursor.ino || stats.size < cursor.size) {
1151
+ throw new FsError(
1152
+ "hash_mismatch",
1153
+ `cursor no longer matches the file it was issued for: ${path14}`,
1154
+ { hint: "re-read the file from the beginning to get a fresh cursor" }
1155
+ );
1156
+ }
1157
+ }
1158
+ __name(assertCursorMatchesFile, "assertCursorMatchesFile");
1159
+
1160
+ // packages/cli/src/serve/fs/workspace-file-system.ts
1092
1161
  function createWorkspaceFileSystemFactory(deps) {
1093
1162
  const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
1094
1163
  if (boundWorkspaces.length === 0) {
@@ -1227,7 +1296,19 @@ var WorkspaceFileSystemImpl = class {
1227
1296
  `limit must be a positive integer, got ${opts.limit}`
1228
1297
  );
1229
1298
  }
1230
- const snapshot = await readTextSnapshotFromResolvedFile(p, opts);
1299
+ if (opts.cursor !== void 0 && opts.line !== void 0) {
1300
+ throw new FsError(
1301
+ "parse_error",
1302
+ "cursor and line are mutually exclusive; a cursor already encodes where to resume"
1303
+ );
1304
+ }
1305
+ if (opts.maxBytes !== void 0 && (!Number.isSafeInteger(opts.maxBytes) || opts.maxBytes < 1 || opts.maxBytes > MAX_READ_BYTES)) {
1306
+ throw new FsError(
1307
+ "parse_error",
1308
+ `maxBytes must be a positive integer in [1, ${MAX_READ_BYTES}], got ${opts.maxBytes}`
1309
+ );
1310
+ }
1311
+ const snapshot = await readTextFromResolvedFile(p, opts, this.deps.lowFs);
1231
1312
  this.deps.generationGuard?.assertOpen();
1232
1313
  const ignoreVerdict = this.ignoreVerdict(p, "file");
1233
1314
  const meta = snapshot.meta;
@@ -1882,7 +1963,7 @@ function validateWriteTextAtomicOptions(opts) {
1882
1963
  }
1883
1964
  }
1884
1965
  __name(validateWriteTextAtomicOptions, "validateWriteTextAtomicOptions");
1885
- async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1966
+ async function readTextFromResolvedFile(p, opts, lowFs) {
1886
1967
  const pre = await fsp2.lstat(p);
1887
1968
  if (pre.isSymbolicLink()) {
1888
1969
  throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
@@ -1892,12 +1973,32 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1892
1973
  if (!pre.isFile()) {
1893
1974
  throw new FsError("parse_error", `path is not a regular file: ${p}`);
1894
1975
  }
1976
+ if (opts.cursor !== void 0) {
1977
+ return readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs);
1978
+ }
1979
+ const wantsWindow = opts.limit !== void 0 || opts.maxBytes !== void 0 || opts.line !== void 0;
1980
+ if (pre.size > MAX_READ_BYTES && wantsWindow) {
1981
+ return readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs);
1982
+ }
1983
+ return readTextSnapshotFromResolvedFile(p, opts, pre);
1984
+ }
1985
+ __name(readTextFromResolvedFile, "readTextFromResolvedFile");
1986
+ async function readTextSnapshotFromResolvedFile(p, opts = {}, knownPre) {
1987
+ const pre = knownPre ?? await fsp2.lstat(p);
1988
+ if (pre.isSymbolicLink()) {
1989
+ throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
1990
+ hint: "re-resolve the target file instead of reading through a link"
1991
+ });
1992
+ }
1993
+ if (!pre.isFile()) {
1994
+ throw new FsError("parse_error", `path is not a regular file: ${p}`);
1995
+ }
1895
1996
  if (pre.size > MAX_READ_BYTES) {
1896
1997
  throw new FsError(
1897
1998
  "file_too_large",
1898
1999
  `file of ${pre.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
1899
2000
  {
1900
- hint: "use readBytes for explicit byte-windowed access on large files"
2001
+ hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
1901
2002
  }
1902
2003
  );
1903
2004
  }
@@ -1914,8 +2015,10 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1914
2015
  startLineIndex,
1915
2016
  opts.limit ?? Number.POSITIVE_INFINITY
1916
2017
  );
1917
- const sizeOutcome = enforceReadSize(raw.length, opts.maxBytes);
2018
+ const maxOutputBytes = opts.maxBytes ?? MAX_READ_BYTES;
2019
+ const sizeOutcome = enforceReadSize(raw.length, maxOutputBytes);
1918
2020
  let content = sliced.content;
2021
+ let byteTruncated = false;
1919
2022
  const meta = {
1920
2023
  encoding: decoded.encoding,
1921
2024
  bom: decoded.bom,
@@ -1924,22 +2027,243 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1924
2027
  originalLineCount: sliced.originalLineCount,
1925
2028
  hash: hashBuffer(raw)
1926
2029
  };
2030
+ const output = Buffer.from(content, "utf-8");
2031
+ if (output.length > maxOutputBytes) {
2032
+ content = safeUtf8Truncate(output, maxOutputBytes).toString("utf-8");
2033
+ meta.lineEnding = detectLineEnding(content);
2034
+ meta.truncated = true;
2035
+ byteTruncated = true;
2036
+ }
1927
2037
  if (sizeOutcome.truncated) {
1928
- const buf = Buffer.from(content, "utf-8");
1929
- if (buf.length > sizeOutcome.bytesToRead) {
1930
- content = safeUtf8Truncate(buf, sizeOutcome.bytesToRead).toString(
1931
- "utf-8"
1932
- );
1933
- meta.lineEnding = detectLineEnding(content);
1934
- }
1935
2038
  meta.truncated = true;
1936
2039
  }
1937
2040
  if (opts.limit !== void 0 && Number.isFinite(opts.limit) && sliced.originalLineCount > opts.limit + startLineIndex) {
1938
2041
  meta.truncated = true;
1939
2042
  }
2043
+ const pageableLineCount = sliced.originalLineCount - (decoded.content.endsWith("\n") ? 1 : 0);
2044
+ meta.hasMore = byteTruncated || sliced.endLine < pageableLineCount;
2045
+ const bomBytes = decoded.bom ? 3 : 0;
2046
+ const decodedBytesMatchSource = isUtf8CompatibleEncoding(decoded.encoding) && Buffer.from(decoded.content, "utf-8").equals(raw.subarray(bomBytes));
2047
+ if (meta.hasMore && !byteTruncated && decodedBytesMatchSource) {
2048
+ const startByte = bomBytes + sliced.startByteOffset;
2049
+ const contentBytes = Buffer.byteLength(content, "utf-8");
2050
+ const nextOffset = startByte + contentBytes + 1;
2051
+ if (nextOffset < raw.length) {
2052
+ meta.nextCursor = encodeTextCursor({
2053
+ off: nextOffset,
2054
+ size: raw.length,
2055
+ dev: String(pre.dev),
2056
+ ino: String(pre.ino)
2057
+ });
2058
+ }
2059
+ }
1940
2060
  return { content, meta };
1941
2061
  }
1942
2062
  __name(readTextSnapshotFromResolvedFile, "readTextSnapshotFromResolvedFile");
2063
+ function assertStreamWindowStable(before, after, p, reason) {
2064
+ const beforeSize = toBigInt(before.size);
2065
+ const afterSize = toBigInt(after.size);
2066
+ if (afterSize < beforeSize || afterSize === beforeSize && (after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)) {
2067
+ throw new FsError("hash_mismatch", `${reason}: ${p}`, {
2068
+ hint: "retry after re-reading the latest file"
2069
+ });
2070
+ }
2071
+ }
2072
+ __name(assertStreamWindowStable, "assertStreamWindowStable");
2073
+ async function readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs) {
2074
+ const cursor = decodeTextCursor(opts.cursor);
2075
+ const fh = await fsp2.open(p, "r");
2076
+ let opened;
2077
+ let afterRead;
2078
+ let window;
2079
+ let primaryError;
2080
+ let hasPrimaryError = false;
2081
+ try {
2082
+ opened = await fh.stat();
2083
+ assertSameFile(pre, opened, p, "read");
2084
+ assertStreamWindowStable(pre, opened, p, "file changed before read");
2085
+ assertCursorMatchesFile(cursor, opened, p);
2086
+ try {
2087
+ const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
2088
+ if (probe.length > 0) {
2089
+ const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
2090
+ if (looksBinary(probe.subarray(0, bytesRead))) {
2091
+ throw new FsError("binary_file", `binary file: ${p}`, {
2092
+ hint: "use readBytes for binary content"
2093
+ });
2094
+ }
2095
+ }
2096
+ window = await lowFs.readTextCursorFromHandle({
2097
+ fileHandle: fh,
2098
+ startOffset: cursor.off,
2099
+ fileSize: opened.size,
2100
+ maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
2101
+ maxSnapBytes: MAX_TEXT_SCAN_BYTES,
2102
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {}
2103
+ });
2104
+ } catch (err) {
2105
+ hasPrimaryError = true;
2106
+ primaryError = err;
2107
+ }
2108
+ afterRead = await fh.stat();
2109
+ } finally {
2110
+ await fh.close();
2111
+ }
2112
+ if (opened === void 0 || afterRead === void 0) {
2113
+ throw new FsError("internal_error", `failed to stat opened file: ${p}`);
2114
+ }
2115
+ const post = await fsp2.lstat(p);
2116
+ if (post.isSymbolicLink()) {
2117
+ throw new FsError(
2118
+ "symlink_escape",
2119
+ `path was replaced with a symlink during read: ${p}`,
2120
+ { hint: "TOCTOU swap detected via post-read lstat" }
2121
+ );
2122
+ }
2123
+ assertSameFile(opened, afterRead, p, "read");
2124
+ assertStreamWindowStable(opened, afterRead, p, "file changed during read");
2125
+ assertSameFile(opened, post, p, "read");
2126
+ assertStreamWindowStable(opened, post, p, "file changed during read");
2127
+ if (hasPrimaryError) {
2128
+ if (primaryError instanceof LargeNonUtf8TextError) {
2129
+ throw new FsError("binary_file", primaryError.message, {
2130
+ cause: primaryError,
2131
+ hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
2132
+ });
2133
+ }
2134
+ if (primaryError instanceof CursorNotAtLineBoundaryError) {
2135
+ throw new FsError("parse_error", primaryError.message, {
2136
+ cause: primaryError,
2137
+ hint: "pass a cursor returned by a previous read"
2138
+ });
2139
+ }
2140
+ throw primaryError;
2141
+ }
2142
+ if (window === void 0) {
2143
+ throw new FsError(
2144
+ "internal_error",
2145
+ `cursor text read returned no result: ${p}`
2146
+ );
2147
+ }
2148
+ const meta = {
2149
+ encoding: window.encoding,
2150
+ bom: window.bom,
2151
+ lineEnding: window.lineEnding,
2152
+ sizeBytes: opened.size,
2153
+ truncated: true,
2154
+ hasMore: window.nextOffset !== void 0 || window.truncatedByBytes === true
2155
+ };
2156
+ if (window.nextOffset !== void 0) {
2157
+ meta.nextCursor = encodeTextCursor({
2158
+ off: window.nextOffset,
2159
+ size: opened.size,
2160
+ dev: String(opened.dev),
2161
+ ino: String(opened.ino)
2162
+ });
2163
+ }
2164
+ return { content: window.content, meta };
2165
+ }
2166
+ __name(readTextCursorWindowFromResolvedFile, "readTextCursorWindowFromResolvedFile");
2167
+ async function readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs) {
2168
+ const fh = await fsp2.open(p, "r");
2169
+ let opened;
2170
+ let afterRead;
2171
+ let result;
2172
+ let primaryError;
2173
+ let hasPrimaryError = false;
2174
+ try {
2175
+ opened = await fh.stat();
2176
+ assertSameFile(pre, opened, p, "read");
2177
+ assertStreamWindowStable(pre, opened, p, "file changed before read");
2178
+ try {
2179
+ const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
2180
+ if (probe.length > 0) {
2181
+ const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
2182
+ if (looksBinary(probe.subarray(0, bytesRead))) {
2183
+ throw new FsError("binary_file", `binary file: ${p}`, {
2184
+ hint: "use readBytes for binary content"
2185
+ });
2186
+ }
2187
+ }
2188
+ result = await lowFs.readTextFileFromHandle({
2189
+ fileHandle: fh,
2190
+ fileSize: opened.size,
2191
+ limit: opts.limit ?? Number.POSITIVE_INFINITY,
2192
+ line: opts.line !== void 0 ? opts.line - 1 : 0,
2193
+ maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
2194
+ maxScanBytes: MAX_TEXT_SCAN_BYTES
2195
+ });
2196
+ } catch (err) {
2197
+ hasPrimaryError = true;
2198
+ primaryError = err;
2199
+ }
2200
+ afterRead = await fh.stat();
2201
+ } finally {
2202
+ await fh.close();
2203
+ }
2204
+ if (opened === void 0 || afterRead === void 0) {
2205
+ throw new FsError("internal_error", `failed to stat opened file: ${p}`);
2206
+ }
2207
+ const post = await fsp2.lstat(p);
2208
+ if (post.isSymbolicLink()) {
2209
+ throw new FsError(
2210
+ "symlink_escape",
2211
+ `path was replaced with a symlink during read: ${p}`,
2212
+ { hint: "TOCTOU swap detected via post-read lstat" }
2213
+ );
2214
+ }
2215
+ assertSameFile(opened, afterRead, p, "read");
2216
+ assertStreamWindowStable(opened, afterRead, p, "file changed during read");
2217
+ assertSameFile(opened, post, p, "read");
2218
+ assertStreamWindowStable(opened, post, p, "file changed during read");
2219
+ if (hasPrimaryError) {
2220
+ if (primaryError instanceof LargeNonUtf8TextError) {
2221
+ throw new FsError("binary_file", primaryError.message, {
2222
+ cause: primaryError,
2223
+ hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
2224
+ });
2225
+ }
2226
+ if (primaryError instanceof TextScanBudgetExceededError) {
2227
+ throw new FsError("file_too_large", primaryError.message, {
2228
+ cause: primaryError,
2229
+ hint: `line offsets are resolved by scanning from byte 0 and stop after ${MAX_TEXT_SCAN_BYTES} bytes; page with the cursor from a shallower read to reach this offset in O(1), or use readBytes for raw bytes`
2230
+ });
2231
+ }
2232
+ throw primaryError;
2233
+ }
2234
+ if (result === void 0) {
2235
+ throw new FsError(
2236
+ "internal_error",
2237
+ `large text range read returned no result: ${p}`
2238
+ );
2239
+ }
2240
+ const content = result.content;
2241
+ const readMeta = result._meta;
2242
+ const meta = {
2243
+ encoding: readMeta?.encoding,
2244
+ bom: readMeta?.bom,
2245
+ lineEnding: readMeta?.lineEnding ?? detectLineEnding(content),
2246
+ // Size as of `open`, not as of now: it describes the snapshot the
2247
+ // returned window was cut from. A file that grew during the read
2248
+ // reports the smaller, consistent number.
2249
+ sizeBytes: opened.size,
2250
+ truncated: true,
2251
+ hasMore: readMeta?.nextByteOffset !== void 0 || readMeta?.truncatedByBytes === true
2252
+ };
2253
+ if (readMeta?.nextByteOffset !== void 0) {
2254
+ meta.nextCursor = encodeTextCursor({
2255
+ off: readMeta.nextByteOffset,
2256
+ size: opened.size,
2257
+ dev: String(opened.dev),
2258
+ ino: String(opened.ino)
2259
+ });
2260
+ }
2261
+ if (readMeta?.originalLineCountExact === true && readMeta?.originalLineCount !== void 0) {
2262
+ meta.originalLineCount = readMeta.originalLineCount;
2263
+ }
2264
+ return { content, meta };
2265
+ }
2266
+ __name(readLargeTextWindowFromResolvedFile, "readLargeTextWindowFromResolvedFile");
1943
2267
  async function readStableRegularFileBuffer(p, pre) {
1944
2268
  const fh = await fsp2.open(p, "r");
1945
2269
  let opened;
@@ -1951,7 +2275,7 @@ async function readStableRegularFileBuffer(p, pre) {
1951
2275
  "file_too_large",
1952
2276
  `file of ${opened.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
1953
2277
  {
1954
- hint: "use readBytes for explicit byte-windowed access on large files"
2278
+ hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
1955
2279
  }
1956
2280
  );
1957
2281
  }
@@ -1987,9 +2311,15 @@ function sliceDecodedText(content, startLine, limit) {
1987
2311
  const originalLineCount = lines.length;
1988
2312
  const endLine = Math.min(startLine + limit, originalLineCount);
1989
2313
  const actualStartLine = Math.min(startLine, originalLineCount);
2314
+ let startByteOffset = 0;
2315
+ for (let i = 0; i < actualStartLine; i++) {
2316
+ startByteOffset += Buffer.byteLength(lines[i], "utf-8") + 1;
2317
+ }
1990
2318
  return {
1991
2319
  content: lines.slice(actualStartLine, endLine).join("\n"),
1992
- originalLineCount
2320
+ originalLineCount,
2321
+ startByteOffset,
2322
+ endLine
1993
2323
  };
1994
2324
  }
1995
2325
  __name(sliceDecodedText, "sliceDecodedText");
@@ -2780,13 +3110,29 @@ async function handleGetFile(req, res, deps) {
2780
3110
  });
2781
3111
  return;
2782
3112
  }
3113
+ const rawCursor = req.query["cursor"];
3114
+ if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
3115
+ applyReadHeaders(res);
3116
+ res.status(400).json({
3117
+ errorKind: "parse_error",
3118
+ error: `\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
3119
+ status: 400
3120
+ });
3121
+ return;
3122
+ }
3123
+ const cursor = rawCursor;
2783
3124
  const fs6 = factory.forRequest({
2784
3125
  originatorClientId: clientId ?? void 0,
2785
3126
  route: ROUTE2
2786
3127
  });
2787
3128
  try {
2788
3129
  const resolved = await fs6.resolve(queryPath, "read");
2789
- const out = await fs6.readText(resolved, { maxBytes, line, limit });
3130
+ const out = await fs6.readText(resolved, {
3131
+ maxBytes,
3132
+ line,
3133
+ limit,
3134
+ cursor
3135
+ });
2790
3136
  const returnedBytes = Buffer.byteLength(out.content, "utf-8");
2791
3137
  applyReadHeaders(res);
2792
3138
  res.status(200).json({
@@ -2801,7 +3147,9 @@ async function handleGetFile(req, res, deps) {
2801
3147
  truncated: out.meta.truncated === true,
2802
3148
  hash: out.meta.hash,
2803
3149
  matchedIgnore: out.meta.matchedIgnore ?? null,
2804
- originalLineCount: out.meta.originalLineCount ?? null
3150
+ originalLineCount: out.meta.originalLineCount ?? null,
3151
+ nextCursor: out.meta.nextCursor ?? null,
3152
+ hasMore: out.meta.hasMore === true
2805
3153
  });
2806
3154
  } catch (err) {
2807
3155
  sendFsError(res, err, ROUTE2);
@@ -6851,18 +7199,34 @@ async function removeTasksForSessions(projectRoot, sessionIds) {
6851
7199
  __name(removeTasksForSessions, "removeTasksForSessions");
6852
7200
 
6853
7201
  // packages/cli/src/serve/server/session-archive.ts
7202
+ var DaemonDrainingError = class extends Error {
7203
+ static {
7204
+ __name(this, "DaemonDrainingError");
7205
+ }
7206
+ name = "DaemonDrainingError";
7207
+ code = "daemon_draining";
7208
+ constructor() {
7209
+ super("The daemon is draining and no longer accepts session maintenance.");
7210
+ }
7211
+ };
6854
7212
  var SessionArchiveCoordinator = class {
6855
7213
  static {
6856
7214
  __name(this, "SessionArchiveCoordinator");
6857
7215
  }
6858
7216
  exclusive = /* @__PURE__ */ new Set();
6859
7217
  shared = /* @__PURE__ */ new Map();
7218
+ maintenanceSealed = false;
7219
+ activeMaintenance = 0;
7220
+ maintenanceDrain;
6860
7221
  assertNotTransitioning(sessionId) {
6861
7222
  if (this.exclusive.has(sessionId)) {
6862
7223
  throw new SessionArchivingError(sessionId);
6863
7224
  }
6864
7225
  }
6865
7226
  async runExclusiveMany(sessionIds, fn) {
7227
+ if (this.maintenanceSealed) {
7228
+ throw new DaemonDrainingError();
7229
+ }
6866
7230
  const uniqueSessionIds = [...new Set(sessionIds)];
6867
7231
  for (const sessionId of uniqueSessionIds) {
6868
7232
  this.assertNotTransitioning(sessionId);
@@ -6873,13 +7237,33 @@ var SessionArchiveCoordinator = class {
6873
7237
  for (const sessionId of uniqueSessionIds) {
6874
7238
  this.exclusive.add(sessionId);
6875
7239
  }
7240
+ this.activeMaintenance++;
6876
7241
  try {
6877
7242
  return await fn();
6878
7243
  } finally {
6879
7244
  for (const sessionId of uniqueSessionIds) {
6880
7245
  this.exclusive.delete(sessionId);
6881
7246
  }
7247
+ this.activeMaintenance--;
7248
+ if (this.activeMaintenance === 0) {
7249
+ this.maintenanceDrain?.resolve();
7250
+ this.maintenanceDrain = void 0;
7251
+ }
7252
+ }
7253
+ }
7254
+ sealMaintenanceAndWait() {
7255
+ this.maintenanceSealed = true;
7256
+ if (this.activeMaintenance === 0) {
7257
+ return Promise.resolve();
7258
+ }
7259
+ if (!this.maintenanceDrain) {
7260
+ let resolve5;
7261
+ const promise = new Promise((done) => {
7262
+ resolve5 = done;
7263
+ });
7264
+ this.maintenanceDrain = { promise, resolve: resolve5 };
6882
7265
  }
7266
+ return this.maintenanceDrain.promise;
6883
7267
  }
6884
7268
  async runSharedMany(sessionIds, fn) {
6885
7269
  const uniqueSessionIds = [...new Set(sessionIds)];
@@ -6903,70 +7287,280 @@ var SessionArchiveCoordinator = class {
6903
7287
  }
6904
7288
  }
6905
7289
  };
7290
+ async function runWithDaemonWriterLease(params) {
7291
+ const {
7292
+ action,
7293
+ sessionId,
7294
+ service,
7295
+ mutate,
7296
+ mutationAppliedAfterError,
7297
+ afterMutationApplied
7298
+ } = params;
7299
+ let lease;
7300
+ try {
7301
+ lease = await service.acquireSessionWriterLease(sessionId, {
7302
+ processKind: "daemon",
7303
+ reclaimPolicy: "never"
7304
+ });
7305
+ } catch (error2) {
7306
+ return { mutationApplied: false, error: error2 };
7307
+ }
7308
+ let value;
7309
+ let mutationApplied = false;
7310
+ let mutationError;
7311
+ try {
7312
+ const mutation = await mutate(() => lease.assertOwnedAndUnchanged());
7313
+ value = mutation.value;
7314
+ mutationApplied = mutation.mutationApplied;
7315
+ } catch (error2) {
7316
+ mutationError = error2;
7317
+ try {
7318
+ mutationApplied = await mutationAppliedAfterError();
7319
+ } catch {
7320
+ mutationApplied = false;
7321
+ }
7322
+ }
7323
+ let maintenanceError;
7324
+ if (mutationApplied) {
7325
+ try {
7326
+ await afterMutationApplied();
7327
+ } catch (error2) {
7328
+ maintenanceError = error2;
7329
+ logSessionArchiveWarning(
7330
+ `scheduled task lifecycle update failed action=${action} workspace=${safeLogValue(
7331
+ service.getProjectRoot()
7332
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7333
+ errorMessage(error2)
7334
+ )}`
7335
+ );
7336
+ }
7337
+ }
7338
+ let releaseError;
7339
+ try {
7340
+ await lease.release();
7341
+ } catch (error2) {
7342
+ releaseError = error2;
7343
+ }
7344
+ if (releaseError !== void 0) {
7345
+ logMaintenanceLeaseReleaseFailure({
7346
+ action,
7347
+ workspace: service.getProjectRoot(),
7348
+ sessionId,
7349
+ error: releaseError,
7350
+ mutationApplied
7351
+ });
7352
+ if (mutationError !== void 0) {
7353
+ logSessionArchiveWarning(
7354
+ `session maintenance mutation also failed action=${action} workspace=${safeLogValue(
7355
+ service.getProjectRoot()
7356
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7357
+ errorMessage(mutationError)
7358
+ )}`
7359
+ );
7360
+ }
7361
+ return { mutationApplied, error: releaseError, maintenanceError };
7362
+ }
7363
+ if (mutationError !== void 0) {
7364
+ return { mutationApplied, error: mutationError, maintenanceError };
7365
+ }
7366
+ return { value, mutationApplied, maintenanceError };
7367
+ }
7368
+ __name(runWithDaemonWriterLease, "runWithDaemonWriterLease");
7369
+ function logMaintenanceLeaseReleaseFailure(params) {
7370
+ const errorKind = typeof params.error === "object" && params.error !== null && typeof params.error.errorKind === "string" ? params.error.errorKind : "unknown";
7371
+ logSessionArchiveWarning(
7372
+ `session maintenance lease release failed action=${params.action} workspace=${safeLogValue(
7373
+ params.workspace
7374
+ )} session=${safeLogValue(params.sessionId)} errorKind=${safeLogValue(
7375
+ errorKind
7376
+ )} mutationApplied=${params.mutationApplied}`
7377
+ );
7378
+ }
7379
+ __name(logMaintenanceLeaseReleaseFailure, "logMaintenanceLeaseReleaseFailure");
7380
+ async function classifySessionLocation(service, sessionId) {
7381
+ return service.getSessionLocation(sessionId);
7382
+ }
7383
+ __name(classifySessionLocation, "classifySessionLocation");
7384
+ function sessionLocationError(sessionId) {
7385
+ return new Error(`Session archive conflict: ${sessionId}`);
7386
+ }
7387
+ __name(sessionLocationError, "sessionLocationError");
7388
+ function updateScheduledTaskForMaintenance(service, sessionId, action) {
7389
+ if (action === "archive") {
7390
+ return disableTasksForSessions(service.getProjectRoot(), [sessionId]);
7391
+ }
7392
+ if (action === "unarchive") {
7393
+ return enableTasksForSessions(service.getProjectRoot(), [sessionId]);
7394
+ }
7395
+ return removeTasksForSessions(service.getProjectRoot(), [sessionId]);
7396
+ }
7397
+ __name(updateScheduledTaskForMaintenance, "updateScheduledTaskForMaintenance");
7398
+ async function deletePersistedSessionWithLease(service, sessionId) {
7399
+ const initialLocation = await classifySessionLocation(service, sessionId);
7400
+ if (initialLocation === void 0) {
7401
+ return { kind: "notFound", mutationApplied: false };
7402
+ }
7403
+ if (initialLocation === "conflict") {
7404
+ return {
7405
+ kind: "error",
7406
+ error: sessionLocationError(sessionId),
7407
+ mutationApplied: false
7408
+ };
7409
+ }
7410
+ const mutation = await runWithDaemonWriterLease({
7411
+ action: "delete",
7412
+ sessionId,
7413
+ service,
7414
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7415
+ const lockedLocation = await classifySessionLocation(service, sessionId);
7416
+ if (lockedLocation === void 0) {
7417
+ return {
7418
+ value: "notFound",
7419
+ mutationApplied: false
7420
+ };
7421
+ }
7422
+ if (lockedLocation === "conflict") {
7423
+ throw sessionLocationError(sessionId);
7424
+ }
7425
+ await assertOwnedAndUnchanged();
7426
+ const removed = await service.removeSession(sessionId);
7427
+ return {
7428
+ value: removed ? "removed" : "notFound",
7429
+ mutationApplied: removed
7430
+ };
7431
+ }, "mutate"),
7432
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === void 0, "mutationAppliedAfterError"),
7433
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "delete"), "afterMutationApplied")
7434
+ });
7435
+ if (mutation.error !== void 0) {
7436
+ return {
7437
+ kind: "error",
7438
+ error: mutation.error,
7439
+ mutationApplied: mutation.mutationApplied
7440
+ };
7441
+ }
7442
+ return {
7443
+ kind: mutation.value ?? "notFound",
7444
+ mutationApplied: mutation.mutationApplied
7445
+ };
7446
+ }
7447
+ __name(deletePersistedSessionWithLease, "deletePersistedSessionWithLease");
6906
7448
  async function deleteDaemonSessions(params) {
6907
7449
  const { sessionIds, service, bridge, coordinator, onError } = params;
6908
7450
  const uniqueSessionIds = [...new Set(sessionIds)];
6909
- const closeErrors = [];
6910
- const removed = [];
6911
- const notFound = [];
6912
- const removeErrors = [];
6913
7451
  for (const sessionId of uniqueSessionIds) {
6914
7452
  coordinator.assertNotTransitioning(sessionId);
6915
7453
  }
6916
- await Promise.all(
7454
+ const results = await Promise.all(
6917
7455
  uniqueSessionIds.map(async (sessionId) => {
6918
7456
  try {
6919
- await coordinator.runExclusiveMany([sessionId], async () => {
6920
- let shouldRemove = false;
7457
+ return await coordinator.runExclusiveMany([sessionId], async () => {
6921
7458
  try {
6922
7459
  await bridge.closeSession(sessionId);
6923
- shouldRemove = true;
6924
- } catch (closeErr) {
6925
- if (closeErr instanceof SessionNotFoundError || closeErr instanceof Error && closeErr.name === "SessionNotFoundError") {
6926
- shouldRemove = true;
6927
- } else {
6928
- const message = closeErr instanceof Error ? closeErr.message : String(closeErr);
6929
- onError?.({ phase: "close", sessionId, error: message });
6930
- closeErrors.push({ sessionId, error: message });
7460
+ } catch (error2) {
7461
+ if (isSessionNotFoundError(error2)) {
7462
+ const result2 = await deletePersistedSessionWithLease(
7463
+ service,
7464
+ sessionId
7465
+ );
7466
+ if (result2.kind === "error") {
7467
+ onError?.({
7468
+ phase: "remove",
7469
+ sessionId,
7470
+ error: errorMessage(result2.error)
7471
+ });
7472
+ }
7473
+ return result2;
6931
7474
  }
7475
+ onError?.({
7476
+ phase: "close",
7477
+ sessionId,
7478
+ error: errorMessage(error2)
7479
+ });
7480
+ return {
7481
+ kind: "error",
7482
+ error: error2,
7483
+ mutationApplied: false
7484
+ };
6932
7485
  }
6933
- if (!shouldRemove) return;
6934
- try {
6935
- if (await service.removeSession(sessionId)) {
6936
- removed.push(sessionId);
6937
- } else {
6938
- notFound.push(sessionId);
6939
- }
6940
- } catch (removeErr) {
6941
- const message = removeErr instanceof Error ? removeErr.message : String(removeErr);
6942
- onError?.({ phase: "remove", sessionId, error: message });
6943
- removeErrors.push({ sessionId, error: message });
7486
+ const result = await deletePersistedSessionWithLease(
7487
+ service,
7488
+ sessionId
7489
+ );
7490
+ if (result.kind === "error") {
7491
+ onError?.({
7492
+ phase: "remove",
7493
+ sessionId,
7494
+ error: errorMessage(result.error)
7495
+ });
6944
7496
  }
7497
+ return result;
6945
7498
  });
6946
- } catch (err) {
6947
- if (err instanceof SessionArchivingError && err.lockKind === "exclusive") {
6948
- throw err;
7499
+ } catch (error2) {
7500
+ if (error2 instanceof DaemonDrainingError) {
7501
+ throw error2;
6949
7502
  }
6950
- const message = err instanceof Error ? err.message : String(err);
6951
- onError?.({ phase: "delete", sessionId, error: message });
6952
- closeErrors.push({ sessionId, error: message });
7503
+ onError?.({
7504
+ phase: "delete",
7505
+ sessionId,
7506
+ error: errorMessage(error2)
7507
+ });
7508
+ return {
7509
+ kind: "error",
7510
+ error: error2,
7511
+ mutationApplied: false
7512
+ };
6953
7513
  }
6954
7514
  })
6955
7515
  );
6956
- await removeTasksForSessions(service.getProjectRoot(), removed).catch(
6957
- (err) => {
6958
- logSessionArchiveWarning(
6959
- `removeTasksForSessions failed for [${removed.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
6960
- );
7516
+ const removed = [];
7517
+ const notFound = [];
7518
+ const errors = [];
7519
+ for (let i = 0; i < results.length; i++) {
7520
+ const sessionId = uniqueSessionIds[i];
7521
+ const result = results[i];
7522
+ if (result.kind === "removed") {
7523
+ removed.push(sessionId);
7524
+ } else if (result.kind === "notFound") {
7525
+ notFound.push(sessionId);
7526
+ } else {
7527
+ errors.push({ sessionId, error: errorMessage(result.error) });
6961
7528
  }
6962
- );
6963
- return { removed, notFound, errors: [...closeErrors, ...removeErrors] };
7529
+ }
7530
+ return { removed, notFound, errors };
6964
7531
  }
6965
7532
  __name(deleteDaemonSessions, "deleteDaemonSessions");
6966
- async function assertSessionLoadable(workspaceCwd, sessionId) {
6967
- const location = await new SessionService(workspaceCwd).getSessionLocation(
6968
- sessionId
6969
- );
7533
+ async function deleteDaemonSessionIfOrphan(params) {
7534
+ const { sessionId, service, bridge, coordinator } = params;
7535
+ coordinator.assertNotTransitioning(sessionId);
7536
+ const result = await coordinator.runExclusiveMany([sessionId], async () => {
7537
+ let killed = false;
7538
+ try {
7539
+ killed = await bridge.killSession(sessionId, {
7540
+ requireZeroAttaches: true
7541
+ });
7542
+ } catch (error2) {
7543
+ if (!isSessionNotFoundError(error2)) throw error2;
7544
+ killed = true;
7545
+ }
7546
+ if (!killed) {
7547
+ return void 0;
7548
+ }
7549
+ return deletePersistedSessionWithLease(service, sessionId);
7550
+ });
7551
+ if (result === void 0) {
7552
+ return false;
7553
+ }
7554
+ if (result.kind === "error") {
7555
+ throw result.error;
7556
+ }
7557
+ return true;
7558
+ }
7559
+ __name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
7560
+ async function assertSessionLoadable(workspaceCwd, sessionId, runtimeBaseDir) {
7561
+ const location = await new SessionService(workspaceCwd, {
7562
+ runtimeBaseDir
7563
+ }).getSessionLocation(sessionId);
6970
7564
  if (location === "archived") {
6971
7565
  throw new SessionArchivedError(sessionId);
6972
7566
  }
@@ -6976,10 +7570,10 @@ async function assertSessionLoadable(workspaceCwd, sessionId) {
6976
7570
  return location;
6977
7571
  }
6978
7572
  __name(assertSessionLoadable, "assertSessionLoadable");
6979
- async function assertSessionArchived(workspaceCwd, sessionId) {
6980
- const location = await new SessionService(workspaceCwd).getSessionLocation(
6981
- sessionId
6982
- );
7573
+ async function assertSessionArchived(workspaceCwd, sessionId, runtimeBaseDir) {
7574
+ const location = await new SessionService(workspaceCwd, {
7575
+ runtimeBaseDir
7576
+ }).getSessionLocation(sessionId);
6983
7577
  if (location === "active") {
6984
7578
  throw new SessionNotArchivedError(sessionId);
6985
7579
  }
@@ -6995,43 +7589,6 @@ function isSessionNotFoundError(err) {
6995
7589
  return err instanceof SessionNotFoundError || err instanceof Error && err.name === "SessionNotFoundError";
6996
7590
  }
6997
7591
  __name(isSessionNotFoundError, "isSessionNotFoundError");
6998
- async function classifySessionLocations(service, sessionIds) {
6999
- const result = {
7000
- active: [],
7001
- archived: [],
7002
- notFound: [],
7003
- errors: []
7004
- };
7005
- const locationResults = await Promise.allSettled(
7006
- sessionIds.map(async (sessionId) => ({
7007
- sessionId,
7008
- location: await service.getSessionLocation(sessionId)
7009
- }))
7010
- );
7011
- for (let i = 0; i < locationResults.length; i++) {
7012
- const sessionId = sessionIds[i];
7013
- const locationResult = locationResults[i];
7014
- if (locationResult.status === "rejected") {
7015
- result.errors.push({ sessionId, error: locationResult.reason });
7016
- continue;
7017
- }
7018
- const location = locationResult.value.location;
7019
- if (location === void 0) {
7020
- result.notFound.push(sessionId);
7021
- } else if (location === "archived") {
7022
- result.archived.push(sessionId);
7023
- } else if (location === "conflict") {
7024
- result.errors.push({
7025
- sessionId,
7026
- error: new Error(`Session archive conflict: ${sessionId}`)
7027
- });
7028
- } else {
7029
- result.active.push(sessionId);
7030
- }
7031
- }
7032
- return result;
7033
- }
7034
- __name(classifySessionLocations, "classifySessionLocations");
7035
7592
  function logSessionArchiveResult(action, result) {
7036
7593
  const changedLabel = action === "archive" ? "archived" : "unarchived";
7037
7594
  const alreadyLabel = action === "archive" ? "alreadyArchived" : "alreadyActive";
@@ -7071,59 +7628,126 @@ __name(sanitizeLogLine, "sanitizeLogLine");
7071
7628
  async function archiveDaemonSessions(params) {
7072
7629
  const { sessionIds, service, bridge, coordinator } = params;
7073
7630
  const uniqueSessionIds = [...new Set(sessionIds)];
7074
- const archived = [];
7075
- const alreadyArchived = [];
7076
- const notFound = [];
7077
- const errors = [];
7078
- const initial = await classifySessionLocations(service, uniqueSessionIds);
7079
- const activeIds = initial.active;
7080
- alreadyArchived.push(...initial.archived);
7081
- notFound.push(...initial.notFound);
7082
- errors.push(...initial.errors);
7083
- if (activeIds.length > 0) {
7084
- await coordinator.runExclusiveMany(activeIds, async () => {
7085
- const locked = await classifySessionLocations(service, activeIds);
7086
- const closableIds = locked.active;
7087
- alreadyArchived.push(...locked.archived);
7088
- notFound.push(...locked.notFound);
7089
- errors.push(...locked.errors);
7090
- const closeResults = await Promise.allSettled(
7091
- closableIds.map(async (sessionId) => {
7631
+ for (const sessionId of uniqueSessionIds) {
7632
+ coordinator.assertNotTransitioning(sessionId);
7633
+ }
7634
+ const results = await Promise.all(
7635
+ uniqueSessionIds.map(async (sessionId) => {
7636
+ try {
7637
+ return await coordinator.runExclusiveMany([sessionId], async () => {
7092
7638
  try {
7093
7639
  await bridge.closeSession(sessionId, void 0, {
7094
7640
  requireAgentClose: true
7095
7641
  });
7096
- } catch (err) {
7097
- if (!isSessionNotFoundError(err)) {
7098
- throw err;
7642
+ } catch (error2) {
7643
+ if (!isSessionNotFoundError(error2)) {
7644
+ return {
7645
+ kind: "error",
7646
+ error: error2,
7647
+ mutationApplied: false
7648
+ };
7099
7649
  }
7100
7650
  }
7101
- })
7102
- );
7103
- const archiveIds = [];
7104
- for (let i = 0; i < closeResults.length; i++) {
7105
- const sessionId = closableIds[i];
7106
- const result = closeResults[i];
7107
- if (result.status === "fulfilled") {
7108
- archiveIds.push(sessionId);
7109
- } else {
7110
- errors.push({ sessionId, error: result.reason });
7111
- }
7112
- }
7113
- try {
7114
- const archiveResult = await service.archiveSessions(archiveIds, {
7115
- knownLocation: "active"
7651
+ const initialLocation = await classifySessionLocation(
7652
+ service,
7653
+ sessionId
7654
+ );
7655
+ if (initialLocation === void 0) {
7656
+ return { kind: "notFound", mutationApplied: false };
7657
+ }
7658
+ if (initialLocation === "archived") {
7659
+ return {
7660
+ kind: "alreadyArchived",
7661
+ mutationApplied: false
7662
+ };
7663
+ }
7664
+ if (initialLocation === "conflict") {
7665
+ return {
7666
+ kind: "error",
7667
+ error: sessionLocationError(sessionId),
7668
+ mutationApplied: false
7669
+ };
7670
+ }
7671
+ const mutation = await runWithDaemonWriterLease({
7672
+ action: "archive",
7673
+ sessionId,
7674
+ service,
7675
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7676
+ const lockedLocation = await classifySessionLocation(
7677
+ service,
7678
+ sessionId
7679
+ );
7680
+ if (lockedLocation === void 0) {
7681
+ return {
7682
+ value: "notFound",
7683
+ mutationApplied: false
7684
+ };
7685
+ }
7686
+ if (lockedLocation === "archived") {
7687
+ return {
7688
+ value: "alreadyArchived",
7689
+ mutationApplied: false
7690
+ };
7691
+ }
7692
+ if (lockedLocation === "conflict") {
7693
+ throw sessionLocationError(sessionId);
7694
+ }
7695
+ await assertOwnedAndUnchanged();
7696
+ const result = await service.archiveSessions([sessionId], {
7697
+ knownLocation: "active"
7698
+ });
7699
+ if (result.errors[0]) throw result.errors[0].error;
7700
+ if (result.archived.length > 0) {
7701
+ return {
7702
+ value: "archived",
7703
+ mutationApplied: true
7704
+ };
7705
+ }
7706
+ return {
7707
+ value: result.alreadyArchived.length > 0 ? "alreadyArchived" : "notFound",
7708
+ mutationApplied: false
7709
+ };
7710
+ }, "mutate"),
7711
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "archived", "mutationAppliedAfterError"),
7712
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "archive"), "afterMutationApplied")
7713
+ });
7714
+ if (mutation.error !== void 0) {
7715
+ return {
7716
+ kind: "error",
7717
+ error: mutation.error,
7718
+ mutationApplied: mutation.mutationApplied
7719
+ };
7720
+ }
7721
+ return {
7722
+ kind: mutation.value ?? "notFound",
7723
+ mutationApplied: mutation.mutationApplied
7724
+ };
7116
7725
  });
7117
- archived.push(...archiveResult.archived);
7118
- alreadyArchived.push(...archiveResult.alreadyArchived);
7119
- notFound.push(...archiveResult.notFound);
7120
- errors.push(...archiveResult.errors);
7121
- } catch (err) {
7122
- for (const sessionId of archiveIds) {
7123
- errors.push({ sessionId, error: err });
7726
+ } catch (error2) {
7727
+ if (error2 instanceof DaemonDrainingError) {
7728
+ throw error2;
7124
7729
  }
7730
+ return {
7731
+ kind: "error",
7732
+ error: error2,
7733
+ mutationApplied: false,
7734
+ maintenanceError: void 0
7735
+ };
7125
7736
  }
7126
- });
7737
+ })
7738
+ );
7739
+ const archived = [];
7740
+ const alreadyArchived = [];
7741
+ const notFound = [];
7742
+ const errors = [];
7743
+ for (let i = 0; i < results.length; i++) {
7744
+ const sessionId = uniqueSessionIds[i];
7745
+ const result = results[i];
7746
+ if (result.kind === "archived") archived.push(sessionId);
7747
+ else if (result.kind === "alreadyArchived") {
7748
+ alreadyArchived.push(sessionId);
7749
+ } else if (result.kind === "notFound") notFound.push(sessionId);
7750
+ else errors.push({ sessionId, error: result.error });
7127
7751
  }
7128
7752
  logSessionArchiveResult("archive", {
7129
7753
  requested: uniqueSessionIds,
@@ -7132,51 +7756,144 @@ async function archiveDaemonSessions(params) {
7132
7756
  notFound,
7133
7757
  errors
7134
7758
  });
7135
- await disableTasksForSessions(service.getProjectRoot(), archived).catch(
7136
- (err) => {
7137
- logSessionArchiveWarning(
7138
- `disableTasksForSessions failed for [${archived.join(", ")}]: ${err instanceof Error ? err.message : String(err)} \u2014 bound tasks may keep firing until reconciled`
7139
- );
7140
- }
7141
- );
7142
7759
  return { archived, alreadyArchived, notFound, errors };
7143
7760
  }
7144
7761
  __name(archiveDaemonSessions, "archiveDaemonSessions");
7145
7762
  async function unarchiveDaemonSessions(params) {
7146
7763
  const { sessionIds, service, coordinator } = params;
7147
7764
  const uniqueSessionIds = [...new Set(sessionIds)];
7148
- const unarchived = [];
7149
- const alreadyActive = [];
7150
- const notFound = [];
7151
- const errors = [];
7152
- const initial = await classifySessionLocations(service, uniqueSessionIds);
7153
- const archivedIds = initial.archived;
7154
- alreadyActive.push(...initial.active);
7155
- notFound.push(...initial.notFound);
7156
- errors.push(...initial.errors);
7157
- if (archivedIds.length > 0) {
7158
- await coordinator.runExclusiveMany(archivedIds, async () => {
7159
- const locked = await classifySessionLocations(service, archivedIds);
7160
- const unarchiveIds = locked.archived;
7161
- alreadyActive.push(...locked.active);
7162
- notFound.push(...locked.notFound);
7163
- errors.push(...locked.errors);
7164
- if (unarchiveIds.length > 0) {
7165
- try {
7166
- const result = await service.unarchiveSessions(unarchiveIds, {
7167
- knownLocation: "archived"
7765
+ for (const sessionId of uniqueSessionIds) {
7766
+ coordinator.assertNotTransitioning(sessionId);
7767
+ }
7768
+ const results = await Promise.all(
7769
+ uniqueSessionIds.map(async (sessionId) => {
7770
+ try {
7771
+ return await coordinator.runExclusiveMany([sessionId], async () => {
7772
+ const initialLocation = await classifySessionLocation(
7773
+ service,
7774
+ sessionId
7775
+ );
7776
+ if (initialLocation === void 0) {
7777
+ return { kind: "notFound", mutationApplied: false };
7778
+ }
7779
+ if (initialLocation === "active") {
7780
+ let maintenanceError;
7781
+ try {
7782
+ await updateScheduledTaskForMaintenance(
7783
+ service,
7784
+ sessionId,
7785
+ "unarchive"
7786
+ );
7787
+ } catch (error2) {
7788
+ maintenanceError = error2;
7789
+ logSessionArchiveWarning(
7790
+ `scheduled task lifecycle update failed action=unarchive workspace=${safeLogValue(
7791
+ service.getProjectRoot()
7792
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7793
+ errorMessage(error2)
7794
+ )}`
7795
+ );
7796
+ }
7797
+ return {
7798
+ kind: "alreadyActive",
7799
+ mutationApplied: false,
7800
+ maintenanceError
7801
+ };
7802
+ }
7803
+ if (initialLocation === "conflict") {
7804
+ return {
7805
+ kind: "error",
7806
+ error: sessionLocationError(sessionId),
7807
+ mutationApplied: false
7808
+ };
7809
+ }
7810
+ const mutation = await runWithDaemonWriterLease({
7811
+ action: "unarchive",
7812
+ sessionId,
7813
+ service,
7814
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7815
+ const lockedLocation = await classifySessionLocation(
7816
+ service,
7817
+ sessionId
7818
+ );
7819
+ if (lockedLocation === void 0) {
7820
+ return {
7821
+ value: "notFound",
7822
+ mutationApplied: false
7823
+ };
7824
+ }
7825
+ if (lockedLocation === "active") {
7826
+ return {
7827
+ value: "alreadyActive",
7828
+ mutationApplied: false
7829
+ };
7830
+ }
7831
+ if (lockedLocation === "conflict") {
7832
+ throw sessionLocationError(sessionId);
7833
+ }
7834
+ await assertOwnedAndUnchanged();
7835
+ const result = await service.unarchiveSessions([sessionId], {
7836
+ knownLocation: "archived"
7837
+ });
7838
+ if (result.errors[0]) throw result.errors[0].error;
7839
+ if (result.unarchived.length > 0) {
7840
+ return {
7841
+ value: "unarchived",
7842
+ mutationApplied: true
7843
+ };
7844
+ }
7845
+ return {
7846
+ value: result.alreadyActive.length > 0 ? "alreadyActive" : "notFound",
7847
+ mutationApplied: false
7848
+ };
7849
+ }, "mutate"),
7850
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "active", "mutationAppliedAfterError"),
7851
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(
7852
+ service,
7853
+ sessionId,
7854
+ "unarchive"
7855
+ ), "afterMutationApplied")
7168
7856
  });
7169
- unarchived.push(...result.unarchived);
7170
- alreadyActive.push(...result.alreadyActive);
7171
- notFound.push(...result.notFound);
7172
- errors.push(...result.errors);
7173
- } catch (err) {
7174
- for (const sessionId of unarchiveIds) {
7175
- errors.push({ sessionId, error: err });
7857
+ if (mutation.error !== void 0) {
7858
+ return {
7859
+ kind: "error",
7860
+ error: mutation.error,
7861
+ mutationApplied: mutation.mutationApplied
7862
+ };
7176
7863
  }
7864
+ return {
7865
+ kind: mutation.value ?? "notFound",
7866
+ mutationApplied: mutation.mutationApplied,
7867
+ maintenanceError: mutation.maintenanceError
7868
+ };
7869
+ });
7870
+ } catch (error2) {
7871
+ if (error2 instanceof DaemonDrainingError) {
7872
+ throw error2;
7177
7873
  }
7874
+ return {
7875
+ kind: "error",
7876
+ error: error2,
7877
+ mutationApplied: false,
7878
+ maintenanceError: void 0
7879
+ };
7178
7880
  }
7179
- });
7881
+ })
7882
+ );
7883
+ const unarchived = [];
7884
+ const alreadyActive = [];
7885
+ const notFound = [];
7886
+ const errors = [];
7887
+ for (let i = 0; i < results.length; i++) {
7888
+ const sessionId = uniqueSessionIds[i];
7889
+ const result = results[i];
7890
+ if (result.kind === "unarchived") unarchived.push(sessionId);
7891
+ else if (result.kind === "alreadyActive") alreadyActive.push(sessionId);
7892
+ else if (result.kind === "notFound") notFound.push(sessionId);
7893
+ else errors.push({ sessionId, error: result.error });
7894
+ if (result.maintenanceError !== void 0) {
7895
+ errors.push({ sessionId, error: result.maintenanceError });
7896
+ }
7180
7897
  }
7181
7898
  logSessionArchiveResult("unarchive", {
7182
7899
  requested: uniqueSessionIds,
@@ -7185,17 +7902,6 @@ async function unarchiveDaemonSessions(params) {
7185
7902
  notFound,
7186
7903
  errors
7187
7904
  });
7188
- const resumeSessionIds = [.../* @__PURE__ */ new Set([...unarchived, ...alreadyActive])];
7189
- try {
7190
- await enableTasksForSessions(service.getProjectRoot(), resumeSessionIds);
7191
- } catch (err) {
7192
- logSessionArchiveWarning(
7193
- `enableTasksForSessions failed for [${resumeSessionIds.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
7194
- );
7195
- for (const sessionId of resumeSessionIds) {
7196
- errors.push({ sessionId, error: err });
7197
- }
7198
- }
7199
7905
  return { unarchived, alreadyActive, notFound, errors };
7200
7906
  }
7201
7907
  __name(unarchiveDaemonSessions, "unarchiveDaemonSessions");
@@ -7596,6 +8302,13 @@ function pickSessionArtifactInput(params) {
7596
8302
  }
7597
8303
  __name(pickSessionArtifactInput, "pickSessionArtifactInput");
7598
8304
  function toRpcError(err) {
8305
+ if (err instanceof DaemonDrainingError) {
8306
+ return {
8307
+ code: RPC.INTERNAL_ERROR,
8308
+ message: err.message,
8309
+ data: { errorKind: "daemon_draining" }
8310
+ };
8311
+ }
7599
8312
  const writerError = sessionWriterRpcError(err);
7600
8313
  if (writerError) return writerError;
7601
8314
  if (err instanceof AcpParamError || err instanceof InvalidCursorError) {
@@ -7804,7 +8517,7 @@ function rpcErrorFrame(id, err) {
7804
8517
  __name(rpcErrorFrame, "rpcErrorFrame");
7805
8518
  var ACP_PROTOCOL_VERSION = 1;
7806
8519
  var AcpDispatcher = class {
7807
- constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0) {
8520
+ constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0, sessionRuntimeBaseDir = Storage.getRuntimeBaseDir()) {
7808
8521
  this.bridge = bridge;
7809
8522
  this.boundWorkspace = boundWorkspace;
7810
8523
  this.getEnv = getEnv;
@@ -7817,6 +8530,7 @@ var AcpDispatcher = class {
7817
8530
  this.archiveCoordinator = archiveCoordinator;
7818
8531
  this.isWorkspaceTrusted = isWorkspaceTrusted;
7819
8532
  this.captureGenerationAssertion = captureGenerationAssertion;
8533
+ this.sessionRuntimeBaseDir = sessionRuntimeBaseDir;
7820
8534
  this.agentManager = createDaemonSubagentManager(boundWorkspace);
7821
8535
  }
7822
8536
  static {
@@ -7824,13 +8538,15 @@ var AcpDispatcher = class {
7824
8538
  }
7825
8539
  agentManager;
7826
8540
  killOrphanSession(sessionId, removePersistedSession = false) {
7827
- void this.bridge.killSession(sessionId, { requireZeroAttaches: true }).then(async (killed) => {
7828
- if (killed && removePersistedSession) {
7829
- await new SessionService(this.boundWorkspace).removeSession(
7830
- sessionId
7831
- );
7832
- }
7833
- }).catch(
8541
+ const cleanup = removePersistedSession ? deleteDaemonSessionIfOrphan({
8542
+ sessionId,
8543
+ service: new SessionService(this.boundWorkspace, {
8544
+ runtimeBaseDir: this.sessionRuntimeBaseDir
8545
+ }),
8546
+ bridge: this.bridge,
8547
+ coordinator: this.archiveCoordinator
8548
+ }) : this.bridge.killSession(sessionId, { requireZeroAttaches: true });
8549
+ void cleanup.catch(
7834
8550
  (err) => writeStderrLine(
7835
8551
  `qwen serve: /acp orphan killSession(${logSafe(sessionId)}) failed: ${logSafe(errMsg(err))}`
7836
8552
  )
@@ -8080,6 +8796,12 @@ var AcpDispatcher = class {
8080
8796
  * (it mints the connection) and never reaches here.
8081
8797
  */
8082
8798
  async handle(conn, msg, sessionHeader, reqLoopback) {
8799
+ return Storage.runWithResolvedRuntimeBaseDir(
8800
+ this.sessionRuntimeBaseDir,
8801
+ () => this.handleInRuntime(conn, msg, sessionHeader, reqLoopback)
8802
+ );
8803
+ }
8804
+ async handleInRuntime(conn, msg, sessionHeader, reqLoopback) {
8083
8805
  const loopback = reqLoopback ?? conn.fromLoopback;
8084
8806
  if (isResponse(msg)) {
8085
8807
  try {
@@ -9926,8 +10648,26 @@ var AcpDispatcher = class {
9926
10648
  );
9927
10649
  return;
9928
10650
  }
10651
+ const rawCursor = params["cursor"];
10652
+ if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
10653
+ if (id !== void 0)
10654
+ conn.sendConn(
10655
+ error(
10656
+ id,
10657
+ RPC.INVALID_PARAMS,
10658
+ `\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`
10659
+ )
10660
+ );
10661
+ return;
10662
+ }
10663
+ const cursor = rawCursor;
9929
10664
  const resolved = await fs6.resolve(p, "read");
9930
- const out = await fs6.readText(resolved, { maxBytes, line, limit });
10665
+ const out = await fs6.readText(resolved, {
10666
+ maxBytes,
10667
+ line,
10668
+ limit,
10669
+ cursor
10670
+ });
9931
10671
  this.replyConn(conn, id, {
9932
10672
  path: p,
9933
10673
  content: out.content,
@@ -13061,7 +13801,8 @@ function mountAcpHttp(app, bridge, opts) {
13061
13801
  () => {
13062
13802
  const guard = opts.workspaceRegistry?.primaryEntry.current?.guard;
13063
13803
  return guard ? () => guard.assertOpen() : void 0;
13064
- }
13804
+ },
13805
+ opts.workspaceRegistry?.primary.sessionRuntimeBaseDir ?? Storage.getRuntimeBaseDir()
13065
13806
  );
13066
13807
  dispatcherRef.current = dispatcher;
13067
13808
  const primaryMount = {
@@ -13368,7 +14109,8 @@ function mountAcpHttp(app, bridge, opts) {
13368
14109
  () => {
13369
14110
  const guard = rt.generationGuard;
13370
14111
  return guard ? () => guard.assertOpen() : void 0;
13371
- }
14112
+ },
14113
+ rt.sessionRuntimeBaseDir
13372
14114
  );
13373
14115
  secondaryDispatcherRef.current = secondaryDispatcher;
13374
14116
  return {
@@ -16646,13 +17388,17 @@ function createExtensionsController(deps) {
16646
17388
  const startedAt = Date.now();
16647
17389
  try {
16648
17390
  runtime.workspaceService.invalidateWorkspaceSkillsStatus();
16649
- return {
16650
- status: "fulfilled",
16651
- result: await runtime.bridge.refreshExtensionsForAllSessions(
16652
- bridgeMutationEvent(event)
16653
- ),
16654
- elapsedMs: Date.now() - startedAt
16655
- };
17391
+ try {
17392
+ return {
17393
+ status: "fulfilled",
17394
+ result: await runtime.bridge.refreshExtensionsForAllSessions(
17395
+ bridgeMutationEvent(event)
17396
+ ),
17397
+ elapsedMs: Date.now() - startedAt
17398
+ };
17399
+ } finally {
17400
+ runtime.workspaceService.invalidateWorkspaceSkillsStatus();
17401
+ }
16656
17402
  } catch (reason) {
16657
17403
  return {
16658
17404
  status: "rejected",
@@ -16727,10 +17473,14 @@ function createExtensionsController(deps) {
16727
17473
  const { result, elapsedMs } = await runReconciliation(async () => {
16728
17474
  workspace.invalidateWorkspaceSkillsStatus();
16729
17475
  const startedAt = Date.now();
16730
- const result2 = await bridge.refreshExtensionsForAllSessions(
16731
- bridgeMutationEvent(event)
16732
- );
16733
- return { result: result2, elapsedMs: Date.now() - startedAt };
17476
+ try {
17477
+ const result2 = await bridge.refreshExtensionsForAllSessions(
17478
+ bridgeMutationEvent(event)
17479
+ );
17480
+ return { result: result2, elapsedMs: Date.now() - startedAt };
17481
+ } finally {
17482
+ workspace.invalidateWorkspaceSkillsStatus();
17483
+ }
16734
17484
  });
16735
17485
  const warnings = [...commitWarnings];
16736
17486
  if (result.failed > 0) {
@@ -17249,11 +17999,15 @@ function registerWorkspaceExtensionRoutes(app, deps) {
17249
17999
  async () => await Promise.allSettled(
17250
18000
  runtimes.map(async (runtime) => {
17251
18001
  runtime.workspaceService.invalidateWorkspaceSkillsStatus();
17252
- const result = await runtime.bridge.refreshExtensionsForAllSessions();
17253
- if (result.failed > 0) {
17254
- throw new Error(
17255
- `${result.failed} extension session refresh(es) failed`
17256
- );
18002
+ try {
18003
+ const result = await runtime.bridge.refreshExtensionsForAllSessions();
18004
+ if (result.failed > 0) {
18005
+ throw new Error(
18006
+ `${result.failed} extension session refresh(es) failed`
18007
+ );
18008
+ }
18009
+ } finally {
18010
+ runtime.workspaceService.invalidateWorkspaceSkillsStatus();
17257
18011
  }
17258
18012
  })
17259
18013
  )
@@ -19071,6 +19825,12 @@ var legacySessionTelemetryRoutes = [
19071
19825
  attribution: "handler_resolved",
19072
19826
  route: "POST /session/:id/fork"
19073
19827
  },
19828
+ {
19829
+ method: "POST",
19830
+ path: "/session/:id/side-task",
19831
+ attribution: "handler_resolved",
19832
+ route: "POST /session/:id/side-task"
19833
+ },
19074
19834
  {
19075
19835
  method: "POST",
19076
19836
  path: "/session/:id/cd",
@@ -21045,10 +21805,8 @@ var VirtualSubagentSessions = class {
21045
21805
  totalTokens: task.stats?.totalTokens
21046
21806
  };
21047
21807
  }
21048
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21049
- const projectDir = Storage.runWithRuntimeBaseDir(
21050
- runtimeDir,
21051
- runtime.workspaceCwd,
21808
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21809
+ runtime.sessionRuntimeBaseDir,
21052
21810
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21053
21811
  );
21054
21812
  const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
@@ -21083,10 +21841,8 @@ var VirtualSubagentSessions = class {
21083
21841
  return void 0;
21084
21842
  }
21085
21843
  async findLegacyTaskByToolCall(runtime, parentSessionId, toolCallId) {
21086
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21087
- const projectDir = Storage.runWithRuntimeBaseDir(
21088
- runtimeDir,
21089
- runtime.workspaceCwd,
21844
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21845
+ runtime.sessionRuntimeBaseDir,
21090
21846
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21091
21847
  );
21092
21848
  const parentRecords = await read(
@@ -21159,10 +21915,8 @@ var VirtualSubagentSessions = class {
21159
21915
  };
21160
21916
  }
21161
21917
  async readParentToolCallMetrics(runtime, parentSessionId, toolCallId) {
21162
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21163
- const projectDir = Storage.runWithRuntimeBaseDir(
21164
- runtimeDir,
21165
- runtime.workspaceCwd,
21918
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21919
+ runtime.sessionRuntimeBaseDir,
21166
21920
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21167
21921
  );
21168
21922
  const records = await read(
@@ -21174,7 +21928,11 @@ var VirtualSubagentSessions = class {
21174
21928
  let task = await this.findTask(
21175
21929
  runtime,
21176
21930
  parentSessionId,
21177
- (candidate) => candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
21931
+ (candidate) => (
21932
+ // /fork has no parent transcript tool call, so its task ID is the
21933
+ // stable reference used by Web Shell.
21934
+ candidate.id === toolCallId || candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
21935
+ )
21178
21936
  );
21179
21937
  const metrics = task && task.status !== "running" ? await this.readParentToolCallMetrics(
21180
21938
  runtime,
@@ -21234,6 +21992,23 @@ var VirtualSubagentSessions = class {
21234
21992
  }
21235
21993
  };
21236
21994
 
21995
+ // packages/cli/src/serve/workspace-runtime-storage.ts
21996
+ init_esbuild_shims();
21997
+ function runWithWorkspaceRuntimeStorage(runtime, fn) {
21998
+ return Storage.runWithResolvedRuntimeBaseDir(
21999
+ runtime.sessionRuntimeBaseDir,
22000
+ fn
22001
+ );
22002
+ }
22003
+ __name(runWithWorkspaceRuntimeStorage, "runWithWorkspaceRuntimeStorage");
22004
+ function createWorkspaceRuntimeSessionService(runtime, options = {}) {
22005
+ return new SessionService(runtime.workspaceCwd, {
22006
+ ...options,
22007
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir
22008
+ });
22009
+ }
22010
+ __name(createWorkspaceRuntimeSessionService, "createWorkspaceRuntimeSessionService");
22011
+
21237
22012
  // packages/cli/src/serve/routes/session.ts
21238
22013
  var GIT_RESERVED_BRANCH = "HEAD";
21239
22014
  var MAX_BRANCH_NAME_BYTES = 1e3;
@@ -21244,6 +22019,7 @@ var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exce
21244
22019
  var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
21245
22020
  var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
21246
22021
  "POST /session/:id/branch",
22022
+ "POST /session/:id/side-task",
21247
22023
  "POST /session/:id/fork",
21248
22024
  "POST /session/:id/cd"
21249
22025
  ];
@@ -21258,7 +22034,8 @@ function isReadOnlyWorkspaceInspection(runtime) {
21258
22034
  }
21259
22035
  __name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
21260
22036
  function runWorkspaceInspectionWithLogPolicy(runtime, read2) {
21261
- return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read2) : read2();
22037
+ const readInRuntime = /* @__PURE__ */ __name(() => runWithWorkspaceRuntimeStorage(runtime, read2), "readInRuntime");
22038
+ return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(readInRuntime) : readInRuntime();
21262
22039
  }
21263
22040
  __name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
21264
22041
  function requireSessionArtifactClientId(clientId, res) {
@@ -21595,9 +22372,30 @@ function registerSessionRoutes(app, deps) {
21595
22372
  }
21596
22373
  return runtime;
21597
22374
  }, "resolveRuntimeForCatalogRoute");
21598
- const hasActivePersistedSessions = /* @__PURE__ */ __name(async (workspaceCwd) => {
22375
+ const resolveLegacyPrimaryRuntimeFromParam = /* @__PURE__ */ __name((req, res) => {
22376
+ const entry = resolveWorkspaceEntryFromParam(
22377
+ workspaceRegistry,
22378
+ req,
22379
+ res,
22380
+ "id"
22381
+ );
22382
+ if (!entry) return null;
22383
+ if (!entry.primary) {
22384
+ sendWorkspaceMismatch2(res, entry.workspaceCwd);
22385
+ return null;
22386
+ }
22387
+ const runtime = entry.state === "active" ? entry.current?.runtime : void 0;
22388
+ if (!runtime) {
22389
+ sendWorkspaceRuntimeUnavailable(res, entry);
22390
+ return null;
22391
+ }
22392
+ return runtime;
22393
+ }, "resolveLegacyPrimaryRuntimeFromParam");
22394
+ const hasActivePersistedSessions = /* @__PURE__ */ __name(async (runtime) => {
21599
22395
  try {
21600
- const page = await new SessionService(workspaceCwd).listSessions({
22396
+ const page = await createWorkspaceRuntimeSessionService(
22397
+ runtime
22398
+ ).listSessions({
21601
22399
  archiveState: "active",
21602
22400
  size: 1
21603
22401
  });
@@ -21647,20 +22445,28 @@ function registerSessionRoutes(app, deps) {
21647
22445
  try {
21648
22446
  const result = await archiveCoordinator.runSharedMany(
21649
22447
  [sessionId],
21650
- async () => {
22448
+ () => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
21651
22449
  if (target.archiveState === "archived") {
21652
- await assertSessionArchived(target.workspaceCwd, sessionId);
22450
+ await assertSessionArchived(
22451
+ target.runtime.workspaceCwd,
22452
+ sessionId,
22453
+ target.runtime.sessionRuntimeBaseDir
22454
+ );
21653
22455
  } else {
21654
- await assertSessionLoadable(target.workspaceCwd, sessionId);
22456
+ await assertSessionLoadable(
22457
+ target.runtime.workspaceCwd,
22458
+ sessionId,
22459
+ target.runtime.sessionRuntimeBaseDir
22460
+ );
21655
22461
  }
21656
22462
  return exportSessionTranscript({
21657
- workspaceCwd: target.workspaceCwd,
22463
+ workspaceCwd: target.runtime.workspaceCwd,
21658
22464
  sessionId,
21659
22465
  format,
21660
22466
  archiveState: target.archiveState,
21661
22467
  config: { getChannel: /* @__PURE__ */ __name(() => "daemon", "getChannel") }
21662
22468
  });
21663
- }
22469
+ })
21664
22470
  );
21665
22471
  const filename = result.filename.replace(/["\\\r\n]/g, "_");
21666
22472
  res.status(200).set("Cache-Control", "no-store").set("X-Content-Type-Options", "nosniff").set("Content-Type", result.mimeType).set("Content-Disposition", `attachment; filename="${filename}"`).send(result.content);
@@ -21676,7 +22482,7 @@ function registerSessionRoutes(app, deps) {
21676
22482
  sendBridgeError2(res, err, {
21677
22483
  route: target.route,
21678
22484
  sessionId,
21679
- ...target.workspaceQualified ? { workspaceCwd: target.workspaceCwd } : {}
22485
+ ...target.workspaceQualified ? { workspaceCwd: target.runtime.workspaceCwd } : {}
21680
22486
  });
21681
22487
  }
21682
22488
  }, "handleSessionExport");
@@ -21861,7 +22667,8 @@ function registerSessionRoutes(app, deps) {
21861
22667
  const activeInRuntime = /* @__PURE__ */ __name(async (runtime) => {
21862
22668
  const location = await assertSessionLoadable(
21863
22669
  runtime.workspaceCwd,
21864
- sessionId
22670
+ sessionId,
22671
+ runtime.sessionRuntimeBaseDir
21865
22672
  );
21866
22673
  return location === "active";
21867
22674
  }, "activeInRuntime");
@@ -21964,19 +22771,6 @@ function registerSessionRoutes(app, deps) {
21964
22771
  sessionId: e.sessionId,
21965
22772
  error: e.error instanceof Error ? e.error.message : String(e.error)
21966
22773
  })), "serializeSessionErrors");
21967
- const resolveWorkspaceParam = /* @__PURE__ */ __name((req, res) => {
21968
- const workspaceCwd = req.params["id"] ?? "";
21969
- if (!path10.isAbsolute(workspaceCwd)) {
21970
- res.status(400).json({ error: "`:id` must decode to an absolute workspace path" });
21971
- return null;
21972
- }
21973
- const key = canonicalizeWorkspace(workspaceCwd);
21974
- if (key !== boundWorkspace) {
21975
- sendWorkspaceMismatch2(res, key);
21976
- return null;
21977
- }
21978
- return key;
21979
- }, "resolveWorkspaceParam");
21980
22774
  const withPrimaryOnlyMutableSession = /* @__PURE__ */ __name((route, handler) => {
21981
22775
  if (!isPrimaryOnlyLiveSessionRoute(route)) {
21982
22776
  throw new Error(`Unregistered primary-only session route: ${route}`);
@@ -22250,13 +23044,16 @@ function registerSessionRoutes(app, deps) {
22250
23044
  } catch (error2) {
22251
23045
  if (!session.attached) {
22252
23046
  try {
22253
- const killed = await runtime.bridge.killSession(session.sessionId, {
22254
- requireZeroAttaches: true
22255
- });
22256
- if (killed) {
22257
- await new SessionService(runtime.workspaceCwd).removeSession(
22258
- session.sessionId
22259
- );
23047
+ const removed = await runWithWorkspaceRuntimeStorage(
23048
+ runtime,
23049
+ () => deleteDaemonSessionIfOrphan({
23050
+ sessionId: session.sessionId,
23051
+ service: createWorkspaceRuntimeSessionService(runtime),
23052
+ bridge: runtime.bridge,
23053
+ coordinator: archiveCoordinator
23054
+ })
23055
+ );
23056
+ if (removed) {
22260
23057
  if (worktreeMeta) {
22261
23058
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22262
23059
  });
@@ -22288,13 +23085,16 @@ function registerSessionRoutes(app, deps) {
22288
23085
  }
22289
23086
  if (!session.attached) {
22290
23087
  try {
22291
- const killed = await runtime.bridge.killSession(session.sessionId, {
22292
- requireZeroAttaches: true
22293
- });
22294
- if (killed) {
22295
- await new SessionService(runtime.workspaceCwd).removeSession(
22296
- session.sessionId
22297
- );
23088
+ const removed = await runWithWorkspaceRuntimeStorage(
23089
+ runtime,
23090
+ () => deleteDaemonSessionIfOrphan({
23091
+ sessionId: session.sessionId,
23092
+ service: createWorkspaceRuntimeSessionService(runtime),
23093
+ bridge: runtime.bridge,
23094
+ coordinator: archiveCoordinator
23095
+ })
23096
+ );
23097
+ if (removed) {
22298
23098
  if (worktreeMeta) {
22299
23099
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22300
23100
  });
@@ -22353,9 +23153,9 @@ function registerSessionRoutes(app, deps) {
22353
23153
  ).catch(() => {
22354
23154
  });
22355
23155
  await writeWorktreeSession(
22356
- new SessionService(workspaceCwd).getWorktreeSessionPath(
22357
- session.sessionId
22358
- ),
23156
+ createWorkspaceRuntimeSessionService(
23157
+ runtime
23158
+ ).getWorktreeSessionPath(session.sessionId),
22359
23159
  {
22360
23160
  slug: worktreeMeta.slug,
22361
23161
  worktreePath: worktreeMeta.path,
@@ -22373,11 +23173,15 @@ function registerSessionRoutes(app, deps) {
22373
23173
  error: cdErr instanceof Error ? cdErr.message : String(cdErr)
22374
23174
  });
22375
23175
  }
22376
- const killed = await runtime.bridge.killSession(session.sessionId, { requireZeroAttaches: true }).catch(() => false);
22377
- if (killed) {
22378
- await new SessionService(workspaceCwd).removeSession(session.sessionId).catch(() => {
22379
- });
22380
- }
23176
+ await runWithWorkspaceRuntimeStorage(
23177
+ runtime,
23178
+ () => deleteDaemonSessionIfOrphan({
23179
+ sessionId: session.sessionId,
23180
+ service: createWorkspaceRuntimeSessionService(runtime),
23181
+ bridge: runtime.bridge,
23182
+ coordinator: archiveCoordinator
23183
+ })
23184
+ ).catch(() => false);
22381
23185
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22382
23186
  });
22383
23187
  res.status(500).json({
@@ -22502,9 +23306,13 @@ function registerSessionRoutes(app, deps) {
22502
23306
  const session = await archiveCoordinator.runSharedMany(
22503
23307
  [sessionId],
22504
23308
  async () => {
22505
- await assertSessionLoadable(workspaceCwd, sessionId);
22506
- const metadata = await new SessionService(
22507
- workspaceCwd
23309
+ await assertSessionLoadable(
23310
+ workspaceCwd,
23311
+ sessionId,
23312
+ runtime.sessionRuntimeBaseDir
23313
+ );
23314
+ const metadata = await createWorkspaceRuntimeSessionService(
23315
+ runtime
22508
23316
  ).readCreationMetadata(sessionId);
22509
23317
  runtime.generationGuard?.assertOpen();
22510
23318
  return action === "load" ? await runtime.bridge.loadSession({
@@ -22554,7 +23362,9 @@ function registerSessionRoutes(app, deps) {
22554
23362
  }
22555
23363
  if (!session.worktree) {
22556
23364
  const sidecar = await readWorktreeSession(
22557
- new SessionService(workspaceCwd).getWorktreeSessionPath(sessionId)
23365
+ createWorkspaceRuntimeSessionService(
23366
+ runtime
23367
+ ).getWorktreeSessionPath(sessionId)
22558
23368
  ).catch(() => null);
22559
23369
  if (sidecar) {
22560
23370
  let realTarget;
@@ -22757,13 +23567,72 @@ function registerSessionRoutes(app, deps) {
22757
23567
  { name },
22758
23568
  { clientId }
22759
23569
  );
23570
+ try {
23571
+ runtime.generationGuard?.assertOpen();
23572
+ } catch (error2) {
23573
+ if (!result.attached) {
23574
+ await runWithWorkspaceRuntimeStorage(
23575
+ runtime,
23576
+ () => deleteDaemonSessionIfOrphan({
23577
+ sessionId: result.sessionId,
23578
+ service: createWorkspaceRuntimeSessionService(runtime),
23579
+ bridge: runtime.bridge,
23580
+ coordinator: archiveCoordinator
23581
+ })
23582
+ ).catch(() => false);
23583
+ } else {
23584
+ await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
23585
+ });
23586
+ }
23587
+ throw error2;
23588
+ }
23589
+ if (!res.writable) {
23590
+ if (!result.attached) {
23591
+ void runWithWorkspaceRuntimeStorage(
23592
+ runtime,
23593
+ () => deleteDaemonSessionIfOrphan({
23594
+ sessionId: result.sessionId,
23595
+ service: createWorkspaceRuntimeSessionService(runtime),
23596
+ bridge: runtime.bridge,
23597
+ coordinator: archiveCoordinator
23598
+ })
23599
+ ).catch(() => {
23600
+ });
23601
+ } else {
23602
+ runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
23603
+ });
23604
+ }
23605
+ return;
23606
+ }
23607
+ res.status(201).json(result);
23608
+ }
23609
+ )
23610
+ );
23611
+ app.post(
23612
+ "/session/:id/side-task",
23613
+ mutate(),
23614
+ withPrimaryOnlyMutableSession(
23615
+ "POST /session/:id/side-task",
23616
+ async (req, res, sessionId, runtime) => {
23617
+ const body = safeBody(req);
23618
+ let name = typeof body?.["name"] === "string" ? body["name"] : void 0;
23619
+ if (name) {
23620
+ name = Array.from(name.replace(/[\x00-\x1F\x7F-\x9F]/g, "")).slice(0, 200).join("");
23621
+ }
23622
+ const clientId = parseClientIdHeader(req, res);
23623
+ if (clientId === null) return;
23624
+ const result = await runtime.bridge.createSideTaskSession(
23625
+ sessionId,
23626
+ { name },
23627
+ { clientId }
23628
+ );
22760
23629
  try {
22761
23630
  runtime.generationGuard?.assertOpen();
22762
23631
  } catch (error2) {
22763
23632
  if (!result.attached) {
22764
23633
  const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
22765
23634
  if (killed) {
22766
- await new SessionService(runtime.workspaceCwd).removeSession(result.sessionId).catch(() => {
23635
+ await createWorkspaceRuntimeSessionService(runtime).removeSession(result.sessionId).catch(() => {
22767
23636
  });
22768
23637
  }
22769
23638
  } else {
@@ -22774,7 +23643,12 @@ function registerSessionRoutes(app, deps) {
22774
23643
  }
22775
23644
  if (!res.writable) {
22776
23645
  if (!result.attached) {
22777
- runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => {
23646
+ runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
23647
+ if (!killed) return void 0;
23648
+ return createWorkspaceRuntimeSessionService(
23649
+ runtime
23650
+ ).removeSession(result.sessionId);
23651
+ }).catch(() => {
22778
23652
  });
22779
23653
  } else {
22780
23654
  runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
@@ -22870,7 +23744,7 @@ function registerSessionRoutes(app, deps) {
22870
23744
  app.get("/session/:id/export", async (req, res) => {
22871
23745
  await handleSessionExport(req, res, {
22872
23746
  route: "GET /session/:id/export",
22873
- workspaceCwd: boundWorkspace
23747
+ runtime: workspaceRegistry.primary
22874
23748
  });
22875
23749
  });
22876
23750
  app.get("/workspaces/:workspace/session/:id/export", async (req, res) => {
@@ -22879,7 +23753,7 @@ function registerSessionRoutes(app, deps) {
22879
23753
  if (!runtime) return;
22880
23754
  await handleSessionExport(req, res, {
22881
23755
  route,
22882
- workspaceCwd: runtime.workspaceCwd,
23756
+ runtime,
22883
23757
  workspaceQualified: true
22884
23758
  });
22885
23759
  });
@@ -22891,7 +23765,7 @@ function registerSessionRoutes(app, deps) {
22891
23765
  if (!runtime) return;
22892
23766
  await handleSessionExport(req, res, {
22893
23767
  route,
22894
- workspaceCwd: runtime.workspaceCwd,
23768
+ runtime,
22895
23769
  workspaceQualified: true,
22896
23770
  archiveState: "archived"
22897
23771
  });
@@ -22988,67 +23862,74 @@ function registerSessionRoutes(app, deps) {
22988
23862
  }
22989
23863
  try {
22990
23864
  const result = await runWithoutDebugLogSession(
22991
- () => archiveCoordinator.runSharedMany([sessionId], async () => {
22992
- const service = new SessionService(runtime.workspaceCwd);
22993
- if (cursor === void 0) {
22994
- await assertSessionLoadable(runtime.workspaceCwd, sessionId);
22995
- }
22996
- const codec = getTranscriptCursorCodec(runtime);
22997
- const reader = new SessionTranscriptReader(
22998
- runtime.workspaceCwd,
22999
- codec
23000
- );
23001
- let page;
23002
- try {
23003
- page = await reader.readPage(sessionId, {
23004
- ...limit !== void 0 ? { limit } : {},
23005
- ...cursor !== void 0 ? { cursor } : {},
23006
- ...beforeRecordId !== void 0 ? { beforeRecordId } : {},
23007
- maxBytes: SESSION_TRANSCRIPT_MAX_PAGE_BYTES
23008
- });
23009
- } catch (error2) {
23010
- if (error2.code !== "ENOENT") {
23011
- throw error2;
23012
- }
23013
- if (cursor !== void 0) {
23014
- throw new SessionTranscriptSnapshotUnavailableError(sessionId);
23865
+ () => archiveCoordinator.runSharedMany(
23866
+ [sessionId],
23867
+ () => runWithWorkspaceRuntimeStorage(runtime, async () => {
23868
+ const service = createWorkspaceRuntimeSessionService(runtime);
23869
+ if (cursor === void 0) {
23870
+ await assertSessionLoadable(
23871
+ runtime.workspaceCwd,
23872
+ sessionId,
23873
+ runtime.sessionRuntimeBaseDir
23874
+ );
23015
23875
  }
23016
- const location = await service.getSessionLocation(sessionId);
23017
- if (location === "archived") {
23018
- throw new SessionArchivedError(sessionId);
23876
+ const codec = getTranscriptCursorCodec(runtime);
23877
+ const reader = new SessionTranscriptReader(
23878
+ runtime.workspaceCwd,
23879
+ codec
23880
+ );
23881
+ let page;
23882
+ try {
23883
+ page = await reader.readPage(sessionId, {
23884
+ ...limit !== void 0 ? { limit } : {},
23885
+ ...cursor !== void 0 ? { cursor } : {},
23886
+ ...beforeRecordId !== void 0 ? { beforeRecordId } : {},
23887
+ maxBytes: SESSION_TRANSCRIPT_MAX_PAGE_BYTES
23888
+ });
23889
+ } catch (error2) {
23890
+ if (error2.code !== "ENOENT") {
23891
+ throw error2;
23892
+ }
23893
+ if (cursor !== void 0) {
23894
+ throw new SessionTranscriptSnapshotUnavailableError(sessionId);
23895
+ }
23896
+ const location = await service.getSessionLocation(sessionId);
23897
+ if (location === "archived") {
23898
+ throw new SessionArchivedError(sessionId);
23899
+ }
23900
+ if (location === "conflict") {
23901
+ throw new SessionConflictError(sessionId);
23902
+ }
23903
+ throw new SessionNotFoundError(sessionId);
23019
23904
  }
23020
- if (location === "conflict") {
23021
- throw new SessionConflictError(sessionId);
23905
+ if (page.records.some((record) => record.sessionId !== sessionId)) {
23906
+ throw new SessionTranscriptSnapshotUnavailableError(sessionId);
23022
23907
  }
23023
- throw new SessionNotFoundError(sessionId);
23024
- }
23025
- if (page.records.some((record) => record.sessionId !== sessionId)) {
23026
- throw new SessionTranscriptSnapshotUnavailableError(sessionId);
23027
- }
23028
- const replay = await replayTranscriptRecordPage({
23029
- sessionId,
23030
- page,
23031
- encodeCursor: /* @__PURE__ */ __name((state) => codec.encode(state), "encodeCursor")
23032
- });
23033
- const cursorTooLarge = replay.nextCursor !== void 0 && Buffer.byteLength(replay.nextCursor) > WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES;
23034
- return {
23035
- v: 1,
23036
- sessionId,
23037
- events: replay.updates.map((update) => ({
23908
+ const replay = await replayTranscriptRecordPage({
23909
+ sessionId,
23910
+ page,
23911
+ encodeCursor: /* @__PURE__ */ __name((state) => codec.encode(state), "encodeCursor")
23912
+ });
23913
+ const cursorTooLarge = replay.nextCursor !== void 0 && Buffer.byteLength(replay.nextCursor) > WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES;
23914
+ return {
23038
23915
  v: 1,
23039
- type: "session_update",
23040
- data: update
23041
- })),
23042
- ...replay.nextCursor && !cursorTooLarge ? { nextCursor: replay.nextCursor } : {},
23043
- hasMore: cursorTooLarge ? false : replay.hasMore,
23044
- startTime: replay.startTime,
23045
- lastUpdated: replay.lastUpdated,
23046
- ...replay.partial || cursorTooLarge ? {
23047
- partial: true,
23048
- replayError: cursorTooLarge ? TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR : replay.replayError
23049
- } : {}
23050
- };
23051
- })
23916
+ sessionId,
23917
+ events: replay.updates.map((update) => ({
23918
+ v: 1,
23919
+ type: "session_update",
23920
+ data: update
23921
+ })),
23922
+ ...replay.nextCursor && !cursorTooLarge ? { nextCursor: replay.nextCursor } : {},
23923
+ hasMore: cursorTooLarge ? false : replay.hasMore,
23924
+ startTime: replay.startTime,
23925
+ lastUpdated: replay.lastUpdated,
23926
+ ...replay.partial || cursorTooLarge ? {
23927
+ partial: true,
23928
+ replayError: cursorTooLarge ? TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR : replay.replayError
23929
+ } : {}
23930
+ };
23931
+ })
23932
+ )
23052
23933
  );
23053
23934
  const serialized = serializeWorkspaceTranscriptResponse(
23054
23935
  result,
@@ -23701,18 +24582,22 @@ function registerSessionRoutes(app, deps) {
23701
24582
  const uniqueIds = parseSessionIdsBody(req, res);
23702
24583
  if (uniqueIds === void 0) return;
23703
24584
  try {
23704
- const service = new SessionService(boundWorkspace);
23705
- const result = await deleteDaemonSessions({
23706
- sessionIds: uniqueIds,
23707
- service,
23708
- bridge,
23709
- coordinator: archiveCoordinator,
23710
- onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
23711
- writeStderrLine(
23712
- `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
23713
- );
23714
- }, "onError")
23715
- });
24585
+ const runtime = workspaceRegistry.primary;
24586
+ const service = createWorkspaceRuntimeSessionService(runtime);
24587
+ const result = await runWithWorkspaceRuntimeStorage(
24588
+ runtime,
24589
+ () => deleteDaemonSessions({
24590
+ sessionIds: uniqueIds,
24591
+ service,
24592
+ bridge,
24593
+ coordinator: archiveCoordinator,
24594
+ onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
24595
+ writeStderrLine(
24596
+ `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
24597
+ );
24598
+ }, "onError")
24599
+ })
24600
+ );
23716
24601
  for (const removedId of result.removed) {
23717
24602
  clearBranchSessionEntry(removedId);
23718
24603
  }
@@ -23724,16 +24609,20 @@ function registerSessionRoutes(app, deps) {
23724
24609
  app.post("/sessions/archive", mutate(), async (req, res) => {
23725
24610
  const uniqueIds = parseSessionIdsBody(req, res);
23726
24611
  if (uniqueIds === void 0) return;
23727
- const service = new SessionService(boundWorkspace, {
24612
+ const runtime = workspaceRegistry.primary;
24613
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23728
24614
  onWarning: logSessionArchiveWarning
23729
24615
  });
23730
24616
  try {
23731
- const result = await archiveDaemonSessions({
23732
- sessionIds: uniqueIds,
23733
- service,
23734
- bridge,
23735
- coordinator: archiveCoordinator
23736
- });
24617
+ const result = await runWithWorkspaceRuntimeStorage(
24618
+ runtime,
24619
+ () => archiveDaemonSessions({
24620
+ sessionIds: uniqueIds,
24621
+ service,
24622
+ bridge,
24623
+ coordinator: archiveCoordinator
24624
+ })
24625
+ );
23737
24626
  res.status(200).json({
23738
24627
  archived: result.archived,
23739
24628
  alreadyArchived: result.alreadyArchived,
@@ -23747,15 +24636,19 @@ function registerSessionRoutes(app, deps) {
23747
24636
  app.post("/sessions/unarchive", mutate(), async (req, res) => {
23748
24637
  const uniqueIds = parseSessionIdsBody(req, res);
23749
24638
  if (uniqueIds === void 0) return;
23750
- const service = new SessionService(boundWorkspace, {
24639
+ const runtime = workspaceRegistry.primary;
24640
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23751
24641
  onWarning: logSessionArchiveWarning
23752
24642
  });
23753
24643
  try {
23754
- const result = await unarchiveDaemonSessions({
23755
- sessionIds: uniqueIds,
23756
- service,
23757
- coordinator: archiveCoordinator
23758
- });
24644
+ const result = await runWithWorkspaceRuntimeStorage(
24645
+ runtime,
24646
+ () => unarchiveDaemonSessions({
24647
+ sessionIds: uniqueIds,
24648
+ service,
24649
+ coordinator: archiveCoordinator
24650
+ })
24651
+ );
23759
24652
  res.status(200).json({
23760
24653
  unarchived: result.unarchived,
23761
24654
  alreadyActive: result.alreadyActive,
@@ -23778,18 +24671,21 @@ function registerSessionRoutes(app, deps) {
23778
24671
  const uniqueIds = parseSessionIdsBody(req, res);
23779
24672
  if (uniqueIds === void 0) return;
23780
24673
  try {
23781
- const service = new SessionService(runtime.workspaceCwd);
23782
- const result = await deleteDaemonSessions({
23783
- sessionIds: uniqueIds,
23784
- service,
23785
- bridge: runtime.bridge,
23786
- coordinator: archiveCoordinator,
23787
- onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
23788
- writeStderrLine(
23789
- `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
23790
- );
23791
- }, "onError")
23792
- });
24674
+ const service = createWorkspaceRuntimeSessionService(runtime);
24675
+ const result = await runWithWorkspaceRuntimeStorage(
24676
+ runtime,
24677
+ () => deleteDaemonSessions({
24678
+ sessionIds: uniqueIds,
24679
+ service,
24680
+ bridge: runtime.bridge,
24681
+ coordinator: archiveCoordinator,
24682
+ onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
24683
+ writeStderrLine(
24684
+ `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
24685
+ );
24686
+ }, "onError")
24687
+ })
24688
+ );
23793
24689
  for (const removedId of result.removed) {
23794
24690
  clearBranchSessionEntry(removedId);
23795
24691
  }
@@ -23808,16 +24704,19 @@ function registerSessionRoutes(app, deps) {
23808
24704
  if (!runtime) return;
23809
24705
  const uniqueIds = parseSessionIdsBody(req, res);
23810
24706
  if (uniqueIds === void 0) return;
23811
- const service = new SessionService(runtime.workspaceCwd, {
24707
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23812
24708
  onWarning: logSessionArchiveWarning
23813
24709
  });
23814
24710
  try {
23815
- const result = await archiveDaemonSessions({
23816
- sessionIds: uniqueIds,
23817
- service,
23818
- bridge: runtime.bridge,
23819
- coordinator: archiveCoordinator
23820
- });
24711
+ const result = await runWithWorkspaceRuntimeStorage(
24712
+ runtime,
24713
+ () => archiveDaemonSessions({
24714
+ sessionIds: uniqueIds,
24715
+ service,
24716
+ bridge: runtime.bridge,
24717
+ coordinator: archiveCoordinator
24718
+ })
24719
+ );
23821
24720
  res.status(200).json({
23822
24721
  archived: result.archived,
23823
24722
  alreadyArchived: result.alreadyArchived,
@@ -23838,15 +24737,18 @@ function registerSessionRoutes(app, deps) {
23838
24737
  if (!runtime) return;
23839
24738
  const uniqueIds = parseSessionIdsBody(req, res);
23840
24739
  if (uniqueIds === void 0) return;
23841
- const service = new SessionService(runtime.workspaceCwd, {
24740
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23842
24741
  onWarning: logSessionArchiveWarning
23843
24742
  });
23844
24743
  try {
23845
- const result = await unarchiveDaemonSessions({
23846
- sessionIds: uniqueIds,
23847
- service,
23848
- coordinator: archiveCoordinator
23849
- });
24744
+ const result = await runWithWorkspaceRuntimeStorage(
24745
+ runtime,
24746
+ () => unarchiveDaemonSessions({
24747
+ sessionIds: uniqueIds,
24748
+ service,
24749
+ coordinator: archiveCoordinator
24750
+ })
24751
+ );
23850
24752
  res.status(200).json({
23851
24753
  unarchived: result.unarchived,
23852
24754
  alreadyActive: result.alreadyActive,
@@ -23890,74 +24792,80 @@ function registerSessionRoutes(app, deps) {
23890
24792
  const sessionId = requireSessionId(req, res);
23891
24793
  if (sessionId === null) return;
23892
24794
  try {
23893
- await archiveCoordinator.runSharedMany([sessionId], async () => {
23894
- const sessionService = new SessionService(target.workspaceCwd);
23895
- let exists = await sessionService.sessionExistsInAnyState(sessionId);
23896
- if (!exists) {
23897
- try {
23898
- const summary = target.bridge.getSessionSummary(sessionId);
23899
- exists = summary.workspaceCwd === target.workspaceCwd;
23900
- } catch {
23901
- exists = false;
24795
+ await archiveCoordinator.runSharedMany(
24796
+ [sessionId],
24797
+ () => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
24798
+ const sessionService = createWorkspaceRuntimeSessionService(
24799
+ target.runtime
24800
+ );
24801
+ let exists = await sessionService.sessionExistsInAnyState(sessionId);
24802
+ if (!exists) {
24803
+ try {
24804
+ const summary = target.runtime.bridge.getSessionSummary(sessionId);
24805
+ exists = summary.workspaceCwd === target.runtime.workspaceCwd;
24806
+ } catch {
24807
+ exists = false;
24808
+ }
23902
24809
  }
23903
- }
23904
- if (!exists) {
23905
- res.status(404).json({
23906
- error: `No session with id "${sessionId}"`,
23907
- sessionId
23908
- });
23909
- return;
23910
- }
23911
- const body = safeBody(req);
23912
- const rawIsPinned = body["isPinned"];
23913
- if (rawIsPinned !== void 0 && typeof rawIsPinned !== "boolean") {
23914
- res.status(400).json({
23915
- error: "`isPinned` must be a boolean",
23916
- code: "invalid_session_organization",
23917
- field: "isPinned"
23918
- });
23919
- return;
23920
- }
23921
- const rawGroupId = body["groupId"];
23922
- if (rawGroupId !== void 0 && rawGroupId !== null && typeof rawGroupId !== "string") {
23923
- res.status(400).json({
23924
- error: "`groupId` must be a string or null",
23925
- code: "invalid_session_organization",
23926
- field: "groupId"
23927
- });
23928
- return;
23929
- }
23930
- const rawColor = body["color"];
23931
- if (rawColor !== void 0 && rawColor !== null && (typeof rawColor !== "string" || !GROUP_COLOR_OPTIONS.includes(rawColor))) {
23932
- res.status(400).json({
23933
- error: "`color` must be a supported color or null",
23934
- code: "invalid_session_organization",
23935
- field: "color"
24810
+ if (!exists) {
24811
+ res.status(404).json({
24812
+ error: `No session with id "${sessionId}"`,
24813
+ sessionId
24814
+ });
24815
+ return;
24816
+ }
24817
+ const body = safeBody(req);
24818
+ const rawIsPinned = body["isPinned"];
24819
+ if (rawIsPinned !== void 0 && typeof rawIsPinned !== "boolean") {
24820
+ res.status(400).json({
24821
+ error: "`isPinned` must be a boolean",
24822
+ code: "invalid_session_organization",
24823
+ field: "isPinned"
24824
+ });
24825
+ return;
24826
+ }
24827
+ const rawGroupId = body["groupId"];
24828
+ if (rawGroupId !== void 0 && rawGroupId !== null && typeof rawGroupId !== "string") {
24829
+ res.status(400).json({
24830
+ error: "`groupId` must be a string or null",
24831
+ code: "invalid_session_organization",
24832
+ field: "groupId"
24833
+ });
24834
+ return;
24835
+ }
24836
+ const rawColor = body["color"];
24837
+ if (rawColor !== void 0 && rawColor !== null && (typeof rawColor !== "string" || !GROUP_COLOR_OPTIONS.includes(
24838
+ rawColor
24839
+ ))) {
24840
+ res.status(400).json({
24841
+ error: "`color` must be a supported color or null",
24842
+ code: "invalid_session_organization",
24843
+ field: "color"
24844
+ });
24845
+ return;
24846
+ }
24847
+ const organization = await createSessionOrganizationService(
24848
+ target.runtime.workspaceCwd
24849
+ ).updateSessionOrganization(sessionId, {
24850
+ ...rawIsPinned !== void 0 ? { isPinned: rawIsPinned } : {},
24851
+ ...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
24852
+ ...rawColor !== void 0 ? { color: rawColor } : {}
23936
24853
  });
23937
- return;
23938
- }
23939
- const organization = await createSessionOrganizationService(
23940
- target.workspaceCwd
23941
- ).updateSessionOrganization(sessionId, {
23942
- ...rawIsPinned !== void 0 ? { isPinned: rawIsPinned } : {},
23943
- ...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
23944
- ...rawColor !== void 0 ? { color: rawColor } : {}
23945
- });
23946
- res.status(200).json({ sessionId, ...organization });
23947
- });
24854
+ res.status(200).json({ sessionId, ...organization });
24855
+ })
24856
+ );
23948
24857
  } catch (err) {
23949
24858
  if (sendSessionOrganizationError(res, err)) return;
23950
24859
  sendBridgeError2(res, err, {
23951
24860
  route: target.route,
23952
24861
  sessionId,
23953
- workspaceCwd: target.workspaceCwd
24862
+ workspaceCwd: target.runtime.workspaceCwd
23954
24863
  });
23955
24864
  }
23956
24865
  }, "handleSessionOrganizationUpdate");
23957
24866
  app.patch("/session/:id/organization", mutate(), async (req, res) => {
23958
24867
  await handleSessionOrganizationUpdate(req, res, {
23959
- workspaceCwd: boundWorkspace,
23960
- bridge,
24868
+ runtime: workspaceRegistry.primary,
23961
24869
  route: "PATCH /session/:id/organization"
23962
24870
  });
23963
24871
  });
@@ -23969,8 +24877,7 @@ function registerSessionRoutes(app, deps) {
23969
24877
  const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
23970
24878
  if (!runtime) return;
23971
24879
  await handleSessionOrganizationUpdate(req, res, {
23972
- workspaceCwd: runtime.workspaceCwd,
23973
- bridge: runtime.bridge,
24880
+ runtime,
23974
24881
  route
23975
24882
  });
23976
24883
  }
@@ -23992,14 +24899,17 @@ function registerSessionRoutes(app, deps) {
23992
24899
  }
23993
24900
  });
23994
24901
  app.post("/workspace/:id/session-groups", mutate(), async (req, res) => {
23995
- const key = resolveWorkspaceParam(req, res);
23996
- if (key === null) return;
24902
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
24903
+ if (runtime === null) return;
23997
24904
  const body = safeBody(req);
23998
24905
  try {
23999
- const group = await createSessionOrganizationService(key).createGroup({
24000
- name: body["name"],
24001
- color: body["color"]
24002
- });
24906
+ const group = await runWithWorkspaceRuntimeStorage(
24907
+ runtime,
24908
+ () => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
24909
+ name: body["name"],
24910
+ color: body["color"]
24911
+ })
24912
+ );
24003
24913
  res.status(201).json({ group });
24004
24914
  } catch (err) {
24005
24915
  if (sendSessionOrganizationError(res, err)) return;
@@ -24012,17 +24922,20 @@ function registerSessionRoutes(app, deps) {
24012
24922
  "/workspace/:id/session-groups/:groupId",
24013
24923
  mutate(),
24014
24924
  async (req, res) => {
24015
- const key = resolveWorkspaceParam(req, res);
24016
- if (key === null) return;
24925
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
24926
+ if (runtime === null) return;
24017
24927
  const body = safeBody(req);
24018
24928
  try {
24019
- const group = await createSessionOrganizationService(key).updateGroup(
24020
- req.params["groupId"] ?? "",
24021
- {
24022
- ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
24023
- ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
24024
- ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
24025
- }
24929
+ const group = await runWithWorkspaceRuntimeStorage(
24930
+ runtime,
24931
+ () => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
24932
+ req.params["groupId"] ?? "",
24933
+ {
24934
+ ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
24935
+ ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
24936
+ ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
24937
+ }
24938
+ )
24026
24939
  );
24027
24940
  res.status(200).json({ group });
24028
24941
  } catch (err) {
@@ -24037,11 +24950,14 @@ function registerSessionRoutes(app, deps) {
24037
24950
  "/workspace/:id/session-groups/:groupId",
24038
24951
  mutate(),
24039
24952
  async (req, res) => {
24040
- const key = resolveWorkspaceParam(req, res);
24041
- if (key === null) return;
24953
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
24954
+ if (runtime === null) return;
24042
24955
  try {
24043
- const deleted = await createSessionOrganizationService(key).deleteGroup(
24044
- req.params["groupId"] ?? ""
24956
+ const deleted = await runWithWorkspaceRuntimeStorage(
24957
+ runtime,
24958
+ () => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
24959
+ req.params["groupId"] ?? ""
24960
+ )
24045
24961
  );
24046
24962
  res.status(200).json({ deleted });
24047
24963
  } catch (err) {
@@ -24076,12 +24992,13 @@ function registerSessionRoutes(app, deps) {
24076
24992
  if (!runtime) return;
24077
24993
  const body = safeBody(req);
24078
24994
  try {
24079
- const group = await createSessionOrganizationService(
24080
- runtime.workspaceCwd
24081
- ).createGroup({
24082
- name: body["name"],
24083
- color: body["color"]
24084
- });
24995
+ const group = await runWithWorkspaceRuntimeStorage(
24996
+ runtime,
24997
+ () => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
24998
+ name: body["name"],
24999
+ color: body["color"]
25000
+ })
25001
+ );
24085
25002
  res.status(201).json({ group });
24086
25003
  } catch (err) {
24087
25004
  if (sendSessionOrganizationError(res, err)) return;
@@ -24098,13 +25015,17 @@ function registerSessionRoutes(app, deps) {
24098
25015
  if (!runtime) return;
24099
25016
  const body = safeBody(req);
24100
25017
  try {
24101
- const group = await createSessionOrganizationService(
24102
- runtime.workspaceCwd
24103
- ).updateGroup(req.params["groupId"] ?? "", {
24104
- ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
24105
- ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
24106
- ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
24107
- });
25018
+ const group = await runWithWorkspaceRuntimeStorage(
25019
+ runtime,
25020
+ () => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
25021
+ req.params["groupId"] ?? "",
25022
+ {
25023
+ ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
25024
+ ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
25025
+ ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
25026
+ }
25027
+ )
25028
+ );
24108
25029
  res.status(200).json({ group });
24109
25030
  } catch (err) {
24110
25031
  if (sendSessionOrganizationError(res, err)) return;
@@ -24120,9 +25041,12 @@ function registerSessionRoutes(app, deps) {
24120
25041
  const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
24121
25042
  if (!runtime) return;
24122
25043
  try {
24123
- const deleted = await createSessionOrganizationService(
24124
- runtime.workspaceCwd
24125
- ).deleteGroup(req.params["groupId"] ?? "");
25044
+ const deleted = await runWithWorkspaceRuntimeStorage(
25045
+ runtime,
25046
+ () => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
25047
+ req.params["groupId"] ?? ""
25048
+ )
25049
+ );
24126
25050
  res.status(200).json({ deleted });
24127
25051
  } catch (err) {
24128
25052
  if (sendSessionOrganizationError(res, err)) return;
@@ -24210,7 +25134,7 @@ function registerSessionRoutes(app, deps) {
24210
25134
  ...parentSessionId !== void 0 ? { parentSessionId } : {},
24211
25135
  ...parsedSource
24212
25136
  };
24213
- const usePersisted = readOnlySecondary || runtime.primary || view === "organized" || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0 || (cursor !== void 0 && cursor !== "" ? isNumericSessionCursor(cursor) : await hasActivePersistedSessions(key));
25137
+ const usePersisted = readOnlySecondary || runtime.primary || view === "organized" || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0 || (cursor !== void 0 && cursor !== "" ? isNumericSessionCursor(cursor) : await hasActivePersistedSessions(runtime));
24214
25138
  if (!usePersisted && (view !== void 0 || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0)) {
24215
25139
  throw new Error(
24216
25140
  "session list live path received persisted-only options"
@@ -24707,11 +25631,14 @@ function requireOpenGeneration2(target, res) {
24707
25631
  }
24708
25632
  }
24709
25633
  __name(requireOpenGeneration2, "requireOpenGeneration");
24710
- async function rollbackCronMutation(workspaceCwd, before, after, route) {
25634
+ async function rollbackCronMutation(target, before, after, route) {
24711
25635
  if (!before || !after) return;
24712
- await updateCronTasks(
24713
- workspaceCwd,
24714
- (tasks) => isDeepStrictEqual2(tasks, after) ? before : tasks
25636
+ await runWithScheduledTaskTarget(
25637
+ target,
25638
+ () => updateCronTasks(
25639
+ target.workspaceCwd,
25640
+ (tasks) => isDeepStrictEqual2(tasks, after) ? before : tasks
25641
+ )
24715
25642
  ).catch((error2) => {
24716
25643
  writeStderrLine(
24717
25644
  `qwen serve: ${route} failed to roll back a stale task mutation: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -24719,6 +25646,27 @@ async function rollbackCronMutation(workspaceCwd, before, after, route) {
24719
25646
  });
24720
25647
  }
24721
25648
  __name(rollbackCronMutation, "rollbackCronMutation");
25649
+ async function teardownBoundSession(target, sessionId) {
25650
+ if (target.cleanupSession) {
25651
+ await target.cleanupSession(sessionId).catch(() => {
25652
+ });
25653
+ } else if (target.bridge) {
25654
+ await target.bridge.closeSession(sessionId).catch(() => {
25655
+ });
25656
+ await new SessionService(target.workspaceCwd, {
25657
+ runtimeBaseDir: target.runtimeBaseDir
25658
+ }).removeSession(sessionId).catch(() => {
25659
+ });
25660
+ }
25661
+ }
25662
+ __name(teardownBoundSession, "teardownBoundSession");
25663
+ function runWithScheduledTaskTarget(target, fn) {
25664
+ if (target.runtimeBaseDir === void 0) {
25665
+ return fn();
25666
+ }
25667
+ return Storage.runWithResolvedRuntimeBaseDir(target.runtimeBaseDir, fn);
25668
+ }
25669
+ __name(runWithScheduledTaskTarget, "runWithScheduledTaskTarget");
24722
25670
  function computeNextRunAt(task) {
24723
25671
  if (task.enabled === false) return null;
24724
25672
  return nextDurableFireMs(task);
@@ -24793,7 +25741,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24793
25741
  if (!target) return;
24794
25742
  if (!requireOpenGeneration2(target, res)) return;
24795
25743
  try {
24796
- const tasks = await readCronTasks(target.workspaceCwd);
25744
+ const tasks = await runWithScheduledTaskTarget(
25745
+ target,
25746
+ () => readCronTasks(target.workspaceCwd)
25747
+ );
24797
25748
  if (!requireOpenGeneration2(target, res)) return;
24798
25749
  res.status(200).json({ v: 1, tasks: tasks.map(toView) });
24799
25750
  } catch (err) {
@@ -24887,7 +25838,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24887
25838
  let boundSessionId;
24888
25839
  if (bridge) {
24889
25840
  try {
24890
- if ((await readCronTasks(workspaceCwd)).length >= MAX_SCHEDULED_TASKS) {
25841
+ if ((await runWithScheduledTaskTarget(
25842
+ target,
25843
+ () => readCronTasks(workspaceCwd)
25844
+ )).length >= MAX_SCHEDULED_TASKS) {
24891
25845
  res.status(409).json({
24892
25846
  error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
24893
25847
  code: "max_tasks_reached"
@@ -24906,10 +25860,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24906
25860
  });
24907
25861
  boundSessionId = session.sessionId;
24908
25862
  if (!requireOpenGeneration2(target, res)) {
24909
- await bridge.closeSession(boundSessionId).catch(() => {
24910
- });
24911
- await new SessionService(workspaceCwd).removeSession(boundSessionId).catch(() => {
24912
- });
25863
+ await teardownBoundSession(target, boundSessionId);
24913
25864
  return;
24914
25865
  }
24915
25866
  try {
@@ -24946,29 +25897,29 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24946
25897
  ...nameResult.value !== void 0 ? { name: nameResult.value } : {}
24947
25898
  };
24948
25899
  const rollbackSession = /* @__PURE__ */ __name(async () => {
24949
- if (boundSessionId !== void 0 && bridge) {
24950
- await bridge.closeSession(boundSessionId).catch(() => {
24951
- });
24952
- await new SessionService(workspaceCwd).removeSession(boundSessionId).catch(() => {
24953
- });
25900
+ if (boundSessionId !== void 0) {
25901
+ await teardownBoundSession(target, boundSessionId);
24954
25902
  }
24955
25903
  }, "rollbackSession");
24956
25904
  let overCap = false;
24957
25905
  let rollbackBefore;
24958
25906
  let rollbackAfter;
24959
25907
  try {
24960
- await updateCronTasks(
24961
- workspaceCwd,
24962
- (tasks) => {
24963
- if (tasks.length >= MAX_SCHEDULED_TASKS) {
24964
- overCap = true;
24965
- return tasks;
24966
- }
24967
- rollbackBefore = tasks;
24968
- rollbackAfter = [...tasks, task];
24969
- return rollbackAfter;
24970
- },
24971
- { assertCanCommit: target.assertGenerationOpen }
25908
+ await runWithScheduledTaskTarget(
25909
+ target,
25910
+ () => updateCronTasks(
25911
+ workspaceCwd,
25912
+ (tasks) => {
25913
+ if (tasks.length >= MAX_SCHEDULED_TASKS) {
25914
+ overCap = true;
25915
+ return tasks;
25916
+ }
25917
+ rollbackBefore = tasks;
25918
+ rollbackAfter = [...tasks, task];
25919
+ return rollbackAfter;
25920
+ },
25921
+ { assertCanCommit: target.assertGenerationOpen }
25922
+ )
24972
25923
  );
24973
25924
  } catch (err) {
24974
25925
  await rollbackSession();
@@ -24987,7 +25938,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24987
25938
  target.assertGenerationOpen?.();
24988
25939
  } catch (error2) {
24989
25940
  await rollbackCronMutation(
24990
- workspaceCwd,
25941
+ target,
24991
25942
  rollbackBefore,
24992
25943
  rollbackAfter,
24993
25944
  `POST ${base}`
@@ -25121,44 +26072,47 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25121
26072
  let rollbackBefore;
25122
26073
  let rollbackAfter;
25123
26074
  try {
25124
- await updateCronTasks(
25125
- workspaceCwd,
25126
- (tasks) => {
25127
- const idx = tasks.findIndex((t) => t.id === id);
25128
- if (idx === -1) return tasks;
25129
- found = true;
25130
- const current = tasks[idx];
25131
- if (patch.enabled === true && taskHasLegacyCondition(current)) {
25132
- blockedLegacy = true;
25133
- return tasks;
25134
- }
25135
- if (patch.enabled === true && current.disabledByArchive === true) {
25136
- blockedByArchive = true;
25137
- return tasks;
25138
- }
25139
- const next = { ...current, ...patch };
25140
- if (clearName) delete next.name;
25141
- if (clearDelivery) delete next.delivery;
25142
- const justReEnabled = current.enabled === false && patch.enabled === true;
25143
- const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
25144
- const becameRecurring = patch.recurring === true && current.recurring !== true;
25145
- const becameOneShot = patch.recurring === false && current.recurring !== false;
25146
- {
25147
- const now = Date.now();
25148
- const minute = now - now % 6e4;
25149
- if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
25150
- next.lastFiredAt = minute;
25151
- } else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
25152
- next.createdAt = now;
25153
- next.lastFiredAt = minute;
26075
+ await runWithScheduledTaskTarget(
26076
+ target,
26077
+ () => updateCronTasks(
26078
+ workspaceCwd,
26079
+ (tasks) => {
26080
+ const idx = tasks.findIndex((t) => t.id === id);
26081
+ if (idx === -1) return tasks;
26082
+ found = true;
26083
+ const current = tasks[idx];
26084
+ if (patch.enabled === true && taskHasLegacyCondition(current)) {
26085
+ blockedLegacy = true;
26086
+ return tasks;
25154
26087
  }
25155
- }
25156
- updated = next;
25157
- rollbackBefore = tasks;
25158
- rollbackAfter = tasks.map((t, i) => i === idx ? next : t);
25159
- return rollbackAfter;
25160
- },
25161
- { assertCanCommit: target.assertGenerationOpen }
26088
+ if (patch.enabled === true && current.disabledByArchive === true) {
26089
+ blockedByArchive = true;
26090
+ return tasks;
26091
+ }
26092
+ const next = { ...current, ...patch };
26093
+ if (clearName) delete next.name;
26094
+ if (clearDelivery) delete next.delivery;
26095
+ const justReEnabled = current.enabled === false && patch.enabled === true;
26096
+ const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
26097
+ const becameRecurring = patch.recurring === true && current.recurring !== true;
26098
+ const becameOneShot = patch.recurring === false && current.recurring !== false;
26099
+ {
26100
+ const now = Date.now();
26101
+ const minute = now - now % 6e4;
26102
+ if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
26103
+ next.lastFiredAt = minute;
26104
+ } else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
26105
+ next.createdAt = now;
26106
+ next.lastFiredAt = minute;
26107
+ }
26108
+ }
26109
+ updated = next;
26110
+ rollbackBefore = tasks;
26111
+ rollbackAfter = tasks.map((t, i) => i === idx ? next : t);
26112
+ return rollbackAfter;
26113
+ },
26114
+ { assertCanCommit: target.assertGenerationOpen }
26115
+ )
25162
26116
  );
25163
26117
  } catch (err) {
25164
26118
  if (sendGenerationClosedError(res, err)) return;
@@ -25176,7 +26130,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25176
26130
  target.assertGenerationOpen?.();
25177
26131
  } catch (error2) {
25178
26132
  await rollbackCronMutation(
25179
- workspaceCwd,
26133
+ target,
25180
26134
  rollbackBefore,
25181
26135
  rollbackAfter,
25182
26136
  `PATCH ${base}/${id}`
@@ -25245,21 +26199,24 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25245
26199
  let rollbackBefore;
25246
26200
  let rollbackAfter;
25247
26201
  try {
25248
- await updateCronTasks(
25249
- workspaceCwd,
25250
- (tasks) => {
25251
- const idx = tasks.findIndex((t) => t.id === id);
25252
- if (idx === -1) return tasks;
25253
- const match = tasks[idx].sessionId;
25254
- if (typeof match === "string" && match.length > 0) {
25255
- boundSessionId = match;
25256
- }
25257
- removed = true;
25258
- rollbackBefore = tasks;
25259
- rollbackAfter = tasks.filter((_, i) => i !== idx);
25260
- return rollbackAfter;
25261
- },
25262
- { assertCanCommit: target.assertGenerationOpen }
26202
+ await runWithScheduledTaskTarget(
26203
+ target,
26204
+ () => updateCronTasks(
26205
+ workspaceCwd,
26206
+ (tasks) => {
26207
+ const idx = tasks.findIndex((t) => t.id === id);
26208
+ if (idx === -1) return tasks;
26209
+ const match = tasks[idx].sessionId;
26210
+ if (typeof match === "string" && match.length > 0) {
26211
+ boundSessionId = match;
26212
+ }
26213
+ removed = true;
26214
+ rollbackBefore = tasks;
26215
+ rollbackAfter = tasks.filter((_, i) => i !== idx);
26216
+ return rollbackAfter;
26217
+ },
26218
+ { assertCanCommit: target.assertGenerationOpen }
26219
+ )
25263
26220
  );
25264
26221
  } catch (err) {
25265
26222
  if (sendGenerationClosedError(res, err)) return;
@@ -25277,7 +26234,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25277
26234
  target.assertGenerationOpen?.();
25278
26235
  } catch (error2) {
25279
26236
  await rollbackCronMutation(
25280
- workspaceCwd,
26237
+ target,
25281
26238
  rollbackBefore,
25282
26239
  rollbackAfter,
25283
26240
  `DELETE ${base}/${id}`
@@ -25321,37 +26278,40 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25321
26278
  let rollbackBefore;
25322
26279
  let rollbackAfter;
25323
26280
  try {
25324
- await updateCronTasks(
25325
- workspaceCwd,
25326
- (tasks) => {
25327
- const idx = tasks.findIndex((t) => t.id === id);
25328
- if (idx === -1) return tasks;
25329
- found = true;
25330
- const current = tasks[idx];
25331
- if (taskHasLegacyCondition(current)) {
25332
- blockedLegacy = true;
25333
- return tasks;
25334
- }
25335
- if (current.enabled === false) {
25336
- blockedDisabled = true;
25337
- return tasks;
25338
- }
25339
- const next = {
25340
- ...current,
25341
- lastFiredAt: now,
25342
- runs: appendCronRun(current.runs, {
25343
- at: now,
25344
- kind: "manual",
25345
- ...current.sessionId ? { sessionId: current.sessionId } : {}
25346
- })
25347
- };
25348
- updated = next;
25349
- rollbackBefore = tasks;
25350
- const nextTasks = !current.recurring ? tasks.filter((_, i) => i !== idx) : tasks.map((t, i) => i === idx ? next : t);
25351
- rollbackAfter = nextTasks;
25352
- return nextTasks;
25353
- },
25354
- { assertCanCommit: target.assertGenerationOpen }
26281
+ await runWithScheduledTaskTarget(
26282
+ target,
26283
+ () => updateCronTasks(
26284
+ workspaceCwd,
26285
+ (tasks) => {
26286
+ const idx = tasks.findIndex((t) => t.id === id);
26287
+ if (idx === -1) return tasks;
26288
+ found = true;
26289
+ const current = tasks[idx];
26290
+ if (taskHasLegacyCondition(current)) {
26291
+ blockedLegacy = true;
26292
+ return tasks;
26293
+ }
26294
+ if (current.enabled === false) {
26295
+ blockedDisabled = true;
26296
+ return tasks;
26297
+ }
26298
+ const next = {
26299
+ ...current,
26300
+ lastFiredAt: now,
26301
+ runs: appendCronRun(current.runs, {
26302
+ at: now,
26303
+ kind: "manual",
26304
+ ...current.sessionId ? { sessionId: current.sessionId } : {}
26305
+ })
26306
+ };
26307
+ updated = next;
26308
+ rollbackBefore = tasks;
26309
+ const nextTasks = !current.recurring ? tasks.filter((_, i) => i !== idx) : tasks.map((t, i) => i === idx ? next : t);
26310
+ rollbackAfter = nextTasks;
26311
+ return nextTasks;
26312
+ },
26313
+ { assertCanCommit: target.assertGenerationOpen }
26314
+ )
25355
26315
  );
25356
26316
  } catch (err) {
25357
26317
  if (sendGenerationClosedError(res, err)) return;
@@ -25369,7 +26329,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25369
26329
  target.assertGenerationOpen?.();
25370
26330
  } catch (error2) {
25371
26331
  await rollbackCronMutation(
25372
- workspaceCwd,
26332
+ target,
25373
26333
  rollbackBefore,
25374
26334
  rollbackAfter,
25375
26335
  `POST ${base}/${id}/run`
@@ -25425,6 +26385,12 @@ function registerScheduledTasksRoutes(app, deps) {
25425
26385
  if (runtime && !requireTrustedWorkspaceRuntime(runtime, res)) return null;
25426
26386
  return {
25427
26387
  workspaceCwd: boundWorkspace,
26388
+ ...runtime ? {
26389
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
26390
+ ...deps.cleanupSession ? {
26391
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => deps.cleanupSession(runtime, sessionId), "cleanupSession")
26392
+ } : {}
26393
+ } : {},
25428
26394
  bridge: runtime?.bridge ?? bridge,
25429
26395
  ...runtime?.generationGuard ? {
25430
26396
  assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
@@ -25443,7 +26409,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
25443
26409
  mutate,
25444
26410
  safeBody: safeBody2,
25445
26411
  manageScheduledTaskSessions,
25446
- channelDeliveryAuthorizations
26412
+ channelDeliveryAuthorizations,
26413
+ cleanupSession
25447
26414
  } = deps;
25448
26415
  registerScheduledTaskCrudRoutes(app, {
25449
26416
  prefix: "/workspaces/:workspace",
@@ -25457,6 +26424,10 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
25457
26424
  if (!requireTrustedWorkspaceRuntime(runtime, res)) return null;
25458
26425
  return {
25459
26426
  workspaceCwd: runtime.workspaceCwd,
26427
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
26428
+ ...cleanupSession ? {
26429
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession")
26430
+ } : {},
25460
26431
  // Mirror the primary surface: only bind a session when management is on,
25461
26432
  // so a bound task always has something to keep it resident + rehydrate it.
25462
26433
  bridge: manageScheduledTaskSessions ? runtime.bridge : void 0,
@@ -25735,7 +26706,7 @@ __name(collectBoundSessionIds, "collectBoundSessionIds");
25735
26706
  var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
25736
26707
  var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
25737
26708
  var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
25738
- async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding) {
26709
+ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding, cleanupSession) {
25739
26710
  const unbound = tasks.filter(
25740
26711
  (t) => !t.sessionId && t.enabled !== false && !taskHasLegacyCondition(t) && !binding.has(t.id)
25741
26712
  );
@@ -25753,16 +26724,14 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
25753
26724
  sourceId: task.id
25754
26725
  });
25755
26726
  let timedOut = false;
25756
- rawSpawn.then(({ sessionId: sessionId2 }) => {
26727
+ rawSpawn.then(async ({ sessionId: sessionId2 }) => {
25757
26728
  if (timedOut) {
25758
26729
  log.debug(
25759
26730
  "keepalive: late spawn resolved, cleaning up",
25760
26731
  task.id,
25761
26732
  sessionId2
25762
26733
  );
25763
- bridge.closeSession(sessionId2).catch(() => {
25764
- });
25765
- new SessionService(boundWorkspace).removeSession(sessionId2).catch(() => {
26734
+ await cleanupSession(sessionId2).catch(() => {
25766
26735
  });
25767
26736
  }
25768
26737
  }).catch(() => {
@@ -25810,9 +26779,7 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
25810
26779
  } catch (err) {
25811
26780
  log.debug("keepalive: failed to bind task", task.id, err);
25812
26781
  if (spawnedSessionId !== void 0) {
25813
- await bridge.closeSession(spawnedSessionId).catch(() => {
25814
- });
25815
- await new SessionService(boundWorkspace).removeSession(spawnedSessionId).catch(() => {
26782
+ await cleanupSession(spawnedSessionId).catch(() => {
25816
26783
  });
25817
26784
  }
25818
26785
  }
@@ -25834,11 +26801,17 @@ function startScheduledTaskKeepalive(opts) {
25834
26801
  const { bridge, boundWorkspace, intervalMs } = opts;
25835
26802
  const reviveTimeoutMs = opts.reviveTimeoutMs ?? KEEPALIVE_REVIVE_TIMEOUT_MS;
25836
26803
  const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
26804
+ const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
26805
+ await bridge.closeSession(sessionId);
26806
+ await new SessionService(boundWorkspace, {
26807
+ runtimeBaseDir: opts.runtimeBaseDir
26808
+ }).removeSession(sessionId);
26809
+ });
25837
26810
  const reviveState = /* @__PURE__ */ new Map();
25838
26811
  const reviving = /* @__PURE__ */ new Set();
25839
26812
  const binding = /* @__PURE__ */ new Set();
25840
26813
  const renamed = /* @__PURE__ */ new Set();
25841
- const tick = /* @__PURE__ */ __name(async () => {
26814
+ const tickInRuntime = /* @__PURE__ */ __name(async () => {
25842
26815
  let tasks;
25843
26816
  try {
25844
26817
  tasks = await readCronTasks(boundWorkspace);
@@ -25916,9 +26889,14 @@ function startScheduledTaskKeepalive(opts) {
25916
26889
  tasks,
25917
26890
  renamed,
25918
26891
  spawnTimeoutMs,
25919
- binding
26892
+ binding,
26893
+ cleanupSession
25920
26894
  );
25921
- }, "tick");
26895
+ }, "tickInRuntime");
26896
+ const tick = /* @__PURE__ */ __name(() => opts.runtimeBaseDir === void 0 ? tickInRuntime() : Storage.runWithResolvedRuntimeBaseDir(
26897
+ opts.runtimeBaseDir,
26898
+ tickInRuntime
26899
+ ), "tick");
25922
26900
  let running = false;
25923
26901
  const timer = setInterval(() => {
25924
26902
  if (running) return;
@@ -25929,7 +26907,10 @@ function startScheduledTaskKeepalive(opts) {
25929
26907
  }, intervalMs);
25930
26908
  timer.unref?.();
25931
26909
  let bindDebounce;
25932
- const cronFilePath = getCronFilePath(boundWorkspace);
26910
+ const cronFilePath = opts.runtimeBaseDir === void 0 ? getCronFilePath(boundWorkspace) : Storage.runWithResolvedRuntimeBaseDir(
26911
+ opts.runtimeBaseDir,
26912
+ () => getCronFilePath(boundWorkspace)
26913
+ );
25933
26914
  const cronDir = path11.dirname(cronFilePath);
25934
26915
  const cronFileName = path11.basename(cronFilePath);
25935
26916
  let fileWatcher;
@@ -27424,6 +28405,14 @@ function sendPermissionVoteError(res, err, ctx, daemonLog) {
27424
28405
  }
27425
28406
  __name(sendPermissionVoteError, "sendPermissionVoteError");
27426
28407
  function sendBridgeError(res, err, ctx, daemonLog) {
28408
+ if (err instanceof DaemonDrainingError) {
28409
+ res.status(503).json({
28410
+ error: err.message,
28411
+ code: err.code,
28412
+ errorKind: err.code
28413
+ });
28414
+ return;
28415
+ }
27427
28416
  if (sendGenerationClosedError(res, err)) return;
27428
28417
  if (err instanceof SessionWriterError) {
27429
28418
  res.status(err.httpStatus).json({
@@ -32730,6 +33719,18 @@ function parsePairingCode(body, res) {
32730
33719
  return code.trim().toUpperCase();
32731
33720
  }
32732
33721
  __name(parsePairingCode, "parsePairingCode");
33722
+ function parsePairingSenderId(body, res) {
33723
+ const senderId = body["senderId"];
33724
+ if (typeof senderId !== "string" || senderId.length === 0) {
33725
+ res.status(400).json({
33726
+ error: "`senderId` must be a non-empty string.",
33727
+ code: "invalid_channel_pairing_sender_id"
33728
+ });
33729
+ return void 0;
33730
+ }
33731
+ return senderId;
33732
+ }
33733
+ __name(parsePairingSenderId, "parsePairingSenderId");
32733
33734
  function errorCode2(error2) {
32734
33735
  if (!error2 || typeof error2 !== "object") return void 0;
32735
33736
  try {
@@ -32751,6 +33752,7 @@ var ERROR_STATUS = /* @__PURE__ */ new Map([
32751
33752
  ["untrusted_workspace", 403],
32752
33753
  ["channel_instance_not_found", 404],
32753
33754
  ["channel_pairing_request_not_found", 404],
33755
+ ["channel_pairing_approval_not_found", 404],
32754
33756
  ["channel_pairing_not_enabled", 409],
32755
33757
  ["channel_settings_conflict", 409],
32756
33758
  ["channel_runtime_owner_mismatch", 409],
@@ -32807,6 +33809,8 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
32807
33809
  const register = /* @__PURE__ */ __name((prefix, resolveRuntime) => {
32808
33810
  const pairingRead = deps.mutate({ strict: true });
32809
33811
  const pairingApprove = deps.mutate({ strict: true });
33812
+ const pairingApprovalsRead = deps.mutate({ strict: true });
33813
+ const pairingRevoke = deps.mutate({ strict: true });
32810
33814
  const upsert = deps.mutate({ strict: true });
32811
33815
  const remove = deps.mutate({ strict: true });
32812
33816
  const startup = deps.mutate({ strict: true });
@@ -32869,6 +33873,40 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
32869
33873
  }
32870
33874
  }
32871
33875
  );
33876
+ app.get(
33877
+ `${prefix}/channels/:name/pairing-approvals`,
33878
+ pairingApprovalsRead,
33879
+ async (req, res) => {
33880
+ const resolved = await target(req, res);
33881
+ if (!resolved || !validateClient(req, res, resolved.runtime)) return;
33882
+ const name = parseInstanceName(req, res);
33883
+ if (!name) return;
33884
+ try {
33885
+ noStore(res);
33886
+ res.status(200).json(await resolved.service.pairingApprovals(name));
33887
+ } catch (error2) {
33888
+ sendManagementError(res, error2);
33889
+ }
33890
+ }
33891
+ );
33892
+ app.delete(
33893
+ `${prefix}/channels/:name/pairing-approvals`,
33894
+ pairingRevoke,
33895
+ async (req, res) => {
33896
+ const resolved = await target(req, res);
33897
+ if (!resolved || !validateClient(req, res, resolved.runtime)) return;
33898
+ const name = parseInstanceName(req, res);
33899
+ if (!name) return;
33900
+ const senderId = parsePairingSenderId(deps.safeBody(req), res);
33901
+ if (!senderId) return;
33902
+ try {
33903
+ noStore(res);
33904
+ res.status(200).json(await resolved.service.revokePairingApproval(name, senderId));
33905
+ } catch (error2) {
33906
+ sendManagementError(res, error2);
33907
+ }
33908
+ }
33909
+ );
32872
33910
  app.put(`${prefix}/channels/:name`, upsert, async (req, res) => {
32873
33911
  const resolved = await target(req, res);
32874
33912
  if (!resolved || !validateClient(req, res, resolved.runtime)) return;
@@ -33993,6 +35031,16 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
33993
35031
  defaultBridgeForAdmission = bridge;
33994
35032
  }
33995
35033
  const archiveCoordinator = new SessionArchiveCoordinator();
35034
+ app.locals.sessionArchiveCoordinator = archiveCoordinator;
35035
+ const cleanupSession = /* @__PURE__ */ __name((runtime, sessionId) => runWithWorkspaceRuntimeStorage(
35036
+ runtime,
35037
+ () => deleteDaemonSessionIfOrphan({
35038
+ sessionId,
35039
+ service: createWorkspaceRuntimeSessionService(runtime),
35040
+ bridge: runtime.bridge,
35041
+ coordinator: archiveCoordinator
35042
+ })
35043
+ ), "cleanupSession");
33996
35044
  installSelfOriginStripMiddleware(app, getPort);
33997
35045
  app.locals.fsFactory = fsFactory;
33998
35046
  app.locals.boundWorkspace = boundWorkspace;
@@ -34057,6 +35105,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34057
35105
  {
34058
35106
  workspaceId: hashDaemonWorkspace(boundWorkspace),
34059
35107
  workspaceCwd: boundWorkspace,
35108
+ sessionRuntimeBaseDir: Storage.getRuntimeBaseDir(),
34060
35109
  primary: true,
34061
35110
  trusted: deps.primaryWorkspaceTrusted ?? false,
34062
35111
  env: primaryRuntimeEnvMetadata ?? {
@@ -34681,6 +35730,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34681
35730
  safeBody,
34682
35731
  bridge: deps.manageScheduledTaskSessions ? primaryBridge : void 0,
34683
35732
  getRuntime: /* @__PURE__ */ __name(() => workspaceRegistry.primaryEntry.state === "active" ? workspaceRegistry.primaryEntry.current?.runtime : void 0, "getRuntime"),
35733
+ cleanupSession,
34684
35734
  channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
34685
35735
  });
34686
35736
  registerGoalsRoutes(app, {
@@ -34694,7 +35744,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34694
35744
  mutate,
34695
35745
  safeBody,
34696
35746
  manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
34697
- channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
35747
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
35748
+ cleanupSession
34698
35749
  });
34699
35750
  registerUsageStatsRoutes(app);
34700
35751
  if (deps.manageScheduledTaskSessions) {
@@ -34714,23 +35765,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34714
35765
  }, "registerScheduledTaskAuthorizations");
34715
35766
  const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
34716
35767
  const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
34717
- const rehydrateWorkspace = /* @__PURE__ */ __name((taskBridge, workspaceCwd) => {
34718
- void rehydrateScheduledTaskSessions({
34719
- bridge: taskBridge,
34720
- boundWorkspace: workspaceCwd,
34721
- onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(workspaceCwd, tasks), "onTasksRead"),
34722
- onError: /* @__PURE__ */ __name((sessionId, err) => {
34723
- process.stderr.write(
34724
- `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
35768
+ const rehydrateWorkspace = /* @__PURE__ */ __name((runtime) => {
35769
+ void runWithWorkspaceRuntimeStorage(
35770
+ runtime,
35771
+ () => rehydrateScheduledTaskSessions({
35772
+ bridge: runtime.bridge,
35773
+ boundWorkspace: runtime.workspaceCwd,
35774
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead"),
35775
+ onError: /* @__PURE__ */ __name((sessionId, err) => {
35776
+ process.stderr.write(
35777
+ `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
34725
35778
  `
34726
- );
34727
- }, "onError")
34728
- // Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
34729
- // catches readCronTasks failures and per-session load errors internally
34730
- // (returning { loaded, failed }), so this only guards an unexpected throw
34731
- // from the function entry itself. Log rather than swallow it — a silent
34732
- // failure here leaves every bound task dormant with no diagnostic.
34733
- }).catch((err) => {
35779
+ );
35780
+ }, "onError")
35781
+ // Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
35782
+ // catches readCronTasks failures and per-session load errors internally
35783
+ // (returning { loaded, failed }), so this only guards an unexpected throw
35784
+ // from the function entry itself. Log rather than swallow it — a silent
35785
+ // failure here leaves every bound task dormant with no diagnostic.
35786
+ })
35787
+ ).catch((err) => {
34734
35788
  process.stderr.write(
34735
35789
  `qwen serve: unexpected scheduled-task rehydration failure: ${err instanceof Error ? err.message : String(err)}
34736
35790
  `
@@ -34746,9 +35800,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34746
35800
  bridge: runtime.bridge,
34747
35801
  boundWorkspace: runtime.workspaceCwd,
34748
35802
  intervalMs: keepaliveIntervalMs,
35803
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
35804
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession"),
34749
35805
  onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
34750
35806
  });
34751
- rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
35807
+ rehydrateWorkspace(runtime);
34752
35808
  keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
34753
35809
  }, "startKeepaliveForWorkspace");
34754
35810
  for (const runtime of workspaceRegistry.list()) {