@qwen-code/qwen-code 0.22.0 → 0.22.2-nightly.20260828.7357136dd1

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 (483) hide show
  1. package/bundled/computer-use/SKILL.md +229 -0
  2. package/bundled/computer-use/agents/openai.yaml +4 -0
  3. package/bundled/coordinate/SKILL.md +5 -5
  4. package/bundled/goal-draft/SKILL.md +109 -0
  5. package/bundled/qc-helper/docs/configuration/auth.md +7 -7
  6. package/bundled/qc-helper/docs/configuration/model-providers.md +70 -9
  7. package/bundled/qc-helper/docs/configuration/settings.md +48 -48
  8. package/bundled/qc-helper/docs/extension/introduction.md +3 -1
  9. package/bundled/qc-helper/docs/features/_meta.ts +1 -0
  10. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  11. package/bundled/qc-helper/docs/features/channels/dingtalk.md +12 -0
  12. package/bundled/qc-helper/docs/features/channels/dws.md +120 -0
  13. package/bundled/qc-helper/docs/features/channels/overview.md +37 -6
  14. package/bundled/qc-helper/docs/features/code-review.md +27 -23
  15. package/bundled/qc-helper/docs/features/commands.md +4 -3
  16. package/bundled/qc-helper/docs/features/computer-use.md +57 -51
  17. package/bundled/qc-helper/docs/features/goals.md +58 -0
  18. package/bundled/qc-helper/docs/features/headless.md +13 -11
  19. package/bundled/qc-helper/docs/features/mcp.md +35 -12
  20. package/bundled/qc-helper/docs/features/status-line.md +3 -3
  21. package/bundled/qc-helper/docs/features/sub-agents.md +1 -1
  22. package/bundled/qc-helper/docs/features/worktree.md +1 -1
  23. package/bundled/qc-helper/docs/overview.md +1 -1
  24. package/bundled/qc-helper/docs/quickstart.md +1 -1
  25. package/bundled/qc-helper/docs/qwen-serve.md +29 -6
  26. package/bundled/review/SKILL.md +185 -435
  27. package/bundled/review/references/aone.md +18 -0
  28. package/bundled/review/references/persistence.md +109 -0
  29. package/bundled/review/references/posting.md +272 -0
  30. package/chunks/MaxSizedBox-LMWXCLDV.js +110 -0
  31. package/chunks/{StandaloneSessionPicker-KTHPCSR6.js → StandaloneSessionPicker-W3F7U3JL.js} +87 -88
  32. package/chunks/{acp-startup-profiler-T4GEAPLX.js → acp-startup-profiler-GNYAL6LI.js} +2 -2
  33. package/chunks/{acpAgent-CRY3JZ5O.js → acpAgent-EYZ6EEHD.js} +3223 -2145
  34. package/chunks/agent-RBLGBY65.js +95 -0
  35. package/chunks/agent-headless-L5T4Y4OZ.js +85 -0
  36. package/chunks/{anthropicContentGenerator-Y2OX6LS4.js → anthropicContentGenerator-GMHML35Q.js} +128 -59
  37. package/chunks/{artifact-tool-SBXMTVCB.js → artifact-tool-XSMPHZBT.js} +11 -3
  38. package/chunks/{askUserQuestion-KEQJRFD6.js → askUserQuestion-4SWJY65V.js} +2 -2
  39. package/chunks/bridge-5LR2F2ND.js +119 -0
  40. package/chunks/{ca-D3F4S6NG.js → ca-7HPYOYSZ.js} +3 -0
  41. package/chunks/{channel-management-service-IRTT7RNE.js → channel-management-service-KHR3N6CH.js} +6 -6
  42. package/chunks/channel-settings-store-4FOAZW72.js +120 -0
  43. package/chunks/{channel-worker-group-BJNMR2MP.js → channel-worker-group-6NA6BBZV.js} +9 -7
  44. package/chunks/{channel-worker-manager-EMA7CQDJ.js → channel-worker-manager-NEZ2J6RK.js} +11 -8
  45. package/chunks/{channel-worker-supervisor-F6I6WSWW.js → channel-worker-supervisor-FKU7DIHJ.js} +12 -6
  46. package/chunks/{chunk-HDKCKCYO.js → chunk-23RFD54N.js} +1 -1
  47. package/chunks/{read-package-up-UXSW3YPB.js → chunk-2EAZ43JQ.js} +1 -0
  48. package/chunks/{chunk-KM73TBQ4.js → chunk-2LD5U7Q3.js} +31 -0
  49. package/chunks/{chunk-GIWB5QLV.js → chunk-2SXSLSQE.js} +4 -4
  50. package/chunks/chunk-2TNL5KPM.js +49 -0
  51. package/chunks/chunk-335CJSNF.js +2320 -0
  52. package/chunks/chunk-36LGBEM6.js +130 -0
  53. package/chunks/{chunk-O5BDEWBC.js → chunk-3JXM2CVW.js} +3 -3
  54. package/chunks/{chunk-2E3V7G6Y.js → chunk-3K6TUZHS.js} +55 -50
  55. package/chunks/{chunk-WWUSHZ7M.js → chunk-3OOXT6CR.js} +5 -5
  56. package/chunks/{chunk-2UZJWSVD.js → chunk-3WK3QDNV.js} +2 -2
  57. package/chunks/{chunk-4J7OPYNS.js → chunk-3XOKEVII.js} +6 -6
  58. package/chunks/chunk-3Y34Q3JV.js +1584 -0
  59. package/chunks/{chunk-YMVFIYHV.js → chunk-42IDLQWS.js} +26 -20
  60. package/chunks/{chunk-7HFULI45.js → chunk-454XFGH4.js} +3 -3
  61. package/chunks/chunk-4CMJKUND.js +95 -0
  62. package/chunks/{chunk-XLDFW44M.js → chunk-4K7KNVWH.js} +3 -3
  63. package/chunks/{chunk-YDJRMQU4.js → chunk-4QHPPXK2.js} +16 -8
  64. package/chunks/{chunk-7KOFLDEP.js → chunk-5JTIYALA.js} +1 -1
  65. package/chunks/{chunk-CXJHQVEK.js → chunk-5PA6UEYA.js} +4 -0
  66. package/chunks/{chunk-7NBVNAJJ.js → chunk-62GQFYID.js} +3 -3
  67. package/chunks/{chunk-JGUBDRBC.js → chunk-6DIGWMGT.js} +3 -3
  68. package/chunks/{chunk-X7V3N6YH.js → chunk-6JCGO55P.js} +885 -3380
  69. package/chunks/{chunk-HIK2OF33.js → chunk-6PJOTWAN.js} +1 -1
  70. package/chunks/{chunk-VUMLT7E5.js → chunk-6W2IK5KC.js} +956 -17
  71. package/chunks/{chunk-S4C4JJKE.js → chunk-6ZZBRRKQ.js} +5 -5
  72. package/chunks/{chunk-W4CRPSC5.js → chunk-7EQQR46F.js} +1 -1
  73. package/chunks/{chunk-PHJJ3RVO.js → chunk-7GWQW5ID.js} +7 -15
  74. package/chunks/chunk-7J6OTNGO.js +424 -0
  75. package/chunks/{chunk-URN2JIAQ.js → chunk-7TUBJBBJ.js} +5 -1
  76. package/chunks/{chunk-A5F63FEW.js → chunk-7VD6IPQM.js} +1 -1
  77. package/chunks/{chunk-36OF5PRW.js → chunk-ABS25QER.js} +7 -3
  78. package/chunks/{chunk-UU4WC7DK.js → chunk-AJGR6E6Z.js} +117 -30
  79. package/chunks/{chunk-MQP3MHWN.js → chunk-AU3MMVJF.js} +43 -20
  80. package/chunks/{chunk-ZS5BHEPD.js → chunk-AXC26UCQ.js} +1 -1
  81. package/chunks/{chunk-PDL6LKB5.js → chunk-AY3BNYEQ.js} +1 -1
  82. package/chunks/{chunk-O5Z7EB6Y.js → chunk-AYHQZBJ4.js} +170 -207
  83. package/chunks/{chunk-WRT324N6.js → chunk-B466ZSHZ.js} +3 -3
  84. package/chunks/{chunk-5XHAOUWD.js → chunk-B5OUL5EL.js} +3 -3
  85. package/chunks/{chunk-GAHYKJPV.js → chunk-B5PHIJGI.js} +186 -60
  86. package/chunks/{chunk-IBJ5S45N.js → chunk-B7CDU2SL.js} +2 -2
  87. package/chunks/{chunk-UZPYR3EV.js → chunk-BFPESSTR.js} +1 -1
  88. package/chunks/{chunk-43T5WDQ7.js → chunk-BFSFJR3D.js} +1 -1
  89. package/chunks/{chunk-IWOWEENB.js → chunk-BKWNKLZB.js} +404 -44
  90. package/chunks/{chunk-3CLIDIVQ.js → chunk-BOWFGCEU.js} +3 -3
  91. package/chunks/{chunk-BB5IMQCV.js → chunk-BPAKYXQ3.js} +2 -2
  92. package/chunks/{chunk-ZRYQMWEP.js → chunk-BWORX6FA.js} +2 -2
  93. package/chunks/{chunk-AP3B7LKD.js → chunk-BXDAPVQU.js} +2 -2
  94. package/chunks/{chunk-NUGZAFR2.js → chunk-C2X7KY45.js} +147 -6
  95. package/chunks/{chunk-MZKWFWVG.js → chunk-C3KURPP7.js} +6 -6
  96. package/chunks/{chunk-WZDM44SB.js → chunk-CAJTKR6W.js} +7 -7
  97. package/chunks/{chunk-DB2OKNTU.js → chunk-CFJY4DGX.js} +2 -2
  98. package/chunks/{chunk-QKBYFU2Q.js → chunk-CFKIH3D3.js} +21 -1
  99. package/chunks/{chunk-I432KXWD.js → chunk-CMHFCLBU.js} +1 -1
  100. package/chunks/{create-sub-session-XBCVGNFU.js → chunk-CQH5KTKC.js} +4 -6
  101. package/chunks/{chunk-5HJUPACR.js → chunk-CRKKHXTI.js} +185 -174
  102. package/chunks/{chunk-L4HVF7LM.js → chunk-CYAUBK46.js} +3 -3
  103. package/chunks/{chunk-AZF6SME3.js → chunk-D5LUXLUH.js} +3 -3
  104. package/chunks/{chunk-RPJQ3O4M.js → chunk-DFDWJE6Z.js} +60 -53
  105. package/chunks/{chunk-KSPRQSB4.js → chunk-DIMEPKCW.js} +52 -12
  106. package/chunks/chunk-DJBQCO2E.js +842 -0
  107. package/chunks/{chunk-OVH5Y7KS.js → chunk-DP4MWIM3.js} +19 -3
  108. package/chunks/{chunk-LI4YHTQK.js → chunk-DYXFD5RO.js} +182 -3
  109. package/chunks/{chunk-NW35NVFN.js → chunk-E3XVSVKK.js} +26 -4
  110. package/chunks/{chunk-VSNPOSDN.js → chunk-EB6QRGHM.js} +108 -13
  111. package/chunks/{chunk-FVBVJEBG.js → chunk-EKNBU2X7.js} +10 -8
  112. package/chunks/{chunk-DJEHYM4H.js → chunk-EKSCLBBF.js} +3 -3
  113. package/chunks/{chunk-624NHDGB.js → chunk-ERFDKH32.js} +11 -0
  114. package/chunks/chunk-EW5VVLJT.js +3525 -0
  115. package/chunks/{chunk-T6XLJRQY.js → chunk-EWIQ3NAE.js} +38774 -6955
  116. package/chunks/{chunk-4XPSVIED.js → chunk-FALBWZF4.js} +6 -6
  117. package/chunks/chunk-FBX2SDQ4.js +48 -0
  118. package/chunks/{chunk-VMJL7RH6.js → chunk-FEHMA4RO.js} +539 -651
  119. package/chunks/{chunk-PXOJLJ5W.js → chunk-FMFBLTLY.js} +606 -223
  120. package/chunks/{chunk-ZLCT4C5A.js → chunk-FTF2YIZ5.js} +1 -1
  121. package/chunks/{chunk-IOSEW6KP.js → chunk-G6FECKTJ.js} +9 -6
  122. package/chunks/{chunk-RDG44S5I.js → chunk-GGNE3JAW.js} +2 -2
  123. package/chunks/chunk-GYTKQYDB.js +23 -0
  124. package/chunks/{chunk-B6UBOIFE.js → chunk-H33EQVMG.js} +14 -11
  125. package/chunks/chunk-H72BQNM3.js +645 -0
  126. package/chunks/{chunk-YZBDKFRQ.js → chunk-HGIMWQVT.js} +995 -892
  127. package/chunks/chunk-HOCJDUFY.js +20 -0
  128. package/chunks/{chunk-6UQSU7CQ.js → chunk-HPXV655A.js} +60 -107
  129. package/chunks/{chunk-45NQKMYB.js → chunk-HVC3PNVC.js} +1 -1
  130. package/chunks/{chunk-QJHPWLZC.js → chunk-HYDJDQGJ.js} +1 -1
  131. package/chunks/{chunk-7DMTAQJ6.js → chunk-IB7FQJRY.js} +163 -57
  132. package/chunks/{chunk-AW27A43Y.js → chunk-ICURCKIU.js} +1428 -120
  133. package/chunks/{chunk-4F5WV4RF.js → chunk-ISKH4QX3.js} +288 -15
  134. package/chunks/{chunk-SE55HQGF.js → chunk-J6S24ZJE.js} +92 -70
  135. package/chunks/{chunk-7DYNJFES.js → chunk-JB4JIVTJ.js} +6 -1
  136. package/chunks/{chunk-OARZJFZX.js → chunk-JN4IWWMN.js} +4 -4
  137. package/chunks/{chunk-6PCOVQO2.js → chunk-JUUBLSZU.js} +8 -8
  138. package/chunks/{chunk-FEMQ6Y7W.js → chunk-JWALNCLT.js} +47 -126
  139. package/chunks/{chunk-TBVSALA3.js → chunk-K5KXUXWC.js} +3 -3
  140. package/chunks/{chunk-XYQHT3AW.js → chunk-KTJFDCX4.js} +2 -2
  141. package/chunks/{chunk-6FRJEE2S.js → chunk-LEFCFTEX.js} +6 -6
  142. package/chunks/{chunk-BUGYW6FB.js → chunk-LEGTMYAE.js} +1 -1
  143. package/chunks/{chunk-MPHLIJYL.js → chunk-LLZA2IK3.js} +20 -8
  144. package/chunks/{chunk-BEGIBJAZ.js → chunk-LNETQKBE.js} +4 -4
  145. package/chunks/{chunk-KVGR4MCF.js → chunk-LUEHOUHM.js} +3 -3
  146. package/chunks/{chunk-2A4C2MEG.js → chunk-LVPZO674.js} +35 -12
  147. package/chunks/{chunk-25NESM4G.js → chunk-M4ORUPYI.js} +29 -5
  148. package/chunks/{chunk-VFACN2CE.js → chunk-M6FOJXW3.js} +1 -1
  149. package/chunks/{chunk-FYZMB6DB.js → chunk-MAYHGRP4.js} +12 -12
  150. package/chunks/{chunk-K3LPAED5.js → chunk-MQM5PJML.js} +24 -4
  151. package/chunks/{chunk-ZRFUT5VV.js → chunk-MTJN7FOT.js} +7 -7
  152. package/chunks/{chunk-BGXZBI5B.js → chunk-N4X7G4J2.js} +2 -1
  153. package/chunks/{chunk-2TRNCJK4.js → chunk-NIFYWDYN.js} +1 -1
  154. package/chunks/{chunk-SQS55KR4.js → chunk-NU7RKEZR.js} +2 -2
  155. package/chunks/{chunk-U2UYQMM6.js → chunk-NXMBRVMQ.js} +3 -3
  156. package/chunks/chunk-OI4NY7RA.js +346 -0
  157. package/chunks/{chunk-LURJYO2T.js → chunk-OZ6KS6KW.js} +4 -0
  158. package/chunks/{chunk-K52PZNU4.js → chunk-PDQGMSZK.js} +2 -2
  159. package/chunks/{chunk-PZRUV52H.js → chunk-PPKZ7JOE.js} +20 -2
  160. package/chunks/{chunk-SAH4BD2J.js → chunk-PQEISIKS.js} +67 -0
  161. package/chunks/{chunk-AO4M6NMD.js → chunk-PWIGAMA4.js} +146 -27
  162. package/chunks/{chunk-S3G6YFQC.js → chunk-QFCDF5PL.js} +1 -1
  163. package/chunks/chunk-QHMLYMMS.js +32 -0
  164. package/chunks/{chunk-5XUTPXQU.js → chunk-QPTRRPZU.js} +47 -13
  165. package/chunks/{chunk-UUQFJILB.js → chunk-RFI4YGMR.js} +34 -267
  166. package/chunks/{chunk-A6NRNRKE.js → chunk-RFIDDFAL.js} +1 -1
  167. package/chunks/chunk-RKFGE7JH.js +93 -0
  168. package/chunks/chunk-RNVFRIOO.js +275 -0
  169. package/chunks/{chunk-WU5E4HMO.js → chunk-RU7BK6B3.js} +1 -1
  170. package/chunks/{chunk-J5ZDDUKM.js → chunk-RVXDXY6I.js} +4 -4
  171. package/chunks/{chunk-OE52YHCZ.js → chunk-RWZB422L.js} +11 -11
  172. package/chunks/chunk-RXFQM6FQ.js +42 -0
  173. package/chunks/{chunk-MHG6NDS6.js → chunk-RYNZQGXN.js} +19 -2
  174. package/chunks/{chunk-4CWDWDL6.js → chunk-SJ5ERAW3.js} +1 -1
  175. package/chunks/{chunk-Q54XG7IX.js → chunk-SMPR7SPO.js} +1 -1
  176. package/chunks/{chunk-UIRLQ3N7.js → chunk-SRZZY4IY.js} +3 -3
  177. package/chunks/{chunk-ND7NOI4P.js → chunk-STUJ7IMZ.js} +0 -92
  178. package/chunks/{chunk-VYC7XFYV.js → chunk-SUX7HDNA.js} +5 -5
  179. package/chunks/{chunk-ZZUVC6RI.js → chunk-SVNO44PF.js} +3 -3
  180. package/chunks/{chunk-FDD2IUEL.js → chunk-SZLBBZH4.js} +370 -35
  181. package/chunks/{chunk-GHY5OIYP.js → chunk-T2NKRHZZ.js} +13 -13
  182. package/chunks/chunk-T4EFG2P5.js +113 -0
  183. package/chunks/{chunk-BMCSKS37.js → chunk-TLHUNMO7.js} +6 -6
  184. package/chunks/{chunk-JOLJTKIG.js → chunk-TPI7O7HR.js} +1 -1
  185. package/chunks/{chunk-6QSA4JHL.js → chunk-TQHGJYR3.js} +4492 -1121
  186. package/chunks/{chunk-ISJMN3ML.js → chunk-TTX2JUE6.js} +1 -1
  187. package/chunks/{chunk-EFB657PR.js → chunk-TW3E6YNO.js} +3 -3
  188. package/chunks/{chunk-LD5VIJ7S.js → chunk-TWSKM647.js} +1 -1
  189. package/chunks/chunk-U54AYGEC.js +337 -0
  190. package/chunks/{chunk-A5F2YNO6.js → chunk-UHQFIS7N.js} +260 -10
  191. package/chunks/{chunk-6NFAEG54.js → chunk-UTLCH2FK.js} +24 -13
  192. package/chunks/{chunk-7JBHIQS2.js → chunk-UY3PBNY3.js} +19 -37
  193. package/chunks/{chunk-DWCKACFL.js → chunk-V2NDP3I4.js} +2 -2
  194. package/chunks/{chunk-2GXYDNXP.js → chunk-V2QDDC5J.js} +19 -9
  195. package/chunks/{chunk-VLRBJ24J.js → chunk-V5J4J5TP.js} +2 -2
  196. package/chunks/{chunk-X2UOOG5V.js → chunk-VQUGEVGR.js} +1 -1
  197. package/chunks/{chunk-RDQ7QB4Y.js → chunk-VTHREBQM.js} +2 -2
  198. package/chunks/{chunk-YLFLHKDL.js → chunk-W3N5XAZ6.js} +1 -1
  199. package/chunks/{chunk-62JOGZL5.js → chunk-W6DUQ5GA.js} +11497 -10502
  200. package/chunks/{chunk-P47E4SJC.js → chunk-WALC5VJH.js} +4 -4
  201. package/chunks/{chunk-3ZFJUBTP.js → chunk-WAOIHTJS.js} +1 -1
  202. package/chunks/{chunk-KIVGVFMM.js → chunk-WBHKK3CU.js} +16 -4
  203. package/chunks/{chunk-XZJKSETB.js → chunk-WXEA74YB.js} +3 -3
  204. package/chunks/{chunk-VEND4KA4.js → chunk-X3ZRTCJD.js} +1 -1
  205. package/chunks/{chunk-YRLW2MSX.js → chunk-XBVNNDPK.js} +11 -4
  206. package/chunks/{chunk-XL5K4SVK.js → chunk-XF63PKEN.js} +1 -1
  207. package/chunks/{chunk-LDGWX737.js → chunk-XLLQJRAH.js} +323 -510
  208. package/chunks/{chunk-2Z6LSQMF.js → chunk-XQFT3QUF.js} +1 -1
  209. package/chunks/{chunk-P3QQPMQA.js → chunk-XZA32HII.js} +4 -4
  210. package/chunks/{chunk-C72BXMJ5.js → chunk-Y3QL45LS.js} +1 -1
  211. package/chunks/{chunk-QS4ENGVF.js → chunk-Y4TPOUEV.js} +17 -8
  212. package/chunks/{chunk-AVCCKIZ6.js → chunk-YRZX2PHA.js} +1 -1
  213. package/chunks/{chunk-Z3JMO2CH.js → chunk-YTDVNSUQ.js} +1 -1
  214. package/chunks/{chunk-WS7PAXXR.js → chunk-YWQ237GX.js} +15 -199
  215. package/chunks/chunk-ZELCTN6Y.js +29 -0
  216. package/chunks/{chunk-TQOF5KBL.js → chunk-ZEZKIS2K.js} +0 -31
  217. package/chunks/{chunk-IIWGSX4L.js → chunk-ZTP35P4B.js} +1 -1
  218. package/chunks/{chunk-K623ENWT.js → chunk-ZU4UDIWX.js} +23 -1
  219. package/chunks/chunk-ZYNTSXWK.js +32 -0
  220. package/chunks/config-utils-JVGAP34H.js +113 -0
  221. package/chunks/contextCommand-XDB7OSO7.js +106 -0
  222. package/chunks/{core-runtime-CES6JSVV.js → core-runtime-XHYA2RH7.js} +66 -63
  223. package/chunks/create-sub-session-23ITIELI.js +17 -0
  224. package/chunks/{create-sub-session-UJTPMVOG.js → create-sub-session-MHYCFNCM.js} +168 -87
  225. package/chunks/{cron-create-IKA56DAF.js → cron-create-KJ4IY6PP.js} +57 -10
  226. package/chunks/{cron-delete-K5Q62EGH.js → cron-delete-MBLQCAYY.js} +4 -4
  227. package/chunks/{cron-list-QBFGAMP7.js → cron-list-DWH2PQ47.js} +4 -4
  228. package/chunks/{daemon-RZZUPGOJ.js → daemon-K5XS42ID.js} +567 -27
  229. package/chunks/{daemon-git-worktree-guard-3QY2BQYB.js → daemon-git-worktree-guard-V3P5XLHB.js} +339 -95
  230. package/chunks/daemon-status-provider-KKU7ZTLM.js +117 -0
  231. package/chunks/daemon-trust-policy-TZGK34DW.js +112 -0
  232. package/chunks/{daemon-trust-policy-monitor-TK4K7M63.js → daemon-trust-policy-monitor-F23DD2M4.js} +69 -69
  233. package/chunks/{de-RYUHH2C6.js → de-X6HLSIFE.js} +1 -0
  234. package/chunks/deferred-core-runtime-LKLGBCGZ.js +114 -0
  235. package/chunks/{display-image-OEJMJV3S.js → display-image-BE7I6ZB6.js} +5 -5
  236. package/chunks/{dist-5EV2G6MC.js → dist-4WXLCBDR.js} +1 -1
  237. package/chunks/{dist-ES6HNUW2.js → dist-5VXFRTWU.js} +525 -64
  238. package/chunks/{dist-ESS34DHC.js → dist-6BPYWHVD.js} +89 -65
  239. package/chunks/{dist-2OG3PGKO.js → dist-GFN5DCBX.js} +76 -67
  240. package/chunks/{dist-K7IQB53U.js → dist-HZNT6GQS.js} +1 -1
  241. package/chunks/{dist-J6P3C52Z.js → dist-LVZCXVPF.js} +99 -26
  242. package/chunks/{dist-LZO24N3E.js → dist-N6W6E753.js} +71 -64
  243. package/chunks/dist-QDLFKWOL.js +2512 -0
  244. package/chunks/{dist-VVQBOKDH.js → dist-SWQMYP2Q.js} +18 -16
  245. package/chunks/earlyInputCapture-NERYFYTR.js +107 -0
  246. package/chunks/{edit-A2633SLR.js → edit-ACCATIXB.js} +49 -51
  247. package/chunks/{en-3RHLPITS.js → en-YLXBXM4Z.js} +5 -1
  248. package/chunks/{enter-worktree-OIAHE2TB.js → enter-worktree-35QCAAFP.js} +7 -8
  249. package/chunks/{enterPlanMode-SUGIKLR7.js → enterPlanMode-NEN6EPVM.js} +48 -50
  250. package/chunks/environment-CKWHBC5T.js +129 -0
  251. package/chunks/errors-XTZPNQ77.js +113 -0
  252. package/chunks/{exit-worktree-3UT3SSWT.js → exit-worktree-XQD6D543.js} +7 -8
  253. package/chunks/exitPlanMode-CY344X5J.js +83 -0
  254. package/chunks/{fast-path-3AVP3G35.js → fast-path-YSOX4PAM.js} +31 -10
  255. package/chunks/{fast-path-settings-WHX3J3ZI.js → fast-path-settings-XMFBYFUH.js} +2 -2
  256. package/chunks/{fr-4PL5GHG4.js → fr-FTZWF462.js} +1 -0
  257. package/chunks/{gemini-7PVQWHTH.js → gemini-VQY2YCPH.js} +137 -129
  258. package/chunks/{geminiContentGenerator-B2FOJJDJ.js → geminiContentGenerator-PAPXNIGU.js} +16 -13
  259. package/chunks/{glob-7YGXE6OV.js → glob-GVCUSBBF.js} +48 -50
  260. package/chunks/{goal-tools-TLJCE7YZ.js → goal-tools-5STK6OXW.js} +77 -31
  261. package/chunks/{grep-6DV6LTON.js → grep-5GPICQBU.js} +6 -6
  262. package/chunks/handleAutoUpdate-ZJPJN42W.js +109 -0
  263. package/chunks/i18n-BZYKOST7.js +124 -0
  264. package/chunks/{image-gen-7CSCJ73T.js → image-gen-J6FDGUZP.js} +8 -12
  265. package/chunks/initializer-GO2C5HE3.js +113 -0
  266. package/chunks/installationInfo-WM2GXQZ6.js +107 -0
  267. package/chunks/{ja-HZ7X7PQO.js → ja-2GL5FKYJ.js} +1 -0
  268. package/chunks/{keychain-token-storage-MTFTAESK.js → keychain-token-storage-37XPR34V.js} +2 -2
  269. package/chunks/list-ERDJB7PQ.js +116 -0
  270. package/chunks/{list-agents-43XUEXJV.js → list-agents-DI3YFTDT.js} +2 -2
  271. package/chunks/loadedSettingsAdapter-7JOCVOKV.js +110 -0
  272. package/chunks/{loggingContentGenerator-RNE66CKK.js → loggingContentGenerator-3ONLU3BS.js} +327 -39
  273. package/chunks/{loop-wakeup-E54KDUXC.js → loop-wakeup-XJFONSQ7.js} +5 -5
  274. package/chunks/{ls-CGL2UC3H.js → ls-3VAT2J7A.js} +4 -4
  275. package/chunks/{lsp-5IKUO5DX.js → lsp-5W7IRUBH.js} +2 -2
  276. package/chunks/{managed-npm-update-Y3SC3GLJ.js → managed-npm-update-TLRCC2GE.js} +62 -62
  277. package/chunks/mcp-2LH3QXR2.js +110 -0
  278. package/chunks/{monitor-PXYSGSUN.js → monitor-P7LDAL4W.js} +48 -50
  279. package/chunks/nonInteractiveCli-E5T7PZ27.js +184 -0
  280. package/chunks/{notebook-edit-ISIBJVBR.js → notebook-edit-F7KSG4WQ.js} +49 -51
  281. package/chunks/open-with-auth-4UI3KHUR.js +55 -0
  282. package/chunks/{openaiContentGenerator-6TBOPEGT.js → openaiContentGenerator-2EXCZUGN.js} +29 -32
  283. package/chunks/pidfile-P25DWA5Q.js +111 -0
  284. package/chunks/process-registry-OAEG6WGC.js +662 -0
  285. package/chunks/{processUtils-YK2TDTTU.js → processUtils-PVDKBL35.js} +2 -2
  286. package/chunks/prompt-terminal-ledger-AJ7T7OIV.js +105 -0
  287. package/chunks/{pt-QT5N2Q6Q.js → pt-XN2YWJVM.js} +1 -0
  288. package/chunks/{qwenContentGenerator-CLDMA2Y4.js → qwenContentGenerator-TBBRLWIT.js} +54 -62
  289. package/chunks/{qwenOAuth2-DLDR6UC5.js → qwenOAuth2-OF5WRBQT.js} +7 -11
  290. package/chunks/read-file-6IIY4RLJ.js +32 -0
  291. package/chunks/{read-mcp-resource-XYES2B42.js → read-mcp-resource-XD257PGJ.js} +2 -2
  292. package/chunks/read-package-up-6T6ICKR7.js +13 -0
  293. package/chunks/{record-artifact-W3IBTGL7.js → record-artifact-VW23GS4F.js} +4 -5
  294. package/chunks/report-findings-XA3FJG3N.js +33 -0
  295. package/chunks/request-shutdown-BCLA3JV2.js +133 -0
  296. package/chunks/resumeHistoryUtils-44IETXDY.js +118 -0
  297. package/chunks/ripGrep-E7ESZ7SS.js +39 -0
  298. package/chunks/{ru-STMG5BPD.js → ru-OLTMFJEW.js} +1 -0
  299. package/chunks/{run-qwen-serve-XJHOW2NY.js → run-qwen-serve-DXBCYW7V.js} +924 -356
  300. package/chunks/runtime-RUSPD35D.js +148 -0
  301. package/chunks/scheduled-tasks-DVRJZO6I.js +127 -0
  302. package/chunks/scheduler-TDRB2NSY.js +122 -0
  303. package/chunks/{sdk-exporters-http-RSIOP3G2.js → sdk-exporters-http-TTU2CHBU.js} +5 -5
  304. package/chunks/{sdk-impl-CB3KARSK.js → sdk-impl-UUMVYMAL.js} +12 -6
  305. package/chunks/{send-message-J4VT46OI.js → send-message-AJ4OCUBV.js} +24 -29
  306. package/chunks/serve-KITOM7OR.js +118 -0
  307. package/chunks/{server-74ONDK62.js → server-THCOMUC2.js} +5814 -4549
  308. package/chunks/{session-BO6VBWJP.js → session-XKR5MPXE.js} +152 -142
  309. package/chunks/session-pr-refresh-KRBH7KDA.js +278 -0
  310. package/chunks/{settings-35QZNFDG.js → settings-YXZ4XBKK.js} +72 -72
  311. package/chunks/shell-5FJ2DZ3W.js +93 -0
  312. package/chunks/{skill-DKEMQSNJ.js → skill-VMMJZ6CJ.js} +161 -33
  313. package/chunks/skill-settings-7SG4YA2W.js +118 -0
  314. package/chunks/spawnChannel-BPMIXRBI.js +112 -0
  315. package/chunks/standalone-update-QN5HFRIC.js +118 -0
  316. package/chunks/{startInteractiveUI-J2QSGWPU.js → startInteractiveUI-5A7RQFRP.js} +3139 -2438
  317. package/chunks/{syntheticOutput-JAXMIMZP.js → syntheticOutput-ML43GEFN.js} +3 -3
  318. package/chunks/{task-create-I2H322E4.js → task-create-QN4LYRSE.js} +11 -11
  319. package/chunks/{task-list-3OLIWFTQ.js → task-list-JPLGK45U.js} +5 -5
  320. package/chunks/{task-stop-JAUY6MSY.js → task-stop-CXEH5L2D.js} +2 -2
  321. package/chunks/{task-update-B3XO4CPI.js → task-update-IWEOJFV2.js} +11 -11
  322. package/chunks/{team-create-W534PMGX.js → team-create-HVGVUL2L.js} +49 -51
  323. package/chunks/{team-delete-Q7GE7RRI.js → team-delete-RZVVSGCY.js} +5 -5
  324. package/chunks/{team-plan-approval-WNV6P6NG.js → team-plan-approval-S5A5FQWU.js} +48 -50
  325. package/chunks/terminal-image-renderer-SIVPPXDI.js +114 -0
  326. package/chunks/theme-manager-TA33UZZX.js +102 -0
  327. package/chunks/{todoWrite-FJJTY2TI.js → todoWrite-WDJNQEMW.js} +43 -25
  328. package/chunks/{tool-search-Y4KL3LRE.js → tool-search-NX7IPDKP.js} +19 -20
  329. package/chunks/total-session-admission-PWXZBOVX.js +114 -0
  330. package/chunks/trustedFolders-V6Y4CU3F.js +122 -0
  331. package/chunks/{update-relaunch-OHVFN6KF.js → update-relaunch-CGSX3R37.js} +6 -6
  332. package/chunks/updateCheck-T5O2WGIB.js +118 -0
  333. package/chunks/useAutoAcceptIndicator-ULBJJWPY.js +120 -0
  334. package/chunks/{validateNonInterActiveAuth-WJXH426F.js → validateNonInterActiveAuth-E5S2JSRC.js} +114 -108
  335. package/chunks/{version-QMDRADXM.js → version-LS5JPU36.js} +2 -2
  336. package/chunks/{web-fetch-ROS6P4LP.js → web-fetch-RLMFZTS3.js} +25 -244
  337. package/chunks/{web-search-JS3E76O6.js → web-search-LMCIC4N5.js} +11 -13
  338. package/chunks/{web-shell-static-3NUTRHAH.js → web-shell-static-A6QMUNNV.js} +11 -4
  339. package/chunks/webapi-Z5OM224P.js +4118 -0
  340. package/chunks/{workflow-2FCMBTBZ.js → workflow-JBXU3IGA.js} +713 -138
  341. package/chunks/workspace-providers-status-525ORQBH.js +114 -0
  342. package/chunks/{workspace-registration-store-SU4EJKSD.js → workspace-registration-store-7Y44R4LV.js} +1 -1
  343. package/chunks/workspace-registry-HS4RWUSQ.js +123 -0
  344. package/chunks/workspace-service-7PXDM6EB.js +129 -0
  345. package/chunks/workspace-skills-status-FMJGC2XI.js +113 -0
  346. package/chunks/{workspace-trust-reconciler-4Y4F7XIX.js → workspace-trust-reconciler-3YTWSQBY.js} +78 -77
  347. package/chunks/write-file-BVQRYQQO.js +88 -0
  348. package/chunks/{zh-TW-NX43Z2S2.js → zh-TW-RPTMRTHG.js} +5 -1
  349. package/chunks/{zh-3JQ75KFU.js → zh-UNY63FR3.js} +5 -1
  350. package/chunks/{zoom-image-DNBKCGGF.js → zoom-image-FGCELNS4.js} +14 -15
  351. package/cli.js +13 -13
  352. package/locales/ca.js +3 -0
  353. package/locales/de.js +1 -0
  354. package/locales/en.js +5 -0
  355. package/locales/fr.js +1 -0
  356. package/locales/ja.js +1 -0
  357. package/locales/pt.js +1 -0
  358. package/locales/ru.js +1 -0
  359. package/locales/zh-TW.js +5 -0
  360. package/locales/zh.js +5 -0
  361. package/package.json +3 -3
  362. package/web-shell/assets/{abnfDiagram-VCTEODGH-DWHXEVlf.js → abnfDiagram-VCTEODGH-2XZDeWYO.js} +1 -1
  363. package/web-shell/assets/{arc-CXKjm86V.js → arc-B6UgMh90.js} +1 -1
  364. package/web-shell/assets/{architectureDiagram-5GKGNRK7-B_ynI0cX.js → architectureDiagram-5GKGNRK7-DZgNFeN1.js} +1 -1
  365. package/web-shell/assets/{blockDiagram-NRAW4CY4-DMebd9X0.js → blockDiagram-NRAW4CY4-DQ2wvBFN.js} +1 -1
  366. package/web-shell/assets/{c4Diagram-UCG6FXSJ-BZ5BlxS-.js → c4Diagram-UCG6FXSJ-DMmQMrc4.js} +1 -1
  367. package/web-shell/assets/channel-D_TyfiTx.js +1 -0
  368. package/web-shell/assets/{chunk-2Q5K7J3B-CluJKopE.js → chunk-2Q5K7J3B-C8Zh2e9y.js} +1 -1
  369. package/web-shell/assets/{chunk-5VM5RSS4-hzDAPFOo.js → chunk-5VM5RSS4-C3LTenP8.js} +1 -1
  370. package/web-shell/assets/{chunk-F27PBJKO-6vHioKJe.js → chunk-F27PBJKO-CxABOc8n.js} +1 -1
  371. package/web-shell/assets/{chunk-G27WJ6UU-B_5hKTGo.js → chunk-G27WJ6UU-CD_JxHDC.js} +1 -1
  372. package/web-shell/assets/{chunk-JWPE2WC7-CO9VoFCH.js → chunk-JWPE2WC7-BdmZPmce.js} +1 -1
  373. package/web-shell/assets/{chunk-LCL6LL3I-7L5JpxYu.js → chunk-LCL6LL3I-80bcHmfK.js} +1 -1
  374. package/web-shell/assets/{chunk-POPQ4Y6H-DHLJMAqj.js → chunk-POPQ4Y6H-CNpLZyQF.js} +1 -1
  375. package/web-shell/assets/{chunk-SVP7TREG-Dt-4Cqdl.js → chunk-SVP7TREG-CXlKgMv3.js} +1 -1
  376. package/web-shell/assets/{chunk-XXDRQBXY-QlSQ3ssG.js → chunk-XXDRQBXY-CivyYyvL.js} +1 -1
  377. package/web-shell/assets/classDiagram-DTDB5LWJ-Bw_H3xMd.js +1 -0
  378. package/web-shell/assets/classDiagram-v2-JRS7N3AN-Bw_H3xMd.js +1 -0
  379. package/web-shell/assets/{cose-bilkent-JH36ORCC-DMw3EOxl.js → cose-bilkent-JH36ORCC-COAjRH3w.js} +1 -1
  380. package/web-shell/assets/{cynefin-OW5HDTMX-s6vEA7RQ.js → cynefin-OW5HDTMX-DqU1JHO6.js} +1 -1
  381. package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-AOKsvYLt.js → cynefinDiagram-5FMLGOSQ-BCLI1Bvj.js} +1 -1
  382. package/web-shell/assets/{dagre-3AP2YEHR-9QAZn3m7.js → dagre-3AP2YEHR-DmAz8nqF.js} +1 -1
  383. package/web-shell/assets/{diagram-S7CK7UJ4-CWpnu4FN.js → diagram-S7CK7UJ4-Ck-5QLT5.js} +1 -1
  384. package/web-shell/assets/{diagram-UQ7AKVKN-9l0jXD8q.js → diagram-UQ7AKVKN-C0ljX0mW.js} +1 -1
  385. package/web-shell/assets/{diagram-VSXAHHWV-BMUHroj4.js → diagram-VSXAHHWV-DPgvT24v.js} +1 -1
  386. package/web-shell/assets/{diagram-VX7I27RA-Co9x27vm.js → diagram-VX7I27RA-D7hWr1LR.js} +1 -1
  387. package/web-shell/assets/{diagram-Z3DM3KII-BKnTeOER.js → diagram-Z3DM3KII-D59tlOta.js} +1 -1
  388. package/web-shell/assets/{ebnfDiagram-PWID7BFC-QBZD9CKG.js → ebnfDiagram-PWID7BFC-CY2DDx00.js} +1 -1
  389. package/web-shell/assets/{erDiagram-SSCWMZ5O-dKWAEGun.js → erDiagram-SSCWMZ5O-AR4h8Q8k.js} +1 -1
  390. package/web-shell/assets/{flowDiagram-A5DVABFB-CR_UgVqj.js → flowDiagram-A5DVABFB-DbF0HqBz.js} +1 -1
  391. package/web-shell/assets/{ganttDiagram-EL5Y4UJY-DQUnjWO6.js → ganttDiagram-EL5Y4UJY-J52mrIhc.js} +1 -1
  392. package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-C4j59wPL.js → gitGraphDiagram-WWUBYQGX-CcgMY5EV.js} +1 -1
  393. package/web-shell/assets/index-BjUg3vPr.css +5 -0
  394. package/web-shell/assets/index-CFwYYVFU.js +1873 -0
  395. package/web-shell/assets/{index-tYXRIPz4.js → index-MQs7l15A.js} +1 -1
  396. package/web-shell/assets/{infoDiagram-RXCK75RN-mzqbt50w.js → infoDiagram-RXCK75RN-Buu3ibp2.js} +1 -1
  397. package/web-shell/assets/{ishikawaDiagram-5VMMS53U-ChLOqhGl.js → ishikawaDiagram-5VMMS53U-CoKQxnF3.js} +1 -1
  398. package/web-shell/assets/{journeyDiagram-EYS64GPL-SifZE-R8.js → journeyDiagram-EYS64GPL-CxK35mTC.js} +1 -1
  399. package/web-shell/assets/{kanban-definition-3QL26DDD-Sft2qlbc.js → kanban-definition-3QL26DDD-tk2CHTQ1.js} +1 -1
  400. package/web-shell/assets/{layout-O2uHVkPd.js → layout-DEpMwb4u.js} +1 -1
  401. package/web-shell/assets/{linear-BVqYgjSc.js → linear-DSQsLh53.js} +1 -1
  402. package/web-shell/assets/{mermaid.core-CZ9MQaJ6.js → mermaid.core-DIZuPBQT.js} +6 -6
  403. package/web-shell/assets/{mindmap-definition-FBJOCRG2-BNQYjBqM.js → mindmap-definition-FBJOCRG2-CCAvk8r_.js} +1 -1
  404. package/web-shell/assets/{pegDiagram-XKGWAZYB-rh1J8uv6.js → pegDiagram-XKGWAZYB-CpJ28jxz.js} +1 -1
  405. package/web-shell/assets/{pieDiagram-E7YTZNPT-BQHR5mn9.js → pieDiagram-E7YTZNPT-ziJR2R32.js} +1 -1
  406. package/web-shell/assets/{quadrantDiagram-AXDQQJYC-CLCbP7mK.js → quadrantDiagram-AXDQQJYC-B60zE3Mh.js} +1 -1
  407. package/web-shell/assets/{railroadDiagram-O6MQD6OU-CDQhrkbm.js → railroadDiagram-O6MQD6OU-M3GqQ_g1.js} +1 -1
  408. package/web-shell/assets/{requirementDiagram-EFPCY7ZU-BdP9uswg.js → requirementDiagram-EFPCY7ZU-ntCtYqTk.js} +1 -1
  409. package/web-shell/assets/{sankeyDiagram-P5KCCOFB-CFZDFBXF.js → sankeyDiagram-P5KCCOFB-AYLoItcZ.js} +1 -1
  410. package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-BW9WOJXI.js → sequenceDiagram-WJ2MYXX4-DEWk4Mlj.js} +1 -1
  411. package/web-shell/assets/{sizeCapture-X5ZJPWSS-CPMia32z.js → sizeCapture-X5ZJPWSS-OOWvzPay.js} +1 -1
  412. package/web-shell/assets/{stateDiagram-HBIQ2CUA-BANp9p7F.js → stateDiagram-HBIQ2CUA-BcMmvxem.js} +1 -1
  413. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-DRLLqPWO.js +1 -0
  414. package/web-shell/assets/{swimlanes-XN3QIQJK-JroXksK-.js → swimlanes-XN3QIQJK-DuZTWWvh.js} +1 -1
  415. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-DOfLQQYt.js +8 -0
  416. package/web-shell/assets/{timeline-definition-24CTP7MA-DfuVIfYY.js → timeline-definition-24CTP7MA-CjqtZXEd.js} +1 -1
  417. package/web-shell/assets/{vennDiagram-4TSXK5OY-BZXoSjRB.js → vennDiagram-4TSXK5OY-knVCVkQ4.js} +1 -1
  418. package/web-shell/assets/{wardleyDiagram-VM6X3IG4-BdiY8avC.js → wardleyDiagram-VM6X3IG4-yoWhw0a2.js} +1 -1
  419. package/web-shell/assets/{xychartDiagram-S5SC5T6Z-DcXh_U4H.js → xychartDiagram-S5SC5T6Z-ue14E_gL.js} +1 -1
  420. package/web-shell/index.html +20 -5
  421. package/chunks/MaxSizedBox-3OZJCC3J.js +0 -110
  422. package/chunks/agent-BFE3DQM3.js +0 -93
  423. package/chunks/agent-headless-LLVKZZ4P.js +0 -87
  424. package/chunks/bridge-EBYO4SYM.js +0 -118
  425. package/chunks/channel-settings-store-5VP2Y2YM.js +0 -115
  426. package/chunks/chunk-2J3OJGTL.js +0 -98
  427. package/chunks/chunk-7IV52LTO.js +0 -202
  428. package/chunks/chunk-AXMWHKXA.js +0 -42
  429. package/chunks/chunk-F6WFNA7U.js +0 -22
  430. package/chunks/chunk-IO257NUD.js +0 -623
  431. package/chunks/chunk-JS73NNWF.js +0 -30
  432. package/chunks/chunk-SJ4HB27T.js +0 -945
  433. package/chunks/chunk-VGHZT6JR.js +0 -51
  434. package/chunks/chunk-YHC2EYYG.js +0 -125
  435. package/chunks/computer-use-EGPWFEX6.js +0 -2142
  436. package/chunks/config-utils-WZ43VOBS.js +0 -25
  437. package/chunks/contextCommand-5DSEQI6S.js +0 -106
  438. package/chunks/daemon-status-provider-EYMLPYJU.js +0 -116
  439. package/chunks/daemon-trust-policy-CQYKZ7VO.js +0 -112
  440. package/chunks/deferred-core-runtime-WFEPUXZR.js +0 -114
  441. package/chunks/earlyInputCapture-PN4PP7V5.js +0 -107
  442. package/chunks/environment-WUPHLPKZ.js +0 -127
  443. package/chunks/errors-WPMPVIAT.js +0 -113
  444. package/chunks/exitPlanMode-MLFHYZNB.js +0 -85
  445. package/chunks/handleAutoUpdate-F5OTWUT5.js +0 -109
  446. package/chunks/i18n-C562S6KN.js +0 -124
  447. package/chunks/initializer-7YPGOFP4.js +0 -113
  448. package/chunks/installationInfo-ARU5Q2H7.js +0 -107
  449. package/chunks/list-KTSK275C.js +0 -116
  450. package/chunks/loadedSettingsAdapter-F3T2EQ5J.js +0 -110
  451. package/chunks/mcp-6ONTVPAY.js +0 -110
  452. package/chunks/nonInteractiveCli-KZDWFAN6.js +0 -178
  453. package/chunks/pidfile-IO7ALSZF.js +0 -111
  454. package/chunks/process-registry-PMJOA5CO.js +0 -172
  455. package/chunks/prompt-terminal-ledger-TCE7PMCE.js +0 -105
  456. package/chunks/read-file-2HOD2ATO.js +0 -33
  457. package/chunks/resumeHistoryUtils-DDSBAQJS.js +0 -118
  458. package/chunks/ripGrep-E7P6K4QR.js +0 -40
  459. package/chunks/runtime-J4SPTJRQ.js +0 -148
  460. package/chunks/scheduler-VRAEZZ4E.js +0 -122
  461. package/chunks/serve-KEAWV4TI.js +0 -118
  462. package/chunks/shell-H6K63WG3.js +0 -95
  463. package/chunks/skill-settings-TCKLXIXM.js +0 -118
  464. package/chunks/spawnChannel-2K6NKWM5.js +0 -111
  465. package/chunks/standalone-update-LSCGOEFP.js +0 -118
  466. package/chunks/terminal-image-renderer-UHX3UD66.js +0 -114
  467. package/chunks/theme-manager-6B47ZPIF.js +0 -102
  468. package/chunks/total-session-admission-NSCFWGJH.js +0 -113
  469. package/chunks/trustedFolders-7XMJWGQ3.js +0 -122
  470. package/chunks/updateCheck-EOVLHD4T.js +0 -118
  471. package/chunks/useAutoAcceptIndicator-ZNMIGBTN.js +0 -120
  472. package/chunks/workspace-providers-status-GPGU5YMT.js +0 -113
  473. package/chunks/workspace-registry-BQISXT6Y.js +0 -122
  474. package/chunks/workspace-service-LLY6HCUC.js +0 -129
  475. package/chunks/workspace-skills-status-L5N2Y3ZP.js +0 -113
  476. package/chunks/write-file-EJHU2Z3E.js +0 -90
  477. package/web-shell/assets/channel-Zg3WHgq_.js +0 -1
  478. package/web-shell/assets/classDiagram-DTDB5LWJ-C16l9jQz.js +0 -1
  479. package/web-shell/assets/classDiagram-v2-JRS7N3AN-C16l9jQz.js +0 -1
  480. package/web-shell/assets/index-BN_m_uHJ.css +0 -5
  481. package/web-shell/assets/index-DrlJu79f.js +0 -1792
  482. package/web-shell/assets/stateDiagram-v2-4QOOHH4V-NZYAoQLU.js +0 -1
  483. package/web-shell/assets/swimlanesDiagram-VK2B7HYN-3YdVX3vj.js +0 -8
