@qwen-code/qwen-code 0.21.1 → 0.21.2-nightly.20260801.bc382c3ff

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 (367) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +9 -7
  2. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  3. package/bundled/qc-helper/docs/features/channels/github.md +49 -10
  4. package/bundled/qc-helper/docs/features/channels/gitlab.md +177 -0
  5. package/bundled/qc-helper/docs/features/code-review.md +20 -0
  6. package/bundled/qc-helper/docs/features/commands.md +1 -0
  7. package/bundled/qc-helper/docs/features/hooks.md +135 -18
  8. package/bundled/qc-helper/docs/features/memory.md +27 -0
  9. package/bundled/qc-helper/docs/features/skills.md +14 -0
  10. package/bundled/qc-helper/docs/features/sub-agents.md +55 -8
  11. package/bundled/qc-helper/docs/features/tool-use-summaries.md +7 -7
  12. package/bundled/qc-helper/docs/qwen-serve.md +28 -6
  13. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +2 -2
  14. package/bundled/review/SKILL.md +1 -1
  15. package/chunks/{MaxSizedBox-VI3ROJJA.js → MaxSizedBox-CDHTDITS.js} +45 -40
  16. package/chunks/{StandaloneSessionPicker-LYXKD2EV.js → StandaloneSessionPicker-L63HUAHP.js} +65 -60
  17. package/chunks/{acp-startup-profiler-DFVPFQ6C.js → acp-startup-profiler-3RICG2YW.js} +2 -2
  18. package/chunks/{acpAgent-WN5SRDQO.js → acpAgent-6WVVT2P3.js} +962 -599
  19. package/chunks/{agent-K6ECSM64.js → agent-KDM4CBOU.js} +40 -35
  20. package/chunks/agent-headless-AS7K2K57.js +79 -0
  21. package/chunks/{anthropicContentGenerator-V2QOGVYD.js → anthropicContentGenerator-WCBYB6JG.js} +337 -27
  22. package/chunks/{artifact-tool-6K6U7XYJ.js → artifact-tool-ANV4CFCR.js} +2 -2
  23. package/chunks/{askUserQuestion-GD2IJJ7I.js → askUserQuestion-MALEB47H.js} +2 -2
  24. package/chunks/{bridge-3KJEWDNE.js → bridge-JNEW6FES.js} +46 -41
  25. package/chunks/{build-S6DO7LMM.js → build-GDBLPA24.js} +1 -1
  26. package/chunks/{ca-6W3SK7OQ.js → ca-4OJN75WT.js} +46 -5
  27. package/chunks/{channel-management-service-XR7GZSWF.js → channel-management-service-QOO7TD3T.js} +21 -6
  28. package/chunks/{channel-settings-store-HW4FXXUA.js → channel-settings-store-4CSMTR4L.js} +47 -42
  29. package/chunks/{channel-worker-group-XDPTDWTX.js → channel-worker-group-ERSUOPIR.js} +8 -8
  30. package/chunks/{channel-worker-manager-YYEHVRRE.js → channel-worker-manager-X247YDQ7.js} +8 -8
  31. package/chunks/{channel-worker-supervisor-74HTWA2G.js → channel-worker-supervisor-ORJIEEPP.js} +4 -4
  32. package/chunks/{chunk-VWOOBLTY.js → chunk-25QQVOCG.js} +5 -5
  33. package/chunks/{chunk-CAPPWD3X.js → chunk-2A6MHYIA.js} +3 -3
  34. package/chunks/{chunk-2XSLTRFZ.js → chunk-2CTKGIFR.js} +2 -2
  35. package/chunks/{chunk-DZLYR4U3.js → chunk-2DNKEBXY.js} +1 -1
  36. package/chunks/{chunk-UWMLWVCA.js → chunk-2IIJTXYF.js} +26 -10
  37. package/chunks/{chunk-JYBU6YUE.js → chunk-2M5N3DHY.js} +1 -1
  38. package/chunks/{chunk-AQIDMUGU.js → chunk-2PNQQ4UR.js} +2 -2
  39. package/chunks/{chunk-OKF7JF3R.js → chunk-2UISUFHQ.js} +3 -3
  40. package/chunks/{chunk-2LQTH543.js → chunk-33FNCQSY.js} +2 -2
  41. package/chunks/{chunk-M7OONWYU.js → chunk-3LGZEYOF.js} +4 -2
  42. package/chunks/{chunk-ZURDMIDR.js → chunk-3MHPWQ2M.js} +242 -76
  43. package/chunks/{chunk-UHUSJ6X7.js → chunk-3RXUYQJI.js} +25 -6
  44. package/chunks/{chunk-E5Z2AVNV.js → chunk-3SH53ANB.js} +0 -11
  45. package/chunks/{chunk-BNWB5CYE.js → chunk-3WXMXT7C.js} +22 -11
  46. package/chunks/{chunk-A2D5BAVP.js → chunk-42IKVPST.js} +1 -1
  47. package/chunks/{chunk-2DN4J57Y.js → chunk-432XCUHF.js} +1 -1
  48. package/chunks/{chunk-EVKE2FZL.js → chunk-433VD3HX.js} +4 -4
  49. package/chunks/{chunk-Q43KPN7X.js → chunk-434YCHSV.js} +6 -6
  50. package/chunks/{chunk-5TBMQLGG.js → chunk-4LKVQFHM.js} +2 -2
  51. package/chunks/{chunk-YDLJGZHL.js → chunk-4NFY2S7N.js} +0 -33
  52. package/chunks/{chunk-6PE7N3A4.js → chunk-5UJ6A3CH.js} +145 -10
  53. package/chunks/{chunk-GNR2RNMP.js → chunk-5UZITEHA.js} +3 -3
  54. package/chunks/chunk-6FMJLI5M.js +1591 -0
  55. package/chunks/{chunk-RPLGZJV2.js → chunk-6O5DVH27.js} +1 -1
  56. package/chunks/{chunk-2RFKHEXL.js → chunk-6PLDPT2C.js} +1 -1
  57. package/chunks/{chunk-7AEJDLRA.js → chunk-7IYLHTTM.js} +3 -3
  58. package/chunks/{chunk-65PQENQP.js → chunk-7K2WTPQO.js} +5 -5
  59. package/chunks/{chunk-P4WOAOJW.js → chunk-7MY2AR5A.js} +72 -26
  60. package/chunks/{chunk-GXIJHV66.js → chunk-A2A34TSB.js} +3 -3
  61. package/chunks/{chunk-XWWKIXVD.js → chunk-A5YZ3FA2.js} +2 -1
  62. package/chunks/{chunk-64LQLPL7.js → chunk-A6SX5TAH.js} +3 -3
  63. package/chunks/{chunk-SZ3KHTDR.js → chunk-AKA24BGO.js} +1 -1
  64. package/chunks/chunk-AQ37AY7B.js +93 -0
  65. package/chunks/{chunk-2N7CODY5.js → chunk-AQEWCKX4.js} +2 -2
  66. package/chunks/{chunk-KCO4FLFJ.js → chunk-AYB4HSBI.js} +3 -3
  67. package/chunks/{chunk-WZRWHXFE.js → chunk-BFHXDAR7.js} +1 -1
  68. package/chunks/{chunk-L55JWS76.js → chunk-BGXZBI5B.js} +1 -1
  69. package/chunks/{chunk-5MKRTI4T.js → chunk-BKUN5QHP.js} +7 -7
  70. package/chunks/{chunk-Y4IHBGBP.js → chunk-BV4QX43X.js} +1 -1
  71. package/chunks/{chunk-PB3MBFKG.js → chunk-C4L2MEIT.js} +4 -4
  72. package/chunks/{chunk-TCIFAA7K.js → chunk-CHCLO3M7.js} +14 -14
  73. package/chunks/{chunk-CVHIL5IG.js → chunk-CWEIMFFW.js} +13 -6
  74. package/chunks/{chunk-2FAK6PNM.js → chunk-DUIJ2IXG.js} +5 -13
  75. package/chunks/{chunk-T2QMKU3R.js → chunk-DVGTU5TC.js} +19 -7
  76. package/chunks/{chunk-LGAOC3ZS.js → chunk-DYA25Y7U.js} +1 -1
  77. package/chunks/{chunk-SGFT55XI.js → chunk-E4WHKETF.js} +32 -4
  78. package/chunks/{chunk-WBL3FJEU.js → chunk-FC4KQFCS.js} +1 -1
  79. package/chunks/{chunk-MHAIJPTD.js → chunk-FJHA23GM.js} +12 -12
  80. package/chunks/{chunk-S7W2GKIO.js → chunk-G7XXKQYS.js} +2 -0
  81. package/chunks/{chunk-MR5EAQ5M.js → chunk-GALUTA2C.js} +1 -1
  82. package/chunks/{chunk-7I5GTCT4.js → chunk-GB3AB7TR.js} +4008 -3648
  83. package/chunks/{chunk-QIZKCVM3.js → chunk-GHJM2C2T.js} +6 -8
  84. package/chunks/chunk-GOFAQQZA.js +132 -0
  85. package/chunks/{chunk-BCZFQXWK.js → chunk-GTM6IHBB.js} +2 -2
  86. package/chunks/{chunk-5ZF5XXTS.js → chunk-GVISB2OH.js} +2 -2
  87. package/chunks/{chunk-FNMZK765.js → chunk-H36SETQS.js} +1 -1
  88. package/chunks/{chunk-UBEPNVDI.js → chunk-H4346YW5.js} +28 -16
  89. package/chunks/{chunk-CQL64ESB.js → chunk-H4DSRWAS.js} +24 -13
  90. package/chunks/{chunk-YGF33UXG.js → chunk-H6MC6VQX.js} +222 -173
  91. package/chunks/{chunk-GZXCZHCT.js → chunk-I3G5JWBV.js} +1 -1
  92. package/chunks/{chunk-Y6AXW2OG.js → chunk-I5GNT6ZS.js} +7 -1
  93. package/chunks/{chunk-GEBV2JGB.js → chunk-I6FAHB4N.js} +1 -1
  94. package/chunks/{chunk-UPUG4GXM.js → chunk-I7JDGNG6.js} +3 -3
  95. package/chunks/{chunk-JHNRZMHI.js → chunk-II6WPWHY.js} +9 -9
  96. package/chunks/{chunk-B4AJNNOL.js → chunk-J26HHFI5.js} +1 -1
  97. package/chunks/{chunk-S3TWXGKA.js → chunk-JE7KQ2UP.js} +4 -2
  98. package/chunks/{chunk-ZHBO7WVX.js → chunk-JELIWHXD.js} +1 -1
  99. package/chunks/{chunk-3EFXSQCM.js → chunk-JRIDA5HF.js} +7 -7
  100. package/chunks/{chunk-TFRMVU6R.js → chunk-K4CGQN4Q.js} +1 -1
  101. package/chunks/{chunk-WUZ7H6DP.js → chunk-K5Q62CGR.js} +1 -1
  102. package/chunks/{chunk-JCW2R7WC.js → chunk-K623ENWT.js} +3 -79
  103. package/chunks/{chunk-T2NCM2ET.js → chunk-K6KS3LTN.js} +2 -749
  104. package/chunks/{chunk-TDL6LB4K.js → chunk-KG22G46Y.js} +22 -10
  105. package/chunks/{chunk-GATT5TKW.js → chunk-KKN2IE7Q.js} +1 -1
  106. package/chunks/{chunk-JMONIXMJ.js → chunk-KVUBYJDM.js} +2 -2
  107. package/chunks/{chunk-TBBV36Y4.js → chunk-KXSYDCP2.js} +4 -4
  108. package/chunks/{chunk-EIF3FXTB.js → chunk-LAPK3GLC.js} +121 -18
  109. package/chunks/chunk-LBOVL47Y.js +29 -0
  110. package/chunks/{chunk-U3E3UQAA.js → chunk-LBWNSLJK.js} +4 -4
  111. package/chunks/{chunk-S4WJVPZW.js → chunk-LL4U3BSH.js} +15 -7
  112. package/chunks/{chunk-657BH7VM.js → chunk-LRJWFR6L.js} +4 -4
  113. package/chunks/{chunk-PT722TDT.js → chunk-M2F5PLOW.js} +770 -125
  114. package/chunks/{chunk-3L2SPEBH.js → chunk-M744OFVE.js} +1 -1
  115. package/chunks/{chunk-VYOXCEPJ.js → chunk-MBKPUM5Y.js} +1 -1
  116. package/chunks/chunk-MISUEWB4.js +8749 -0
  117. package/chunks/{chunk-PONHVBRT.js → chunk-MOHAWIAW.js} +2 -2
  118. package/chunks/{chunk-HMRM2A3U.js → chunk-MSIVKDRC.js} +4 -4
  119. package/chunks/{record-artifact-XAMSFSW4.js → chunk-MYT7N6QH.js} +22 -7
  120. package/chunks/{chunk-X5WNMMIA.js → chunk-NGWYUZZO.js} +11510 -15137
  121. package/chunks/{chunk-PQNHRFJC.js → chunk-NYX53SV4.js} +0 -2
  122. package/chunks/{chunk-6RPMI2AB.js → chunk-NZB4NDJL.js} +10 -10
  123. package/chunks/{chunk-BGTQCTQW.js → chunk-O2ZYHG33.js} +6 -5
  124. package/chunks/chunk-O6GEWCJA.js +21 -0
  125. package/chunks/{chunk-JX27F6QS.js → chunk-OBAIHYFT.js} +1 -1
  126. package/chunks/{chunk-BPZKP57P.js → chunk-OCRM53TT.js} +3 -3
  127. package/chunks/{chunk-V7RNNPGC.js → chunk-P5Y23G2L.js} +18 -1
  128. package/chunks/{chunk-FTD6DP4T.js → chunk-PDDYAXL2.js} +5 -1
  129. package/chunks/{chunk-JSD33JG6.js → chunk-PGEGUNH5.js} +67 -10
  130. package/chunks/{chunk-A4COXFB3.js → chunk-PGP7Y3RQ.js} +5 -5
  131. package/chunks/{chunk-T3O2B4XO.js → chunk-PHODQP2V.js} +6 -6
  132. package/chunks/{chunk-BMFALVGQ.js → chunk-PXA5AWHY.js} +1 -1
  133. package/chunks/chunk-QL4TN4HS.js +59 -0
  134. package/chunks/{chunk-W4MIWP6M.js → chunk-QMBEW7EW.js} +2 -2
  135. package/chunks/{chunk-U4VTUMMK.js → chunk-QONSRAEV.js} +1 -1
  136. package/chunks/{chunk-LW3RFMG7.js → chunk-QYPT3QUD.js} +3 -3
  137. package/chunks/{chunk-TV64SXKD.js → chunk-RGJ4JWSU.js} +131 -48
  138. package/chunks/{chunk-75MIQ3LV.js → chunk-RPYYTL7E.js} +61 -13
  139. package/chunks/{chunk-52ZSWYEG.js → chunk-SK2UKB45.js} +1 -1
  140. package/chunks/{chunk-PLDQBIO6.js → chunk-SWEBEXPI.js} +1 -1
  141. package/chunks/chunk-T3CHYWJZ.js +758 -0
  142. package/chunks/{chunk-VCPIZRYH.js → chunk-TFFMATHX.js} +9 -7
  143. package/chunks/{chunk-J7OACQDE.js → chunk-TNVKFQXQ.js} +458 -97
  144. package/chunks/{chunk-A3NDJ5SB.js → chunk-TYERNYH4.js} +2 -2
  145. package/chunks/{chunk-GKX7E4CO.js → chunk-U25CMJYY.js} +1 -1
  146. package/chunks/{chunk-7XATOOE7.js → chunk-UH7Z7Y45.js} +1 -1
  147. package/chunks/{chunk-XFZYFU3I.js → chunk-UHQ3L6GC.js} +1 -1
  148. package/chunks/{chunk-GZ3RCT54.js → chunk-UHTJC7O3.js} +1 -1
  149. package/chunks/{chunk-XZC5VLBZ.js → chunk-UKZEXS6K.js} +6 -0
  150. package/chunks/{chunk-LO4ROVP4.js → chunk-UOFFZNXV.js} +111 -13
  151. package/chunks/{chunk-5YKDXHUY.js → chunk-URN76TKR.js} +2 -2
  152. package/chunks/{chunk-T4TXDL7G.js → chunk-UWLG4UCE.js} +132 -35
  153. package/chunks/{chunk-KAMYKP7E.js → chunk-UWSXFI6E.js} +1 -1
  154. package/chunks/{chunk-7BAU433D.js → chunk-VS3GXRNZ.js} +1198 -240
  155. package/chunks/{chunk-EJGJIBRS.js → chunk-VWF42XC6.js} +3 -3
  156. package/chunks/{chunk-RCUQIPTN.js → chunk-W7XZ3KP5.js} +1 -1
  157. package/chunks/{chunk-OCESJA77.js → chunk-WISQLM4Q.js} +1197 -1154
  158. package/chunks/{chunk-NOKIVHOL.js → chunk-WK4TJUEA.js} +1 -1
  159. package/chunks/{chunk-JFMA7Y5M.js → chunk-WP4HGHFG.js} +5 -5
  160. package/chunks/{chunk-4G2BISNC.js → chunk-XC2VAFVZ.js} +1 -1
  161. package/chunks/{chunk-2LKVPASC.js → chunk-XC656O42.js} +3 -3
  162. package/chunks/{chunk-5KTQXHPY.js → chunk-XCLLRKY5.js} +3 -3
  163. package/chunks/{chunk-HV26XH34.js → chunk-XFDPIC4P.js} +3 -3
  164. package/chunks/{chunk-JTV5K7NH.js → chunk-XSA5EKTJ.js} +1 -1
  165. package/chunks/{chunk-75GFAX4R.js → chunk-YAVY33G4.js} +1 -1
  166. package/chunks/{chunk-WBSMNTSV.js → chunk-YXEVDA66.js} +2 -2
  167. package/chunks/{chunk-7DXQIJID.js → chunk-ZRFJ75D7.js} +3 -3
  168. package/chunks/{chunk-XBYYDKAZ.js → chunk-ZTN6OA5J.js} +8 -7
  169. package/chunks/{computer-use-ZTIDHMMA.js → computer-use-Z4NCIIJN.js} +40 -35
  170. package/chunks/{config-utils-NYSXDMEQ.js → config-utils-64LM6OEQ.js} +4 -4
  171. package/chunks/{contextCommand-2PIEU37Z.js → contextCommand-HVM7XFCB.js} +43 -38
  172. package/chunks/{core-runtime-3XEYLQFK.js → core-runtime-NL3ZBHBU.js} +40 -35
  173. package/chunks/{create-sub-session-SBYUMSSS.js → create-sub-session-AM32K2HD.js} +2 -2
  174. package/chunks/{create-sub-session-R76FVXCI.js → create-sub-session-XHSCDYFU.js} +43 -38
  175. package/chunks/{cron-create-2QK6TCEC.js → cron-create-HPXYE6C5.js} +4 -4
  176. package/chunks/{cron-delete-FDCDFYMG.js → cron-delete-FPVNTKPK.js} +4 -4
  177. package/chunks/{cron-list-XN3WVBTP.js → cron-list-ZEI6PAAV.js} +4 -4
  178. package/chunks/{daemon-Q2AB5Z23.js → daemon-PCNCI5YU.js} +72 -3
  179. package/chunks/daemon-status-provider-XD23SNAM.js +94 -0
  180. package/chunks/{daemon-trust-policy-ILUDTLHD.js → daemon-trust-policy-NOHK7IW5.js} +46 -41
  181. package/chunks/{daemon-trust-policy-monitor-HS3PKKRO.js → daemon-trust-policy-monitor-ZBTSR333.js} +46 -41
  182. package/chunks/{de-SY6O76BF.js → de-A6TI4LBB.js} +46 -5
  183. package/chunks/{deferred-core-runtime-X4QV662U.js → deferred-core-runtime-JJBHKM2C.js} +40 -35
  184. package/chunks/{dist-HVRQ2CFL.js → dist-4LAMY2SK.js} +1180 -5
  185. package/chunks/{dist-DOLYHMXE.js → dist-4T4NCJFL.js} +2 -2
  186. package/chunks/dist-7KOL6OMD.js +13467 -0
  187. package/chunks/{dist-SSU66DM4.js → dist-BH76AT7N.js} +1 -1
  188. package/chunks/{dist-BSTVRPMT.js → dist-BXA3JXVQ.js} +541 -19
  189. package/chunks/{dist-SV7Q3AWJ.js → dist-OEEFI6UU.js} +12 -9
  190. package/chunks/{dist-YGBBMK3Z.js → dist-SMLVOWKV.js} +5 -4
  191. package/chunks/{dist-IXQEQWRG.js → dist-V2RK6S6Q.js} +1 -1
  192. package/chunks/{earlyInputCapture-XKLZT7ZD.js → earlyInputCapture-KLAZDAIP.js} +41 -36
  193. package/chunks/{edit-HHGIOTQ2.js → edit-YQZWCISX.js} +40 -35
  194. package/chunks/{en-NBK3JKCE.js → en-RESOFG55.js} +46 -5
  195. package/chunks/{enter-worktree-ZN7PUQ46.js → enter-worktree-WLVWI3FP.js} +40 -35
  196. package/chunks/{enterPlanMode-EIFIDSIV.js → enterPlanMode-6RYXFQUD.js} +40 -35
  197. package/chunks/{environment-XXQ75D2Q.js → environment-DXJTXSVT.js} +43 -38
  198. package/chunks/{errors-4GMVU7CK.js → errors-XGAGG2S2.js} +43 -38
  199. package/chunks/{exit-worktree-GXMI4ATY.js → exit-worktree-C4276VPP.js} +40 -35
  200. package/chunks/{exitPlanMode-34UVY7M6.js → exitPlanMode-MM5HIRUF.js} +40 -35
  201. package/chunks/{fast-path-VPIVA7L6.js → fast-path-PIXYOHCH.js} +6 -2
  202. package/chunks/{fr-4KG5V7UT.js → fr-QF7RI5ZE.js} +46 -5
  203. package/chunks/{gemini-4BWIK4WD.js → gemini-43RLVUNP.js} +158 -96
  204. package/chunks/{geminiContentGenerator-3XVV5MSS.js → geminiContentGenerator-PNQ4TSID.js} +6 -6
  205. package/chunks/{glob-TZ2ABCJG.js → glob-ZMBQKAU5.js} +40 -35
  206. package/chunks/goal-tools-Y767F7LZ.js +335 -0
  207. package/chunks/{grep-BEF463NA.js → grep-HSV37W2Q.js} +40 -35
  208. package/chunks/handleAutoUpdate-QDHZPBAY.js +85 -0
  209. package/chunks/{i18n-FMM5FDXR.js → i18n-ME22A6RN.js} +42 -37
  210. package/chunks/{image-gen-HHVLF7HS.js → image-gen-IFC7ZWSB.js} +9 -9
  211. package/chunks/{initializer-625TIAIO.js → initializer-J7H2CHVB.js} +47 -42
  212. package/chunks/{installationInfo-6AM4I2Y3.js → installationInfo-R7FXPQN5.js} +41 -36
  213. package/chunks/{ja-F3GSQXMF.js → ja-URQESVGW.js} +46 -5
  214. package/chunks/{keychain-token-storage-72IYCAZV.js → keychain-token-storage-7BT4TQ2A.js} +2 -2
  215. package/chunks/{kittyProtocolDetector-MBRTDRBK.js → kittyProtocolDetector-BFLAKYXH.js} +1 -1
  216. package/chunks/list-OYDIBA4N.js +93 -0
  217. package/chunks/{list-agents-R6KDXQR3.js → list-agents-GATIBBQQ.js} +2 -2
  218. package/chunks/{loadedSettingsAdapter-SPUTNKAV.js → loadedSettingsAdapter-OK6GK2GE.js} +46 -41
  219. package/chunks/{loggingContentGenerator-LKOF7XI7.js → loggingContentGenerator-U4ZEG4GL.js} +53 -38
  220. package/chunks/{loop-wakeup-3IQKCYAH.js → loop-wakeup-3DZMQQQQ.js} +13 -6
  221. package/chunks/{ls-DKZ37A7N.js → ls-7F4GHXIH.js} +4 -4
  222. package/chunks/{lsp-QNWN7KN3.js → lsp-6FEHVBWI.js} +2 -2
  223. package/chunks/{managed-npm-update-ACQGGIN5.js → managed-npm-update-PGKAJLLO.js} +43 -38
  224. package/chunks/mcp-S4DXJD2G.js +87 -0
  225. package/chunks/{monitor-DF52UVHI.js → monitor-E5ZFMT74.js} +40 -35
  226. package/chunks/nonInteractiveCli-HNOHKEPE.js +149 -0
  227. package/chunks/{notebook-edit-FCWS4XVN.js → notebook-edit-6QDN6VZJ.js} +40 -35
  228. package/chunks/{openaiContentGenerator-7LDK3DCJ.js → openaiContentGenerator-3NLB2C5O.js} +19 -19
  229. package/chunks/{pidfile-6ERW3DF4.js → pidfile-ZMOIUGG6.js} +41 -36
  230. package/chunks/{processUtils-COKZAMUP.js → processUtils-E4QGQVWW.js} +2 -2
  231. package/chunks/{pt-EQ33KWEN.js → pt-EEEQXRUI.js} +46 -5
  232. package/chunks/{qwenContentGenerator-TKWUMR7N.js → qwenContentGenerator-2LFRWJTM.js} +46 -41
  233. package/chunks/{qwenOAuth2-7HMU47SF.js → qwenOAuth2-N32BUQDC.js} +8 -8
  234. package/chunks/{read-file-X6DRC574.js → read-file-GLDCWZBG.js} +11 -11
  235. package/chunks/{read-mcp-resource-GFTWYXMK.js → read-mcp-resource-AFS3UKZO.js} +2 -2
  236. package/chunks/record-artifact-ECZSCEG5.js +21 -0
  237. package/chunks/{resumeHistoryUtils-PFPM2GWM.js → resumeHistoryUtils-F5BE5QDW.js} +48 -43
  238. package/chunks/ripGrep-T23Y4AGY.js +77 -0
  239. package/chunks/{ru-7OZAUKGG.js → ru-WGZDYQAB.js} +46 -5
  240. package/chunks/{run-qwen-serve-TSTCO4XE.js → run-qwen-serve-TI2HGLLU.js} +290 -75
  241. package/chunks/{runtime-DAUPSUKI.js → runtime-WCWM3DO7.js} +53 -46
  242. package/chunks/{scheduler-KMADMT26.js → scheduler-2QZO5AV5.js} +40 -35
  243. package/chunks/{sdk-exporters-http-WO556XNU.js → sdk-exporters-http-IKNWQJNV.js} +3 -3
  244. package/chunks/{sdk-impl-LPAVACSF.js → sdk-impl-7CUUMQDB.js} +3 -3
  245. package/chunks/{send-message-SAWK4DZX.js → send-message-X7G2JSII.js} +6 -11
  246. package/chunks/{serve-NNRWS6F4.js → serve-DZOMYUFU.js} +46 -41
  247. package/chunks/{server-WEH7DVCH.js → server-N4AJRKIQ.js} +2269 -1016
  248. package/chunks/{session-WXC56V2I.js → session-GS6AKMN7.js} +151 -86
  249. package/chunks/{settings-DJDXFDZ3.js → settings-CUN3SELH.js} +50 -45
  250. package/chunks/{shell-JN5VRQXD.js → shell-NGBFVXC5.js} +40 -35
  251. package/chunks/{skill-SGXPKJCS.js → skill-SC2BSO75.js} +30 -16
  252. package/chunks/{skill-settings-VJ5PDMZI.js → skill-settings-XVPCPW5K.js} +45 -40
  253. package/chunks/{spawnChannel-ETMJW7YX.js → spawnChannel-RILO4YY3.js} +42 -37
  254. package/chunks/{standalone-update-MK3Z7KBI.js → standalone-update-TMLT6LVJ.js} +43 -38
  255. package/chunks/{startInteractiveUI-ZCGIXPGT.js → startInteractiveUI-J45WOEOU.js} +883 -1112
  256. package/chunks/{syntheticOutput-355CB6CJ.js → syntheticOutput-FHRY3BPQ.js} +3 -3
  257. package/chunks/{task-create-INGWNUG4.js → task-create-LAQXBIHC.js} +11 -10
  258. package/chunks/{task-list-5XNNGTF4.js → task-list-V6K5DRDH.js} +6 -6
  259. package/chunks/{task-stop-4ROAOBXH.js → task-stop-LQXE52L6.js} +2 -2
  260. package/chunks/{task-update-CRK5VWWZ.js → task-update-NXRCXSPB.js} +11 -10
  261. package/chunks/{team-create-QQGAJG7P.js → team-create-W3EVWCTA.js} +40 -35
  262. package/chunks/{team-delete-S2RCXA4P.js → team-delete-Z4KGO7RC.js} +6 -6
  263. package/chunks/{team-plan-approval-RT7Q5R6O.js → team-plan-approval-URYVKJF4.js} +40 -35
  264. package/chunks/theme-manager-CUAMS2NI.js +81 -0
  265. package/chunks/{todoWrite-7WM3VDMY.js → todoWrite-OFIZDI7P.js} +32 -4
  266. package/chunks/{tool-search-Z3Z4AYKP.js → tool-search-DCICFL32.js} +15 -14
  267. package/chunks/total-session-admission-3ZTAXVUK.js +89 -0
  268. package/chunks/{trustedFolders-X2JEIO57.js → trustedFolders-EVCN36O5.js} +42 -37
  269. package/chunks/{update-relaunch-VWNPYDIP.js → update-relaunch-XLW46RHQ.js} +5 -5
  270. package/chunks/{updateCheck-KAQH67DV.js → updateCheck-ZHVXDAIH.js} +44 -39
  271. package/chunks/{useAutoAcceptIndicator-JH6BCF7S.js → useAutoAcceptIndicator-ZGD6BJSP.js} +50 -45
  272. package/chunks/{validateNonInterActiveAuth-GIUJ2UFS.js → validateNonInterActiveAuth-R3BAQFDY.js} +88 -83
  273. package/chunks/{version-BGLYIJUY.js → version-PMWREGCG.js} +1 -1
  274. package/chunks/{web-fetch-OTDU4VQF.js → web-fetch-PGN27SGF.js} +14 -14
  275. package/chunks/{web-search-FP6SIHPR.js → web-search-KW4UNMRE.js} +8 -8
  276. package/chunks/{workflow-YCIVBYSB.js → workflow-SN3TJBTJ.js} +363 -310
  277. package/chunks/workspace-providers-status-O3HUZGGR.js +90 -0
  278. package/chunks/{workspace-registration-store-OTMS3H4C.js → workspace-registration-store-M3FJ74RS.js} +2 -2
  279. package/chunks/{workspace-registry-O63R6IZ4.js → workspace-registry-U7ISW23N.js} +47 -42
  280. package/chunks/{workspace-service-M6LLHKJ5.js → workspace-service-VH6IWADT.js} +53 -48
  281. package/chunks/{workspace-skills-status-C2V7BAIS.js → workspace-skills-status-XANARSZS.js} +48 -43
  282. package/chunks/{workspace-trust-reconciler-IBUPOUJN.js → workspace-trust-reconciler-35EFR4GC.js} +53 -48
  283. package/chunks/write-file-NCRSGUDT.js +79 -0
  284. package/chunks/{zh-H3YDK5QW.js → zh-OHX23Q44.js} +43 -5
  285. package/chunks/{zh-TW-JYCP7XUA.js → zh-TW-4G7YKDAQ.js} +43 -5
  286. package/chunks/zoom-image-X7CIADYC.js +224 -0
  287. package/cli.js +55 -48
  288. package/locales/ca.js +60 -4
  289. package/locales/de.js +62 -4
  290. package/locales/en.js +59 -4
  291. package/locales/fr.js +64 -4
  292. package/locales/ja.js +61 -4
  293. package/locales/pt.js +60 -4
  294. package/locales/ru.js +63 -4
  295. package/locales/zh-TW.js +52 -4
  296. package/locales/zh.js +52 -4
  297. package/package.json +3 -3
  298. package/web-shell/assets/{arc-75-Wdeo3.js → arc-CaMTqKio.js} +1 -1
  299. package/web-shell/assets/{architectureDiagram-3BPJPVTR-FKeXQbyP.js → architectureDiagram-3BPJPVTR-Bjxztij2.js} +1 -1
  300. package/web-shell/assets/{blockDiagram-GPEHLZMM-CY0vc-A3.js → blockDiagram-GPEHLZMM-BYJzeHi9.js} +1 -1
  301. package/web-shell/assets/{c4Diagram-AAUBKEIU-CNP-A-8u.js → c4Diagram-AAUBKEIU-fYAa-Eil.js} +1 -1
  302. package/web-shell/assets/channel-LEZei0-5.js +1 -0
  303. package/web-shell/assets/{chunk-2J33WTMH-GybS4Gii.js → chunk-2J33WTMH-B1OTlTml.js} +1 -1
  304. package/web-shell/assets/{chunk-4BX2VUAB-02H91V8v.js → chunk-4BX2VUAB-DNj4uy6k.js} +1 -1
  305. package/web-shell/assets/{chunk-55IACEB6-D3M-2VT6.js → chunk-55IACEB6-DAqNmg3c.js} +1 -1
  306. package/web-shell/assets/{chunk-727SXJPM-CCu29u4H.js → chunk-727SXJPM-BwB4ddxE.js} +1 -1
  307. package/web-shell/assets/{chunk-AQP2D5EJ-CaFKWgrn.js → chunk-AQP2D5EJ-DmHR_UZs.js} +1 -1
  308. package/web-shell/assets/{chunk-FMBD7UC4-ZZpPqIwQ.js → chunk-FMBD7UC4-BlfOXumo.js} +1 -1
  309. package/web-shell/assets/{chunk-ND2GUHAM-D22DqGs8.js → chunk-ND2GUHAM-BKogiSy7.js} +1 -1
  310. package/web-shell/assets/{chunk-QZHKN3VN-Bu85S0fw.js → chunk-QZHKN3VN-DEclVrOF.js} +1 -1
  311. package/web-shell/assets/classDiagram-4FO5ZUOK-BiaRhfvf.js +1 -0
  312. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BiaRhfvf.js +1 -0
  313. package/web-shell/assets/{cose-bilkent-S5V4N54A-f1CK1Gwe.js → cose-bilkent-S5V4N54A-CwtS21WT.js} +1 -1
  314. package/web-shell/assets/{dagre-BM42HDAG-D0Ow8F_n.js → dagre-BM42HDAG-BAAIlB4p.js} +1 -1
  315. package/web-shell/assets/{diagram-2AECGRRQ-BPrmTWp8.js → diagram-2AECGRRQ-ChljtF_V.js} +1 -1
  316. package/web-shell/assets/{diagram-5GNKFQAL-HccuFAzy.js → diagram-5GNKFQAL-BIXVd31-.js} +1 -1
  317. package/web-shell/assets/{diagram-KO2AKTUF-BrS76mbA.js → diagram-KO2AKTUF-BEiBaS15.js} +1 -1
  318. package/web-shell/assets/{diagram-LMA3HP47-V7T9lU-5.js → diagram-LMA3HP47-C-g4tWKM.js} +1 -1
  319. package/web-shell/assets/{diagram-OG6HWLK6-DKidyJMR.js → diagram-OG6HWLK6-CNCCbNQG.js} +1 -1
  320. package/web-shell/assets/{erDiagram-TEJ5UH35-DBadZIkp.js → erDiagram-TEJ5UH35-v8ysnsdI.js} +1 -1
  321. package/web-shell/assets/{flowDiagram-I6XJVG4X-BymfqdNJ.js → flowDiagram-I6XJVG4X-LKVlLjwA.js} +1 -1
  322. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DOw340jf.js → ganttDiagram-6RSMTGT7-DA5MrKYG.js} +1 -1
  323. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-_8EiD8sl.js → gitGraphDiagram-PVQCEYII-Cyg5fe6d.js} +1 -1
  324. package/web-shell/assets/index-BgOcEaVt.js +1756 -0
  325. package/web-shell/assets/index-C2GE3DAF.js +74 -0
  326. package/web-shell/assets/{index-CKIadvET.js → index-CKdUkVVS.js} +1 -1
  327. package/web-shell/assets/index-DA5Lvscv.css +5 -0
  328. package/web-shell/assets/{infoDiagram-5YYISTIA-D61KYQBu.js → infoDiagram-5YYISTIA-SLsfu3Qd.js} +1 -1
  329. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CsiXSpNx.js → ishikawaDiagram-YF4QCWOH-CmHOmTNx.js} +1 -1
  330. package/web-shell/assets/{journeyDiagram-JHISSGLW-Sdfionyh.js → journeyDiagram-JHISSGLW-C3gM_HFQ.js} +1 -1
  331. package/web-shell/assets/{kanban-definition-UN3LZRKU-C3WI3Cnl.js → kanban-definition-UN3LZRKU-BbHD7duM.js} +1 -1
  332. package/web-shell/assets/{linear-Dpigcc62.js → linear-CSBvm435.js} +1 -1
  333. package/web-shell/assets/{mermaid.core-Ct97pqgW.js → mermaid.core-CPMw15lU.js} +5 -5
  334. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BzeaN0rB.js → mindmap-definition-RKZ34NQL-C_tNqXQW.js} +1 -1
  335. package/web-shell/assets/{pieDiagram-4H26LBE5-CvjgcbVD.js → pieDiagram-4H26LBE5-DH_N-8yY.js} +1 -1
  336. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BUzgTNdH.js → quadrantDiagram-W4KKPZXB-CRbS8UkN.js} +1 -1
  337. package/web-shell/assets/{requirementDiagram-4Y6WPE33-B7zKlgUQ.js → requirementDiagram-4Y6WPE33-DJgdZPZn.js} +1 -1
  338. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Bb9CQgrT.js → sankeyDiagram-5OEKKPKP-vhL1y5zx.js} +1 -1
  339. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DJ6V7itG.js → sequenceDiagram-3UESZ5HK-UQthhFwd.js} +1 -1
  340. package/web-shell/assets/{stateDiagram-AJRCARHV-IImflERY.js → stateDiagram-AJRCARHV-CAywEm20.js} +1 -1
  341. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-lfJQHw-7.js +1 -0
  342. package/web-shell/assets/{timeline-definition-PNZ67QCA-6Q_uWHKh.js → timeline-definition-PNZ67QCA-CLO8b3FD.js} +1 -1
  343. package/web-shell/assets/{vennDiagram-CIIHVFJN-TmyKyjwv.js → vennDiagram-CIIHVFJN-BNAAh0Mu.js} +1 -1
  344. package/web-shell/assets/{wardley-L42UT6IY-CRh9uiPv.js → wardley-L42UT6IY-CUY7bLpN.js} +1 -1
  345. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-59TKAW8w.js → wardleyDiagram-YWT4CUSO-CSg_ORdW.js} +1 -1
  346. package/web-shell/assets/{xychartDiagram-2RQKCTM6-GCSUIK2L.js → xychartDiagram-2RQKCTM6-BjffV208.js} +1 -1
  347. package/web-shell/index.html +2 -2
  348. package/chunks/agent-headless-NO4Y2HOE.js +0 -74
  349. package/chunks/chunk-6QIGFD5W.js +0 -82
  350. package/chunks/chunk-HGT6JR3U.js +0 -177
  351. package/chunks/daemon-status-provider-3XJI6CAL.js +0 -89
  352. package/chunks/handleAutoUpdate-L6ERF36Y.js +0 -80
  353. package/chunks/list-L2GA674Y.js +0 -88
  354. package/chunks/mcp-SZLHKFJW.js +0 -82
  355. package/chunks/nonInteractiveCli-5T7KYKLK.js +0 -144
  356. package/chunks/ripGrep-OWV2IVJC.js +0 -72
  357. package/chunks/theme-manager-EEWIQJ7J.js +0 -76
  358. package/chunks/total-session-admission-44JKRWQD.js +0 -84
  359. package/chunks/workspace-providers-status-S35YAIUS.js +0 -85
  360. package/chunks/write-file-3BZC3EAE.js +0 -72
  361. package/chunks/zoom-image-TZ6S2O57.js +0 -351
  362. package/web-shell/assets/channel-DPYMT76A.js +0 -1
  363. package/web-shell/assets/classDiagram-4FO5ZUOK--JstsIgL.js +0 -1
  364. package/web-shell/assets/classDiagram-v2-Q7XG4LA2--JstsIgL.js +0 -1
  365. package/web-shell/assets/index-D1eXNRHe.js +0 -1389
  366. package/web-shell/assets/index-DVLD4CQq.css +0 -5
  367. 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,
