@qwen-code/qwen-code 0.21.8 → 0.21.9

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 (258) hide show
  1. package/README.md +2 -1
  2. package/bundled/qc-helper/docs/configuration/settings.md +32 -30
  3. package/bundled/qc-helper/docs/extension/introduction.md +15 -1
  4. package/bundled/qc-helper/docs/features/code-review.md +2 -0
  5. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
  6. package/bundled/qc-helper/docs/qwen-serve.md +42 -39
  7. package/bundled/review/SKILL.md +11 -7
  8. package/chunks/{MaxSizedBox-7PM6BGJ5.js → MaxSizedBox-6BZANW7X.js} +9 -9
  9. package/chunks/{StandaloneSessionPicker-3UQHM7GV.js → StandaloneSessionPicker-VDC5KE7T.js} +28 -25
  10. package/chunks/{acpAgent-5UWLFV6V.js → acpAgent-F2NSBCUF.js} +1433 -706
  11. package/chunks/{agent-624T2BLO.js → agent-VOHJOEBB.js} +8 -8
  12. package/chunks/{agent-headless-2EE5J2KX.js → agent-headless-J5NFOPHP.js} +8 -8
  13. package/chunks/{bridge-JENKGFFP.js → bridge-NQIZZLAS.js} +13 -13
  14. package/chunks/{channel-management-service-DDWUPHMU.js → channel-management-service-PHELKOW2.js} +4 -4
  15. package/chunks/{channel-settings-store-SA6JZSPH.js → channel-settings-store-VIY2OENO.js} +17 -15
  16. package/chunks/{channel-worker-group-E67EN3RV.js → channel-worker-group-MSHT6CWR.js} +6 -6
  17. package/chunks/{channel-worker-manager-SW4C45CF.js → channel-worker-manager-XXD3GDSK.js} +6 -6
  18. package/chunks/{channel-worker-supervisor-5SRD24FG.js → channel-worker-supervisor-IVSDIMI4.js} +4 -4
  19. package/chunks/{chunk-S3Y3GBFD.js → chunk-23VQTELM.js} +2 -2
  20. package/chunks/{chunk-XZKQT2B2.js → chunk-3WDYBTTI.js} +5 -5
  21. package/chunks/{chunk-YEF7XEO2.js → chunk-3XVDTHBJ.js} +3 -3
  22. package/chunks/{chunk-IBYULW65.js → chunk-46YJDYCU.js} +145 -10
  23. package/chunks/chunk-4JRM2BSM.js +48 -0
  24. package/chunks/{chunk-L4N6TIP7.js → chunk-4TRQPFDP.js} +4 -2
  25. package/chunks/{chunk-5ZGR6RKJ.js → chunk-4XQNB3KN.js} +3 -3
  26. package/chunks/chunk-5EJZE3FP.js +140 -0
  27. package/chunks/{chunk-XHD7CRP2.js → chunk-5RBDAGC6.js} +2 -2
  28. package/chunks/{chunk-KJZ26VBX.js → chunk-67EWJE77.js} +1 -1
  29. package/chunks/{chunk-TE3ZAJE7.js → chunk-6Q5ABMTU.js} +1 -1
  30. package/chunks/{chunk-U5SLIG7E.js → chunk-7AEPJGL4.js} +1 -1
  31. package/chunks/{chunk-OHKJVAKG.js → chunk-7GOYZQPR.js} +20 -1977
  32. package/chunks/{chunk-3SE7J4DR.js → chunk-7S4JBJLU.js} +3 -3
  33. package/chunks/{chunk-TKSZJ5BV.js → chunk-AKJQSWV4.js} +3 -3
  34. package/chunks/{chunk-E4ZBKMSF.js → chunk-ATMO54WE.js} +6 -6
  35. package/chunks/{chunk-KKDVZLGL.js → chunk-BAMN6XSD.js} +1 -1
  36. package/chunks/{chunk-IUQ52YJK.js → chunk-BIRWP6LU.js} +1 -1
  37. package/chunks/{chunk-AKA24BGO.js → chunk-BT6GQIEJ.js} +1 -1
  38. package/chunks/{chunk-ZCLLJARV.js → chunk-BZP4QPNK.js} +10 -10
  39. package/chunks/{chunk-2M5N3DHY.js → chunk-CMOBWHWW.js} +1 -1
  40. package/chunks/{chunk-WV5J6Q6N.js → chunk-D7BXVKSF.js} +1 -1
  41. package/chunks/{chunk-NLREQJFK.js → chunk-DA4HRSBW.js} +15 -0
  42. package/chunks/{chunk-GOEVOFQI.js → chunk-DH5YXSIF.js} +3 -3
  43. package/chunks/{chunk-DIWZNWZT.js → chunk-DX3RGJMS.js} +13 -2
  44. package/chunks/{chunk-PLFATELK.js → chunk-DZUO626D.js} +1 -1
  45. package/chunks/{chunk-NGYI5EF5.js → chunk-E2FPSSKP.js} +8 -8
  46. package/chunks/{chunk-ZPLALRXZ.js → chunk-FBMCDU63.js} +4 -137
  47. package/chunks/{chunk-2ILAOM2I.js → chunk-FCLHHEUK.js} +17 -16
  48. package/chunks/{chunk-SNRT2TJJ.js → chunk-G2TX5ZXC.js} +3 -3
  49. package/chunks/{chunk-C5VWPTGT.js → chunk-GAKGOXTC.js} +1 -1
  50. package/chunks/{chunk-QQWD7LZV.js → chunk-HADWBW5R.js} +4 -4
  51. package/chunks/{chunk-77QVBFCU.js → chunk-HZGBKOX3.js} +3 -3
  52. package/chunks/{chunk-RPWVIXDB.js → chunk-I5VM3SKY.js} +4 -4
  53. package/chunks/{chunk-7VUERJHS.js → chunk-II6G3EY6.js} +325 -104
  54. package/chunks/{chunk-FN6YXJOP.js → chunk-IOEZE2YT.js} +1 -1
  55. package/chunks/chunk-JUWS2Z5K.js +1995 -0
  56. package/chunks/{chunk-VXZ5HAOV.js → chunk-K4ADGWHU.js} +1 -1
  57. package/chunks/{chunk-YOM7DEGB.js → chunk-KSAFZ5TA.js} +2 -2
  58. package/chunks/{chunk-KAQCJO6Y.js → chunk-KTKYGS2P.js} +35 -9
  59. package/chunks/{chunk-GBDINRIL.js → chunk-KTQGGPGV.js} +3 -3
  60. package/chunks/{chunk-6M26GBKX.js → chunk-L2AFWWJE.js} +42 -3
  61. package/chunks/{chunk-QXVSWG66.js → chunk-LHEC5V6G.js} +2 -2
  62. package/chunks/{chunk-J26HHFI5.js → chunk-LP2QGNSP.js} +32 -2
  63. package/chunks/{chunk-HWX5HPUG.js → chunk-LZZLUCRS.js} +108 -11
  64. package/chunks/{chunk-KTJFU7RT.js → chunk-MFDYOYZZ.js} +2 -2
  65. package/chunks/{chunk-3WNQOYHQ.js → chunk-MHP476D3.js} +74 -31
  66. package/chunks/{chunk-Y4TETC74.js → chunk-MTCYGTWH.js} +4 -4
  67. package/chunks/{chunk-EN2TKTFH.js → chunk-NV3F44FL.js} +6 -2
  68. package/chunks/{chunk-BF52U4XJ.js → chunk-OGDIJKHK.js} +1 -1
  69. package/chunks/{chunk-7DVT4LVV.js → chunk-OGNFHGIG.js} +3 -3
  70. package/chunks/{chunk-IYES5WOT.js → chunk-P2FK2HBV.js} +2 -2
  71. package/chunks/{chunk-2M4K4KYS.js → chunk-P3RBMQ4P.js} +4 -4
  72. package/chunks/{chunk-FYAXKJK7.js → chunk-P4ZEZSJZ.js} +692 -106
  73. package/chunks/{chunk-UFALT4LK.js → chunk-PBRVUF5B.js} +1 -1
  74. package/chunks/{chunk-LKRMNRSN.js → chunk-PDPFQ2FO.js} +2 -0
  75. package/chunks/{chunk-6TR7CFXH.js → chunk-PNBBJOCP.js} +1 -1
  76. package/chunks/{chunk-M3STHEMM.js → chunk-PVOGHGSF.js} +5 -5
  77. package/chunks/{chunk-4WU6NY7F.js → chunk-QSNSL4R4.js} +2 -2
  78. package/chunks/{chunk-DQSDACD2.js → chunk-RBHQXGDK.js} +1 -1
  79. package/chunks/{chunk-ZHA242R4.js → chunk-RVSTTOJ4.js} +2 -2
  80. package/chunks/{chunk-EIVICVHM.js → chunk-SCAZZ3Q4.js} +4 -4
  81. package/chunks/{chunk-BF224XHL.js → chunk-T5RLUXWJ.js} +2 -2
  82. package/chunks/{chunk-B52AWKBB.js → chunk-T6HEQR2Q.js} +16 -5
  83. package/chunks/{chunk-FWBXMANW.js → chunk-THIKWITR.js} +3 -3
  84. package/chunks/{chunk-WG6542MA.js → chunk-TQCYNLNJ.js} +1 -1
  85. package/chunks/chunk-TQOF5KBL.js +71 -0
  86. package/chunks/{chunk-NPUXXRJI.js → chunk-TZ6KJ44L.js} +1 -1
  87. package/chunks/{chunk-YHJFF7KH.js → chunk-UJUM2SRN.js} +147 -47
  88. package/chunks/{chunk-4ALIARFY.js → chunk-UYAUA63Q.js} +1 -1
  89. package/chunks/chunk-VFMASYQA.js +389 -0
  90. package/chunks/chunk-VGHZT6JR.js +51 -0
  91. package/chunks/{chunk-ZWBUH5UP.js → chunk-VKJ4KTPJ.js} +1 -1
  92. package/chunks/{chunk-QGHSP65Z.js → chunk-VNNWAZSI.js} +2 -2
  93. package/chunks/{chunk-757GB46F.js → chunk-W3FSZSF2.js} +1 -1
  94. package/chunks/{chunk-GQCEQPYQ.js → chunk-WGK4TSB7.js} +3 -3
  95. package/chunks/{chunk-PG62DFWD.js → chunk-WP5VOXF7.js} +6 -127
  96. package/chunks/{chunk-NVRDQFCX.js → chunk-XTY5DN4Y.js} +1 -1
  97. package/chunks/{chunk-GXSNGY5M.js → chunk-XX7QFP34.js} +1677 -1307
  98. package/chunks/{chunk-3PY4LPJF.js → chunk-YGT2AUJ7.js} +84 -4
  99. package/chunks/{chunk-4DU3NCHG.js → chunk-YTFDX4PR.js} +8 -3
  100. package/chunks/{chunk-OA4JVLSA.js → chunk-Z7VOMGDC.js} +22 -1
  101. package/chunks/{chunk-DX5W5AON.js → chunk-ZBXGWQ4S.js} +3 -3
  102. package/chunks/chunk-ZLBIFIMV.js +1099 -0
  103. package/chunks/{chunk-HA3SAB64.js → chunk-ZOSTTOUJ.js} +1 -1
  104. package/chunks/{chunk-VWMUDKLC.js → chunk-ZTQSOV56.js} +4 -4
  105. package/chunks/{computer-use-ESQYJ3JY.js → computer-use-PMZ7ICGY.js} +8 -8
  106. package/chunks/{config-utils-XQHBJP7G.js → config-utils-ULCSRMWD.js} +4 -4
  107. package/chunks/{contextCommand-CX3YF4ZE.js → contextCommand-GEZU7YHE.js} +11 -10
  108. package/chunks/{core-runtime-DIAU7JMG.js → core-runtime-HRJI2MN6.js} +8 -8
  109. package/chunks/{create-sub-session-HDPD6HOA.js → create-sub-session-VBNVI4YU.js} +9 -9
  110. package/chunks/{daemon-VZBGJUNL.js → daemon-POSQPD3G.js} +115 -7
  111. package/chunks/{daemon-status-provider-H6O4UQ4F.js → daemon-status-provider-N4CRQKFI.js} +18 -18
  112. package/chunks/{daemon-trust-policy-BNUXG6MT.js → daemon-trust-policy-BHO3JUHM.js} +16 -14
  113. package/chunks/{daemon-trust-policy-monitor-E4EQ7GF4.js → daemon-trust-policy-monitor-YEKJ2726.js} +16 -14
  114. package/chunks/{deferred-core-runtime-CBMSHPAU.js → deferred-core-runtime-SH57E3J3.js} +8 -8
  115. package/chunks/{dist-KVISB2O2.js → dist-3NTTUAHT.js} +1 -1
  116. package/chunks/{dist-RCH3I7SS.js → dist-6BMOAE3Z.js} +2 -2
  117. package/chunks/{dist-IRL7WA5Z.js → dist-B2CGTW6T.js} +1 -1
  118. package/chunks/{dist-TUSWNE2I.js → dist-EWW3J4HQ.js} +1 -1
  119. package/chunks/{dist-HIACTZEK.js → dist-EZE3V3Q7.js} +1 -1
  120. package/chunks/{dist-EEEQGCZA.js → dist-J47AXBZC.js} +1 -1
  121. package/chunks/{dist-MKX5OSFF.js → dist-OTUO3AS2.js} +4 -1088
  122. package/chunks/{dist-MBF3I5MX.js → dist-Z3CS4OVP.js} +1 -1
  123. package/chunks/{earlyInputCapture-UIOP7OIN.js → earlyInputCapture-B2JJ2HME.js} +8 -8
  124. package/chunks/{edit-ITMZYFKA.js → edit-7FTXENAN.js} +10 -8
  125. package/chunks/{enter-worktree-S4PL5UV6.js → enter-worktree-JPHV2PBG.js} +8 -8
  126. package/chunks/{enterPlanMode-YV52NNJT.js → enterPlanMode-CGBJ3AHJ.js} +8 -8
  127. package/chunks/{environment-NGOWPRZV.js → environment-LXASZAHD.js} +11 -11
  128. package/chunks/{errors-BU26DTDX.js → errors-XIGVT2AD.js} +10 -10
  129. package/chunks/{exit-worktree-XRM6LH5F.js → exit-worktree-DKSGXW65.js} +8 -8
  130. package/chunks/{exitPlanMode-ZLI5F7KR.js → exitPlanMode-THFL2HYN.js} +8 -8
  131. package/chunks/{fast-path-UJWORIED.js → fast-path-4NXAT5UL.js} +4 -3
  132. package/chunks/{fast-path-settings-37WQD5B2.js → fast-path-settings-RPAVBD7P.js} +2 -2
  133. package/chunks/{gemini-ZSKNDUMU.js → gemini-B3N6FACU.js} +56 -60
  134. package/chunks/{geminiContentGenerator-YGEXOEKD.js → geminiContentGenerator-YYFE2HIE.js} +1 -1
  135. package/chunks/{glob-7KZG44BR.js → glob-BPHSCFJP.js} +8 -8
  136. package/chunks/{grep-6ZFC7RJ5.js → grep-ROZIRFLU.js} +8 -8
  137. package/chunks/{handleAutoUpdate-KSEL3TQS.js → handleAutoUpdate-WV6SPZQB.js} +13 -12
  138. package/chunks/{i18n-ZIUXBW5V.js → i18n-YWJWPQKD.js} +13 -11
  139. package/chunks/{image-gen-AUIZJJNK.js → image-gen-SISRZ6FS.js} +1 -1
  140. package/chunks/{initializer-7AHY3N6Q.js → initializer-66OAD6GO.js} +16 -14
  141. package/chunks/{installationInfo-VGBXMYLY.js → installationInfo-3YUGIP36.js} +9 -9
  142. package/chunks/{list-PSFKQHLB.js → list-VEYR66XB.js} +19 -17
  143. package/chunks/{loadedSettingsAdapter-FTMRCTOF.js → loadedSettingsAdapter-V2JCPCYD.js} +16 -14
  144. package/chunks/{loggingContentGenerator-MZAN52UV.js → loggingContentGenerator-RBLNDREC.js} +6 -6
  145. package/chunks/main-PXAUXNF2.js +8 -0
  146. package/chunks/{managed-npm-update-O4NHK45X.js → managed-npm-update-C5ID5R4R.js} +9 -9
  147. package/chunks/{mcp-6CFP2AYQ.js → mcp-OZ54NZJQ.js} +16 -14
  148. package/chunks/{monitor-DAKD6OU4.js → monitor-7Y4TVFTK.js} +18 -14
  149. package/chunks/{nonInteractiveCli-RC7VIUZL.js → nonInteractiveCli-QEK4LHAC.js} +51 -49
  150. package/chunks/{notebook-edit-474DPMRL.js → notebook-edit-OG35EBGY.js} +9 -8
  151. package/chunks/{openaiContentGenerator-2NFY2MWO.js → openaiContentGenerator-443BNRPJ.js} +5 -5
  152. package/chunks/{pidfile-KBFVDNQP.js → pidfile-ZK4OLRZA.js} +8 -8
  153. package/chunks/{processUtils-6GRYH4Y3.js → processUtils-4YGB4RUZ.js} +2 -2
  154. package/chunks/{qwenContentGenerator-KAHU6IZY.js → qwenContentGenerator-D5C2LCSZ.js} +9 -9
  155. package/chunks/{qwenOAuth2-RRQTCP4W.js → qwenOAuth2-Z4YQBMYN.js} +1 -1
  156. package/chunks/{read-file-3M6WXDXP.js → read-file-EXTJLWMU.js} +4 -4
  157. package/chunks/{resumeHistoryUtils-D6TAY3HX.js → resumeHistoryUtils-UPCGRJUL.js} +13 -12
  158. package/chunks/{ripGrep-PLPENT3E.js → ripGrep-QBVIRCU4.js} +8 -8
  159. package/chunks/{run-qwen-serve-ZAFIJKJC.js → run-qwen-serve-ZYGJNE3E.js} +169 -68
  160. package/chunks/{runtime-ZED7CYOZ.js → runtime-BZZ4LWCP.js} +21 -19
  161. package/chunks/{scheduler-MD3AL2W5.js → scheduler-YNQNOU2E.js} +135 -15
  162. package/chunks/{sdk-exporters-http-KHAB5JSD.js → sdk-exporters-http-XVTZQRCE.js} +2 -2
  163. package/chunks/{sdk-impl-KD7FSTC3.js → sdk-impl-7W7AKCS4.js} +7 -3
  164. package/chunks/{serve-E3VUDRZN.js → serve-LJHAXDCH.js} +18 -14
  165. package/chunks/{server-OWMEMAKR.js → server-ADMLELR6.js} +1229 -1098
  166. package/chunks/{session-HZ57QK7K.js → session-YKZXFFTM.js} +55 -53
  167. package/chunks/{settings-V7BR3RKP.js → settings-EQBUAQ7Y.js} +15 -13
  168. package/chunks/{shell-23OMNMW6.js → shell-3QZOJGTT.js} +8 -8
  169. package/chunks/{skill-6HBDYZRS.js → skill-UWSSMXE7.js} +5 -5
  170. package/chunks/{skill-settings-HWJLTU7M.js → skill-settings-T6MLB7NU.js} +15 -13
  171. package/chunks/{spawnChannel-N6KKUW5B.js → spawnChannel-VS7ZFUFP.js} +11 -11
  172. package/chunks/{standalone-update-QGIKHATD.js → standalone-update-2W26SRRO.js} +11 -10
  173. package/chunks/{startInteractiveUI-GX2CRL42.js → startInteractiveUI-CVS7K3D6.js} +86 -75
  174. package/chunks/{team-create-CFFKU7KL.js → team-create-4WFTNNUL.js} +8 -8
  175. package/chunks/{team-plan-approval-6EFOKR6A.js → team-plan-approval-DBYI33S3.js} +8 -8
  176. package/chunks/{terminal-image-renderer-TLDNACQY.js → terminal-image-renderer-S5WPPQKH.js} +8 -8
  177. package/chunks/{theme-manager-5LJ3H7VO.js → theme-manager-LI2RIOVR.js} +8 -8
  178. package/chunks/{tool-search-UJV3A24H.js → tool-search-4773EUQ4.js} +4 -4
  179. package/chunks/{total-session-admission-D63QYXGO.js → total-session-admission-PAY5CH2Z.js} +16 -15
  180. package/chunks/{trustedFolders-KZCOB53W.js → trustedFolders-FRSLE674.js} +9 -9
  181. package/chunks/{types-ML3TRJQ5.js → types-WYCFCEHR.js} +5 -3
  182. package/chunks/{update-relaunch-IFILM3SA.js → update-relaunch-ZSFQTU6M.js} +5 -5
  183. package/chunks/{updateCheck-YZ2CRCFC.js → updateCheck-AXWSO7KA.js} +12 -11
  184. package/chunks/{useAutoAcceptIndicator-AXEVNA3Q.js → useAutoAcceptIndicator-VHLXIA7U.js} +18 -16
  185. package/chunks/{validateNonInterActiveAuth-3WTOJFWA.js → validateNonInterActiveAuth-PDJECMFU.js} +48 -46
  186. package/chunks/{version-GXK7OHZY.js → version-RBN764QS.js} +1 -1
  187. package/chunks/{web-fetch-ILB4GAVR.js → web-fetch-7BJK42AF.js} +4 -4
  188. package/chunks/{web-search-HKRPGPZZ.js → web-search-L2CILQXV.js} +4 -3
  189. package/chunks/{workflow-FXIPRQQA.js → workflow-5VH2R74I.js} +170 -137
  190. package/chunks/{workspace-providers-status-NYHC7HSR.js → workspace-providers-status-OZTQ6JFH.js} +19 -17
  191. package/chunks/{workspace-registration-store-AKEB7OMW.js → workspace-registration-store-IX5RJQS5.js} +1 -1
  192. package/chunks/{workspace-registry-CDAS5TVZ.js → workspace-registry-73N4BGG4.js} +16 -15
  193. package/chunks/{workspace-service-PAMUKMAV.js → workspace-service-I5RUPSNV.js} +26 -22
  194. package/chunks/{workspace-skills-status-YQSHCCMS.js → workspace-skills-status-DMK6VYDO.js} +17 -15
  195. package/chunks/{workspace-trust-reconciler-RPTXOIY2.js → workspace-trust-reconciler-QX4RL3TC.js} +24 -21
  196. package/chunks/{write-file-CGS57TS4.js → write-file-UGDD5UTS.js} +8 -8
  197. package/chunks/{zoom-image-E7D72GYV.js → zoom-image-ZAHEO3YP.js} +4 -4
  198. package/cli.js +12 -12
  199. package/package.json +3 -3
  200. package/web-shell/assets/{arc-DybZaz32.js → arc-CHY4saMJ.js} +1 -1
  201. package/web-shell/assets/{architectureDiagram-3BPJPVTR-jN3qBd19.js → architectureDiagram-3BPJPVTR-Bu6CwvHj.js} +1 -1
  202. package/web-shell/assets/{blockDiagram-GPEHLZMM-Ct5DZPrj.js → blockDiagram-GPEHLZMM-XGt6iGf_.js} +1 -1
  203. package/web-shell/assets/{c4Diagram-AAUBKEIU-CUAFMlUG.js → c4Diagram-AAUBKEIU-CBbYl19W.js} +1 -1
  204. package/web-shell/assets/channel-B40srHOa.js +1 -0
  205. package/web-shell/assets/{chunk-2J33WTMH-CuV8n90B.js → chunk-2J33WTMH-BEhmVrdx.js} +1 -1
  206. package/web-shell/assets/{chunk-4BX2VUAB-BUzl_kls.js → chunk-4BX2VUAB-fQLyE0Bg.js} +1 -1
  207. package/web-shell/assets/{chunk-55IACEB6-BnDBLX6A.js → chunk-55IACEB6-yGdtyx4a.js} +1 -1
  208. package/web-shell/assets/{chunk-727SXJPM-B83uTOjm.js → chunk-727SXJPM-DYbX2GLo.js} +1 -1
  209. package/web-shell/assets/{chunk-AQP2D5EJ-DM3HLgpT.js → chunk-AQP2D5EJ-DyKTEsYn.js} +1 -1
  210. package/web-shell/assets/{chunk-FMBD7UC4-CSQ5hgyb.js → chunk-FMBD7UC4-D8Uy_GzX.js} +1 -1
  211. package/web-shell/assets/{chunk-ND2GUHAM-BWOF4SxX.js → chunk-ND2GUHAM-C8wNR2K7.js} +1 -1
  212. package/web-shell/assets/{chunk-QZHKN3VN-BsOH9LMi.js → chunk-QZHKN3VN-BnybNxnt.js} +1 -1
  213. package/web-shell/assets/classDiagram-4FO5ZUOK-qumcXQW_.js +1 -0
  214. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-qumcXQW_.js +1 -0
  215. package/web-shell/assets/{cose-bilkent-S5V4N54A-IENqH2iJ.js → cose-bilkent-S5V4N54A-jq4uiFRp.js} +1 -1
  216. package/web-shell/assets/{dagre-BM42HDAG--dyzDTGo.js → dagre-BM42HDAG-Bs7oye1U.js} +1 -1
  217. package/web-shell/assets/{diagram-2AECGRRQ-BE7Dcqof.js → diagram-2AECGRRQ-BHGGJNyM.js} +1 -1
  218. package/web-shell/assets/{diagram-5GNKFQAL-Cr8-5OTj.js → diagram-5GNKFQAL-BJezVLGT.js} +1 -1
  219. package/web-shell/assets/{diagram-KO2AKTUF-Bzey3uAY.js → diagram-KO2AKTUF-5JzQN_rL.js} +1 -1
  220. package/web-shell/assets/{diagram-LMA3HP47-sErl28Xb.js → diagram-LMA3HP47-BlPYOgY9.js} +1 -1
  221. package/web-shell/assets/{diagram-OG6HWLK6-Dq30ATIo.js → diagram-OG6HWLK6-CtMHEaFK.js} +1 -1
  222. package/web-shell/assets/{erDiagram-TEJ5UH35-BkCoEfVW.js → erDiagram-TEJ5UH35-CRNdq2AB.js} +1 -1
  223. package/web-shell/assets/{flowDiagram-I6XJVG4X-DHwO0rrI.js → flowDiagram-I6XJVG4X-De1WwLzu.js} +1 -1
  224. package/web-shell/assets/{ganttDiagram-6RSMTGT7-s7vAPxWq.js → ganttDiagram-6RSMTGT7-YbWfL5Zn.js} +1 -1
  225. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CQxhwPOU.js → gitGraphDiagram-PVQCEYII-DzCN8bmd.js} +1 -1
  226. package/web-shell/assets/index-BDOGGGaN.css +5 -0
  227. package/web-shell/assets/{index-CF4wApWp.js → index-CocPvF9Q.js} +1 -1
  228. package/web-shell/assets/index-DSH2KrMc.js +1771 -0
  229. package/web-shell/assets/{infoDiagram-5YYISTIA-BnFrD0bq.js → infoDiagram-5YYISTIA-DLHoopnE.js} +1 -1
  230. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-Bf9zK5NK.js → ishikawaDiagram-YF4QCWOH-XnbU04SS.js} +1 -1
  231. package/web-shell/assets/{journeyDiagram-JHISSGLW-CyGAhsxi.js → journeyDiagram-JHISSGLW-CipPyEeJ.js} +1 -1
  232. package/web-shell/assets/{kanban-definition-UN3LZRKU-CbsK5akB.js → kanban-definition-UN3LZRKU-DrSeyE5d.js} +1 -1
  233. package/web-shell/assets/{linear-cQsF4P8D.js → linear-LrBKnAo_.js} +1 -1
  234. package/web-shell/assets/{mermaid.core-Z4HVqrKY.js → mermaid.core-C3U9UVmf.js} +5 -5
  235. package/web-shell/assets/{mindmap-definition-RKZ34NQL-CYnrBo_f.js → mindmap-definition-RKZ34NQL-DqRWgC9H.js} +1 -1
  236. package/web-shell/assets/{pieDiagram-4H26LBE5-CBzOfhrs.js → pieDiagram-4H26LBE5-BNXY5p6H.js} +1 -1
  237. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-D4LK1Ebn.js → quadrantDiagram-W4KKPZXB-Ccj9QzE4.js} +1 -1
  238. package/web-shell/assets/{requirementDiagram-4Y6WPE33-Bzti2Lcj.js → requirementDiagram-4Y6WPE33-CjPM2_gx.js} +1 -1
  239. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-yTBw5Z2s.js → sankeyDiagram-5OEKKPKP-C0RsvKbj.js} +1 -1
  240. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-D07UVRiZ.js → sequenceDiagram-3UESZ5HK-ClN1P5z7.js} +1 -1
  241. package/web-shell/assets/{stateDiagram-AJRCARHV-UE_lHsTn.js → stateDiagram-AJRCARHV-By0eiB2Y.js} +1 -1
  242. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Ds0WlK3F.js +1 -0
  243. package/web-shell/assets/{timeline-definition-PNZ67QCA-DRvYdiTs.js → timeline-definition-PNZ67QCA-g_iaSQgv.js} +1 -1
  244. package/web-shell/assets/{vennDiagram-CIIHVFJN-CQLIXs0u.js → vennDiagram-CIIHVFJN-y9ZqJ-TD.js} +1 -1
  245. package/web-shell/assets/{wardley-L42UT6IY-JZz_Xqse.js → wardley-L42UT6IY-BVVfaxpF.js} +1 -1
  246. package/web-shell/assets/{wardleyDiagram-YWT4CUSO--i7BiJwB.js → wardleyDiagram-YWT4CUSO-D3ooZKZT.js} +1 -1
  247. package/web-shell/assets/{xychartDiagram-2RQKCTM6-Bkc-bW0S.js → xychartDiagram-2RQKCTM6-6GXrY6M1.js} +1 -1
  248. package/web-shell/index.html +2 -2
  249. package/chunks/chunk-RXFQM6FQ.js +0 -42
  250. package/chunks/chunk-UA5H3DS2.js +0 -203
  251. package/web-shell/assets/channel-BMwLrwLW.js +0 -1
  252. package/web-shell/assets/classDiagram-4FO5ZUOK-BGDv98jY.js +0 -1
  253. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BGDv98jY.js +0 -1
  254. package/web-shell/assets/index-Bckpjr-I.css +0 -5
  255. package/web-shell/assets/index-DwEr9HEW.js +0 -1768
  256. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DC6xgXjX.js +0 -1
  257. /package/chunks/{chunk-VXZBKKQR.js → chunk-NTTBXH7U.js} +0 -0
  258. /package/chunks/{chunk-GRC5HGPI.js → chunk-OIBUG24X.js} +0 -0