@@ -339,6 +339,20 @@ function truncateCodePoints(str, max) {
339
339
  return cp.length > max ? cp.slice(0, max).join("") : str;
340
340
  }
341
341
  __name(truncateCodePoints, "truncateCodePoints");
342
+ function truncateUtf16Units(str, max) {
343
+ if (str.length <= max)
344
+ return str;
345
+ let kept = "";
346
+ let units = 0;
347
+ for (const ch of str) {
348
+ if (units + ch.length > max)
349
+ break;
350
+ kept += ch;
351
+ units += ch.length;
352
+ }
353
+ return kept;
354
+ }
355
+ __name(truncateUtf16Units, "truncateUtf16Units");
342
356
  function sanitizeSenderName(name) {
343
357
  const cleaned = name.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/[[\]\r\n]/g, " ");
344
358
  return truncateCodePoints(cleaned, 64).trim() || "unknown";
@@ -350,8 +364,81 @@ function sanitizeQuotedText(text, maxLen) {
350
364
  return cp.length > maxLen ? cp.slice(0, maxLen - 1).join("") + "\u2026" : cleaned;
351
365
  }
352
366
  __name(sanitizeQuotedText, "sanitizeQuotedText");
367
+ var START_OF_LINE_TAG_MAX_CONTENT = 64;
368
+ var LINE_TERMINATORS = "\r\n\u2028\u2029";
369
+ function isTagLeadBlank(ch) {
370
+ return ch !== "\r" && ch !== "\n" && /\s/.test(ch);
371
+ }
372
+ __name(isTagLeadBlank, "isTagLeadBlank");
373
+ function unwrapStartOfLineTags(text) {
374
+ if (!text.includes("["))
375
+ return text;
376
+ const deleted = new Uint8Array(text.length);
377
+ let peeled = false;
378
+ let lineStart = 0;
379
+ while (lineStart < text.length) {
380
+ let open = lineStart;
381
+ let close = lineStart;
382
+ let carried = 0;
383
+ for (; ; ) {
384
+ while (open < text.length) {
385
+ const ch = text[open];
386
+ if (ch === "\r" || ch === "\n")
387
+ break;
388
+ if (deleted[open] === 0 && !isTagLeadBlank(ch))
389
+ break;
390
+ if (open < close && deleted[open] === 0)
391
+ carried -= 1;
392
+ open += 1;
393
+ }
394
+ if (text[open] !== "[")
395
+ break;
396
+ let content = open < close ? carried - 1 : 0;
397
+ let cursor = Math.max(close, open + 1);
398
+ while (cursor < text.length) {
399
+ const ch = text[cursor];
400
+ if (ch === "]" || ch === "\r" || ch === "\n")
401
+ break;
402
+ content += 1;
403
+ if (content > START_OF_LINE_TAG_MAX_CONTENT)
404
+ break;
405
+ cursor += 1;
406
+ }
407
+ if (text[cursor] !== "]" || content < 1 || content > START_OF_LINE_TAG_MAX_CONTENT) {
408
+ break;
409
+ }
410
+ deleted[open] = 1;
411
+ deleted[cursor] = 1;
412
+ peeled = true;
413
+ open += 1;
414
+ close = cursor + 1;
415
+ carried = content;
416
+ }
417
+ let nextLine = open;
418
+ while (nextLine < text.length && !LINE_TERMINATORS.includes(text[nextLine])) {
419
+ nextLine += 1;
420
+ }
421
+ lineStart = nextLine + 1;
422
+ }
423
+ if (!peeled)
424
+ return text;
425
+ const parts = [];
426
+ let cut = 0;
427
+ for (let i = 0; i < text.length; i++) {
428
+ if (deleted[i] === 0)
429
+ continue;
430
+ if (i > cut)
431
+ parts.push(text.slice(cut, i));
432
+ cut = i + 1;
433
+ }
434
+ parts.push(text.slice(cut));
435
+ return parts.join("");
436
+ }
437
+ __name(unwrapStartOfLineTags, "unwrapStartOfLineTags");
353
438
  function sanitizePromptText(text) {
354
- return text.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/^([ \t]*)\[([^\]\r\n]{1,64})\](:?)/gm, "$1$2$3").replace(/[\u0000-\u001f\u007f]/g, " ");
439
+ const unwrapped = unwrapStartOfLineTags(text.replace(PROMPT_UNSAFE_INVISIBLES, " "));
440
+ const folded = unwrapped.replace(/[\u0000-\u001f\u007f]/g, " ");
441
+ return unwrapStartOfLineTags(folded);
355
442
  }