@@ -13,6 +8,7 @@ import {
13
8
  formatWorkspaceMemoryDreamSummary,
14
9
  formatWorkspaceMemoryForgetSummary,
15
10
  isValidServerName,
11
+ loadSettingsCached,
16
12
  normalizeChannelDelivery,
17
13
  parseChannelDelivery,
18
14
  redactMcpServersSetting,
@@ -21,7 +17,12 @@ import {
21
17
  shouldSuppressRememberErrorDetails,
22
18
  workspaceMemoryFailureCode,
23
19
  workspaceMemoryFailureDiagnostics
24
- } from "./chunk-6PE7N3A4.js";
20
+ } from "./chunk-5UJ6A3CH.js";
21
+ import {
22
+ openQwenAsrRealtimeStream,
23
+ openVoiceStream,
24
+ openVoiceStreamWithRetry
25
+ } from "./chunk-GTM6IHBB.js";
25
26
  import {
26
27
  SetupGithubError,
27
28
  collectSessionData,
@@ -33,13 +34,13 @@ import {
33
34
  toJson,
34
35
  toJsonl,
35
36
  toMarkdown
36
- } from "./chunk-LO4ROVP4.js";
37
+ } from "./chunk-UOFFZNXV.js";
37
38
  import {
38
39
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
39
40
  ObservedChannelContactStore
40
- } from "./chunk-LGAOC3ZS.js";
41
- import "./chunk-XFZYFU3I.js";
42
- import "./chunk-YDLJGZHL.js";
41
+ } from "./chunk-DYA25Y7U.js";
42
+ import "./chunk-4NFY2S7N.js";
43
+ import "./chunk-UHQ3L6GC.js";
43
44
  import "./chunk-2MIN6GRR.js";
44
45
  import "./chunk-QHTIBUWB.js";
45
46
  import "./chunk-QTERJVPZ.js";
@@ -101,14 +102,18 @@ import {
101
102
  setRateLimiter,
102
103
  unsafeRevealSecret,
103
104
  validateMcpRuntimeServerName
104
- } from "./chunk-YGF33UXG.js";
105
+ } from "./chunk-H6MC6VQX.js";
105
106
  import {
106
107
  isLoopbackBind
107
108
  } from "./chunk-RXFQM6FQ.js";
109
+ import {
110
+ createWorkspaceSkillsStatusProvider
111
+ } from "./chunk-H4346YW5.js";
112
+ import "./chunk-BGXZBI5B.js";
108
113
  import {
109
114
  evaluateDaemonWorkspaceTrust,
110
115
  readDaemonTrustPolicySnapshot
111
- } from "./chunk-HV26XH34.js";
116
+ } from "./chunk-XFDPIC4P.js";
112
117
  import {
113
118
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
114
119
  MAX_WORKSPACE_SKILL_NAME_LENGTH,
@@ -122,14 +127,14 @@ import {
122
127
  validateWorkspaceSkillName,
123
128
  validateWorkspaceVoiceState,
124
129
  voiceSettingsScopeToWire
125
- } from "./chunk-P4WOAOJW.js";
130
+ } from "./chunk-7MY2AR5A.js";
126
131
  import {
127
132
  PermissionRulesValidationError,
128
133
  buildPermissionSettings,
129
134
  isPermissionRuleType,
130
135
  normalizePermissionRules,
131
136
  readPermissionRuleSet
132
- } from "./chunk-MR5EAQ5M.js";
137
+ } from "./chunk-GALUTA2C.js";
133
138
  import {
134
139
  assertVoiceBaseUrlNetworkAllowed,
135
140
  isStreamingVoiceModel,
@@ -137,13 +142,13 @@ import {
137
142
  resolveVoiceTranscriptionConfig,
138
143
  sanitizeVoiceErrorMessage,
139
144
  transcribeVoiceAudio
140
- } from "./chunk-CAPPWD3X.js";
145
+ } from "./chunk-2A6MHYIA.js";
141
146
  import {
142
147
  isVoiceEnabled,
143
148
  isVoiceMode,
144
149
  readVoiceModel
145
- } from "./chunk-JTV5K7NH.js";
146
- import "./chunk-ZHBO7WVX.js";
150
+ } from "./chunk-XSA5EKTJ.js";
151
+ import "./chunk-JELIWHXD.js";
147
152
  import {
148
153
  WorkspacePermissionRulesSessionRequiredError,
149
154
  WorkspaceSettingsPartialPersistError,
@@ -152,28 +157,28 @@ import {
152
157
  } from "./chunk-OA4JVLSA.js";
153
158
  import {
154
159
  createTotalSessionAdmissionController
155
- } from "./chunk-SZ3KHTDR.js";
160
+ } from "./chunk-AKA24BGO.js";
156
161
  import {
157
162
  WorkspaceGenerationClosedError,
158
163
  createSingleWorkspaceRegistry,
159
164
  createWorkspaceSessionOwnerIndex
160
- } from "./chunk-JYBU6YUE.js";
165
+ } from "./chunk-2M5N3DHY.js";
161
166
  import "./chunk-GRC5HGPI.js";
162
167
  import {
163
168
  assertValidChannelSecretUpdates
164
- } from "./chunk-5ZF5XXTS.js";
169
+ } from "./chunk-GVISB2OH.js";
165
170
  import {
166
171
  createDaemonStatusProvider
167
- } from "./chunk-TBBV36Y4.js";
172
+ } from "./chunk-KXSYDCP2.js";
168
173
  import "./chunk-VXZBKKQR.js";
169
- import "./chunk-QIZKCVM3.js";
170
- import "./chunk-E5Z2AVNV.js";
174
+ import "./chunk-GHJM2C2T.js";
175
+ import "./chunk-3SH53ANB.js";
171
176
  import {
172
177
  SessionArtifactAuthorizationError,
173
178
  SessionArtifactValidationError,
174
179
  createAcpSessionBridge,
175
180
  parseSessionSource
176
- } from "./chunk-ZURDMIDR.js";
181
+ } from "./chunk-3MHPWQ2M.js";
177
182
  import {
178
183
  EVENT_SCHEMA_VERSION,
179
184
  EventBus,
@@ -181,41 +186,37 @@ import {
181
186
  } from "./chunk-GLWP3FDB.js";
182
187
  import "./chunk-XCGIMOLN.js";
183
188
  import "./chunk-OCPBI7J5.js";
184
- import "./chunk-KAMYKP7E.js";
189
+ import "./chunk-UWSXFI6E.js";
185
190
  import {
186
191
  createWorkspaceProvidersStatusProvider
187
- } from "./chunk-3EFXSQCM.js";
192
+ } from "./chunk-JRIDA5HF.js";
188
193
  import {
189
194
  getAuthTypeFromEnv,
190
195
  resolveCliGenerationConfig
191
- } from "./chunk-KCO4FLFJ.js";
196
+ } from "./chunk-AYB4HSBI.js";
192
197
  import {
193
198
  snapshotProcessEnv
194
- } from "./chunk-2FAK6PNM.js";
195
- import {
196
- createWorkspaceSkillsStatusProvider
197
- } from "./chunk-UBEPNVDI.js";
198
- import "./chunk-L55JWS76.js";
199
+ } from "./chunk-DUIJ2IXG.js";
199
200
  import {
200
201
  STATUS_SCHEMA_VERSION,
201
202
  createIdleWorkspaceMemoryStatus,
202
203
  mapDomainErrorToErrorKind
203
- } from "./chunk-FTD6DP4T.js";
204
+ } from "./chunk-PDDYAXL2.js";
204
205
  import "./chunk-Z4X5MTRT.js";
205
- import "./chunk-WBL3FJEU.js";
206
+ import "./chunk-FC4KQFCS.js";
206
207
  import {
207
208
  daemonObservedContactsPath,
208
209
  loadChannelsConfig
209
- } from "./chunk-BNWB5CYE.js";
210
- import "./chunk-5MKRTI4T.js";
210
+ } from "./chunk-3WXMXT7C.js";
211
+ import "./chunk-BKUN5QHP.js";
211
212
  import "./chunk-57OAHC2Y.js";
212
213
  import {
213
214
  parseChannelWebhookConfigLenient
214
- } from "./chunk-2XSLTRFZ.js";
215
- import "./chunk-TFRMVU6R.js";
215
+ } from "./chunk-2CTKGIFR.js";
216
+ import "./chunk-K4CGQN4Q.js";
216
217
  import {
217
218
  supportedChannelCatalog
218
- } from "./chunk-XBYYDKAZ.js";
219
+ } from "./chunk-ZTN6OA5J.js";
219
220
  import "./chunk-V6WHFGST.js";
220
221
  import {
221
222
  MAX_REGISTERED_WORKSPACES,
@@ -224,8 +225,8 @@ import {
224
225
  WorkspaceRegistrationStoreLimitError,
225
226
  normalizeWorkspaceDisplayName,
226
227
  workspaceRegistrationId
227
- } from "./chunk-AQIDMUGU.js";
228
- import "./chunk-XZC5VLBZ.js";
228
+ } from "./chunk-2PNQQ4UR.js";
229
+ import "./chunk-UKZEXS6K.js";
229
230
  import {
230
231
  BranchWhilePromptActiveError,
231
232
  CancelSentinelCollisionError,
@@ -258,13 +259,13 @@ import {
258
259
  WorkspaceInitRaceError,
259
260
  WorkspaceInitSymlinkError,
260
261
  WorkspaceMismatchError
261
- } from "./chunk-B4AJNNOL.js";
262
+ } from "./chunk-J26HHFI5.js";
262
263
  import {
263
264
  MAX_WORKSPACE_PATH_LENGTH,
264
265
  canonicalizeWorkspace,
265
266
  canonicalizeWorkspaces,
266
267
  translateAndCheckAbsoluteWorkspacePath
267
- } from "./chunk-2RFKHEXL.js";
268
+ } from "./chunk-6PLDPT2C.js";
268
269
  import {
269
270
  ChannelDeliveryError,
270
271
  MAX_CHANNEL_STARTUP_FAILURES,
@@ -274,10 +275,10 @@ import {
274
275
  QWEN_SERVER_TOKEN_ENV,
275
276
  isChannelDeliveryError,
276
277
  isChannelWebhookEnqueueError
277
- } from "./chunk-U4VTUMMK.js";
278
+ } from "./chunk-QONSRAEV.js";
278
279
  import {
279
280
  normalizeWorkerDiagnostic
280
- } from "./chunk-GZ3RCT54.js";
281
+ } from "./chunk-UHTJC7O3.js";
281
282
  import {
282
283
  normalizeServeChannelSelection
283
284
  } from "./chunk-ALMR3E6Q.js";
@@ -286,10 +287,11 @@ import {
286
287
  redactLogCredentials
287
288
  } from "./chunk-M5GB774H.js";
288
289
  import "./chunk-5HBA2Z7V.js";
289
- import "./chunk-T2NCM2ET.js";
290
+ import "./chunk-K6KS3LTN.js";
291
+ import "./chunk-T3CHYWJZ.js";
290
292
  import {
291
293
  sanitizeLogText
292
- } from "./chunk-7I5GTCT4.js";
294
+ } from "./chunk-GB3AB7TR.js";
293
295
  import "./chunk-UDXSXLER.js";
294
296
  import {
295
297
  getDialogSettingKeys,
@@ -300,31 +302,27 @@ import {
300
302
  getWritableScopes,
301
303
  loadSettings,
302
304
  validateSettingValue
303
- } from "./chunk-EIF3FXTB.js";
305
+ } from "./chunk-LAPK3GLC.js";
304
306
  import "./chunk-RKUWKYED.js";
307
+ import "./chunk-GOXKNSDZ.js";
308
+ import "./chunk-IDS7MSUP.js";
305
309
  import {
306
310
  SUPPORTED_LANGUAGES,
307
311
  detectSystemLanguage,
308
312
  resolveLanguageSetting,
309
313
  resolveSupportedLanguage
310
- } from "./chunk-TCIFAA7K.js";
311
- import "./chunk-2N7CODY5.js";
312
- import "./chunk-GOXKNSDZ.js";
313
- import "./chunk-IDS7MSUP.js";
314
+ } from "./chunk-CHCLO3M7.js";
315
+ import "./chunk-AQEWCKX4.js";
314
316
  import "./chunk-6PEXNQTX.js";
315
- import "./chunk-VYOXCEPJ.js";
316
- import "./chunk-VJNBRRZG.js";
317
317
  import {
318
318
  getWorkspaceTrustStatus
319
- } from "./chunk-Q43KPN7X.js";
319
+ } from "./chunk-434YCHSV.js";
320
320
  import "./chunk-ALGGS7UH.js";
321
321
  import {
322
322
  isWithinRoot as isWithinRoot2
323
323
  } from "./chunk-MR3PXB6E.js";
324
- import {
325
- writeStderrLine,
326
- writeStderrLineSafe
327
- } from "./chunk-OWAK7LMW.js";
324
+ import "./chunk-MBKPUM5Y.js";
325
+ import "./chunk-VJNBRRZG.js";
328
326
  import {
329
327
  ALL_PROVIDERS,
330
328
  BTW_MAX_INPUT_LENGTH,
@@ -398,19 +396,20 @@ import {
398
396
  writeWorkspaceContextFile,
399
397
  writeWorktreeSession,
400
398
  writeWorktreeSessionMarker
401
- } from "./chunk-X5WNMMIA.js";
399
+ } from "./chunk-NGWYUZZO.js";
400
+ import "./chunk-GOFAQQZA.js";
401
+ import "./chunk-5M6IDOMF.js";
402
402
  import "./chunk-TWPJO254.js";
403
403
  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
404
  import {
411
405
  MAX_JOBS,
412
406
  nextDurableFireMs
413
- } from "./chunk-CVHIL5IG.js";
407
+ } from "./chunk-CWEIMFFW.js";
408
+ import "./chunk-I7JDGNG6.js";
409
+ import "./chunk-A6SX5TAH.js";
410
+ import "./chunk-33FNCQSY.js";
411
+ import "./chunk-6PVPNMXU.js";
412
+ import "./chunk-PXA5AWHY.js";
414
413
  import {
415
414
  nextFireTime,
416
415
  parseCron
@@ -423,22 +422,26 @@ import {
423
422
  readCronTasks,
424
423
  taskHasLegacyCondition,
425
424
  updateCronTasks
426
- } from "./chunk-PONHVBRT.js";
425
+ } from "./chunk-MOHAWIAW.js";
426
+ import "./chunk-MYT7N6QH.js";
427
+ import "./chunk-O6GEWCJA.js";
427
428
  import "./chunk-T26EAKDL.js";