@@ -1,5 +1,11 @@
1
1
  // Force strict mode and setup for ESM
2
2
  "use strict";
3
+ import {
4
+ deriveWebSocketBase,
5
+ openQwenAsrRealtimeStream,
6
+ openVoiceStream,
7
+ openVoiceStreamWithRetry
8
+ } from "./chunk-Q3JQ7OSU.js";
3
9
  import {
4
10
  GENERATION_MAX_PROMPT_BYTES,
5
11
  LIVE_SESSION_SOURCE_PREFIX,
@@ -11,7 +17,6 @@ import {
11
17
  isCompatibleLiveSessionSource,
12
18
  isReservedLiveSessionSource,
13
19
  isValidServerName,
14
- loadSettingsCached,
15
20
  normalizeChannelDelivery,
16
21
  parseChannelDelivery,
17
22
  readLoadableLiveConversationMetadata,
@@ -21,13 +26,7 @@ import {
21
26
  shouldSuppressRememberErrorDetails,
22
27
  workspaceMemoryFailureCode,
23
28
  workspaceMemoryFailureDiagnostics
24
- } from "./chunk-ZPLALRXZ.js";
25
- import {
26
- deriveWebSocketBase,
27
- openQwenAsrRealtimeStream,
28
- openVoiceStream,
29
- openVoiceStreamWithRetry
30
- } from "./chunk-Q3JQ7OSU.js";
29
+ } from "./chunk-FBMCDU63.js";
31
30
  import {
32
31
  SetupGithubError,
33
32
  collectSessionData,
@@ -39,12 +38,12 @@ import {
39
38
  toJson,
40
39
  toJsonl,
41
40
  toMarkdown
42
- } from "./chunk-2M4K4KYS.js";
41
+ } from "./chunk-P3RBMQ4P.js";
43
42
  import {
44
43
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
45
44
  ObservedChannelContactStore
46
45
  } from "./chunk-OWMAZHIX.js";
47
- import "./chunk-4ALIARFY.js";
46
+ import "./chunk-UYAUA63Q.js";
48
47
  import {
49
48
  escapeAnsiCtrlCodes
50
49
  } from "./chunk-4NFY2S7N.js";
@@ -108,46 +107,14 @@ import {
108
107
  setRateLimiter,
109
108
  unsafeRevealSecret,
110
109
  validateMcpRuntimeServerName
111
- } from "./chunk-KAQCJO6Y.js";
110
+ } from "./chunk-KTKYGS2P.js";
111
+ import "./chunk-VGHZT6JR.js";
112
112
  import {
113
- isLoopbackBind
114
- } from "./chunk-RXFQM6FQ.js";
113
+ isLoopbackBind,
114
+ normalizeSessionIdForLookup,
115
+ parseCallerSuppliedSessionId
116
+ } from "./chunk-TQOF5KBL.js";
115
117
  import "./chunk-HGCQ5SE7.js";
116
- import {
117
- createTotalSessionAdmissionController
118
- } from "./chunk-AKA24BGO.js";
119
- import {
120
- WorkspaceGenerationClosedError,
121
- createSingleWorkspaceRegistry,
122
- createWorkspaceSessionOwnerIndex
123
- } from "./chunk-2M5N3DHY.js";
124
- import "./chunk-GRC5HGPI.js";
125
- import {
126
- assertValidChannelSecretUpdates
127
- } from "./chunk-4WU6NY7F.js";
128
- import {
129
- createWorkspaceProvidersStatusProvider
130
- } from "./chunk-XZKQT2B2.js";
131
- import {
132
- getAuthTypeFromEnv,
133
- resolveCliGenerationConfig
134
- } from "./chunk-GBDINRIL.js";
135
- import {
136
- createWorkspaceSkillsStatusProvider
137
- } from "./chunk-DX5W5AON.js";
138
- import "./chunk-BGXZBI5B.js";
139
- import {
140
- isServeDebugMode,
141
- mountWebShellAssets,
142
- mountWebShellSpaFallback
143
- } from "./chunk-SOORFWKY.js";
144
- import {
145
- require_express
146
- } from "./chunk-GDXET5XU.js";
147
- import {
148
- evaluateDaemonWorkspaceTrust,
149
- readDaemonTrustPolicySnapshot
150
- } from "./chunk-SNRT2TJJ.js";
151
118
  import {
152
119
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
153
120
  MAX_WORKSPACE_SKILL_NAME_LENGTH,
@@ -161,14 +128,14 @@ import {
161
128
  validateWorkspaceSkillName,
162
129
  validateWorkspaceVoiceState,
163
130
  voiceSettingsScopeToWire
164
- } from "./chunk-IBYULW65.js";
131
+ } from "./chunk-46YJDYCU.js";
165
132
  import {
166
133
  PermissionRulesValidationError,
167
134
  buildPermissionSettings,
168
135
  isPermissionRuleType,
169
136
  normalizePermissionRules,
170
137
  readPermissionRuleSet
171
- } from "./chunk-KKDVZLGL.js";
138
+ } from "./chunk-BAMN6XSD.js";
172
139
  import {
173
140
  assertVoiceBaseUrlNetworkAllowed,
174
141
  isStreamingVoiceModel,
@@ -176,46 +143,92 @@ import {
176
143
  resolveVoiceTranscriptionConfig,
177
144
  sanitizeVoiceErrorMessage,
178
145
  transcribeVoiceAudio
179
- } from "./chunk-DQSDACD2.js";
146
+ } from "./chunk-RBHQXGDK.js";
180
147
  import {
181
148
  isVoiceEnabled,
182
149
  isVoiceMode,
183
150
  readVoiceModel
184
- } from "./chunk-C5VWPTGT.js";
151
+ } from "./chunk-GAKGOXTC.js";
185
152
  import "./chunk-AOHJKPKL.js";
153
+ import {
154
+ createTotalSessionAdmissionController
155
+ } from "./chunk-BT6GQIEJ.js";
156
+ import {
157
+ WorkspaceGenerationClosedError,
158
+ createSingleWorkspaceRegistry,
159
+ createWorkspaceSessionOwnerIndex
160
+ } from "./chunk-CMOBWHWW.js";
161
+ import "./chunk-OIBUG24X.js";
162
+ import {
163
+ MAX_SESSION_RESTORE_TIMEOUT_MS,
164
+ resolveSessionRestoreTimeoutMs,
165
+ restoreRetryAfterSeconds
166
+ } from "./chunk-4JRM2BSM.js";
167
+ import {
168
+ assertValidChannelSecretUpdates
169
+ } from "./chunk-QSNSL4R4.js";
170
+ import {
171
+ createDaemonStatusProvider
172
+ } from "./chunk-ZTQSOV56.js";
173
+ import "./chunk-NTTBXH7U.js";
174
+ import "./chunk-7S4JBJLU.js";
175
+ import "./chunk-3SH53ANB.js";
176
+ import {
177
+ createWorkspaceProvidersStatusProvider
178
+ } from "./chunk-3WDYBTTI.js";
179
+ import {
180
+ getAuthTypeFromEnv,
181
+ resolveCliGenerationConfig
182
+ } from "./chunk-KTQGGPGV.js";
183
+ import {
184
+ snapshotProcessEnv
185
+ } from "./chunk-23VQTELM.js";
186
+ import {
187
+ createWorkspaceSkillsStatusProvider
188
+ } from "./chunk-ZBXGWQ4S.js";
189
+ import "./chunk-BGXZBI5B.js";
186
190
  import "./chunk-Z4X5MTRT.js";
187
191
  import {
188
192
  WorkspacePermissionRulesSessionRequiredError,
189
193
  WorkspaceSettingsPartialPersistError,
190
- WorkspaceSkillNotFoundError,
191
- WorkspaceSkillNotToggleableError
192
- } from "./chunk-OA4JVLSA.js";
194
+ mapWorkspaceSkillToggleError
195
+ } from "./chunk-Z7VOMGDC.js";
196
+ import {
197
+ isServeDebugMode,
198
+ mountWebShellAssets,
199
+ mountWebShellSpaFallback
200
+ } from "./chunk-SOORFWKY.js";
201
+ import {
202
+ require_express
203
+ } from "./chunk-GDXET5XU.js";
204
+ import {
205
+ evaluateDaemonWorkspaceTrust,
206
+ readDaemonTrustPolicySnapshot
207
+ } from "./chunk-G2TX5ZXC.js";
193
208
  import {
194
209
  daemonObservedContactsPath,
195
210
  loadChannelsConfig
196
- } from "./chunk-E4ZBKMSF.js";
197
- import "./chunk-QQWD7LZV.js";
211
+ } from "./chunk-ATMO54WE.js";
212
+ import "./chunk-HADWBW5R.js";
198
213
  import "./chunk-57OAHC2Y.js";
214
+ import {
215
+ parseChannelWebhookConfigLenient
216
+ } from "./chunk-LHEC5V6G.js";
217
+ import "./chunk-67EWJE77.js";
218
+ import {
219
+ supportedChannelCatalog
220
+ } from "./chunk-E2FPSSKP.js";
199
221
  import {
200
222
  LIVE_HOST_BUNDLE_ID,
201
223
  LIVE_HOST_PROTOCOL_VERSION,
202
224
  LIVE_INPUT_AUDIO_EPOCH_BYTES
203
225
  } from "./chunk-NKLP3DCK.js";
204
- import {
205
- createDaemonStatusProvider
206
- } from "./chunk-VWMUDKLC.js";
207
- import "./chunk-VXZBKKQR.js";
208
- import "./chunk-3SE7J4DR.js";
209
- import "./chunk-3SH53ANB.js";
210
- import {
211
- snapshotProcessEnv
212
- } from "./chunk-S3Y3GBFD.js";
213
226
  import {
214
227
  SessionArtifactAuthorizationError,
215
228
  SessionArtifactValidationError,
216
229
  createAcpSessionBridge,
217
230
  parseSessionSource
218
- } from "./chunk-FYAXKJK7.js";
231
+ } from "./chunk-P4ZEZSJZ.js";
219
232
  import {
220
233
  EVENT_SCHEMA_VERSION,
221
234
  EventBus,
@@ -223,22 +236,16 @@ import {
223
236
  } from "./chunk-MZSJ43WV.js";
224
237
  import "./chunk-XCGIMOLN.js";
225
238
  import "./chunk-OCPBI7J5.js";
226
- import "./chunk-RPWVIXDB.js";
239
+ import "./chunk-I5VM3SKY.js";
227
240
  import {
228
241
  STATUS_SCHEMA_VERSION,
242
+ SessionRestoreTimeoutError,
229
243
  createIdleWorkspaceMemoryStatus,
230
244
  mapDomainErrorToErrorKind
231
- } from "./chunk-NLREQJFK.js";
245
+ } from "./chunk-DA4HRSBW.js";
232
246
  import "./chunk-K6KS3LTN.js";
233
247
  import "./chunk-FC4KQFCS.js";
234
248
  import "./chunk-T3CHYWJZ.js";
235
- import {
236
- parseChannelWebhookConfigLenient
237
- } from "./chunk-QXVSWG66.js";
238
- import "./chunk-KJZ26VBX.js";
239
- import {
240
- supportedChannelCatalog
241
- } from "./chunk-NGYI5EF5.js";
242
249
  import "./chunk-V6WHFGST.js";
243
250
  import {
244
251
  MAX_REGISTERED_WORKSPACES,
@@ -247,12 +254,14 @@ import {
247
254
  WorkspaceRegistrationStoreLimitError,
248
255
  normalizeWorkspaceDisplayName,
249
256
  workspaceRegistrationId
250
- } from "./chunk-757GB46F.js";
257
+ } from "./chunk-W3FSZSF2.js";
251
258
  import {
259
+ REQUESTED_SESSION_ID_META_KEY,
252
260
  gradeActiveWorkCoverage
253
261
  } from "./chunk-M2PNLYGY.js";
254
262
  import {
255
263
  BranchWhilePromptActiveError,
264
+ BridgeChannelQuarantinedError,
256
265
  CancelSentinelCollisionError,
257
266
  CdWhilePromptActiveError,
258
267
  InvalidClientIdError,
@@ -283,7 +292,7 @@ import {
283
292
  WorkspaceInitRaceError,
284
293
  WorkspaceInitSymlinkError,
285
294
  WorkspaceMismatchError
286
- } from "./chunk-J26HHFI5.js";
295
+ } from "./chunk-LP2QGNSP.js";
287
296
  import {
288
297
  MAX_WORKSPACE_PATH_LENGTH,
289
298
  canonicalizeWorkspace,
@@ -302,19 +311,19 @@ import {
302
311
  } from "./chunk-YP5KH5Y7.js";
303
312
  import {
304
313
  normalizeWorkerDiagnostic
305
- } from "./chunk-UFALT4LK.js";
314
+ } from "./chunk-PBRVUF5B.js";
306
315
  import {
307
316
  normalizeServeChannelSelection
308
317
  } from "./chunk-ALMR3E6Q.js";
309
318
  import "./chunk-HIBNSEJE.js";
310
- import "./chunk-BKHCW2BI.js";
311
319
  import {
312
320
  redactLogCredentials
313
321
  } from "./chunk-M5GB774H.js";
322
+ import "./chunk-BKHCW2BI.js";
314
323
  import "./chunk-5HBA2Z7V.js";
315
324
  import {
316
325
  sanitizeLogText
317
- } from "./chunk-DIWZNWZT.js";
326
+ } from "./chunk-DX3RGJMS.js";
318
327
  import "./chunk-UDXSXLER.js";
319
328
  import {
320
329
  getDialogSettingKeys,
@@ -325,23 +334,26 @@ import {
325
334
  getWritableScopes,
326
335
  loadSettings,
327
336
  validateSettingValue
328
- } from "./chunk-OHKJVAKG.js";
337
+ } from "./chunk-JUWS2Z5K.js";
338
+ import "./chunk-7GOYZQPR.js";
329
339
  import "./chunk-RKUWKYED.js";
330
340
  import "./chunk-GOXKNSDZ.js";
331
341
  import "./chunk-IDS7MSUP.js";
332
342
  import {
333
- SUPPORTED_LANGUAGES,
334
343
  detectSystemLanguage,
335
- resolveLanguageSetting,
344
+ resolveLanguageSetting
345
+ } from "./chunk-WP5VOXF7.js";
346
+ import {
347
+ SUPPORTED_LANGUAGES,
336
348
  resolveSupportedLanguage
337
- } from "./chunk-PG62DFWD.js";
338
- import "./chunk-B52AWKBB.js";
339
- import "./chunk-UA5H3DS2.js";
340
- import "./chunk-FN6YXJOP.js";
349
+ } from "./chunk-5EJZE3FP.js";
350
+ import "./chunk-T6HEQR2Q.js";
351
+ import "./chunk-VFMASYQA.js";
352
+ import "./chunk-IOEZE2YT.js";
341
353
  import "./chunk-VJNBRRZG.js";
342
354
  import {
343
355
  getWorkspaceTrustStatus
344
- } from "./chunk-HA3SAB64.js";
356
+ } from "./chunk-ZOSTTOUJ.js";
345
357
  import "./chunk-NPQ5ZKRP.js";
