@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
@@ -17,16 +17,17 @@ import {
17
17
  } from "./chunk-OCPBI7J5.js";
18
18
  import {
19
19
  defaultSpawnChannelFactory
20
- } from "./chunk-RPWVIXDB.js";
20
+ } from "./chunk-I5VM3SKY.js";
21
21
  import {
22
22
  BridgeChannelClosedError,
23
23
  BridgeTimeoutError,
24
24
  SERVE_CONTROL_EXT_METHODS,
25
25
  SERVE_STATUS_EXT_METHODS,
26
26
  STATUS_SCHEMA_VERSION,
27
+ SessionRestoreTimeoutError,
27
28
  createIdleWorkspaceExtensionsStatus,
28
29
  createIdleWorkspaceHooksStatus
29
- } from "./chunk-NLREQJFK.js";
30
+ } from "./chunk-DA4HRSBW.js";
30
31
  import {
31
32
  ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM,
32
33
  ACTIVE_WORK_CLOSE_TIMEOUT_MS,
@@ -59,6 +60,7 @@ import {
59
60
  } from "./chunk-M2PNLYGY.js";
60
61
  import {
61
62
  BranchWhilePromptActiveError,
63
+ BridgeChannelQuarantinedError,
62
64
  CancelSentinelCollisionError,
63
65
  CdWhilePromptActiveError,
64
66
  InvalidClientIdError,
@@ -77,7 +79,7 @@ import {
77
79
  SessionShellDisabledError,
78
80
  WorkspaceMismatchError,
79
81
  isNotCurrentlyGeneratingCancelError
80
- } from "./chunk-J26HHFI5.js";
82
+ } from "./chunk-LP2QGNSP.js";
81
83
  import {
82
84
  canonicalizeWorkspace,
83
85
  translateAndCheckAbsoluteWorkspacePath
@@ -111,16 +113,16 @@ import {
111
113
  metadataBudgetBytes,
112
114
  normalizeSnapshotPayload,
113
115
  stableSessionArtifactId
114
- } from "./chunk-GXSNGY5M.js";
116
+ } from "./chunk-XX7QFP34.js";
115
117
  import {
116
118
  DAEMON_TRACEPARENT_META_KEY,
117
119
  DAEMON_TRACESTATE_META_KEY
118
- } from "./chunk-L4N6TIP7.js";
120
+ } from "./chunk-4TRQPFDP.js";
119
121
  import {
120
122
  INVOCATION_CONTEXT_META_KEY,
121
123
  PRIVATE_ACP_CAPABILITY_ENV,
122
124
  PRIVATE_PARENT_CAPABILITY_META_KEY
123
- } from "./chunk-3PY4LPJF.js";
125
+ } from "./chunk-YGT2AUJ7.js";
124
126
  import {
125
127
  init_esbuild_shims
126
128
  } from "./chunk-5O2XNYP6.js";
@@ -148,6 +150,7 @@ var LATEST_WINS_UPDATES = /* @__PURE__ */ new Set([
148
150
  "current_mode_update"
149
151
  ]);
150
152
  var REPLAY_SEGMENT_COMPACT_THRESHOLD = 64;