428
- import "./chunk-6PVPNMXU.js";
429
429
  import "./chunk-CPBF7KYF.js";
430
- import "./chunk-6QIGFD5W.js";
431
- import "./chunk-XWWKIXVD.js";
432
- import "./chunk-75GFAX4R.js";
433
- import "./chunk-OKF7JF3R.js";
430
+ import "./chunk-MISUEWB4.js";
431
+ import "./chunk-KRXPRVGL.js";
432
+ import "./chunk-A5YZ3FA2.js";
433
+ import "./chunk-YAVY33G4.js";
434
+ import "./chunk-2UISUFHQ.js";
435
+ import "./chunk-6FMJLI5M.js";
434
436
  import {
435
437
  APPROVAL_MODES,
436
438
  SubagentError,
437
439
  SubagentErrorCode
438
- } from "./chunk-JSD33JG6.js";
440
+ } from "./chunk-PGEGUNH5.js";
439
441
  import "./chunk-S6LOFUVP.js";
440
- import "./chunk-JCW2R7WC.js";
441
- import "./chunk-2DN4J57Y.js";
442
+ import "./chunk-K623ENWT.js";
443
+ import "./chunk-AQ37AY7B.js";
444
+ import "./chunk-432XCUHF.js";
442
445
  import "./chunk-ZPJWUGCS.js";
443
446
  import {
444
447
  QwenOAuth2Client,
@@ -448,15 +451,15 @@ import {
448
451
  isDeviceAuthorizationSuccess,
449
452
  isDeviceTokenPending,
450
453
  isDeviceTokenSuccess
451
- } from "./chunk-2LKVPASC.js";
454
+ } from "./chunk-XC656O42.js";
452
455
  import "./chunk-NAVJD2PQ.js";
453
- import "./chunk-LW3RFMG7.js";
454
- import "./chunk-W4MIWP6M.js";
456
+ import "./chunk-QYPT3QUD.js";
457
+ import "./chunk-QMBEW7EW.js";
455
458
  import "./chunk-DGEIYUC3.js";
456
459
  import "./chunk-MPHPFVKK.js";
457
460
  import "./chunk-GLNBDYUX.js";
458
461
  import "./chunk-DJ2GSRLV.js";
459
- import "./chunk-5KTQXHPY.js";
462
+ import "./chunk-XCLLRKY5.js";
460
463
  import {
461
464
  addDaemonRequestAttribute,
462
465
  emitDaemonLog,
@@ -466,41 +469,49 @@ import {
466
469
  recordDaemonHttpRequest,
467
470
  recordDaemonHttpResponse,
468
471
  withDaemonRequestSpan
469
- } from "./chunk-75MIQ3LV.js";
472
+ } from "./chunk-RPYYTL7E.js";
470
473
  import "./chunk-2J3OJGTL.js";
471
474
  import "./chunk-P3QQPMQA.js";
472
- import "./chunk-RPLGZJV2.js";
475
+ import "./chunk-6O5DVH27.js";
473
476
  import "./chunk-GLCZKT5V.js";
474
- import "./chunk-DZLYR4U3.js";
477
+ import "./chunk-2DNKEBXY.js";
475
478
  import "./chunk-CR3C7WXL.js";
476
479
  import "./chunk-XWRJCPHC.js";
477
480
  import {
481
+ CursorNotAtLineBoundaryError,
482
+ LargeNonUtf8TextError,
483
+ TextScanBudgetExceededError,
478
484
  decodeBufferWithEncodingInfoAsync,
479
485
  getAllGeminiMdFilenames,
486
+ isUtf8CompatibleEncoding,
480
487
  isWithinRoot,
481
488
  parseLineTolerant,
482
489
  read
483
- } from "./chunk-PT722TDT.js";
490
+ } from "./chunk-M2F5PLOW.js";
484
491
  import "./chunk-VGC4I5JJ.js";
485
- import "./chunk-SGFT55XI.js";
486
- import "./chunk-Y4IHBGBP.js";
487
- import "./chunk-Y6AXW2OG.js";
488
- import "./chunk-VCPIZRYH.js";
492
+ import "./chunk-E4WHKETF.js";
493
+ import "./chunk-BV4QX43X.js";
494
+ import "./chunk-I5GNT6ZS.js";
495
+ import "./chunk-TFFMATHX.js";
489
496
  import "./chunk-46UV252V.js";
490
497
  import "./chunk-ZBVS26BY.js";
491
- import "./chunk-WZRWHXFE.js";
492
- import "./chunk-A3NDJ5SB.js";
493
- import "./chunk-7XATOOE7.js";
494
- import "./chunk-BGTQCTQW.js";
498
+ import "./chunk-BFHXDAR7.js";
499
+ import "./chunk-TYERNYH4.js";
500
+ import "./chunk-UH7Z7Y45.js";
501
+ import "./chunk-O2ZYHG33.js";
495
502
  import "./chunk-W4RQUHY3.js";
496
- import "./chunk-S7W2GKIO.js";
503
+ import "./chunk-G7XXKQYS.js";
497
504
  import {
498
505
  FatalConfigError,
499
506
  Storage,
500
507
  createDebugLogger,
501
508
  runWithoutDebugLogSession
502
- } from "./chunk-UHUSJ6X7.js";
509
+ } from "./chunk-3RXUYQJI.js";
503
510
  import "./chunk-VOQXFAY5.js";
511
+ import {
512
+ writeStderrLine,
513
+ writeStderrLineSafe
514
+ } from "./chunk-OWAK7LMW.js";
504
515
  import "./chunk-75DOP5OR.js";
505
516
  import "./chunk-DMTGGOSA.js";
506
517
  import "./chunk-YQ3U5MUC.js";
@@ -936,7 +947,9 @@ init_esbuild_shims();
936
947
  init_esbuild_shims();
937
948
  import * as path2 from "node:path";
938
949
  var MAX_READ_BYTES = 256 * 1024;
950
+ var MAX_TEXT_SCAN_BYTES = 8 * 1024 * 1024;
939
951
  var MAX_WRITE_BYTES = 5 * 1024 * 1024;
952
+ var BINARY_PROBE_BYTES = 4096;
940
953
  function shouldIgnore(absolute, boundWorkspace, ignore, kind = "file") {
941
954
  const rel = path2.relative(boundWorkspace, absolute);
942
955
  if (rel === "" || rel.startsWith("..")) return { ignored: false };
@@ -1089,6 +1102,64 @@ init_esbuild_shims();
1089
1102
  import { createHash as createHash2, randomBytes } from "node:crypto";
1090
1103
  import { constants as fsConstants, promises as fsp2 } from "node:fs";
1091
1104
  import * as path4 from "node:path";
1105
+
1106
+ // packages/cli/src/serve/fs/text-cursor.ts
1107
+ init_esbuild_shims();
1108
+ var CURSOR_VERSION = 1;
1109
+ var MAX_TEXT_CURSOR_CHARS = 1024;
1110
+ function encodeTextCursor(state) {
1111
+ return Buffer.from(
1112
+ JSON.stringify({ v: CURSOR_VERSION, ...state }),
1113
+ "utf8"
1114
+ ).toString("base64url");
1115
+ }
1116
+ __name(encodeTextCursor, "encodeTextCursor");
1117
+ function decodeTextCursor(cursor) {
1118
+ if (cursor.length === 0 || cursor.length > MAX_TEXT_CURSOR_CHARS) {
1119
+ throw new FsError(
1120
+ "parse_error",
1121
+ `cursor must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
1122
+ { hint: "pass a cursor returned by a previous read" }
1123
+ );
1124
+ }
1125
+ let parsed;
1126
+ try {
1127
+ parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
1128
+ } catch {
1129
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1130
+ hint: "pass a cursor returned by a previous read"
1131
+ });
1132
+ }
1133
+ if (typeof parsed !== "object" || parsed === null) {
1134
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1135
+ hint: "pass a cursor returned by a previous read"
1136
+ });
1137
+ }
1138
+ const raw = parsed;
1139
+ const off = raw["off"];
1140
+ const size = raw["size"];
1141
+ const dev = raw["dev"];
1142
+ const ino = raw["ino"];
1143
+ if (raw["v"] !== CURSOR_VERSION || !Number.isSafeInteger(off) || off < 0 || !Number.isSafeInteger(size) || size < 0 || typeof dev !== "string" || typeof ino !== "string") {
1144
+ throw new FsError("parse_error", "cursor is not a valid read cursor", {
1145
+ hint: "pass a cursor returned by a previous read"
1146
+ });
1147
+ }
1148
+ return { off, size, dev, ino };
1149
+ }
1150
+ __name(decodeTextCursor, "decodeTextCursor");
1151
+ function assertCursorMatchesFile(cursor, stats, path14) {
1152
+ if (String(stats.dev) !== cursor.dev || String(stats.ino) !== cursor.ino || stats.size < cursor.size) {
1153
+ throw new FsError(
1154
+ "hash_mismatch",
1155
+ `cursor no longer matches the file it was issued for: ${path14}`,
1156
+ { hint: "re-read the file from the beginning to get a fresh cursor" }
1157
+ );
1158
+ }
1159
+ }
1160
+ __name(assertCursorMatchesFile, "assertCursorMatchesFile");
1161
+
1162
+ // packages/cli/src/serve/fs/workspace-file-system.ts
1092
1163
  function createWorkspaceFileSystemFactory(deps) {
1093
1164
  const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
1094
1165
  if (boundWorkspaces.length === 0) {
@@ -1227,7 +1298,19 @@ var WorkspaceFileSystemImpl = class {
1227
1298
  `limit must be a positive integer, got ${opts.limit}`
1228
1299
  );
1229
1300
  }
1230
- const snapshot = await readTextSnapshotFromResolvedFile(p, opts);
1301
+ if (opts.cursor !== void 0 && opts.line !== void 0) {
1302
+ throw new FsError(
1303
+ "parse_error",
1304
+ "cursor and line are mutually exclusive; a cursor already encodes where to resume"
1305
+ );
1306
+ }
1307
+ if (opts.maxBytes !== void 0 && (!Number.isSafeInteger(opts.maxBytes) || opts.maxBytes < 1 || opts.maxBytes > MAX_READ_BYTES)) {
1308
+ throw new FsError(
1309
+ "parse_error",
1310
+ `maxBytes must be a positive integer in [1, ${MAX_READ_BYTES}], got ${opts.maxBytes}`
1311
+ );
1312
+ }
1313
+ const snapshot = await readTextFromResolvedFile(p, opts, this.deps.lowFs);
1231
1314
  this.deps.generationGuard?.assertOpen();
1232
1315
  const ignoreVerdict = this.ignoreVerdict(p, "file");
1233
1316
  const meta = snapshot.meta;
@@ -1882,7 +1965,7 @@ function validateWriteTextAtomicOptions(opts) {
1882
1965
  }
1883
1966
  }
1884
1967
  __name(validateWriteTextAtomicOptions, "validateWriteTextAtomicOptions");
1885
- async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1968
+ async function readTextFromResolvedFile(p, opts, lowFs) {
1886
1969
  const pre = await fsp2.lstat(p);
1887
1970
  if (pre.isSymbolicLink()) {
1888
1971
  throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
@@ -1892,12 +1975,32 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1892
1975
  if (!pre.isFile()) {
1893
1976
  throw new FsError("parse_error", `path is not a regular file: ${p}`);
1894
1977
  }
1978
+ if (opts.cursor !== void 0) {
1979
+ return readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs);
1980
+ }
1981
+ const wantsWindow = opts.limit !== void 0 || opts.maxBytes !== void 0 || opts.line !== void 0;
1982
+ if (pre.size > MAX_READ_BYTES && wantsWindow) {
1983
+ return readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs);
1984
+ }
1985
+ return readTextSnapshotFromResolvedFile(p, opts, pre);
1986
+ }
1987
+ __name(readTextFromResolvedFile, "readTextFromResolvedFile");
1988
+ async function readTextSnapshotFromResolvedFile(p, opts = {}, knownPre) {
1989
+ const pre = knownPre ?? await fsp2.lstat(p);
1990
+ if (pre.isSymbolicLink()) {
1991
+ throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
1992
+ hint: "re-resolve the target file instead of reading through a link"
1993
+ });
1994
+ }
1995
+ if (!pre.isFile()) {
1996
+ throw new FsError("parse_error", `path is not a regular file: ${p}`);
1997
+ }
1895
1998
  if (pre.size > MAX_READ_BYTES) {
1896
1999
  throw new FsError(
1897
2000
  "file_too_large",
1898
2001
  `file of ${pre.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
1899
2002
  {
1900
- hint: "use readBytes for explicit byte-windowed access on large files"
2003
+ hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
1901
2004
  }
1902
2005
  );
1903
2006
  }
@@ -1914,8 +2017,10 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1914
2017
  startLineIndex,
1915
2018
  opts.limit ?? Number.POSITIVE_INFINITY
1916
2019
  );
1917
- const sizeOutcome = enforceReadSize(raw.length, opts.maxBytes);
2020
+ const maxOutputBytes = opts.maxBytes ?? MAX_READ_BYTES;
2021
+ const sizeOutcome = enforceReadSize(raw.length, maxOutputBytes);
1918
2022
  let content = sliced.content;
2023
+ let byteTruncated = false;
1919
2024
  const meta = {
1920
2025
  encoding: decoded.encoding,
1921
2026
  bom: decoded.bom,
@@ -1924,22 +2029,243 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
1924
2029
  originalLineCount: sliced.originalLineCount,
1925
2030
  hash: hashBuffer(raw)
1926
2031
  };
2032
+ const output = Buffer.from(content, "utf-8");
2033
+ if (output.length > maxOutputBytes) {
2034
+ content = safeUtf8Truncate(output, maxOutputBytes).toString("utf-8");
2035
+ meta.lineEnding = detectLineEnding(content);
2036
+ meta.truncated = true;
2037
+ byteTruncated = true;
2038
+ }
1927
2039
  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
2040
  meta.truncated = true;
1936
2041
  }
1937
2042
  if (opts.limit !== void 0 && Number.isFinite(opts.limit) && sliced.originalLineCount > opts.limit + startLineIndex) {
1938
2043
  meta.truncated = true;
1939
2044
  }
2045
+ const pageableLineCount = sliced.originalLineCount - (decoded.content.endsWith("\n") ? 1 : 0);
2046
+ meta.hasMore = byteTruncated || sliced.endLine < pageableLineCount;
2047
+ const bomBytes = decoded.bom ? 3 : 0;
2048
+ const decodedBytesMatchSource = isUtf8CompatibleEncoding(decoded.encoding) && Buffer.from(decoded.content, "utf-8").equals(raw.subarray(bomBytes));
2049
+ if (meta.hasMore && !byteTruncated && decodedBytesMatchSource) {
2050
+ const startByte = bomBytes + sliced.startByteOffset;
2051
+ const contentBytes = Buffer.byteLength(content, "utf-8");
2052
+ const nextOffset = startByte + contentBytes + 1;
2053
+ if (nextOffset < raw.length) {
2054
+ meta.nextCursor = encodeTextCursor({
2055
+ off: nextOffset,
2056
+ size: raw.length,
2057
+ dev: String(pre.dev),
2058
+ ino: String(pre.ino)
2059
+ });
2060
+ }
2061
+ }
1940
2062
  return { content, meta };
1941
2063
  }
1942
2064
  __name(readTextSnapshotFromResolvedFile, "readTextSnapshotFromResolvedFile");
2065
+ function assertStreamWindowStable(before, after, p, reason) {
2066
+ const beforeSize = toBigInt(before.size);
2067
+ const afterSize = toBigInt(after.size);
2068
+ if (afterSize < beforeSize || afterSize === beforeSize && (after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)) {
2069
+ throw new FsError("hash_mismatch", `${reason}: ${p}`, {
2070
+ hint: "retry after re-reading the latest file"
2071
+ });
2072
+ }
2073
+ }
2074
+ __name(assertStreamWindowStable, "assertStreamWindowStable");
2075
+ async function readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs) {
2076
+ const cursor = decodeTextCursor(opts.cursor);
2077
+ const fh = await fsp2.open(p, "r");
2078
+ let opened;
2079
+ let afterRead;
2080
+ let window;
2081
+ let primaryError;
2082
+ let hasPrimaryError = false;
2083
+ try {
2084
+ opened = await fh.stat();
2085
+ assertSameFile(pre, opened, p, "read");
2086
+ assertStreamWindowStable(pre, opened, p, "file changed before read");
2087
+ assertCursorMatchesFile(cursor, opened, p);
2088
+ try {
2089
+ const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
2090
+ if (probe.length > 0) {
2091
+ const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
2092
+ if (looksBinary(probe.subarray(0, bytesRead))) {
2093
+ throw new FsError("binary_file", `binary file: ${p}`, {
2094
+ hint: "use readBytes for binary content"
2095
+ });
2096
+ }
2097
+ }
2098
+ window = await lowFs.readTextCursorFromHandle({
2099
+ fileHandle: fh,
2100
+ startOffset: cursor.off,
2101
+ fileSize: opened.size,
2102
+ maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
2103
+ maxSnapBytes: MAX_TEXT_SCAN_BYTES,
2104
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {}
2105
+ });
2106
+ } catch (err) {
2107
+ hasPrimaryError = true;
2108
+ primaryError = err;
2109
+ }
2110
+ afterRead = await fh.stat();
2111
+ } finally {
2112
+ await fh.close();
2113
+ }
2114
+ if (opened === void 0 || afterRead === void 0) {
2115
+ throw new FsError("internal_error", `failed to stat opened file: ${p}`);
2116
+ }
2117
+ const post = await fsp2.lstat(p);
2118
+ if (post.isSymbolicLink()) {
2119
+ throw new FsError(
2120
+ "symlink_escape",
2121
+ `path was replaced with a symlink during read: ${p}`,
2122
+ { hint: "TOCTOU swap detected via post-read lstat" }
2123
+ );
2124
+ }
2125
+ assertSameFile(opened, afterRead, p, "read");
2126
+ assertStreamWindowStable(opened, afterRead, p, "file changed during read");
2127
+ assertSameFile(opened, post, p, "read");
2128
+ assertStreamWindowStable(opened, post, p, "file changed during read");
2129
+ if (hasPrimaryError) {
2130
+ if (primaryError instanceof LargeNonUtf8TextError) {
2131
+ throw new FsError("binary_file", primaryError.message, {
2132
+ cause: primaryError,
2133
+ hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
2134
+ });
2135
+ }
2136
+ if (primaryError instanceof CursorNotAtLineBoundaryError) {
2137
+ throw new FsError("parse_error", primaryError.message, {
2138
+ cause: primaryError,
2139
+ hint: "pass a cursor returned by a previous read"
2140
+ });
2141
+ }
2142
+ throw primaryError;
2143
+ }
2144
+ if (window === void 0) {
2145
+ throw new FsError(
2146
+ "internal_error",
2147
+ `cursor text read returned no result: ${p}`
2148
+ );
2149
+ }
2150
+ const meta = {
2151
+ encoding: window.encoding,
2152
+ bom: window.bom,
2153
+ lineEnding: window.lineEnding,
2154
+ sizeBytes: opened.size,
2155
+ truncated: true,
2156
+ hasMore: window.nextOffset !== void 0 || window.truncatedByBytes === true
2157
+ };
2158
+ if (window.nextOffset !== void 0) {
2159
+ meta.nextCursor = encodeTextCursor({
2160
+ off: window.nextOffset,
2161
+ size: opened.size,
2162
+ dev: String(opened.dev),
2163
+ ino: String(opened.ino)
2164
+ });
2165
+ }
2166
+ return { content: window.content, meta };
2167
+ }
2168
+ __name(readTextCursorWindowFromResolvedFile, "readTextCursorWindowFromResolvedFile");
2169
+ async function readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs) {
2170
+ const fh = await fsp2.open(p, "r");
2171
+ let opened;
2172
+ let afterRead;
2173
+ let result;
2174
+ let primaryError;
2175
+ let hasPrimaryError = false;
2176
+ try {
2177
+ opened = await fh.stat();
2178
+ assertSameFile(pre, opened, p, "read");
2179
+ assertStreamWindowStable(pre, opened, p, "file changed before read");
2180
+ try {
2181
+ const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
2182
+ if (probe.length > 0) {
2183
+ const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
2184
+ if (looksBinary(probe.subarray(0, bytesRead))) {
2185
+ throw new FsError("binary_file", `binary file: ${p}`, {
2186
+ hint: "use readBytes for binary content"
2187
+ });
2188
+ }
2189
+ }
2190
+ result = await lowFs.readTextFileFromHandle({
2191
+ fileHandle: fh,
2192
+ fileSize: opened.size,
2193
+ limit: opts.limit ?? Number.POSITIVE_INFINITY,
2194
+ line: opts.line !== void 0 ? opts.line - 1 : 0,
2195
+ maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
2196
+ maxScanBytes: MAX_TEXT_SCAN_BYTES
2197
+ });
2198
+ } catch (err) {
2199
+ hasPrimaryError = true;
2200
+ primaryError = err;
2201
+ }
2202
+ afterRead = await fh.stat();
2203
+ } finally {
2204
+ await fh.close();
2205
+ }
2206
+ if (opened === void 0 || afterRead === void 0) {
2207
+ throw new FsError("internal_error", `failed to stat opened file: ${p}`);
2208
+ }
2209
+ const post = await fsp2.lstat(p);
2210
+ if (post.isSymbolicLink()) {
2211
+ throw new FsError(
2212
+ "symlink_escape",
2213
+ `path was replaced with a symlink during read: ${p}`,
2214
+ { hint: "TOCTOU swap detected via post-read lstat" }
2215
+ );
2216
+ }
2217
+ assertSameFile(opened, afterRead, p, "read");
2218
+ assertStreamWindowStable(opened, afterRead, p, "file changed during read");
2219
+ assertSameFile(opened, post, p, "read");
2220
+ assertStreamWindowStable(opened, post, p, "file changed during read");
2221
+ if (hasPrimaryError) {
2222
+ if (primaryError instanceof LargeNonUtf8TextError) {
2223
+ throw new FsError("binary_file", primaryError.message, {
2224
+ cause: primaryError,
2225
+ hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
2226
+ });
2227
+ }
2228
+ if (primaryError instanceof TextScanBudgetExceededError) {
2229
+ throw new FsError("file_too_large", primaryError.message, {
2230
+ cause: primaryError,
2231
+ 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`
2232
+ });
2233
+ }
2234
+ throw primaryError;
2235
+ }
2236
+ if (result === void 0) {
2237
+ throw new FsError(
2238
+ "internal_error",
2239
+ `large text range read returned no result: ${p}`
2240
+ );
2241
+ }
2242
+ const content = result.content;
2243
+ const readMeta = result._meta;
2244
+ const meta = {
2245
+ encoding: readMeta?.encoding,
2246
+ bom: readMeta?.bom,
2247
+ lineEnding: readMeta?.lineEnding ?? detectLineEnding(content),
2248
+ // Size as of `open`, not as of now: it describes the snapshot the
2249
+ // returned window was cut from. A file that grew during the read
2250
+ // reports the smaller, consistent number.
2251
+ sizeBytes: opened.size,
2252
+ truncated: true,
2253
+ hasMore: readMeta?.nextByteOffset !== void 0 || readMeta?.truncatedByBytes === true
2254
+ };
2255
+ if (readMeta?.nextByteOffset !== void 0) {
2256
+ meta.nextCursor = encodeTextCursor({
2257
+ off: readMeta.nextByteOffset,
2258
+ size: opened.size,
2259
+ dev: String(opened.dev),
2260
+ ino: String(opened.ino)
2261
+ });
2262
+ }
2263
+ if (readMeta?.originalLineCountExact === true && readMeta?.originalLineCount !== void 0) {
2264
+ meta.originalLineCount = readMeta.originalLineCount;
2265
+ }
2266
+ return { content, meta };
2267
+ }
2268
+ __name(readLargeTextWindowFromResolvedFile, "readLargeTextWindowFromResolvedFile");
1943
2269
  async function readStableRegularFileBuffer(p, pre) {
1944
2270
  const fh = await fsp2.open(p, "r");
1945
2271
  let opened;
@@ -1951,7 +2277,7 @@ async function readStableRegularFileBuffer(p, pre) {
1951
2277
  "file_too_large",
1952
2278
  `file of ${opened.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
1953
2279
  {
1954
- hint: "use readBytes for explicit byte-windowed access on large files"
2280
+ hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
1955
2281
  }
1956
2282
  );
1957
2283
  }
@@ -1987,9 +2313,15 @@ function sliceDecodedText(content, startLine, limit) {
1987
2313
  const originalLineCount = lines.length;
1988
2314
  const endLine = Math.min(startLine + limit, originalLineCount);
1989
2315
  const actualStartLine = Math.min(startLine, originalLineCount);
2316
+ let startByteOffset = 0;
2317
+ for (let i = 0; i < actualStartLine; i++) {
2318
+ startByteOffset += Buffer.byteLength(lines[i], "utf-8") + 1;
2319
+ }
1990
2320
  return {
1991
2321
  content: lines.slice(actualStartLine, endLine).join("\n"),
1992
- originalLineCount
2322
+ originalLineCount,
2323
+ startByteOffset,
2324
+ endLine
1993
2325
  };
1994
2326
  }
1995
2327
  __name(sliceDecodedText, "sliceDecodedText");
@@ -2780,13 +3112,29 @@ async function handleGetFile(req, res, deps) {
2780
3112
  });
2781
3113
  return;
2782
3114
  }
3115
+ const rawCursor = req.query["cursor"];
3116
+ if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
3117
+ applyReadHeaders(res);
3118
+ res.status(400).json({
3119
+ errorKind: "parse_error",
3120
+ error: `\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
3121
+ status: 400
3122
+ });
3123
+ return;
3124
+ }
3125
+ const cursor = rawCursor;
2783
3126
  const fs6 = factory.forRequest({
2784
3127
  originatorClientId: clientId ?? void 0,
2785
3128
  route: ROUTE2
2786
3129
  });
2787
3130
  try {
2788
3131
  const resolved = await fs6.resolve(queryPath, "read");
2789
- const out = await fs6.readText(resolved, { maxBytes, line, limit });
3132
+ const out = await fs6.readText(resolved, {
3133
+ maxBytes,
3134
+ line,
3135
+ limit,
3136
+ cursor
3137
+ });
2790
3138
  const returnedBytes = Buffer.byteLength(out.content, "utf-8");
2791
3139
  applyReadHeaders(res);
2792
3140
  res.status(200).json({
@@ -2801,7 +3149,9 @@ async function handleGetFile(req, res, deps) {
2801
3149
  truncated: out.meta.truncated === true,
2802
3150
  hash: out.meta.hash,
2803
3151
  matchedIgnore: out.meta.matchedIgnore ?? null,
2804
- originalLineCount: out.meta.originalLineCount ?? null
3152
+ originalLineCount: out.meta.originalLineCount ?? null,
3153
+ nextCursor: out.meta.nextCursor ?? null,
3154
+ hasMore: out.meta.hasMore === true
2805
3155
  });
2806
3156
  } catch (err) {
2807
3157
  sendFsError(res, err, ROUTE2);
@@ -4506,11 +4856,16 @@ async function validateManagedMemoryAvailable(deps, res, kind, assertGenerationO
4506
4856
  }
4507
4857
  }
4508
4858
  __name(validateManagedMemoryAvailable, "validateManagedMemoryAvailable");
4509
- function mountWorkspaceMemoryRememberRoutes(app, deps) {
4859
+ function mountWorkspaceMemoryRememberRoutesAt(app, basePath, mutate, resolveRouteDeps) {
4510
4860
  app.post(
4511
- "/workspace/memory/remember",
4512
- deps.mutate({ strict: true }),
4861
+ `${basePath}/remember`,
4862
+ mutate({ strict: true }),
4513
4863
  async (req, res) => {
4864
+ const deps = resolveRouteDeps(req, res, {
4865
+ creating: true,
4866
+ kind: "remember"
4867
+ });
4868
+ if (!deps) return;
4514
4869
  const assertGenerationOpen = deps.captureGenerationAssertion?.();
4515
4870
  if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4516
4871
  if (!requireTrustedWorkspace(deps, res)) return;
@@ -4574,9 +4929,14 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
4574
4929
  }
4575
4930
  );
4576
4931
  app.get(
4577
- "/workspace/memory/remember/:taskId",
4578
- deps.mutate({ strict: true }),
4932
+ `${basePath}/remember/:taskId`,
4933
+ mutate({ strict: true }),
4579
4934
  (req, res) => {
4935
+ const deps = resolveRouteDeps(req, res, {
4936
+ creating: false,
4937
+ kind: "remember"
4938
+ });
4939
+ if (!deps) return;
4580
4940
  const assertGenerationOpen = deps.captureGenerationAssertion?.();
4581
4941
  if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4582
4942
  if (!requireTrustedWorkspace(deps, res)) return;
@@ -4597,64 +4957,70 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
4597
4957
  res.status(200).json(task);
4598
4958
  }
4599
4959
  );
4600
- app.post(
4601
- "/workspace/memory/forget",
4602
- deps.mutate({ strict: true }),
4603
- async (req, res) => {
4604
- const assertGenerationOpen = deps.captureGenerationAssertion?.();
4605
- if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4606
- if (!requireTrustedWorkspace(deps, res)) return;
4607
- const body = deps.safeBody(req);
4608
- const query = body["query"];
4609
- const trimmedQuery = typeof query === "string" ? query.trim() : "";
4610
- if (!trimmedQuery) {
4611
- res.status(400).json({
4612
- error: "`query` must be a non-empty string",
4613
- code: "invalid_query"
4614
- });
4615
- return;
4616
- }
4617
- if (Buffer.byteLength(trimmedQuery, "utf8") > MAX_REMEMBER_CONTENT_BYTES) {
4618
- res.status(400).json({
4619
- error: `\`query\` exceeds the ${MAX_REMEMBER_CONTENT_BYTES}-byte limit`,
4620
- code: "invalid_query"
4621
- });
4622
- return;
4623
- }
4624
- const originatorClientId = validateOriginatorClientId(deps, req, res);
4625
- if (originatorClientId === null) return;
4626
- if (!await validateManagedMemoryAvailable(
4627
- deps,
4628
- res,
4629
- "forget",
4630
- assertGenerationOpen
4631
- ))
4632
- return;
4633
- if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4634
- try {
4635
- const task = deps.lane.enqueueForget({
4636
- query: trimmedQuery,
4637
- ...originatorClientId ? { originatorClientId } : {},
4638
- ...assertGenerationOpen ? { assertGenerationOpen } : {}
4639
- });
4640
- res.status(202).json(task);
4641
- } catch (err) {
4642
- const code = workspaceMemoryFailureCode(
4643
- err,
4644
- "forget_failed",
4645
- logWorkspaceMemoryExtractionError
4646
- );
4647
- res.status(publicErrorStatus(code)).json({
4648
- error: publicErrorMessage(code, "forget"),
4649
- code
4650
- });
4651
- }
4960
+ app.post(`${basePath}/forget`, mutate({ strict: true }), async (req, res) => {
4961
+ const deps = resolveRouteDeps(req, res, {
4962
+ creating: true,
4963
+ kind: "forget"
4964
+ });
4965
+ if (!deps) return;
4966
+ const assertGenerationOpen = deps.captureGenerationAssertion?.();
4967
+ if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4968
+ if (!requireTrustedWorkspace(deps, res)) return;
4969
+ const body = deps.safeBody(req);
4970
+ const query = body["query"];
4971
+ const trimmedQuery = typeof query === "string" ? query.trim() : "";
4972
+ if (!trimmedQuery) {
4973
+ res.status(400).json({
4974
+ error: "`query` must be a non-empty string",
4975
+ code: "invalid_query"
4976
+ });
4977
+ return;
4652
4978
  }
4653
- );
4979
+ if (Buffer.byteLength(trimmedQuery, "utf8") > MAX_REMEMBER_CONTENT_BYTES) {
4980
+ res.status(400).json({
4981
+ error: `\`query\` exceeds the ${MAX_REMEMBER_CONTENT_BYTES}-byte limit`,
4982
+ code: "invalid_query"
4983
+ });
4984
+ return;
4985
+ }
4986
+ const originatorClientId = validateOriginatorClientId(deps, req, res);
4987
+ if (originatorClientId === null) return;
4988
+ if (!await validateManagedMemoryAvailable(
4989
+ deps,
4990
+ res,
4991
+ "forget",
4992
+ assertGenerationOpen
4993
+ ))
4994
+ return;
4995
+ if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4996
+ try {
4997
+ const task = deps.lane.enqueueForget({
4998
+ query: trimmedQuery,
4999
+ ...originatorClientId ? { originatorClientId } : {},
5000
+ ...assertGenerationOpen ? { assertGenerationOpen } : {}
5001
+ });
5002
+ res.status(202).json(task);
5003
+ } catch (err) {
5004
+ const code = workspaceMemoryFailureCode(
5005
+ err,
5006
+ "forget_failed",
5007
+ logWorkspaceMemoryExtractionError
5008
+ );
5009
+ res.status(publicErrorStatus(code)).json({
5010
+ error: publicErrorMessage(code, "forget"),
5011
+ code
5012
+ });
5013
+ }
5014
+ });
4654
5015
  app.get(
4655
- "/workspace/memory/forget/:taskId",
4656
- deps.mutate({ strict: true }),
5016
+ `${basePath}/forget/:taskId`,
5017
+ mutate({ strict: true }),
4657
5018
  (req, res) => {
5019
+ const deps = resolveRouteDeps(req, res, {
5020
+ creating: false,
5021
+ kind: "forget"
5022
+ });
5023
+ if (!deps) return;
4658
5024
  const assertGenerationOpen = deps.captureGenerationAssertion?.();
4659
5025
  if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4660
5026
  if (!requireTrustedWorkspace(deps, res)) return;
@@ -4675,68 +5041,88 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
4675
5041
  res.status(200).json(task);
4676
5042
  }
4677
5043
  );