356
443
  __name(sanitizePromptText, "sanitizePromptText");
357
444
  function sanitizeDisplayText(text, maxLen) {
@@ -376,6 +463,18 @@ var CHANNEL_PROMPT_AUTHORIZATION_META_KEY = "qwen.daemon.channelPromptAuthorizat
376
463
  var CHANNEL_PROMPT_META_KEY = "qwen.channel.prompt";
377
464
  var ACP_PRIVATE_PARENT_CAPABILITY_META_KEY = "qwen-code/private-parent-capability";
378
465
  var ACP_PRIVATE_PARENT_CAPABILITY_ENV = "QWEN_CODE_PRIVATE_ACP_CAPABILITY";
466
+ function resolvePromptImages(options) {
467
+ const images = options?.images && options.images.length > 0 ? options.images : options?.imageBase64 && options.imageMimeType ? [{ data: options.imageBase64, mimeType: options.imageMimeType }] : [];
468
+ return images.filter((image) => !!image && typeof image.data === "string" && image.data.length > 0 && typeof image.mimeType === "string" && image.mimeType.length > 0).map((image) => {
469
+ const cleaned = image.mimeType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
470
+ return {
471
+ data: image.data,
472
+ // Normalize the alias like the daemon attachment store's own naming.
473
+ mimeType: cleaned === "image/jpg" ? "image/jpeg" : cleaned
474
+ };
475
+ });
476
+ }
477
+ __name(resolvePromptImages, "resolvePromptImages");
379
478
 
380
479
  // packages/channels/base/dist/ChannelLoopTools.js
381
480
  init_esbuild_shims();
@@ -704,11 +803,11 @@ var AcpBridge = class extends EventEmitter {
704
803
  this.on("slashCommandOutput", onSlashCommandOutput);
705
804
  this.on("responseBoundary", clearChunks);
706
805
  const prompt = [];
707
- if (options?.imageBase64 && options.imageMimeType) {
806
+ for (const image of resolvePromptImages(options)) {
708
807
  prompt.push({
709
808
  type: "image",
710
- data: options.imageBase64,
711
- mimeType: options.imageMimeType
809
+ data: image.data,
810
+ mimeType: image.mimeType
712
811
  });
713
812
  }
714
813
  prompt.push({ type: "text", text });
@@ -794,6 +893,8 @@ var AcpBridge = class extends EventEmitter {
794
893
  if (meta?.["qwenDiscreteMessage"] === true) {
795
894
  if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true && content?.type === "text" && content.text) {
796
895
  this.emit("backgroundResponse", sessionId, content.text);
896
+ } else if (meta["source"] === "vision_bridge_notice" && content?.type === "text" && content.text) {
897
+ this.emit("textChunk", sessionId, content.text);
797
898
  }
798
899
  break;
799
900
  }
@@ -1017,14 +1118,14 @@ init_esbuild_shims();
1017
1118
  // packages/channels/base/dist/PollingChannelBase.js
1018
1119
  init_esbuild_shims();
1019
1120
  import { createHash as createHash2 } from "node:crypto";
1020
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
1121
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync as renameSync5, writeFileSync as writeFileSync5 } from "node:fs";
1021
1122
  import { join as join6 } from "node:path";
1022
- import process3 from "node:process";
1123
+ import process4 from "node:process";
1023
1124
 
1024
1125
  // packages/channels/base/dist/ChannelBase.js
1025
1126
  init_esbuild_shims();
1026
1127
  import { basename as basename3, join as join5 } from "node:path";
1027
- import { randomUUID as randomUUID2 } from "node:crypto";
1128
+ import { randomUUID as randomUUID3 } from "node:crypto";
1028
1129
 
1029
1130
  // packages/channels/base/dist/BlockStreamer.js
1030
1131
  init_esbuild_shims();
@@ -1064,6 +1165,10 @@ var BlockStreamer = class {
1064
1165
  this.clearIdleTimer();
1065
1166
  this.buffer = "";
1066
1167
  }
1168
+ /** Await already-queued sends without emitting the buffered text. */
1169
+ async drain() {
1170
+ await this.sending;
1171
+ }
1067
1172
  // ---------------------------------------------------------------------------
1068
1173
  // Internal
1069
1174
  // ---------------------------------------------------------------------------
@@ -1092,8 +1197,10 @@ var BlockStreamer = class {
1092
1197
  const trimmed = text.trim();
1093
1198
  if (!trimmed)
1094
1199
  return;
1200
+ const block = /\n[^\S\n]*$/.test(text) ? `${trimmed}
1201
+ ` : trimmed;
1095
1202
  this.blockCount++;
1096
- this.sending = this.sending.then(() => this.opts.send(trimmed)).catch(() => {
1203
+ this.sending = this.sending.then(() => this.opts.send(block)).catch(() => {
1097
1204
  });
1098
1205
  }
1099
1206
  /**
@@ -1565,6 +1672,7 @@ var SessionRouter = class {
1565
1672
  defaultScope;
1566
1673
  channelScopes = /* @__PURE__ */ new Map();
1567
1674
  channelApprovalModes = /* @__PURE__ */ new Map();
1675
+ channelsWithoutLoops = /* @__PURE__ */ new Set();
1568
1676
  persistPath;
1569
1677
  recoveryMode;
1570
1678
  constructor(bridge, defaultCwd, scope = "user", persistPath, options = {}) {
@@ -1577,6 +1685,7 @@ var SessionRouter = class {
1577
1685
  /** Replace the bridge instance (used after crash recovery restart). */
1578
1686
  setBridge(bridge) {
1579
1687
  this.bridge = bridge;
1688
+ this.liveSessionIds.clear();
1580
1689
  }
1581
1690
  /** Set scope override for a specific channel. */
1582
1691
  setChannelScope(channelName, scope) {
@@ -1589,6 +1698,13 @@ var SessionRouter = class {
1589
1698
  this.channelApprovalModes.delete(channelName);
1590
1699
  }
1591
1700
  }
1701
+ setChannelLoopsEnabled(channelName, enabled) {
1702
+ if (enabled) {
1703
+ this.channelsWithoutLoops.delete(channelName);
1704
+ } else {
1705
+ this.channelsWithoutLoops.add(channelName);
1706
+ }
1707
+ }
1592
1708
  routingKey(channelName, senderId, chatId, threadId) {
1593
1709
  const scope = this.channelScopes.get(channelName) || this.defaultScope;
1594
1710
  switch (scope) {
@@ -1605,7 +1721,11 @@ var SessionRouter = class {
1605
1721
  }
1606
1722
  sessionOptions(channelName) {
1607
1723
  const approvalMode = this.channelApprovalModes.get(channelName);
1608
- return approvalMode ? { approvalMode } : void 0;
1724
+ const loopsDisabled = this.channelsWithoutLoops.has(channelName);
1725
+ return approvalMode || loopsDisabled ? {
1726
+ ...approvalMode ? { approvalMode } : {},
1727
+ ...loopsDisabled ? { enableChannelLoops: false } : {}
1728
+ } : void 0;
1609
1729
  }
1610
1730
  async resolve(channelName, senderId, chatId, threadId, cwd, isGroup, options) {
1611
1731
  const key = this.routingKey(channelName, senderId, chatId, options?.routingThreadId ?? threadId);
@@ -1792,6 +1912,120 @@ var SessionRouter = class {
1792
1912
  }
1793
1913
  return false;
1794
1914
  }
1915
+ getSessionCwd(sessionId) {
1916
+ return this.toCwd.get(sessionId);
1917
+ }
1918
+ async createManagedSession(target, cwd) {
1919
+ const loadWindow = this.beginSessionLoad();
1920
+ const lifecycleGeneration = this.lifecycleGeneration;
1921
+ const bridge = this.bridge;
1922
+ const bindingToken = {};
1923
+ try {
1924
+ let lastDeadSessionId;
1925
+ for (let attempt = 0; attempt < 2; attempt++) {
1926
+ const sessionId = await bridge.newSession(cwd, {
1927
+ ...this.sessionOptions(target.channelName),
1928
+ sourceId: target.channelName
1929
+ }, bindingToken);
1930
+ if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
1931
+ this.scheduleManagedDiscard(bridge, sessionId, bindingToken);
1932
+ throw new Error("Managed session creation was invalidated");
1933
+ }
1934
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
1935
+ throw new Error("Invalid session ID from bridge");
1936
+ }
1937
+ if (loadWindow.delete(sessionId)) {
1938
+ lastDeadSessionId = sessionId;
1939
+ await bridge.discardSession?.(sessionId, bindingToken);
1940
+ continue;
1941
+ }
1942
+ this.toTarget.set(sessionId, target);
1943
+ this.toCwd.set(sessionId, cwd);
1944
+ this.liveSessionIds.add(sessionId);
1945
+ return sessionId;
1946
+ }
1947
+ throw new Error(`Managed session ${lastDeadSessionId ?? "unknown"} died before creation completed`);
1948
+ } finally {
1949
+ this.endSessionLoad(loadWindow);
1950
+ }
1951
+ }
1952
+ async loadManagedSession(sessionId, target, cwd) {
1953
+ if (this.liveSessionIds.has(sessionId)) {
1954
+ this.toTarget.set(sessionId, target);
1955
+ this.toCwd.set(sessionId, cwd);
1956
+ return { loaded: false };
1957
+ }
1958
+ const loadWindow = this.beginSessionLoad();
1959
+ const lifecycleGeneration = this.lifecycleGeneration;
1960
+ const bridge = this.bridge;
1961
+ const bindingToken = {};
1962
+ let loadedSessionId;
1963
+ try {
1964
+ loadedSessionId = await bridge.loadSession(sessionId, cwd, this.sessionOptions(target.channelName), bindingToken);
1965
+ if (lifecycleGeneration !== this.lifecycleGeneration || bridge !== this.bridge) {
1966
+ this.scheduleManagedDiscard(bridge, loadedSessionId, bindingToken);
1967
+ loadedSessionId = void 0;
1968
+ throw new Error("Managed session load was invalidated");
1969
+ }
1970
+ if (loadedSessionId !== sessionId) {
1971
+ const unexpectedSessionId = loadedSessionId;
1972
+ await bridge.discardSession?.(unexpectedSessionId, bindingToken);
1973
+ loadedSessionId = void 0;
1974
+ throw new Error(`Bridge returned session ${unexpectedSessionId || "unknown"} while loading ${sessionId}`);
1975
+ }
1976
+ if (loadWindow.delete(sessionId)) {
1977
+ throw new Error(`Managed session ${sessionId} died before loading completed`);
1978
+ }
1979
+ this.toTarget.set(sessionId, target);
1980
+ this.toCwd.set(sessionId, cwd);
1981
+ this.liveSessionIds.add(sessionId);
1982
+ return { loaded: true };
1983
+ } catch (error) {
1984
+ if (loadedSessionId) {
1985
+ await bridge.discardSession?.(loadedSessionId, bindingToken).catch(() => void 0);
1986
+ }
1987
+ throw error;
1988
+ } finally {
1989
+ this.endSessionLoad(loadWindow);
1990
+ }
1991
+ }
1992
+ activateManagedSession(sessionId, target, cwd) {
1993
+ const key = this.routingKey(target.channelName, target.senderId, target.chatId, target.threadId);
1994
+ if (this.toSession.get(key) === sessionId)
1995
+ return;
1996
+ this.invalidateRouteOperation(key);
1997
+ this.toSession.set(key, sessionId);
1998
+ this.toTarget.set(sessionId, target);
1999
+ this.toCwd.set(sessionId, cwd);
2000
+ this.persist();
2001
+ }
2002
+ forgetManagedSession(sessionId) {
2003
+ let changed = false;
2004
+ for (const [key, mappedSessionId] of this.toSession) {
2005
+ if (mappedSessionId !== sessionId)
2006
+ continue;
2007
+ this.invalidateRouteOperation(key);
2008
+ this.toSession.delete(key);
2009
+ changed = true;
2010
+ }
2011
+ changed = this.toTarget.delete(sessionId) || changed;
2012
+ changed = this.toCwd.delete(sessionId) || changed;
2013
+ changed = this.liveSessionIds.delete(sessionId) || changed;
2014
+ if (changed)
2015
+ this.persist();
2016
+ }
2017
+ async detachManagedSession(sessionId) {
2018
+ try {
2019
+ if (this.liveSessionIds.has(sessionId)) {
2020
+ if (!this.bridge.discardSession) {
2021
+ throw new Error("Managed session detach is not supported");
2022
+ }
2023
+ await this.bridge.discardSession(sessionId);
2024
+ }
2025
+ } finally {
2026
+ this.forgetManagedSession(sessionId);
2027
+ }
2028
+ }
1795
2029
  /**
1796
2030
  * Remove session(s) for the given sender. Returns the removed session IDs.
1797
2031
  */
@@ -1966,6 +2200,7 @@ var SessionRouter = class {
1966
2200
  this.toSession.set(key, sessionId);
1967
2201
  this.toTarget.set(sessionId, entry.target);
1968
2202
  this.toCwd.set(sessionId, entry.cwd);
2203
+ this.liveSessionIds.add(sessionId);
1969
2204
  reservation.resolve(sessionId);
1970
2205
  if (sessionId !== entry.sessionId) {
1971
2206
  changed = true;
@@ -2189,6 +2424,12 @@ var SessionRouter = class {
2189
2424
  } catch {
2190
2425
  }
2191
2426
  }
2427
+ scheduleManagedDiscard(bridge, sessionId, bindingToken) {
2428
+ try {
2429
+ void bridge.discardSession?.(sessionId, bindingToken).catch(() => void 0);
2430
+ } catch {
2431
+ }
2432
+ }
2192
2433
  createSessionReservation() {
2193
2434
  let resolveReservation;
2194
2435
  let rejectReservation;
@@ -2207,6 +2448,615 @@ var SessionRouter = class {
2207
2448
  }
2208
2449
  };
2209
2450
 
2451
+ // packages/channels/base/dist/named-session-manager.js
2452
+ init_esbuild_shims();
2453
+ import { randomUUID as randomUUID2 } from "node:crypto";
2454
+ import { chmodSync as chmodSync3, existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync4, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
2455
+ import { dirname as dirname4 } from "node:path";
2456
+ import process3 from "node:process";
2457
+ var REGISTRY_VERSION = 1;
2458
+ var MAX_OPEN_TASKS = 8;
2459
+ var TASK_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
2460
+ var NamedSessionManager = class {
2461
+ static {
2462
+ __name(this, "NamedSessionManager");
2463
+ }
2464
+ channelName;
2465
+ cwd;
2466
+ canonicalCwd;
2467
+ filePath;
2468
+ router;
2469
+ isBusy;
2470
+ now;
2471
+ registry;
2472
+ ownerOperations = /* @__PURE__ */ new Map();
2473
+ constructor(options) {
2474
+ this.channelName = options.channelName;
2475
+ this.cwd = options.cwd;
2476
+ this.canonicalCwd = canonicalizeWorkspacePath(options.cwd);
2477
+ this.filePath = options.filePath;
2478
+ this.router = options.router;
2479
+ this.isBusy = options.isBusy;
2480
+ this.now = options.now ?? Date.now;
2481
+ this.registry = this.readRegistry();
2482
+ }
2483
+ resolve(input, expectedSessionId, reserve) {
2484
+ return this.withOwnerLock(input, () => this.resolveLocked(input, expectedSessionId, reserve));
2485
+ }
2486
+ resolveAfterPreparation(input, prepare, needsSession, reserve) {
2487
+ return this.withOwnerLock(input, async () => {
2488
+ if (await prepare() === false)
2489
+ return { status: "aborted" };
2490
+ if (!needsSession())
2491
+ return { status: "bypassed" };
2492
+ try {
2493
+ return {
2494
+ status: "resolved",
2495
+ sessionId: await this.resolveLocked(input, void 0, reserve)
2496
+ };
2497
+ } catch (error) {
2498
+ return { status: "resolve_error", error };
2499
+ }
2500
+ });
2501
+ }
2502
+ list(input, includeClosed) {
2503
+ return this.withOwnerLock(input, async () => {
2504
+ const owner = await this.ensureOwner(input, false);
2505
+ if (!owner)
2506
+ return [];
2507
+ return owner.tasks.filter((task) => includeClosed || task.status === "open").map((task) => this.view(owner, task));
2508
+ });
2509
+ }
2510
+ current(input) {
2511
+ return this.withOwnerLock(input, async () => {
2512
+ const owner = await this.ensureOwner(input, false);
2513
+ if (!owner?.activeTaskName)
2514
+ return void 0;
2515
+ const task = this.findTask(owner, owner.activeTaskName);
2516
+ return task ? this.selection(owner, task) : void 0;
2517
+ });
2518
+ }
2519
+ create(input, name) {
2520
+ return this.withOwnerLock(input, async () => {
2521
+ this.validateName(name);
2522
+ const existingOwner = await this.ensureOwner(input, false);
2523
+ const owner = existingOwner ?? this.createOwner(input, null, []);
2524
+ if (this.findTask(owner, name)) {
2525
+ throw new Error(`Task "${name}" already exists.`);
2526
+ }
2527
+ if (this.openTaskCount(owner) >= MAX_OPEN_TASKS) {
2528
+ throw new Error("You already have eight open tasks. Close one before creating another.");
2529
+ }
2530
+ this.assertCanLeaveSelected(owner, void 0);
2531
+ const timestamp = this.nextTimestamp(owner);
2532
+ const target = this.target(input);
2533
+ const sessionId = await this.createSession(target, this.cwd, `Could not create task "${name}".`);
2534
+ const task = {
2535
+ name,
2536
+ sessionId,
2537
+ cwd: this.cwd,
2538
+ isolation: "shared",
2539
+ status: "open",
2540
+ target,
2541
+ createdAt: timestamp,
2542
+ updatedAt: timestamp,
2543
+ lastSelectedAt: timestamp
2544
+ };
2545
+ const nextOwner = {
2546
+ ...owner,
2547
+ activeTaskName: name,
2548
+ tasks: [...owner.tasks, task]
2549
+ };
2550
+ try {
2551
+ this.commitOwner(nextOwner);
2552
+ } catch (error) {
2553
+ await this.router.detachManagedSession(sessionId).catch(() => void 0);
2554
+ throw error;
2555
+ }
2556
+ this.router.activateManagedSession(sessionId, target, this.cwd);
2557
+ return this.selection(nextOwner, task);
2558
+ });
2559
+ }
2560
+ use(input, name) {
2561
+ return this.withOwnerLock(input, async () => {
2562
+ const owner = await this.ensureOwner(input, false);
2563
+ if (!owner)
2564
+ throw new Error("No named tasks exist in this chat.");
2565
+ const task = this.findTask(owner, name);
2566
+ if (!task)
2567
+ throw new Error(`Task "${name}" was not found.`);
2568
+ this.assertCanLeaveSelected(owner, task.name);
2569
+ if (this.isBusy(task.sessionId)) {
2570
+ throw new Error(`Task "${task.name}" is still running or waiting for permission.`);
2571
+ }
2572
+ if (task.status === "closed" && this.openTaskCount(owner) >= MAX_OPEN_TASKS) {
2573
+ throw new Error("You already have eight open tasks. Close one before reopening another.");
2574
+ }
2575
+ const timestamp = this.nextTimestamp(owner);
2576
+ const loaded = await this.loadTask(task, `Could not load task "${task.name}". The current task was not changed.`);
2577
+ const updatedTask = {
2578
+ ...task,
2579
+ status: "open",
2580
+ updatedAt: timestamp,
2581
+ lastSelectedAt: timestamp
2582
+ };
2583
+ const nextOwner = this.replaceTask(owner, updatedTask, task.name);
2584
+ try {
2585
+ this.commitOwner(nextOwner);
2586
+ } catch (error) {
2587
+ if (loaded) {
2588
+ await this.router.detachManagedSession(task.sessionId).catch(() => void 0);
2589
+ }
2590
+ throw error;
2591
+ }
2592
+ this.router.activateManagedSession(task.sessionId, task.target, task.cwd);
2593
+ return this.selection(nextOwner, updatedTask);
2594
+ });
2595
+ }
2596
+ close(input, name) {
2597
+ return this.withOwnerLock(input, async () => {
2598
+ const owner = await this.ensureOwner(input, false);
2599
+ if (!owner)
2600
+ throw new Error("No named tasks exist in this chat.");
2601
+ const task = this.findTask(owner, name);
2602
+ if (!task)
2603
+ throw new Error(`Task "${name}" was not found.`);
2604
+ if (task.status === "closed") {
2605
+ throw new Error(`Task "${task.name}" is already closed.`);
2606
+ }
2607
+ if (this.isBusy(task.sessionId)) {
2608
+ throw new Error(`Task "${task.name}" is still running or waiting for permission.`);
2609
+ }
2610
+ const wasActive = this.sameName(owner.activeTaskName, task.name);
2611
+ const timestamp = this.nextTimestamp(owner);
2612
+ const replacement = wasActive ? owner.tasks.filter((candidate) => candidate.status === "open" && !this.sameName(candidate.name, task.name)).sort((a, b) => b.lastSelectedAt - a.lastSelectedAt)[0] : void 0;
2613
+ let replacementLoaded = false;
2614
+ if (replacement) {
2615
+ if (this.isBusy(replacement.sessionId)) {
2616
+ throw new Error(`Task "${replacement.name}" is still running or waiting for permission.`);
2617
+ }
2618
+ replacementLoaded = await this.loadTask(replacement, `Could not load fallback task "${replacement.name}". Task "${task.name}" was not closed.`);
2619
+ }
2620
+ const closedTask = {
2621
+ ...task,
2622
+ status: "closed",
2623
+ updatedAt: timestamp
2624
+ };
2625
+ let nextOwner = this.replaceTask(owner, closedTask, wasActive ? replacement?.name ?? null : owner.activeTaskName);
2626
+ const selectedReplacement = replacement ? {
2627
+ ...replacement,
2628
+ updatedAt: timestamp,
2629
+ lastSelectedAt: timestamp
2630
+ } : void 0;
2631
+ if (selectedReplacement) {
2632
+ nextOwner = this.replaceTask(nextOwner, selectedReplacement, selectedReplacement.name);
2633
+ }
2634
+ try {
2635
+ this.commitOwner(nextOwner);
2636
+ } catch (error) {
2637
+ if (replacement && replacementLoaded) {
2638
+ await this.router.detachManagedSession(replacement.sessionId).catch(() => void 0);
2639
+ }
2640
+ throw error;
2641
+ }
2642
+ if (replacement) {
2643
+ this.router.activateManagedSession(replacement.sessionId, replacement.target, replacement.cwd);
2644
+ }
2645
+ try {
2646
+ await this.router.detachManagedSession(task.sessionId);
2647
+ } catch (error) {
2648
+ this.commitOwner(owner);
2649
+ this.router.forgetManagedSession(task.sessionId);
2650
+ await this.loadTask(task, `Task "${task.name}" could not be restored after close failed.`);
2651
+ if (wasActive) {
2652
+ this.router.activateManagedSession(task.sessionId, task.target, task.cwd);
2653
+ }
2654
+ throw new Error(`Failed to close task "${task.name}".`, {
2655
+ cause: error
2656
+ });
2657
+ }
2658
+ const activeTask = nextOwner.activeTaskName ? this.findTask(nextOwner, nextOwner.activeTaskName) : void 0;
2659
+ return {
2660
+ closed: this.view(nextOwner, closedTask),
2661
+ ...activeTask ? { active: this.view(nextOwner, activeTask) } : {}
2662
+ };
2663
+ });
2664
+ }
2665
+ reset(input) {
2666
+ return this.withOwnerLock(input, async () => {
2667
+ const owner = await this.ensureOwner(input, false);
2668
+ if (!owner?.activeTaskName)
2669
+ return void 0;
2670
+ const task = this.findTask(owner, owner.activeTaskName);
2671
+ if (!task || task.status !== "open")
2672
+ return void 0;
2673
+ const timestamp = this.nextTimestamp(owner);
2674
+ const sessionId = await this.createSession(task.target, task.cwd, `Could not reset task "${task.name}".`);
2675
+ const updatedTask = {
2676
+ ...task,
2677
+ sessionId,
2678
+ updatedAt: timestamp,
2679
+ lastSelectedAt: timestamp
2680
+ };
2681
+ const nextOwner = this.replaceTask(owner, updatedTask, task.name);
2682
+ try {
2683
+ this.commitOwner(nextOwner);
2684
+ } catch (error) {
2685
+ await this.router.detachManagedSession(sessionId).catch(() => void 0);
2686
+ throw error;
2687
+ }
2688
+ this.router.activateManagedSession(sessionId, updatedTask.target, updatedTask.cwd);
2689
+ this.router.forgetManagedSession(task.sessionId);
2690
+ return {
2691
+ name: task.name,
2692
+ previousSessionId: task.sessionId,
2693
+ sessionId
2694
+ };
2695
+ });
2696
+ }
2697
+ async ensureOwner(input, createDefault) {
2698
+ const existing = this.getOwner(input);
2699
+ if (existing)
2700
+ return existing;
2701
+ const sessionId = this.router.getSession(this.channelName, input.senderId, input.chatId);
2702
+ const routedTarget = sessionId ? this.router.getTarget(sessionId) : void 0;
2703
+ if (sessionId && routedTarget && (routedTarget.channelName !== this.channelName || routedTarget.chatId !== input.chatId || routedTarget.senderId !== input.senderId)) {
2704
+ this.adoptForeignLegacyRoute(sessionId, routedTarget);
2705
+ }
2706
+ if (sessionId && routedTarget?.channelName === this.channelName && routedTarget.chatId === input.chatId && routedTarget.senderId === input.senderId) {
2707
+ const routedCwd = this.router.getSessionCwd(sessionId);
2708
+ if (routedCwd !== void 0 && !this.isCurrentCwd(routedCwd)) {
2709
+ await this.router.detachManagedSession(sessionId).catch(() => void 0);
2710
+ } else {
2711
+ const timestamp2 = this.nextTimestamp();
2712
+ const task2 = {
2713
+ name: "default",
2714
+ sessionId,
2715
+ cwd: routedCwd ?? this.cwd,
2716
+ isolation: "shared",
2717
+ status: "open",
2718
+ target: routedTarget,
2719
+ createdAt: timestamp2,
2720
+ updatedAt: timestamp2,
2721
+ lastSelectedAt: timestamp2
2722
+ };
2723
+ const adopted = this.createOwner(input, task2.name, [task2]);
2724
+ this.commitOwner(adopted);
2725
+ return adopted;
2726
+ }
2727
+ }
2728
+ if (!createDefault)
2729
+ return void 0;
2730
+ const target = this.target(input);
2731
+ const timestamp = this.nextTimestamp();
2732
+ const createdSessionId = await this.createSession(target, this.cwd, "Could not create the default task.");
2733
+ const task = {
2734
+ name: "default",
2735
+ sessionId: createdSessionId,
2736
+ cwd: this.cwd,
2737
+ isolation: "shared",
2738
+ status: "open",
2739
+ target,
2740
+ createdAt: timestamp,
2741
+ updatedAt: timestamp,
2742
+ lastSelectedAt: timestamp
2743
+ };
2744
+ const created = this.createOwner(input, task.name, [task]);
2745
+ try {
2746
+ this.commitOwner(created);
2747
+ } catch (error) {
2748
+ await this.router.detachManagedSession(createdSessionId).catch(() => void 0);
2749
+ throw error;
2750
+ }
2751
+ this.router.activateManagedSession(createdSessionId, target, this.cwd);
2752
+ return created;
2753
+ }
2754
+ async resolveLocked(input, expectedSessionId, reserve) {
2755
+ const owner = await this.ensureOwner(input, true);
2756
+ if (!owner?.activeTaskName)
2757
+ return void 0;
2758
+ const task = this.findTask(owner, owner.activeTaskName);
2759
+ if (!task || task.status !== "open") {
2760
+ throw new Error("The selected Channel task is unavailable.");
2761
+ }
2762
+ if (expectedSessionId !== void 0 && task.sessionId !== expectedSessionId) {
2763
+ return void 0;
2764
+ }
2765
+ const release = reserve?.(task.sessionId);
2766
+ try {
2767
+ await this.loadTask(task, `Could not load task "${task.name}". No replacement session was created.`);
2768
+ this.router.activateManagedSession(task.sessionId, task.target, task.cwd);
2769
+ return task.sessionId;
2770
+ } catch (error) {
2771
+ release?.();
2772
+ throw error;
2773
+ }
2774
+ }
2775
+ adoptForeignLegacyRoute(sessionId, target) {
2776
+ const cwd = this.router.getSessionCwd(sessionId);
2777
+ if (target.channelName !== this.channelName || cwd === void 0 || !this.isCurrentCwd(cwd)) {
2778
+ this.router.forgetManagedSession(sessionId);
2779
+ return;
2780
+ }
2781
+ const existing = this.getOwner(target);
2782
+ if (existing) {
2783
+ if (existing.tasks.some((task2) => task2.sessionId === sessionId))
2784
+ return;
2785
+ this.router.forgetManagedSession(sessionId);
2786
+ return;
2787
+ }
2788
+ const timestamp = this.nextTimestamp();
2789
+ const task = {
2790
+ name: "default",
2791
+ sessionId,
2792
+ cwd,
2793
+ isolation: "shared",
2794
+ status: "open",
2795
+ target,
2796
+ createdAt: timestamp,
2797
+ updatedAt: timestamp,
2798
+ lastSelectedAt: timestamp
2799
+ };
2800
+ this.commitOwner(this.createOwner(target, task.name, [task]));
2801
+ }
2802
+ assertCanLeaveSelected(owner, nextTaskName) {
2803
+ if (!owner.activeTaskName || nextTaskName && this.sameName(owner.activeTaskName, nextTaskName)) {
2804
+ return;
2805
+ }
2806
+ const selected = this.findTask(owner, owner.activeTaskName);
2807
+ if (selected && this.isBusy(selected.sessionId)) {
2808
+ throw new Error(`Task "${selected.name}" is still running or waiting for permission.`);
2809
+ }
2810
+ }
2811
+ async loadTask(task, failureMessage) {
2812
+ try {
2813
+ return (await this.router.loadManagedSession(task.sessionId, task.target, task.cwd)).loaded;
2814
+ } catch (error) {
2815
+ throw new Error(failureMessage, { cause: error });
2816
+ }
2817
+ }
2818
+ async createSession(target, cwd, failureMessage) {
2819
+ try {
2820
+ return await this.router.createManagedSession(target, cwd);
2821
+ } catch (error) {
2822
+ throw new Error(failureMessage, { cause: error });
2823
+ }
2824
+ }
2825
+ withOwnerLock(input, operation) {
2826
+ const key = JSON.stringify([
2827
+ this.channelName,
2828
+ input.chatId,
2829
+ input.senderId
2830
+ ]);
2831
+ const previous = this.ownerOperations.get(key) ?? Promise.resolve();
2832
+ const result = previous.catch(() => void 0).then(operation);
2833
+ const tail = result.then(() => void 0, () => void 0);
2834
+ this.ownerOperations.set(key, tail);
2835
+ return result.finally(() => {
2836
+ if (this.ownerOperations.get(key) === tail) {
2837
+ this.ownerOperations.delete(key);
2838
+ }
2839
+ });
2840
+ }
2841
+ getOwner(input) {
2842
+ const owner = this.registry.owners.find((candidate) => candidate.channelName === this.channelName && candidate.chatId === input.chatId && candidate.senderId === input.senderId);
2843
+ return owner ? this.cloneOwner(owner) : void 0;
2844
+ }
2845
+ createOwner(input, activeTaskName, tasks) {
2846
+ return {
2847
+ channelName: this.channelName,
2848
+ chatId: input.chatId,
2849
+ senderId: input.senderId,
2850
+ activeTaskName,
2851
+ tasks
2852
+ };
2853
+ }
2854
+ target(input) {
2855
+ return {
2856
+ channelName: this.channelName,
2857
+ senderId: input.senderId,
2858
+ chatId: input.chatId,
2859
+ ...input.threadId !== void 0 ? { threadId: input.threadId } : {},
2860
+ ...input.isGroup !== void 0 ? { isGroup: input.isGroup } : {}
2861
+ };
2862
+ }
2863
+ findTask(owner, name) {
2864
+ const normalized = this.normalizeName(name);
2865
+ return owner.tasks.find((task) => this.normalizeName(task.name) === normalized);
2866
+ }
2867
+ replaceTask(owner, task, activeTaskName) {
2868
+ return {
2869
+ ...owner,
2870
+ activeTaskName,
2871
+ tasks: owner.tasks.map((candidate) => this.sameName(candidate.name, task.name) ? task : candidate)
2872
+ };
2873
+ }
2874
+ view(owner, task) {
2875
+ return {
2876
+ name: task.name,
2877
+ status: task.status,
2878
+ isolation: task.isolation,
2879
+ active: task.status === "open" && this.sameName(owner.activeTaskName, task.name)
2880
+ };
2881
+ }
2882
+ selection(owner, task) {
2883
+ return { ...this.view(owner, task), sessionId: task.sessionId };
2884
+ }
2885
+ openTaskCount(owner) {
2886
+ return owner.tasks.filter((task) => task.status === "open").length;
2887
+ }
2888
+ nextTimestamp(owner) {
2889
+ const now = this.now();
2890
+ if (!Number.isSafeInteger(now) || now < 0) {
2891
+ throw new Error("Invalid named-session clock value.");
2892
+ }
2893
+ let timestamp = now;
2894
+ for (const task of owner?.tasks ?? []) {
2895
+ timestamp = Math.max(timestamp, task.createdAt + 1, task.updatedAt + 1, task.lastSelectedAt + 1);
2896
+ }
2897
+ if (!Number.isSafeInteger(timestamp)) {
2898
+ throw new Error("Named-session timestamp limit reached.");
2899
+ }
2900
+ return timestamp;
2901
+ }
2902
+ validateName(name) {
2903
+ if (!TASK_NAME_PATTERN.test(name)) {
2904
+ throw new Error("Task names must be 1-32 ASCII letters, numbers, underscores, or hyphens and start with a letter or number.");
2905
+ }
2906
+ }
2907
+ normalizeName(name) {
2908
+ return name.toLowerCase();
2909
+ }
2910
+ sameName(a, b) {
2911
+ return a !== null && this.normalizeName(a) === this.normalizeName(b);
2912
+ }
2913
+ cloneOwner(owner) {
2914
+ return {
2915
+ ...owner,
2916
+ tasks: owner.tasks.map((task) => ({
2917
+ ...task,
2918
+ target: { ...task.target }
2919
+ }))
2920
+ };
2921
+ }
2922
+ commitOwner(owner) {
2923
+ const owners = this.registry.owners.map((candidate) => candidate.channelName === owner.channelName && candidate.chatId === owner.chatId && candidate.senderId === owner.senderId ? owner : candidate);
2924
+ if (!owners.some((candidate) => candidate.channelName === owner.channelName && candidate.chatId === owner.chatId && candidate.senderId === owner.senderId)) {
2925
+ owners.push(owner);
2926
+ }
2927
+ const next = { version: REGISTRY_VERSION, owners };
2928
+ if (!this.isRegistry(next)) {
2929
+ throw new Error("Invalid named-session registry update.");
2930
+ }
2931
+ this.writeRegistry(next);
2932
+ this.registry = next;
2933
+ }
2934
+ readRegistry() {
2935
+ if (!existsSync4(this.filePath)) {
2936
+ return { version: REGISTRY_VERSION, owners: [] };
2937
+ }
2938
+ let value;
2939
+ try {
2940
+ value = JSON.parse(readFileSync4(this.filePath, "utf8"));
2941
+ } catch (error) {
2942
+ throw new Error(`Failed to read named-session registry: ${this.filePath}`, {
2943
+ cause: error
2944
+ });
2945
+ }
2946
+ if (!this.isRegistry(value)) {
2947
+ if (this.isRegistry(value, false)) {
2948
+ const stalePath = `${this.filePath}.stale-${randomUUID2()}`;
2949
+ try {
2950
+ renameSync4(this.filePath, stalePath);
2951
+ } catch (error) {
2952
+ throw new Error("Failed to archive stale named-session registry.", {
2953
+ cause: error
2954
+ });
2955
+ }
2956
+ process3.stderr.write("[NamedSessionManager] Archived a stale registry after the channel working directory changed.\n");
2957
+ return { version: REGISTRY_VERSION, owners: [] };
2958
+ }
2959
+ throw new Error(`Invalid named-session registry: ${this.filePath}`);
2960
+ }
2961
+ return value;
2962
+ }
2963
+ writeRegistry(registry) {
2964
+ const dir = dirname4(this.filePath);
2965
+ const tempPath = `${this.filePath}.${process3.pid}-${randomUUID2()}.tmp`;
2966
+ try {
2967
+ mkdirSync4(dir, { recursive: true, mode: 448 });
2968
+ try {
2969
+ chmodSync3(dir, 448);
2970
+ } catch {
2971
+ }
2972
+ writeFileSync4(tempPath, JSON.stringify(registry, null, 2), {
2973
+ encoding: "utf8",
2974
+ mode: 384
2975
+ });
2976
+ renameSync4(tempPath, this.filePath);
2977
+ try {
2978
+ chmodSync3(this.filePath, 384);
2979
+ } catch {
2980
+ }
2981
+ } catch (error) {
2982
+ throw new Error("Failed to persist named-session registry.", {
2983
+ cause: error
2984
+ });
2985
+ } finally {
2986
+ try {
2987
+ rmSync2(tempPath, { force: true });
2988
+ } catch {
2989
+ }
2990
+ }
2991
+ }
2992
+ isRegistry(value, requireCurrentCwd = true) {
2993
+ if (!this.isRecord(value) || value["version"] !== REGISTRY_VERSION) {
2994
+ return false;
2995
+ }
2996
+ const owners = value["owners"];
2997
+ if (!Array.isArray(owners))
2998
+ return false;
2999
+ const ownerKeys = /* @__PURE__ */ new Set();
3000
+ const sessionIds = /* @__PURE__ */ new Set();
3001
+ for (const owner of owners) {
3002
+ if (!this.isOwner(owner, ownerKeys, sessionIds, requireCurrentCwd)) {
3003
+ return false;
3004
+ }
3005
+ }
3006
+ return true;
3007
+ }
3008
+ isOwner(value, ownerKeys, sessionIds, requireCurrentCwd) {
3009
+ if (!this.isRecord(value))
3010
+ return false;
3011
+ const channelName = value["channelName"];
3012
+ const chatId = value["chatId"];
3013
+ const senderId = value["senderId"];
3014
+ const activeTaskName = value["activeTaskName"];
3015
+ const tasks = value["tasks"];
3016
+ if (channelName !== this.channelName || typeof chatId !== "string" || typeof senderId !== "string" || activeTaskName !== null && typeof activeTaskName !== "string" || !Array.isArray(tasks)) {
3017
+ return false;
3018
+ }
3019
+ const ownerKey = JSON.stringify([channelName, chatId, senderId]);
3020
+ if (ownerKeys.has(ownerKey))
3021
+ return false;
3022
+ ownerKeys.add(ownerKey);
3023
+ const names = /* @__PURE__ */ new Set();
3024
+ let openTasks = 0;
3025
+ let activeFound = activeTaskName === null;
3026
+ for (const task of tasks) {
3027
+ if (!this.isTask(task, channelName, chatId, senderId, requireCurrentCwd)) {
3028
+ return false;
3029
+ }
3030
+ const normalized = this.normalizeName(task.name);
3031
+ if (names.has(normalized) || sessionIds.has(task.sessionId))
3032
+ return false;
3033
+ names.add(normalized);
3034
+ sessionIds.add(task.sessionId);
3035
+ if (task.status === "open")
3036
+ openTasks++;
3037
+ if (activeTaskName !== null && task.status === "open" && this.sameName(activeTaskName, task.name)) {
3038
+ activeFound = true;
3039
+ }
3040
+ }
3041
+ return openTasks <= MAX_OPEN_TASKS && activeFound;
3042
+ }
3043
+ isTask(value, channelName, chatId, senderId, requireCurrentCwd) {
3044
+ if (!this.isRecord(value) || !this.isRecord(value["target"]))
3045
+ return false;
3046
+ const target = value["target"];
3047
+ return typeof value["name"] === "string" && TASK_NAME_PATTERN.test(value["name"]) && typeof value["sessionId"] === "string" && value["sessionId"].length > 0 && typeof value["cwd"] === "string" && (!requireCurrentCwd || this.isCurrentCwd(value["cwd"])) && value["isolation"] === "shared" && (value["status"] === "open" || value["status"] === "closed") && this.isTimestamp(value["createdAt"]) && this.isTimestamp(value["updatedAt"]) && this.isTimestamp(value["lastSelectedAt"]) && target["channelName"] === channelName && target["chatId"] === chatId && target["senderId"] === senderId && (target["threadId"] === void 0 || typeof target["threadId"] === "string") && (target["isGroup"] === void 0 || typeof target["isGroup"] === "boolean");
3048
+ }
3049
+ isCurrentCwd(cwd) {
3050
+ return canonicalizeWorkspacePath(cwd) === this.canonicalCwd;
3051
+ }
3052
+ isTimestamp(value) {
3053
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
3054
+ }
3055
+ isRecord(value) {
3056
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3057
+ }
3058
+ };
3059
+
2210
3060
  // packages/channels/base/dist/ChannelLoopScheduler.js
2211
3061
  init_esbuild_shims();
2212
3062
  var MAX_RESULT_PREVIEW_LENGTH = 500;
@@ -2901,6 +3751,7 @@ var ChannelBase = class {
2901
3751
  groupPairingNotified = /* @__PURE__ */ new Map();
2902
3752
  loopController;
2903
3753
  observedContacts;
3754
+ namedSessions;
2904
3755
  observedContactEnvelopes = /* @__PURE__ */ new WeakSet();
2905
3756
  instructedSessions = /* @__PURE__ */ new Set();
2906
3757
  unattendedMemorySessions = /* @__PURE__ */ new Set();
@@ -2909,6 +3760,8 @@ var ChannelBase = class {
2909
3760
  commands = /* @__PURE__ */ new Map();
2910
3761
  /** Per-session promise chain to serialize prompt + send (followup mode). */
2911
3762
  sessionQueues = /* @__PURE__ */ new Map();
3763
+ queuedTurns = /* @__PURE__ */ new Map();
3764
+ namedTurnBindings = /* @__PURE__ */ new WeakMap();
2912
3765
  registerBridgeEvents;
2913
3766
  bridgeRecovery;
2914
3767
  /**
@@ -2985,7 +3838,16 @@ var ChannelBase = class {
2985
3838
  await this.pushProactive(target, text);
2986
3839
  return;
2987
3840
  }
2988
- await this.sendResponseMessage(target.chatId, text, sessionId);
3841
+ await this.deliverBackgroundReply(target.chatId, text, sessionId);
3842
+ }
3843
+ /**
3844
+ * Fallback delivery of a background response when proactive send is
3845
+ * unavailable. Adapters whose turn replies bypass sendResponseMessage (to
3846
+ * stay out of turn-scoped streaming state, for example) override only this
3847
+ * step instead of re-implementing the whole dispatch flow.
3848
+ */
3849
+ async deliverBackgroundReply(chatId, text, sessionId) {
3850
+ await this.sendResponseMessage(chatId, text, sessionId);
2989
3851
  }
2990
3852
  async dispatchPermissionRequest(event) {
2991
3853
  const target = this.permissionTargetForEvent(event);
@@ -3206,6 +4068,21 @@ var ChannelBase = class {
3206
4068
  this.dmGate = new DmGate(config.dmPolicy);
3207
4069
  this.gate = new SenderGate(config.senderPolicy, config.allowedUsers, pairingStore);
3208
4070
  this.router = options?.router || new SessionRouter(bridge, config.cwd, config.sessionScope);
4071
+ if (config.multiSession) {
4072
+ if (config.sessionScope !== "user") {
4073
+ throw new Error(`Channel "${name}" requires sessionScope "user" when multiSession is enabled.`);
4074
+ }
4075
+ if (!options?.stateDir) {
4076
+ throw new Error(`Channel "${name}" multiSession is available only in daemon-managed mode.`);
4077
+ }
4078
+ this.namedSessions = new NamedSessionManager({
4079
+ channelName: name,
4080
+ cwd: config.cwd,
4081
+ filePath: join5(options.stateDir, "named-sessions.json"),
4082
+ router: this.router,
4083
+ isBusy: /* @__PURE__ */ __name((sessionId) => this.isNamedSessionBusy(sessionId), "isBusy")
4084
+ });
4085
+ }
3209
4086
  this.registerSharedCommands();
3210
4087
  if (this.loopController) {
3211
4088
  bridge.registerChannelLoopToolHandler?.(this.channelLoopToolHandler);
@@ -3369,7 +4246,7 @@ var ChannelBase = class {
3369
4246
  ensureOutputSegment(sessionId, active) {
3370
4247
  if (!active.owner)
3371
4248
  return void 0;
3372
- const segmentId = active.activeSegmentId ?? randomUUID2();
4249
+ const segmentId = active.activeSegmentId ?? randomUUID3();
3373
4250
  const context = this.outputSegmentContext(sessionId, active, segmentId);
3374
4251
  if (context)
3375
4252
  active.activeSegmentId = segmentId;
@@ -3598,8 +4475,11 @@ var ChannelBase = class {
3598
4475
  imageBase64: void 0,
3599
4476
  imageMimeType: void 0
3600
4477
  };
4478
+ if (this.namedSessions) {
4479
+ this.bindNamedTurn(syntheticEnvelope, sessionId);
4480
+ }
3601
4481
  this.markPreflighted(syntheticEnvelope);
3602
- this.processInbound(syntheticEnvelope).catch((err) => {
4482
+ void this.processPreflightedInbound(syntheticEnvelope).catch((err) => {
3603
4483
  process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) after ${taskLabel} for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
3604
4484
  `);
3605
4485
  });
@@ -3695,7 +4575,7 @@ ${promptText}` : promptText;
3695
4575
  doneResolve = resolve3;
3696
4576
  });
3697
4577
  const promptState = {
3698
- runId: randomUUID2(),
4578
+ runId: randomUUID3(),
3699
4579
  cancelled: false,
3700
4580
  done,
3701
4581
  resolve: doneResolve,
@@ -3911,7 +4791,7 @@ ${promptText}` : promptText;
3911
4791
  doneResolve = resolve3;
3912
4792
  });
3913
4793
  const promptState = {
3914
- runId: randomUUID2(),
4794
+ runId: randomUUID3(),
3915
4795
  cancelled: false,
3916
4796
  done,
3917
4797
  resolve: doneResolve,
@@ -4292,7 +5172,7 @@ ${promptText}` : promptText;
4292
5172
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can cancel requests in this shared session.");
4293
5173
  return true;
4294
5174
  }
4295
- const activeSessionId = this.findActiveSessionId(envelope);
5175
+ const activeSessionId = this.namedSessions ? await this.findNamedActiveSessionId(envelope) : this.findActiveSessionId(envelope);
4296
5176
  if (!activeSessionId) {
4297
5177
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No request is currently running.");
4298
5178
  return true;
@@ -4517,10 +5397,203 @@ ${requestList}`);
4517
5397
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, accepted ? decision === "approve" ? "Permission approved." : decision === "approve-always" ? "Permission approved always." : "Permission denied." : "Permission request is no longer pending.");
4518
5398
  return true;
4519
5399
  }
5400
+ namedSessionOwner(envelope) {
5401
+ return {
5402
+ senderId: envelope.senderId,
5403
+ chatId: envelope.chatId,
5404
+ ...envelope.threadId !== void 0 ? { threadId: envelope.threadId } : {},
5405
+ ...envelope.isGroup !== void 0 ? { isGroup: envelope.isGroup } : {}
5406
+ };
5407
+ }
5408
+ async currentSessionId(envelope) {
5409
+ if (this.namedSessions) {
5410
+ return (await this.namedSessions.current(this.namedSessionOwner(envelope)))?.sessionId;
5411
+ }
5412
+ return this.router.getSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5413
+ }
5414
+ reserveQueuedTurn(sessionId) {
5415
+ this.queuedTurns.set(sessionId, (this.queuedTurns.get(sessionId) ?? 0) + 1);
5416
+ }
5417
+ releaseQueuedTurn(sessionId) {
5418
+ const remaining = (this.queuedTurns.get(sessionId) ?? 1) - 1;
5419
+ if (remaining === 0) {
5420
+ this.queuedTurns.delete(sessionId);
5421
+ } else {
5422
+ this.queuedTurns.set(sessionId, remaining);
5423
+ }
5424
+ }
5425
+ bindNamedTurn(envelope, sessionId) {
5426
+ const binding = {
5427
+ sessionId,
5428
+ generation: this.sessionGenerations.get(sessionId) ?? 0,
5429
+ claimed: false,
5430
+ released: false
5431
+ };
5432
+ this.namedTurnBindings.set(envelope, binding);
5433
+ this.reserveQueuedTurn(sessionId);
5434
+ return binding;
5435
+ }
5436
+ releaseNamedTurnBinding(binding) {
5437
+ if (binding.sessionId === null || binding.claimed || binding.released) {
5438
+ return;
5439
+ }
5440
+ binding.released = true;
5441
+ this.releaseQueuedTurn(binding.sessionId);
5442
+ }
5443
+ finishNamedTurnBinding(envelope) {
5444
+ const binding = this.namedTurnBindings.get(envelope);
5445
+ if (!binding)
5446
+ return;
5447
+ this.releaseNamedTurnBinding(binding);
5448
+ this.namedTurnBindings.delete(envelope);
5449
+ }
5450
+ bypassesNamedTurnBinding(envelope) {
5451
+ const parsed = this.parseCommand(envelope.text);
5452
+ if (parsed && this.commands.has(parsed.command))
5453
+ return true;
5454
+ const bangText = envelope.text.trimStart();
5455
+ return bangText.startsWith("!") && (envelope.isGroup || this.isSharedSession(envelope));
5456
+ }
5457
+ async prepareNamedTurnBinding(envelope) {
5458
+ const namedSessions = this.namedSessions;
5459
+ if (!namedSessions || this.namedTurnBindings.has(envelope))
5460
+ return true;
5461
+ if (this.bypassesNamedTurnBinding(envelope))
5462
+ return true;
5463
+ try {
5464
+ const sessionId = await namedSessions.resolve(this.namedSessionOwner(envelope), void 0, (resolvedSessionId) => {
5465
+ const binding = this.bindNamedTurn(envelope, resolvedSessionId);
5466
+ return () => this.releaseNamedTurnBinding(binding);
5467
+ });
5468
+ if (!sessionId && !this.namedTurnBindings.has(envelope)) {
5469
+ this.namedTurnBindings.set(envelope, {
5470
+ sessionId: null,
5471
+ generation: 0,
5472
+ claimed: false,
5473
+ released: true
5474
+ });
5475
+ }
5476
+ return true;
5477
+ } catch (error) {
5478
+ this.finishNamedTurnBinding(envelope);
5479
+ await this.sendNamedSessionError(envelope, error);
5480
+ return false;
5481
+ }
5482
+ }
5483
+ isNamedSessionBusy(sessionId) {
5484
+ if ((this.queuedTurns.get(sessionId) ?? 0) > 0)
5485
+ return true;
5486
+ if (this.activePrompts.has(sessionId))
5487
+ return true;
5488
+ for (const permission of this.pendingPermissions.values()) {
5489
+ if (permission.sessionId === sessionId)
5490
+ return true;
5491
+ }
5492
+ try {
5493
+ return this.bridge.listSessions?.().some((session) => session.sessionId === sessionId && session.hasActivePrompt) ?? false;
5494
+ } catch {
5495
+ return true;
5496
+ }
5497
+ }
5498
+ async sendNamedSessionError(envelope, error) {
5499
+ const message = error instanceof Error ? sanitizeDisplayText(error.message, 500) : "Named-session operation failed.";
5500
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, message || "Named-session operation failed.");
5501
+ }
5502
+ async handleNamedSessionsCommand(envelope, args) {
5503
+ const namedSessions = this.namedSessions;
5504
+ if (!namedSessions)
5505
+ return false;
5506
+ const normalized = args.trim().toLowerCase();
5507
+ if (normalized !== "" && normalized !== "all") {
5508
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Usage: /sessions [all]");
5509
+ return true;
5510
+ }
5511
+ try {
5512
+ const tasks = await namedSessions.list(this.namedSessionOwner(envelope), normalized === "all");
5513
+ if (tasks.length === 0) {
5514
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, normalized === "all" ? "No named tasks." : "No open named tasks.");
5515
+ return true;
5516
+ }
5517
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, [
5518
+ normalized === "all" ? "Tasks:" : "Open tasks:",
5519
+ ...tasks.map((task) => `${task.active ? "*" : "-"} ${task.name} (${task.status}, ${task.isolation})`)
5520
+ ].join("\n"));
5521
+ } catch (error) {
5522
+ await this.sendNamedSessionError(envelope, error);
5523
+ }
5524
+ return true;
5525
+ }
5526
+ async handleNamedSessionCommand(envelope, args) {
5527
+ const namedSessions = this.namedSessions;
5528
+ if (!namedSessions)
5529
+ return false;
5530
+ const parts = args.trim().split(/\s+/u).filter(Boolean);
5531
+ const subcommand = parts.shift()?.toLowerCase() ?? "";
5532
+ const owner = this.namedSessionOwner(envelope);
5533
+ try {
5534
+ switch (subcommand) {
5535
+ case "current": {
5536
+ if (parts.length > 0)
5537
+ break;
5538
+ const current = await namedSessions.current(owner);
5539
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, current ? `Current task: ${current.name} (${current.isolation})` : "No task is currently selected. Use /session new <name> or /session use <name>.");
5540
+ return true;
5541
+ }
5542
+ case "new": {
5543
+ if (parts.includes("--worktree")) {
5544
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Worktree tasks are not available in Part 2 yet. Create a shared task with /session new <name>.");
5545
+ return true;
5546
+ }
5547
+ if (parts.length !== 1)
5548
+ break;
5549
+ const created = await namedSessions.create(owner, parts[0]);
5550
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Created and selected task "${created.name}" (shared workspace).`);
5551
+ return true;
5552
+ }
5553
+ case "use": {
5554
+ if (parts.length !== 1)
5555
+ break;
5556
+ const selected = await namedSessions.use(owner, parts[0]);
5557
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Selected task "${selected.name}" (${selected.isolation} workspace).`);
5558
+ return true;
5559
+ }
5560
+ case "close": {
5561
+ if (parts.length !== 1)
5562
+ break;
5563
+ const result = await namedSessions.close(owner, parts[0]);
5564
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, result.active ? `Closed task "${result.closed.name}". Selected "${result.active.name}".` : `Closed task "${result.closed.name}". No task is selected.`);
5565
+ return true;
5566
+ }
5567
+ case "cancel":
5568
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Named task cancellation is not available in Part 2 yet. Wait for the selected task to finish before switching; Telegram users can use /cancel.");
5569
+ return true;
5570
+ default:
5571
+ break;
5572
+ }
5573
+ } catch (error) {
5574
+ await this.sendNamedSessionError(envelope, error);
5575
+ return true;
5576
+ }
5577
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Usage: /session current | /session new <name> | /session use <name> | /session close <name> | /session cancel [<name>]");
5578
+ return true;
5579
+ }
4520
5580
  /** Register shared slash commands. Called from constructor. */
4521
5581
  registerSharedCommands() {
4522
5582
  const doClear = /* @__PURE__ */ __name(async (envelope) => {
4523
- const removedIds = this.router.removeSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5583
+ let resetTaskName;
5584
+ let removedIds;
5585
+ if (this.namedSessions) {
5586
+ try {
5587
+ const reset = await this.namedSessions.reset(this.namedSessionOwner(envelope));
5588
+ resetTaskName = reset?.name;
5589
+ removedIds = reset ? [reset.previousSessionId] : [];
5590
+ } catch (error) {
5591
+ await this.sendNamedSessionError(envelope, error);
5592
+ return;
5593
+ }
5594
+ } else {
5595
+ removedIds = this.router.removeSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5596
+ }
4524
5597
  this.clearPendingGroupHistory(envelope);
4525
5598
  if (removedIds.length > 0) {
4526
5599
  for (const id of removedIds) {
@@ -4566,7 +5639,7 @@ ${requestList}`);
4566
5639
  }
4567
5640
  this.discardRetiredSession(this.bridge, id, "cleared");
4568
5641
  }
4569
- await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Session cleared. The next message starts a fresh conversation.");
5642
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, resetTaskName ? `Task "${resetTaskName}" reset with a fresh conversation.` : "Session cleared. The next message starts a fresh conversation.");
4570
5643
  } else {
4571
5644
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No active session to clear.");
4572
5645
  }
@@ -4586,6 +5659,10 @@ ${requestList}`);
4586
5659
  this.registerCommand("clear", clearHandler);
4587
5660
  this.registerCommand("reset", clearHandler);
4588
5661
  this.registerCommand("new", clearHandler);
5662
+ if (this.namedSessions) {
5663
+ this.registerCommand("sessions", (envelope, args) => this.handleNamedSessionsCommand(envelope, args));
5664
+ this.registerCommand("session", (envelope, args) => this.handleNamedSessionCommand(envelope, args));
5665
+ }
4589
5666
  this.registerCommand("approve", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve"));
4590
5667
  this.registerCommand("approve-always", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve-always"));
4591
5668
  this.registerCommand("deny", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "deny"));
@@ -4594,7 +5671,7 @@ ${requestList}`);
4594
5671
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can view this shared session.");
4595
5672
  return true;
4596
5673
  }
4597
- const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5674
+ const active = this.namedSessions ? Boolean(await this.currentSessionId(envelope)) : this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
4598
5675
  const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
4599
5676
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, [
4600
5677
  `Channel: ${this.name}`,
@@ -4619,7 +5696,11 @@ ${requestList}`);
4619
5696
  "/status \u2014 Show session info",
4620
5697
  "/approve [request-id] \u2014 Approve a pending permission request",
4621
5698
  "/approve-always [request-id] \u2014 Always approve a pending permission request",
4622
- "/deny [request-id] \u2014 Deny a pending permission request"
5699
+ "/deny [request-id] \u2014 Deny a pending permission request",
5700
+ ...this.namedSessions ? [
5701
+ "/sessions [all] \u2014 List your named tasks",
5702
+ "/session current|new|use|close \u2014 Manage your named tasks"
5703
+ ] : []
4623
5704
  ];
4624
5705
  const sharedCmds = /* @__PURE__ */ new Set([
4625
5706
  "help",
@@ -4633,7 +5714,9 @@ ${requestList}`);
4633
5714
  "channel-memory",
4634
5715
  "forget-channel",
4635
5716
  "who",
4636
- "status"
5717
+ "status",
5718
+ "sessions",
5719
+ "session"
4637
5720
  ]);
4638
5721
  const platformCmds = [...this.commands.keys()].filter((c) => !sharedCmds.has(c));
4639
5722
  if (platformCmds.length > 0) {
@@ -4641,7 +5724,7 @@ ${requestList}`);
4641
5724
  lines.push(`/${cmd}`);
4642
5725
  }
4643
5726
  }
4644
- const sessionId = this.router.getSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5727
+ const sessionId = await this.currentSessionId(envelope);
4645
5728
  const agentCommands = sessionId ? this.getAgentCommandsForSession(sessionId) : this.bridge.availableCommands;
4646
5729
  if (agentCommands.length > 0) {
4647
5730
  lines.push("", "Agent commands (forwarded to Qwen Code):");
@@ -4658,7 +5741,7 @@ ${requestList}`);
4658
5741
  await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can view this shared session.");
4659
5742
  return true;
4660
5743
  }
4661
- const hasSession = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
5744
+ const hasSession = this.namedSessions ? Boolean(await this.currentSessionId(envelope)) : this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
4662
5745
  const policy = this.config.senderPolicy;
4663
5746
  const lines = [
4664
5747
  `Session: ${hasSession ? "active" : "none"}`,
@@ -4989,6 +6072,10 @@ ${requestList}`);
4989
6072
  const sessionId = this.router.getSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
4990
6073
  return sessionId && this.activePrompts.has(sessionId) ? sessionId : void 0;
4991
6074
  }
6075
+ async findNamedActiveSessionId(envelope) {
6076
+ const sessionId = await this.currentSessionId(envelope);
6077
+ return sessionId && this.activePrompts.has(sessionId) ? sessionId : void 0;
6078
+ }
4992
6079
  channelMemoryTarget(envelope) {
4993
6080
  return {
4994
6081
  channelName: this.name,
@@ -5716,9 +6803,12 @@ ${formatted.join("\n")}
5716
6803
  ${CURRENT_MESSAGE_MARKER}
5717
6804
  ${promptText}`;
5718
6805
  }
5719
- preflightInbound(envelope) {
5720
- const groupResult = this.groupGate.check(envelope);
5721
- if (!groupResult.allowed) {
6806
+ preflightInbound(envelope, options = {}) {
6807
+ const groupResult = this.groupGate.check(envelope, {
6808
+ createPairingRequest: !options.deferPairingRequests
6809
+ });
6810
+ const deferredGroupPairing = options.deferPairingRequests === true && groupResult.reason === "pairing_trigger_required" && (envelope.isMentioned || envelope.isReplyToBot);
6811
+ if (!groupResult.allowed && !deferredGroupPairing) {
5722
6812
  if (groupResult.pairing !== void 0) {
5723
6813
  this.logPreflightRejected("group_pairing_required");
5724
6814
  return this.onGroupPairingRequired(envelope.chatId, groupResult.pairing, envelope.threadId).then(() => false).catch((err) => {
@@ -5745,6 +6835,10 @@ ${promptText}`;
5745
6835
  this.markPreflighted(envelope);
5746
6836
  return true;
5747
6837
  }
6838
+ if (options.deferPairingRequests === true && this.config.senderPolicy === "pairing" && !this.gate.isAllowed(envelope.senderId)) {
6839
+ this.markPreflighted(envelope);
6840
+ return true;
6841
+ }
5748
6842
  const result = this.gate.check(envelope.senderId, envelope.senderName);
5749
6843
  if (!result.allowed) {
5750
6844
  if (result.pairing !== void 0) {
@@ -5781,7 +6875,50 @@ ${promptText}`;
5781
6875
  const preflight = this.preflightInbound(envelope);
5782
6876
  if (!(isPromiseLike(preflight) ? await preflight : preflight))
5783
6877
  return;
5784
- await this.processInbound(envelope);
6878
+ await this.processPreflightedInbound(envelope);
6879
+ }
6880
+ async prepareThenHandleInbound(envelope, prepare, preflightOptions = {}) {
6881
+ const preflight = this.preflightInbound(envelope, preflightOptions);
6882
+ if (!(isPromiseLike(preflight) ? await preflight : preflight))
6883
+ return;
6884
+ if (this.namedSessions) {
6885
+ const result = await this.namedSessions.resolveAfterPreparation(this.namedSessionOwner(envelope), prepare, () => !this.bypassesNamedTurnBinding(envelope), (sessionId) => {
6886
+ const binding = this.bindNamedTurn(envelope, sessionId);
6887
+ return () => this.releaseNamedTurnBinding(binding);
6888
+ });
6889
+ if (result.status === "aborted")
6890
+ return;
6891
+ if (result.status === "resolve_error") {
6892
+ this.finishNamedTurnBinding(envelope);
6893
+ await this.sendNamedSessionError(envelope, result.error);
6894
+ return;
6895
+ }
6896
+ if (result.status === "resolved" && !result.sessionId && !this.namedTurnBindings.has(envelope)) {
6897
+ this.namedTurnBindings.set(envelope, {
6898
+ sessionId: null,
6899
+ generation: 0,
6900
+ claimed: false,
6901
+ released: true
6902
+ });
6903
+ }
6904
+ } else if (await prepare() === false) {
6905
+ return;
6906
+ }
6907
+ try {
6908
+ await this.handleInbound(envelope);
6909
+ } finally {
6910
+ this.finishNamedTurnBinding(envelope);
6911
+ }
6912
+ }
6913
+ async processPreflightedInbound(envelope, process5 = () => this.processInbound(envelope)) {
6914
+ if (this.namedSessions && !await this.prepareNamedTurnBinding(envelope)) {
6915
+ return;
6916
+ }
6917
+ try {
6918
+ await process5();
6919
+ } finally {
6920
+ this.finishNamedTurnBinding(envelope);
6921
+ }
5785
6922
  }
5786
6923
  async recordObservedContact(envelope) {
5787
6924
  if (!this.observedContacts)
@@ -5906,7 +7043,45 @@ ${promptText}`;
5906
7043
  }
5907
7044
  }
5908
7045
  await this.waitForBridgeRecovery();
5909
- const sessionId = await this.router.resolve(this.name, envelope.senderId, envelope.chatId, envelope.threadId, this.config.cwd, envelope.isGroup);
7046
+ let sessionId;
7047
+ let namedTurn = this.namedTurnBindings.get(envelope);
7048
+ if (this.namedSessions && namedTurn) {
7049
+ if (namedTurn.sessionId === null) {
7050
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No task was selected when this message was received. Select a task and send it again.");
7051
+ return;
7052
+ }
7053
+ if (this.dropQueuedTurnIfStale(namedTurn.sessionId, namedTurn.generation, envelope)) {
7054
+ return;
7055
+ }
7056
+ try {
7057
+ sessionId = await this.namedSessions.resolve(this.namedSessionOwner(envelope), namedTurn.sessionId);
7058
+ } catch (error) {
7059
+ await this.sendNamedSessionError(envelope, error);
7060
+ return;
7061
+ }
7062
+ if (!sessionId) {
7063
+ process.stderr.write(`[${this.name}] dropped collected turn from ${envelope.senderId} for session ${namedTurn.sessionId}: selected task changed before it ran
7064
+ `);
7065
+ return;
7066
+ }
7067
+ } else if (this.namedSessions) {
7068
+ try {
7069
+ sessionId = await this.namedSessions.resolve(this.namedSessionOwner(envelope), void 0, (resolvedSessionId) => {
7070
+ const binding = this.bindNamedTurn(envelope, resolvedSessionId);
7071
+ namedTurn = binding;
7072
+ return () => this.releaseNamedTurnBinding(binding);
7073
+ });
7074
+ } catch (error) {
7075
+ await this.sendNamedSessionError(envelope, error);
7076
+ return;
7077
+ }
7078
+ if (!sessionId) {
7079
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No task is currently selected. Use /session new <name> or /session use <name>.");
7080
+ return;
7081
+ }
7082
+ } else {
7083
+ sessionId = await this.router.resolve(this.name, envelope.senderId, envelope.chatId, envelope.threadId, this.config.cwd, envelope.isGroup);
7084
+ }
5910
7085
  if (bangText.startsWith("!")) {
5911
7086
  const cmd = bangText.slice(1).trim();
5912
7087
  const bridgeShellCommand = this.bridge.shellCommand;
@@ -5951,12 +7126,19 @@ ${promptText}`;
5951
7126
  }
5952
7127
  let imageBase64 = envelope.imageBase64;
5953
7128
  let imageMimeType = envelope.imageMimeType;
7129
+ const images = [];
7130
+ if (imageBase64 && imageMimeType) {
7131
+ images.push({ data: imageBase64, mimeType: imageMimeType });
7132
+ }
5954
7133
  if (envelope.attachments?.length) {
5955
7134
  const filePaths = [];
5956
7135
  for (const att of envelope.attachments) {
5957
- if (att.type === "image" && att.data && !imageBase64) {
5958
- imageBase64 = att.data;
5959
- imageMimeType = att.mimeType;
7136
+ if (att.type === "image" && att.data) {
7137
+ images.push({ data: att.data, mimeType: att.mimeType });
7138
+ if (!imageBase64) {
7139
+ imageBase64 = att.data;
7140
+ imageMimeType = att.mimeType;
7141
+ }
5960
7142
  } else if (att.filePath) {
5961
7143
  const label = att.type === "file" ? "file" : att.type;
5962
7144
  const name = att.fileName ? ` "${sanitizeQuotedText(att.fileName, 128)}"` : "";
@@ -6042,8 +7224,13 @@ ${promptText}`;
6042
7224
  this.instructedSessions.add(sessionId);
6043
7225
  }
6044
7226
  const prev = this.sessionQueues.get(sessionId) ?? Promise.resolve();
6045
- const generation = this.sessionGenerations.get(sessionId) ?? 0;
7227
+ const generation = namedTurn?.generation ?? this.sessionGenerations.get(sessionId) ?? 0;
6046
7228
  const useBlockStreaming = this.config.blockStreaming === "on";
7229
+ if (namedTurn) {
7230
+ namedTurn.claimed = true;
7231
+ } else {
7232
+ this.reserveQueuedTurn(sessionId);
7233
+ }
6047
7234
  const current = prev.then(async () => {
6048
7235
  clearTimeout(steerWatchdog);
6049
7236
  if (this.dropQueuedTurnIfStale(sessionId, generation, envelope)) {
@@ -6110,7 +7297,7 @@ ${promptToSend}`;
6110
7297
  doneResolve = r;
6111
7298
  });
6112
7299
  const promptState = {
6113
- runId: randomUUID2(),
7300
+ runId: randomUUID3(),
6114
7301
  owner: {
6115
7302
  kind: "channel_user",
6116
7303
  id: envelope.senderId
@@ -6184,6 +7371,7 @@ ${promptToSend}`;
6184
7371
  promptBridge.on("responseBoundary", onResponseBoundary);
6185
7372
  try {
6186
7373
  const response = await promptBridge.prompt(sessionId, promptToSend, {
7374
+ ...images.length > 0 ? { images } : {},
6187
7375
  imageBase64,
6188
7376
  imageMimeType,
6189
7377
  displayText
@@ -6246,7 +7434,10 @@ ${promptToSend}`;
6246
7434
  } finally {
6247
7435
  promptBridge.off("textChunk", onChunk);
6248
7436
  promptBridge.off("responseBoundary", onResponseBoundary);
6249
- streamer?.stop();
7437
+ if (streamer) {
7438
+ streamer.stop();
7439
+ await streamer.drain();
7440
+ }
6250
7441
  const stillCurrent = this.activePrompts.get(sessionId) === promptState;
6251
7442
  if (!promptState.clearEvicted) {
6252
7443
  try {
@@ -6260,39 +7451,15 @@ ${promptToSend}`;
6260
7451
  this.activePrompts.delete(sessionId);
6261
7452
  }
6262
7453
  promptState.resolve();
6263
- const buffer = this.collectBuffers.get(sessionId);
6264
- if (stillCurrent && buffer && buffer.length > 0) {
6265
- this.collectBuffers.delete(sessionId);
6266
- const lost = buffer.length;
6267
- const coalesced = buffer.map((b) => b.text).join("\n\n");
6268
- const coalescedDisplayText = buffer.map((b) => b.displayText).join("\n\n");
6269
- const lastEnvelope = buffer[buffer.length - 1].envelope;
6270
- this.notifyPromptBufferDrained(lastEnvelope.chatId, sessionId, buffer);
6271
- const syntheticEnvelope = {
6272
- ...lastEnvelope,
6273
- text: coalesced,
6274
- displayText: coalescedDisplayText,
6275
- // Coalesced text already carries each message's [sender] prefix.
6276
- alreadyPrefixed: true,
6277
- // Clear attachments/references — already resolved in original text
6278
- referencedText: void 0,
6279
- mentionedMemberIds: void 0,
6280
- attachments: void 0,
6281
- metadata: void 0,
6282
- imageBase64: void 0,
6283
- imageMimeType: void 0
6284
- };
6285
- this.markPreflighted(syntheticEnvelope);
6286
- this.processInbound(syntheticEnvelope).catch((err) => {
6287
- process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) on collect re-entry for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
6288
- `);
6289
- });
6290
- }
7454
+ this.drainCollectBufferForCurrentPrompt(sessionId, stillCurrent, "prompt completion");
6291
7455
  }
6292
7456
  });
6293
- this.sessionQueues.set(sessionId, current.catch(() => {
7457
+ const tracked = current.finally(() => {
7458
+ this.releaseQueuedTurn(sessionId);
7459
+ });
7460
+ this.sessionQueues.set(sessionId, tracked.catch(() => {
6294
7461
  }));
6295
- await current;
7462
+ await tracked;
6296
7463
  }
6297
7464
  pairingRejectionMessage(rejected) {
6298
7465
  return rejected === "sender_pending" ? "You already have a pending pairing request. It must be approved or expire before another can be created." : "Too many pending pairing requests. Please try again later.";
@@ -6402,10 +7569,10 @@ var PollingChannelBase = class extends ChannelBase {
6402
7569
  }
6403
7570
  saveCursor() {
6404
7571
  const path4 = this.cursorPath();
6405
- mkdirSync4(join6(getGlobalQwenDir(), "channels"), { recursive: true });
7572
+ mkdirSync5(join6(getGlobalQwenDir(), "channels"), { recursive: true });
6406
7573
  const tmp = `${path4}.tmp`;
6407
- writeFileSync4(tmp, JSON.stringify(this.cursor) + "\n", "utf-8");
6408
- renameSync4(tmp, path4);
7574
+ writeFileSync5(tmp, JSON.stringify(this.cursor) + "\n", "utf-8");
7575
+ renameSync5(tmp, path4);
6409
7576
  }
6410
7577
  startPollLoop() {
6411
7578
  if (this.running)
@@ -6429,7 +7596,7 @@ var PollingChannelBase = class extends ChannelBase {
6429
7596
  } catch (err) {
6430
7597
  this.consecutiveErrors++;
6431
7598
  const backoff = Math.min(INITIAL_BACKOFF * 2 ** (this.consecutiveErrors - 1), MAX_BACKOFF);
6432
- process3.stderr.write(`[Channel:${this.name}] poll error (attempt ${this.consecutiveErrors}), backing off ${backoff}ms: ${err}
7599
+ process4.stderr.write(`[Channel:${this.name}] poll error (attempt ${this.consecutiveErrors}), backing off ${backoff}ms: ${err}
6433
7600
  `);
6434
7601
  await this.abortableSleep(backoff);
6435
7602
  continue;
@@ -6439,7 +7606,7 @@ var PollingChannelBase = class extends ChannelBase {
6439
7606
  }
6440
7607
  loadCursorFromDisk() {
6441
7608
  try {
6442
- const raw = readFileSync4(this.cursorPath(), "utf-8").trim();
7609
+ const raw = readFileSync5(this.cursorPath(), "utf-8").trim();
6443
7610
  if (!raw)
6444
7611
  return null;
6445
7612
  return this.validateCursor(JSON.parse(raw));
@@ -6473,6 +7640,48 @@ function getTextContent(content) {
6473
7640
  return getString(content["text"]);
6474
7641
  }
6475
7642
  __name(getTextContent, "getTextContent");
7643
+ var CHANNEL_IMAGE_EXTENSIONS = ["bmp", "gif", "jpeg", "png", "webp"];
7644
+ var CHANNEL_IMAGE_MAX_UPLOAD_BYTES = 8 * 1024 * 1024;
7645
+ var CHANNEL_IMAGE_INLINE_MAX_BASE64_BYTES = 8 * 1024 * 1024;
7646
+ function channelImageName(mimeType, index = 0) {
7647
+ if (!mimeType.startsWith("image/")) {
7648
+ return void 0;
7649
+ }
7650
+ const extension = mimeType.slice("image/".length);
7651
+ if (!CHANNEL_IMAGE_EXTENSIONS.includes(extension)) {
7652
+ return void 0;
7653
+ }
7654
+ return index === 0 ? `image.${extension}` : `image-${index + 1}.${extension}`;
7655
+ }
7656
+ __name(channelImageName, "channelImageName");
7657
+ function decodeChannelImage(data, oversizedReason) {
7658
+ let estimatedBytes = Math.floor(data.length * 3 / 4);
7659
+ if (data.length % 4 === 0) {
7660
+ if (data.endsWith("=="))
7661
+ estimatedBytes -= 2;
7662
+ else if (data.endsWith("="))
7663
+ estimatedBytes -= 1;
7664
+ }
7665
+ if (estimatedBytes > CHANNEL_IMAGE_MAX_UPLOAD_BYTES) {
7666
+ return { skip: oversizedReason };
7667
+ }
7668
+ const bytes = Buffer.from(data, "base64");
7669
+ if (bytes.byteLength === 0) {
7670
+ return { skip: "empty once base64-decoded" };
7671
+ }
7672
+ return { bytes };
7673
+ }
7674
+ __name(decodeChannelImage, "decodeChannelImage");
7675
+ function isDefinitePromptAdmissionRejection(error) {
7676
+ if (!isRecord3(error)) {
7677
+ return false;
7678
+ }
7679
+ if (error["name"] === "DaemonPendingPromptLimitError") {
7680
+ return true;
7681
+ }
7682
+ return error["name"] === "DaemonHttpError" && typeof error["status"] === "number" && error["_daemonTurnError"] !== true;
7683
+ }
7684
+ __name(isDefinitePromptAdmissionRejection, "isDefinitePromptAdmissionRejection");
6476
7685
  function getSessionUpdate(data) {
6477
7686
  if (!isRecord3(data) || !isRecord3(data["update"])) {
6478
7687
  return void 0;
@@ -6544,8 +7753,9 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6544
7753
  availableCommandsBySession = /* @__PURE__ */ new Map();
6545
7754
  turnBarriers = /* @__PURE__ */ new Map();
6546
7755
  channelLoopToolHandlers = [];
7756
+ channelLoopDisabledSessions = /* @__PURE__ */ new Set();
6547
7757
  registeredChannelLoopMcpSessions = /* @__PURE__ */ new Set();
6548
- channelLoopMcpRegistrations = /* @__PURE__ */ new Map();
7758
+ channelLoopMcpOperations = /* @__PURE__ */ new Map();
6549
7759
  channelLoopMcpServer;
6550
7760
  connected = false;
6551
7761
  lifecycleGeneration = 0;
@@ -6605,7 +7815,12 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6605
7815
  await this.rejectStaleSession(session);
6606
7816
  }
6607
7817
  this.attachSession(session, bindingToken);
6608
- await this.registerChannelLoopMcpForSession(session.sessionId);
7818
+ if (options?.enableChannelLoops === false) {
7819
+ this.channelLoopDisabledSessions.add(session.sessionId);
7820
+ void this.reconcileChannelLoopMcpForSession(session.sessionId);
7821
+ } else {
7822
+ await this.reconcileChannelLoopMcpForSession(session.sessionId);
7823
+ }
6609
7824
  return session.sessionId;
6610
7825
  }
6611
7826
  async loadSession(sessionId, cwd, options, bindingToken) {
@@ -6627,7 +7842,12 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6627
7842
  throw new Error(`Daemon returned session ${session.sessionId} while loading ${sessionId}`);
6628
7843
  }
6629
7844
  this.attachSession(session, bindingToken);
6630
- await this.registerChannelLoopMcpForSession(session.sessionId);
7845
+ if (options?.enableChannelLoops === false) {
7846
+ this.channelLoopDisabledSessions.add(session.sessionId);
7847
+ void this.reconcileChannelLoopMcpForSession(session.sessionId);
7848
+ } else {
7849
+ await this.reconcileChannelLoopMcpForSession(session.sessionId);
7850
+ }
6631
7851
  return session.sessionId;
6632
7852
  }
6633
7853
  registerChannelLoopToolHandler(handler) {
@@ -6640,7 +7860,9 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6640
7860
  cancel: /* @__PURE__ */ __name((sessionId, id) => this.resolveChannelLoopToolHandler(sessionId).cancel(sessionId, id), "cancel")
6641
7861
  });
6642
7862
  for (const sessionId of this.sessions.keys()) {
6643
- void this.registerChannelLoopMcpForSession(sessionId);
7863
+ if (!this.channelLoopDisabledSessions.has(sessionId)) {
7864
+ void this.reconcileChannelLoopMcpForSession(sessionId);
7865
+ }
6644
7866
  }
6645
7867
  }
6646
7868
  async prompt(sessionId, text, options) {
@@ -6684,29 +7906,101 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6684
7906
  this.on("responseBoundary", clearChunks);
6685
7907
  this.on("sessionDied", onSessionDied);
6686
7908
  const turnBarrier = this.createTurnBarrier(sessionId);
6687
- const prompt = [];
6688
- if (options?.imageBase64 && options.imageMimeType) {
6689
- prompt.push({
6690
- type: "image",
6691
- data: options.imageBase64,
6692
- mimeType: options.imageMimeType
6693
- });
6694
- }
6695
- prompt.push({ type: "text", text });
6696
- const promptAuthorization = this.options.promptAuthorization;
7909
+ const uploadedAttachmentIds = [];
7910
+ let rollbackUploadedAttachments = false;
7911
+ const uploadAttachment = session.uploadAttachment?.bind(session);
7912
+ const removeAttachment = session.removeAttachment?.bind(session);
6697
7913
  try {
6698
- const result = await session.prompt({
6699
- prompt,
6700
- _meta: {
6701
- [CHANNEL_PROMPT_META_KEY]: true,
6702
- ...promptAuthorization ? {
6703
- [CHANNEL_PROMPT_AUTHORIZATION_META_KEY]: promptAuthorization
6704
- } : {},
6705
- ...options?.displayText !== void 0 ? {
6706
- [CHANNEL_PROMPT_DISPLAY_TEXT_META_KEY]: options.displayText
6707
- } : {}
7914
+ const prompt = [];
7915
+ const images = resolvePromptImages(options);
7916
+ if (this.options.sessionAttachments && uploadAttachment && removeAttachment) {
7917
+ try {
7918
+ const uploads = await Promise.allSettled(images.map(async (image, index) => {
7919
+ const name = channelImageName(image.mimeType, index);
7920
+ if (!name) {
7921
+ process.stderr.write(`[DaemonChannelBridge] skipped channel image with unsupported MIME type ${sanitizeLogText(image.mimeType, 128)} for session ${sanitizeLogText(sessionId, 128)}
7922
+ `);
7923
+ return void 0;
7924
+ }
7925
+ const decoded = decodeChannelImage(image.data, "above the daemon attachment size limit");
7926
+ if ("skip" in decoded) {
7927
+ process.stderr.write(`[DaemonChannelBridge] skipped channel image ${decoded.skip} ${sanitizeLogText(image.mimeType, 128)} for session ${sanitizeLogText(sessionId, 128)}
7928
+ `);
7929
+ return void 0;
7930
+ }
7931
+ const attachment = await uploadAttachment(new Blob([decoded.bytes], {
7932
+ type: image.mimeType
7933
+ }), name, image.mimeType, controller.signal);
7934
+ const attachmentId = getString(attachment["attachmentId"]);
7935
+ if (attachmentId)
7936
+ uploadedAttachmentIds.push(attachmentId);
7937
+ return attachment;
7938
+ }));
7939
+ const failure = uploads.find((upload) => upload.status === "rejected");
7940
+ if (failure) {
7941
+ throw failure.reason;
7942
+ }
7943
+ for (const upload of uploads) {
7944
+ if (upload.status === "fulfilled" && upload.value) {
7945
+ prompt.push(upload.value);
7946
+ }
7947
+ }
7948
+ } catch (error) {
7949
+ rollbackUploadedAttachments = true;
7950
+ throw error;
7951
+ }
7952
+ } else {
7953
+ let inlineBase64Bytes = 0;
7954
+ for (const image of images) {
7955
+ const decoded = decodeChannelImage(image.data, "above the inline image budget");
7956
+ if ("skip" in decoded) {
7957
+ process.stderr.write(`[DaemonChannelBridge] skipped channel image ${decoded.skip} ${sanitizeLogText(image.mimeType, 128)} for session ${sanitizeLogText(sessionId, 128)}
7958
+ `);
7959
+ continue;
7960
+ }
7961
+ if (inlineBase64Bytes + image.data.length > CHANNEL_IMAGE_INLINE_MAX_BASE64_BYTES) {
7962
+ process.stderr.write(`[DaemonChannelBridge] skipped channel image to keep the inline prompt under the daemon body limit ${sanitizeLogText(image.mimeType, 128)} for session ${sanitizeLogText(sessionId, 128)}
7963
+ `);
7964
+ continue;
7965
+ }
7966
+ inlineBase64Bytes += image.data.length;
7967
+ prompt.push({
7968
+ type: "image",
7969
+ data: image.data,
7970
+ mimeType: image.mimeType
7971
+ });
7972
+ }
7973
+ }
7974
+ prompt.push({ type: "text", text });
7975
+ if (controller.signal.aborted) {
7976
+ rollbackUploadedAttachments = true;
7977
+ controller.signal.throwIfAborted();
7978
+ }
7979
+ const promptAuthorization = this.options.promptAuthorization;
7980
+ if (controller.signal.aborted) {
7981
+ rollbackUploadedAttachments = true;
7982
+ throw controller.signal.reason;
7983
+ }
7984
+ let result;
7985
+ try {
7986
+ result = await session.prompt({
7987
+ prompt,
7988
+ _meta: {
7989
+ [CHANNEL_PROMPT_META_KEY]: true,
7990
+ ...promptAuthorization ? {
7991
+ [CHANNEL_PROMPT_AUTHORIZATION_META_KEY]: promptAuthorization
7992
+ } : {},
7993
+ ...options?.displayText !== void 0 ? {
7994
+ [CHANNEL_PROMPT_DISPLAY_TEXT_META_KEY]: options.displayText
7995
+ } : {}
7996
+ }
7997
+ }, controller.signal);
7998
+ } catch (error) {
7999
+ if (isDefinitePromptAdmissionRejection(error)) {
8000
+ rollbackUploadedAttachments = true;
6708
8001
  }
6709
- }, controller.signal);
8002
+ throw error;
8003
+ }
6710
8004
  await Promise.race([
6711
8005
  turnBarrier,
6712
8006
  new Promise((resolve3) => setTimeout(resolve3, 0))
@@ -6729,6 +8023,16 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6729
8023
  if (controllers.size === 0 && this.activePromptControllers.get(sessionId) === controllers) {
6730
8024
  this.activePromptControllers.delete(sessionId);
6731
8025
  }
8026
+ if (rollbackUploadedAttachments && removeAttachment) {
8027
+ const removals = await Promise.allSettled(uploadedAttachmentIds.map((attachmentId) => removeAttachment(attachmentId)));
8028
+ removals.forEach((removal, index) => {
8029
+ if (removal.status === "rejected") {
8030
+ const reason = removal.reason instanceof Error ? removal.reason.message : String(removal.reason);
8031
+ process.stderr.write(`[DaemonChannelBridge] failed to remove channel image ${sanitizeLogText(uploadedAttachmentIds[index] ?? "", 128)} for session ${sanitizeLogText(sessionId, 128)} during rollback: ${sanitizeLogText(reason, 256)}
8032
+ `);
8033
+ }
8034
+ });
8035
+ }
6732
8036
  }
6733
8037
  }
6734
8038
  async shellCommand(sessionId, command, signal) {
@@ -6922,6 +8226,8 @@ var DaemonChannelBridge = class extends EventEmitter2 {
6922
8226
  if (meta?.["qwenDiscreteMessage"] === true) {
6923
8227
  if (meta["source"] === "background_notification_response" && meta["rewritten"] !== true && text) {
6924
8228
  this.emit("backgroundResponse", sessionId, text);
8229
+ } else if (meta["source"] === "vision_bridge_notice" && text) {
8230
+ this.emit("textChunk", sessionId, text);
6925
8231
  }
6926
8232
  break;
6927
8233
  }
@@ -7084,6 +8390,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
7084
8390
  this.eventControllers.delete(sessionId);
7085
8391
  this.sessions.delete(sessionId);
7086
8392
  this.sessionBindingTokens.delete(sessionId);
8393
+ this.channelLoopDisabledSessions.delete(sessionId);
7087
8394
  this.abortActivePrompts(sessionId);
7088
8395
  this.activePrompts.delete(sessionId);
7089
8396
  this.availableCommandsBySession.delete(sessionId);
@@ -7101,45 +8408,45 @@ var DaemonChannelBridge = class extends EventEmitter2 {
7101
8408
  }
7102
8409
  }
7103
8410
  if (unregisterChannelLoopMcp) {
7104
- this.unregisterChannelLoopMcpForSession(sessionId);
8411
+ void this.reconcileChannelLoopMcpForSession(sessionId);
7105
8412
  }
7106
8413
  return session;
7107
8414
  }
7108
- async registerChannelLoopMcpForSession(sessionId) {
7109
- const host = this.options.channelLoopMcpHost;
7110
- const server = this.channelLoopMcpServer;
7111
- if (!host || !server || this.registeredChannelLoopMcpSessions.has(sessionId)) {
7112
- return;
7113
- }
7114
- const pending = this.channelLoopMcpRegistrations.get(sessionId);
7115
- if (pending) {
7116
- await pending;
7117
- return;
7118
- }
7119
- const registration = host.register(sessionId, (message) => server.handleMessage(message, { sessionId })).then(async () => {
7120
- if (this.sessions.has(sessionId)) {
7121
- this.registeredChannelLoopMcpSessions.add(sessionId);
7122
- } else {
8415
+ reconcileChannelLoopMcpForSession(sessionId) {
8416
+ const previous = this.channelLoopMcpOperations.get(sessionId) ?? Promise.resolve();
8417
+ const operation = previous.catch(() => void 0).then(async () => {
8418
+ const host = this.options.channelLoopMcpHost;
8419
+ const server = this.channelLoopMcpServer;
8420
+ const shouldRegister = host !== void 0 && server !== void 0 && this.sessions.has(sessionId) && !this.channelLoopDisabledSessions.has(sessionId);
8421
+ if (!shouldRegister) {
8422
+ if (host && this.registeredChannelLoopMcpSessions.has(sessionId)) {
8423
+ await host.unregister(sessionId);
8424
+ this.registeredChannelLoopMcpSessions.delete(sessionId);
8425
+ }
8426
+ return;
8427
+ }
8428
+ if (this.registeredChannelLoopMcpSessions.has(sessionId))
8429
+ return;
8430
+ await host.register(sessionId, (message) => server.handleMessage(message, { sessionId }));
8431
+ this.registeredChannelLoopMcpSessions.add(sessionId);
8432
+ if (!this.sessions.has(sessionId) || this.channelLoopDisabledSessions.has(sessionId)) {
7123
8433
  await host.unregister(sessionId);
8434
+ this.registeredChannelLoopMcpSessions.delete(sessionId);
7124
8435
  }
7125
8436
  }).catch((error) => {
7126
8437
  this.lastError = error;
7127
8438
  }).finally(() => {
7128
- if (this.channelLoopMcpRegistrations.get(sessionId) === registration) {
7129
- this.channelLoopMcpRegistrations.delete(sessionId);
8439
+ if (this.channelLoopMcpOperations.get(sessionId) === operation) {
8440
+ this.channelLoopMcpOperations.delete(sessionId);
7130
8441
  }
7131
8442
  });
7132
- this.channelLoopMcpRegistrations.set(sessionId, registration);
7133
- await registration;
7134
- }
7135
- unregisterChannelLoopMcpForSession(sessionId) {
7136
- if (!this.registeredChannelLoopMcpSessions.delete(sessionId))
7137
- return;
7138
- void this.options.channelLoopMcpHost?.unregister(sessionId).catch((error) => {
7139
- this.lastError = error;
7140
- });
8443
+ this.channelLoopMcpOperations.set(sessionId, operation);
8444
+ return operation;
7141
8445
  }
7142
8446
  resolveChannelLoopToolHandler(sessionId) {
8447
+ if (!this.sessions.has(sessionId) || this.channelLoopDisabledSessions.has(sessionId)) {
8448
+ throw new Error("Channel loop tools are unavailable for this session");
8449
+ }
7143
8450
  const handler = this.channelLoopToolHandlers.find((candidate) => candidate.canHandle?.(sessionId) === true || this.channelLoopToolHandlers.length === 1 && !candidate.canHandle);
7144
8451
  if (handler)
7145
8452
  return handler;
@@ -7370,6 +8677,7 @@ export {
7370
8677
  isChannelProactiveDeliveryError,
7371
8678
  PairingStore,
7372
8679
  truncateCodePoints,
8680
+ truncateUtf16Units,
7373
8681
  sanitizeSenderName,
7374
8682
  sanitizePromptText,
7375
8683
  sanitizeDisplayText,