153
+ var LIVE_JOURNAL_TEXT_CHUNKS_PER_EVENT = 256;
151
154
  function replayRecordId(event) {
152
155
  if (event.type !== "session_update") return void 0;
153
156
  const data = event.data;
@@ -185,10 +188,14 @@ var TurnBoundaryCompactionEngine = class {
185
188
  replaySegmentStart = 0;
186
189
  replayBytes = 0;
187
190
  liveJournal = [];
188
- /** Serialized size of each `liveJournal` entry, index-parallel. */
191
+ /** Serialized source-event size of each `liveJournal` entry, index-parallel. */
189
192
  journalEntryBytes = [];
193
+ /** Raw event count represented by each `liveJournal` entry. */
194
+ journalEntryEvents = [];
190
195
  journalTotalBytes = 0;
196
+ journalTotalEvents = 0;
191
197
  journalTruncatedEvents = 0;
198
+ liveJournalTextSegment;
192
199
  lastEventId = 0;
193
200
  closed = false;
194
201
  truncatedEvents = 0;
@@ -233,15 +240,7 @@ var TurnBoundaryCompactionEngine = class {
233
240
  if (seenRecordId !== void 0) {
234
241
  this.activeRecordId = seenRecordId;
235
242
  }
236
- this.liveJournal.push(event);
237
- const bytes = byteLength ?? serializedBridgeEventByteLength(event) ?? 0;
238
- this.journalEntryBytes.push(bytes);
239
- this.journalTotalBytes += bytes;
240
- while (this.liveJournal.length > this.maxJournalEvents || this.journalTotalBytes > this.maxJournalBytes && this.liveJournal.length > 1) {
241
- this.liveJournal.shift();
242
- this.journalTotalBytes -= this.journalEntryBytes.shift() ?? 0;
243
- this.journalTruncatedEvents += 1;
244
- }
243
+ this.appendLiveJournal(event, byteLength);
245
244
  if (TURN_BOUNDARY_TYPES.has(event.type)) {
246
245
  this.compactCurrentTurn(event);
247
246
  return;
@@ -259,7 +258,13 @@ var TurnBoundaryCompactionEngine = class {
259
258
  this.makeHistoryTruncatedEvent(compactedTurns.length)
260
259
  );
261
260
  }
262
- const liveJournal = this.liveJournal.slice();
261
+ const liveJournal = this.liveJournal.map(
262
+ (entry) => isLiveJournalTextSegment(entry) ? mergeLiveJournalTextEvent(
263
+ entry.firstEvent,
264
+ entry.lastEvent,
265
+ entry.chunks
266
+ ) : entry
267
+ );
263
268
  if (this.journalTruncatedEvents > 0) {
264
269
  liveJournal.unshift({
265
270
  v: EVENT_SCHEMA_VERSION,
@@ -268,7 +273,7 @@ var TurnBoundaryCompactionEngine = class {
268
273
  reason: "replay_window_exceeded",
269
274
  scope: "live_journal",
270
275
  truncatedEvents: this.journalTruncatedEvents,
271
- retainedEvents: this.liveJournal.length,
276
+ retainedEvents: this.journalTotalEvents,
272
277
  maxBytes: this.maxJournalBytes,
273
278
  maxEvents: this.maxJournalEvents,
274
279
  // Pagination anchor — see makeHistoryTruncatedEvent.
@@ -341,6 +346,54 @@ var TurnBoundaryCompactionEngine = class {
341
346
  this.toolSlotIndex.clear();
342
347
  this.clearTextSlotIndex();
343
348
  }
349
+ appendLiveJournal(event, byteLength) {
350
+ const bytes = byteLength ?? serializedBridgeEventByteLength(event) ?? 0;
351
+ const textChunk = liveJournalTextChunk(event);
352
+ const current = this.liveJournalTextSegment;
353
+ const currentIndex = this.liveJournal.length - 1;
354
+ if (textChunk && current && this.liveJournal[currentIndex] === current && current.chunks.length < LIVE_JOURNAL_TEXT_CHUNKS_PER_EVENT && this.journalEntryBytes[currentIndex] + bytes <= this.maxJournalBytes && current.sessionUpdate === textChunk.sessionUpdate && current.parentToolCallId === textChunk.parentToolCallId && stringArraysEqual(current.sourceRecordIds, textChunk.sourceRecordIds) && current.promptId === event.promptId && current.originatorClientId === event.originatorClientId && current.sessionId === captureSessionId(event) && hasOnlyTimestampEnvelopeMeta(current.lastEvent._meta) && hasOnlyTimestampEnvelopeMeta(event._meta)) {
355
+ current.chunks.push(textChunk.text);
356
+ current.lastEvent = event;
357
+ this.journalEntryBytes[currentIndex] += bytes;
358
+ this.journalEntryEvents[currentIndex] += 1;
359
+ this.journalTotalBytes += bytes;
360
+ this.journalTotalEvents += 1;
361
+ } else {
362
+ let entry = event;
363
+ if (textChunk) {
364
+ const segment = {
365
+ sessionUpdate: textChunk.sessionUpdate,
366
+ chunks: [textChunk.text],
367
+ sourceRecordIds: textChunk.sourceRecordIds,
368
+ parentToolCallId: textChunk.parentToolCallId,
369
+ promptId: event.promptId,
370
+ originatorClientId: event.originatorClientId,
371
+ sessionId: captureSessionId(event),
372
+ firstEvent: event,
373
+ lastEvent: event
374
+ };
375
+ entry = segment;
376
+ this.liveJournalTextSegment = segment;
377
+ } else {
378
+ this.liveJournalTextSegment = void 0;
379
+ }
380
+ this.liveJournal.push(entry);
381
+ this.journalEntryBytes.push(bytes);
382
+ this.journalEntryEvents.push(1);
383
+ this.journalTotalBytes += bytes;
384
+ this.journalTotalEvents += 1;
385
+ }
386
+ while (this.liveJournal.length > this.maxJournalEvents || this.journalTotalBytes > this.maxJournalBytes && this.liveJournal.length > 1) {
387
+ const dropped = this.liveJournal.shift();
388
+ this.journalTotalBytes -= this.journalEntryBytes.shift() ?? 0;
389
+ const droppedEvents = this.journalEntryEvents.shift() ?? 0;
390
+ this.journalTotalEvents -= droppedEvents;
391
+ this.journalTruncatedEvents += droppedEvents;
392
+ if (dropped === this.liveJournalTextSegment) {
393
+ this.liveJournalTextSegment = void 0;
394
+ }
395
+ }
396
+ }
344
397
  classifySessionUpdate(event) {
345
398
  const data = event.data;
346
399
  const updateType = data?.update?.sessionUpdate;
@@ -350,7 +403,7 @@ var TurnBoundaryCompactionEngine = class {
350
403
  }
351
404
  switch (updateType) {
352
405
  case "agent_message_chunk": {
353
- if (hasTodoStopGuardDiscreteMeta(data?.update?._meta)) {
406
+ if (hasDiscreteMessageMeta(data?.update?._meta)) {
354
407
  this.slots.push({ kind: "misc", event });
355
408
  break;
356
409
  }
@@ -358,6 +411,10 @@ var TurnBoundaryCompactionEngine = class {
358
411
  break;
359
412
  }
360
413
  case "agent_thought_chunk": {
414
+ if (hasDiscreteMessageMeta(data?.update?._meta)) {
415
+ this.slots.push({ kind: "misc", event });
416
+ break;
417
+ }
361
418
  this.mergeTextSlot("thought", event, data);
362
419
  break;
363
420
  }
@@ -506,8 +563,11 @@ var TurnBoundaryCompactionEngine = class {
506
563
  resetJournal() {
507
564
  this.liveJournal = [];
508
565
  this.journalEntryBytes = [];
566
+ this.journalEntryEvents = [];
509
567
  this.journalTotalBytes = 0;
568
+ this.journalTotalEvents = 0;
510
569
  this.journalTruncatedEvents = 0;
570
+ this.liveJournalTextSegment = void 0;
511
571
  }
512
572
  addReplaySegment(events, turnCount) {
513
573
  if (events.length === 0) return;
@@ -625,6 +685,61 @@ var TurnBoundaryCompactionEngine = class {
625
685
  this.textSlotIndex.thought.clear();
626
686
  }
627
687
  };
688
+ function isLiveJournalTextSegment(entry) {
689
+ return "firstEvent" in entry;
690
+ }
691
+ __name(isLiveJournalTextSegment, "isLiveJournalTextSegment");
692
+ function liveJournalTextChunk(event) {
693
+ if (event.type !== "session_update") return void 0;
694
+ const data = event.data;
695
+ const sessionUpdate = data?.update?.sessionUpdate;
696
+ if (sessionUpdate !== "agent_message_chunk" && sessionUpdate !== "agent_thought_chunk") {
697
+ return void 0;
698
+ }
699
+ if (!hasOnlyModeledChunkKeys(data)) {
700
+ return void 0;
701
+ }
702
+ if (hasDiscreteMessageMeta(data?.update?._meta) || hasUnmodeledTextMeta(data?.update?._meta)) {
703
+ return void 0;
704
+ }
705
+ const content = data?.update?.content;
706
+ if (content?.type !== "text" || typeof content.text !== "string") {
707
+ return void 0;
708
+ }
709
+ return {
710
+ sessionUpdate,
711
+ text: content.text,
712
+ sourceRecordIds: extractSourceRecordIdsFromMeta(data?.update?._meta),
713
+ parentToolCallId: extractParentToolCallIdFromMeta(data?.update?._meta)
714
+ };
715
+ }
716
+ __name(liveJournalTextChunk, "liveJournalTextChunk");
717
+ function hasOnlyModeledChunkKeys(data) {
718
+ if (!data || !data.update) return false;
719
+ const content = data.update.content;
720
+ return Object.keys(data).every((key) => key === "sessionId" || key === "update") && Object.keys(data.update).every(
721
+ (key) => key === "sessionUpdate" || key === "content" || key === "_meta"
722
+ ) && (content === void 0 || typeof content === "object" && content !== null && Object.keys(content).every((key) => key === "type" || key === "text"));
723
+ }
724
+ __name(hasOnlyModeledChunkKeys, "hasOnlyModeledChunkKeys");
725
+ function mergeLiveJournalTextEvent(existing, incoming, chunks) {
726
+ const existingData = existing.data;
727
+ const incomingData = incoming.data;
728
+ return {
729
+ ...existing,
730
+ ...incoming,
731
+ data: {
732
+ ...existingData,
733
+ ...incomingData,
734
+ update: {
735
+ ...existingData.update,
736
+ ...incomingData.update,
737
+ content: { type: "text", text: chunks.join("") }
738
+ }
739
+ }
740
+ };
741
+ }
742
+ __name(mergeLiveJournalTextEvent, "mergeLiveJournalTextEvent");
628
743
  function makeMergedSessionUpdateEvent(sessionUpdate, text, eventId, meta, envelopeMeta, turn, sessionId) {
629
744
  return {
630
745
  id: eventId || void 0,
@@ -705,10 +820,57 @@ function stringArraysEqual(left, right) {
705
820
  return left.every((value, index) => value === right[index]);
706
821
  }
707
822
  __name(stringArraysEqual, "stringArraysEqual");
708
- function hasTodoStopGuardDiscreteMeta(meta) {
709
- return typeof meta === "object" && meta !== null && meta["qwenDiscreteMessage"] === true && meta["source"] === "todo_stop_guard";
823
+ function hasDiscreteMessageMeta(meta) {
824
+ return typeof meta === "object" && meta !== null && meta["qwenDiscreteMessage"] === true;
825
+ }
826
+ __name(hasDiscreteMessageMeta, "hasDiscreteMessageMeta");
827
+ function hasOnlyTimestampEnvelopeMeta(meta) {
828
+ if (meta === void 0) return true;
829
+ if (typeof meta !== "object" || meta === null) return false;
830
+ return Object.keys(meta).every(
831
+ (key) => key === "timestamp" || key === "serverTimestamp"
832
+ );
833
+ }
834
+ __name(hasOnlyTimestampEnvelopeMeta, "hasOnlyTimestampEnvelopeMeta");
835
+ function hasUnmodeledTextMeta(meta) {
836
+ if (meta === void 0) return false;
837
+ if (typeof meta !== "object" || meta === null) return true;
838
+ const record = meta;
839
+ for (const [key, value] of Object.entries(record)) {
840
+ if (key === "timestamp" || key === "serverTimestamp") {
841
+ continue;
842
+ }
843
+ if (key === "parentToolCallId") {
844
+ if (typeof value !== "string") return true;
845
+ continue;
846
+ }
847
+ if (key === "subagentType") {
848
+ if (typeof value !== "string") return true;
849
+ continue;
850
+ }
851
+ if (key === "qwenTranscript") {
852
+ if (typeof value !== "object" || value === null) return true;
853
+ const transcript = value;
854
+ for (const [field, fieldValue] of Object.entries(transcript)) {
855
+ if (field === "sourceRecordIds") {
856
+ if (!Array.isArray(fieldValue) || fieldValue.some((id) => typeof id !== "string")) {
857
+ return true;
858
+ }
859
+ continue;
860
+ }
861
+ if (field === "planToolCallId") {
862
+ if (typeof fieldValue !== "string") return true;
863
+ continue;
864
+ }
865
+ return true;
866
+ }
867
+ continue;
868
+ }
869
+ return true;
870
+ }
871
+ return false;
710
872
  }
711
- __name(hasTodoStopGuardDiscreteMeta, "hasTodoStopGuardDiscreteMeta");
873
+ __name(hasUnmodeledTextMeta, "hasUnmodeledTextMeta");
712
874
  function mergeToolCallEvent(existing, incoming) {
713
875
  const existingData = existing.data;
714
876
  const incomingData = incoming.data;
@@ -762,6 +924,46 @@ function mergeTranscriptUpdateMeta(existing, incoming) {
762
924
  }
763
925
  __name(mergeTranscriptUpdateMeta, "mergeTranscriptUpdateMeta");
764
926
 
927
+ // packages/acp-bridge/src/session-restore-timeout.ts
928
+ init_esbuild_shims();
929
+ var DEFAULT_SESSION_RESTORE_TIMEOUT_MS = 6e4;
930
+ var MAX_SESSION_RESTORE_TIMEOUT_MS = 2147483647;
931
+ var MIN_RESTORE_RETRY_AFTER_SECONDS = 5;
932
+ var MAX_RESTORE_RETRY_AFTER_SECONDS = 120;
933
+ function restoreRetryAfterSeconds(timeoutMs) {
934
+ return Math.min(
935
+ MAX_RESTORE_RETRY_AFTER_SECONDS,
936
+ Math.max(MIN_RESTORE_RETRY_AFTER_SECONDS, Math.ceil(timeoutMs / 1e3))
937
+ );
938
+ }
939
+ __name(restoreRetryAfterSeconds, "restoreRetryAfterSeconds");
940
+ function assertValidTimeoutMs(field, timeoutMs) {
941
+ if (!Number.isFinite(timeoutMs) || !Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_SESSION_RESTORE_TIMEOUT_MS) {
942
+ throw new TypeError(
943
+ `Invalid ${field}: ${timeoutMs}. Must be a positive integer no greater than ${MAX_SESSION_RESTORE_TIMEOUT_MS}.`
944
+ );
945
+ }
946
+ }
947
+ __name(assertValidTimeoutMs, "assertValidTimeoutMs");
948
+ function resolveSessionRestoreTimeoutMs(opts) {
949
+ if (opts.sessionRestoreTimeoutMs !== void 0) {
950
+ assertValidTimeoutMs(
951
+ "sessionRestoreTimeoutMs",
952
+ opts.sessionRestoreTimeoutMs
953
+ );
954
+ return opts.sessionRestoreTimeoutMs;
955
+ }
956
+ if (opts.initializeTimeoutMs !== void 0) {
957
+ assertValidTimeoutMs("initializeTimeoutMs", opts.initializeTimeoutMs);
958
+ return Math.max(
959
+ opts.initializeTimeoutMs,
960
+ DEFAULT_SESSION_RESTORE_TIMEOUT_MS
961
+ );
962
+ }
963
+ return DEFAULT_SESSION_RESTORE_TIMEOUT_MS;
964
+ }
965
+ __name(resolveSessionRestoreTimeoutMs, "resolveSessionRestoreTimeoutMs");
966
+
765
967
  // packages/acp-bridge/src/session-source.ts
766
968
  init_esbuild_shims();
767
969
  var SESSION_SOURCE_META_KEY = "qwen.session.source";
@@ -1977,6 +2179,9 @@ var BridgeClient = class {
1977
2179
  }
1978
2180
  }
1979
2181
  async sessionUpdate(params) {
2182
+ if (this.abandonedRestoreIds.has(params.sessionId)) {
2183
+ return;
2184
+ }
1980
2185
  if (!this.ownsSession(params.sessionId) && !this.inFlightRestoreIds.has(params.sessionId)) {
1981
2186
  writeStderrLine(
1982
2187
  `[demux] session=${params.sessionId} type=session_update action=dropped reason=session_not_owned`
@@ -2147,22 +2352,19 @@ var BridgeClient = class {
2147
2352
  * stale frame for that id anywhere in the system.
2148
2353
  */
2149
2354
  tombstonedSessionIds = /* @__PURE__ */ new Map();
2355
+ /** Restore ownership for `sessionUpdate` and artifact demultiplexing. */
2356
+ inFlightRestoreIds = /* @__PURE__ */ new Set();
2150
2357
  /**
2151
- * Allow-list of sessionIds currently being restored via
2152
- * `session/load` / `session/resume`. Bypasses the tombstone check
2153
- * in `bufferEarlyEvent` so restore-time events for a
2154
- * previously-closed id flow through to the future
2155
- * `createSessionEntry -> drainEarlyEvents` call.
2156
- *
2157
- * Without this, the tombstone set before a future `load` can clear
2158
- * it via `drainEarlyEvents` would silently drop legitimate
2159
- * restore-time events (e.g. MCP discovery budget events firing
2160
- * during the ACP call window).
2161
- *
2162
- * Bridge factory enters the set before awaiting the ACP restore
2163
- * call and exits on settle (success or failure).
2358
+ * Registrations allowed to buffer early extended notifications through an
2359
+ * ordinary close tombstone. This includes restores and caller-supplied-id
2360
+ * spawns, and lasts only until their ACP registration attempt settles.
2164
2361
  */
2165
- inFlightRestoreIds = /* @__PURE__ */ new Set();
2362
+ inFlightSessionRegistrationIds = /* @__PURE__ */ new Set();
2363
+ /**
2364
+ * Restore ids whose caller timed out while the non-cancellable ACP request
2365
+ * continues.
2366
+ */
2367
+ abandonedRestoreIds = /* @__PURE__ */ new Set();
2166
2368
  /**
2167
2369
  * Handle child->bridge ACP `extMethod` requests (calls that expect a
2168
2370
  * response, unlike `extNotification`). Served methods:
@@ -2629,6 +2831,10 @@ var BridgeClient = class {
2629
2831
  * forward-compat.
2630
2832
  */
2631
2833
  async extNotification(method, params) {
2834
+ const notificationSessionId = params["sessionId"];
2835
+ if (typeof notificationSessionId === "string" && this.abandonedRestoreIds.has(notificationSessionId)) {
2836
+ return;
2837
+ }
2632
2838
  if (method === ACTIVE_WORK_NOTIFICATION_METHOD) {
2633
2839
  const snapshot = parseActiveWorkSnapshot(params);
2634
2840
  if (snapshot) {
@@ -2907,6 +3113,9 @@ var BridgeClient = class {
2907
3113
  }
2908
3114
  }
2909
3115
  publishExtNotification(sessionId, type, data, turnScoped = false) {
3116
+ if (this.abandonedRestoreIds.has(sessionId)) {
3117
+ return;
3118
+ }
2910
3119
  const entry = this.resolveEntry(sessionId);
2911
3120
  const frame = {
2912
3121
  type,
@@ -3052,9 +3261,12 @@ var BridgeClient = class {
3052
3261
  * dropped to bound per-session memory.
3053
3262
  */
3054
3263
  bufferEarlyEvent(sessionId, frame) {
3264
+ if (this.abandonedRestoreIds.has(sessionId)) {
3265
+ return;
3266
+ }
3055
3267
  const now = Date.now();
3056
3268
  this.sweepExpiredTombstones(now);
3057
- if (this.tombstonedSessionIds.has(sessionId) && !this.inFlightRestoreIds.has(sessionId)) {
3269
+ if (this.tombstonedSessionIds.has(sessionId) && !this.inFlightSessionRegistrationIds.has(sessionId)) {
3058
3270
  writeStderrLine(
3059
3271
  `qwen serve: dropping early extNotification for tombstoned session ${JSON.stringify(sessionId)} (post-close stale event)`
3060
3272
  );
@@ -3116,8 +3328,31 @@ var BridgeClient = class {
3116
3328
  * failed restore doesn't leave a dangling allow-list entry.
3117
3329
  */
3118
3330
  markRestoreInFlight(sessionId) {
3331
+ this.markSessionRegistrationInFlight(sessionId);
3119
3332
  this.inFlightRestoreIds.add(sessionId);
3120
3333
  }
3334
+ /**
3335
+ * Transfer an id from closed/abandoned ownership to a new registration
3336
+ * attempt before its ACP call starts. The in-flight allow-list is what lets
3337
+ * legitimate early notifications bypass the ordinary close tombstone until
3338
+ * `createSessionEntry` can drain them.
3339
+ */
3340
+ markSessionRegistrationInFlight(sessionId) {
3341
+ this.clearAbandonedRestoreFence(sessionId);
3342
+ this.inFlightSessionRegistrationIds.add(sessionId);
3343
+ }
3344
+ /**
3345
+ * Drop the abandoned-restore fence for `sessionId`.
3346
+ *
3347
+ * The fence has no TTL and suppresses session updates, guardrail events,
3348
+ * and child notifications, so it must not outlive the abandoned attempt it
3349
+ * was raised for. The bridge clears it whenever a legitimate owner takes
3350
+ * the id — a new restore, or `createSessionEntry` registering a session
3351
+ * from any other route.
3352
+ */
3353
+ clearAbandonedRestoreFence(sessionId) {
3354
+ this.abandonedRestoreIds.delete(sessionId);
3355
+ }
3121
3356
  /**
3122
3357
  * Companion to `markRestoreInFlight`. Bridge factory calls this when
3123
3358
  * the restore IIFE settles — after `createSessionEntry` runs
@@ -3126,6 +3361,16 @@ var BridgeClient = class {
3126
3361
  */
3127
3362
  clearRestoreInFlight(sessionId) {
3128
3363
  this.inFlightRestoreIds.delete(sessionId);
3364
+ this.clearSessionRegistrationInFlight(sessionId);
3365
+ }
3366
+ clearSessionRegistrationInFlight(sessionId) {
3367
+ this.inFlightSessionRegistrationIds.delete(sessionId);
3368
+ }
3369
+ markRestoreAbandoned(sessionId) {
3370
+ this.inFlightRestoreIds.delete(sessionId);
3371
+ this.inFlightSessionRegistrationIds.delete(sessionId);
3372
+ this.abandonedRestoreIds.add(sessionId);
3373
+ this.earlyEvents.delete(sessionId);
3129
3374
  }
3130
3375
  /**
3131
3376
  * Drain any frames buffered for `sessionId` onto `entry.events`.
@@ -6172,7 +6417,31 @@ function createAcpSessionBridge(opts) {
6172
6417
  } else {
6173
6418
  maxSessions = opts.maxSessions;
6174
6419
  }
6175
- const reserveFreshSession = /* @__PURE__ */ __name((context) => opts.freshSessionAdmission?.(context), "reserveFreshSession");
6420
+ const freshSessionBlocker = /* @__PURE__ */ __name(() => {
6421
+ for (const ci of aliveChannels) {
6422
+ if (ci.isDying) continue;
6423
+ if (ci.isQuarantined) {
6424
+ return { channel: ci, reason: "restore_cleanup_failed" };
6425
+ }
6426
+ if (ci.restoreSettlementOverdue) {
6427
+ return { channel: ci, reason: "restore_settlement_overdue" };
6428
+ }
6429
+ }
6430
+ return void 0;
6431
+ }, "freshSessionBlocker");
6432
+ const assertFreshSessionsAvailable = /* @__PURE__ */ __name(() => {
6433
+ const blocker = freshSessionBlocker();
6434
+ if (blocker) {
6435
+ throw new BridgeChannelQuarantinedError(
6436
+ blocker.reason,
6437
+ abandonedRestoreRetryAfterSeconds
6438
+ );
6439
+ }
6440
+ }, "assertFreshSessionsAvailable");
6441
+ const reserveFreshSession = /* @__PURE__ */ __name((context) => {
6442
+ assertFreshSessionsAvailable();
6443
+ return opts.freshSessionAdmission?.(context);
6444
+ }, "reserveFreshSession");
6176
6445
  const releaseFreshSessionReservation = /* @__PURE__ */ __name((reservation) => {
6177
6446
  if (!reservation) return;
6178
6447
  try {
@@ -6217,6 +6486,11 @@ function createAcpSessionBridge(opts) {
6217
6486
  `Invalid initializeTimeoutMs: ${initTimeoutMs}. Must be > 0.`
6218
6487
  );
6219
6488
  }
6489
+ const sessionRestoreTimeoutMs = resolveSessionRestoreTimeoutMs(opts);
6490
+ const restoreSettlementGraceMs = sessionRestoreTimeoutMs;
6491
+ const abandonedRestoreRetryAfterSeconds = restoreRetryAfterSeconds(
6492
+ sessionRestoreTimeoutMs
6493
+ );
6220
6494
  const permissionTimeoutRaw = opts.permissionResponseTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
6221
6495
  const permissionTimeoutMs = permissionTimeoutRaw > 0 && Number.isFinite(permissionTimeoutRaw) ? (
6222
6496
  // Clamp to 2^31-1: Node treats setTimeout delays larger than
@@ -6327,8 +6601,11 @@ function createAcpSessionBridge(opts) {
6327
6601
  try {
6328
6602
  if (!await confirmChildUnheld(entry)) return;
6329
6603
  if (byId.get(entry.sessionId) !== entry) return;
6604
+ const condemnedOwner = channelInfoForEntry(entry);
6605
+ const agentCloseTimeoutMs = condemnedOwner?.isQuarantined === true || condemnedOwner?.restoreSettlementOverdue === true ? ACTIVE_WORK_CLOSE_TIMEOUT_MS : void 0;
6330
6606
  await closeSessionImpl(entry.sessionId, void 0, {
6331
- reason: opts2.closeReason
6607
+ reason: opts2.closeReason,
6608
+ ...agentCloseTimeoutMs !== void 0 ? { agentCloseTimeoutMs } : {}
6332
6609
  }).catch((err) => {
6333
6610
  writeStderrLine(
6334
6611
  `qwen serve: deferred close (${opts2.trigger}) failed for ${JSON.stringify(entry.sessionId)}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
@@ -6343,6 +6620,7 @@ function createAcpSessionBridge(opts) {
6343
6620
  const info = channelInfoForEntry(entry);
6344
6621
  if (!info?.activeWork) return true;
6345
6622
  if (info.isDying) return false;
6623
+ if (info.isQuarantined || info.restoreSettlementOverdue) return true;
6346
6624
  try {
6347
6625
  const response = await withTimeout(
6348
6626
  entry.connection.extMethod(SERVE_CONTROL_EXT_METHODS.sessionClose, {
@@ -6506,8 +6784,35 @@ function createAcpSessionBridge(opts) {
6506
6784
  workspaceMcpResourcesCache.delete(serverName);
6507
6785
  }
6508
6786
  __name(invalidateWorkspaceMcpDetailCache, "invalidateWorkspaceMcpDetailCache");
6787
+ function channelShouldReapWhenIdle(ci) {
6788
+ return ci.emptyReapPending || ci.unsettledAbandonedRestores.size > 0 || ci.isQuarantined;
6789
+ }
6790
+ __name(channelShouldReapWhenIdle, "channelShouldReapWhenIdle");
6791
+ function armRestoreSettlementGrace(ci, sessionId, action) {
6792
+ if (ci.restoreSettlementTimers.has(sessionId)) return;
6793
+ const timer = setTimeout(() => {
6794
+ ci.restoreSettlementTimers.delete(sessionId);
6795
+ if (!ci.unsettledAbandonedRestores.has(sessionId)) return;
6796
+ if (ci.isDying || !aliveChannels.has(ci)) return;
6797
+ ci.restoreSettlementOverdue = true;
6798
+ writeStderrLine(
6799
+ `qwen serve: abandoned session/${action} for ${JSON.stringify(sessionId)} has not settled ${restoreSettlementGraceMs}ms after its deadline; refusing fresh sessions on channel ${ci.id} until it drains`
6800
+ );
6801
+ telemetry.event("session.restore.settlement_overdue", {
6802
+ "qwen-code.daemon.session_restore.action": action,
6803
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
6804
+ "qwen-code.daemon.session_restore.settlement_grace_ms": restoreSettlementGraceMs,
6805
+ "qwen-code.daemon.acp_channel.id": ci.id,
6806
+ "session.id": sessionId
6807
+ });
6808
+ void reapPendingEmptyChannel(ci);
6809
+ }, restoreSettlementGraceMs);
6810
+ timer.unref();
6811
+ ci.restoreSettlementTimers.set(sessionId, timer);
6812
+ }
6813
+ __name(armRestoreSettlementGrace, "armRestoreSettlementGrace");
6509
6814
  async function reapPendingEmptyChannel(ci) {
6510
- if (!ci.emptyReapPending || !hasNoChannelWork(ci)) return;
6815
+ if (!channelShouldReapWhenIdle(ci) || !hasNoChannelWork(ci)) return;
6511
6816
  ci.emptyReapPending = false;
6512
6817
  ci.isDying = true;
6513
6818
  await ci.channel.kill().catch(() => {
@@ -6677,6 +6982,7 @@ function createAcpSessionBridge(opts) {
6677
6982
  }
6678
6983
  }, "teeServeDebugLine");
6679
6984
  const inFlightSpawns = /* @__PURE__ */ new Map();
6985
+ const inFlightRequestedSessionSpawns = /* @__PURE__ */ new Map();
6680
6986
  const inFlightRestores = /* @__PURE__ */ new Map();
6681
6987
  const pendingRestoreEvents = /* @__PURE__ */ new Map();
6682
6988
  const createClientId = /* @__PURE__ */ __name(() => `client_${randomUUID2()}`, "createClientId");
@@ -6894,7 +7200,11 @@ function createAcpSessionBridge(opts) {
6894
7200
  workspaceMcpAuthenticationServerNames: /* @__PURE__ */ new Set(),
6895
7201
  workspaceMcpAuthenticationTimers: /* @__PURE__ */ new Map(),
6896
7202
  emptyReapPending: false,
7203
+ unsettledAbandonedRestores: /* @__PURE__ */ new Set(),
7204
+ restoreSettlementOverdue: false,
7205
+ restoreSettlementTimers: /* @__PURE__ */ new Map(),
6897
7206
  isDying: false,
7207
+ isQuarantined: false,
6898
7208
  handshakeComplete: false
6899
7209
  };
6900
7210
  infoRef.current = info;
@@ -6915,6 +7225,10 @@ function createAcpSessionBridge(opts) {
6915
7225
  }
6916
7226
  info.workspaceMcpAuthenticationTimers.clear();
6917
7227
  info.workspaceMcpAuthenticationServerNames.clear();
7228
+ for (const timer of info.restoreSettlementTimers.values()) {
7229
+ clearTimeout(timer);
7230
+ }
7231
+ info.restoreSettlementTimers.clear();
6918
7232
  aliveChannels.delete(info);
6919
7233
  if (channelInfo === info) channelInfo = void 0;
6920
7234
  const sessions = Array.from(info.sessionIds);
@@ -7076,6 +7390,9 @@ function createAcpSessionBridge(opts) {
7076
7390
  ensureChannel
7077
7391
  );
7078
7392
  ci.sessionSpawnsInFlight++;
7393
+ if (requestedSessionId !== void 0) {
7394
+ ci.client.markSessionRegistrationInFlight(requestedSessionId);
7395
+ }
7079
7396
  let sessionRegistered = false;
7080
7397
  let sessionRemovedDuringInitialization = false;
7081
7398
  let initializedSessionId;
@@ -7260,6 +7577,12 @@ function createAcpSessionBridge(opts) {
7260
7577
  ...entry.branch ? { branch: entry.branch } : {}
7261
7578
  };
7262
7579
  } finally {
7580
+ if (requestedSessionId !== void 0) {
7581
+ ci.client.clearSessionRegistrationInFlight(requestedSessionId);
7582
+ if (initializedSessionId !== requestedSessionId && !byId.has(requestedSessionId)) {
7583
+ ci.client.markSessionClosed(requestedSessionId);
7584
+ }
7585
+ }
7263
7586
  ci.sessionSpawnsInFlight = Math.max(0, ci.sessionSpawnsInFlight - 1);
7264
7587
  if (!sessionRegistered) {
7265
7588
  await reapPendingEmptyChannel(ci);
@@ -7932,6 +8255,7 @@ function createAcpSessionBridge(opts) {
7932
8255
  };
7933
8256
  ci.sessionIds.add(entry.sessionId);
7934
8257
  byId.set(entry.sessionId, entry);
8258
+ ci.client.clearAbandonedRestoreFence(entry.sessionId);
7935
8259
  touchActivity();
7936
8260
  telemetry.metrics?.sessionLifecycle("spawn");
7937
8261
  emitSessionLifecycle({
@@ -8272,19 +8596,27 @@ function createAcpSessionBridge(opts) {
8272
8596
  ...historyAnchorRecordId !== void 0 ? { historyAnchorRecordId } : {}
8273
8597
  };
8274
8598
  }
8599
+ if (inFlightRequestedSessionSpawns.has(req.sessionId)) {
8600
+ throw new RestoreInProgressError(req.sessionId, "spawn", action);
8601
+ }
8275
8602
  const inFlight = inFlightRestores.get(req.sessionId);
8276
8603
  if (inFlight) {
8277
- if (action !== inFlight.action || historyReplay !== inFlight.historyReplay || hideInheritedHistory !== inFlight.hideInheritedHistory) {
8604
+ if (inFlight.lifecycle.phase === "abandoned" || action !== inFlight.action || historyReplay !== inFlight.historyReplay || hideInheritedHistory !== inFlight.hideInheritedHistory) {
8605
+ const abandoned = inFlight.lifecycle.phase === "abandoned";
8278
8606
  throw new RestoreInProgressError(
8279
8607
  req.sessionId,
8280
8608
  inFlight.action,
8281
- action
8609
+ action,
8610
+ abandoned ? {
8611
+ reason: "awaiting_abandoned_cleanup",
8612
+ retryAfterSeconds: abandonedRestoreRetryAfterSeconds
8613
+ } : void 0
8282
8614
  );
8283
8615
  }
8284
8616
  inFlight.coalesceState.count++;
8285
8617
  let restored;
8286
8618
  try {
8287
- restored = await inFlight.promise;
8619
+ restored = await inFlight.publicPromise;
8288
8620
  } catch (err) {
8289
8621
  inFlight.coalesceState.count--;
8290
8622
  throw err;
@@ -8310,6 +8642,7 @@ function createAcpSessionBridge(opts) {
8310
8642
  hasActivePrompt: entry.promptActive
8311
8643
  };
8312
8644
  }
8645
+ assertFreshSessionsAvailable();
8313
8646
  if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
8314
8647
  throw new SessionLimitExceededError(maxSessions);
8315
8648
  }
@@ -8328,12 +8661,145 @@ function createAcpSessionBridge(opts) {
8328
8661
  admissionReleased = true;
8329
8662
  releaseFreshSessionReservation(admission);
8330
8663
  }, "releaseAdmissionOnce");
8664
+ let resolveSettlement;
8665
+ const settlementPromise = new Promise((resolve2) => {
8666
+ resolveSettlement = resolve2;
8667
+ });
8668
+ const restoreLifecycle = {
8669
+ phase: "active"
8670
+ };
8671
+ const settleAbandonedRestore = /* @__PURE__ */ __name(async (channel, lateResult) => {
8672
+ telemetry.event("session.restore.late_result", {
8673
+ "qwen-code.daemon.session_restore.action": action,
8674
+ "qwen-code.daemon.session_restore.result": lateResult,
8675
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8676
+ "qwen-code.daemon.acp_channel.id": channel.id,
8677
+ "session.id": req.sessionId
8678
+ });
8679
+ const usurper = byId.get(req.sessionId);
8680
+ if (usurper) {
8681
+ writeStderrLine(
8682
+ `qwen serve: skipping abandoned session/${action} cleanup for ${JSON.stringify(req.sessionId)}: the id is now owned by a live session`
8683
+ );
8684
+ telemetry.event("session.restore.cleanup", {
8685
+ "qwen-code.daemon.session_restore.action": action,
8686
+ "qwen-code.daemon.session_restore.cleanup_result": "id_reclaimed",
8687
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8688
+ "qwen-code.daemon.acp_channel.id": channel.id,
8689
+ "session.id": req.sessionId
8690
+ });
8691
+ channel.unsettledAbandonedRestores.delete(req.sessionId);
8692
+ const reclaimedTimer = channel.restoreSettlementTimers.get(
8693
+ req.sessionId
8694
+ );
8695
+ if (reclaimedTimer !== void 0) {
8696
+ clearTimeout(reclaimedTimer);
8697
+ channel.restoreSettlementTimers.delete(req.sessionId);
8698
+ }
8699
+ if (channel.unsettledAbandonedRestores.size === 0) {
8700
+ channel.restoreSettlementOverdue = false;
8701
+ }
8702
+ releaseAdmissionOnce();
8703
+ resolveSettlement();
8704
+ return;
8705
+ }
8706
+ try {
8707
+ if (channel.isDying || !aliveChannels.has(channel)) {
8708
+ await channel.channel.exited;
8709
+ telemetry.event("session.restore.cleanup", {
8710
+ "qwen-code.daemon.session_restore.action": action,
8711
+ "qwen-code.daemon.session_restore.cleanup_result": "transport_closed",
8712
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8713
+ "qwen-code.daemon.acp_channel.id": channel.id,
8714
+ "session.id": req.sessionId
8715
+ });
8716
+ return;
8717
+ }
8718
+ try {
8719
+ await Promise.race([
8720
+ withTimeout(
8721
+ channel.connection.extMethod(
8722
+ SERVE_CONTROL_EXT_METHODS.sessionClose,
8723
+ {
8724
+ sessionId: req.sessionId,
8725
+ drainTimeoutMs: Math.max(1, Math.floor(initTimeoutMs * 0.8))
8726
+ }
8727
+ ),
8728
+ initTimeoutMs,
8729
+ "abandonedRestoreClose"
8730
+ ),
8731
+ getChannelClosedReject(channel)
8732
+ ]);
8733
+ telemetry.event("session.restore.cleanup", {
8734
+ "qwen-code.daemon.session_restore.action": action,
8735
+ "qwen-code.daemon.session_restore.cleanup_result": "closed",
8736
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8737
+ "qwen-code.daemon.acp_channel.id": channel.id,
8738
+ "session.id": req.sessionId
8739
+ });
8740
+ } catch (error) {
8741
+ if (isAcpSessionResourceNotFound(error, req.sessionId)) {
8742
+ telemetry.event("session.restore.cleanup", {
8743
+ "qwen-code.daemon.session_restore.action": action,
8744
+ "qwen-code.daemon.session_restore.cleanup_result": "not_found",
8745
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8746
+ "qwen-code.daemon.acp_channel.id": channel.id,
8747
+ "session.id": req.sessionId
8748
+ });
8749
+ return;
8750
+ }
8751
+ if (channel.isDying || !aliveChannels.has(channel)) {
8752
+ await channel.channel.exited;
8753
+ telemetry.event("session.restore.cleanup", {
8754
+ "qwen-code.daemon.session_restore.action": action,
8755
+ "qwen-code.daemon.session_restore.cleanup_result": "transport_closed",
8756
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8757
+ "qwen-code.daemon.acp_channel.id": channel.id,
8758
+ "session.id": req.sessionId
8759
+ });
8760
+ return;
8761
+ }
8762
+ channel.isQuarantined = true;
8763
+ writeStderrLine(
8764
+ `qwen serve: quarantining ACP channel after timed-out session/${action} cleanup failed for ${JSON.stringify(req.sessionId)}: ${extractErrorMessage(error)}`
8765
+ );
8766
+ telemetry.event("session.restore.cleanup", {
8767
+ "qwen-code.daemon.session_restore.action": action,
8768
+ "qwen-code.daemon.session_restore.cleanup_result": "quarantined",
8769
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8770
+ "qwen-code.daemon.acp_channel.id": channel.id,
8771
+ "session.id": req.sessionId
8772
+ });
8773
+ if (hasNoChannelWork(channel)) {
8774
+ void killChannelWithLog(
8775
+ channel,
8776
+ `abandoned session/${action} cleanup`
8777
+ );
8778
+ }
8779
+ await channel.channel.exited;
8780
+ }
8781
+ } finally {
8782
+ channel.client.markSessionClosed(req.sessionId);
8783
+ channel.unsettledAbandonedRestores.delete(req.sessionId);
8784
+ const graceTimer = channel.restoreSettlementTimers.get(req.sessionId);
8785
+ if (graceTimer !== void 0) {
8786
+ clearTimeout(graceTimer);
8787
+ channel.restoreSettlementTimers.delete(req.sessionId);
8788
+ }
8789
+ if (channel.unsettledAbandonedRestores.size === 0) {
8790
+ channel.restoreSettlementOverdue = false;
8791
+ }
8792
+ releaseAdmissionOnce();
8793
+ resolveSettlement();
8794
+ }
8795
+ }, "settleAbandonedRestore");
8331
8796
  const promise = (async () => {
8332
8797
  pendingRestoreEvents.set(req.sessionId, restoreEvents);
8333
- ci = await ensureChannel();
8334
- ci.pendingRestoreIds.add(req.sessionId);
8335
- ci.client.markRestoreInFlight(req.sessionId);
8336
- const transportClosed = ci.channel.exited.then(() => {
8798
+ const restoreChannel = await ensureChannel();
8799
+ ci = restoreChannel;
8800
+ restoreChannel.pendingRestoreIds.add(req.sessionId);
8801
+ restoreChannel.client.markRestoreInFlight(req.sessionId);
8802
+ const transportClosed = restoreChannel.channel.exited.then(() => {
8337
8803
  throw new BridgeChannelClosedError(`during session/${action}`);
8338
8804
  });
8339
8805
  transportClosed.catch(() => {
@@ -8344,10 +8810,18 @@ function createAcpSessionBridge(opts) {
8344
8810
  let replayError;
8345
8811
  let replayHasMore;
8346
8812
  try {
8347
- if (action === "load") {
8348
- state = await Promise.race([
8349
- withTimeout(
8350
- ci.connection.loadSession({
8813
+ const rawRestore = telemetry.withSpan(
8814
+ "session.restore",
8815
+ {
8816
+ "qwen-code.daemon.bridge.operation": `session.${action}`,
8817
+ "qwen-code.daemon.session_restore.action": action,
8818
+ "qwen-code.daemon.acp_channel.id": restoreChannel.id,
8819
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8820
+ "session.id": req.sessionId
8821
+ },
8822
+ async () => {
8823
+ if (action === "load") {
8824
+ const request2 = telemetry.injectPromptContext({
8351
8825
  sessionId: req.sessionId,
8352
8826
  cwd: workspaceKey,
8353
8827
  // Restore path drops per-request `mcpServers` (matches
@@ -8356,49 +8830,88 @@ function createAcpSessionBridge(opts) {
8356
8830
  // intentionally has no `mcpServers` field for the
8357
8831
  // same reason.
8358
8832
  mcpServers: [],
8359
- ...historyReplay === "response" || hideInheritedHistory || req.sourceType ? {
8360
- _meta: {
8361
- ...sessionSourceRequestMeta(
8362
- req.sourceType,
8363
- req.sourceId
8364
- ),
8365
- ...historyReplay === "response" ? {
8366
- [LOAD_REPLAY_MODE_META_KEY]: LOAD_REPLAY_BULK_MODE,
8367
- ...req.historyPageSize !== void 0 ? {
8368
- [LOAD_REPLAY_PAGE_SIZE_META_KEY]: req.historyPageSize
8369
- } : {}
8370
- } : {},
8371
- ...hideInheritedHistory ? {
8372
- [LOAD_REPLAY_HIDE_INHERITED_META_KEY]: true
8833
+ _meta: {
8834
+ ...sessionSourceRequestMeta(req.sourceType, req.sourceId),
8835
+ ...historyReplay === "response" ? {
8836
+ [LOAD_REPLAY_MODE_META_KEY]: LOAD_REPLAY_BULK_MODE,
8837
+ ...req.historyPageSize !== void 0 ? {
8838
+ [LOAD_REPLAY_PAGE_SIZE_META_KEY]: req.historyPageSize
8373
8839
  } : {}
8374
- }
8375
- } : {}
8376
- }),
8377
- initTimeoutMs,
8378
- "loadSession"
8379
- ),
8380
- transportClosed
8381
- ]);
8382
- } else {
8383
- state = await Promise.race([
8384
- withTimeout(
8385
- ci.connection.unstable_resumeSession({
8386
- sessionId: req.sessionId,
8387
- cwd: workspaceKey,
8388
- mcpServers: [],
8389
- ...req.sourceType ? {
8390
- _meta: sessionSourceRequestMeta(
8391
- req.sourceType,
8392
- req.sourceId
8393
- )
8394
- } : {}
8395
- }),
8396
- initTimeoutMs,
8397
- "resumeSession"
8398
- ),
8399
- transportClosed
8400
- ]);
8401
- }
8840
+ } : {},
8841
+ ...hideInheritedHistory ? { [LOAD_REPLAY_HIDE_INHERITED_META_KEY]: true } : {}
8842
+ }
8843
+ });
8844
+ return await restoreChannel.connection.loadSession(request2);
8845
+ }
8846
+ const request = telemetry.injectPromptContext({
8847
+ sessionId: req.sessionId,
8848
+ cwd: workspaceKey,
8849
+ mcpServers: [],
8850
+ _meta: sessionSourceRequestMeta(req.sourceType, req.sourceId)
8851
+ });
8852
+ return await restoreChannel.connection.unstable_resumeSession(
8853
+ request
8854
+ );
8855
+ }
8856
+ );
8857
+ const observedRestore = Promise.race([rawRestore, transportClosed]);
8858
+ state = await new Promise((resolve2, reject) => {
8859
+ const timer = setTimeout(() => {
8860
+ if (restoreLifecycle.phase !== "active") return;
8861
+ restoreLifecycle.phase = "abandoned";
8862
+ restoreChannel.pendingRestoreIds.delete(req.sessionId);
8863
+ restoreChannel.client.markRestoreAbandoned(req.sessionId);
8864
+ pendingRestoreEvents.delete(req.sessionId);
8865
+ restoreEvents.close();
8866
+ restoreChannel.unsettledAbandonedRestores.add(req.sessionId);
8867
+ const channelWasEmpty = hasNoChannelWork(restoreChannel);
8868
+ telemetry.event("session.restore.public_result", {
8869
+ "qwen-code.daemon.session_restore.action": action,
8870
+ "qwen-code.daemon.session_restore.result": "timeout",
8871
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
8872
+ "qwen-code.daemon.acp_channel.id": restoreChannel.id,
8873
+ "qwen-code.daemon.session_restore.channel_was_empty": channelWasEmpty,
8874
+ "session.id": req.sessionId
8875
+ });
8876
+ writeStderrLine(
8877
+ `qwen serve: session/${action} timed out after ${sessionRestoreTimeoutMs}ms for ${JSON.stringify(req.sessionId)} on channel ${restoreChannel.id}; decision=${channelWasEmpty ? "kill_empty" : "fence_shared"}`
8878
+ );
8879
+ if (channelWasEmpty) {
8880
+ void killChannelWithLog(
8881
+ restoreChannel,
8882
+ `timed-out session/${action} on empty channel`
8883
+ );
8884
+ } else {
8885
+ armRestoreSettlementGrace(restoreChannel, req.sessionId, action);
8886
+ }
8887
+ reject(
8888
+ new SessionRestoreTimeoutError(
8889
+ req.sessionId,
8890
+ action,
8891
+ sessionRestoreTimeoutMs
8892
+ )
8893
+ );
8894
+ }, sessionRestoreTimeoutMs);
8895
+ timer.unref();
8896
+ void observedRestore.then(
8897
+ (value) => {
8898
+ if (restoreLifecycle.phase === "active") {
8899
+ clearTimeout(timer);
8900
+ resolve2(value);
8901
+ return;
8902
+ }
8903
+ void settleAbandonedRestore(restoreChannel, "success");
8904
+ },
8905
+ (error) => {
8906
+ if (restoreLifecycle.phase === "active") {
8907
+ clearTimeout(timer);
8908
+ reject(error);
8909
+ return;
8910
+ }
8911
+ void settleAbandonedRestore(restoreChannel, "failure");
8912
+ }
8913
+ );
8914
+ });
8402
8915
  if (action === "load" && historyReplay === "response") {
8403
8916
  const extracted = extractLoadReplayResponse(state);
8404
8917
  state = extracted.state;
@@ -8408,6 +8921,7 @@ function createAcpSessionBridge(opts) {
8408
8921
  replayHasMore = extracted.hasMore === true ? true : void 0;
8409
8922
  }
8410
8923
  } catch (err) {
8924
+ if (err instanceof SessionRestoreTimeoutError) throw err;
8411
8925
  restoreEvents.close();
8412
8926
  if (isAcpSessionResourceNotFound(err, req.sessionId)) {
8413
8927
  throw new SessionNotFoundError(req.sessionId);
@@ -8544,6 +9058,7 @@ function createAcpSessionBridge(opts) {
8544
9058
  ...replayFieldsFor(entry, action)
8545
9059
  };
8546
9060
  })().finally(async () => {
9061
+ if (restoreLifecycle.phase === "abandoned") return;
8547
9062
  releaseAdmissionOnce();
8548
9063
  ci?.pendingRestoreIds.delete(req.sessionId);
8549
9064
  ci?.client.clearRestoreInFlight(req.sessionId);
@@ -8573,18 +9088,48 @@ function createAcpSessionBridge(opts) {
8573
9088
  await reapPendingEmptyChannel(ci);
8574
9089
  }
8575
9090
  });
9091
+ void promise.then(
9092
+ () => {
9093
+ if (restoreLifecycle.phase === "active") {
9094
+ telemetry.event("session.restore.public_result", {
9095
+ "qwen-code.daemon.session_restore.action": action,
9096
+ "qwen-code.daemon.session_restore.result": "success",
9097
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
9098
+ ...ci ? { "qwen-code.daemon.acp_channel.id": ci.id } : {},
9099
+ "session.id": req.sessionId
9100
+ });
9101
+ resolveSettlement();
9102
+ }
9103
+ },
9104
+ () => {
9105
+ if (restoreLifecycle.phase === "active") {
9106
+ telemetry.event("session.restore.public_result", {
9107
+ "qwen-code.daemon.session_restore.action": action,
9108
+ "qwen-code.daemon.session_restore.result": "failure",
9109
+ "qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
9110
+ ...ci ? { "qwen-code.daemon.acp_channel.id": ci.id } : {},
9111
+ "session.id": req.sessionId
9112
+ });
9113
+ resolveSettlement();
9114
+ }
9115
+ }
9116
+ );
8576
9117
  inFlightRestores.set(req.sessionId, {
8577
9118
  action,
8578
9119
  historyReplay,
8579
9120
  hideInheritedHistory,
8580
- promise,
9121
+ publicPromise: promise,
9122
+ settlementPromise,
9123
+ lifecycle: restoreLifecycle,
8581
9124
  coalesceState
8582
9125
  });
8583
- try {
8584
- return await promise;
8585
- } finally {
8586
- inFlightRestores.delete(req.sessionId);
8587
- }
9126
+ void settlementPromise.finally(() => {
9127
+ const current = inFlightRestores.get(req.sessionId);
9128
+ if (current?.settlementPromise === settlementPromise) {
9129
+ inFlightRestores.delete(req.sessionId);
9130
+ }
9131
+ });
9132
+ return await promise;
8588
9133
  }
8589
9134
  __name(restoreSession, "restoreSession");
8590
9135
  async function closeSessionImpl(sessionId, context, closeOpts) {
@@ -8622,7 +9167,8 @@ function createAcpSessionBridge(opts) {
8622
9167
  entry.pendingInteractions.clear();
8623
9168
  await notifyAgentSessionClose(entry, ci, "closeSession", {
8624
9169
  throwOnFailure: true,
8625
- requireFlush: closeOpts?.requireAgentClose === true
9170
+ requireFlush: closeOpts?.requireAgentClose === true,
9171
+ ...closeOpts?.agentCloseTimeoutMs !== void 0 ? { timeoutMs: closeOpts.agentCloseTimeoutMs } : {}
8626
9172
  });
8627
9173
  } catch (error) {
8628
9174
  if (isDefinitiveAcpRequestError(error)) {
@@ -8827,7 +9373,7 @@ function createAcpSessionBridge(opts) {
8827
9373
  if (req.sessionScope !== void 0 && req.sessionScope !== "single" && req.sessionScope !== "thread") {
8828
9374
  throw new InvalidSessionScopeError(req.sessionScope);
8829
9375
  }
8830
- const effectiveScope = req.sessionScope ?? defaultSessionScope;
9376
+ const effectiveScope = req.sessionId !== void 0 ? "thread" : req.sessionScope ?? defaultSessionScope;
8831
9377
  const source = parseSessionSource(req.sourceType, req.sourceId);
8832
9378
  if ("error" in source) {
8833
9379
  throw new InvalidSessionMetadataError("sourceType", source.error);
@@ -8914,13 +9460,51 @@ function createAcpSessionBridge(opts) {
8914
9460
  };
8915
9461
  }
8916
9462
  }
9463
+ if (req.sessionId !== void 0) {
9464
+ const restoreOwner = inFlightRestores.get(req.sessionId);
9465
+ if (restoreOwner) {
9466
+ const abandoned = restoreOwner.lifecycle.phase === "abandoned";
9467
+ throw new RestoreInProgressError(
9468
+ req.sessionId,
9469
+ restoreOwner.action,
9470
+ "spawn",
9471
+ abandoned ? {
9472
+ reason: "awaiting_abandoned_cleanup",
9473
+ retryAfterSeconds: abandonedRestoreRetryAfterSeconds
9474
+ } : void 0
9475
+ );
9476
+ }
9477
+ if (inFlightRequestedSessionSpawns.has(req.sessionId)) {
9478
+ throw new RestoreInProgressError(req.sessionId, "spawn", "spawn");
9479
+ }
9480
+ }
9481
+ assertFreshSessionsAvailable();
8917
9482
  if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
8918
9483
  throw new SessionLimitExceededError(maxSessions);
8919
9484
  }
8920
- const admission = reserveFreshSession({
8921
- operation: "spawn",
8922
- workspaceCwd: workspaceKey
8923
- });
9485
+ const requestedSessionRegistrationOwner = req.sessionId !== void 0 ? Symbol(req.sessionId) : void 0;
9486
+ if (req.sessionId !== void 0 && requestedSessionRegistrationOwner !== void 0) {
9487
+ inFlightRequestedSessionSpawns.set(
9488
+ req.sessionId,
9489
+ requestedSessionRegistrationOwner
9490
+ );
9491
+ }
9492
+ const releaseRequestedSessionRegistration = /* @__PURE__ */ __name(() => {
9493
+ if (req.sessionId !== void 0 && requestedSessionRegistrationOwner !== void 0 && inFlightRequestedSessionSpawns.get(req.sessionId) === requestedSessionRegistrationOwner) {
9494
+ inFlightRequestedSessionSpawns.delete(req.sessionId);
9495
+ }
9496
+ }, "releaseRequestedSessionRegistration");
9497
+ let admission;
9498
+ try {
9499
+ admission = reserveFreshSession({
9500
+ operation: "spawn",
9501
+ workspaceCwd: workspaceKey,
9502
+ ...req.sessionId !== void 0 ? { sessionId: req.sessionId } : {}
9503
+ });
9504
+ } catch (error) {
9505
+ releaseRequestedSessionRegistration();
9506
+ throw error;
9507
+ }
8924
9508
  let admissionReleased = false;
8925
9509
  const releaseAdmissionOnce = /* @__PURE__ */ __name(() => {
8926
9510
  if (admissionReleased) return;
@@ -8947,6 +9531,7 @@ function createAcpSessionBridge(opts) {
8947
9531
  } finally {
8948
9532
  releaseAdmissionOnce();
8949
9533
  inFlightSpawns.delete(tracker);
9534
+ releaseRequestedSessionRegistration();
8950
9535
  }
8951
9536
  },
8952
9537
  // Keep this method non-async: admission failures must throw before
@@ -9528,6 +10113,7 @@ function createAcpSessionBridge(opts) {
9528
10113
  if (entry.promptActive && !isSideTask) {
9529
10114
  throw new BranchWhilePromptActiveError(sessionId);
9530
10115
  }
10116
+ assertFreshSessionsAvailable();
9531
10117
  if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
9532
10118
  throw new SessionLimitExceededError(maxSessions);
9533
10119
  }
@@ -11486,7 +12072,7 @@ function createAcpSessionBridge(opts) {
11486
12072
  )
11487
12073
  );
11488
12074
  const inFlightRestoreAwaits = Array.from(inFlightRestores.values()).map(
11489
- (restore) => restore.promise.then(
12075
+ (restore) => restore.settlementPromise.then(
11490
12076
  () => void 0,
11491
12077
  () => void 0
11492
12078
  )