4678
- app.post(
4679
- "/workspace/memory/dream",
4680
- deps.mutate({ strict: true }),
4681
- async (req, res) => {
4682
- const assertGenerationOpen = deps.captureGenerationAssertion?.();
4683
- if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4684
- if (!requireTrustedWorkspace(deps, res)) return;
4685
- const originatorClientId = validateOriginatorClientId(deps, req, res);
4686
- if (originatorClientId === null) return;
4687
- if (!await validateManagedMemoryAvailable(
4688
- deps,
4689
- res,
4690
- "dream",
4691
- assertGenerationOpen
4692
- ))
4693
- return;
4694
- if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4695
- try {
4696
- const task = deps.lane.enqueueDream({
4697
- ...originatorClientId ? { originatorClientId } : {},
4698
- ...assertGenerationOpen ? { assertGenerationOpen } : {}
4699
- });
4700
- res.status(202).json(task);
4701
- } catch (err) {
4702
- const code = workspaceMemoryFailureCode(
4703
- err,
4704
- "dream_failed",
4705
- logWorkspaceMemoryExtractionError
4706
- );
4707
- res.status(publicErrorStatus(code)).json({
4708
- error: publicErrorMessage(code, "dream"),
4709
- code
4710
- });
4711
- }
4712
- }
4713
- );
4714
- app.get(
4715
- "/workspace/memory/dream/:taskId",
4716
- deps.mutate({ strict: true }),
4717
- (req, res) => {
4718
- const assertGenerationOpen = deps.captureGenerationAssertion?.();
4719
- if (!requireOpenGeneration(assertGenerationOpen, res)) return;
4720
- if (!requireTrustedWorkspace(deps, res)) return;
4721
- const requesterClientId = validateOriginatorClientId(deps, req, res);
4722
- if (requesterClientId === null) return;
4723
- const task = deps.lane.get(
4724
- req.params["taskId"],
4725
- requesterClientId,
4726
- "dream"
5044
+ app.post(`${basePath}/dream`, mutate({ strict: true }), async (req, res) => {
5045
+ const deps = resolveRouteDeps(req, res, {
5046
+ creating: true,
5047
+ kind: "dream"
5048
+ });
5049
+ if (!deps) return;
5050
+ const assertGenerationOpen = deps.captureGenerationAssertion?.();
5051
+ if (!requireOpenGeneration(assertGenerationOpen, res)) return;
5052
+ if (!requireTrustedWorkspace(deps, res)) return;
5053
+ const originatorClientId = validateOriginatorClientId(deps, req, res);
5054
+ if (originatorClientId === null) return;
5055
+ if (!await validateManagedMemoryAvailable(
5056
+ deps,
5057
+ res,
5058
+ "dream",
5059
+ assertGenerationOpen
5060
+ ))
5061
+ return;
5062
+ if (!requireOpenGeneration(assertGenerationOpen, res)) return;
5063
+ try {
5064
+ const task = deps.lane.enqueueDream({
5065
+ ...originatorClientId ? { originatorClientId } : {},
5066
+ ...assertGenerationOpen ? { assertGenerationOpen } : {}
5067
+ });
5068
+ res.status(202).json(task);
5069
+ } catch (err) {
5070
+ const code = workspaceMemoryFailureCode(
5071
+ err,
5072
+ "dream_failed",
5073
+ logWorkspaceMemoryExtractionError
4727
5074
  );
4728
- if (!task) {
4729
- res.status(404).json({
4730
- error: "Workspace memory dream task not found",
4731
- code: "dream_task_not_found"
4732
- });
4733
- return;
4734
- }
4735
- res.status(200).json(task);
5075
+ res.status(publicErrorStatus(code)).json({
5076
+ error: publicErrorMessage(code, "dream"),
5077
+ code
5078
+ });
5079
+ }
5080
+ });
5081
+ app.get(`${basePath}/dream/:taskId`, mutate({ strict: true }), (req, res) => {
5082
+ const deps = resolveRouteDeps(req, res, {
5083
+ creating: false,
5084
+ kind: "dream"
5085
+ });
5086
+ if (!deps) return;
5087
+ const assertGenerationOpen = deps.captureGenerationAssertion?.();
5088
+ if (!requireOpenGeneration(assertGenerationOpen, res)) return;
5089
+ if (!requireTrustedWorkspace(deps, res)) return;
5090
+ const requesterClientId = validateOriginatorClientId(deps, req, res);
5091
+ if (requesterClientId === null) return;
5092
+ const task = deps.lane.get(
5093
+ req.params["taskId"],
5094
+ requesterClientId,
5095
+ "dream"
5096
+ );
5097
+ if (!task) {
5098
+ res.status(404).json({
5099
+ error: "Workspace memory dream task not found",
5100
+ code: "dream_task_not_found"
5101
+ });
5102
+ return;
4736
5103
  }
5104
+ res.status(200).json(task);
5105
+ });
5106
+ }
5107
+ __name(mountWorkspaceMemoryRememberRoutesAt, "mountWorkspaceMemoryRememberRoutesAt");
5108
+ function mountWorkspaceMemoryRememberRoutes(app, deps) {
5109
+ mountWorkspaceMemoryRememberRoutesAt(
5110
+ app,
5111
+ "/workspace/memory",
5112
+ deps.mutate,
5113
+ () => deps
4737
5114
  );
4738
5115
  }
4739
5116
  __name(mountWorkspaceMemoryRememberRoutes, "mountWorkspaceMemoryRememberRoutes");
5117
+ function mountWorkspaceQualifiedMemoryRememberRoutes(app, deps) {
5118
+ mountWorkspaceMemoryRememberRoutesAt(
5119
+ app,
5120
+ "/workspaces/:workspace/memory",
5121
+ deps.mutate,
5122
+ deps.resolveRouteDeps
5123
+ );
5124
+ }
5125
+ __name(mountWorkspaceQualifiedMemoryRememberRoutes, "mountWorkspaceQualifiedMemoryRememberRoutes");
4740
5126
 
4741
5127
  // packages/cli/src/serve/workspace-memory.ts
4742
5128
  init_esbuild_shims();
@@ -6851,18 +7237,34 @@ async function removeTasksForSessions(projectRoot, sessionIds) {
6851
7237
  __name(removeTasksForSessions, "removeTasksForSessions");
6852
7238
 
6853
7239
  // packages/cli/src/serve/server/session-archive.ts
7240
+ var DaemonDrainingError = class extends Error {
7241
+ static {
7242
+ __name(this, "DaemonDrainingError");
7243
+ }
7244
+ name = "DaemonDrainingError";
7245
+ code = "daemon_draining";
7246
+ constructor() {
7247
+ super("The daemon is draining and no longer accepts session maintenance.");
7248
+ }
7249
+ };
6854
7250
  var SessionArchiveCoordinator = class {
6855
7251
  static {
6856
7252
  __name(this, "SessionArchiveCoordinator");
6857
7253
  }
6858
7254
  exclusive = /* @__PURE__ */ new Set();
6859
7255
  shared = /* @__PURE__ */ new Map();
7256
+ maintenanceSealed = false;
7257
+ activeMaintenance = 0;
7258
+ maintenanceDrain;
6860
7259
  assertNotTransitioning(sessionId) {
6861
7260
  if (this.exclusive.has(sessionId)) {
6862
7261
  throw new SessionArchivingError(sessionId);
6863
7262
  }
6864
7263
  }
6865
7264
  async runExclusiveMany(sessionIds, fn) {
7265
+ if (this.maintenanceSealed) {
7266
+ throw new DaemonDrainingError();
7267
+ }
6866
7268
  const uniqueSessionIds = [...new Set(sessionIds)];
6867
7269
  for (const sessionId of uniqueSessionIds) {
6868
7270
  this.assertNotTransitioning(sessionId);
@@ -6873,14 +7275,34 @@ var SessionArchiveCoordinator = class {
6873
7275
  for (const sessionId of uniqueSessionIds) {
6874
7276
  this.exclusive.add(sessionId);
6875
7277
  }
7278
+ this.activeMaintenance++;
6876
7279
  try {
6877
7280
  return await fn();
6878
7281
  } finally {
6879
7282
  for (const sessionId of uniqueSessionIds) {
6880
7283
  this.exclusive.delete(sessionId);
6881
7284
  }
7285
+ this.activeMaintenance--;
7286
+ if (this.activeMaintenance === 0) {
7287
+ this.maintenanceDrain?.resolve();
7288
+ this.maintenanceDrain = void 0;
7289
+ }
6882
7290
  }
6883
7291
  }
7292
+ sealMaintenanceAndWait() {
7293
+ this.maintenanceSealed = true;
7294
+ if (this.activeMaintenance === 0) {
7295
+ return Promise.resolve();
7296
+ }
7297
+ if (!this.maintenanceDrain) {
7298
+ let resolve5;
7299
+ const promise = new Promise((done) => {
7300
+ resolve5 = done;
7301
+ });
7302
+ this.maintenanceDrain = { promise, resolve: resolve5 };
7303
+ }
7304
+ return this.maintenanceDrain.promise;
7305
+ }
6884
7306
  async runSharedMany(sessionIds, fn) {
6885
7307
  const uniqueSessionIds = [...new Set(sessionIds)];
6886
7308
  for (const sessionId of uniqueSessionIds) {
@@ -6903,70 +7325,280 @@ var SessionArchiveCoordinator = class {
6903
7325
  }
6904
7326
  }
6905
7327
  };
7328
+ async function runWithDaemonWriterLease(params) {
7329
+ const {
7330
+ action,
7331
+ sessionId,
7332
+ service,
7333
+ mutate,
7334
+ mutationAppliedAfterError,
7335
+ afterMutationApplied
7336
+ } = params;
7337
+ let lease;
7338
+ try {
7339
+ lease = await service.acquireSessionWriterLease(sessionId, {
7340
+ processKind: "daemon",
7341
+ reclaimPolicy: "never"
7342
+ });
7343
+ } catch (error2) {
7344
+ return { mutationApplied: false, error: error2 };
7345
+ }
7346
+ let value;
7347
+ let mutationApplied = false;
7348
+ let mutationError;
7349
+ try {
7350
+ const mutation = await mutate(() => lease.assertOwnedAndUnchanged());
7351
+ value = mutation.value;
7352
+ mutationApplied = mutation.mutationApplied;
7353
+ } catch (error2) {
7354
+ mutationError = error2;
7355
+ try {
7356
+ mutationApplied = await mutationAppliedAfterError();
7357
+ } catch {
7358
+ mutationApplied = false;
7359
+ }
7360
+ }
7361
+ let maintenanceError;
7362
+ if (mutationApplied) {
7363
+ try {
7364
+ await afterMutationApplied();
7365
+ } catch (error2) {
7366
+ maintenanceError = error2;
7367
+ logSessionArchiveWarning(
7368
+ `scheduled task lifecycle update failed action=${action} workspace=${safeLogValue(
7369
+ service.getProjectRoot()
7370
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7371
+ errorMessage(error2)
7372
+ )}`
7373
+ );
7374
+ }
7375
+ }
7376
+ let releaseError;
7377
+ try {
7378
+ await lease.release();
7379
+ } catch (error2) {
7380
+ releaseError = error2;
7381
+ }
7382
+ if (releaseError !== void 0) {
7383
+ logMaintenanceLeaseReleaseFailure({
7384
+ action,
7385
+ workspace: service.getProjectRoot(),
7386
+ sessionId,
7387
+ error: releaseError,
7388
+ mutationApplied
7389
+ });
7390
+ if (mutationError !== void 0) {
7391
+ logSessionArchiveWarning(
7392
+ `session maintenance mutation also failed action=${action} workspace=${safeLogValue(
7393
+ service.getProjectRoot()
7394
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7395
+ errorMessage(mutationError)
7396
+ )}`
7397
+ );
7398
+ }
7399
+ return { mutationApplied, error: releaseError, maintenanceError };
7400
+ }
7401
+ if (mutationError !== void 0) {
7402
+ return { mutationApplied, error: mutationError, maintenanceError };
7403
+ }
7404
+ return { value, mutationApplied, maintenanceError };
7405
+ }
7406
+ __name(runWithDaemonWriterLease, "runWithDaemonWriterLease");
7407
+ function logMaintenanceLeaseReleaseFailure(params) {
7408
+ const errorKind = typeof params.error === "object" && params.error !== null && typeof params.error.errorKind === "string" ? params.error.errorKind : "unknown";
7409
+ logSessionArchiveWarning(
7410
+ `session maintenance lease release failed action=${params.action} workspace=${safeLogValue(
7411
+ params.workspace
7412
+ )} session=${safeLogValue(params.sessionId)} errorKind=${safeLogValue(
7413
+ errorKind
7414
+ )} mutationApplied=${params.mutationApplied}`
7415
+ );
7416
+ }
7417
+ __name(logMaintenanceLeaseReleaseFailure, "logMaintenanceLeaseReleaseFailure");
7418
+ async function classifySessionLocation(service, sessionId) {
7419
+ return service.getSessionLocation(sessionId);
7420
+ }
7421
+ __name(classifySessionLocation, "classifySessionLocation");
7422
+ function sessionLocationError(sessionId) {
7423
+ return new Error(`Session archive conflict: ${sessionId}`);
7424
+ }
7425
+ __name(sessionLocationError, "sessionLocationError");
7426
+ function updateScheduledTaskForMaintenance(service, sessionId, action) {
7427
+ if (action === "archive") {
7428
+ return disableTasksForSessions(service.getProjectRoot(), [sessionId]);
7429
+ }
7430
+ if (action === "unarchive") {
7431
+ return enableTasksForSessions(service.getProjectRoot(), [sessionId]);
7432
+ }
7433
+ return removeTasksForSessions(service.getProjectRoot(), [sessionId]);
7434
+ }
7435
+ __name(updateScheduledTaskForMaintenance, "updateScheduledTaskForMaintenance");
7436
+ async function deletePersistedSessionWithLease(service, sessionId) {
7437
+ const initialLocation = await classifySessionLocation(service, sessionId);
7438
+ if (initialLocation === void 0) {
7439
+ return { kind: "notFound", mutationApplied: false };
7440
+ }
7441
+ if (initialLocation === "conflict") {
7442
+ return {
7443
+ kind: "error",
7444
+ error: sessionLocationError(sessionId),
7445
+ mutationApplied: false
7446
+ };
7447
+ }
7448
+ const mutation = await runWithDaemonWriterLease({
7449
+ action: "delete",
7450
+ sessionId,
7451
+ service,
7452
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7453
+ const lockedLocation = await classifySessionLocation(service, sessionId);
7454
+ if (lockedLocation === void 0) {
7455
+ return {
7456
+ value: "notFound",
7457
+ mutationApplied: false
7458
+ };
7459
+ }
7460
+ if (lockedLocation === "conflict") {
7461
+ throw sessionLocationError(sessionId);
7462
+ }
7463
+ await assertOwnedAndUnchanged();
7464
+ const removed = await service.removeSession(sessionId);
7465
+ return {
7466
+ value: removed ? "removed" : "notFound",
7467
+ mutationApplied: removed
7468
+ };
7469
+ }, "mutate"),
7470
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === void 0, "mutationAppliedAfterError"),
7471
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "delete"), "afterMutationApplied")
7472
+ });
7473
+ if (mutation.error !== void 0) {
7474
+ return {
7475
+ kind: "error",
7476
+ error: mutation.error,
7477
+ mutationApplied: mutation.mutationApplied
7478
+ };
7479
+ }
7480
+ return {
7481
+ kind: mutation.value ?? "notFound",
7482
+ mutationApplied: mutation.mutationApplied
7483
+ };
7484
+ }
7485
+ __name(deletePersistedSessionWithLease, "deletePersistedSessionWithLease");
6906
7486
  async function deleteDaemonSessions(params) {
6907
7487
  const { sessionIds, service, bridge, coordinator, onError } = params;
6908
7488
  const uniqueSessionIds = [...new Set(sessionIds)];
6909
- const closeErrors = [];
6910
- const removed = [];
6911
- const notFound = [];
6912
- const removeErrors = [];
6913
7489
  for (const sessionId of uniqueSessionIds) {
6914
7490
  coordinator.assertNotTransitioning(sessionId);
6915
7491
  }
6916
- await Promise.all(
7492
+ const results = await Promise.all(
6917
7493
  uniqueSessionIds.map(async (sessionId) => {
6918
7494
  try {
6919
- await coordinator.runExclusiveMany([sessionId], async () => {
6920
- let shouldRemove = false;
7495
+ return await coordinator.runExclusiveMany([sessionId], async () => {
6921
7496
  try {
6922
7497
  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 });
7498
+ } catch (error2) {
7499
+ if (isSessionNotFoundError(error2)) {
7500
+ const result2 = await deletePersistedSessionWithLease(
7501
+ service,
7502
+ sessionId
7503
+ );
7504
+ if (result2.kind === "error") {
7505
+ onError?.({
7506
+ phase: "remove",
7507
+ sessionId,
7508
+ error: errorMessage(result2.error)
7509
+ });
7510
+ }
7511
+ return result2;
6931
7512
  }
7513
+ onError?.({
7514
+ phase: "close",
7515
+ sessionId,
7516
+ error: errorMessage(error2)
7517
+ });
7518
+ return {
7519
+ kind: "error",
7520
+ error: error2,
7521
+ mutationApplied: false
7522
+ };
6932
7523
  }
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 });
7524
+ const result = await deletePersistedSessionWithLease(
7525
+ service,
7526
+ sessionId
7527
+ );
7528
+ if (result.kind === "error") {
7529
+ onError?.({
7530
+ phase: "remove",
7531
+ sessionId,
7532
+ error: errorMessage(result.error)
7533
+ });
6944
7534
  }
7535
+ return result;
6945
7536
  });
6946
- } catch (err) {
6947
- if (err instanceof SessionArchivingError && err.lockKind === "exclusive") {
6948
- throw err;
7537
+ } catch (error2) {
7538
+ if (error2 instanceof DaemonDrainingError) {
7539
+ throw error2;
6949
7540
  }
6950
- const message = err instanceof Error ? err.message : String(err);
6951
- onError?.({ phase: "delete", sessionId, error: message });
6952
- closeErrors.push({ sessionId, error: message });
7541
+ onError?.({
7542
+ phase: "delete",
7543
+ sessionId,
7544
+ error: errorMessage(error2)
7545
+ });
7546
+ return {
7547
+ kind: "error",
7548
+ error: error2,
7549
+ mutationApplied: false
7550
+ };
6953
7551
  }
6954
7552
  })
6955
7553
  );
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
- );
7554
+ const removed = [];
7555
+ const notFound = [];
7556
+ const errors = [];
7557
+ for (let i = 0; i < results.length; i++) {
7558
+ const sessionId = uniqueSessionIds[i];
7559
+ const result = results[i];
7560
+ if (result.kind === "removed") {
7561
+ removed.push(sessionId);
7562
+ } else if (result.kind === "notFound") {
7563
+ notFound.push(sessionId);
7564
+ } else {
7565
+ errors.push({ sessionId, error: errorMessage(result.error) });
6961
7566
  }
6962
- );
6963
- return { removed, notFound, errors: [...closeErrors, ...removeErrors] };
7567
+ }
7568
+ return { removed, notFound, errors };
6964
7569
  }
6965
7570
  __name(deleteDaemonSessions, "deleteDaemonSessions");