346
358
  import {
347
359
  isWithinRoot as isWithinRoot2
@@ -421,7 +433,7 @@ import {
421
433
  writeWorkspaceContextFile,
422
434
  writeWorktreeSession,
423
435
  writeWorktreeSessionMarker
424
- } from "./chunk-GXSNGY5M.js";
436
+ } from "./chunk-XX7QFP34.js";
425
437
  import "./chunk-GOFAQQZA.js";
426
438
  import "./chunk-5M6IDOMF.js";
427
439
  import "./chunk-TWPJO254.js";
@@ -434,7 +446,7 @@ import "./chunk-MVUQRLOH.js";
434
446
  import "./chunk-XCWO3SMQ.js";
435
447
  import "./chunk-7MH4J33A.js";
436
448
  import "./chunk-6PVPNMXU.js";
437
- import "./chunk-VXZ5HAOV.js";
449
+ import "./chunk-K4ADGWHU.js";
438
450
  import {
439
451
  nextFireTime,
440
452
  parseCron
@@ -462,7 +474,7 @@ import "./chunk-67N6HB5H.js";
462
474
  import {
463
475
  APPROVAL_MODES
464
476
  } from "./chunk-WAUGQKUU.js";
465
- import "./chunk-PLFATELK.js";
477
+ import "./chunk-DZUO626D.js";
466
478
  import {
467
479
  addDaemonRequestAttribute,
468
480
  captureDaemonTelemetryContext,
@@ -474,7 +486,7 @@ import {
474
486
  recordDaemonHttpResponse,
475
487
  runWithDaemonTelemetryContext,
476
488
  withDaemonRequestSpan
477
- } from "./chunk-L4N6TIP7.js";
489
+ } from "./chunk-4TRQPFDP.js";
478
490
  import "./chunk-SAH4BD2J.js";
479
491
  import "./chunk-CPG6P4GG.js";
480
492
  import "./chunk-S6LOFUVP.js";
@@ -521,23 +533,23 @@ import {
521
533
  isWithinRoot,
522
534
  parseLineTolerant,
523
535
  read
524
- } from "./chunk-3PY4LPJF.js";
536
+ } from "./chunk-YGT2AUJ7.js";
525
537
  import "./chunk-WOJZWRAZ.js";
526
538
  import "./chunk-VGC4I5JJ.js";
527
539
  import "./chunk-FVKHVJZQ.js";
528
540
  import "./chunk-COBO5EBO.js";
529
541
  import "./chunk-6ZRFAKXK.js";
530
542
  import "./chunk-PYQADEFD.js";
531
- import "./chunk-M3STHEMM.js";
543
+ import "./chunk-PVOGHGSF.js";
532
544
  import "./chunk-F6WFNA7U.js";
533
545
  import "./chunk-46UV252V.js";
534
546
  import "./chunk-ZBVS26BY.js";
535
547
  import "./chunk-KKBPOU75.js";
536
548
  import "./chunk-EUNWC2VS.js";
537
549
  import "./chunk-FOGU3LJX.js";
538
- import "./chunk-6M26GBKX.js";
550
+ import "./chunk-L2AFWWJE.js";
539
551
  import "./chunk-W4RQUHY3.js";
540
- import "./chunk-LKRMNRSN.js";
552
+ import "./chunk-PDPFQ2FO.js";
541
553
  import {
542
554
  FatalConfigError,
543
555
  Storage,
@@ -1225,26 +1237,165 @@ function createWorkspaceFileSystemFactory(deps) {
1225
1237
  });
1226
1238
  const lowFs = new StandardFileSystemService();
1227
1239
  const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
1240
+ const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
1241
+ primaryWorkspace,
1242
+ workspaces,
1243
+ trusted: deps.trusted,
1244
+ audit,
1245
+ ctx,
1246
+ lowFs,
1247
+ pathLocks,
1248
+ generationGuard: deps.generationGuard
1249
+ }), "forRequest");
1228
1250
  return {
1229
1251
  assertCanWrite() {
1230
1252
  deps.generationGuard?.assertOpen();
1231
1253
  assertTrustedForIntent(deps.trusted, "write");
1232
1254
  },
1233
- forRequest(ctx) {
1234
- return new WorkspaceFileSystemImpl({
1235
- primaryWorkspace,
1236
- workspaces,
1237
- trusted: deps.trusted,
1238
- audit,
1239
- ctx,
1240
- lowFs,
1241
- pathLocks,
1242
- generationGuard: deps.generationGuard
1243
- });
1255
+ forRequest,
1256
+ async writeSameHostToolText(ctx, request2) {
1257
+ try {
1258
+ deps.generationGuard?.assertOpen();
1259
+ } catch (err) {
1260
+ throw recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1261
+ }
1262
+ let resolved;
1263
+ try {
1264
+ resolved = await resolveWithinWorkspace(
1265
+ request2.path,
1266
+ workspaces.map((workspace) => workspace.path),
1267
+ "write"
1268
+ );
1269
+ deps.generationGuard?.assertOpen();
1270
+ } catch (err) {
1271
+ if (!(err instanceof FsError && err.kind === "path_outside_workspace")) {
1272
+ throw recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1273
+ }
1274
+ try {
1275
+ await writeSameHostToolTextOutsideWorkspace({
1276
+ request: request2,
1277
+ trusted: deps.trusted,
1278
+ audit,
1279
+ ctx,
1280
+ pathLocks,
1281
+ generationGuard: deps.generationGuard
1282
+ });
1283
+ return;
1284
+ } catch (outsideErr) {
1285
+ throw recordSameHostToolWriteDenied(
1286
+ audit,
1287
+ ctx,
1288
+ request2.path,
1289
+ outsideErr
1290
+ );
1291
+ }
1292
+ }
1293
+ try {
1294
+ await forRequest(ctx).writeTextOverwrite(resolved, request2.content);
1295
+ } catch (err) {
1296
+ if (isWorkspaceGenerationClosedError(err)) {
1297
+ recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1298
+ }
1299
+ throw err;
1300
+ }
1244
1301
  }
1245
1302
  };
1246
1303
  }
1247
1304
  __name(createWorkspaceFileSystemFactory, "createWorkspaceFileSystemFactory");