6966
- async function assertSessionLoadable(workspaceCwd, sessionId) {
6967
- const location = await new SessionService(workspaceCwd).getSessionLocation(
6968
- sessionId
6969
- );
7571
+ async function deleteDaemonSessionIfOrphan(params) {
7572
+ const { sessionId, service, bridge, coordinator } = params;
7573
+ coordinator.assertNotTransitioning(sessionId);
7574
+ const result = await coordinator.runExclusiveMany([sessionId], async () => {
7575
+ let killed = false;
7576
+ try {
7577
+ killed = await bridge.killSession(sessionId, {
7578
+ requireZeroAttaches: true
7579
+ });
7580
+ } catch (error2) {
7581
+ if (!isSessionNotFoundError(error2)) throw error2;
7582
+ killed = true;
7583
+ }
7584
+ if (!killed) {
7585
+ return void 0;
7586
+ }
7587
+ return deletePersistedSessionWithLease(service, sessionId);
7588
+ });
7589
+ if (result === void 0) {
7590
+ return false;
7591
+ }
7592
+ if (result.kind === "error") {
7593
+ throw result.error;
7594
+ }
7595
+ return true;
7596
+ }
7597
+ __name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
7598
+ async function assertSessionLoadable(workspaceCwd, sessionId, runtimeBaseDir) {
7599
+ const location = await new SessionService(workspaceCwd, {
7600
+ runtimeBaseDir
7601
+ }).getSessionLocation(sessionId);
6970
7602
  if (location === "archived") {
6971
7603
  throw new SessionArchivedError(sessionId);
6972
7604
  }
@@ -6976,10 +7608,10 @@ async function assertSessionLoadable(workspaceCwd, sessionId) {
6976
7608
  return location;
6977
7609
  }
6978
7610
  __name(assertSessionLoadable, "assertSessionLoadable");
6979
- async function assertSessionArchived(workspaceCwd, sessionId) {
6980
- const location = await new SessionService(workspaceCwd).getSessionLocation(
6981
- sessionId
6982
- );
7611
+ async function assertSessionArchived(workspaceCwd, sessionId, runtimeBaseDir) {
7612
+ const location = await new SessionService(workspaceCwd, {
7613
+ runtimeBaseDir
7614
+ }).getSessionLocation(sessionId);
6983
7615
  if (location === "active") {
6984
7616
  throw new SessionNotArchivedError(sessionId);
6985
7617
  }
@@ -6995,43 +7627,6 @@ function isSessionNotFoundError(err) {
6995
7627
  return err instanceof SessionNotFoundError || err instanceof Error && err.name === "SessionNotFoundError";
6996
7628
  }
6997
7629
  __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
7630
  function logSessionArchiveResult(action, result) {
7036
7631
  const changedLabel = action === "archive" ? "archived" : "unarchived";
7037
7632
  const alreadyLabel = action === "archive" ? "alreadyArchived" : "alreadyActive";
@@ -7071,59 +7666,126 @@ __name(sanitizeLogLine, "sanitizeLogLine");
7071
7666
  async function archiveDaemonSessions(params) {
7072
7667
  const { sessionIds, service, bridge, coordinator } = params;
7073
7668
  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) => {
7669
+ for (const sessionId of uniqueSessionIds) {
7670
+ coordinator.assertNotTransitioning(sessionId);
7671
+ }
7672
+ const results = await Promise.all(
7673
+ uniqueSessionIds.map(async (sessionId) => {
7674
+ try {
7675
+ return await coordinator.runExclusiveMany([sessionId], async () => {
7092
7676
  try {
7093
7677
  await bridge.closeSession(sessionId, void 0, {
7094
7678
  requireAgentClose: true
7095
7679
  });
7096
- } catch (err) {
7097
- if (!isSessionNotFoundError(err)) {
7098
- throw err;
7680
+ } catch (error2) {
7681
+ if (!isSessionNotFoundError(error2)) {
7682
+ return {
7683
+ kind: "error",
7684
+ error: error2,
7685
+ mutationApplied: false
7686
+ };
7099
7687
  }
7100
7688
  }
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"
7689
+ const initialLocation = await classifySessionLocation(
7690
+ service,
7691
+ sessionId
7692
+ );
7693
+ if (initialLocation === void 0) {
7694
+ return { kind: "notFound", mutationApplied: false };
7695
+ }
7696
+ if (initialLocation === "archived") {
7697
+ return {
7698
+ kind: "alreadyArchived",
7699
+ mutationApplied: false
7700
+ };
7701
+ }
7702
+ if (initialLocation === "conflict") {
7703
+ return {
7704
+ kind: "error",
7705
+ error: sessionLocationError(sessionId),
7706
+ mutationApplied: false
7707
+ };
7708
+ }
7709
+ const mutation = await runWithDaemonWriterLease({
7710
+ action: "archive",
7711
+ sessionId,
7712
+ service,
7713
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7714
+ const lockedLocation = await classifySessionLocation(
7715
+ service,
7716
+ sessionId
7717
+ );
7718
+ if (lockedLocation === void 0) {
7719
+ return {
7720
+ value: "notFound",
7721
+ mutationApplied: false
7722
+ };
7723
+ }
7724
+ if (lockedLocation === "archived") {
7725
+ return {
7726
+ value: "alreadyArchived",
7727
+ mutationApplied: false
7728
+ };
7729
+ }
7730
+ if (lockedLocation === "conflict") {
7731
+ throw sessionLocationError(sessionId);
7732
+ }
7733
+ await assertOwnedAndUnchanged();
7734
+ const result = await service.archiveSessions([sessionId], {
7735
+ knownLocation: "active"
7736
+ });
7737
+ if (result.errors[0]) throw result.errors[0].error;
7738
+ if (result.archived.length > 0) {
7739
+ return {
7740
+ value: "archived",
7741
+ mutationApplied: true
7742
+ };
7743
+ }
7744
+ return {
7745
+ value: result.alreadyArchived.length > 0 ? "alreadyArchived" : "notFound",
7746
+ mutationApplied: false
7747
+ };
7748
+ }, "mutate"),
7749
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "archived", "mutationAppliedAfterError"),
7750
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "archive"), "afterMutationApplied")
7751
+ });
7752
+ if (mutation.error !== void 0) {
7753
+ return {
7754
+ kind: "error",
7755
+ error: mutation.error,
7756
+ mutationApplied: mutation.mutationApplied
7757
+ };
7758
+ }
7759
+ return {
7760
+ kind: mutation.value ?? "notFound",
7761
+ mutationApplied: mutation.mutationApplied
7762
+ };
7116
7763
  });
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 });
7764
+ } catch (error2) {
7765
+ if (error2 instanceof DaemonDrainingError) {
7766
+ throw error2;
7124
7767
  }
7768
+ return {
7769
+ kind: "error",
7770
+ error: error2,
7771
+ mutationApplied: false,
7772
+ maintenanceError: void 0
7773
+ };
7125
7774
  }
7126
- });
7775
+ })
7776
+ );
7777
+ const archived = [];
7778
+ const alreadyArchived = [];
7779
+ const notFound = [];
7780
+ const errors = [];
7781
+ for (let i = 0; i < results.length; i++) {
7782
+ const sessionId = uniqueSessionIds[i];
7783
+ const result = results[i];
7784
+ if (result.kind === "archived") archived.push(sessionId);
7785
+ else if (result.kind === "alreadyArchived") {
7786
+ alreadyArchived.push(sessionId);
7787
+ } else if (result.kind === "notFound") notFound.push(sessionId);
7788
+ else errors.push({ sessionId, error: result.error });
7127
7789
  }
7128
7790
  logSessionArchiveResult("archive", {
7129
7791
  requested: uniqueSessionIds,
@@ -7132,51 +7794,144 @@ async function archiveDaemonSessions(params) {
7132
7794
  notFound,
7133
7795
  errors
7134
7796
  });
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
7797
  return { archived, alreadyArchived, notFound, errors };
7143
7798
  }
7144
7799
  __name(archiveDaemonSessions, "archiveDaemonSessions");
7145
7800
  async function unarchiveDaemonSessions(params) {
7146
7801
  const { sessionIds, service, coordinator } = params;
7147
7802
  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"
7803
+ for (const sessionId of uniqueSessionIds) {
7804
+ coordinator.assertNotTransitioning(sessionId);
7805
+ }
7806
+ const results = await Promise.all(
7807
+ uniqueSessionIds.map(async (sessionId) => {
7808
+ try {
7809
+ return await coordinator.runExclusiveMany([sessionId], async () => {
7810
+ const initialLocation = await classifySessionLocation(
7811
+ service,
7812
+ sessionId
7813
+ );
7814
+ if (initialLocation === void 0) {
7815
+ return { kind: "notFound", mutationApplied: false };
7816
+ }
7817
+ if (initialLocation === "active") {
7818
+ let maintenanceError;
7819
+ try {
7820
+ await updateScheduledTaskForMaintenance(
7821
+ service,
7822
+ sessionId,
7823
+ "unarchive"
7824
+ );
7825
+ } catch (error2) {
7826
+ maintenanceError = error2;
7827
+ logSessionArchiveWarning(
7828
+ `scheduled task lifecycle update failed action=unarchive workspace=${safeLogValue(
7829
+ service.getProjectRoot()
7830
+ )} session=${safeLogValue(sessionId)} error=${safeLogValue(
7831
+ errorMessage(error2)
7832
+ )}`
7833
+ );
7834
+ }
7835
+ return {
7836
+ kind: "alreadyActive",
7837
+ mutationApplied: false,
7838
+ maintenanceError
7839
+ };
7840
+ }
7841
+ if (initialLocation === "conflict") {
7842
+ return {
7843
+ kind: "error",
7844
+ error: sessionLocationError(sessionId),
7845
+ mutationApplied: false
7846
+ };
7847
+ }
7848
+ const mutation = await runWithDaemonWriterLease({
7849
+ action: "unarchive",
7850
+ sessionId,
7851
+ service,
7852
+ mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
7853
+ const lockedLocation = await classifySessionLocation(
7854
+ service,
7855
+ sessionId
7856
+ );
7857
+ if (lockedLocation === void 0) {
7858
+ return {
7859
+ value: "notFound",
7860
+ mutationApplied: false
7861
+ };
7862
+ }
7863
+ if (lockedLocation === "active") {
7864
+ return {
7865
+ value: "alreadyActive",
7866
+ mutationApplied: false
7867
+ };
7868
+ }
7869
+ if (lockedLocation === "conflict") {
7870
+ throw sessionLocationError(sessionId);
7871
+ }
7872
+ await assertOwnedAndUnchanged();
7873
+ const result = await service.unarchiveSessions([sessionId], {
7874
+ knownLocation: "archived"
7875
+ });
7876
+ if (result.errors[0]) throw result.errors[0].error;
7877
+ if (result.unarchived.length > 0) {
7878
+ return {
7879
+ value: "unarchived",
7880
+ mutationApplied: true
7881
+ };
7882
+ }
7883
+ return {
7884
+ value: result.alreadyActive.length > 0 ? "alreadyActive" : "notFound",
7885
+ mutationApplied: false
7886
+ };
7887
+ }, "mutate"),
7888
+ mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "active", "mutationAppliedAfterError"),
7889
+ afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(
7890
+ service,
7891
+ sessionId,
7892
+ "unarchive"
7893
+ ), "afterMutationApplied")
7168
7894
  });
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 });
7895
+ if (mutation.error !== void 0) {
7896
+ return {
7897
+ kind: "error",
7898
+ error: mutation.error,
7899
+ mutationApplied: mutation.mutationApplied
7900
+ };
7176
7901
  }
7902
+ return {
7903
+ kind: mutation.value ?? "notFound",
7904
+ mutationApplied: mutation.mutationApplied,
7905
+ maintenanceError: mutation.maintenanceError
7906
+ };
7907
+ });
7908
+ } catch (error2) {
7909
+ if (error2 instanceof DaemonDrainingError) {
7910
+ throw error2;
7177
7911
  }
7912
+ return {
7913
+ kind: "error",
7914
+ error: error2,
7915
+ mutationApplied: false,
7916
+ maintenanceError: void 0
7917
+ };
7178
7918
  }
7179
- });
7919
+ })
7920
+ );
7921
+ const unarchived = [];
7922
+ const alreadyActive = [];
7923
+ const notFound = [];
7924
+ const errors = [];
7925
+ for (let i = 0; i < results.length; i++) {
7926
+ const sessionId = uniqueSessionIds[i];
7927
+ const result = results[i];
7928
+ if (result.kind === "unarchived") unarchived.push(sessionId);
7929
+ else if (result.kind === "alreadyActive") alreadyActive.push(sessionId);
7930
+ else if (result.kind === "notFound") notFound.push(sessionId);
7931
+ else errors.push({ sessionId, error: result.error });
7932
+ if (result.maintenanceError !== void 0) {
7933
+ errors.push({ sessionId, error: result.maintenanceError });
7934
+ }
7180
7935
  }
7181
7936
  logSessionArchiveResult("unarchive", {
7182
7937
  requested: uniqueSessionIds,
@@ -7185,17 +7940,6 @@ async function unarchiveDaemonSessions(params) {
7185
7940
  notFound,
7186
7941
  errors
7187
7942
  });
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
7943
  return { unarchived, alreadyActive, notFound, errors };
7200
7944
  }
7201
7945
  __name(unarchiveDaemonSessions, "unarchiveDaemonSessions");
@@ -7596,6 +8340,13 @@ function pickSessionArtifactInput(params) {
7596
8340
  }
7597
8341
  __name(pickSessionArtifactInput, "pickSessionArtifactInput");
7598
8342
  function toRpcError(err) {
8343
+ if (err instanceof DaemonDrainingError) {
8344
+ return {
8345
+ code: RPC.INTERNAL_ERROR,
8346
+ message: err.message,
8347
+ data: { errorKind: "daemon_draining" }
8348
+ };
8349
+ }
7599
8350
  const writerError = sessionWriterRpcError(err);
7600
8351
  if (writerError) return writerError;
7601
8352
  if (err instanceof AcpParamError || err instanceof InvalidCursorError) {
@@ -7804,7 +8555,7 @@ function rpcErrorFrame(id, err) {
7804
8555
  __name(rpcErrorFrame, "rpcErrorFrame");
7805
8556
  var ACP_PROTOCOL_VERSION = 1;
7806
8557
  var AcpDispatcher = class {
7807
- constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0) {
8558
+ constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0, sessionRuntimeBaseDir = Storage.getRuntimeBaseDir()) {
7808
8559
  this.bridge = bridge;
7809
8560
  this.boundWorkspace = boundWorkspace;
7810
8561
  this.getEnv = getEnv;
@@ -7817,6 +8568,7 @@ var AcpDispatcher = class {
7817
8568
  this.archiveCoordinator = archiveCoordinator;
7818
8569
  this.isWorkspaceTrusted = isWorkspaceTrusted;
7819
8570
  this.captureGenerationAssertion = captureGenerationAssertion;
8571
+ this.sessionRuntimeBaseDir = sessionRuntimeBaseDir;
7820
8572
  this.agentManager = createDaemonSubagentManager(boundWorkspace);
7821
8573
  }
7822
8574
  static {
@@ -7824,13 +8576,15 @@ var AcpDispatcher = class {
7824
8576
  }
7825
8577
  agentManager;
7826
8578
  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(
8579
+ const cleanup = removePersistedSession ? deleteDaemonSessionIfOrphan({
8580
+ sessionId,
8581
+ service: new SessionService(this.boundWorkspace, {
8582
+ runtimeBaseDir: this.sessionRuntimeBaseDir
8583
+ }),
8584
+ bridge: this.bridge,
8585
+ coordinator: this.archiveCoordinator
8586
+ }) : this.bridge.killSession(sessionId, { requireZeroAttaches: true });
8587
+ void cleanup.catch(
7834
8588
  (err) => writeStderrLine(
7835
8589
  `qwen serve: /acp orphan killSession(${logSafe(sessionId)}) failed: ${logSafe(errMsg(err))}`
7836
8590
  )
@@ -8080,6 +8834,12 @@ var AcpDispatcher = class {
8080
8834
  * (it mints the connection) and never reaches here.
8081
8835
  */
8082
8836
  async handle(conn, msg, sessionHeader, reqLoopback) {
8837
+ return Storage.runWithResolvedRuntimeBaseDir(
8838
+ this.sessionRuntimeBaseDir,
8839
+ () => this.handleInRuntime(conn, msg, sessionHeader, reqLoopback)
8840
+ );
8841
+ }
8842
+ async handleInRuntime(conn, msg, sessionHeader, reqLoopback) {
8083
8843
  const loopback = reqLoopback ?? conn.fromLoopback;
8084
8844
  if (isResponse(msg)) {
8085
8845
  try {
@@ -9926,8 +10686,26 @@ var AcpDispatcher = class {
9926
10686
  );
9927
10687
  return;
9928
10688
  }
10689
+ const rawCursor = params["cursor"];
10690
+ if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
10691
+ if (id !== void 0)
10692
+ conn.sendConn(
10693
+ error(
10694
+ id,
10695
+ RPC.INVALID_PARAMS,
10696
+ `\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`
10697
+ )
10698
+ );
10699
+ return;
10700
+ }
10701
+ const cursor = rawCursor;
9929
10702
  const resolved = await fs6.resolve(p, "read");
9930
- const out = await fs6.readText(resolved, { maxBytes, line, limit });
10703
+ const out = await fs6.readText(resolved, {
10704
+ maxBytes,
10705
+ line,
10706
+ limit,
10707
+ cursor
10708
+ });
9931
10709
  this.replyConn(conn, id, {
9932
10710
  path: p,
9933
10711
  content: out.content,
@@ -13061,7 +13839,8 @@ function mountAcpHttp(app, bridge, opts) {
13061
13839
  () => {
13062
13840
  const guard = opts.workspaceRegistry?.primaryEntry.current?.guard;
13063
13841
  return guard ? () => guard.assertOpen() : void 0;
13064
- }
13842
+ },
13843
+ opts.workspaceRegistry?.primary.sessionRuntimeBaseDir ?? Storage.getRuntimeBaseDir()
13065
13844
  );
13066
13845
  dispatcherRef.current = dispatcher;
13067
13846
  const primaryMount = {
@@ -13368,7 +14147,8 @@ function mountAcpHttp(app, bridge, opts) {
13368
14147
  () => {
13369
14148
  const guard = rt.generationGuard;
13370
14149
  return guard ? () => guard.assertOpen() : void 0;
13371
- }
14150
+ },
14151
+ rt.sessionRuntimeBaseDir
13372
14152
  );
13373
14153
  secondaryDispatcherRef.current = secondaryDispatcher;
13374
14154
  return {
@@ -14108,6 +14888,16 @@ function mountAcpHttp(app, bridge, opts) {
14108
14888
  memoryTasks: mount?.workspaceRememberLane.pendingCount() ?? 0
14109
14889
  };
14110
14890
  }, "getWorkspaceActivity"),
14891
+ ensureWorkspaceRememberLane: /* @__PURE__ */ __name((workspaceId) => {
14892
+ if (disposed) return void 0;
14893
+ const existing = mountForWorkspace(workspaceId);
14894
+ if (existing) return existing.workspaceRememberLane;
14895
+ const rt = opts.workspaceRegistry?.getByWorkspaceId(workspaceId);
14896
+ if (!rt) return void 0;
14897
+ const mount = getOrCreateSecondaryMount(rt);
14898
+ return mount?.workspaceRememberLane;
14899
+ }, "ensureWorkspaceRememberLane"),
14900
+ getWorkspaceRememberLane: /* @__PURE__ */ __name((workspaceId) => mountForWorkspace(workspaceId)?.workspaceRememberLane, "getWorkspaceRememberLane"),
14111
14901
  commitWorkspaceRemoval: /* @__PURE__ */ __name((workspaceId) => {
14112
14902
  const mount = secondaryMounts.get(workspaceId);
14113
14903
  mount?.workspaceRememberLane.dispose();
@@ -16646,13 +17436,17 @@ function createExtensionsController(deps) {
16646
17436
  const startedAt = Date.now();
16647
17437
  try {
16648
17438
  runtime.workspaceService.invalidateWorkspaceSkillsStatus();
16649
- return {
16650
- status: "fulfilled",
16651
- result: await runtime.bridge.refreshExtensionsForAllSessions(
16652
- bridgeMutationEvent(event)
16653
- ),
16654
- elapsedMs: Date.now() - startedAt
16655
- };
17439
+ try {
17440
+ return {
17441
+ status: "fulfilled",
17442
+ result: await runtime.bridge.refreshExtensionsForAllSessions(
17443
+ bridgeMutationEvent(event)
17444
+ ),
17445
+ elapsedMs: Date.now() - startedAt
17446
+ };
17447
+ } finally {
17448
+ runtime.workspaceService.invalidateWorkspaceSkillsStatus();
17449
+ }
16656
17450
  } catch (reason) {
16657
17451
  return {
16658
17452
  status: "rejected",
@@ -16727,10 +17521,14 @@ function createExtensionsController(deps) {
16727
17521
  const { result, elapsedMs } = await runReconciliation(async () => {
16728
17522
  workspace.invalidateWorkspaceSkillsStatus();
16729
17523
  const startedAt = Date.now();
16730
- const result2 = await bridge.refreshExtensionsForAllSessions(
16731
- bridgeMutationEvent(event)
16732
- );
16733
- return { result: result2, elapsedMs: Date.now() - startedAt };
17524
+ try {
17525
+ const result2 = await bridge.refreshExtensionsForAllSessions(
17526
+ bridgeMutationEvent(event)
17527
+ );
17528
+ return { result: result2, elapsedMs: Date.now() - startedAt };
17529
+ } finally {
17530
+ workspace.invalidateWorkspaceSkillsStatus();
17531
+ }
16734
17532
  });
16735
17533
  const warnings = [...commitWarnings];
16736
17534
  if (result.failed > 0) {
@@ -17249,11 +18047,15 @@ function registerWorkspaceExtensionRoutes(app, deps) {
17249
18047
  async () => await Promise.allSettled(
17250
18048
  runtimes.map(async (runtime) => {
17251
18049
  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
- );
18050
+ try {
18051
+ const result = await runtime.bridge.refreshExtensionsForAllSessions();
18052
+ if (result.failed > 0) {
18053
+ throw new Error(
18054
+ `${result.failed} extension session refresh(es) failed`
18055
+ );
18056
+ }
18057
+ } finally {
18058
+ runtime.workspaceService.invalidateWorkspaceSkillsStatus();
17257
18059
  }
17258
18060
  })
17259
18061
  )
@@ -19071,6 +19873,12 @@ var legacySessionTelemetryRoutes = [
19071
19873
  attribution: "handler_resolved",
19072
19874
  route: "POST /session/:id/fork"
19073
19875
  },
19876
+ {
19877
+ method: "POST",
19878
+ path: "/session/:id/side-task",
19879
+ attribution: "handler_resolved",
19880
+ route: "POST /session/:id/side-task"
19881
+ },
19074
19882
  {
19075
19883
  method: "POST",
19076
19884
  path: "/session/:id/cd",
@@ -21045,10 +21853,8 @@ var VirtualSubagentSessions = class {
21045
21853
  totalTokens: task.stats?.totalTokens
21046
21854
  };
21047
21855
  }
21048
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21049
- const projectDir = Storage.runWithRuntimeBaseDir(
21050
- runtimeDir,
21051
- runtime.workspaceCwd,
21856
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21857
+ runtime.sessionRuntimeBaseDir,
21052
21858
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21053
21859
  );
21054
21860
  const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
@@ -21083,10 +21889,8 @@ var VirtualSubagentSessions = class {
21083
21889
  return void 0;
21084
21890
  }
21085
21891
  async findLegacyTaskByToolCall(runtime, parentSessionId, toolCallId) {
21086
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21087
- const projectDir = Storage.runWithRuntimeBaseDir(
21088
- runtimeDir,
21089
- runtime.workspaceCwd,
21892
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21893
+ runtime.sessionRuntimeBaseDir,
21090
21894
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21091
21895
  );
21092
21896
  const parentRecords = await read(
@@ -21159,10 +21963,8 @@ var VirtualSubagentSessions = class {
21159
21963
  };
21160
21964
  }
21161
21965
  async readParentToolCallMetrics(runtime, parentSessionId, toolCallId) {
21162
- const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
21163
- const projectDir = Storage.runWithRuntimeBaseDir(
21164
- runtimeDir,
21165
- runtime.workspaceCwd,
21966
+ const projectDir = Storage.runWithResolvedRuntimeBaseDir(
21967
+ runtime.sessionRuntimeBaseDir,
21166
21968
  () => new Storage(runtime.workspaceCwd).getProjectDir()
21167
21969
  );
21168
21970
  const records = await read(
@@ -21174,7 +21976,11 @@ var VirtualSubagentSessions = class {
21174
21976
  let task = await this.findTask(
21175
21977
  runtime,
21176
21978
  parentSessionId,
21177
- (candidate) => candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
21979
+ (candidate) => (
21980
+ // /fork has no parent transcript tool call, so its task ID is the
21981
+ // stable reference used by Web Shell.
21982
+ candidate.id === toolCallId || candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
21983
+ )
21178
21984
  );
21179
21985
  const metrics = task && task.status !== "running" ? await this.readParentToolCallMetrics(
21180
21986
  runtime,
@@ -21234,16 +22040,35 @@ var VirtualSubagentSessions = class {
21234
22040
  }
21235
22041
  };
21236
22042
 
22043
+ // packages/cli/src/serve/workspace-runtime-storage.ts
22044
+ init_esbuild_shims();
22045
+ function runWithWorkspaceRuntimeStorage(runtime, fn) {
22046
+ return Storage.runWithResolvedRuntimeBaseDir(
22047
+ runtime.sessionRuntimeBaseDir,
22048
+ fn
22049
+ );
22050
+ }
22051
+ __name(runWithWorkspaceRuntimeStorage, "runWithWorkspaceRuntimeStorage");
22052
+ function createWorkspaceRuntimeSessionService(runtime, options = {}) {
22053
+ return new SessionService(runtime.workspaceCwd, {
22054
+ ...options,
22055
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir
22056
+ });
22057
+ }
22058
+ __name(createWorkspaceRuntimeSessionService, "createWorkspaceRuntimeSessionService");
22059
+
21237
22060
  // packages/cli/src/serve/routes/session.ts
21238
22061
  var GIT_RESERVED_BRANCH = "HEAD";
21239
22062
  var MAX_BRANCH_NAME_BYTES = 1e3;
21240
22063
  var MAX_BRANCH_COMPONENT_BYTES = 200;
22064
+ var HTTP_SESSION_ID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
21241
22065
  var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
21242
22066
  var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
21243
22067
  var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
21244
22068
  var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
21245
22069
  var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
21246
22070
  "POST /session/:id/branch",
22071
+ "POST /session/:id/side-task",
21247
22072
  "POST /session/:id/fork",
21248
22073
  "POST /session/:id/cd"
21249
22074
  ];
@@ -21258,7 +22083,8 @@ function isReadOnlyWorkspaceInspection(runtime) {
21258
22083
  }
21259
22084
  __name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
21260
22085
  function runWorkspaceInspectionWithLogPolicy(runtime, read2) {
21261
- return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read2) : read2();
22086
+ const readInRuntime = /* @__PURE__ */ __name(() => runWithWorkspaceRuntimeStorage(runtime, read2), "readInRuntime");
22087
+ return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(readInRuntime) : readInRuntime();
21262
22088
  }
21263
22089
  __name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
21264
22090
  function requireSessionArtifactClientId(clientId, res) {
@@ -21395,6 +22221,15 @@ function shouldPreserveTranscriptResolutionError(err) {
21395
22221
  return err instanceof SessionArchivedError || err instanceof SessionConflictError || err instanceof SessionNotFoundError;
21396
22222
  }
21397
22223
  __name(shouldPreserveTranscriptResolutionError, "shouldPreserveTranscriptResolutionError");
22224
+ function isSessionLive(bridge, sessionId) {
22225
+ try {
22226
+ bridge.getSessionSummary(sessionId);
22227
+ return true;
22228
+ } catch (err) {
22229
+ return !(err instanceof SessionNotFoundError);
22230
+ }
22231
+ }
22232
+ __name(isSessionLive, "isSessionLive");
21398
22233
  function parseOptionalApprovalMode(body, res) {
21399
22234
  const rawApprovalMode = body["approvalMode"];
21400
22235
  if (rawApprovalMode === void 0) {
@@ -21429,6 +22264,7 @@ function registerSessionRoutes(app, deps) {
21429
22264
  const transcriptCursorCodecs = /* @__PURE__ */ new Map();
21430
22265
  const activeBranchSessions = /* @__PURE__ */ new Map();
21431
22266
  const inFlightBranchWorkspaces = /* @__PURE__ */ new Set();
22267
+ const inFlightSessionIds = /* @__PURE__ */ new Set();
21432
22268
  const clearBranchSessionEntry = /* @__PURE__ */ __name((sessionId) => {
21433
22269
  for (const [cwd, sid] of activeBranchSessions) {
21434
22270
  if (sid === sessionId) {
@@ -21595,9 +22431,30 @@ function registerSessionRoutes(app, deps) {
21595
22431
  }
21596
22432
  return runtime;
21597
22433
  }, "resolveRuntimeForCatalogRoute");
21598
- const hasActivePersistedSessions = /* @__PURE__ */ __name(async (workspaceCwd) => {
22434
+ const resolveLegacyPrimaryRuntimeFromParam = /* @__PURE__ */ __name((req, res) => {
22435
+ const entry = resolveWorkspaceEntryFromParam(
22436
+ workspaceRegistry,
22437
+ req,
22438
+ res,
22439
+ "id"
22440
+ );
22441
+ if (!entry) return null;
22442
+ if (!entry.primary) {
22443
+ sendWorkspaceMismatch2(res, entry.workspaceCwd);
22444
+ return null;
22445
+ }
22446
+ const runtime = entry.state === "active" ? entry.current?.runtime : void 0;
22447
+ if (!runtime) {
22448
+ sendWorkspaceRuntimeUnavailable(res, entry);
22449
+ return null;
22450
+ }
22451
+ return runtime;
22452
+ }, "resolveLegacyPrimaryRuntimeFromParam");
22453
+ const hasActivePersistedSessions = /* @__PURE__ */ __name(async (runtime) => {
21599
22454
  try {
21600
- const page = await new SessionService(workspaceCwd).listSessions({
22455
+ const page = await createWorkspaceRuntimeSessionService(
22456
+ runtime
22457
+ ).listSessions({
21601
22458
  archiveState: "active",
21602
22459
  size: 1
21603
22460
  });
@@ -21647,20 +22504,28 @@ function registerSessionRoutes(app, deps) {
21647
22504
  try {
21648
22505
  const result = await archiveCoordinator.runSharedMany(
21649
22506
  [sessionId],
21650
- async () => {
22507
+ () => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
21651
22508
  if (target.archiveState === "archived") {
21652
- await assertSessionArchived(target.workspaceCwd, sessionId);
22509
+ await assertSessionArchived(
22510
+ target.runtime.workspaceCwd,
22511
+ sessionId,
22512
+ target.runtime.sessionRuntimeBaseDir
22513
+ );
21653
22514
  } else {
21654
- await assertSessionLoadable(target.workspaceCwd, sessionId);
22515
+ await assertSessionLoadable(
22516
+ target.runtime.workspaceCwd,
22517
+ sessionId,
22518
+ target.runtime.sessionRuntimeBaseDir
22519
+ );
21655
22520
  }
21656
22521
  return exportSessionTranscript({
21657
- workspaceCwd: target.workspaceCwd,
22522
+ workspaceCwd: target.runtime.workspaceCwd,
21658
22523
  sessionId,
21659
22524
  format,
21660
22525
  archiveState: target.archiveState,
21661
22526
  config: { getChannel: /* @__PURE__ */ __name(() => "daemon", "getChannel") }
21662
22527
  });
21663
- }
22528
+ })
21664
22529
  );
21665
22530
  const filename = result.filename.replace(/["\\\r\n]/g, "_");
21666
22531
  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 +22541,7 @@ function registerSessionRoutes(app, deps) {
21676
22541
  sendBridgeError2(res, err, {
21677
22542
  route: target.route,
21678
22543
  sessionId,
21679
- ...target.workspaceQualified ? { workspaceCwd: target.workspaceCwd } : {}
22544
+ ...target.workspaceQualified ? { workspaceCwd: target.runtime.workspaceCwd } : {}
21680
22545
  });
21681
22546
  }
21682
22547
  }, "handleSessionExport");
@@ -21861,7 +22726,8 @@ function registerSessionRoutes(app, deps) {
21861
22726
  const activeInRuntime = /* @__PURE__ */ __name(async (runtime) => {
21862
22727
  const location = await assertSessionLoadable(
21863
22728
  runtime.workspaceCwd,
21864
- sessionId
22729
+ sessionId,
22730
+ runtime.sessionRuntimeBaseDir
21865
22731
  );
21866
22732
  return location === "active";
21867
22733
  }, "activeInRuntime");
@@ -21964,19 +22830,6 @@ function registerSessionRoutes(app, deps) {
21964
22830
  sessionId: e.sessionId,
21965
22831
  error: e.error instanceof Error ? e.error.message : String(e.error)
21966
22832
  })), "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
22833
  const withPrimaryOnlyMutableSession = /* @__PURE__ */ __name((route, handler) => {
21981
22834
  if (!isPrimaryOnlyLiveSessionRoute(route)) {
21982
22835
  throw new Error(`Unregistered primary-only session route: ${route}`);
@@ -22039,201 +22892,246 @@ function registerSessionRoutes(app, deps) {
22039
22892
  }
22040
22893
  const clientId = parseClientIdHeader(req, res);
22041
22894
  if (clientId === null) return;
22042
- let branchMeta;
22043
- let branchBaseCommit;
22044
- const rawBranch = body["branch"];
22045
- if (rawBranch !== void 0 && rawBranch !== null) {
22046
- if (body["worktree"] !== void 0 && body["worktree"] !== null) {
22895
+ const rawSessionId = body["sessionId"];
22896
+ let requestedSessionId;
22897
+ if (rawSessionId !== void 0 && rawSessionId !== null) {
22898
+ if (typeof rawSessionId !== "string" || !HTTP_SESSION_ID_REGEX.test(rawSessionId)) {
22047
22899
  res.status(400).json({
22048
- error: "`branch` and `worktree` are mutually exclusive",
22049
- code: "branch_and_worktree_conflict"
22900
+ error: '`sessionId` must be a UUID (e.g. "550e8400-e29b-41d4-a716-446655440000")',
22901
+ code: "invalid_session_id"
22050
22902
  });
22051
22903
  return;
22052
22904
  }
22053
- if (typeof rawBranch !== "object" || Array.isArray(rawBranch)) {
22054
- res.status(400).json({
22055
- error: '`branch` must be an object (e.g. `{"name":"feat/my-feature"}`)',
22056
- code: "invalid_branch"
22905
+ requestedSessionId = rawSessionId.toLowerCase();
22906
+ const sessionIdToCheck = requestedSessionId;
22907
+ if (isSessionLive(runtime.bridge, sessionIdToCheck)) {
22908
+ res.status(409).json({
22909
+ error: `Session "${requestedSessionId}" already exists`,
22910
+ code: "session_id_conflict"
22057
22911
  });
22058
22912
  return;
22059
22913
  }
22060
- const branchReq = rawBranch;
22061
- const branchName = branchReq["name"];
22062
- if (typeof branchName !== "string" || branchName.length === 0) {
22063
- res.status(400).json({
22064
- error: "`branch.name` must be a non-empty string",
22065
- code: "branch_invalid_name"
22914
+ const runtimeOutputDir = loadSettingsCached(workspaceCwd).merged.advanced?.runtimeOutputDir;
22915
+ if (await Storage.runWithRuntimeBaseDir(
22916
+ runtimeOutputDir,
22917
+ workspaceCwd,
22918
+ () => new SessionService(workspaceCwd).sessionExistsInAnyState(
22919
+ sessionIdToCheck
22920
+ )
22921
+ )) {
22922
+ res.status(409).json({
22923
+ error: `Session "${requestedSessionId}" already exists`,
22924
+ code: "session_id_conflict"
22066
22925
  });
22067
22926
  return;
22068
22927
  }
22069
- if (/[^\p{L}\p{N}._/-]/u.test(branchName) || branchName.includes("..") || branchName.includes("//") || branchName.startsWith(".") || branchName.startsWith("-") || branchName.startsWith("/") || branchName.endsWith("/") || branchName.endsWith(".") || branchName.endsWith(".git") || branchName.includes("@{") || branchName.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")) || branchName.toUpperCase() === GIT_RESERVED_BRANCH || Buffer.byteLength(branchName, "utf8") > MAX_BRANCH_NAME_BYTES || branchName.split("/").some(
22070
- (c) => Buffer.byteLength(c, "utf8") > MAX_BRANCH_COMPONENT_BYTES
22071
- )) {
22072
- res.status(400).json({
22073
- error: `Invalid branch name: ${branchName}`,
22074
- code: "branch_invalid_name"
22928
+ if (inFlightSessionIds.has(requestedSessionId)) {
22929
+ res.status(409).json({
22930
+ error: `Session "${requestedSessionId}" creation already in progress`,
22931
+ code: "session_id_conflict"
22075
22932
  });
22076
22933
  return;
22077
22934
  }
22078
- const existingBranchSession = activeBranchSessions.get(workspaceCwd);
22079
- if (existingBranchSession) {
22080
- try {
22081
- runtime.bridge.getSessionSummary(existingBranchSession);
22935
+ inFlightSessionIds.add(requestedSessionId);
22936
+ }
22937
+ let branchMeta;
22938
+ let branchBaseCommit;
22939
+ let worktreeMeta;
22940
+ try {
22941
+ const rawBranch = body["branch"];
22942
+ if (rawBranch !== void 0 && rawBranch !== null) {
22943
+ if (body["worktree"] !== void 0 && body["worktree"] !== null) {
22944
+ res.status(400).json({
22945
+ error: "`branch` and `worktree` are mutually exclusive",
22946
+ code: "branch_and_worktree_conflict"
22947
+ });
22948
+ return;
22949
+ }
22950
+ if (typeof rawBranch !== "object" || Array.isArray(rawBranch)) {
22951
+ res.status(400).json({
22952
+ error: '`branch` must be an object (e.g. `{"name":"feat/my-feature"}`)',
22953
+ code: "invalid_branch"
22954
+ });
22955
+ return;
22956
+ }
22957
+ const branchReq = rawBranch;
22958
+ const branchName = branchReq["name"];
22959
+ if (typeof branchName !== "string" || branchName.length === 0) {
22960
+ res.status(400).json({
22961
+ error: "`branch.name` must be a non-empty string",
22962
+ code: "branch_invalid_name"
22963
+ });
22964
+ return;
22965
+ }
22966
+ if (/[^\p{L}\p{N}._/-]/u.test(branchName) || branchName.includes("..") || branchName.includes("//") || branchName.startsWith(".") || branchName.startsWith("-") || branchName.startsWith("/") || branchName.endsWith("/") || branchName.endsWith(".") || branchName.endsWith(".git") || branchName.includes("@{") || branchName.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")) || branchName.toUpperCase() === GIT_RESERVED_BRANCH || Buffer.byteLength(branchName, "utf8") > MAX_BRANCH_NAME_BYTES || branchName.split("/").some(
22967
+ (c) => Buffer.byteLength(c, "utf8") > MAX_BRANCH_COMPONENT_BYTES
22968
+ )) {
22969
+ res.status(400).json({
22970
+ error: `Invalid branch name: ${branchName}`,
22971
+ code: "branch_invalid_name"
22972
+ });
22973
+ return;
22974
+ }
22975
+ const existingBranchSession = activeBranchSessions.get(workspaceCwd);
22976
+ if (existingBranchSession) {
22977
+ try {
22978
+ runtime.bridge.getSessionSummary(existingBranchSession);
22979
+ res.status(409).json({
22980
+ error: "A branch session is already active for this workspace",
22981
+ code: "branch_session_conflict",
22982
+ existingSessionId: existingBranchSession
22983
+ });
22984
+ return;
22985
+ } catch {
22986
+ activeBranchSessions.delete(workspaceCwd);
22987
+ }
22988
+ }
22989
+ const sharedCheckoutSession = runtime.bridge.listWorkspaceSessions(workspaceCwd).find((session2) => !session2.worktree && session2.clientCount > 0);
22990
+ if (sharedCheckoutSession) {
22082
22991
  res.status(409).json({
22083
- error: "A branch session is already active for this workspace",
22992
+ error: "Another session is already active in this workspace; creating a branch would move its shared checkout",
22084
22993
  code: "branch_session_conflict",
22085
- existingSessionId: existingBranchSession
22994
+ existingSessionId: sharedCheckoutSession.sessionId
22086
22995
  });
22087
22996
  return;
22997
+ }
22998
+ let wtService;
22999
+ try {
23000
+ wtService = new GitWorktreeService(workspaceCwd);
22088
23001
  } catch {
22089
- activeBranchSessions.delete(workspaceCwd);
23002
+ res.status(500).json({
23003
+ error: "Failed to initialize git service",
23004
+ code: "branch_init_failed"
23005
+ });
23006
+ return;
22090
23007
  }
23008
+ if (!await wtService.isGitRepository()) {
23009
+ res.status(400).json({
23010
+ error: "Branch creation requires a git repository",
23011
+ code: "branch_not_git_repo"
23012
+ });
23013
+ return;
23014
+ }
23015
+ if (await branchExists(workspaceCwd, branchName)) {
23016
+ res.status(409).json({
23017
+ error: `Branch "${branchName}" already exists`,
23018
+ code: "branch_already_exists"
23019
+ });
23020
+ return;
23021
+ }
23022
+ let dirty;
23023
+ try {
23024
+ dirty = await isDirtyTree(workspaceCwd);
23025
+ } catch {
23026
+ res.status(500).json({
23027
+ error: "Failed to check working tree status",
23028
+ code: "branch_status_failed"
23029
+ });
23030
+ return;
23031
+ }
23032
+ if (dirty) {
23033
+ res.status(409).json({
23034
+ error: "Uncommitted changes detected. Commit or stash first.",
23035
+ code: "branch_dirty_tree"
23036
+ });
23037
+ return;
23038
+ }
23039
+ const baseCommit = await getHeadCommit(workspaceCwd);
23040
+ const baseBranch = await wtService.getCurrentBranch().catch(() => "HEAD");
23041
+ if (inFlightBranchWorkspaces.has(workspaceCwd) || activeBranchSessions.has(workspaceCwd)) {
23042
+ res.status(409).json({
23043
+ error: "A branch session is already being created for this workspace",
23044
+ code: "branch_session_conflict"
23045
+ });
23046
+ return;
23047
+ }
23048
+ inFlightBranchWorkspaces.add(workspaceCwd);
23049
+ try {
23050
+ await createBranch(workspaceCwd, branchName);
23051
+ } catch (checkoutErr) {
23052
+ daemonLog?.warn("branch checkout failed", {
23053
+ error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
23054
+ });
23055
+ await rollbackBranchCreation(
23056
+ workspaceCwd,
23057
+ { name: branchName, baseBranch },
23058
+ baseCommit,
23059
+ daemonLog
23060
+ );
23061
+ res.status(500).json({
23062
+ error: "Failed to create branch",
23063
+ code: "branch_checkout_failed"
23064
+ });
23065
+ return;
23066
+ }
23067
+ branchMeta = { name: branchName, baseBranch };
23068
+ branchBaseCommit = baseCommit;
23069
+ sessionScope = "thread";
22091
23070
  }
22092
- const sharedCheckoutSession = runtime.bridge.listWorkspaceSessions(workspaceCwd).find((session) => !session.worktree && session.clientCount > 0);
22093
- if (sharedCheckoutSession) {
22094
- res.status(409).json({
22095
- error: "Another session is already active in this workspace; creating a branch would move its shared checkout",
22096
- code: "branch_session_conflict",
22097
- existingSessionId: sharedCheckoutSession.sessionId
22098
- });
22099
- return;
22100
- }
22101
- let wtService;
22102
- try {
22103
- wtService = new GitWorktreeService(workspaceCwd);
22104
- } catch {
22105
- res.status(500).json({
22106
- error: "Failed to initialize git service",
22107
- code: "branch_init_failed"
22108
- });
22109
- return;
22110
- }
22111
- if (!await wtService.isGitRepository()) {
22112
- res.status(400).json({
22113
- error: "Branch creation requires a git repository",
22114
- code: "branch_not_git_repo"
22115
- });
22116
- return;
22117
- }
22118
- if (await branchExists(workspaceCwd, branchName)) {
22119
- res.status(409).json({
22120
- error: `Branch "${branchName}" already exists`,
22121
- code: "branch_already_exists"
22122
- });
22123
- return;
22124
- }
22125
- let dirty;
22126
- try {
22127
- dirty = await isDirtyTree(workspaceCwd);
22128
- } catch {
22129
- res.status(500).json({
22130
- error: "Failed to check working tree status",
22131
- code: "branch_status_failed"
22132
- });
22133
- return;
22134
- }
22135
- if (dirty) {
22136
- res.status(409).json({
22137
- error: "Uncommitted changes detected. Commit or stash first.",
22138
- code: "branch_dirty_tree"
22139
- });
22140
- return;
22141
- }
22142
- const baseCommit = await getHeadCommit(workspaceCwd);
22143
- const baseBranch = await wtService.getCurrentBranch().catch(() => "HEAD");
22144
- if (inFlightBranchWorkspaces.has(workspaceCwd) || activeBranchSessions.has(workspaceCwd)) {
22145
- res.status(409).json({
22146
- error: "A branch session is already being created for this workspace",
22147
- code: "branch_session_conflict"
22148
- });
22149
- return;
22150
- }
22151
- inFlightBranchWorkspaces.add(workspaceCwd);
22152
- try {
22153
- await createBranch(workspaceCwd, branchName);
22154
- } catch (checkoutErr) {
22155
- daemonLog?.warn("branch checkout failed", {
22156
- error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
22157
- });
22158
- await rollbackBranchCreation(
22159
- workspaceCwd,
22160
- { name: branchName, baseBranch },
22161
- baseCommit,
22162
- daemonLog
22163
- );
22164
- res.status(500).json({
22165
- error: "Failed to create branch",
22166
- code: "branch_checkout_failed"
22167
- });
22168
- return;
22169
- }
22170
- branchMeta = { name: branchName, baseBranch };
22171
- branchBaseCommit = baseCommit;
22172
- sessionScope = "thread";
22173
- }
22174
- let worktreeMeta;
22175
- const rawWorktree = body["worktree"];
22176
- if (rawWorktree !== void 0 && rawWorktree !== null) {
22177
- if (typeof rawWorktree !== "object" || Array.isArray(rawWorktree)) {
22178
- res.status(400).json({
22179
- error: '`worktree` must be an object (e.g. `{}` or `{"slug":"my-task"}`)',
22180
- code: "invalid_worktree"
22181
- });
22182
- return;
22183
- }
22184
- const wtReq = rawWorktree;
22185
- let wtService;
22186
- try {
22187
- wtService = new GitWorktreeService(workspaceCwd);
22188
- } catch {
22189
- res.status(500).json({
22190
- error: "Failed to initialize worktree service",
22191
- code: "worktree_init_failed"
22192
- });
22193
- return;
22194
- }
22195
- if (!await wtService.isGitRepository()) {
22196
- res.status(400).json({
22197
- error: "Worktree isolation requires a git repository",
22198
- code: "worktree_not_git_repo"
22199
- });
22200
- return;
22201
- }
22202
- const rawSlug = wtReq["slug"];
22203
- let slug;
22204
- if (rawSlug === void 0 || rawSlug === null) {
22205
- slug = GitWorktreeService.generateAutoSlug();
22206
- } else if (typeof rawSlug !== "string" || rawSlug.length === 0) {
22207
- res.status(400).json({
22208
- error: "`worktree.slug` must be a non-empty string when provided",
22209
- code: "worktree_invalid_slug"
22210
- });
22211
- return;
22212
- } else {
22213
- slug = rawSlug;
22214
- }
22215
- const slugError = GitWorktreeService.validateUserWorktreeSlug(slug);
22216
- if (slugError) {
22217
- res.status(400).json({ error: slugError, code: "worktree_invalid_slug" });
22218
- return;
23071
+ const rawWorktree = body["worktree"];
23072
+ if (rawWorktree !== void 0 && rawWorktree !== null) {
23073
+ if (typeof rawWorktree !== "object" || Array.isArray(rawWorktree)) {
23074
+ res.status(400).json({
23075
+ error: '`worktree` must be an object (e.g. `{}` or `{"slug":"my-task"}`)',
23076
+ code: "invalid_worktree"
23077
+ });
23078
+ return;
23079
+ }
23080
+ const wtReq = rawWorktree;
23081
+ let wtService;
23082
+ try {
23083
+ wtService = new GitWorktreeService(workspaceCwd);
23084
+ } catch {
23085
+ res.status(500).json({
23086
+ error: "Failed to initialize worktree service",
23087
+ code: "worktree_init_failed"
23088
+ });
23089
+ return;
23090
+ }
23091
+ if (!await wtService.isGitRepository()) {
23092
+ res.status(400).json({
23093
+ error: "Worktree isolation requires a git repository",
23094
+ code: "worktree_not_git_repo"
23095
+ });
23096
+ return;
23097
+ }
23098
+ const rawSlug = wtReq["slug"];
23099
+ let slug;
23100
+ if (rawSlug === void 0 || rawSlug === null) {
23101
+ slug = GitWorktreeService.generateAutoSlug();
23102
+ } else if (typeof rawSlug !== "string" || rawSlug.length === 0) {
23103
+ res.status(400).json({
23104
+ error: "`worktree.slug` must be a non-empty string when provided",
23105
+ code: "worktree_invalid_slug"
23106
+ });
23107
+ return;
23108
+ } else {
23109
+ slug = rawSlug;
23110
+ }
23111
+ const slugError = GitWorktreeService.validateUserWorktreeSlug(slug);
23112
+ if (slugError) {
23113
+ res.status(400).json({ error: slugError, code: "worktree_invalid_slug" });
23114
+ return;
23115
+ }
23116
+ const baseBranch = await wtService.getCurrentBranch().catch(() => void 0);
23117
+ const wtResult = await wtService.createUserWorktree(slug, baseBranch);
23118
+ if (!wtResult.success || !wtResult.worktree) {
23119
+ res.status(500).json({
23120
+ error: wtResult.error ?? "Failed to create worktree",
23121
+ code: "worktree_create_failed"
23122
+ });
23123
+ return;
23124
+ }
23125
+ worktreeMeta = {
23126
+ slug,
23127
+ path: wtResult.worktree.path,
23128
+ branch: wtResult.worktree.branch
23129
+ };
23130
+ sessionScope = "thread";
22219
23131
  }
22220
- const baseBranch = await wtService.getCurrentBranch().catch(() => void 0);
22221
- const wtResult = await wtService.createUserWorktree(slug, baseBranch);
22222
- if (!wtResult.success || !wtResult.worktree) {
22223
- res.status(500).json({
22224
- error: wtResult.error ?? "Failed to create worktree",
22225
- code: "worktree_create_failed"
22226
- });
22227
- return;
23132
+ if (requestedSessionId !== void 0) {
23133
+ sessionScope = "thread";
22228
23134
  }
22229
- worktreeMeta = {
22230
- slug,
22231
- path: wtResult.worktree.path,
22232
- branch: wtResult.worktree.branch
22233
- };
22234
- sessionScope = "thread";
22235
- }
22236
- try {
22237
23135
  const session = await runtime.bridge.spawnOrAttach({
22238
23136
  workspaceCwd,
22239
23137
  modelServiceId,
@@ -22243,20 +23141,60 @@ function registerSessionRoutes(app, deps) {
22243
23141
  ...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
22244
23142
  ...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
22245
23143
  ...worktreeMeta ? { worktree: worktreeMeta } : {},
22246
- ...branchMeta ? { branch: branchMeta } : {}
23144
+ ...branchMeta ? { branch: branchMeta } : {},
23145
+ ...requestedSessionId !== void 0 ? { sessionId: requestedSessionId } : {}
22247
23146
  });
23147
+ if (requestedSessionId !== void 0 && session.sessionId !== requestedSessionId) {
23148
+ if (daemonLog) {
23149
+ daemonLog.warn("session id not honored by agent", {
23150
+ requested: requestedSessionId,
23151
+ actual: session.sessionId
23152
+ });
23153
+ }
23154
+ if (!session.attached) {
23155
+ await runWithWorkspaceRuntimeStorage(
23156
+ runtime,
23157
+ () => deleteDaemonSessionIfOrphan({
23158
+ sessionId: session.sessionId,
23159
+ service: createWorkspaceRuntimeSessionService(runtime),
23160
+ bridge: runtime.bridge,
23161
+ coordinator: archiveCoordinator
23162
+ })
23163
+ ).catch(() => false);
23164
+ }
23165
+ if (worktreeMeta) {
23166
+ await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
23167
+ });
23168
+ }
23169
+ if (branchMeta) {
23170
+ await rollbackBranchCreation(
23171
+ workspaceCwd,
23172
+ branchMeta,
23173
+ branchBaseCommit,
23174
+ daemonLog
23175
+ );
23176
+ }
23177
+ res.status(500).json({
23178
+ error: "Agent did not honor the requested session id",
23179
+ code: "session_id_not_honored"
23180
+ });
23181
+ return;
23182
+ }
22248
23183
  try {
22249
23184
  runtime.generationGuard?.assertOpen();
22250
23185
  } catch (error2) {
22251
23186
  if (!session.attached) {
22252
23187
  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
- );
23188
+ const removed = await runWithWorkspaceRuntimeStorage(
23189
+ runtime,
23190
+ () => deleteDaemonSessionIfOrphan({
23191
+ sessionId: session.sessionId,
23192
+ service: createWorkspaceRuntimeSessionService(runtime),
23193
+ bridge: runtime.bridge,
23194
+ coordinator: archiveCoordinator
23195
+ })
23196
+ );
23197
+ if (removed) {
22260
23198
  if (worktreeMeta) {
22261
23199
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22262
23200
  });
@@ -22288,13 +23226,16 @@ function registerSessionRoutes(app, deps) {
22288
23226
  }
22289
23227
  if (!session.attached) {
22290
23228
  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
- );
23229
+ const removed = await runWithWorkspaceRuntimeStorage(
23230
+ runtime,
23231
+ () => deleteDaemonSessionIfOrphan({
23232
+ sessionId: session.sessionId,
23233
+ service: createWorkspaceRuntimeSessionService(runtime),
23234
+ bridge: runtime.bridge,
23235
+ coordinator: archiveCoordinator
23236
+ })
23237
+ );
23238
+ if (removed) {
22298
23239
  if (worktreeMeta) {
22299
23240
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22300
23241
  });
@@ -22353,9 +23294,9 @@ function registerSessionRoutes(app, deps) {
22353
23294
  ).catch(() => {
22354
23295
  });
22355
23296
  await writeWorktreeSession(
22356
- new SessionService(workspaceCwd).getWorktreeSessionPath(
22357
- session.sessionId
22358
- ),
23297
+ createWorkspaceRuntimeSessionService(
23298
+ runtime
23299
+ ).getWorktreeSessionPath(session.sessionId),
22359
23300
  {
22360
23301
  slug: worktreeMeta.slug,
22361
23302
  worktreePath: worktreeMeta.path,
@@ -22373,11 +23314,15 @@ function registerSessionRoutes(app, deps) {
22373
23314
  error: cdErr instanceof Error ? cdErr.message : String(cdErr)
22374
23315
  });
22375
23316
  }
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
- }
23317
+ await runWithWorkspaceRuntimeStorage(
23318
+ runtime,
23319
+ () => deleteDaemonSessionIfOrphan({
23320
+ sessionId: session.sessionId,
23321
+ service: createWorkspaceRuntimeSessionService(runtime),
23322
+ bridge: runtime.bridge,
23323
+ coordinator: archiveCoordinator
23324
+ })
23325
+ ).catch(() => false);
22381
23326
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
22382
23327
  });
22383
23328
  res.status(500).json({
@@ -22406,6 +23351,10 @@ function registerSessionRoutes(app, deps) {
22406
23351
  );
22407
23352
  }
22408
23353
  sendBridgeError2(res, err, { route: "POST /session" });
23354
+ } finally {
23355
+ if (requestedSessionId !== void 0) {
23356
+ inFlightSessionIds.delete(requestedSessionId);
23357
+ }
22409
23358
  }
22410
23359
  });
22411
23360
  const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
@@ -22502,9 +23451,13 @@ function registerSessionRoutes(app, deps) {
22502
23451
  const session = await archiveCoordinator.runSharedMany(
22503
23452
  [sessionId],
22504
23453
  async () => {
22505
- await assertSessionLoadable(workspaceCwd, sessionId);
22506
- const metadata = await new SessionService(
22507
- workspaceCwd
23454
+ await assertSessionLoadable(
23455
+ workspaceCwd,
23456
+ sessionId,
23457
+ runtime.sessionRuntimeBaseDir
23458
+ );
23459
+ const metadata = await createWorkspaceRuntimeSessionService(
23460
+ runtime
22508
23461
  ).readCreationMetadata(sessionId);
22509
23462
  runtime.generationGuard?.assertOpen();
22510
23463
  return action === "load" ? await runtime.bridge.loadSession({
@@ -22554,7 +23507,9 @@ function registerSessionRoutes(app, deps) {
22554
23507
  }
22555
23508
  if (!session.worktree) {
22556
23509
  const sidecar = await readWorktreeSession(
22557
- new SessionService(workspaceCwd).getWorktreeSessionPath(sessionId)
23510
+ createWorkspaceRuntimeSessionService(
23511
+ runtime
23512
+ ).getWorktreeSessionPath(sessionId)
22558
23513
  ).catch(() => null);
22559
23514
  if (sidecar) {
22560
23515
  let realTarget;
@@ -22757,13 +23712,72 @@ function registerSessionRoutes(app, deps) {
22757
23712
  { name },
22758
23713
  { clientId }
22759
23714
  );
23715
+ try {
23716
+ runtime.generationGuard?.assertOpen();
23717
+ } catch (error2) {
23718
+ if (!result.attached) {
23719
+ await runWithWorkspaceRuntimeStorage(
23720
+ runtime,
23721
+ () => deleteDaemonSessionIfOrphan({
23722
+ sessionId: result.sessionId,
23723
+ service: createWorkspaceRuntimeSessionService(runtime),
23724
+ bridge: runtime.bridge,
23725
+ coordinator: archiveCoordinator
23726
+ })
23727
+ ).catch(() => false);
23728
+ } else {
23729
+ await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
23730
+ });
23731
+ }
23732
+ throw error2;
23733
+ }
23734
+ if (!res.writable) {
23735
+ if (!result.attached) {
23736
+ void runWithWorkspaceRuntimeStorage(
23737
+ runtime,
23738
+ () => deleteDaemonSessionIfOrphan({
23739
+ sessionId: result.sessionId,
23740
+ service: createWorkspaceRuntimeSessionService(runtime),
23741
+ bridge: runtime.bridge,
23742
+ coordinator: archiveCoordinator
23743
+ })
23744
+ ).catch(() => {
23745
+ });
23746
+ } else {
23747
+ runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
23748
+ });
23749
+ }
23750
+ return;
23751
+ }
23752
+ res.status(201).json(result);
23753
+ }
23754
+ )
23755
+ );
23756
+ app.post(
23757
+ "/session/:id/side-task",
23758
+ mutate(),
23759
+ withPrimaryOnlyMutableSession(
23760
+ "POST /session/:id/side-task",
23761
+ async (req, res, sessionId, runtime) => {
23762
+ const body = safeBody(req);
23763
+ let name = typeof body?.["name"] === "string" ? body["name"] : void 0;
23764
+ if (name) {
23765
+ name = Array.from(name.replace(/[\x00-\x1F\x7F-\x9F]/g, "")).slice(0, 200).join("");
23766
+ }
23767
+ const clientId = parseClientIdHeader(req, res);
23768
+ if (clientId === null) return;
23769
+ const result = await runtime.bridge.createSideTaskSession(
23770
+ sessionId,
23771
+ { name },
23772
+ { clientId }
23773
+ );
22760
23774
  try {
22761
23775
  runtime.generationGuard?.assertOpen();
22762
23776
  } catch (error2) {
22763
23777
  if (!result.attached) {
22764
23778
  const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
22765
23779
  if (killed) {
22766
- await new SessionService(runtime.workspaceCwd).removeSession(result.sessionId).catch(() => {
23780
+ await createWorkspaceRuntimeSessionService(runtime).removeSession(result.sessionId).catch(() => {
22767
23781
  });
22768
23782
  }
22769
23783
  } else {
@@ -22774,7 +23788,12 @@ function registerSessionRoutes(app, deps) {
22774
23788
  }
22775
23789
  if (!res.writable) {
22776
23790
  if (!result.attached) {
22777
- runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => {
23791
+ runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
23792
+ if (!killed) return void 0;
23793
+ return createWorkspaceRuntimeSessionService(
23794
+ runtime
23795
+ ).removeSession(result.sessionId);
23796
+ }).catch(() => {
22778
23797
  });
22779
23798
  } else {
22780
23799
  runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
@@ -22870,7 +23889,7 @@ function registerSessionRoutes(app, deps) {
22870
23889
  app.get("/session/:id/export", async (req, res) => {
22871
23890
  await handleSessionExport(req, res, {
22872
23891
  route: "GET /session/:id/export",
22873
- workspaceCwd: boundWorkspace
23892
+ runtime: workspaceRegistry.primary
22874
23893
  });
22875
23894
  });
22876
23895
  app.get("/workspaces/:workspace/session/:id/export", async (req, res) => {
@@ -22879,7 +23898,7 @@ function registerSessionRoutes(app, deps) {
22879
23898
  if (!runtime) return;
22880
23899
  await handleSessionExport(req, res, {
22881
23900
  route,
22882
- workspaceCwd: runtime.workspaceCwd,
23901
+ runtime,
22883
23902
  workspaceQualified: true
22884
23903
  });
22885
23904
  });
@@ -22891,7 +23910,7 @@ function registerSessionRoutes(app, deps) {
22891
23910
  if (!runtime) return;
22892
23911
  await handleSessionExport(req, res, {
22893
23912
  route,
22894
- workspaceCwd: runtime.workspaceCwd,
23913
+ runtime,
22895
23914
  workspaceQualified: true,
22896
23915
  archiveState: "archived"
22897
23916
  });
@@ -22988,67 +24007,74 @@ function registerSessionRoutes(app, deps) {
22988
24007
  }
22989
24008
  try {
22990
24009
  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);
24010
+ () => archiveCoordinator.runSharedMany(
24011
+ [sessionId],
24012
+ () => runWithWorkspaceRuntimeStorage(runtime, async () => {
24013
+ const service = createWorkspaceRuntimeSessionService(runtime);
24014
+ if (cursor === void 0) {
24015
+ await assertSessionLoadable(
24016
+ runtime.workspaceCwd,
24017
+ sessionId,
24018
+ runtime.sessionRuntimeBaseDir
24019
+ );
23015
24020
  }
23016
- const location = await service.getSessionLocation(sessionId);
23017
- if (location === "archived") {
23018
- throw new SessionArchivedError(sessionId);
24021
+ const codec = getTranscriptCursorCodec(runtime);
24022
+ const reader = new SessionTranscriptReader(
24023
+ runtime.workspaceCwd,
24024
+ codec
24025
+ );
24026
+ let page;
24027
+ try {
24028
+ page = await reader.readPage(sessionId, {
24029
+ ...limit !== void 0 ? { limit } : {},
24030
+ ...cursor !== void 0 ? { cursor } : {},
24031
+ ...beforeRecordId !== void 0 ? { beforeRecordId } : {},
24032
+ maxBytes: SESSION_TRANSCRIPT_MAX_PAGE_BYTES
24033
+ });
24034
+ } catch (error2) {
24035
+ if (error2.code !== "ENOENT") {
24036
+ throw error2;
24037
+ }
24038
+ if (cursor !== void 0) {
24039
+ throw new SessionTranscriptSnapshotUnavailableError(sessionId);
24040
+ }
24041
+ const location = await service.getSessionLocation(sessionId);
24042
+ if (location === "archived") {
24043
+ throw new SessionArchivedError(sessionId);
24044
+ }
24045
+ if (location === "conflict") {
24046
+ throw new SessionConflictError(sessionId);
24047
+ }
24048
+ throw new SessionNotFoundError(sessionId);
23019
24049
  }
23020
- if (location === "conflict") {
23021
- throw new SessionConflictError(sessionId);
24050
+ if (page.records.some((record) => record.sessionId !== sessionId)) {
24051
+ throw new SessionTranscriptSnapshotUnavailableError(sessionId);
23022
24052
  }
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) => ({
24053
+ const replay = await replayTranscriptRecordPage({
24054
+ sessionId,
24055
+ page,
24056
+ encodeCursor: /* @__PURE__ */ __name((state) => codec.encode(state), "encodeCursor")
24057
+ });
24058
+ const cursorTooLarge = replay.nextCursor !== void 0 && Buffer.byteLength(replay.nextCursor) > WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES;
24059
+ return {
23038
24060
  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
- })
24061
+ sessionId,
24062
+ events: replay.updates.map((update) => ({
24063
+ v: 1,
24064
+ type: "session_update",
24065
+ data: update
24066
+ })),
24067
+ ...replay.nextCursor && !cursorTooLarge ? { nextCursor: replay.nextCursor } : {},
24068
+ hasMore: cursorTooLarge ? false : replay.hasMore,
24069
+ startTime: replay.startTime,
24070
+ lastUpdated: replay.lastUpdated,
24071
+ ...replay.partial || cursorTooLarge ? {
24072
+ partial: true,
24073
+ replayError: cursorTooLarge ? TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR : replay.replayError
24074
+ } : {}
24075
+ };
24076
+ })
24077
+ )
23052
24078
  );
23053
24079
  const serialized = serializeWorkspaceTranscriptResponse(
23054
24080
  result,
@@ -23701,18 +24727,22 @@ function registerSessionRoutes(app, deps) {
23701
24727
  const uniqueIds = parseSessionIdsBody(req, res);
23702
24728
  if (uniqueIds === void 0) return;
23703
24729
  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
- });
24730
+ const runtime = workspaceRegistry.primary;
24731
+ const service = createWorkspaceRuntimeSessionService(runtime);
24732
+ const result = await runWithWorkspaceRuntimeStorage(
24733
+ runtime,
24734
+ () => deleteDaemonSessions({
24735
+ sessionIds: uniqueIds,
24736
+ service,
24737
+ bridge,
24738
+ coordinator: archiveCoordinator,
24739
+ onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
24740
+ writeStderrLine(
24741
+ `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
24742
+ );
24743
+ }, "onError")
24744
+ })
24745
+ );
23716
24746
  for (const removedId of result.removed) {
23717
24747
  clearBranchSessionEntry(removedId);
23718
24748
  }
@@ -23724,16 +24754,20 @@ function registerSessionRoutes(app, deps) {
23724
24754
  app.post("/sessions/archive", mutate(), async (req, res) => {
23725
24755
  const uniqueIds = parseSessionIdsBody(req, res);
23726
24756
  if (uniqueIds === void 0) return;
23727
- const service = new SessionService(boundWorkspace, {
24757
+ const runtime = workspaceRegistry.primary;
24758
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23728
24759
  onWarning: logSessionArchiveWarning
23729
24760
  });
23730
24761
  try {
23731
- const result = await archiveDaemonSessions({
23732
- sessionIds: uniqueIds,
23733
- service,
23734
- bridge,
23735
- coordinator: archiveCoordinator
23736
- });
24762
+ const result = await runWithWorkspaceRuntimeStorage(
24763
+ runtime,
24764
+ () => archiveDaemonSessions({
24765
+ sessionIds: uniqueIds,
24766
+ service,
24767
+ bridge,
24768
+ coordinator: archiveCoordinator
24769
+ })
24770
+ );
23737
24771
  res.status(200).json({
23738
24772
  archived: result.archived,
23739
24773
  alreadyArchived: result.alreadyArchived,
@@ -23747,15 +24781,19 @@ function registerSessionRoutes(app, deps) {
23747
24781
  app.post("/sessions/unarchive", mutate(), async (req, res) => {
23748
24782
  const uniqueIds = parseSessionIdsBody(req, res);
23749
24783
  if (uniqueIds === void 0) return;
23750
- const service = new SessionService(boundWorkspace, {
24784
+ const runtime = workspaceRegistry.primary;
24785
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23751
24786
  onWarning: logSessionArchiveWarning
23752
24787
  });
23753
24788
  try {
23754
- const result = await unarchiveDaemonSessions({
23755
- sessionIds: uniqueIds,
23756
- service,
23757
- coordinator: archiveCoordinator
23758
- });
24789
+ const result = await runWithWorkspaceRuntimeStorage(
24790
+ runtime,
24791
+ () => unarchiveDaemonSessions({
24792
+ sessionIds: uniqueIds,
24793
+ service,
24794
+ coordinator: archiveCoordinator
24795
+ })
24796
+ );
23759
24797
  res.status(200).json({
23760
24798
  unarchived: result.unarchived,
23761
24799
  alreadyActive: result.alreadyActive,
@@ -23778,18 +24816,21 @@ function registerSessionRoutes(app, deps) {
23778
24816
  const uniqueIds = parseSessionIdsBody(req, res);
23779
24817
  if (uniqueIds === void 0) return;
23780
24818
  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
- });
24819
+ const service = createWorkspaceRuntimeSessionService(runtime);
24820
+ const result = await runWithWorkspaceRuntimeStorage(
24821
+ runtime,
24822
+ () => deleteDaemonSessions({
24823
+ sessionIds: uniqueIds,
24824
+ service,
24825
+ bridge: runtime.bridge,
24826
+ coordinator: archiveCoordinator,
24827
+ onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
24828
+ writeStderrLine(
24829
+ `qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
24830
+ );
24831
+ }, "onError")
24832
+ })
24833
+ );
23793
24834
  for (const removedId of result.removed) {
23794
24835
  clearBranchSessionEntry(removedId);
23795
24836
  }
@@ -23808,16 +24849,19 @@ function registerSessionRoutes(app, deps) {
23808
24849
  if (!runtime) return;
23809
24850
  const uniqueIds = parseSessionIdsBody(req, res);
23810
24851
  if (uniqueIds === void 0) return;
23811
- const service = new SessionService(runtime.workspaceCwd, {
24852
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23812
24853
  onWarning: logSessionArchiveWarning
23813
24854
  });
23814
24855
  try {
23815
- const result = await archiveDaemonSessions({
23816
- sessionIds: uniqueIds,
23817
- service,
23818
- bridge: runtime.bridge,
23819
- coordinator: archiveCoordinator
23820
- });
24856
+ const result = await runWithWorkspaceRuntimeStorage(
24857
+ runtime,
24858
+ () => archiveDaemonSessions({
24859
+ sessionIds: uniqueIds,
24860
+ service,
24861
+ bridge: runtime.bridge,
24862
+ coordinator: archiveCoordinator
24863
+ })
24864
+ );
23821
24865
  res.status(200).json({
23822
24866
  archived: result.archived,
23823
24867
  alreadyArchived: result.alreadyArchived,
@@ -23838,15 +24882,18 @@ function registerSessionRoutes(app, deps) {
23838
24882
  if (!runtime) return;
23839
24883
  const uniqueIds = parseSessionIdsBody(req, res);
23840
24884
  if (uniqueIds === void 0) return;
23841
- const service = new SessionService(runtime.workspaceCwd, {
24885
+ const service = createWorkspaceRuntimeSessionService(runtime, {
23842
24886
  onWarning: logSessionArchiveWarning
23843
24887
  });
23844
24888
  try {
23845
- const result = await unarchiveDaemonSessions({
23846
- sessionIds: uniqueIds,
23847
- service,
23848
- coordinator: archiveCoordinator
23849
- });
24889
+ const result = await runWithWorkspaceRuntimeStorage(
24890
+ runtime,
24891
+ () => unarchiveDaemonSessions({
24892
+ sessionIds: uniqueIds,
24893
+ service,
24894
+ coordinator: archiveCoordinator
24895
+ })
24896
+ );
23850
24897
  res.status(200).json({
23851
24898
  unarchived: result.unarchived,
23852
24899
  alreadyActive: result.alreadyActive,
@@ -23890,74 +24937,80 @@ function registerSessionRoutes(app, deps) {
23890
24937
  const sessionId = requireSessionId(req, res);
23891
24938
  if (sessionId === null) return;
23892
24939
  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;
24940
+ await archiveCoordinator.runSharedMany(
24941
+ [sessionId],
24942
+ () => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
24943
+ const sessionService = createWorkspaceRuntimeSessionService(
24944
+ target.runtime
24945
+ );
24946
+ let exists = await sessionService.sessionExistsInAnyState(sessionId);
24947
+ if (!exists) {
24948
+ try {
24949
+ const summary = target.runtime.bridge.getSessionSummary(sessionId);
24950
+ exists = summary.workspaceCwd === target.runtime.workspaceCwd;
24951
+ } catch {
24952
+ exists = false;
24953
+ }
23902
24954
  }
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"
24955
+ if (!exists) {
24956
+ res.status(404).json({
24957
+ error: `No session with id "${sessionId}"`,
24958
+ sessionId
24959
+ });
24960
+ return;
24961
+ }
24962
+ const body = safeBody(req);
24963
+ const rawIsPinned = body["isPinned"];
24964
+ if (rawIsPinned !== void 0 && typeof rawIsPinned !== "boolean") {
24965
+ res.status(400).json({
24966
+ error: "`isPinned` must be a boolean",
24967
+ code: "invalid_session_organization",
24968
+ field: "isPinned"
24969
+ });
24970
+ return;
24971
+ }
24972
+ const rawGroupId = body["groupId"];
24973
+ if (rawGroupId !== void 0 && rawGroupId !== null && typeof rawGroupId !== "string") {
24974
+ res.status(400).json({
24975
+ error: "`groupId` must be a string or null",
24976
+ code: "invalid_session_organization",
24977
+ field: "groupId"
24978
+ });
24979
+ return;
24980
+ }
24981
+ const rawColor = body["color"];
24982
+ if (rawColor !== void 0 && rawColor !== null && (typeof rawColor !== "string" || !GROUP_COLOR_OPTIONS.includes(
24983
+ rawColor
24984
+ ))) {
24985
+ res.status(400).json({
24986
+ error: "`color` must be a supported color or null",
24987
+ code: "invalid_session_organization",
24988
+ field: "color"
24989
+ });
24990
+ return;
24991
+ }
24992
+ const organization = await createSessionOrganizationService(
24993
+ target.runtime.workspaceCwd
24994
+ ).updateSessionOrganization(sessionId, {
24995
+ ...rawIsPinned !== void 0 ? { isPinned: rawIsPinned } : {},
24996
+ ...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
24997
+ ...rawColor !== void 0 ? { color: rawColor } : {}
23936
24998
  });
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
- });
24999
+ res.status(200).json({ sessionId, ...organization });
25000
+ })
25001
+ );
23948
25002
  } catch (err) {
23949
25003
  if (sendSessionOrganizationError(res, err)) return;
23950
25004
  sendBridgeError2(res, err, {
23951
25005
  route: target.route,
23952
25006
  sessionId,
23953
- workspaceCwd: target.workspaceCwd
25007
+ workspaceCwd: target.runtime.workspaceCwd
23954
25008
  });
23955
25009
  }
23956
25010
  }, "handleSessionOrganizationUpdate");
23957
25011
  app.patch("/session/:id/organization", mutate(), async (req, res) => {
23958
25012
  await handleSessionOrganizationUpdate(req, res, {
23959
- workspaceCwd: boundWorkspace,
23960
- bridge,
25013
+ runtime: workspaceRegistry.primary,
23961
25014
  route: "PATCH /session/:id/organization"
23962
25015
  });
23963
25016
  });
@@ -23969,8 +25022,7 @@ function registerSessionRoutes(app, deps) {
23969
25022
  const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
23970
25023
  if (!runtime) return;
23971
25024
  await handleSessionOrganizationUpdate(req, res, {
23972
- workspaceCwd: runtime.workspaceCwd,
23973
- bridge: runtime.bridge,
25025
+ runtime,
23974
25026
  route
23975
25027
  });
23976
25028
  }
@@ -23992,14 +25044,17 @@ function registerSessionRoutes(app, deps) {
23992
25044
  }
23993
25045
  });
23994
25046
  app.post("/workspace/:id/session-groups", mutate(), async (req, res) => {
23995
- const key = resolveWorkspaceParam(req, res);
23996
- if (key === null) return;
25047
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
25048
+ if (runtime === null) return;
23997
25049
  const body = safeBody(req);
23998
25050
  try {
23999
- const group = await createSessionOrganizationService(key).createGroup({
24000
- name: body["name"],
24001
- color: body["color"]
24002
- });
25051
+ const group = await runWithWorkspaceRuntimeStorage(
25052
+ runtime,
25053
+ () => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
25054
+ name: body["name"],
25055
+ color: body["color"]
25056
+ })
25057
+ );
24003
25058
  res.status(201).json({ group });
24004
25059
  } catch (err) {
24005
25060
  if (sendSessionOrganizationError(res, err)) return;
@@ -24012,17 +25067,20 @@ function registerSessionRoutes(app, deps) {
24012
25067
  "/workspace/:id/session-groups/:groupId",
24013
25068
  mutate(),
24014
25069
  async (req, res) => {
24015
- const key = resolveWorkspaceParam(req, res);
24016
- if (key === null) return;
25070
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
25071
+ if (runtime === null) return;
24017
25072
  const body = safeBody(req);
24018
25073
  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
- }
25074
+ const group = await runWithWorkspaceRuntimeStorage(
25075
+ runtime,
25076
+ () => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
25077
+ req.params["groupId"] ?? "",
25078
+ {
25079
+ ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
25080
+ ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
25081
+ ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
25082
+ }
25083
+ )
24026
25084
  );
24027
25085
  res.status(200).json({ group });
24028
25086
  } catch (err) {
@@ -24037,11 +25095,14 @@ function registerSessionRoutes(app, deps) {
24037
25095
  "/workspace/:id/session-groups/:groupId",
24038
25096
  mutate(),
24039
25097
  async (req, res) => {
24040
- const key = resolveWorkspaceParam(req, res);
24041
- if (key === null) return;
25098
+ const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
25099
+ if (runtime === null) return;
24042
25100
  try {
24043
- const deleted = await createSessionOrganizationService(key).deleteGroup(
24044
- req.params["groupId"] ?? ""
25101
+ const deleted = await runWithWorkspaceRuntimeStorage(
25102
+ runtime,
25103
+ () => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
25104
+ req.params["groupId"] ?? ""
25105
+ )
24045
25106
  );
24046
25107
  res.status(200).json({ deleted });
24047
25108
  } catch (err) {
@@ -24076,12 +25137,13 @@ function registerSessionRoutes(app, deps) {
24076
25137
  if (!runtime) return;
24077
25138
  const body = safeBody(req);
24078
25139
  try {
24079
- const group = await createSessionOrganizationService(
24080
- runtime.workspaceCwd
24081
- ).createGroup({
24082
- name: body["name"],
24083
- color: body["color"]
24084
- });
25140
+ const group = await runWithWorkspaceRuntimeStorage(
25141
+ runtime,
25142
+ () => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
25143
+ name: body["name"],
25144
+ color: body["color"]
25145
+ })
25146
+ );
24085
25147
  res.status(201).json({ group });
24086
25148
  } catch (err) {
24087
25149
  if (sendSessionOrganizationError(res, err)) return;
@@ -24098,13 +25160,17 @@ function registerSessionRoutes(app, deps) {
24098
25160
  if (!runtime) return;
24099
25161
  const body = safeBody(req);
24100
25162
  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
- });
25163
+ const group = await runWithWorkspaceRuntimeStorage(
25164
+ runtime,
25165
+ () => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
25166
+ req.params["groupId"] ?? "",
25167
+ {
25168
+ ...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
25169
+ ...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
25170
+ ...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
25171
+ }
25172
+ )
25173
+ );
24108
25174
  res.status(200).json({ group });
24109
25175
  } catch (err) {
24110
25176
  if (sendSessionOrganizationError(res, err)) return;
@@ -24120,9 +25186,12 @@ function registerSessionRoutes(app, deps) {
24120
25186
  const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
24121
25187
  if (!runtime) return;
24122
25188
  try {
24123
- const deleted = await createSessionOrganizationService(
24124
- runtime.workspaceCwd
24125
- ).deleteGroup(req.params["groupId"] ?? "");
25189
+ const deleted = await runWithWorkspaceRuntimeStorage(
25190
+ runtime,
25191
+ () => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
25192
+ req.params["groupId"] ?? ""
25193
+ )
25194
+ );
24126
25195
  res.status(200).json({ deleted });
24127
25196
  } catch (err) {
24128
25197
  if (sendSessionOrganizationError(res, err)) return;
@@ -24210,7 +25279,7 @@ function registerSessionRoutes(app, deps) {
24210
25279
  ...parentSessionId !== void 0 ? { parentSessionId } : {},
24211
25280
  ...parsedSource
24212
25281
  };
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));
25282
+ 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
25283
  if (!usePersisted && (view !== void 0 || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0)) {
24215
25284
  throw new Error(
24216
25285
  "session list live path received persisted-only options"
@@ -24707,11 +25776,14 @@ function requireOpenGeneration2(target, res) {
24707
25776
  }
24708
25777
  }
24709
25778
  __name(requireOpenGeneration2, "requireOpenGeneration");
24710
- async function rollbackCronMutation(workspaceCwd, before, after, route) {
25779
+ async function rollbackCronMutation(target, before, after, route) {
24711
25780
  if (!before || !after) return;
24712
- await updateCronTasks(
24713
- workspaceCwd,
24714
- (tasks) => isDeepStrictEqual2(tasks, after) ? before : tasks
25781
+ await runWithScheduledTaskTarget(
25782
+ target,
25783
+ () => updateCronTasks(
25784
+ target.workspaceCwd,
25785
+ (tasks) => isDeepStrictEqual2(tasks, after) ? before : tasks
25786
+ )
24715
25787
  ).catch((error2) => {
24716
25788
  writeStderrLine(
24717
25789
  `qwen serve: ${route} failed to roll back a stale task mutation: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -24719,6 +25791,27 @@ async function rollbackCronMutation(workspaceCwd, before, after, route) {
24719
25791
  });
24720
25792
  }
24721
25793
  __name(rollbackCronMutation, "rollbackCronMutation");
25794
+ async function teardownBoundSession(target, sessionId) {
25795
+ if (target.cleanupSession) {
25796
+ await target.cleanupSession(sessionId).catch(() => {
25797
+ });
25798
+ } else if (target.bridge) {
25799
+ await target.bridge.closeSession(sessionId).catch(() => {
25800
+ });
25801
+ await new SessionService(target.workspaceCwd, {
25802
+ runtimeBaseDir: target.runtimeBaseDir
25803
+ }).removeSession(sessionId).catch(() => {
25804
+ });
25805
+ }
25806
+ }
25807
+ __name(teardownBoundSession, "teardownBoundSession");
25808
+ function runWithScheduledTaskTarget(target, fn) {
25809
+ if (target.runtimeBaseDir === void 0) {
25810
+ return fn();
25811
+ }
25812
+ return Storage.runWithResolvedRuntimeBaseDir(target.runtimeBaseDir, fn);
25813
+ }
25814
+ __name(runWithScheduledTaskTarget, "runWithScheduledTaskTarget");
24722
25815
  function computeNextRunAt(task) {
24723
25816
  if (task.enabled === false) return null;
24724
25817
  return nextDurableFireMs(task);
@@ -24793,7 +25886,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24793
25886
  if (!target) return;
24794
25887
  if (!requireOpenGeneration2(target, res)) return;
24795
25888
  try {
24796
- const tasks = await readCronTasks(target.workspaceCwd);
25889
+ const tasks = await runWithScheduledTaskTarget(
25890
+ target,
25891
+ () => readCronTasks(target.workspaceCwd)
25892
+ );
24797
25893
  if (!requireOpenGeneration2(target, res)) return;
24798
25894
  res.status(200).json({ v: 1, tasks: tasks.map(toView) });
24799
25895
  } catch (err) {
@@ -24887,7 +25983,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24887
25983
  let boundSessionId;
24888
25984
  if (bridge) {
24889
25985
  try {
24890
- if ((await readCronTasks(workspaceCwd)).length >= MAX_SCHEDULED_TASKS) {
25986
+ if ((await runWithScheduledTaskTarget(
25987
+ target,
25988
+ () => readCronTasks(workspaceCwd)
25989
+ )).length >= MAX_SCHEDULED_TASKS) {
24891
25990
  res.status(409).json({
24892
25991
  error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
24893
25992
  code: "max_tasks_reached"
@@ -24906,10 +26005,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24906
26005
  });
24907
26006
  boundSessionId = session.sessionId;
24908
26007
  if (!requireOpenGeneration2(target, res)) {
24909
- await bridge.closeSession(boundSessionId).catch(() => {
24910
- });
24911
- await new SessionService(workspaceCwd).removeSession(boundSessionId).catch(() => {
24912
- });
26008
+ await teardownBoundSession(target, boundSessionId);
24913
26009
  return;
24914
26010
  }
24915
26011
  try {
@@ -24946,29 +26042,29 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24946
26042
  ...nameResult.value !== void 0 ? { name: nameResult.value } : {}
24947
26043
  };
24948
26044
  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
- });
26045
+ if (boundSessionId !== void 0) {
26046
+ await teardownBoundSession(target, boundSessionId);
24954
26047
  }
24955
26048
  }, "rollbackSession");
24956
26049
  let overCap = false;
24957
26050
  let rollbackBefore;
24958
26051
  let rollbackAfter;
24959
26052
  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 }
26053
+ await runWithScheduledTaskTarget(
26054
+ target,
26055
+ () => updateCronTasks(
26056
+ workspaceCwd,
26057
+ (tasks) => {
26058
+ if (tasks.length >= MAX_SCHEDULED_TASKS) {
26059
+ overCap = true;
26060
+ return tasks;
26061
+ }
26062
+ rollbackBefore = tasks;
26063
+ rollbackAfter = [...tasks, task];
26064
+ return rollbackAfter;
26065
+ },
26066
+ { assertCanCommit: target.assertGenerationOpen }
26067
+ )
24972
26068
  );
24973
26069
  } catch (err) {
24974
26070
  await rollbackSession();
@@ -24987,7 +26083,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
24987
26083
  target.assertGenerationOpen?.();
24988
26084
  } catch (error2) {
24989
26085
  await rollbackCronMutation(
24990
- workspaceCwd,
26086
+ target,
24991
26087
  rollbackBefore,
24992
26088
  rollbackAfter,
24993
26089
  `POST ${base}`
@@ -25121,44 +26217,47 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25121
26217
  let rollbackBefore;
25122
26218
  let rollbackAfter;
25123
26219
  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;
26220
+ await runWithScheduledTaskTarget(
26221
+ target,
26222
+ () => updateCronTasks(
26223
+ workspaceCwd,
26224
+ (tasks) => {
26225
+ const idx = tasks.findIndex((t) => t.id === id);
26226
+ if (idx === -1) return tasks;
26227
+ found = true;
26228
+ const current = tasks[idx];
26229
+ if (patch.enabled === true && taskHasLegacyCondition(current)) {
26230
+ blockedLegacy = true;
26231
+ return tasks;
25154
26232
  }
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 }
26233
+ if (patch.enabled === true && current.disabledByArchive === true) {
26234
+ blockedByArchive = true;
26235
+ return tasks;
26236
+ }
26237
+ const next = { ...current, ...patch };
26238
+ if (clearName) delete next.name;
26239
+ if (clearDelivery) delete next.delivery;
26240
+ const justReEnabled = current.enabled === false && patch.enabled === true;
26241
+ const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
26242
+ const becameRecurring = patch.recurring === true && current.recurring !== true;
26243
+ const becameOneShot = patch.recurring === false && current.recurring !== false;
26244
+ {
26245
+ const now = Date.now();
26246
+ const minute = now - now % 6e4;
26247
+ if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
26248
+ next.lastFiredAt = minute;
26249
+ } else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
26250
+ next.createdAt = now;
26251
+ next.lastFiredAt = minute;
26252
+ }
26253
+ }
26254
+ updated = next;
26255
+ rollbackBefore = tasks;
26256
+ rollbackAfter = tasks.map((t, i) => i === idx ? next : t);
26257
+ return rollbackAfter;
26258
+ },
26259
+ { assertCanCommit: target.assertGenerationOpen }
26260
+ )
25162
26261
  );
25163
26262
  } catch (err) {
25164
26263
  if (sendGenerationClosedError(res, err)) return;
@@ -25176,7 +26275,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25176
26275
  target.assertGenerationOpen?.();
25177
26276
  } catch (error2) {
25178
26277
  await rollbackCronMutation(
25179
- workspaceCwd,
26278
+ target,
25180
26279
  rollbackBefore,
25181
26280
  rollbackAfter,
25182
26281
  `PATCH ${base}/${id}`
@@ -25245,21 +26344,24 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25245
26344
  let rollbackBefore;
25246
26345
  let rollbackAfter;
25247
26346
  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 }
26347
+ await runWithScheduledTaskTarget(
26348
+ target,
26349
+ () => updateCronTasks(
26350
+ workspaceCwd,
26351
+ (tasks) => {
26352
+ const idx = tasks.findIndex((t) => t.id === id);
26353
+ if (idx === -1) return tasks;
26354
+ const match = tasks[idx].sessionId;
26355
+ if (typeof match === "string" && match.length > 0) {
26356
+ boundSessionId = match;
26357
+ }
26358
+ removed = true;
26359
+ rollbackBefore = tasks;
26360
+ rollbackAfter = tasks.filter((_, i) => i !== idx);
26361
+ return rollbackAfter;
26362
+ },
26363
+ { assertCanCommit: target.assertGenerationOpen }
26364
+ )
25263
26365
  );
25264
26366
  } catch (err) {
25265
26367
  if (sendGenerationClosedError(res, err)) return;
@@ -25277,7 +26379,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25277
26379
  target.assertGenerationOpen?.();
25278
26380
  } catch (error2) {
25279
26381
  await rollbackCronMutation(
25280
- workspaceCwd,
26382
+ target,
25281
26383
  rollbackBefore,
25282
26384
  rollbackAfter,
25283
26385
  `DELETE ${base}/${id}`
@@ -25321,37 +26423,40 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25321
26423
  let rollbackBefore;
25322
26424
  let rollbackAfter;
25323
26425
  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 }
26426
+ await runWithScheduledTaskTarget(
26427
+ target,
26428
+ () => updateCronTasks(
26429
+ workspaceCwd,
26430
+ (tasks) => {
26431
+ const idx = tasks.findIndex((t) => t.id === id);
26432
+ if (idx === -1) return tasks;
26433
+ found = true;
26434
+ const current = tasks[idx];
26435
+ if (taskHasLegacyCondition(current)) {
26436
+ blockedLegacy = true;
26437
+ return tasks;
26438
+ }
26439
+ if (current.enabled === false) {
26440
+ blockedDisabled = true;
26441
+ return tasks;
26442
+ }
26443
+ const next = {
26444
+ ...current,
26445
+ lastFiredAt: now,
26446
+ runs: appendCronRun(current.runs, {
26447
+ at: now,
26448
+ kind: "manual",
26449
+ ...current.sessionId ? { sessionId: current.sessionId } : {}
26450
+ })
26451
+ };
26452
+ updated = next;
26453
+ rollbackBefore = tasks;
26454
+ const nextTasks = !current.recurring ? tasks.filter((_, i) => i !== idx) : tasks.map((t, i) => i === idx ? next : t);
26455
+ rollbackAfter = nextTasks;
26456
+ return nextTasks;
26457
+ },
26458
+ { assertCanCommit: target.assertGenerationOpen }
26459
+ )
25355
26460
  );
25356
26461
  } catch (err) {
25357
26462
  if (sendGenerationClosedError(res, err)) return;
@@ -25369,7 +26474,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
25369
26474
  target.assertGenerationOpen?.();
25370
26475
  } catch (error2) {
25371
26476
  await rollbackCronMutation(
25372
- workspaceCwd,
26477
+ target,
25373
26478
  rollbackBefore,
25374
26479
  rollbackAfter,
25375
26480
  `POST ${base}/${id}/run`
@@ -25425,6 +26530,12 @@ function registerScheduledTasksRoutes(app, deps) {
25425
26530
  if (runtime && !requireTrustedWorkspaceRuntime(runtime, res)) return null;
25426
26531
  return {
25427
26532
  workspaceCwd: boundWorkspace,
26533
+ ...runtime ? {
26534
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
26535
+ ...deps.cleanupSession ? {
26536
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => deps.cleanupSession(runtime, sessionId), "cleanupSession")
26537
+ } : {}
26538
+ } : {},
25428
26539
  bridge: runtime?.bridge ?? bridge,
25429
26540
  ...runtime?.generationGuard ? {
25430
26541
  assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
@@ -25443,7 +26554,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
25443
26554
  mutate,
25444
26555
  safeBody: safeBody2,
25445
26556
  manageScheduledTaskSessions,
25446
- channelDeliveryAuthorizations
26557
+ channelDeliveryAuthorizations,
26558
+ cleanupSession
25447
26559
  } = deps;
25448
26560
  registerScheduledTaskCrudRoutes(app, {
25449
26561
  prefix: "/workspaces/:workspace",
@@ -25457,6 +26569,10 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
25457
26569
  if (!requireTrustedWorkspaceRuntime(runtime, res)) return null;
25458
26570
  return {
25459
26571
  workspaceCwd: runtime.workspaceCwd,
26572
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
26573
+ ...cleanupSession ? {
26574
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession")
26575
+ } : {},
25460
26576
  // Mirror the primary surface: only bind a session when management is on,
25461
26577
  // so a bound task always has something to keep it resident + rehydrate it.
25462
26578
  bridge: manageScheduledTaskSessions ? runtime.bridge : void 0,
@@ -25735,7 +26851,7 @@ __name(collectBoundSessionIds, "collectBoundSessionIds");
25735
26851
  var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
25736
26852
  var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
25737
26853
  var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
25738
- async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding) {
26854
+ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding, cleanupSession) {
25739
26855
  const unbound = tasks.filter(
25740
26856
  (t) => !t.sessionId && t.enabled !== false && !taskHasLegacyCondition(t) && !binding.has(t.id)
25741
26857
  );
@@ -25753,16 +26869,14 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
25753
26869
  sourceId: task.id
25754
26870
  });
25755
26871
  let timedOut = false;
25756
- rawSpawn.then(({ sessionId: sessionId2 }) => {
26872
+ rawSpawn.then(async ({ sessionId: sessionId2 }) => {
25757
26873
  if (timedOut) {
25758
26874
  log.debug(
25759
26875
  "keepalive: late spawn resolved, cleaning up",
25760
26876
  task.id,
25761
26877
  sessionId2
25762
26878
  );
25763
- bridge.closeSession(sessionId2).catch(() => {
25764
- });
25765
- new SessionService(boundWorkspace).removeSession(sessionId2).catch(() => {
26879
+ await cleanupSession(sessionId2).catch(() => {
25766
26880
  });
25767
26881
  }
25768
26882
  }).catch(() => {
@@ -25810,9 +26924,7 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
25810
26924
  } catch (err) {
25811
26925
  log.debug("keepalive: failed to bind task", task.id, err);
25812
26926
  if (spawnedSessionId !== void 0) {
25813
- await bridge.closeSession(spawnedSessionId).catch(() => {
25814
- });
25815
- await new SessionService(boundWorkspace).removeSession(spawnedSessionId).catch(() => {
26927
+ await cleanupSession(spawnedSessionId).catch(() => {
25816
26928
  });
25817
26929
  }
25818
26930
  }
@@ -25834,11 +26946,17 @@ function startScheduledTaskKeepalive(opts) {
25834
26946
  const { bridge, boundWorkspace, intervalMs } = opts;
25835
26947
  const reviveTimeoutMs = opts.reviveTimeoutMs ?? KEEPALIVE_REVIVE_TIMEOUT_MS;
25836
26948
  const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
26949
+ const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
26950
+ await bridge.closeSession(sessionId);
26951
+ await new SessionService(boundWorkspace, {
26952
+ runtimeBaseDir: opts.runtimeBaseDir
26953
+ }).removeSession(sessionId);
26954
+ });
25837
26955
  const reviveState = /* @__PURE__ */ new Map();
25838
26956
  const reviving = /* @__PURE__ */ new Set();
25839
26957
  const binding = /* @__PURE__ */ new Set();
25840
26958
  const renamed = /* @__PURE__ */ new Set();
25841
- const tick = /* @__PURE__ */ __name(async () => {
26959
+ const tickInRuntime = /* @__PURE__ */ __name(async () => {
25842
26960
  let tasks;
25843
26961
  try {
25844
26962
  tasks = await readCronTasks(boundWorkspace);
@@ -25916,9 +27034,14 @@ function startScheduledTaskKeepalive(opts) {
25916
27034
  tasks,
25917
27035
  renamed,
25918
27036
  spawnTimeoutMs,
25919
- binding
27037
+ binding,
27038
+ cleanupSession
25920
27039
  );
25921
- }, "tick");
27040
+ }, "tickInRuntime");
27041
+ const tick = /* @__PURE__ */ __name(() => opts.runtimeBaseDir === void 0 ? tickInRuntime() : Storage.runWithResolvedRuntimeBaseDir(
27042
+ opts.runtimeBaseDir,
27043
+ tickInRuntime
27044
+ ), "tick");
25922
27045
  let running = false;
25923
27046
  const timer = setInterval(() => {
25924
27047
  if (running) return;
@@ -25929,7 +27052,10 @@ function startScheduledTaskKeepalive(opts) {
25929
27052
  }, intervalMs);
25930
27053
  timer.unref?.();
25931
27054
  let bindDebounce;
25932
- const cronFilePath = getCronFilePath(boundWorkspace);
27055
+ const cronFilePath = opts.runtimeBaseDir === void 0 ? getCronFilePath(boundWorkspace) : Storage.runWithResolvedRuntimeBaseDir(
27056
+ opts.runtimeBaseDir,
27057
+ () => getCronFilePath(boundWorkspace)
27058
+ );
25933
27059
  const cronDir = path11.dirname(cronFilePath);
25934
27060
  const cronFileName = path11.basename(cronFilePath);
25935
27061
  let fileWatcher;
@@ -26442,7 +27568,7 @@ init_esbuild_shims();
26442
27568
 
26443
27569
  // packages/cli/src/serve/server/serve-features.ts
26444
27570
  init_esbuild_shims();
26445
- var DEFAULT_MAX_SESSIONS = 20;
27571
+ var DEFAULT_MAX_SESSIONS = 32;
26446
27572
  var DEFAULT_MAX_PENDING_PROMPTS_PER_SESSION = 5;
26447
27573
  var SERVE_LANGUAGE_CODES = [
26448
27574
  ...SUPPORTED_LANGUAGES.map((language) => language.code),
@@ -27424,6 +28550,14 @@ function sendPermissionVoteError(res, err, ctx, daemonLog) {
27424
28550
  }
27425
28551
  __name(sendPermissionVoteError, "sendPermissionVoteError");
27426
28552
  function sendBridgeError(res, err, ctx, daemonLog) {
28553
+ if (err instanceof DaemonDrainingError) {
28554
+ res.status(503).json({
28555
+ error: err.message,
28556
+ code: err.code,
28557
+ errorKind: err.code
28558
+ });
28559
+ return;
28560
+ }
27427
28561
  if (sendGenerationClosedError(res, err)) return;
27428
28562
  if (err instanceof SessionWriterError) {
27429
28563
  res.status(err.httpStatus).json({
@@ -29607,9 +30741,18 @@ function registerWorkspaceManagementRoutes(app, deps) {
29607
30741
  }
29608
30742
  }
29609
30743
  );
30744
+ const protectExistingWorkspaceRegistration = mutate({ strict: true });
29610
30745
  app.post(
29611
30746
  "/workspaces",
29612
- mutate({ strict: true }),
30747
+ mutate(),
30748
+ (req, res, next) => {
30749
+ const body = safeBody2(req);
30750
+ if (body["kind"] === "scratch") {
30751
+ next();
30752
+ return;
30753
+ }
30754
+ protectExistingWorkspaceRegistration(req, res, next);
30755
+ },
29613
30756
  async (req, res) => {
29614
30757
  const body = safeBody2(req);
29615
30758
  if ("kind" in body) {
@@ -32730,6 +33873,18 @@ function parsePairingCode(body, res) {
32730
33873
  return code.trim().toUpperCase();
32731
33874
  }
32732
33875
  __name(parsePairingCode, "parsePairingCode");
33876
+ function parsePairingSenderId(body, res) {
33877
+ const senderId = body["senderId"];
33878
+ if (typeof senderId !== "string" || senderId.length === 0) {
33879
+ res.status(400).json({
33880
+ error: "`senderId` must be a non-empty string.",
33881
+ code: "invalid_channel_pairing_sender_id"
33882
+ });
33883
+ return void 0;
33884
+ }
33885
+ return senderId;
33886
+ }
33887
+ __name(parsePairingSenderId, "parsePairingSenderId");
32733
33888
  function errorCode2(error2) {
32734
33889
  if (!error2 || typeof error2 !== "object") return void 0;
32735
33890
  try {
@@ -32751,6 +33906,7 @@ var ERROR_STATUS = /* @__PURE__ */ new Map([
32751
33906
  ["untrusted_workspace", 403],
32752
33907
  ["channel_instance_not_found", 404],
32753
33908
  ["channel_pairing_request_not_found", 404],
33909
+ ["channel_pairing_approval_not_found", 404],
32754
33910
  ["channel_pairing_not_enabled", 409],
32755
33911
  ["channel_settings_conflict", 409],
32756
33912
  ["channel_runtime_owner_mismatch", 409],
@@ -32807,6 +33963,8 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
32807
33963
  const register = /* @__PURE__ */ __name((prefix, resolveRuntime) => {
32808
33964
  const pairingRead = deps.mutate({ strict: true });
32809
33965
  const pairingApprove = deps.mutate({ strict: true });
33966
+ const pairingApprovalsRead = deps.mutate({ strict: true });
33967
+ const pairingRevoke = deps.mutate({ strict: true });
32810
33968
  const upsert = deps.mutate({ strict: true });
32811
33969
  const remove = deps.mutate({ strict: true });
32812
33970
  const startup = deps.mutate({ strict: true });
@@ -32869,6 +34027,40 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
32869
34027
  }
32870
34028
  }
32871
34029
  );
34030
+ app.get(
34031
+ `${prefix}/channels/:name/pairing-approvals`,
34032
+ pairingApprovalsRead,
34033
+ async (req, res) => {
34034
+ const resolved = await target(req, res);
34035
+ if (!resolved || !validateClient(req, res, resolved.runtime)) return;
34036
+ const name = parseInstanceName(req, res);
34037
+ if (!name) return;
34038
+ try {
34039
+ noStore(res);
34040
+ res.status(200).json(await resolved.service.pairingApprovals(name));
34041
+ } catch (error2) {
34042
+ sendManagementError(res, error2);
34043
+ }
34044
+ }
34045
+ );
34046
+ app.delete(
34047
+ `${prefix}/channels/:name/pairing-approvals`,
34048
+ pairingRevoke,
34049
+ async (req, res) => {
34050
+ const resolved = await target(req, res);
34051
+ if (!resolved || !validateClient(req, res, resolved.runtime)) return;
34052
+ const name = parseInstanceName(req, res);
34053
+ if (!name) return;
34054
+ const senderId = parsePairingSenderId(deps.safeBody(req), res);
34055
+ if (!senderId) return;
34056
+ try {
34057
+ noStore(res);
34058
+ res.status(200).json(await resolved.service.revokePairingApproval(name, senderId));
34059
+ } catch (error2) {
34060
+ sendManagementError(res, error2);
34061
+ }
34062
+ }
34063
+ );
32872
34064
  app.put(`${prefix}/channels/:name`, upsert, async (req, res) => {
32873
34065
  const resolved = await target(req, res);
32874
34066
  if (!resolved || !validateClient(req, res, resolved.runtime)) return;
@@ -33993,6 +35185,16 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
33993
35185
  defaultBridgeForAdmission = bridge;
33994
35186
  }
33995
35187
  const archiveCoordinator = new SessionArchiveCoordinator();
35188
+ app.locals.sessionArchiveCoordinator = archiveCoordinator;
35189
+ const cleanupSession = /* @__PURE__ */ __name((runtime, sessionId) => runWithWorkspaceRuntimeStorage(
35190
+ runtime,
35191
+ () => deleteDaemonSessionIfOrphan({
35192
+ sessionId,
35193
+ service: createWorkspaceRuntimeSessionService(runtime),
35194
+ bridge: runtime.bridge,
35195
+ coordinator: archiveCoordinator
35196
+ })
35197
+ ), "cleanupSession");
33996
35198
  installSelfOriginStripMiddleware(app, getPort);
33997
35199
  app.locals.fsFactory = fsFactory;
33998
35200
  app.locals.boundWorkspace = boundWorkspace;
@@ -34057,6 +35259,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34057
35259
  {
34058
35260
  workspaceId: hashDaemonWorkspace(boundWorkspace),
34059
35261
  workspaceCwd: boundWorkspace,
35262
+ sessionRuntimeBaseDir: Storage.getRuntimeBaseDir(),
34060
35263
  primary: true,
34061
35264
  trusted: deps.primaryWorkspaceTrusted ?? false,
34062
35265
  env: primaryRuntimeEnvMetadata ?? {
@@ -34338,6 +35541,49 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34338
35541
  isWorkspaceTrusted: isPrimaryWorkspaceTrusted,
34339
35542
  captureGenerationAssertion: capturePrimaryGenerationAssertion
34340
35543
  });
35544
+ mountWorkspaceQualifiedMemoryRememberRoutes(app, {
35545
+ mutate,
35546
+ resolveRouteDeps: /* @__PURE__ */ __name((req, res, { creating, kind }) => {
35547
+ const runtime = resolveWorkspaceRuntimeFromParam(
35548
+ workspaceRegistry,
35549
+ req,
35550
+ res
35551
+ );
35552
+ if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res))
35553
+ return null;
35554
+ const handle = acpHandleRef.current;
35555
+ const lane = runtime.primary ? workspaceRememberLane : creating ? handle?.ensureWorkspaceRememberLane(runtime.workspaceId) : handle?.getWorkspaceRememberLane(runtime.workspaceId);
35556
+ if (!lane) {
35557
+ if (!handle) {
35558
+ res.status(501).json({
35559
+ error: "Workspace-qualified memory is not enabled on this daemon.",
35560
+ code: "workspace_memory_unavailable",
35561
+ workspaceCwd: runtime.workspaceCwd,
35562
+ workspaceId: runtime.workspaceId
35563
+ });
35564
+ } else if (!creating) {
35565
+ res.status(404).json({
35566
+ error: `Workspace memory ${kind} task not found`,
35567
+ code: `${kind}_task_not_found`
35568
+ });
35569
+ } else {
35570
+ sendWorkspaceRuntimeUnavailable(res, runtime);
35571
+ }
35572
+ return null;
35573
+ }
35574
+ return {
35575
+ bridge: runtime.bridge,
35576
+ lane,
35577
+ parseClientId: parseClientIdHeader,
35578
+ safeBody,
35579
+ isWorkspaceTrusted: /* @__PURE__ */ __name(() => runtime.trusted, "isWorkspaceTrusted"),
35580
+ captureGenerationAssertion: /* @__PURE__ */ __name(() => {
35581
+ const guard = runtime.generationGuard;
35582
+ return guard ? () => guard.assertOpen() : void 0;
35583
+ }, "captureGenerationAssertion")
35584
+ };
35585
+ }, "resolveRouteDeps")
35586
+ });
34341
35587
  mountWorkspaceAgentsRoutes(app, {
34342
35588
  bridge: primaryBridge,
34343
35589
  boundWorkspace: primaryBoundWorkspace,
@@ -34681,6 +35927,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34681
35927
  safeBody,
34682
35928
  bridge: deps.manageScheduledTaskSessions ? primaryBridge : void 0,
34683
35929
  getRuntime: /* @__PURE__ */ __name(() => workspaceRegistry.primaryEntry.state === "active" ? workspaceRegistry.primaryEntry.current?.runtime : void 0, "getRuntime"),
35930
+ cleanupSession,
34684
35931
  channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
34685
35932
  });
34686
35933
  registerGoalsRoutes(app, {
@@ -34694,7 +35941,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34694
35941
  mutate,
34695
35942
  safeBody,
34696
35943
  manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
34697
- channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
35944
+ channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
35945
+ cleanupSession
34698
35946
  });
34699
35947
  registerUsageStatsRoutes(app);
34700
35948
  if (deps.manageScheduledTaskSessions) {
@@ -34714,23 +35962,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34714
35962
  }, "registerScheduledTaskAuthorizations");
34715
35963
  const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
34716
35964
  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)}
35965
+ const rehydrateWorkspace = /* @__PURE__ */ __name((runtime) => {
35966
+ void runWithWorkspaceRuntimeStorage(
35967
+ runtime,
35968
+ () => rehydrateScheduledTaskSessions({
35969
+ bridge: runtime.bridge,
35970
+ boundWorkspace: runtime.workspaceCwd,
35971
+ onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead"),
35972
+ onError: /* @__PURE__ */ __name((sessionId, err) => {
35973
+ process.stderr.write(
35974
+ `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
34725
35975
  `
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) => {
35976
+ );
35977
+ }, "onError")
35978
+ // Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
35979
+ // catches readCronTasks failures and per-session load errors internally
35980
+ // (returning { loaded, failed }), so this only guards an unexpected throw
35981
+ // from the function entry itself. Log rather than swallow it — a silent
35982
+ // failure here leaves every bound task dormant with no diagnostic.
35983
+ })
35984
+ ).catch((err) => {
34734
35985
  process.stderr.write(
34735
35986
  `qwen serve: unexpected scheduled-task rehydration failure: ${err instanceof Error ? err.message : String(err)}
34736
35987
  `
@@ -34746,9 +35997,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
34746
35997
  bridge: runtime.bridge,
34747
35998
  boundWorkspace: runtime.workspaceCwd,
34748
35999
  intervalMs: keepaliveIntervalMs,
36000
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir,
36001
+ cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession"),
34749
36002
  onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
34750
36003
  });
34751
- rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
36004
+ rehydrateWorkspace(runtime);
34752
36005
  keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
34753
36006
  }, "startKeepaliveForWorkspace");
34754
36007
  for (const runtime of workspaceRegistry.list()) {