1305
+ async function writeSameHostToolTextOutsideWorkspace(deps) {
1306
+ const start = performance.now();
1307
+ deps.generationGuard?.assertOpen();
1308
+ assertTrustedForIntent(deps.trusted, "write");
1309
+ enforceWriteSize(Buffer.byteLength(deps.request.content, "utf-8"));
1310
+ const target = await resolveSameHostToolWriteTarget(deps.request.path);
1311
+ await deps.pathLocks.runExclusive(target, async () => {
1312
+ deps.generationGuard?.assertOpen();
1313
+ const meta = mergeWriteMeta(void 0, deps.request.meta ?? {});
1314
+ const content = meta.bom && deps.request.content.charCodeAt(0) === 65279 ? deps.request.content.slice(1) : deps.request.content;
1315
+ const result = await atomicWriteTextResolvedFile({
1316
+ target,
1317
+ content,
1318
+ mode: "overwrite",
1319
+ meta,
1320
+ assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1321
+ });
1322
+ deps.audit.recordAccess(deps.ctx, {
1323
+ intent: "write",
1324
+ absolute: target,
1325
+ durationMs: performance.now() - start,
1326
+ sizeBytes: result.sizeBytes
1327
+ });
1328
+ });
1329
+ }
1330
+ __name(writeSameHostToolTextOutsideWorkspace, "writeSameHostToolTextOutsideWorkspace");
1331
+ async function resolveSameHostToolWriteTarget(input) {
1332
+ if (!path4.isAbsolute(input)) {
1333
+ throw new FsError(
1334
+ "path_outside_workspace",
1335
+ `same-host external tool write requires an absolute path: ${input}`
1336
+ );
1337
+ }
1338
+ if (hasSuspiciousPathPattern(input)) {
1339
+ throw new FsError(
1340
+ "path_outside_workspace",
1341
+ `path contains suspicious pattern: ${input}`
1342
+ );
1343
+ }
1344
+ let leaf;
1345
+ try {
1346
+ leaf = await fsp2.lstat(input);
1347
+ } catch (err) {
1348
+ if (err?.code !== "ENOENT") {
1349
+ throw err;
1350
+ }
1351
+ const parent = await fsp2.realpath(path4.dirname(input));
1352
+ const parentStat = await fsp2.lstat(parent);
1353
+ if (!parentStat.isDirectory()) {
1354
+ throw new FsError(
1355
+ "parse_error",
1356
+ `parent path is not a directory: ${parent}`
1357
+ );
1358
+ }
1359
+ return path4.join(parent, path4.basename(input));
1360
+ }
1361
+ if (leaf.isSymbolicLink()) {
1362
+ throw new FsError(
1363
+ "symlink_escape",
1364
+ `path is a symlink and cannot be overwritten: ${input}`,
1365
+ { hint: "resolve the target explicitly before writing" }
1366
+ );
1367
+ }
1368
+ if (!leaf.isFile()) {
1369
+ throw new FsError("parse_error", `path is not a regular file: ${input}`);
1370
+ }
1371
+ const canonical = await fsp2.realpath(input);
1372
+ const canonicalStat = await fsp2.lstat(canonical);
1373
+ if (!canonicalStat.isFile()) {
1374
+ throw new FsError(
1375
+ "parse_error",
1376
+ `canonical path is not a regular file: ${canonical}`
1377
+ );
1378
+ }
1379
+ assertSameFile(leaf, canonicalStat, input, "write");
1380
+ return canonical;
1381
+ }
1382
+ __name(resolveSameHostToolWriteTarget, "resolveSameHostToolWriteTarget");
1383
+ function isWorkspaceGenerationClosedError(error2) {
1384
+ return error2 instanceof Error && "code" in error2 && error2.code === "workspace_generation_closed";
1385
+ }
1386
+ __name(isWorkspaceGenerationClosedError, "isWorkspaceGenerationClosedError");
1387
+ function recordSameHostToolWriteDenied(audit, ctx, input, error2) {
1388
+ const fsError = wrapAsFsError(error2);
1389
+ audit.recordDenied(ctx, {
1390
+ intent: "write",
1391
+ input,
1392
+ errorKind: fsError.kind,
1393
+ hint: fsError.hint,
1394
+ message: fsError.message
1395
+ });
1396
+ return isWorkspaceGenerationClosedError(error2) && error2 instanceof Error ? error2 : fsError;
1397
+ }
1398
+ __name(recordSameHostToolWriteDenied, "recordSameHostToolWriteDenied");
1248
1399
  function assertNoNestedWorkspaces(workspaces) {
1249
1400
  for (let i = 0; i < workspaces.length; i++) {
1250
1401
  const a = workspaces[i];
@@ -5168,6 +5319,214 @@ function mountWorkspaceQualifiedMemoryRememberRoutes(app, deps) {
5168
5319
  }
5169
5320
  __name(mountWorkspaceQualifiedMemoryRememberRoutes, "mountWorkspaceQualifiedMemoryRememberRoutes");
5170
5321
 
5322
+ // packages/cli/src/serve/session-id-admission.ts
5323
+ init_esbuild_shims();
5324
+ import { access } from "node:fs/promises";
5325
+ var RequestedSessionIdAdmissionError = class extends Error {
5326
+ constructor(code, sessionId, message, details = {}) {
5327
+ super(message);
5328
+ this.code = code;
5329
+ this.sessionId = sessionId;
5330
+ this.details = details;
5331
+ }
5332
+ static {
5333
+ __name(this, "RequestedSessionIdAdmissionError");
5334
+ }
5335
+ name = "RequestedSessionIdAdmissionError";
5336
+ };
5337
+ async function persistedSessionExists(sessionService, sessionId) {
5338
+ if (await sessionService.getSessionLocation(sessionId) !== void 0) {
5339
+ return true;
5340
+ }
5341
+ if (await sessionService.findSessionIdIgnoringCase?.(sessionId) !== void 0) {
5342
+ return true;
5343
+ }
5344
+ for (const state of ["active", "archived"]) {
5345
+ try {
5346
+ await access(
5347
+ sessionService.getWorktreeSessionPathForArchiveState(sessionId, state)
5348
+ );
5349
+ return true;
5350
+ } catch (error2) {
5351
+ if (error2.code !== "ENOENT") throw error2;
5352
+ }
5353
+ }
5354
+ return false;
5355
+ }
5356
+ __name(persistedSessionExists, "persistedSessionExists");
5357
+ function createRequestedSessionIdAdmission({
5358
+ archiveCoordinator,
5359
+ getBridges,
5360
+ getPersistenceTargets,
5361
+ getBridgeWorkspaceId
5362
+ }) {
5363
+ const pending = /* @__PURE__ */ new Map();
5364
+ const liveOwners = /* @__PURE__ */ __name((sessionId) => {
5365
+ const owners = [];
5366
+ let bridges;
5367
+ try {
5368
+ bridges = getBridges();
5369
+ } catch {
5370
+ throw new RequestedSessionIdAdmissionError(
5371
+ "session_id_admission_unavailable",
5372
+ sessionId,
5373
+ `Unable to enumerate live bridges for session "${sessionId}".`,
5374
+ { retryable: true }
5375
+ );
5376
+ }
5377
+ for (const bridge of new Set(bridges)) {
5378
+ try {
5379
+ const summary = bridge.getSessionSummary(sessionId);
5380
+ owners.push({
5381
+ bridge,
5382
+ workspaceCwd: summary.workspaceCwd,
5383
+ workspaceId: getBridgeWorkspaceId?.(bridge)
5384
+ });
5385
+ } catch (error2) {
5386
+ if (error2 instanceof SessionNotFoundError) continue;
5387
+ throw new RequestedSessionIdAdmissionError(
5388
+ "session_id_admission_unavailable",
5389
+ sessionId,
5390
+ `Unable to verify whether session "${sessionId}" is already live.`,
5391
+ { retryable: true }
5392
+ );
5393
+ }
5394
+ }
5395
+ return owners;
5396
+ }, "liveOwners");
5397
+ const conflict = /* @__PURE__ */ __name((sessionId, conflictKind, workspaceCwd) => new RequestedSessionIdAdmissionError(
5398
+ "session_id_conflict",
5399
+ sessionId,
5400
+ `Session "${sessionId}" already exists or is being created.`,
5401
+ {
5402
+ conflict: conflictKind,
5403
+ ...workspaceCwd ? { liveWorkspaceCwd: workspaceCwd } : {}
5404
+ }
5405
+ ), "conflict");
5406
+ const workspaceConflict = /* @__PURE__ */ __name((sessionId, target, conflictKind, liveWorkspaceCwd, liveWorkspaceId) => new RequestedSessionIdAdmissionError(
5407
+ "session_workspace_conflict",
5408
+ sessionId,
5409
+ `Session "${sessionId}" is already live or restoring in another workspace runtime.`,
5410
+ {
5411
+ conflict: conflictKind,
5412
+ workspaceCwd: target.workspaceCwd,
5413
+ ...target.workspaceId ? { workspaceId: target.workspaceId } : {},
5414
+ ...liveWorkspaceCwd ? { liveWorkspaceCwd } : {},
5415
+ ...liveWorkspaceId ? { liveWorkspaceId } : {}
5416
+ }
5417
+ ), "workspaceConflict");
5418
+ const createReservation = /* @__PURE__ */ __name((sessionId, state) => {
5419
+ let released = false;
5420
+ return {
5421
+ release() {
5422
+ if (released) return;
5423
+ released = true;
5424
+ if (pending.get(sessionId) !== state) return;
5425
+ if (state.kind === "restore" && state.count > 1) {
5426
+ state.count--;
5427
+ return;
5428
+ }
5429
+ pending.delete(sessionId);
5430
+ }
5431
+ };
5432
+ }, "createReservation");
5433
+ return {
5434
+ async reserveCreate(rawSessionId, target) {
5435
+ const sessionId = normalizeSessionIdForLookup(rawSessionId);
5436
+ const live = liveOwners(sessionId)[0];
5437
+ if (live) throw conflict(sessionId, "live", live.workspaceCwd);
5438
+ if (pending.has(sessionId)) throw conflict(sessionId, "pending");
5439
+ const state = { kind: "create", target };
5440
+ pending.set(sessionId, state);
5441
+ const reservation = createReservation(sessionId, state);
5442
+ try {
5443
+ let persisted;
5444
+ try {
5445
+ persisted = await archiveCoordinator.runSharedMany(
5446
+ [sessionId],
5447
+ async () => {
5448
+ const targets = [
5449
+ ...new Map(
5450
+ getPersistenceTargets().map((entry) => [
5451
+ `${entry.runtimeBaseDir}\0${entry.workspaceCwd}`,
5452
+ entry
5453
+ ])
5454
+ ).values()
5455
+ ];
5456
+ const results = await Promise.all(
5457
+ targets.map(async (entry) => {
5458
+ const sessionService = new SessionService(
5459
+ entry.workspaceCwd,
5460
+ { runtimeBaseDir: entry.runtimeBaseDir }
5461
+ );
5462
+ return {
5463
+ entry,
5464
+ exists: await persistedSessionExists(
5465
+ sessionService,
5466
+ sessionId
5467
+ )
5468
+ };
5469
+ })
5470
+ );
5471
+ return results.find((result) => result.exists)?.entry;
5472
+ }
5473
+ );
5474
+ } catch {
5475
+ throw new RequestedSessionIdAdmissionError(
5476
+ "session_id_admission_unavailable",
5477
+ sessionId,
5478
+ `Unable to verify persisted state for session "${sessionId}".`,
5479
+ { retryable: true }
5480
+ );
5481
+ }
5482
+ if (persisted) {
5483
+ throw conflict(sessionId, "persisted", persisted.workspaceCwd);
5484
+ }
5485
+ return reservation;
5486
+ } catch (error2) {
5487
+ reservation.release();
5488
+ throw error2;
5489
+ }
5490
+ },
5491
+ reserveRestore(rawSessionId, target) {
5492
+ const sessionId = normalizeSessionIdForLookup(rawSessionId);
5493
+ const foreignLive = liveOwners(sessionId).find(
5494
+ (owner) => owner.bridge !== target.bridge
5495
+ );
5496
+ if (foreignLive) {
5497
+ throw workspaceConflict(
5498
+ sessionId,
5499
+ target,
5500
+ "live",
5501
+ foreignLive.workspaceCwd,
5502
+ foreignLive.workspaceId
5503
+ );
5504
+ }
5505
+ const existing = pending.get(sessionId);
5506
+ if (existing?.kind === "create") {
5507
+ throw conflict(sessionId, "pending");
5508
+ }
5509
+ if (existing?.kind === "restore") {
5510
+ if (existing.target.bridge !== target.bridge) {
5511
+ throw workspaceConflict(
5512
+ sessionId,
5513
+ target,
5514
+ "pending",
5515
+ existing.target.workspaceCwd,
5516
+ existing.target.workspaceId
5517
+ );
5518
+ }
5519
+ existing.count++;
5520
+ return createReservation(sessionId, existing);
5521
+ }
5522
+ const state = { kind: "restore", target, count: 1 };
5523
+ pending.set(sessionId, state);
5524
+ return createReservation(sessionId, state);
5525
+ }
5526
+ };
5527
+ }
5528
+ __name(createRequestedSessionIdAdmission, "createRequestedSessionIdAdmission");
5529
+
5171
5530
  // packages/cli/src/serve/workspace-memory.ts
5172
5531
  init_esbuild_shims();
5173
5532
  import { promises as fs2 } from "node:fs";
@@ -8215,6 +8574,9 @@ var TRUSTED_WORKSPACE_METHODS = /* @__PURE__ */ new Set([
8215
8574
  `${QWEN_METHOD_NS}workspace/session_groups/delete`
8216
8575
  ]);
8217
8576
  var WORKSPACE_GENERATION_MUTATION_METHODS = /* @__PURE__ */ new Set([
8577
+ "session/new",
8578
+ "session/load",
8579
+ "session/resume",
8218
8580
  `${QWEN_METHOD_NS}workspace/init`,
8219
8581
  `${QWEN_METHOD_NS}workspace/trust/request`,
8220
8582
  `${QWEN_METHOD_NS}workspace/permissions/set`,
@@ -8263,6 +8625,23 @@ var AcpParamError = class extends Error {
8263
8625
  __name(this, "AcpParamError");
8264
8626
  }
8265
8627
  };
8628
+ var InvalidRequestedSessionIdError = class extends Error {
8629
+ static {
8630
+ __name(this, "InvalidRequestedSessionIdError");
8631
+ }
8632
+ };
8633
+ var RequestedSessionIdNotHonoredError = class extends Error {
8634
+ constructor(requestedSessionId, actualSessionId) {
8635
+ super(
8636
+ `The ACP agent returned session "${actualSessionId}" instead of requested session "${requestedSessionId}".`
8637
+ );
8638
+ this.requestedSessionId = requestedSessionId;
8639
+ this.actualSessionId = actualSessionId;
8640
+ }
8641
+ static {
8642
+ __name(this, "RequestedSessionIdNotHonoredError");
8643
+ }
8644
+ };
8266
8645
  function parseOptionalPositiveInteger(value, fallback, max) {
8267
8646
  if (value === void 0) return fallback;
8268
8647
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > max) {
@@ -8373,6 +8752,38 @@ function pickSessionArtifactInput(params) {
8373
8752
  }
8374
8753
  __name(pickSessionArtifactInput, "pickSessionArtifactInput");
8375
8754
  function toRpcError(err) {
8755
+ if (err instanceof InvalidRequestedSessionIdError) {
8756
+ return {
8757
+ code: RPC.INVALID_PARAMS,
8758
+ message: err.message,
8759
+ data: { httpStatus: 400, errorKind: "invalid_session_id" }
8760
+ };
8761
+ }
8762
+ if (err instanceof RequestedSessionIdAdmissionError) {
8763
+ const unavailable = err.code === "session_id_admission_unavailable";
8764
+ return {
8765
+ code: unavailable ? RPC.INTERNAL_ERROR : RPC.INVALID_PARAMS,
8766
+ message: err.message,
8767
+ data: {
8768
+ httpStatus: unavailable ? 503 : 409,
8769
+ errorKind: err.code,
8770
+ sessionId: err.sessionId,
8771
+ ...err.details
8772
+ }
8773
+ };
8774
+ }
8775
+ if (err instanceof RequestedSessionIdNotHonoredError) {
8776
+ return {
8777
+ code: RPC.INTERNAL_ERROR,
8778
+ message: err.message,
8779
+ data: {
8780
+ httpStatus: 500,
8781
+ errorKind: "session_id_not_honored",
8782
+ requestedSessionId: err.requestedSessionId,
8783
+ actualSessionId: err.actualSessionId
8784
+ }
8785
+ };
8786
+ }
8376
8787
  if (err instanceof DaemonDrainingError) {
8377
8788
  return {
8378
8789
  code: RPC.INTERNAL_ERROR,
@@ -8495,6 +8906,56 @@ function toRpcError(err) {
8495
8906
  }
8496
8907
  const name = err instanceof Error ? err.name : "";
8497
8908
  switch (name) {
8909
+ case "SessionRestoreTimeoutError": {
8910
+ const restoreError = err;
8911
+ return {
8912
+ code: RPC.INTERNAL_ERROR,
8913
+ message: restoreError.message,
8914
+ data: {
8915
+ code: "session_restore_timeout",
8916
+ errorKind: "restore_timeout",
8917
+ httpStatus: 504,
8918
+ retryable: true,
8919
+ retryAfterSeconds: restoreRetryAfterSeconds(restoreError.timeoutMs),
8920
+ sessionId: restoreError.sessionId,
8921
+ action: restoreError.action,
8922
+ timeoutMs: restoreError.timeoutMs
8923
+ }
8924
+ };
8925
+ }
8926
+ case "RestoreInProgressError": {
8927
+ const fenceError = err;
8928
+ return {
8929
+ code: RPC.INTERNAL_ERROR,
8930
+ message: fenceError.message,
8931
+ data: {
8932
+ code: "restore_in_progress",
8933
+ errorKind: "restore_in_progress",
8934
+ httpStatus: 409,
8935
+ retryable: true,
8936
+ reason: fenceError.reason,
8937
+ retryAfterSeconds: fenceError.retryAfterSeconds,
8938
+ sessionId: fenceError.sessionId,
8939
+ activeAction: fenceError.activeAction,
8940
+ requestedAction: fenceError.requestedAction
8941
+ }
8942
+ };
8943
+ }
8944
+ case "BridgeChannelQuarantinedError": {
8945
+ const unavailableError = err;
8946
+ return {
8947
+ code: RPC.INTERNAL_ERROR,
8948
+ message: unavailableError.message,
8949
+ data: {
8950
+ code: "acp_channel_unavailable",
8951
+ errorKind: "acp_channel_unavailable",
8952
+ httpStatus: 503,
8953
+ retryable: true,
8954
+ reason: unavailableError.reason,
8955
+ retryAfterSeconds: unavailableError.retryAfterSeconds
8956
+ }
8957
+ };
8958
+ }
8498
8959
  case "SessionArchivedError":
8499
8960
  return {
8500
8961
  code: RPC.INTERNAL_ERROR,
@@ -8588,12 +9049,16 @@ function rpcErrorFrame(id, err) {
8588
9049
  __name(rpcErrorFrame, "rpcErrorFrame");
8589
9050
  var ACP_PROTOCOL_VERSION = 1;
8590
9051
  var AcpDispatcher = class {
8591
- constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0, liveSessionIsolation, sessionRuntimeBaseDir = Storage.getRuntimeBaseDir()) {
9052
+ constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, requestedSessionIdAdmission, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0, liveSessionIsolation, sessionRuntimeBaseDir = Storage.getRuntimeBaseDir(), getSessionRuntimeContext = () => ({
9053
+ bridge,
9054
+ sessionRuntimeBaseDir
9055
+ })) {
8592
9056
  this.bridge = bridge;
8593
9057
  this.boundWorkspace = boundWorkspace;
8594
9058
  this.getEnv = getEnv;
8595
9059
  this.workspace = workspace;
8596
9060
  this.workspaceRememberLane = workspaceRememberLane;
9061
+ this.requestedSessionIdAdmission = requestedSessionIdAdmission;
8597
9062
  this.fsFactory = fsFactory;
8598
9063
  this.deviceFlowRegistry = deviceFlowRegistry;
8599
9064
  this.sessionShellCommandEnabled = sessionShellCommandEnabled;
@@ -8603,26 +9068,31 @@ var AcpDispatcher = class {
8603
9068
  this.captureGenerationAssertion = captureGenerationAssertion;
8604
9069
  this.liveSessionIsolation = liveSessionIsolation;
8605
9070
  this.sessionRuntimeBaseDir = sessionRuntimeBaseDir;
9071
+ this.getSessionRuntimeContext = getSessionRuntimeContext;
8606
9072
  this.agentManager = createDaemonSubagentManager(boundWorkspace);
8607
9073
  }
8608
9074
  static {
8609
9075
  __name(this, "AcpDispatcher");
8610
9076
  }
8611
9077
  agentManager;
8612
- killOrphanSession(sessionId, removePersistedSession = false) {
9078
+ removeOrphanSession(sessionId, removePersistedSession = false, runtime = this.getSessionRuntimeContext()) {
8613
9079
  const cleanup = removePersistedSession ? deleteDaemonSessionIfOrphan({
8614
9080
  sessionId,
8615
9081
  service: new SessionService(this.boundWorkspace, {
8616
- runtimeBaseDir: this.sessionRuntimeBaseDir
9082
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir
8617
9083
  }),
8618
- bridge: this.bridge,
9084
+ bridge: runtime.bridge,
8619
9085
  coordinator: this.archiveCoordinator
8620
- }) : this.bridge.killSession(sessionId, { requireZeroAttaches: true });
8621
- void cleanup.catch(
8622
- (err) => writeStderrLine(
9086
+ }) : runtime.bridge.killSession(sessionId, { requireZeroAttaches: true });
9087
+ return cleanup.catch((err) => {
9088
+ writeStderrLine(
8623
9089
  `qwen serve: /acp orphan killSession(${logSafe(sessionId)}) failed: ${logSafe(errMsg(err))}`
8624
- )
8625
- );
9090
+ );
9091
+ return void 0;
9092
+ });
9093
+ }
9094
+ killOrphanSession(sessionId, removePersistedSession = false, runtime) {
9095
+ void this.removeOrphanSession(sessionId, removePersistedSession, runtime);
8626
9096
  }
8627
9097
  /**
8628
9098
  * Build the `WorkspaceRequestContext` for workspace-scoped operations
@@ -8726,9 +9196,9 @@ var AcpDispatcher = class {
8726
9196
  * child's own session state. Returned in `session/new` and as the result
8727
9197
  * of `session/set_config_option`. Best-effort — `undefined` on error.
8728
9198
  */
8729
- async configOptionsFor(sessionId) {
9199
+ async configOptionsFor(sessionId, bridge = this.bridge) {
8730
9200
  try {
8731
- const ctx = await this.bridge.getSessionContextStatus(sessionId);
9201
+ const ctx = await bridge.getSessionContextStatus(sessionId);
8732
9202
  const co = ctx?.state?.configOptions;
8733
9203
  return Array.isArray(co) ? co : void 0;
8734
9204
  } catch (err) {
@@ -8922,7 +9392,13 @@ var AcpDispatcher = class {
8922
9392
  }
8923
9393
  if (!isRequest(msg) && !isNotification(msg)) return;
8924
9394
  const method = msg.method;
8925
- const params = isObject(msg.params) ? msg.params : {};
9395
+ const params = {
9396
+ ...isObject(msg.params) ? msg.params : {}
9397
+ };
9398
+ if (typeof params["sessionId"] === "string") {
9399
+ params["sessionId"] = normalizeSessionIdForLookup(params["sessionId"]);
9400
+ }
9401
+ const normalizedSessionHeader = sessionHeader ? normalizeSessionIdForLookup(sessionHeader) : void 0;
8926
9402
  const id = isRequest(msg) ? msg.id : void 0;
8927
9403
  const generationScoped = TRUSTED_WORKSPACE_METHODS.has(method) || WORKSPACE_GENERATION_MUTATION_METHODS.has(method);
8928
9404
  const assertGenerationOpen = generationScoped ? this.captureGenerationAssertion() : void 0;
@@ -8945,7 +9421,7 @@ var AcpDispatcher = class {
8945
9421
  }
8946
9422
  return;
8947
9423
  }
8948
- if (sessionHeader && typeof params["sessionId"] === "string" && params["sessionId"] !== sessionHeader) {
9424
+ if (normalizedSessionHeader && typeof params["sessionId"] === "string" && params["sessionId"] !== normalizedSessionHeader) {
8949
9425
  if (id !== void 0) {
8950
9426
  conn.sendConn(
8951
9427
  error(
@@ -8963,6 +9439,16 @@ var AcpDispatcher = class {
8963
9439
  this.replyConn(conn, id, {});
8964
9440
  return;
8965
9441
  case "session/new": {
9442
+ const meta = isObject(params["_meta"]) ? params["_meta"] : void 0;
9443
+ const parsedSessionId = parseCallerSuppliedSessionId(
9444
+ meta?.[REQUESTED_SESSION_ID_META_KEY]
9445
+ );
9446
+ if (parsedSessionId.kind === "invalid") {
9447
+ throw new InvalidRequestedSessionIdError(
9448
+ `\`_meta["${REQUESTED_SESSION_ID_META_KEY}"]\` must be an RFC UUID v1-v5`
9449
+ );
9450
+ }
9451
+ const requestedSessionId = parsedSessionId.kind === "valid" ? parsedSessionId.sessionId : void 0;
8966
9452
  const cwd = this.parseSessionWorkspaceCwd(params);
8967
9453
  if (this.liveSessionIsolation) {
8968
9454
  if (id !== void 0) {
@@ -8977,6 +9463,7 @@ var AcpDispatcher = class {
8977
9463
  }
8978
9464
  return;
8979
9465
  }
9466
+ const sessionRuntime = this.getSessionRuntimeContext();
8980
9467
  const source = parseSessionSource(
8981
9468
  params["sourceType"],
8982
9469
  params["sourceId"]
@@ -8999,39 +9486,89 @@ var AcpDispatcher = class {
8999
9486
  }
9000
9487
  return;
9001
9488
  }
9002
- const session = await this.bridge.spawnOrAttach({
9003
- workspaceCwd: cwd,
9004
- clientId: conn.clientId,
9005
- sessionScope: "thread",
9006
- ...source
9007
- });
9008
- if (conn.destroyed) {
9009
- this.killOrphanSession(session.sessionId, true);
9010
- return;
9011
- }
9012
- conn.getOrCreateSession(session.sessionId).clientId = session.clientId;
9013
- conn.ownSession(session.sessionId);
9014
- const configOptions = await this.configOptionsFor(session.sessionId);
9015
- if (conn.destroyed) {
9016
- this.killOrphanSession(session.sessionId, true);
9489
+ const reservation = requestedSessionId ? await this.requestedSessionIdAdmission.reserveCreate(
9490
+ requestedSessionId,
9491
+ {
9492
+ bridge: sessionRuntime.bridge,
9493
+ workspaceCwd: cwd,
9494
+ ...sessionRuntime.workspaceId ? { workspaceId: sessionRuntime.workspaceId } : {}
9495
+ }
9496
+ ) : void 0;
9497
+ try {
9498
+ assertGenerationOpen?.();
9499
+ const session = await sessionRuntime.bridge.spawnOrAttach({
9500
+ workspaceCwd: cwd,
9501
+ clientId: conn.clientId,
9502
+ sessionScope: "thread",
9503
+ ...source,
9504
+ ...requestedSessionId ? { sessionId: requestedSessionId } : {}
9505
+ });
9506
+ const rollbackSession = /* @__PURE__ */ __name(async () => {
9507
+ if (session.attached) {
9508
+ await sessionRuntime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
9509
+ });
9510
+ } else {
9511
+ await this.removeOrphanSession(
9512
+ session.sessionId,
9513
+ true,
9514
+ sessionRuntime
9515
+ );
9516
+ }
9517
+ }, "rollbackSession");
9518
+ try {
9519
+ assertGenerationOpen?.();
9520
+ } catch (error2) {
9521
+ await rollbackSession();
9522
+ throw error2;
9523
+ }
9524
+ if (requestedSessionId !== void 0 && session.sessionId !== requestedSessionId) {
9525
+ await rollbackSession();
9526
+ throw new RequestedSessionIdNotHonoredError(
9527
+ requestedSessionId,
9528
+ session.sessionId
9529
+ );
9530
+ }
9531
+ if (conn.destroyed) {
9532
+ this.killOrphanSession(session.sessionId, true, sessionRuntime);
9533
+ return;
9534
+ }
9535
+ const configOptions = await this.configOptionsFor(
9536
+ session.sessionId,
9537
+ sessionRuntime.bridge
9538
+ );
9539
+ try {
9540
+ assertGenerationOpen?.();
9541
+ } catch (error2) {
9542
+ await rollbackSession();
9543
+ throw error2;
9544
+ }
9545
+ if (conn.destroyed) {
9546
+ this.killOrphanSession(session.sessionId, true, sessionRuntime);
9547
+ return;
9548
+ }
9549
+ conn.getOrCreateSession(session.sessionId).clientId = session.clientId;
9550
+ conn.ownSession(session.sessionId);
9551
+ const models = this.extractModelState(configOptions);
9552
+ const modes = this.extractModeState(configOptions);
9553
+ this.replyConn(conn, id, {
9554
+ sessionId: session.sessionId,
9555
+ ...session.sourceType ? { sourceType: session.sourceType } : {},
9556
+ ...session.sourceId !== void 0 ? { sourceId: session.sourceId } : {},
9557
+ ...session.sourcePersisted !== void 0 ? { sourcePersisted: session.sourcePersisted } : {},
9558
+ ...configOptions ? { configOptions } : {},
9559
+ ...models ? { models } : {},
9560
+ ...modes ? { modes } : {}
9561
+ });
9017
9562
  return;
9563
+ } finally {
9564
+ reservation?.release();
9018
9565
  }
9019
- const models = this.extractModelState(configOptions);
9020
- const modes = this.extractModeState(configOptions);
9021
- this.replyConn(conn, id, {
9022
- sessionId: session.sessionId,
9023
- ...session.sourceType ? { sourceType: session.sourceType } : {},
9024
- ...session.sourceId !== void 0 ? { sourceId: session.sourceId } : {},
9025
- ...session.sourcePersisted !== void 0 ? { sourcePersisted: session.sourcePersisted } : {},
9026
- ...configOptions ? { configOptions } : {},
9027
- ...models ? { models } : {},
9028
- ...modes ? { modes } : {}
9029
- });
9030
- return;
9031
9566
  }
9032
9567
  case "session/load":
9033
9568
  case "session/resume": {
9034
- const sessionId = String(params["sessionId"] ?? "");
9569
+ const sessionId = normalizeSessionIdForLookup(
9570
+ String(params["sessionId"] ?? "")
9571
+ );
9035
9572
  if (!sessionId) {
9036
9573
  if (id !== void 0) {
9037
9574
  conn.sendConn(
@@ -9053,134 +9590,183 @@ var AcpDispatcher = class {
9053
9590
  return;
9054
9591
  }
9055
9592
  const cwd = this.parseSessionWorkspaceCwd(params);
9056
- const restored = await this.archiveCoordinator.runSharedMany(
9057
- [sessionId],
9058
- async () => {
9059
- await assertSessionLoadable(cwd, sessionId);
9060
- const sessionService = new SessionService(cwd);
9061
- const metadata = this.liveSessionIsolation ? await readLoadableLiveConversationMetadata(
9062
- sessionId,
9063
- (candidateId) => sessionService.readCreationMetadata(candidateId)
9064
- ) : await sessionService.readCreationMetadata(sessionId);
9065
- if (metadata === void 0) {
9066
- throw new SessionNotFoundError(sessionId);
9067
- }
9068
- const liveConversationCwd = this.liveSessionIsolation ? await this.liveSessionIsolation.materializeConversationDirectory(
9069
- sessionId
9070
- ) : void 0;
9071
- const session = method === "session/load" ? await this.bridge.loadSession({
9072
- sessionId,
9073
- workspaceCwd: cwd,
9074
- clientId: conn.clientId,
9075
- historyReplay: "response",
9076
- ...metadata
9077
- }) : await this.bridge.resumeSession({
9078
- sessionId,
9079
- workspaceCwd: cwd,
9080
- clientId: conn.clientId,
9081
- ...metadata
9082
- });
9083
- if (liveConversationCwd === void 0) {
9084
- return session;
9085
- }
9086
- if (session.hasActivePrompt) {
9087
- if (session.currentCwd === liveConversationCwd) return session;
9088
- try {
9089
- if (session.clientId) {
9090
- await this.bridge.detachClient(
9091
- session.sessionId,
9092
- session.clientId
9093
- );
9094
- }
9095
- } catch {
9096
- }
9097
- throw new Error(
9098
- "Active Live session is outside its isolated conversation directory."
9593
+ const sessionRuntime = this.getSessionRuntimeContext();
9594
+ const reservation = this.requestedSessionIdAdmission.reserveRestore(
9595
+ sessionId,
9596
+ {
9597
+ bridge: sessionRuntime.bridge,
9598
+ workspaceCwd: cwd,
9599
+ ...sessionRuntime.workspaceId ? { workspaceId: sessionRuntime.workspaceId } : {}
9600
+ }
9601
+ );
9602
+ try {
9603
+ const restored = await this.archiveCoordinator.runSharedMany(
9604
+ [sessionId],
9605
+ async () => {
9606
+ assertGenerationOpen?.();
9607
+ await assertSessionLoadable(
9608
+ cwd,
9609
+ sessionId,
9610
+ sessionRuntime.sessionRuntimeBaseDir
9099
9611
  );
9100
- }
9101
- try {
9102
- const changed = await this.bridge.changeSessionCwd(sessionId, {
9103
- path: liveConversationCwd,
9104
- allowedRoots: [cwd],
9105
- managedRelocation: "live-conversation"
9612
+ const sessionService = new SessionService(cwd, {
9613
+ runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
9614
+ });
9615
+ const metadata = this.liveSessionIsolation ? await readLoadableLiveConversationMetadata(
9616
+ sessionId,
9617
+ (candidateId) => sessionService.readCreationMetadata(candidateId)
9618
+ ) : await sessionService.readCreationMetadata(sessionId);
9619
+ if (metadata === void 0) {
9620
+ throw new SessionNotFoundError(sessionId);
9621
+ }
9622
+ const liveConversationCwd = this.liveSessionIsolation ? await this.liveSessionIsolation.materializeConversationDirectory(
9623
+ sessionId
9624
+ ) : void 0;
9625
+ assertGenerationOpen?.();
9626
+ const session = method === "session/load" ? await sessionRuntime.bridge.loadSession({
9627
+ sessionId,
9628
+ workspaceCwd: cwd,
9629
+ clientId: conn.clientId,
9630
+ historyReplay: "response",
9631
+ ...metadata
9632
+ }) : await sessionRuntime.bridge.resumeSession({
9633
+ sessionId,
9634
+ workspaceCwd: cwd,
9635
+ clientId: conn.clientId,
9636
+ ...metadata
9106
9637
  });
9107
- if (changed.newCwd !== liveConversationCwd) {
9638
+ if (liveConversationCwd === void 0) {
9639
+ return session;
9640
+ }
9641
+ if (session.hasActivePrompt) {
9642
+ if (session.currentCwd === liveConversationCwd)
9643
+ return session;
9644
+ try {
9645
+ if (session.clientId) {
9646
+ await sessionRuntime.bridge.detachClient(
9647
+ session.sessionId,
9648
+ session.clientId
9649
+ );
9650
+ }
9651
+ } catch {
9652
+ }
9108
9653
  throw new Error(
9109
- "Live conversation directory relocation was rejected."
9654
+ "Active Live session is outside its isolated conversation directory."
9110
9655
  );
9111
9656
  }
9112
- session.currentCwd = changed.newCwd;
9113
- } catch (error2) {
9114
9657
  try {
9115
- if (session.attached && session.clientId) {
9116
- await this.bridge.detachClient(
9117
- session.sessionId,
9118
- session.clientId
9658
+ const changed = await sessionRuntime.bridge.changeSessionCwd(
9659
+ sessionId,
9660
+ {
9661
+ path: liveConversationCwd,
9662
+ allowedRoots: [cwd],
9663
+ managedRelocation: "live-conversation"
9664
+ }
9665
+ );
9666
+ if (changed.newCwd !== liveConversationCwd) {
9667
+ throw new Error(
9668
+ "Live conversation directory relocation was rejected."
9119
9669
  );
9120
- } else if (!session.attached) {
9121
- await this.bridge.killSession(session.sessionId, {
9122
- requireZeroAttaches: true
9123
- });
9124
9670
  }
9125
- } catch {
9671
+ session.currentCwd = changed.newCwd;
9672
+ } catch (error2) {
9673
+ try {
9674
+ if (session.attached && session.clientId) {
9675
+ await sessionRuntime.bridge.detachClient(
9676
+ session.sessionId,
9677
+ session.clientId
9678
+ );
9679
+ } else if (!session.attached) {
9680
+ await sessionRuntime.bridge.killSession(
9681
+ session.sessionId,
9682
+ {
9683
+ requireZeroAttaches: true
9684
+ }
9685
+ );
9686
+ }
9687
+ } catch {
9688
+ }
9689
+ throw error2;
9126
9690
  }
9127
- throw error2;
9691
+ return session;
9692
+ }
9693
+ );
9694
+ const rollbackRestore = /* @__PURE__ */ __name(async () => {
9695
+ if (restored.attached) {
9696
+ await sessionRuntime.bridge.detachClient(sessionId, restored.clientId).catch(() => {
9697
+ });
9698
+ } else {
9699
+ await sessionRuntime.bridge.killSession(sessionId, { requireZeroAttaches: true }).catch(() => {
9700
+ });
9128
9701
  }
9129
- return session;
9702
+ }, "rollbackRestore");
9703
+ try {
9704
+ assertGenerationOpen?.();
9705
+ } catch (error2) {
9706
+ await rollbackRestore();
9707
+ throw error2;
9130
9708
  }
9131
- );
9132
- const closeRaced = conn.closingSessions.has(sessionId);
9133
- if (conn.destroyed || closeRaced) {
9134
- const cleanup = restored.attached ? this.bridge.detachClient(sessionId, restored.clientId) : this.bridge.killSession(sessionId, {
9135
- requireZeroAttaches: true
9136
- });
9137
- void cleanup.catch(
9138
- (err) => writeStderrLine(
9139
- `qwen serve: /acp orphan ${restored.attached ? "detach" : "kill"}(${logSafe(sessionId)}) teardown-race: ${logSafe(errMsg(err))}`
9140
- )
9709
+ const loadConfigOptions = await this.configOptionsFor(
9710
+ sessionId,
9711
+ sessionRuntime.bridge
9141
9712
  );
9142
- if (closeRaced && !conn.destroyed && id !== void 0) {
9143
- conn.sendConn(
9144
- error(
9145
- id,
9146
- RPC.INTERNAL_ERROR,
9147
- `session ${sessionId} was closed during load; retry`
9713
+ const loadModels = this.extractModelState(loadConfigOptions);
9714
+ const loadModes = this.extractModeState(loadConfigOptions);
9715
+ const loadState = restored.state ?? {};
9716
+ const loadMeta = isObject(loadState._meta) ? loadState._meta : void 0;
9717
+ const loadQwenMeta = isObject(loadMeta?.[QWEN_META_KEY]) ? loadMeta[QWEN_META_KEY] : void 0;
9718
+ const replayStatus = method === "session/load" && restored.partial === true ? {
9719
+ partial: true,
9720
+ ...typeof restored.replayError === "string" ? { replayError: restored.replayError } : {}
9721
+ } : void 0;
9722
+ try {
9723
+ assertGenerationOpen?.();
9724
+ } catch (error2) {
9725
+ await rollbackRestore();
9726
+ throw error2;
9727
+ }
9728
+ const closeRaced = conn.closingSessions.has(sessionId);
9729
+ if (conn.destroyed || closeRaced) {
9730
+ void rollbackRestore().catch(
9731
+ (err) => writeStderrLine(
9732
+ `qwen serve: /acp orphan ${restored.attached ? "detach" : "kill"}(${logSafe(sessionId)}) teardown-race: ${logSafe(errMsg(err))}`
9148
9733
  )
9149
9734
  );
9735
+ if (closeRaced && !conn.destroyed && id !== void 0) {
9736
+ conn.sendConn(
9737
+ error(
9738
+ id,
9739
+ RPC.INTERNAL_ERROR,
9740
+ `session ${sessionId} was closed during load; retry`
9741
+ )
9742
+ );
9743
+ }
9744
+ return;
9150
9745
  }
9746
+ conn.getOrCreateSession(sessionId).clientId = restored.clientId;
9747
+ if (method === "session/load") {
9748
+ conn.markInitialReplayPending(sessionId);
9749
+ }
9750
+ conn.ownSession(sessionId);
9751
+ this.replyConn(conn, id, {
9752
+ ...loadState,
9753
+ ...replayStatus ? {
9754
+ _meta: {
9755
+ ...loadMeta ?? {},
9756
+ [QWEN_META_KEY]: {
9757
+ ...loadQwenMeta ?? {},
9758
+ sessionLoadReplay: replayStatus
9759
+ }
9760
+ }
9761
+ } : {},
9762
+ ...loadConfigOptions ? { configOptions: loadConfigOptions } : {},
9763
+ ...loadModels ? { models: loadModels } : {},
9764
+ ...loadModes ? { modes: loadModes } : {}
9765
+ });
9151
9766
  return;
9767
+ } finally {
9768
+ reservation.release();
9152
9769
  }
9153
- conn.getOrCreateSession(sessionId).clientId = restored.clientId;
9154
- if (method === "session/load") {
9155
- conn.markInitialReplayPending(sessionId);
9156
- }
9157
- conn.ownSession(sessionId);
9158
- const loadConfigOptions = await this.configOptionsFor(sessionId);
9159
- const loadModels = this.extractModelState(loadConfigOptions);
9160
- const loadModes = this.extractModeState(loadConfigOptions);
9161
- const loadState = restored.state ?? {};
9162
- const loadMeta = isObject(loadState._meta) ? loadState._meta : void 0;
9163
- const loadQwenMeta = isObject(loadMeta?.[QWEN_META_KEY]) ? loadMeta[QWEN_META_KEY] : void 0;
9164
- const replayStatus = method === "session/load" && restored.partial === true ? {
9165
- partial: true,
9166
- ...typeof restored.replayError === "string" ? { replayError: restored.replayError } : {}
9167
- } : void 0;
9168
- this.replyConn(conn, id, {
9169
- ...loadState,
9170
- ...replayStatus ? {
9171
- _meta: {
9172
- ...loadMeta ?? {},
9173
- [QWEN_META_KEY]: {
9174
- ...loadQwenMeta ?? {},
9175
- sessionLoadReplay: replayStatus
9176
- }
9177
- }
9178
- } : {},
9179
- ...loadConfigOptions ? { configOptions: loadConfigOptions } : {},
9180
- ...loadModels ? { models: loadModels } : {},
9181
- ...loadModes ? { modes: loadModes } : {}
9182
- });
9183
- return;
9184
9770
  }
9185
9771
  case "session/list": {
9186
9772
  const workspaceCwd = this.parseBoundWorkspaceParam(params);
@@ -13765,7 +14351,7 @@ function isActiveDrainCorrelation(registry, conn, message) {
13765
14351
  return false;
13766
14352
  }
13767
14353
  const params = message.params !== null && typeof message.params === "object" ? message.params : void 0;
13768
- return typeof params?.sessionId === "string" && conn.ownsSession(params.sessionId);
14354
+ return typeof params?.sessionId === "string" && conn.ownsSession(normalizeSessionIdForLookup(params.sessionId));
13769
14355
  }
13770
14356
  __name(isActiveDrainCorrelation, "isActiveDrainCorrelation");
13771
14357
  var PLURAL_WS_PREFIX = "/workspaces/";
@@ -13942,6 +14528,9 @@ function mountAcpHttp(app, bridge, opts) {
13942
14528
  const enabled = opts.enabled ?? resolveAcpHttpEnabled();
13943
14529
  if (!enabled) return void 0;
13944
14530
  const daemonEnv = opts.daemonEnv ?? process.env;
14531
+ const primarySessionRuntimeBaseDir = opts.workspaceRegistry?.primary.sessionRuntimeBaseDir ?? Storage.getRuntimeBaseDir();
14532
+ const archiveCoordinator = opts.archiveCoordinator ?? new SessionArchiveCoordinator();
14533
+ const requestedSessionIdAdmission = opts.requestedSessionIdAdmission;
13945
14534
  const getPrimaryEnv = /* @__PURE__ */ __name(() => opts.workspaceRegistry ? runtimeEffectiveEnv(opts.workspaceRegistry.primary, daemonEnv) : daemonEnv, "getPrimaryEnv");
13946
14535
  const path15 = opts.path ?? "/acp";
13947
14536
  const dispatcherRef = {};
@@ -14095,11 +14684,12 @@ function mountAcpHttp(app, bridge, opts) {
14095
14684
  getPrimaryEnv,
14096
14685
  opts.workspace,
14097
14686
  opts.workspaceRememberLane,
14687
+ requestedSessionIdAdmission,
14098
14688
  opts.fsFactory,
14099
14689
  opts.deviceFlowRegistry,
14100
14690
  opts.sessionShellCommandEnabled === true,
14101
14691
  registry,
14102
- opts.archiveCoordinator ?? new SessionArchiveCoordinator(),
14692
+ archiveCoordinator,
14103
14693
  opts.isPrimaryWorkspaceTrusted ?? (() => {
14104
14694
  const entry = opts.workspaceRegistry?.primaryEntry;
14105
14695
  return entry ? entry.state === "active" && entry.current?.runtime.trusted === true : true;
@@ -14109,7 +14699,18 @@ function mountAcpHttp(app, bridge, opts) {
14109
14699
  return guard ? () => guard.assertOpen() : void 0;
14110
14700
  },
14111
14701
  void 0,
14112
- opts.workspaceRegistry?.primary.sessionRuntimeBaseDir ?? Storage.getRuntimeBaseDir()
14702
+ primarySessionRuntimeBaseDir,
14703
+ () => {
14704
+ const runtime = opts.workspaceRegistry?.primary;
14705
+ return runtime ? {
14706
+ bridge: runtime.bridge,
14707
+ sessionRuntimeBaseDir: runtime.sessionRuntimeBaseDir,
14708
+ workspaceId: runtime.workspaceId
14709
+ } : {
14710
+ bridge,
14711
+ sessionRuntimeBaseDir: primarySessionRuntimeBaseDir
14712
+ };
14713
+ }
14113
14714
  );
14114
14715
  dispatcherRef.current = dispatcher;
14115
14716
  const primaryMount = {
@@ -14289,7 +14890,8 @@ function mountAcpHttp(app, bridge, opts) {
14289
14890
  res.status(404).json({ error: "Unknown Acp-Connection-Id" });
14290
14891
  return;
14291
14892
  }
14292
- const sessionId = headerOf(req, ACP_SESSION_HEADER);
14893
+ const rawSessionId = headerOf(req, ACP_SESSION_HEADER);
14894
+ const sessionId = rawSessionId ? normalizeSessionIdForLookup(rawSessionId) : void 0;
14293
14895
  if (!sessionId) {
14294
14896
  const connId = conn.connectionId;
14295
14897
  const stream2 = new SseStream(
@@ -14396,12 +14998,17 @@ function mountAcpHttp(app, bridge, opts) {
14396
14998
  rt.bridge,
14397
14999
  rt.workspaceCwd
14398
15000
  );
15001
+ const registeredGeneration = opts.workspaceRegistry?.getEntryByWorkspaceId(
15002
+ rt.workspaceId
15003
+ )?.current;
15004
+ const generationGuard = registeredGeneration?.runtime === rt ? registeredGeneration.guard : rt.generationGuard;
14399
15005
  const secondaryDispatcher = new AcpDispatcher(
14400
15006
  rt.bridge,
14401
15007
  rt.workspaceCwd,
14402
15008
  () => runtimeEffectiveEnv(rt, daemonEnv),
14403
15009
  rt.workspaceService,
14404
15010
  workspaceRememberLane,
15011
+ requestedSessionIdAdmission,
14405
15012
  rt.routeFileSystemFactory,
14406
15013
  // Phase 4: secondary mounts share the daemon-global device-flow registry
14407
15014
  // (single instance per daemon; OAuth credentials are global state). The
@@ -14411,14 +15018,16 @@ function mountAcpHttp(app, bridge, opts) {
14411
15018
  opts.deviceFlowRegistry,
14412
15019
  opts.sessionShellCommandEnabled === true,
14413
15020
  secondaryRegistry,
14414
- opts.archiveCoordinator ?? new SessionArchiveCoordinator(),
15021
+ archiveCoordinator,
14415
15022
  () => rt.trusted,
14416
- () => {
14417
- const guard = rt.generationGuard;
14418
- return guard ? () => guard.assertOpen() : void 0;
14419
- },
15023
+ () => generationGuard ? () => generationGuard.assertOpen() : void 0,
14420
15024
  rt.provenance === "live-conversation" ? opts.liveSessionIsolation : void 0,
14421
- rt.sessionRuntimeBaseDir
15025
+ rt.sessionRuntimeBaseDir,
15026
+ () => ({
15027
+ bridge: rt.bridge,
15028
+ sessionRuntimeBaseDir: rt.sessionRuntimeBaseDir,
15029
+ workspaceId: rt.workspaceId
15030
+ })
14422
15031
  );
14423
15032
  secondaryDispatcherRef.current = secondaryDispatcher;
14424
15033
  return {
@@ -15056,7 +15665,8 @@ function mountAcpHttp(app, bridge, opts) {
15056
15665
  return;
15057
15666
  }
15058
15667
  if (isRequest(message) && message.params && typeof message.params === "object") {
15059
- const sid = message.params["sessionId"];
15668
+ const rawSid = message.params["sessionId"];
15669
+ const sid = typeof rawSid === "string" ? normalizeSessionIdForLookup(rawSid) : rawSid;
15060
15670
  if (typeof sid === "string" && conn.ownsSession(sid)) {
15061
15671
  const binding = conn.sessions.get(sid);
15062
15672
  if (binding && !binding.stream && conn.connStream && !conn.connStream.isClosed) {
@@ -15955,667 +16565,10 @@ function registerDaemonStatusRoutes(app, deps) {
15955
16565
  }
15956
16566
  __name(registerDaemonStatusRoutes, "registerDaemonStatusRoutes");
15957
16567
 
15958
- // packages/cli/src/serve/routes/health-demo.ts
15959
- init_esbuild_shims();
15960
-
15961
- // packages/cli/src/serve/demo.ts
16568
+ // packages/cli/src/serve/routes/health.ts
15962
16569
  init_esbuild_shims();
15963
- function getDemoHtml(_port) {
15964
- return (
15965
- /* html */
15966
- `<!DOCTYPE html>
15967
- <html lang="en">
15968
- <head>
15969
- <meta charset="utf-8" />
15970
- <meta name="viewport" content="width=device-width, initial-scale=1" />
15971
- <title>Qwen Serve Demo</title>
15972
- <style>
15973
- :root { --bg: #1a1a2e; --surface: #16213e; --border: #0f3460; --accent: #e94560; --text: #eee; --text2: #aab; --ok: #4ade80; --warn: #fbbf24; --err: #f87171; }
15974
- * { box-sizing: border-box; margin: 0; padding: 0; }
15975
- body { font-family: 'SF Mono', 'Menlo', 'Consolas', monospace; font-size: 13px; background: var(--bg); color: var(--text); min-height: 100vh; }
15976
- .header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 12px 20px; display: flex; align-items: center; gap: 12px; }
15977
- .header h1 { font-size: 16px; font-weight: 600; }
15978
- .header .badge { font-size: 11px; background: var(--accent); color: #fff; padding: 2px 8px; border-radius: 10px; }
15979
- .header .status { margin-left: auto; display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text2); }
15980
- .header .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--err); }
15981
- .header .dot.ok { background: var(--ok); }
15982
- .container { display: grid; grid-template-columns: 340px 1fr; height: calc(100vh - 49px); }
15983
- .sidebar { background: var(--surface); border-right: 1px solid var(--border); overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 12px; }
15984
- .panel { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 12px; }
15985
- .panel h3 { font-size: 12px; color: var(--accent); margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; }
15986
- .panel label { display: block; font-size: 11px; color: var(--text2); margin-bottom: 3px; }
15987
- .panel input, .panel textarea { width: 100%; background: var(--surface); border: 1px solid var(--border); color: var(--text); padding: 6px 8px; border-radius: 4px; font-family: inherit; font-size: 12px; margin-bottom: 8px; }
15988
- .panel input:focus, .panel textarea:focus { outline: none; border-color: var(--accent); }
15989
- .panel textarea { resize: vertical; min-height: 60px; }
15990
- .btn { display: inline-flex; align-items: center; gap: 4px; padding: 6px 14px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--text); font-family: inherit; font-size: 12px; cursor: pointer; transition: all 0.15s; }
15991
- .btn:hover { border-color: var(--accent); color: var(--accent); }
15992
- .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
15993
- .btn.primary:hover { opacity: 0.85; }
15994
- .btn:disabled { opacity: 0.4; cursor: not-allowed; }
15995
- .btn-row { display: flex; gap: 6px; flex-wrap: wrap; }
15996
- .main { display: flex; flex-direction: column; overflow: hidden; }
15997
- .tabs { display: flex; background: var(--surface); border-bottom: 1px solid var(--border); }
15998
- .tab { padding: 8px 16px; font-size: 12px; color: var(--text2); cursor: pointer; border-bottom: 2px solid transparent; }
15999
- .tab.active { color: var(--accent); border-bottom-color: var(--accent); }
16000
- .tab-content { flex: 1; overflow: hidden; display: none; flex-direction: column; }
16001
- .tab-content.active { display: flex; }
16002
- .log { flex: 1; overflow-y: auto; padding: 12px; font-size: 12px; line-height: 1.6; }
16003
- .log-entry { padding: 3px 0; border-bottom: 1px solid rgba(255,255,255,0.03); word-break: break-all; }
16004
- .log-entry .ts { color: var(--text2); margin-right: 8px; font-size: 11px; }
16005
- .log-entry .tag { display: inline-block; padding: 0 5px; border-radius: 3px; font-size: 10px; margin-right: 6px; }
16006
- .tag-info { background: #1e40af; color: #93c5fd; }
16007
- .tag-event { background: #065f46; color: #6ee7b7; }
16008
- .tag-error { background: #7f1d1d; color: #fca5a5; }
16009
- .tag-response { background: #713f12; color: #fde68a; }
16010
- .tag-thought { background: #4c1d95; color: #c4b5fd; }
16011
- .tag-message { background: #164e63; color: #67e8f9; }
16012
- .chat { flex: 1; overflow-y: auto; padding: 16px; }
16013
- .chat-msg { margin-bottom: 12px; max-width: 85%; }
16014
- .chat-msg.user { margin-left: auto; }
16015
- .chat-msg .bubble { padding: 8px 12px; border-radius: 8px; line-height: 1.5; white-space: pre-wrap; }
16016
- .chat-msg.user .bubble { background: var(--accent); color: #fff; border-bottom-right-radius: 2px; }
16017
- .chat-msg.assistant .bubble { background: var(--surface); border: 1px solid var(--border); border-bottom-left-radius: 2px; }
16018
- .chat-msg .meta { font-size: 10px; color: var(--text2); margin-top: 3px; }
16019
- .chat-input { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--border); background: var(--surface); }
16020
- .chat-input input { flex: 1; }
16021
- .session-info { font-size: 11px; color: var(--text2); padding: 4px 0; }
16022
- .session-info span { color: var(--ok); }
16023
- .empty-hint { color: var(--text2); text-align: center; padding: 40px 20px; font-size: 12px; }
16024
- .permission-card { background: var(--surface); border: 1px solid var(--warn); border-radius: 6px; padding: 10px 12px; margin: 8px 0; }
16025
- .permission-card h4 { color: var(--warn); font-size: 12px; margin-bottom: 6px; }
16026
- .permission-card .opt-btn { margin-right: 4px; margin-top: 4px; }
16027
- </style>
16028
- </head>
16029
- <body>
16030
-
16031
- <div class="header">
16032
- <h1>Qwen Serve</h1>
16033
- <span class="badge">Demo</span>
16034
- <div class="status">
16035
- <span class="dot" id="statusDot"></span>
16036
- <span id="statusText">Connecting...</span>
16037
- </div>
16038
- </div>
16039
-
16040
- <div class="container">
16041
- <div class="sidebar">
16042
- <div class="panel">
16043
- <h3>Session</h3>
16044
- <label>Working Directory (cwd)</label>
16045
- <input type="text" id="cwdInput" placeholder="/path/to/project" />
16046
- <div class="btn-row">
16047
- <button class="btn primary" id="btnCreateSession">Create / Attach</button>
16048
- <button class="btn" id="btnListSessions">List</button>
16049
- </div>
16050
- <div class="session-info" id="sessionInfo" style="display:none">
16051
- Session: <span id="sessionIdDisplay"></span>
16052
- </div>
16053
- </div>
16054
-
16055
- <div class="panel">
16056
- <h3>Prompt</h3>
16057
- <textarea id="promptInput" placeholder="Type your prompt here..."></textarea>
16058
- <div class="btn-row">
16059
- <button class="btn primary" id="btnSendPrompt" disabled>Send</button>
16060
- <button class="btn" id="btnCancel" disabled>Cancel</button>
16061
- </div>
16062
- </div>
16063
-
16064
- <div class="panel">
16065
- <h3>Model</h3>
16066
- <input type="text" id="modelInput" placeholder="Model ID (e.g. qwen3-coder)" />
16067
- <button class="btn" id="btnSetModel" disabled>Switch Model</button>
16068
- </div>
16069
-
16070
- <div class="panel">
16071
- <h3>Auth Token</h3>
16072
- <label>Bearer Token (if --token is set)</label>
16073
- <input type="password" id="tokenInput" placeholder="Optional bearer token" />
16074
- </div>
16075
-
16076
- <div class="panel">
16077
- <h3>Quick Actions</h3>
16078
- <div class="btn-row">
16079
- <button class="btn" id="btnHealth">Health</button>
16080
- <button class="btn" id="btnHealthDeep">Health (deep)</button>
16081
- <button class="btn" id="btnCaps">Capabilities</button>
16082
- </div>
16083
- </div>
16084
-
16085
- <div class="panel" id="permissionPanel" style="display:none">
16086
- <h3>Pending Permissions</h3>
16087
- <div id="permissionList"></div>
16088
- </div>
16089
- </div>
16090
-
16091
- <div class="main">
16092
- <div class="tabs">
16093
- <div class="tab active" data-tab="chat">Chat</div>
16094
- <div class="tab" data-tab="events">Events</div>
16095
- <div class="tab" data-tab="requests">API Log</div>
16096
- </div>
16097
-
16098
- <div class="tab-content active" id="tab-chat">
16099
- <div class="chat" id="chatArea">
16100
- <div class="empty-hint">Create a session to start chatting</div>
16101
- </div>
16102
- <div class="chat-input">
16103
- <input type="text" id="chatInput" placeholder="Send a message..." disabled />
16104
- <button class="btn primary" id="btnChatSend" disabled>Send</button>
16105
- </div>
16106
- </div>
16107
-
16108
- <div class="tab-content" id="tab-events">
16109
- <div class="log" id="eventLog"></div>
16110
- </div>
16111
-
16112
- <div class="tab-content" id="tab-requests">
16113
- <div class="log" id="requestLog"></div>
16114
- </div>
16115
- </div>
16116
- </div>
16117
-
16118
- <script>
16119
- (function() {
16120
- const BASE = '';
16121
- let sessionId = null;
16122
- let eventSource = null;
16123
- let currentAssistantBubble = null;
16124
- let currentThought = '';
16125
-
16126
- // --- DOM refs ---
16127
- const $ = (s) => document.querySelector(s);
16128
- const statusDot = $('#statusDot');
16129
- const statusText = $('#statusText');
16130
- const cwdInput = $('#cwdInput');
16131
- const promptInput = $('#promptInput');
16132
- const modelInput = $('#modelInput');
16133
- const tokenInput = $('#tokenInput');
16134
- const chatArea = $('#chatArea');
16135
- const chatInput = $('#chatInput');
16136
- const eventLog = $('#eventLog');
16137
- const requestLog = $('#requestLog');
16138
- const sessionInfo = $('#sessionInfo');
16139
- const sessionIdDisplay = $('#sessionIdDisplay');
16140
- const permissionPanel = $('#permissionPanel');
16141
- const permissionList = $('#permissionList');
16142
-
16143
- // --- Tabs ---
16144
- document.querySelectorAll('.tab').forEach(tab => {
16145
- tab.addEventListener('click', () => {
16146
- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
16147
- document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
16148
- tab.classList.add('active');
16149
- $('#tab-' + tab.dataset.tab).classList.add('active');
16150
- });
16151
- });
16152
-
16153
- // --- Logging ---
16154
- function ts() {
16155
- return new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
16156
- }
16157
- const MAX_LOG_ENTRIES = 500;
16158
- function addLog(container, tag, tagClass, msg) {
16159
- const el = document.createElement('div');
16160
- el.className = 'log-entry';
16161
- const text = typeof msg === 'object' ? JSON.stringify(msg, null, 2) : msg;
16162
- const tsSpan = document.createElement('span');
16163
- tsSpan.className = 'ts';
16164
- tsSpan.textContent = ts();
16165
- const tagSpan = document.createElement('span');
16166
- tagSpan.className = 'tag ' + tagClass;
16167
- tagSpan.textContent = tag;
16168
- el.appendChild(tsSpan);
16169
- el.appendChild(tagSpan);
16170
- el.appendChild(document.createTextNode(text));
16171
- container.appendChild(el);
16172
- while (container.children.length > MAX_LOG_ENTRIES) {
16173
- container.removeChild(container.firstChild);
16174
- }
16175
- container.scrollTop = container.scrollHeight;
16176
- }
16177
- function logEvent(tag, msg) { addLog(eventLog, tag, 'tag-event', msg); }
16178
- function logRequest(tag, msg) { addLog(requestLog, tag, 'tag-info', msg); }
16179
- function logResponse(tag, msg) { addLog(requestLog, tag, 'tag-response', msg); }
16180
- function logError(tag, msg) { addLog(requestLog, tag, 'tag-error', msg); }
16181
-
16182
- function escHtml(s) {
16183
- const d = document.createElement('div');
16184
- d.textContent = String(s);
16185
- return d.innerHTML;
16186
- }
16187
-
16188
- // --- 401 token hint ---
16189
- let tokenHintTimer = null;
16190
- function highlightTokenInput(msg) {
16191
- tokenInput.style.borderColor = 'var(--warn)';
16192
- tokenInput.focus();
16193
- // Show hint text below the input
16194
- let hint = document.getElementById('tokenHint');
16195
- if (!hint) {
16196
- hint = document.createElement('div');
16197
- hint.id = 'tokenHint';
16198
- hint.style.cssText = 'font-size:11px;color:var(--warn);margin-top:-4px;margin-bottom:4px;';
16199
- tokenInput.parentNode.insertBefore(hint, tokenInput.nextSibling);
16200
- }
16201
- hint.textContent = msg;
16202
- if (tokenHintTimer) clearTimeout(tokenHintTimer);
16203
- tokenHintTimer = setTimeout(() => {
16204
- tokenInput.style.borderColor = '';
16205
- hint.textContent = '';
16206
- }, 6000);
16207
- }
16208
-
16209
- // --- API helpers ---
16210
- function authHeaders() {
16211
- const token = tokenInput.value.trim();
16212
- return token ? { 'Authorization': 'Bearer ' + token } : {};
16213
- }
16214
-
16215
- async function api(method, path, body) {
16216
- const opts = { method, headers: { ...authHeaders() } };
16217
- if (body !== undefined) {
16218
- opts.headers['Content-Type'] = 'application/json';
16219
- opts.body = JSON.stringify(body);
16220
- }
16221
- logRequest(method, path + (body ? ' ' + JSON.stringify(body) : ''));
16222
- try {
16223
- const res = await fetch(BASE + path, opts);
16224
- const text = await res.text();
16225
- let data;
16226
- try { data = JSON.parse(text); } catch { data = text; }
16227
- if (!res.ok) {
16228
- logError(res.status, JSON.stringify(data));
16229
- if (res.status === 401) {
16230
- highlightTokenInput('API returned 401 \u2014 enter your bearer token below');
16231
- }
16232
- return { ok: false, status: res.status, data };
16233
- }
16234
- logResponse(res.status, JSON.stringify(data));
16235
- return { ok: true, status: res.status, data };
16236
- } catch (err) {
16237
- logError('ERR', err.message);
16238
- return { ok: false, status: 0, data: { error: err.message } };
16239
- }
16240
- }
16241
-
16242
- // --- Health check on load ---
16243
- async function checkHealth() {
16244
- const r = await api('GET', '/health');
16245
- if (r.ok) {
16246
- statusDot.classList.add('ok');
16247
- statusText.textContent = 'Connected';
16248
- } else {
16249
- statusDot.classList.remove('ok');
16250
- statusText.textContent = 'Disconnected';
16251
- }
16252
- }
16253
-
16254
- // --- Session ---
16255
- async function createSession() {
16256
- const cwd = cwdInput.value.trim();
16257
- if (!cwd) { alert('Please enter a working directory'); return; }
16258
- const r = await api('POST', '/session', { cwd });
16259
- if (r.ok) {
16260
- sessionId = r.data.sessionId;
16261
- sessionInfo.style.display = 'block';
16262
- sessionIdDisplay.textContent = sessionId;
16263
- enablePrompt(true);
16264
- chatArea.innerHTML = '';
16265
- currentAssistantBubble = null;
16266
- pendingPerms.clear();
16267
- renderPermissions();
16268
- if (r.data.attached) {
16269
- addChatMeta('Attached to existing session');
16270
- } else {
16271
- addChatMeta('New session created');
16272
- }
16273
- connectSSE();
16274
- } else {
16275
- const msg = r.data.error || 'session creation failed (' + r.status + ')';
16276
- addChatMeta('Error: ' + msg);
16277
- if (r.status === 401) highlightTokenInput('Token required or invalid');
16278
- }
16279
- }
16280
-
16281
- function enablePrompt(on) {
16282
- $('#btnSendPrompt').disabled = !on;
16283
- $('#btnCancel').disabled = !on;
16284
- $('#btnSetModel').disabled = !on;
16285
- chatInput.disabled = !on;
16286
- $('#btnChatSend').disabled = !on;
16287
- }
16288
-
16289
- // --- SSE ---
16290
- function connectSSE() {
16291
- if (eventSource) { eventSource.close(); }
16292
- const url = BASE + '/session/' + sessionId + '/events';
16293
- logEvent('SSE', 'Connecting to ' + url);
16294
-
16295
- // Use fetch-based SSE to avoid Origin header issues with EventSource
16296
- const abort = new AbortController();
16297
- eventSource = { close: () => abort.abort() };
16298
-
16299
- (async function readSSE() {
16300
- try {
16301
- const hdrs = authHeaders();
16302
- const res = await fetch(url, { signal: abort.signal, headers: hdrs });
16303
- if (!res.ok) {
16304
- logEvent('SSE-ERR', 'HTTP ' + res.status);
16305
- statusDot.classList.remove('ok');
16306
- statusText.textContent = 'SSE failed (' + res.status + ')';
16307
- enablePrompt(false);
16308
- if (res.status === 401) {
16309
- highlightTokenInput('SSE returned 401 \u2014 enter your bearer token and recreate the session');
16310
- }
16311
- return;
16312
- }
16313
- const reader = res.body.getReader();
16314
- const decoder = new TextDecoder();
16315
- let buffer = '';
16316
- let currentEvent = {};
16317
-
16318
- while (true) {
16319
- const { done, value } = await reader.read();
16320
- if (done) break;
16321
- buffer += decoder.decode(value, { stream: true });
16322
-
16323
- const lines = buffer.split('\\n');
16324
- buffer = lines.pop();
16325
-
16326
- for (const line of lines) {
16327
- if (line.startsWith('data: ')) {
16328
- currentEvent.data = line.slice(6);
16329
- } else if (line.startsWith('event: ')) {
16330
- currentEvent.event = line.slice(7);
16331
- } else if (line.startsWith('id: ')) {
16332
- currentEvent.id = line.slice(4);
16333
- } else if (line === '') {
16334
- if (currentEvent.data) {
16335
- handleSSEMessage(currentEvent);
16336
- }
16337
- currentEvent = {};
16338
- }
16339
- }
16340
- }
16341
- // Process any remaining buffered data
16342
- if (currentEvent.data) handleSSEMessage(currentEvent);
16343
- statusDot.classList.remove('ok');
16344
- statusText.textContent = 'SSE stream ended';
16345
- enablePrompt(false);
16346
- logEvent('SSE', 'Stream ended by server');
16347
- } catch (err) {
16348
- if (err.name !== 'AbortError') {
16349
- logEvent('SSE-ERR', err.message);
16350
- statusDot.classList.remove('ok');
16351
- statusText.textContent = 'SSE error';
16352
- enablePrompt(false);
16353
- }
16354
- }
16355
- })();
16356
- }
16357
-
16358
- function handleSSEMessage(msg) {
16359
- let data;
16360
- try { data = JSON.parse(msg.data); } catch { data = msg.data; }
16361
- const type = data.type || msg.event || 'unknown';
16362
-
16363
- if (type === 'session_update' && data.data) {
16364
- const update = data.data.update || data.data;
16365
- const kind = update.sessionUpdate;
16366
-
16367
- if (kind === 'agent_message_chunk') {
16368
- const text = update.content?.text || '';
16369
- if (text) appendAssistantChunk(text);
16370
- if (update._meta?.usage) {
16371
- const u = update._meta.usage;
16372
- addChatMeta('tokens: in=' + u.inputTokens + ' out=' + u.outputTokens + ' | ' + (update._meta.durationMs || 0) + 'ms');
16373
- currentAssistantBubble = null;
16374
- }
16375
- logEvent('MSG', text || '(usage meta)');
16376
- } else if (kind === 'agent_thought_chunk') {
16377
- const text = update.content?.text || '';
16378
- currentThought += text;
16379
- logEvent('THINK', text);
16380
- } else {
16381
- logEvent(kind || type, JSON.stringify(update));
16382
- }
16383
- } else if (type === 'permission_request') {
16384
- handlePermissionRequest(data);
16385
- logEvent('PERM', JSON.stringify(data.data));
16386
- } else if (type === 'permission_resolved') {
16387
- logEvent('PERM-OK', JSON.stringify(data.data));
16388
- removePermission(data.data?.requestId);
16389
- } else if (type === 'session_died') {
16390
- addChatMeta('Session died: ' + JSON.stringify(data.data));
16391
- logEvent('DIED', JSON.stringify(data.data));
16392
- enablePrompt(false);
16393
- } else if (type === 'model_switched') {
16394
- addChatMeta('Model switched: ' + JSON.stringify(data.data));
16395
- logEvent('MODEL', JSON.stringify(data.data));
16396
- } else {
16397
- logEvent(type, JSON.stringify(data));
16398
- }
16399
- }
16400
-
16401
- // --- Chat UI ---
16402
- function addUserMessage(text) {
16403
- currentAssistantBubble = null;
16404
- currentThought = '';
16405
- const el = document.createElement('div');
16406
- el.className = 'chat-msg user';
16407
- el.innerHTML = '<div class="bubble">' + escHtml(text) + '</div>';
16408
- chatArea.appendChild(el);
16409
- chatArea.scrollTop = chatArea.scrollHeight;
16410
- }
16411
-
16412
- function appendAssistantChunk(text) {
16413
- if (!currentAssistantBubble) {
16414
- if (currentThought) {
16415
- const te = document.createElement('div');
16416
- te.className = 'chat-msg assistant';
16417
- te.innerHTML = '<div class="bubble" style="color:var(--text2);font-style:italic;border-color:var(--border)">Thinking: ' + escHtml(currentThought) + '</div>';
16418
- chatArea.appendChild(te);
16419
- currentThought = '';
16420
- }
16421
- const el = document.createElement('div');
16422
- el.className = 'chat-msg assistant';
16423
- el.innerHTML = '<div class="bubble"></div>';
16424
- chatArea.appendChild(el);
16425
- currentAssistantBubble = el.querySelector('.bubble');
16426
- }
16427
- currentAssistantBubble.textContent += text;
16428
- chatArea.scrollTop = chatArea.scrollHeight;
16429
- }
16430
-
16431
- function addChatMeta(text) {
16432
- const el = document.createElement('div');
16433
- el.className = 'chat-msg assistant';
16434
- el.innerHTML = '<div class="meta">' + escHtml(text) + '</div>';
16435
- chatArea.appendChild(el);
16436
- chatArea.scrollTop = chatArea.scrollHeight;
16437
- }
16438
-
16439
- // --- Prompt ---
16440
- let promptInFlight = false;
16441
- async function sendPrompt(text) {
16442
- if (!sessionId || !text.trim() || promptInFlight) return;
16443
- promptInFlight = true;
16444
- enablePrompt(false);
16445
- addUserMessage(text.trim());
16446
- promptInput.value = '';
16447
- chatInput.value = '';
16448
- try {
16449
- const r = await api('POST', '/session/' + sessionId + '/prompt', {
16450
- prompt: [{ type: 'text', text: text.trim() }]
16451
- });
16452
- if (r.ok) {
16453
- addChatMeta('stopReason: ' + (r.data.stopReason || 'unknown'));
16454
- } else {
16455
- addChatMeta('Error: ' + (r.data.error || 'prompt failed (' + r.status + ')'));
16456
- }
16457
- } finally {
16458
- promptInFlight = false;
16459
- if (sessionId) enablePrompt(true);
16460
- }
16461
- }
16462
-
16463
- // --- Permission handling ---
16464
- const pendingPerms = new Map();
16465
-
16466
- function handlePermissionRequest(data) {
16467
- const req = data.data;
16468
- const requestId = req?.requestId;
16469
- if (!requestId) return;
16470
- pendingPerms.set(requestId, req);
16471
- renderPermissions();
16472
-
16473
- addChatMeta('Permission requested: ' + requestId);
16474
- }
16475
-
16476
- function removePermission(requestId) {
16477
- pendingPerms.delete(requestId);
16478
- renderPermissions();
16479
- }
16480
-
16481
- function renderPermissions() {
16482
- if (pendingPerms.size === 0) {
16483
- permissionPanel.style.display = 'none';
16484
- return;
16485
- }
16486
- permissionPanel.style.display = 'block';
16487
- permissionList.innerHTML = '';
16488
- for (const [id, req] of pendingPerms) {
16489
- const card = document.createElement('div');
16490
- card.className = 'permission-card';
16491
-
16492
- const h4 = document.createElement('h4');
16493
- h4.textContent = req.tool?.name || 'Permission';
16494
- card.appendChild(h4);
16495
-
16496
- const idDiv = document.createElement('div');
16497
- idDiv.style.cssText = 'font-size:11px;color:var(--text2);margin-bottom:6px';
16498
- idDiv.textContent = id;
16499
- card.appendChild(idDiv);
16500
-
16501
- // Show toolCall context (command, input, path, etc.) when available
16502
- const tc = req.toolCall || req.tool;
16503
- if (tc) {
16504
- const detail = document.createElement('pre');
16505
- detail.style.cssText = 'font-size:11px;color:var(--text2);margin-bottom:6px;white-space:pre-wrap;word-break:break-all;max-height:120px;overflow-y:auto;background:var(--bg);padding:6px;border-radius:4px;border:1px solid var(--border)';
16506
- const parts = [];
16507
- if (tc.command) parts.push('command: ' + tc.command);
16508
- if (tc.input) parts.push('input: ' + (typeof tc.input === 'string' ? tc.input : JSON.stringify(tc.input, null, 2)));
16509
- if (tc.path) parts.push('path: ' + tc.path);
16510
- if (tc.diff) parts.push('diff: ' + tc.diff);
16511
- if (tc.serverUrl) parts.push('url: ' + tc.serverUrl);
16512
- if (parts.length === 0 && tc.name) parts.push('tool: ' + tc.name);
16513
- if (parts.length > 0) {
16514
- detail.textContent = parts.join('\\n');
16515
- card.appendChild(detail);
16516
- }
16517
- }
16518
-
16519
- function makePermBtn(reqId, optId, label, isCancel) {
16520
- const btn = document.createElement('button');
16521
- btn.className = 'btn opt-btn';
16522
- btn.textContent = label;
16523
- btn.dataset.req = reqId;
16524
- if (isCancel) {
16525
- btn.dataset.cancel = '1';
16526
- btn.style.borderColor = 'var(--err)';
16527
- btn.style.color = 'var(--err)';
16528
- } else {
16529
- btn.dataset.opt = optId;
16530
- }
16531
- btn.addEventListener('click', async () => {
16532
- let outcome;
16533
- if (isCancel) {
16534
- outcome = { outcome: 'cancelled' };
16535
- } else {
16536
- outcome = { outcome: 'selected', optionId: optId };
16537
- }
16538
- const result = await api('POST', '/permission/' + reqId, { outcome });
16539
- if (result.ok) {
16540
- removePermission(reqId);
16541
- } else {
16542
- logError('PERM-ERR', 'Failed to resolve permission ' + reqId + ': ' + JSON.stringify(result.data));
16543
- }
16544
- });
16545
- return btn;
16546
- }
16547
-
16548
- if (req.options && Array.isArray(req.options)) {
16549
- for (const opt of req.options) {
16550
- card.appendChild(makePermBtn(id, opt.optionId, opt.name || opt.optionId, false));
16551
- }
16552
- }
16553
- card.appendChild(makePermBtn(id, null, 'Cancel', true));
16554
- permissionList.appendChild(card);
16555
- }
16556
- }
16557
-
16558
- // --- Button bindings ---
16559
- $('#btnCreateSession').addEventListener('click', createSession);
16560
- $('#btnListSessions').addEventListener('click', async () => {
16561
- const cwd = cwdInput.value.trim();
16562
- if (!cwd) { alert('Enter a cwd first'); return; }
16563
- await api('GET', '/workspace/' + encodeURIComponent(cwd) + '/sessions');
16564
- });
16565
- $('#btnSendPrompt').addEventListener('click', () => sendPrompt(promptInput.value));
16566
- $('#btnChatSend').addEventListener('click', () => sendPrompt(chatInput.value));
16567
- chatInput.addEventListener('keydown', (e) => {
16568
- if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendPrompt(chatInput.value); }
16569
- });
16570
- promptInput.addEventListener('keydown', (e) => {
16571
- if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendPrompt(promptInput.value); }
16572
- });
16573
- $('#btnCancel').addEventListener('click', async () => {
16574
- if (!sessionId) return;
16575
- await api('POST', '/session/' + sessionId + '/cancel', {});
16576
- });
16577
- $('#btnSetModel').addEventListener('click', async () => {
16578
- if (!sessionId) return;
16579
- const mid = modelInput.value.trim();
16580
- if (!mid) { alert('Enter a model ID'); return; }
16581
- await api('POST', '/session/' + sessionId + '/model', { modelId: mid });
16582
- });
16583
- $('#btnHealth').addEventListener('click', () => api('GET', '/health'));
16584
- $('#btnHealthDeep').addEventListener('click', () => api('GET', '/health?deep=1'));
16585
- $('#btnCaps').addEventListener('click', () => api('GET', '/capabilities'));
16586
-
16587
- // --- Init ---
16588
- checkHealth();
16589
- })();
16590
- </script>
16591
- </body>
16592
- </html>`
16593
- );
16594
- }
16595
- __name(getDemoHtml, "getDemoHtml");
16596
-
16597
- // packages/cli/src/serve/routes/health-demo.ts
16598
- function createHealthDemoRoutes(deps) {
16599
- const {
16600
- opts,
16601
- getPort,
16602
- workspaceRegistry,
16603
- getActiveSseCount: getActiveSseCount2,
16604
- getRateLimiter
16605
- } = deps;
16606
- const demoHandler = /* @__PURE__ */ __name((_req, res) => {
16607
- try {
16608
- res.type("html").set("X-Frame-Options", "DENY").set(
16609
- "Content-Security-Policy",
16610
- "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'"
16611
- ).send(getDemoHtml(getPort()));
16612
- } catch (err) {
16613
- writeStderrLine(
16614
- `qwen serve: /demo render failed: ${err instanceof Error ? err.message : String(err)}`
16615
- );
16616
- res.status(500).json({ error: "Failed to render demo page" });
16617
- }
16618
- }, "demoHandler");
16570
+ function createHealthRoutes(deps) {
16571
+ const { opts, workspaceRegistry, getActiveSseCount: getActiveSseCount2, getRateLimiter } = deps;
16619
16572
  const healthHandler = /* @__PURE__ */ __name((req, res) => {
16620
16573
  if (!isDeepHealthQuery(req.query["deep"])) {
16621
16574
  res.status(200).json({ status: "ok" });
@@ -16705,11 +16658,10 @@ function createHealthDemoRoutes(deps) {
16705
16658
  exposeHealthPreAuth,
16706
16659
  register(app) {
16707
16660
  app.get("/health", healthHandler);
16708
- app.get("/demo", demoHandler);
16709
16661
  }
16710
16662
  };
16711
16663
  }
16712
- __name(createHealthDemoRoutes, "createHealthDemoRoutes");
16664
+ __name(createHealthRoutes, "createHealthRoutes");
16713
16665
 
16714
16666
  // packages/cli/src/serve/routes/workspace-auth.ts
16715
16667
  init_esbuild_shims();
@@ -22430,7 +22382,6 @@ __name(createWorkspaceRuntimeSessionService, "createWorkspaceRuntimeSessionServi
22430
22382
  var GIT_RESERVED_BRANCH = "HEAD";
22431
22383
  var MAX_BRANCH_NAME_BYTES = 1e3;
22432
22384
  var MAX_BRANCH_COMPONENT_BYTES = 200;
22433
- 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;
22434
22385
  var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 2 * SESSION_TRANSCRIPT_MAX_EXPANDED_PAGE_BYTES;
22435
22386
  var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
22436
22387
  var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
@@ -22590,15 +22541,6 @@ function shouldPreserveTranscriptResolutionError(err) {
22590
22541
  return err instanceof SessionArchivedError || err instanceof SessionConflictError || err instanceof SessionNotFoundError;
22591
22542
  }
22592
22543
  __name(shouldPreserveTranscriptResolutionError, "shouldPreserveTranscriptResolutionError");
22593
- function isSessionLive(bridge, sessionId) {
22594
- try {
22595
- bridge.getSessionSummary(sessionId);
22596
- return true;
22597
- } catch (err) {
22598
- return !(err instanceof SessionNotFoundError);
22599
- }
22600
- }
22601
- __name(isSessionLive, "isSessionLive");
22602
22544
  function parseOptionalApprovalMode(body, res) {
22603
22545
  const rawApprovalMode = body["approvalMode"];
22604
22546
  if (rawApprovalMode === void 0) {
@@ -22628,12 +22570,27 @@ function registerSessionRoutes(app, deps) {
22628
22570
  sessionShellCommandEnabled,
22629
22571
  virtualSubagentSessions
22630
22572
  } = deps;
22573
+ const requestedSessionIdAdmission = deps.requestedSessionIdAdmission ?? createRequestedSessionIdAdmission({
22574
+ archiveCoordinator,
22575
+ getBridges: /* @__PURE__ */ __name(() => workspaceRegistry.listManaged().map((runtime) => runtime.bridge), "getBridges"),
22576
+ getPersistenceTargets: /* @__PURE__ */ __name(() => workspaceRegistry.listManaged().map((runtime) => ({
22577
+ workspaceCwd: runtime.workspaceCwd,
22578
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir
22579
+ })), "getPersistenceTargets"),
22580
+ getBridgeWorkspaceId: /* @__PURE__ */ __name((bridge2) => workspaceRegistry.listEntries().find((entry) => entry.current?.runtime.bridge === bridge2)?.workspaceId, "getBridgeWorkspaceId")
22581
+ });
22582
+ const captureRuntimeGenerationAssertion = /* @__PURE__ */ __name((runtime) => {
22583
+ const registeredGeneration = workspaceRegistry.getEntryByWorkspaceId(
22584
+ runtime.workspaceId
22585
+ )?.current;
22586
+ const guard = registeredGeneration?.runtime === runtime ? registeredGeneration.guard : runtime.generationGuard;
22587
+ return guard ? () => guard.assertOpen() : void 0;
22588
+ }, "captureRuntimeGenerationAssertion");
22631
22589
  const LANGUAGE_CODES = deps.languageCodes;
22632
22590
  const transcriptCursorMasterKey = crypto3.randomBytes(32);
22633
22591
  const transcriptCursorCodecs = /* @__PURE__ */ new Map();
22634
22592
  const activeBranchSessions = /* @__PURE__ */ new Map();
22635
22593
  const inFlightBranchWorkspaces = /* @__PURE__ */ new Set();
22636
- const inFlightSessionIds = /* @__PURE__ */ new Set();
22637
22594
  const clearBranchSessionEntry = /* @__PURE__ */ __name((sessionId) => {
22638
22595
  for (const [cwd, sid] of activeBranchSessions) {
22639
22596
  if (sid === sessionId) {
@@ -22695,6 +22652,20 @@ function registerSessionRoutes(app, deps) {
22695
22652
  ...details
22696
22653
  });
22697
22654
  }, "logSessionRoutingFailure");
22655
+ const sendRequestedSessionIdAdmissionError = /* @__PURE__ */ __name((res, error2, route) => {
22656
+ const resolutionKind = error2.code === "session_workspace_conflict" ? "workspace_conflict" : error2.code;
22657
+ logSessionRoutingFailure(route, resolutionKind, {
22658
+ sessionId: error2.sessionId,
22659
+ ...error2.details
22660
+ });
22661
+ const status = error2.code === "session_id_admission_unavailable" ? 503 : 409;
22662
+ res.status(status).json({
22663
+ error: error2.message,
22664
+ code: error2.code,
22665
+ sessionId: error2.sessionId,
22666
+ ...error2.details
22667
+ });
22668
+ }, "sendRequestedSessionIdAdmissionError");
22698
22669
  const sendWorkspaceMismatch2 = /* @__PURE__ */ __name((res, requestedWorkspace) => {
22699
22670
  const runtimes = workspaceRegistry.list();
22700
22671
  if (runtimes.length > 1) {
@@ -22959,7 +22930,6 @@ function registerSessionRoutes(app, deps) {
22959
22930
  sendUntrustedSessionOwner(res, route, sessionId, runtime);
22960
22931
  return false;
22961
22932
  }, "assertTrustedSessionOwner");
22962
- const inFlightRestoreOwners = /* @__PURE__ */ new Map();
22963
22933
  const sendSessionWorkspaceConflict = /* @__PURE__ */ __name((res, route, sessionId, runtime, liveRuntime) => {
22964
22934
  logSessionRoutingFailure(route, "workspace_conflict", {
22965
22935
  sessionId,
@@ -22978,33 +22948,6 @@ function registerSessionRoutes(app, deps) {
22978
22948
  liveWorkspaceId: liveRuntime.workspaceId
22979
22949
  });
22980
22950
  }, "sendSessionWorkspaceConflict");
22981
- const enterRestoreOwner = /* @__PURE__ */ __name((res, route, sessionId, runtime) => {
22982
- const existing = inFlightRestoreOwners.get(sessionId);
22983
- if (existing && existing.workspaceCwd !== runtime.workspaceCwd) {
22984
- sendSessionWorkspaceConflict(res, route, sessionId, runtime, existing);
22985
- return void 0;
22986
- }
22987
- if (existing) {
22988
- existing.count += 1;
22989
- } else {
22990
- inFlightRestoreOwners.set(sessionId, {
22991
- workspaceId: runtime.workspaceId,
22992
- workspaceCwd: runtime.workspaceCwd,
22993
- count: 1
22994
- });
22995
- }
22996
- let released = false;
22997
- return () => {
22998
- if (released) return;
22999
- released = true;
23000
- const current = inFlightRestoreOwners.get(sessionId);
23001
- if (!current || current.workspaceCwd !== runtime.workspaceCwd) return;
23002
- current.count -= 1;
23003
- if (current.count <= 0) {
23004
- inFlightRestoreOwners.delete(sessionId);
23005
- }
23006
- };
23007
- }, "enterRestoreOwner");
23008
22951
  const resolveRuntimeForSessionRestore = /* @__PURE__ */ __name((body, res, route, sessionId) => {
23009
22952
  const cwd = parseOptionalWorkspaceCwd(body, boundWorkspace, res);
23010
22953
  if (cwd === void 0) return void 0;
@@ -23255,6 +23198,7 @@ function registerSessionRoutes(app, deps) {
23255
23198
  });
23256
23199
  return;
23257
23200
  }
23201
+ const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
23258
23202
  const modelServiceId = typeof body["modelServiceId"] === "string" ? body["modelServiceId"] : void 0;
23259
23203
  const rawSessionScope = body["sessionScope"];
23260
23204
  let sessionScope;
@@ -23287,52 +23231,39 @@ function registerSessionRoutes(app, deps) {
23287
23231
  }
23288
23232
  const clientId = parseClientIdHeader(req, res);
23289
23233
  if (clientId === null) return;
23290
- const rawSessionId = body["sessionId"];
23291
- let requestedSessionId;
23292
- if (rawSessionId !== void 0 && rawSessionId !== null) {
23293
- if (typeof rawSessionId !== "string" || !HTTP_SESSION_ID_REGEX.test(rawSessionId)) {
23294
- res.status(400).json({
23295
- error: '`sessionId` must be a UUID (e.g. "550e8400-e29b-41d4-a716-446655440000")',
23296
- code: "invalid_session_id"
23297
- });
23298
- return;
23299
- }
23300
- requestedSessionId = rawSessionId.toLowerCase();
23301
- const sessionIdToCheck = requestedSessionId;
23302
- if (isSessionLive(runtime.bridge, sessionIdToCheck)) {
23303
- res.status(409).json({
23304
- error: `Session "${requestedSessionId}" already exists`,
23305
- code: "session_id_conflict"
23306
- });
23307
- return;
23308
- }
23309
- const runtimeOutputDir = loadSettingsCached(workspaceCwd).merged.advanced?.runtimeOutputDir;
23310
- if (await Storage.runWithRuntimeBaseDir(
23311
- runtimeOutputDir,
23312
- workspaceCwd,
23313
- () => new SessionService(workspaceCwd).sessionExistsInAnyState(
23314
- sessionIdToCheck
23315
- )
23316
- )) {
23317
- res.status(409).json({
23318
- error: `Session "${requestedSessionId}" already exists`,
23319
- code: "session_id_conflict"
23320
- });
23321
- return;
23322
- }
23323
- if (inFlightSessionIds.has(requestedSessionId)) {
23324
- res.status(409).json({
23325
- error: `Session "${requestedSessionId}" creation already in progress`,
23326
- code: "session_id_conflict"
23327
- });
23328
- return;
23234
+ const parsedSessionId = parseCallerSuppliedSessionId(body["sessionId"]);
23235
+ if (parsedSessionId.kind === "invalid") {
23236
+ res.status(400).json({
23237
+ error: '`sessionId` must be an RFC UUID v1-v5 (e.g. "550e8400-e29b-41d4-a716-446655440000")',
23238
+ code: "invalid_session_id"
23239
+ });
23240
+ return;
23241
+ }
23242
+ const requestedSessionId = parsedSessionId.kind === "valid" ? parsedSessionId.sessionId : void 0;
23243
+ let sessionIdReservation;
23244
+ if (requestedSessionId !== void 0) {
23245
+ try {
23246
+ sessionIdReservation = await requestedSessionIdAdmission.reserveCreate(
23247
+ requestedSessionId,
23248
+ {
23249
+ bridge: runtime.bridge,
23250
+ workspaceCwd,
23251
+ workspaceId: runtime.workspaceId
23252
+ }
23253
+ );
23254
+ } catch (error2) {
23255
+ if (error2 instanceof RequestedSessionIdAdmissionError) {
23256
+ sendRequestedSessionIdAdmissionError(res, error2, "POST /session");
23257
+ return;
23258
+ }
23259
+ throw error2;
23329
23260
  }
23330
- inFlightSessionIds.add(requestedSessionId);
23331
23261
  }
23332
23262
  let branchMeta;
23333
23263
  let branchBaseCommit;
23334
23264
  let worktreeMeta;
23335
23265
  try {
23266
+ assertRuntimeGenerationOpen?.();
23336
23267
  const rawBranch = body["branch"];
23337
23268
  if (rawBranch !== void 0 && rawBranch !== null) {
23338
23269
  if (body["worktree"] !== void 0 && body["worktree"] !== null) {
@@ -23440,6 +23371,7 @@ function registerSessionRoutes(app, deps) {
23440
23371
  });
23441
23372
  return;
23442
23373
  }
23374
+ assertRuntimeGenerationOpen?.();
23443
23375
  inFlightBranchWorkspaces.add(workspaceCwd);
23444
23376
  try {
23445
23377
  await createBranch(workspaceCwd, branchName);
@@ -23509,6 +23441,7 @@ function registerSessionRoutes(app, deps) {
23509
23441
  return;
23510
23442
  }
23511
23443
  const baseBranch = await wtService.getCurrentBranch().catch(() => void 0);
23444
+ assertRuntimeGenerationOpen?.();
23512
23445
  const wtResult = await wtService.createUserWorktree(slug, baseBranch);
23513
23446
  if (!wtResult.success || !wtResult.worktree) {
23514
23447
  res.status(500).json({
@@ -23527,6 +23460,7 @@ function registerSessionRoutes(app, deps) {
23527
23460
  if (requestedSessionId !== void 0) {
23528
23461
  sessionScope = "thread";
23529
23462
  }
23463
+ assertRuntimeGenerationOpen?.();
23530
23464
  const session = await runtime.bridge.spawnOrAttach({
23531
23465
  workspaceCwd,
23532
23466
  modelServiceId,
@@ -23556,6 +23490,9 @@ function registerSessionRoutes(app, deps) {
23556
23490
  coordinator: archiveCoordinator
23557
23491
  })
23558
23492
  ).catch(() => false);
23493
+ } else {
23494
+ await runtime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
23495
+ });
23559
23496
  }
23560
23497
  if (worktreeMeta) {
23561
23498
  await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
@@ -23576,7 +23513,7 @@ function registerSessionRoutes(app, deps) {
23576
23513
  return;
23577
23514
  }
23578
23515
  try {
23579
- runtime.generationGuard?.assertOpen();
23516
+ assertRuntimeGenerationOpen?.();
23580
23517
  } catch (error2) {
23581
23518
  if (!session.attached) {
23582
23519
  try {
@@ -23747,9 +23684,7 @@ function registerSessionRoutes(app, deps) {
23747
23684
  }
23748
23685
  sendBridgeError2(res, err, { route: "POST /session" });
23749
23686
  } finally {
23750
- if (requestedSessionId !== void 0) {
23751
- inFlightSessionIds.delete(requestedSessionId);
23752
- }
23687
+ sessionIdReservation?.release();
23753
23688
  }
23754
23689
  });
23755
23690
  const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
@@ -23820,27 +23755,29 @@ function registerSessionRoutes(app, deps) {
23820
23755
  }
23821
23756
  if (resolvedRuntime === void 0) return;
23822
23757
  const { runtime, workspaceCwd } = resolvedRuntime;
23823
- const releaseRestoreOwner = enterRestoreOwner(
23824
- res,
23825
- route,
23826
- sessionId,
23827
- runtime
23828
- );
23829
- if (!releaseRestoreOwner) return;
23758
+ const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
23830
23759
  const approvalMode = parseOptionalApprovalMode(body, res);
23831
- if (approvalMode === null) {
23832
- releaseRestoreOwner();
23833
- return;
23834
- }
23760
+ if (approvalMode === null) return;
23835
23761
  const historyPageSize = action === "load" ? parseHistoryPageSize(body ?? {}, res) : void 0;
23836
- if (historyPageSize === null) {
23837
- releaseRestoreOwner();
23838
- return;
23839
- }
23762
+ if (historyPageSize === null) return;
23840
23763
  const clientId = parseClientIdHeader(req, res);
23841
- if (clientId === null) {
23842
- releaseRestoreOwner();
23843
- return;
23764
+ if (clientId === null) return;
23765
+ let sessionIdReservation;
23766
+ try {
23767
+ sessionIdReservation = requestedSessionIdAdmission.reserveRestore(
23768
+ sessionId,
23769
+ {
23770
+ bridge: runtime.bridge,
23771
+ workspaceCwd,
23772
+ workspaceId: runtime.workspaceId
23773
+ }
23774
+ );
23775
+ } catch (error2) {
23776
+ if (error2 instanceof RequestedSessionIdAdmissionError) {
23777
+ sendRequestedSessionIdAdmissionError(res, error2, route);
23778
+ return;
23779
+ }
23780
+ throw error2;
23844
23781
  }
23845
23782
  try {
23846
23783
  const session = await archiveCoordinator.runSharedMany(
@@ -23867,7 +23804,7 @@ function registerSessionRoutes(app, deps) {
23867
23804
  }
23868
23805
  liveConversationCwd = await materialize(sessionId);
23869
23806
  }
23870
- runtime.generationGuard?.assertOpen();
23807
+ assertRuntimeGenerationOpen?.();
23871
23808
  const restored = action === "load" ? await runtime.bridge.loadSession({
23872
23809
  sessionId,
23873
23810
  workspaceCwd,
@@ -23939,7 +23876,7 @@ function registerSessionRoutes(app, deps) {
23939
23876
  }
23940
23877
  );
23941
23878
  try {
23942
- runtime.generationGuard?.assertOpen();
23879
+ assertRuntimeGenerationOpen?.();
23943
23880
  } catch (error2) {
23944
23881
  if (!session.attached) {
23945
23882
  await runtime.bridge.killSession(session.sessionId, { requireZeroAttaches: true }).catch(() => {
@@ -24041,7 +23978,7 @@ function registerSessionRoutes(app, deps) {
24041
23978
  sessionId
24042
23979
  });
24043
23980
  } finally {
24044
- releaseRestoreOwner();
23981
+ sessionIdReservation.release();
24045
23982
  }
24046
23983
  }, "restoreSessionHandler");
24047
23984
  app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
@@ -27361,7 +27298,7 @@ function collectBoundSessionIds(tasks) {
27361
27298
  return ids;
27362
27299
  }
27363
27300
  __name(collectBoundSessionIds, "collectBoundSessionIds");
27364
- var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
27301
+ var KEEPALIVE_REVIVE_TIMEOUT_MS = 7e4;
27365
27302
  var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
27366
27303
  var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
27367
27304
  async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding, cleanupSession) {
@@ -27607,7 +27544,7 @@ function startScheduledTaskKeepalive(opts) {
27607
27544
  };
27608
27545
  }
27609
27546
  __name(startScheduledTaskKeepalive, "startScheduledTaskKeepalive");
27610
- var REHYDRATE_LOAD_TIMEOUT_MS = 3e4;
27547
+ var REHYDRATE_LOAD_TIMEOUT_MS = 7e4;
27611
27548
  var REHYDRATE_MAX_CONCURRENCY = 4;
27612
27549
  async function rehydrateScheduledTaskSessions(deps) {
27613
27550
  const { bridge, boundWorkspace } = deps;
@@ -27666,6 +27603,7 @@ async function rehydrateScheduledTaskSessions(deps) {
27666
27603
  }
27667
27604
  __name(rehydrateScheduledTaskSessions, "rehydrateScheduledTaskSessions");
27668
27605
  function withTimeout(p, ms, label) {
27606
+ if (ms > MAX_SESSION_RESTORE_TIMEOUT_MS) return p;
27669
27607
  return new Promise((resolve5, reject) => {
27670
27608
  const timer = setTimeout(() => {
27671
27609
  reject(new Error(`${label} timed out after ${ms}ms`));
@@ -28232,6 +28170,7 @@ function registerCapabilitiesRoutes(app, deps) {
28232
28170
  maxPendingPromptsPerSession: advertisedMaxPendingPromptsPerSession(
28233
28171
  deps.maxPendingPromptsPerSession
28234
28172
  ),
28173
+ sessionRestoreTimeoutMs: deps.sessionRestoreTimeoutMs,
28235
28174
  ...multiWorkspace ? {
28236
28175
  maxSessionsPerWorkspace: advertisedMaxSessions(
28237
28176
  deps.maxSessionsPerWorkspace
@@ -29056,6 +28995,25 @@ function bridgeErrorExtraContext(ctx) {
29056
28995
  return extra;
29057
28996
  }
29058
28997
  __name(bridgeErrorExtraContext, "bridgeErrorExtraContext");
28998
+ function recordExpectedBridgeError(err, ctx, daemonLog) {
28999
+ recordDaemonBridgeError(err);
29000
+ recordDaemonError(void 0, err, {
29001
+ ...ctx?.route ? { "http.route": ctx.route } : {},
29002
+ ...ctx?.sessionId ? { "session.id": ctx.sessionId } : {}
29003
+ });
29004
+ emitDaemonLog("Daemon bridge request failed.", {
29005
+ ...ctx?.route ? { "http.route": ctx.route } : {},
29006
+ ...ctx?.sessionId ? { "session.id": ctx.sessionId } : {},
29007
+ "error.type": err.name,
29008
+ "error.message": err.message.slice(0, 1024)
29009
+ });
29010
+ daemonLog?.warn(err.message, {
29011
+ ...ctx?.route ? { route: ctx.route } : {},
29012
+ ...ctx?.sessionId ? { sessionId: ctx.sessionId } : {},
29013
+ errorType: err.name
29014
+ });
29015
+ }
29016
+ __name(recordExpectedBridgeError, "recordExpectedBridgeError");
29059
29017
  function sendPermissionVoteError(res, err, ctx, daemonLog) {
29060
29018
  if (err instanceof InvalidPermissionOptionError) {
29061
29019
  res.status(400).json({
@@ -29097,6 +29055,33 @@ function sendPermissionVoteError(res, err, ctx, daemonLog) {
29097
29055
  }
29098
29056
  __name(sendPermissionVoteError, "sendPermissionVoteError");
29099
29057
  function sendBridgeError(res, err, ctx, daemonLog) {
29058
+ if (err instanceof SessionRestoreTimeoutError) {
29059
+ recordExpectedBridgeError(err, ctx, daemonLog);
29060
+ res.set("Retry-After", String(restoreRetryAfterSeconds(err.timeoutMs)));
29061
+ res.status(504).json({
29062
+ error: err.message,
29063
+ code: "session_restore_timeout",
29064
+ errorKind: "restore_timeout",
29065
+ retryable: true,
29066
+ sessionId: err.sessionId,
29067
+ action: err.action,
29068
+ timeoutMs: err.timeoutMs
29069
+ });
29070
+ return;
29071
+ }
29072
+ if (err instanceof BridgeChannelQuarantinedError) {
29073
+ recordExpectedBridgeError(err, ctx, daemonLog);
29074
+ res.set("Retry-After", String(err.retryAfterSeconds));
29075
+ res.status(503).json({
29076
+ error: err.message,
29077
+ code: "acp_channel_unavailable",
29078
+ errorKind: "acp_channel_unavailable",
29079
+ retryable: true,
29080
+ reason: err.reason,
29081
+ retryAfterSeconds: err.retryAfterSeconds
29082
+ });
29083
+ return;
29084
+ }
29100
29085
  if (err instanceof DaemonDrainingError) {
29101
29086
  res.status(503).json({
29102
29087
  error: err.message,
@@ -29114,22 +29099,9 @@ function sendBridgeError(res, err, ctx, daemonLog) {
29114
29099
  });
29115
29100
  return;
29116
29101
  }
29117
- if (err instanceof WorkspaceSkillNotFoundError) {
29118
- res.status(404).json({
29119
- error: err.message,
29120
- code: "skill_not_found",
29121
- skillName: err.skillName
29122
- });
29123
- return;
29124
- }
29125
- if (err instanceof WorkspaceSkillNotToggleableError) {
29126
- res.status(409).json({
29127
- error: err.message,
29128
- code: err.reason === "inactive_extension" ? "skill_inactive_extension" : "skill_not_toggleable",
29129
- skillName: err.skillName,
29130
- reason: err.reason,
29131
- ...err.lockedScope ? { lockedScope: err.lockedScope } : {}
29132
- });
29102
+ const skillError = mapWorkspaceSkillToggleError(err);
29103
+ if (skillError) {
29104
+ res.status(skillError.code === "skill_not_found" ? 404 : 409).json(skillError);
29133
29105
  return;
29134
29106
  }
29135
29107
  if (err instanceof InvalidSessionTranscriptCursorError) {
@@ -29395,10 +29367,12 @@ function sendBridgeError(res, err, ctx, daemonLog) {
29395
29367
  return;
29396
29368
  }
29397
29369
  if (err instanceof RestoreInProgressError) {
29398
- res.set("Retry-After", "5");
29370
+ res.set("Retry-After", String(err.retryAfterSeconds));
29399
29371
  res.status(409).json({
29400
29372
  error: err.message,
29401
29373
  code: "restore_in_progress",
29374
+ reason: err.reason,
29375
+ retryable: true,
29402
29376
  sessionId: err.sessionId,
29403
29377
  activeAction: err.activeAction,
29404
29378
  requestedAction: err.requestedAction
@@ -35408,6 +35382,26 @@ __name(registerWorkspaceQualifiedToolsRoutes, "registerWorkspaceQualifiedToolsRo
35408
35382
 
35409
35383
  // packages/cli/src/serve/routes/workspace-skills.ts
35410
35384
  init_esbuild_shims();
35385
+ var MAX_WORKSPACE_SKILL_BATCH_SIZE = 100;
35386
+ function rejectSkillNameTooLong(skillName, res) {
35387
+ if (skillName.length <= MAX_WORKSPACE_SKILL_NAME_LENGTH) return false;
35388
+ res.status(400).json({
35389
+ error: `Skill name exceeds ${MAX_WORKSPACE_SKILL_NAME_LENGTH}-character limit`,
35390
+ code: "invalid_skill_name"
35391
+ });
35392
+ return true;
35393
+ }
35394
+ __name(rejectSkillNameTooLong, "rejectSkillNameTooLong");
35395
+ function parseEnabledFlag(body, res) {
35396
+ const enabled = body["enabled"];
35397
+ if (typeof enabled === "boolean") return { enabled };
35398
+ res.status(400).json({
35399
+ error: "`enabled` is required and must be a boolean",
35400
+ code: "invalid_enabled_flag"
35401
+ });
35402
+ return void 0;
35403
+ }
35404
+ __name(parseEnabledFlag, "parseEnabledFlag");
35411
35405
  function parseSkillToggleRequest(req, res, safeBody2) {
35412
35406
  const rawSkillName = req.params["name"];
35413
35407
  if (!rawSkillName || typeof rawSkillName !== "string") {
@@ -35425,24 +35419,42 @@ function parseSkillToggleRequest(req, res, safeBody2) {
35425
35419
  });
35426
35420
  return void 0;
35427
35421
  }
35428
- if (skillName.length > MAX_WORKSPACE_SKILL_NAME_LENGTH) {
35422
+ if (rejectSkillNameTooLong(skillName, res)) return void 0;
35423
+ const flag = parseEnabledFlag(safeBody2(req), res);
35424
+ return flag ? { skillName, enabled: flag.enabled } : void 0;
35425
+ }
35426
+ __name(parseSkillToggleRequest, "parseSkillToggleRequest");
35427
+ function parseSkillBatchToggleRequest(req, res, safeBody2) {
35428
+ const body = safeBody2(req);
35429
+ const rawSkillNames = body["skillNames"];
35430
+ if (!Array.isArray(rawSkillNames) || rawSkillNames.length === 0 || rawSkillNames.length > MAX_WORKSPACE_SKILL_BATCH_SIZE || !rawSkillNames.every((name) => typeof name === "string")) {
35429
35431
  res.status(400).json({
35430
- error: `Skill name exceeds ${MAX_WORKSPACE_SKILL_NAME_LENGTH}-character limit`,
35431
- code: "invalid_skill_name"
35432
+ error: `\`skillNames\` must be a non-empty string array (max ${MAX_WORKSPACE_SKILL_BATCH_SIZE})`,
35433
+ code: "invalid_skill_names"
35432
35434
  });
35433
35435
  return void 0;
35434
35436
  }
35435
- const enabled = safeBody2(req)["enabled"];
35436
- if (typeof enabled !== "boolean") {
35437
- res.status(400).json({
35438
- error: "`enabled` is required and must be a boolean",
35439
- code: "invalid_enabled_flag"
35440
- });
35441
- return void 0;
35437
+ const skillNames = [];
35438
+ const seen = /* @__PURE__ */ new Set();
35439
+ for (const rawSkillName of rawSkillNames) {
35440
+ const skillName = rawSkillName.trim();
35441
+ if (skillName.length === 0) {
35442
+ res.status(400).json({
35443
+ error: "Skill names must not be empty",
35444
+ code: "invalid_skill_name"
35445
+ });
35446
+ return void 0;
35447
+ }
35448
+ if (rejectSkillNameTooLong(skillName, res)) return void 0;
35449
+ const normalizedName = skillName.toLowerCase();
35450
+ if (seen.has(normalizedName)) continue;
35451
+ seen.add(normalizedName);
35452
+ skillNames.push(skillName);
35442
35453
  }
35443
- return { skillName, enabled };
35454
+ const flag = parseEnabledFlag(body, res);
35455
+ return flag ? { skillNames, enabled: flag.enabled } : void 0;
35444
35456
  }
35445
- __name(parseSkillToggleRequest, "parseSkillToggleRequest");
35457
+ __name(parseSkillBatchToggleRequest, "parseSkillBatchToggleRequest");
35446
35458
  function parseSkillScope(value, res) {
35447
35459
  if (value === "workspace" || value === "global") return value;
35448
35460
  res.status(400).json({
@@ -35462,13 +35474,7 @@ function parseSkillInstallRequest(req, res, safeBody2) {
35462
35474
  });
35463
35475
  return void 0;
35464
35476
  }
35465
- if (name.trim().length > MAX_WORKSPACE_SKILL_NAME_LENGTH) {
35466
- res.status(400).json({
35467
- error: `Skill name exceeds ${MAX_WORKSPACE_SKILL_NAME_LENGTH}-character limit`,
35468
- code: "invalid_skill_name"
35469
- });
35470
- return void 0;
35471
- }
35477
+ if (rejectSkillNameTooLong(name.trim(), res)) return void 0;
35472
35478
  const scope = parseSkillScope(body["scope"], res);
35473
35479
  if (!scope) return void 0;
35474
35480
  const rawSource = body["source"];
@@ -35522,6 +35528,7 @@ function registerWorkspaceSkillsRoutes(app, deps) {
35522
35528
  deps.workspaceRuntime.workspaceCwd
35523
35529
  );
35524
35530
  const route = "POST /workspace/skills/:name/enable";
35531
+ const batchRoute = "POST /workspace/skills/enable";
35525
35532
  app.post(
35526
35533
  "/workspace/skills/install",
35527
35534
  deps.mutate({ strict: true }),
@@ -35575,6 +35582,27 @@ function registerWorkspaceSkillsRoutes(app, deps) {
35575
35582
  }
35576
35583
  }
35577
35584
  );
35585
+ app.post(
35586
+ "/workspace/skills/enable",
35587
+ deps.mutate({ strict: true }),
35588
+ async (req, res) => {
35589
+ if (!requireTrustedWorkspaceRuntime(deps.workspaceRuntime, res)) return;
35590
+ const input = parseSkillBatchToggleRequest(req, res, deps.safeBody);
35591
+ if (!input) return;
35592
+ const clientId = deps.parseAndValidateClientId(req, res);
35593
+ if (clientId === null) return;
35594
+ try {
35595
+ const result = await deps.workspaceRuntime.workspaceService.setWorkspaceSkillsEnabled(
35596
+ buildWorkspaceCtx(batchRoute, clientId),
35597
+ input.skillNames,
35598
+ input.enabled
35599
+ );
35600
+ res.status(200).json(result);
35601
+ } catch (err) {
35602
+ deps.sendBridgeError(res, err, { route: batchRoute });
35603
+ }
35604
+ }
35605
+ );
35578
35606
  app.post(
35579
35607
  "/workspace/skills/:name/enable",
35580
35608
  deps.mutate({ strict: true }),
@@ -35600,6 +35628,7 @@ function registerWorkspaceSkillsRoutes(app, deps) {
35600
35628
  __name(registerWorkspaceSkillsRoutes, "registerWorkspaceSkillsRoutes");
35601
35629
  function registerWorkspaceQualifiedSkillsRoutes(app, deps) {
35602
35630
  const route = "POST /workspaces/:workspace/skills/:name/enable";
35631
+ const batchRoute = "POST /workspaces/:workspace/skills/enable";
35603
35632
  app.post(
35604
35633
  "/workspaces/:workspace/skills/install",
35605
35634
  deps.mutate({ strict: true }),
@@ -35671,6 +35700,36 @@ function registerWorkspaceQualifiedSkillsRoutes(app, deps) {
35671
35700
  }
35672
35701
  }
35673
35702
  );
35703
+ app.post(
35704
+ "/workspaces/:workspace/skills/enable",
35705
+ deps.mutate({ strict: true }),
35706
+ async (req, res) => {
35707
+ const runtime = resolveWorkspaceRuntimeFromParam(
35708
+ deps.workspaceRegistry,
35709
+ req,
35710
+ res
35711
+ );
35712
+ if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res)) return;
35713
+ const input = parseSkillBatchToggleRequest(req, res, deps.safeBody);
35714
+ if (!input) return;
35715
+ const clientId = parseAndValidateWorkspaceClientId(
35716
+ req,
35717
+ res,
35718
+ runtime.bridge
35719
+ );
35720
+ if (clientId === null) return;
35721
+ try {
35722
+ const result = await runtime.workspaceService.setWorkspaceSkillsEnabled(
35723
+ createBuildWorkspaceCtx(runtime.workspaceCwd)(batchRoute, clientId),
35724
+ input.skillNames,
35725
+ input.enabled
35726
+ );
35727
+ res.status(200).json(result);
35728
+ } catch (err) {
35729
+ deps.sendBridgeError(res, err, { route: batchRoute });
35730
+ }
35731
+ }
35732
+ );
35674
35733
  app.post(
35675
35734
  "/workspaces/:workspace/skills/:name/enable",
35676
35735
  deps.mutate({ strict: true }),
@@ -39265,11 +39324,13 @@ var execFileAsync3 = promisify3(execFile3);
39265
39324
  var LIVE_HOST_BUNDLE_ID2 = "com.alibaba.qwen-code.live-host";
39266
39325
  var LIVE_HOST_TEAM_IDENTIFIER = "NF4574S59H";
39267
39326
  var LIVE_HOST_APP_PATH = "/Applications/Qwen Live Host.app";
39327
+ var LIVE_HOST_OSS_BASE_URL = "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/live-host";
39268
39328
  var LIVE_HOST_RELEASE_BASE_URL = "https://github.com/QwenLM/qwen-code/releases/download/live-host-latest";
39269
39329
  var LIVE_HOST_MANIFEST_NAME = "Qwen-Live-Host-manifest.json";
39330
+ var LIVE_HOST_MANIFEST_FETCH_TIMEOUT_MS = 5 * 60 * 1e3;
39331
+ var LIVE_HOST_DOWNLOAD_TIMEOUT_MS = 60 * 60 * 1e3;
39270
39332
  var LIVE_HOST_APP_NAME = "Qwen Live Host.app";
39271
39333
  var MAX_DOWNLOAD_BYTES = 512 * 1024 * 1024;
39272
- var FETCH_TIMEOUT_MS = 5 * 60 * 1e3;
39273
39334
  var COMMAND_TIMEOUT_MS = 2 * 60 * 1e3;
39274
39335
  var SHA256_PATTERN = /^[a-f0-9]{64}$/;
39275
39336
  var VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
@@ -39385,11 +39446,24 @@ async function inspectInstalledHost() {
39385
39446
  }
39386
39447
  }
39387
39448
  __name(inspectInstalledHost, "inspectInstalledHost");
39388
- async function fetchManifest() {
39389
- const response = await fetch(
39390
- `${LIVE_HOST_RELEASE_BASE_URL}/${LIVE_HOST_MANIFEST_NAME}`,
39391
- { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) }
39392
- );
39449
+ function resolveLiveHostManifestUrls() {
39450
+ return [
39451
+ `${LIVE_HOST_OSS_BASE_URL}/latest/${LIVE_HOST_MANIFEST_NAME}`,
39452
+ `${LIVE_HOST_RELEASE_BASE_URL}/${LIVE_HOST_MANIFEST_NAME}`
39453
+ ];
39454
+ }
39455
+ __name(resolveLiveHostManifestUrls, "resolveLiveHostManifestUrls");
39456
+ function resolveLiveHostAssetUrls(version, assetName) {
39457
+ return [
39458
+ `${LIVE_HOST_OSS_BASE_URL}/v${version}/${assetName}`,
39459
+ `${LIVE_HOST_RELEASE_BASE_URL}/${assetName}`
39460
+ ];
39461
+ }
39462
+ __name(resolveLiveHostAssetUrls, "resolveLiveHostAssetUrls");
39463
+ async function fetchManifest(url, fetchImpl) {
39464
+ const response = await fetchImpl(url, {
39465
+ signal: AbortSignal.timeout(LIVE_HOST_MANIFEST_FETCH_TIMEOUT_MS)
39466
+ });
39393
39467
  if (!response.ok) {
39394
39468
  await response.body?.cancel().catch(() => {
39395
39469
  });
@@ -39398,9 +39472,9 @@ async function fetchManifest() {
39398
39472
  return parseLiveHostReleaseManifest(await response.json());
39399
39473
  }
39400
39474
  __name(fetchManifest, "fetchManifest");
39401
- async function downloadAsset(asset, destination, onProgress) {
39402
- const response = await fetch(`${LIVE_HOST_RELEASE_BASE_URL}/${asset.name}`, {
39403
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
39475
+ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
39476
+ const response = await fetchImpl(url, {
39477
+ signal: AbortSignal.timeout(LIVE_HOST_DOWNLOAD_TIMEOUT_MS)
39404
39478
  });
39405
39479
  if (!response.ok || !response.body) {
39406
39480
  await response.body?.cancel().catch(() => {
@@ -39437,13 +39511,36 @@ async function downloadAsset(asset, destination, onProgress) {
39437
39511
  }
39438
39512
  }
39439
39513
  __name(downloadAsset, "downloadAsset");
39514
+ async function downloadLiveHostRelease(currentArchitecture, destination, onProgress, fetchImpl = fetch) {
39515
+ const manifestUrls = resolveLiveHostManifestUrls();
39516
+ const labels = ["OSS", "GitHub"];
39517
+ const errors = [];
39518
+ for (let index = 0; index < manifestUrls.length; index += 1) {
39519
+ try {
39520
+ await fsp5.rm(destination, { force: true });
39521
+ const manifest = await fetchManifest(manifestUrls[index], fetchImpl);
39522
+ const asset = manifest.assets[currentArchitecture];
39523
+ const assetUrl = resolveLiveHostAssetUrls(manifest.version, asset.name)[index];
39524
+ await downloadAsset(asset, assetUrl, destination, onProgress, fetchImpl);
39525
+ return { manifest, asset };
39526
+ } catch (error2) {
39527
+ errors.push(
39528
+ new Error(`${labels[index]}: ${errorMessage3(error2)}`, { cause: error2 })
39529
+ );
39530
+ }
39531
+ }
39532
+ await fsp5.rm(destination, { force: true });
39533
+ throw new AggregateError(
39534
+ errors,
39535
+ `Qwen Live Host download failed. ${errors.map((error2) => error2.message).join(" ")}`
39536
+ );
39537
+ }
39538
+ __name(downloadLiveHostRelease, "downloadLiveHostRelease");
39440
39539
  async function installLatestHost(currentArchitecture, onStatus) {
39441
- const manifest = await fetchManifest();
39442
- const asset = manifest.assets[currentArchitecture];
39443
39540
  const temporaryDirectory = await fsp5.mkdtemp(
39444
39541
  path14.join(os2.tmpdir(), "qwen-live-host-")
39445
39542
  );
39446
- const archivePath = path14.join(temporaryDirectory, asset.name);
39543
+ const archivePath = path14.join(temporaryDirectory, "Qwen-Live-Host.zip");
39447
39544
  const extractedPath = path14.join(temporaryDirectory, "extracted");
39448
39545
  const candidatePath = path14.join(extractedPath, LIVE_HOST_APP_NAME);
39449
39546
  const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID11()}.app`;
@@ -39452,9 +39549,13 @@ async function installLatestHost(currentArchitecture, onStatus) {
39452
39549
  let installedCandidate = false;
39453
39550
  try {
39454
39551
  onStatus({ state: "downloading", progress: 0 });
39455
- await downloadAsset(asset, archivePath, (progress) => {
39456
- onStatus({ state: "downloading", progress });
39457
- });
39552
+ const { manifest } = await downloadLiveHostRelease(
39553
+ currentArchitecture,
39554
+ archivePath,
39555
+ (progress) => {
39556
+ onStatus({ state: "downloading", progress });
39557
+ }
39558
+ );
39458
39559
  onStatus({ state: "verifying" });
39459
39560
  await fsp5.mkdir(extractedPath, { mode: 448 });
39460
39561
  await run("/usr/bin/ditto", ["-x", "-k", archivePath, extractedPath]);
@@ -42286,6 +42387,7 @@ function getRuntimeEffectiveEnv(metadata) {
42286
42387
  }
42287
42388
  __name(getRuntimeEffectiveEnv, "getRuntimeEffectiveEnv");
42288
42389
  var DEFAULT_SESSION_IDLE_TIMEOUT_MS = 30 * 6e4;
42390
+ var SCHEDULED_TASK_RESTORE_HEADROOM_MS = 1e4;
42289
42391
  var KEEPALIVE_MIN_INTERVAL_MS = 3e4;
42290
42392
  var KEEPALIVE_MAX_INTERVAL_MS = 10 * 6e4;
42291
42393
  function computeKeepaliveIntervalMs(idleTimeoutMs) {
@@ -42327,11 +42429,18 @@ function createLiveWorkspaceDelegate(getTarget) {
42327
42429
  }
42328
42430
  __name(createLiveWorkspaceDelegate, "createLiveWorkspaceDelegate");
42329
42431
  function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42432
+ const sessionRestoreTimeoutMs = resolveSessionRestoreTimeoutMs(opts);
42433
+ const scheduledTaskRestoreTimeoutMs = sessionRestoreTimeoutMs + SCHEDULED_TASK_RESTORE_HEADROOM_MS > MAX_SESSION_RESTORE_TIMEOUT_MS ? MAX_SESSION_RESTORE_TIMEOUT_MS + 1 : sessionRestoreTimeoutMs + SCHEDULED_TASK_RESTORE_HEADROOM_MS;
42330
42434
  if (deps.workspaceRuntimeRemoval && !deps.voiceCoordinator) {
42331
42435
  throw new Error(
42332
42436
  "createServeApp: deps.workspaceRuntimeRemoval requires the matching deps.voiceCoordinator."
42333
42437
  );
42334
42438
  }
42439
+ if ((deps.workspaceTrustHotReloadAvailable === true || deps.workspaceRuntimeRemoval !== void 0) && deps.getSessionBridges === void 0) {
42440
+ throw new Error(
42441
+ "createServeApp: runtime replacement/removal requires deps.getSessionBridges so session-id admission can inspect draining generations."
42442
+ );
42443
+ }
42335
42444
  const app = (0, import_express5.default)();
42336
42445
  const injectedWorkspaceRegistry = deps.workspaceRegistry;
42337
42446
  const boundWorkspace = injectedWorkspaceRegistry?.primary.workspaceCwd ?? deps.boundWorkspace ?? canonicalizeWorkspace(opts.workspace ?? process.cwd());
@@ -42503,6 +42612,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42503
42612
  maxJournalEvents: opts.maxJournalEvents,
42504
42613
  maxJournalBytes: opts.maxJournalBytes,
42505
42614
  initializeTimeoutMs: opts.initializeTimeoutMs,
42615
+ sessionRestoreTimeoutMs,
42506
42616
  permissionResponseTimeoutMs: opts.permissionResponseTimeoutMs,
42507
42617
  boundWorkspace,
42508
42618
  sessionShellCommandEnabled,
@@ -42510,9 +42620,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42510
42620
  // that don't inject `deps.bridge` get daemon env + preflight cells.
42511
42621
  statusProvider,
42512
42622
  delegateReadTextFileToClient: false,
42513
- // Final ACP text writes remain delegated through WorkspaceFileSystem.
42623
+ // Final ACP text writes remain delegated. Workspace writes use WFS;
42624
+ // marked same-host tool writes may use the factory's host writer.
42514
42625
  // Unexpected delegated reads still fail closed at the WFS boundary.
42515
- fileSystem: createBridgeFileSystemAdapter(fsFactory),
42626
+ fileSystem: createBridgeFileSystemAdapter(fsFactory, {
42627
+ allowSameHostToolWritesOutsideWorkspace: deps.fsFactory === void 0
42628
+ }),
42516
42629
  // Reverse tool channel: answer the child's `client_mcp/message`
42517
42630
  // ext-method by reaching the WS connection that hosts the named server.
42518
42631
  clientMcpSender: clientMcpSenderRegistry.lookup
@@ -42578,6 +42691,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42578
42691
  "setWorkspaceSkillEnabled requires persistDisabledSkills in ServeAppDeps"
42579
42692
  );
42580
42693
  }),
42694
+ persistDisabledSkillsBatch: deps.persistDisabledSkillsBatch ?? (async () => {
42695
+ throw new Error(
42696
+ "setWorkspaceSkillsEnabled requires persistDisabledSkillsBatch in ServeAppDeps"
42697
+ );
42698
+ }),
42581
42699
  queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => bridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
42582
42700
  invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => bridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
42583
42701
  preheatAcpChild: /* @__PURE__ */ __name(() => bridge.preheat(), "preheatAcpChild"),
@@ -42613,6 +42731,15 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42613
42731
  } : {}
42614
42732
  );
42615
42733
  app.locals.workspaceRegistry = workspaceRegistry;
42734
+ const requestedSessionIdAdmission = createRequestedSessionIdAdmission({
42735
+ archiveCoordinator,
42736
+ getBridges: deps.getSessionBridges ?? (() => workspaceRegistry.listManaged().map((runtime) => runtime.bridge)),
42737
+ getPersistenceTargets: /* @__PURE__ */ __name(() => workspaceRegistry.listManaged().map((runtime) => ({
42738
+ workspaceCwd: runtime.workspaceCwd,
42739
+ runtimeBaseDir: runtime.sessionRuntimeBaseDir
42740
+ })), "getPersistenceTargets"),
42741
+ getBridgeWorkspaceId: /* @__PURE__ */ __name((bridge2) => workspaceRegistry.listEntries().find((entry) => entry.current?.runtime.bridge === bridge2)?.workspaceId, "getBridgeWorkspaceId")
42742
+ });
42616
42743
  primaryTrustRegistry = workspaceRegistry;
42617
42744
  const primaryRuntime = createLiveWorkspaceDelegate(
42618
42745
  () => workspaceRegistry.primary
@@ -42935,15 +43062,14 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42935
43062
  mount: false,
42936
43063
  workspaceQualifiedAcpEnabled
42937
43064
  });
42938
- const healthDemoRoutes = createHealthDemoRoutes({
43065
+ const healthRoutes = createHealthRoutes({
42939
43066
  opts,
42940
- getPort,
42941
43067
  workspaceRegistry,
42942
43068
  getActiveSseCount,
42943
43069
  getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
42944
43070
  });
42945
- if (healthDemoRoutes.exposeHealthPreAuth) {
42946
- healthDemoRoutes.register(app);
43071
+ if (healthRoutes.exposeHealthPreAuth) {
43072
+ healthRoutes.register(app);
42947
43073
  }
42948
43074
  installAccessLogMiddleware(app, daemonLog);
42949
43075
  const webShellDir = opts.serveWebShell !== false ? deps.webShellDir : void 0;
@@ -42990,8 +43116,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
42990
43116
  if (rateLimiter) {
42991
43117
  app.use(rateLimiter.middleware);
42992
43118
  }
42993
- if (!healthDemoRoutes.exposeHealthPreAuth) {
42994
- healthDemoRoutes.register(app);
43119
+ if (!healthRoutes.exposeHealthPreAuth) {
43120
+ healthRoutes.register(app);
42995
43121
  }
42996
43122
  installJsonBodyParser(app);
42997
43123
  const mutate = createMutationGate({
@@ -43066,6 +43192,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43066
43192
  maxSessionsPerWorkspace: opts.maxSessions,
43067
43193
  maxTotalSessions: opts.maxTotalSessions,
43068
43194
  maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
43195
+ sessionRestoreTimeoutMs,
43069
43196
  languageCodes
43070
43197
  });
43071
43198
  if (liveVoiceSurfaceAvailable) {
@@ -43477,6 +43604,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43477
43604
  bridge: primaryBridge,
43478
43605
  workspaceRegistry,
43479
43606
  archiveCoordinator,
43607
+ requestedSessionIdAdmission,
43480
43608
  mutate,
43481
43609
  sendBridgeError: sendBridgeError2,
43482
43610
  daemonLog,
@@ -43643,6 +43771,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43643
43771
  () => rehydrateScheduledTaskSessions({
43644
43772
  bridge: runtime.bridge,
43645
43773
  boundWorkspace: runtime.workspaceCwd,
43774
+ loadTimeoutMs: scheduledTaskRestoreTimeoutMs,
43646
43775
  onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead"),
43647
43776
  onError: /* @__PURE__ */ __name((sessionId, err) => {
43648
43777
  process.stderr.write(
@@ -43673,6 +43802,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43673
43802
  bridge: runtime.bridge,
43674
43803
  boundWorkspace: runtime.workspaceCwd,
43675
43804
  intervalMs: keepaliveIntervalMs,
43805
+ reviveTimeoutMs: scheduledTaskRestoreTimeoutMs,
43676
43806
  runtimeBaseDir: runtime.sessionRuntimeBaseDir,
43677
43807
  cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession"),
43678
43808
  onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
@@ -43717,6 +43847,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43717
43847
  workspaceRegistry,
43718
43848
  isPrimaryWorkspaceTrusted,
43719
43849
  archiveCoordinator,
43850
+ requestedSessionIdAdmission,
43720
43851
  workspace: primaryWorkspace,
43721
43852
  fsFactory: primaryRouteFileSystemFactory,
43722
43853
  deviceFlowRegistry,