@qwen-code/qwen-code 0.21.0 → 0.21.1

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 (406) hide show
  1. package/bundled/qc-helper/docs/configuration/model-providers.md +2 -0
  2. package/bundled/qc-helper/docs/configuration/settings.md +38 -28
  3. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  4. package/bundled/qc-helper/docs/features/channels/github.md +107 -0
  5. package/bundled/qc-helper/docs/features/channels/overview.md +61 -6
  6. package/bundled/qc-helper/docs/features/code-review.md +1 -1
  7. package/bundled/qc-helper/docs/features/hooks.md +52 -15
  8. package/bundled/qc-helper/docs/features/mcp.md +9 -1
  9. package/bundled/qc-helper/docs/features/scheduled-tasks.md +3 -1
  10. package/bundled/qc-helper/docs/features/sub-agents.md +20 -0
  11. package/bundled/qc-helper/docs/qwen-serve.md +4 -2
  12. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +2 -2
  13. package/bundled/qc-helper/docs/support/troubleshooting.md +2 -1
  14. package/bundled/review/DESIGN.md +19 -0
  15. package/bundled/review/SKILL.md +120 -61
  16. package/chunks/MaxSizedBox-VI3ROJJA.js +84 -0
  17. package/chunks/{StandaloneSessionPicker-BIRMPLRD.js → StandaloneSessionPicker-LYXKD2EV.js} +67 -68
  18. package/chunks/{acp-startup-profiler-RV3IV562.js → acp-startup-profiler-DFVPFQ6C.js} +2 -2
  19. package/chunks/{acpAgent-6J2U72PQ.js → acpAgent-WN5SRDQO.js} +1373 -553
  20. package/chunks/agent-K6ECSM64.js +80 -0
  21. package/chunks/agent-headless-NO4Y2HOE.js +74 -0
  22. package/chunks/{anthropicContentGenerator-75BKLTSP.js → anthropicContentGenerator-V2QOGVYD.js} +79 -27
  23. package/chunks/{artifact-tool-Y5T7GG7F.js → artifact-tool-6K6U7XYJ.js} +4 -4
  24. package/chunks/{askUserQuestion-2H6747FR.js → askUserQuestion-GD2IJJ7I.js} +4 -4
  25. package/chunks/bridge-3KJEWDNE.js +90 -0
  26. package/chunks/{build-RV63TIRH.js → build-S6DO7LMM.js} +1 -1
  27. package/chunks/{ca-25EDXPFZ.js → ca-6W3SK7OQ.js} +6 -1
  28. package/chunks/channel-management-service-XR7GZSWF.js +403 -0
  29. package/chunks/channel-settings-store-HW4FXXUA.js +87 -0
  30. package/chunks/{channel-worker-group-2ZD7TVAT.js → channel-worker-group-XDPTDWTX.js} +11 -6
  31. package/chunks/{channel-worker-manager-4OA4BCGB.js → channel-worker-manager-YYEHVRRE.js} +11 -6
  32. package/chunks/{channel-worker-supervisor-V7KCFJTS.js → channel-worker-supervisor-74HTWA2G.js} +7 -5
  33. package/chunks/{chunk-M5JM7OSF.js → chunk-2DN4J57Y.js} +2 -3
  34. package/chunks/{chunk-ETSW4KLJ.js → chunk-2FAK6PNM.js} +2 -2
  35. package/chunks/{chunk-BPJSQIJX.js → chunk-2J3OJGTL.js} +0 -2
  36. package/chunks/{chunk-EPDRMGT4.js → chunk-2LKVPASC.js} +4 -28
  37. package/chunks/{chunk-PWTZEM3C.js → chunk-2LQTH543.js} +3 -37
  38. package/chunks/{chunk-LH2BYDQ5.js → chunk-2N7CODY5.js} +18 -12
  39. package/chunks/{chunk-4WIZGAH3.js → chunk-2XSLTRFZ.js} +6 -58
  40. package/chunks/{chunk-FSITMZJH.js → chunk-3EFXSQCM.js} +18 -9
  41. package/chunks/{chunk-HIJQF5B5.js → chunk-3L2SPEBH.js} +1 -1
  42. package/chunks/{chunk-BIQWWWJN.js → chunk-4G2BISNC.js} +1 -1
  43. package/chunks/{chunk-PWVFN2LF.js → chunk-52ZSWYEG.js} +1 -1
  44. package/chunks/{chunk-ZJHVAS7M.js → chunk-5KTQXHPY.js} +4 -5
  45. package/chunks/{chunk-PC6JANNU.js → chunk-5MKRTI4T.js} +4 -4
  46. package/chunks/{chunk-DHHOYAPR.js → chunk-5TBMQLGG.js} +7 -7
  47. package/chunks/{chunk-A4UCTEB5.js → chunk-5WV5S2GT.js} +0 -1
  48. package/chunks/chunk-5YKDXHUY.js +463 -0
  49. package/chunks/chunk-5ZF5XXTS.js +363 -0
  50. package/chunks/{chunk-K4XWPEWB.js → chunk-64LQLPL7.js} +4 -33
  51. package/chunks/{chunk-YPE6A4GC.js → chunk-657BH7VM.js} +2 -2
  52. package/chunks/{chunk-R5AFZNQW.js → chunk-65PQENQP.js} +14 -7
  53. package/chunks/{chunk-RIBKPMRP.js → chunk-6PE7N3A4.js} +18 -7
  54. package/chunks/{chunk-JZA3JUDJ.js → chunk-6QIGFD5W.js} +1 -1
  55. package/chunks/{chunk-JVPM2ULZ.js → chunk-6RPMI2AB.js} +6 -6
  56. package/chunks/{chunk-OHNBB4XR.js → chunk-75GFAX4R.js} +1 -1
  57. package/chunks/{chunk-NIBLUX3Y.js → chunk-75MIQ3LV.js} +148 -21
  58. package/chunks/{chunk-U7M2DMGW.js → chunk-7AEJDLRA.js} +130 -5
  59. package/chunks/{chunk-TPRQ7RZH.js → chunk-7BAU433D.js} +2293 -945
  60. package/chunks/{chunk-M4FMGVY4.js → chunk-7DXQIJID.js} +3 -3
  61. package/chunks/{chunk-RWTEFFPU.js → chunk-7I5GTCT4.js} +620 -383
  62. package/chunks/{chunk-A5L3JMUA.js → chunk-7XATOOE7.js} +18 -4
  63. package/chunks/{chunk-Y34KJKDC.js → chunk-A2D5BAVP.js} +1 -1
  64. package/chunks/{chunk-5I2IWRSH.js → chunk-A3NDJ5SB.js} +2 -2
  65. package/chunks/{chunk-OFDOK3VM.js → chunk-A4COXFB3.js} +8 -13
  66. package/chunks/{chunk-JLU636DO.js → chunk-ALMR3E6Q.js} +1 -0
  67. package/chunks/{chunk-Q4M4MDQ4.js → chunk-AQIDMUGU.js} +1 -1
  68. package/chunks/{chunk-PJIZUQVC.js → chunk-AZQ3DT76.js} +2 -2
  69. package/chunks/{chunk-UH3WSE5L.js → chunk-B4AJNNOL.js} +1 -6
  70. package/chunks/{chunk-BJX6ZSUK.js → chunk-BCZFQXWK.js} +2 -2
  71. package/chunks/{chunk-MB4MZHMJ.js → chunk-BGTQCTQW.js} +211 -522
  72. package/chunks/{chunk-MZAXJAUM.js → chunk-BMFALVGQ.js} +1 -1
  73. package/chunks/{chunk-PSOO6YXD.js → chunk-BNWB5CYE.js} +9 -7
  74. package/chunks/{chunk-BKHWX6I2.js → chunk-BPZKP57P.js} +11 -3
  75. package/chunks/{chunk-H4SBPHSA.js → chunk-CAPPWD3X.js} +3 -3
  76. package/chunks/{chunk-LQIW3YFY.js → chunk-CQL64ESB.js} +7 -7
  77. package/chunks/{chunk-TOFQCPDC.js → chunk-CVHIL5IG.js} +4 -5
  78. package/chunks/{chunk-XVNQMZ2I.js → chunk-DGEIYUC3.js} +0 -1
  79. package/chunks/{chunk-BPZALHVR.js → chunk-DI35ZN7T.js} +1 -1
  80. package/chunks/chunk-DZLYR4U3.js +1252 -0
  81. package/chunks/{chunk-TEHGS6UP.js → chunk-EIF3FXTB.js} +117 -24
  82. package/chunks/{chunk-2SCDWPXI.js → chunk-EJGJIBRS.js} +5 -5
  83. package/chunks/{chunk-7MVVZO4N.js → chunk-EVKE2FZL.js} +4 -4
  84. package/chunks/{chunk-OKY7HXPG.js → chunk-FNMZK765.js} +2 -2
  85. package/chunks/{chunk-VIA5XA4U.js → chunk-FTD6DP4T.js} +3 -1
  86. package/chunks/chunk-FYJ7W2PI.js +194 -0
  87. package/chunks/{chunk-L5UHQJTJ.js → chunk-GATT5TKW.js} +1 -1
  88. package/chunks/{chunk-X5XDDSSH.js → chunk-GEBV2JGB.js} +28 -5
  89. package/chunks/{chunk-VAK25FTU.js → chunk-GKX7E4CO.js} +1 -1
  90. package/chunks/{chunk-LS77BEZP.js → chunk-GLCZKT5V.js} +1 -5
  91. package/chunks/{chunk-5NBDS5S6.js → chunk-GNR2RNMP.js} +162 -7
  92. package/chunks/{chunk-YH6G52F2.js → chunk-GXIJHV66.js} +4 -4
  93. package/chunks/chunk-GZ3RCT54.js +76 -0
  94. package/chunks/{chunk-2X55UKQE.js → chunk-HMRM2A3U.js} +3 -3
  95. package/chunks/chunk-HV26XH34.js +319 -0
  96. package/chunks/{chunk-LB6DUZ26.js → chunk-J7OACQDE.js} +229 -172
  97. package/chunks/{chunk-K36B6G2O.js → chunk-JFMA7Y5M.js} +5 -5
  98. package/chunks/{chunk-55DJUCI2.js → chunk-JHNRZMHI.js} +53 -43
  99. package/chunks/{chunk-63P4EL5V.js → chunk-JMONIXMJ.js} +1 -1
  100. package/chunks/{chunk-L26JL52R.js → chunk-JSD33JG6.js} +47 -64
  101. package/chunks/{chunk-YBL3QUDD.js → chunk-JTV5K7NH.js} +1 -1
  102. package/chunks/{chunk-RZIX2G32.js → chunk-JX27F6QS.js} +1 -1
  103. package/chunks/chunk-JYBU6YUE.js +378 -0
  104. package/chunks/{chunk-7JURR4JT.js → chunk-KAMYKP7E.js} +167 -81
  105. package/chunks/{chunk-KMQ33DO4.js → chunk-KCO4FLFJ.js} +4 -4
  106. package/chunks/{chunk-2W3OOD4W.js → chunk-L55JWS76.js} +6 -3
  107. package/chunks/{chunk-RHLZR4E5.js → chunk-LGAOC3ZS.js} +1 -1
  108. package/chunks/{chunk-EBJQ6AXW.js → chunk-LO4ROVP4.js} +262 -16
  109. package/chunks/{chunk-NH6KE4JX.js → chunk-LW3RFMG7.js} +3 -3
  110. package/chunks/{chunk-J56UI34H.js → chunk-M7OONWYU.js} +2 -2
  111. package/chunks/{chunk-2NH6DYI4.js → chunk-MHAIJPTD.js} +12 -12
  112. package/chunks/{chunk-FODK6UMO.js → chunk-MPHPFVKK.js} +0 -2
  113. package/chunks/{chunk-VRYUBFMC.js → chunk-MR5EAQ5M.js} +1 -1
  114. package/chunks/{chunk-JESCGQM3.js → chunk-NAVJD2PQ.js} +8 -7
  115. package/chunks/{chunk-H5FFA6TH.js → chunk-NOKIVHOL.js} +16 -3
  116. package/chunks/{chunk-6OUGMXDC.js → chunk-NWNEANAT.js} +7 -7
  117. package/chunks/{chunk-SQCQ4KO2.js → chunk-OCESJA77.js} +393 -330
  118. package/chunks/chunk-OCPBI7J5.js +18 -0
  119. package/chunks/{chunk-E5TUC6CA.js → chunk-OKF7JF3R.js} +3 -3
  120. package/chunks/{chunk-TGILQ3YH.js → chunk-P4WOAOJW.js} +141 -64
  121. package/chunks/{chunk-ZFDTEDCF.js → chunk-PB3MBFKG.js} +6 -6
  122. package/chunks/{chunk-3RN6GBKS.js → chunk-PLDQBIO6.js} +1 -1
  123. package/chunks/{chunk-FNQ6T3CV.js → chunk-PONHVBRT.js} +10 -7
  124. package/chunks/{chunk-CIKQ7KKO.js → chunk-PT722TDT.js} +271 -376
  125. package/chunks/chunk-Q43KPN7X.js +2196 -0
  126. package/chunks/{chunk-VDDGDZMA.js → chunk-QHWCP53L.js} +14 -7
  127. package/chunks/{chunk-MVSUYZDT.js → chunk-QIZKCVM3.js} +4 -4
  128. package/chunks/{chunk-QAF7NMK7.js → chunk-RCUQIPTN.js} +1 -1
  129. package/chunks/{chunk-6FGBXPWM.js → chunk-RPLGZJV2.js} +38 -44
  130. package/chunks/{chunk-GSN55ZRI.js → chunk-S4WJVPZW.js} +19 -7
  131. package/chunks/{chunk-6AM5D4ME.js → chunk-S6LOFUVP.js} +0 -12
  132. package/chunks/{chunk-BULDBTYC.js → chunk-S7W2GKIO.js} +1 -28
  133. package/chunks/{chunk-MUP3T3AD.js → chunk-SGFT55XI.js} +1 -35
  134. package/chunks/{chunk-VYPFXUCB.js → chunk-SZ3KHTDR.js} +1 -1
  135. package/chunks/chunk-T26EAKDL.js +13 -0
  136. package/chunks/{chunk-UDX5OBWR.js → chunk-T2QMKU3R.js} +80 -2
  137. package/chunks/{chunk-IKYJHJNF.js → chunk-T3O2B4XO.js} +3 -3
  138. package/chunks/{chunk-RF3EXIHJ.js → chunk-T4TXDL7G.js} +32 -21
  139. package/chunks/{chunk-J24WCGIN.js → chunk-TBBV36Y4.js} +4 -4
  140. package/chunks/{chunk-LKEJ26GS.js → chunk-TCIFAA7K.js} +16 -11
  141. package/chunks/{chunk-JXJFVC6E.js → chunk-TDL6LB4K.js} +46 -11
  142. package/chunks/{chunk-7ZCNENPP.js → chunk-TFRMVU6R.js} +1 -1
  143. package/chunks/{chunk-VULLI6WQ.js → chunk-TV64SXKD.js} +6 -6
  144. package/chunks/{chunk-FQK6JAFG.js → chunk-U3E3UQAA.js} +4 -4
  145. package/chunks/{chunk-LK7CHLVP.js → chunk-U4VTUMMK.js} +0 -60
  146. package/chunks/{chunk-ACY3A37B.js → chunk-UBEPNVDI.js} +23 -18
  147. package/chunks/{chunk-NL7LTRLR.js → chunk-UHUSJ6X7.js} +29 -68
  148. package/chunks/{chunk-ZOIFNCKL.js → chunk-UPUG4GXM.js} +3 -23
  149. package/chunks/{chunk-6GMVPFB2.js → chunk-UWMLWVCA.js} +19 -6
  150. package/chunks/{chunk-IKCX4CCL.js → chunk-VCPIZRYH.js} +118 -95
  151. package/chunks/{chunk-ZNAUOR2I.js → chunk-VWOOBLTY.js} +2 -2
  152. package/chunks/{chunk-YX324OPW.js → chunk-VYOXCEPJ.js} +1 -1
  153. package/chunks/{chunk-USTWD7QV.js → chunk-W4MIWP6M.js} +26 -16
  154. package/chunks/{chunk-HTR4WV6U.js → chunk-W4RQUHY3.js} +31 -1
  155. package/chunks/{chunk-DLWL3Z7A.js → chunk-WBSMNTSV.js} +3 -3
  156. package/chunks/{chunk-IO3IX5Q4.js → chunk-WUZ7H6DP.js} +1 -1
  157. package/chunks/{chunk-2JZBVYTU.js → chunk-WZRWHXFE.js} +1 -8
  158. package/chunks/{chunk-PHOF65IG.js → chunk-X5WNMMIA.js} +23553 -34321
  159. package/chunks/chunk-XBYYDKAZ.js +80 -0
  160. package/chunks/{chunk-COH43MRJ.js → chunk-XCGIMOLN.js} +27 -1
  161. package/chunks/{chunk-WCXCRJYB.js → chunk-XFZYFU3I.js} +1 -1
  162. package/chunks/{chunk-3QMGYBFN.js → chunk-XWWKIXVD.js} +1 -80
  163. package/chunks/{chunk-3SJ43L4W.js → chunk-XZC5VLBZ.js} +2 -0
  164. package/chunks/{chunk-UUUTRMI2.js → chunk-Y4IHBGBP.js} +1 -1
  165. package/chunks/{chunk-PR75REBZ.js → chunk-Y6AXW2OG.js} +12 -82
  166. package/chunks/{chunk-IPUUTYMV.js → chunk-YDLJGZHL.js} +1 -1
  167. package/chunks/{chunk-IJTOWOD7.js → chunk-YGF33UXG.js} +82 -8
  168. package/chunks/chunk-Z4X5MTRT.js +133 -0
  169. package/chunks/{chunk-UW5EOVUN.js → chunk-ZBVS26BY.js} +4 -4
  170. package/chunks/{chunk-ZD6UTE4A.js → chunk-ZHBO7WVX.js} +1 -1
  171. package/chunks/{chunk-HTO4JFDZ.js → chunk-ZPJWUGCS.js} +0 -1
  172. package/chunks/{chunk-KIM5GUMA.js → chunk-ZURDMIDR.js} +368 -156
  173. package/chunks/{computer-use-SOQ4E3VX.js → computer-use-ZTIDHMMA.js} +49 -50
  174. package/chunks/{config-utils-7V7GGIW6.js → config-utils-NYSXDMEQ.js} +4 -3
  175. package/chunks/contextCommand-2PIEU37Z.js +79 -0
  176. package/chunks/core-runtime-3XEYLQFK.js +133 -0
  177. package/chunks/{create-sub-session-QRJLW5BV.js → create-sub-session-R76FVXCI.js} +46 -47
  178. package/chunks/{create-sub-session-IWW2IZ2T.js → create-sub-session-SBYUMSSS.js} +3 -3
  179. package/chunks/{cron-create-YIID5XAW.js → cron-create-2QK6TCEC.js} +6 -6
  180. package/chunks/{cron-delete-ZVHYCEP2.js → cron-delete-FDCDFYMG.js} +5 -5
  181. package/chunks/{cron-list-XEGS463Q.js → cron-list-XN3WVBTP.js} +6 -6
  182. package/chunks/{daemon-YO6433NF.js → daemon-Q2AB5Z23.js} +356 -15
  183. package/chunks/daemon-status-provider-3XJI6CAL.js +89 -0
  184. package/chunks/daemon-trust-policy-ILUDTLHD.js +84 -0
  185. package/chunks/daemon-trust-policy-monitor-HS3PKKRO.js +171 -0
  186. package/chunks/{de-HGRCYDEJ.js → de-SY6O76BF.js} +6 -1
  187. package/chunks/deferred-core-runtime-X4QV662U.js +88 -0
  188. package/chunks/dist-BSTVRPMT.js +4227 -0
  189. package/chunks/{dist-46NQKLTW.js → dist-DOLYHMXE.js} +2 -2
  190. package/chunks/{dist-AIKFMUKK.js → dist-HVRQ2CFL.js} +271 -11
  191. package/chunks/{dist-WEAHOXDM.js → dist-IXQEQWRG.js} +2 -1
  192. package/chunks/{dist-BBLXMS3N.js → dist-SSU66DM4.js} +3 -3
  193. package/chunks/{dist-F6IBUDR4.js → dist-SV7Q3AWJ.js} +1 -1
  194. package/chunks/{dist-YFNEUWSE.js → dist-YGBBMK3Z.js} +1 -1
  195. package/chunks/earlyInputCapture-XKLZT7ZD.js +81 -0
  196. package/chunks/{edit-OBDSQURM.js → edit-HHGIOTQ2.js} +47 -48
  197. package/chunks/{en-MTWBNGDO.js → en-NBK3JKCE.js} +9 -1
  198. package/chunks/{enter-worktree-U6MRPQ2P.js → enter-worktree-ZN7PUQ46.js} +47 -48
  199. package/chunks/{enterPlanMode-BC5QUZZ2.js → enterPlanMode-EIFIDSIV.js} +47 -48
  200. package/chunks/{environment-W5UFC2CH.js → environment-XXQ75D2Q.js} +48 -49
  201. package/chunks/errors-4GMVU7CK.js +87 -0
  202. package/chunks/esm-K5FARBNI.js +5548 -0
  203. package/chunks/{exit-worktree-DGNYMECB.js → exit-worktree-GXMI4ATY.js} +47 -48
  204. package/chunks/exitPlanMode-34UVY7M6.js +72 -0
  205. package/chunks/{fast-path-JJZFJANL.js → fast-path-VPIVA7L6.js} +16 -6
  206. package/chunks/{fr-45RLL55O.js → fr-4KG5V7UT.js} +6 -1
  207. package/chunks/{gemini-QS36EBZV.js → gemini-4BWIK4WD.js} +102 -99
  208. package/chunks/{geminiContentGenerator-AG4KB6CV.js → geminiContentGenerator-3XVV5MSS.js} +40 -11
  209. package/chunks/{getMachineId-bsd-V7W3GODC.js → getMachineId-bsd-FG7IUY6U.js} +1 -1
  210. package/chunks/{getMachineId-darwin-TDO75DQP.js → getMachineId-darwin-GLCJI2RA.js} +1 -1
  211. package/chunks/{getMachineId-linux-TF43WQT2.js → getMachineId-linux-O6OPPAKO.js} +1 -1
  212. package/chunks/{getMachineId-unsupported-ZGUO3TXT.js → getMachineId-unsupported-S6CKYVGC.js} +1 -1
  213. package/chunks/{getMachineId-win-ECFYZZFQ.js → getMachineId-win-X5SRNEH7.js} +1 -1
  214. package/chunks/{glob-V7R3PSK3.js → glob-TZ2ABCJG.js} +47 -48
  215. package/chunks/{grep-QYPSK7OP.js → grep-BEF463NA.js} +49 -49
  216. package/chunks/handleAutoUpdate-L6ERF36Y.js +80 -0
  217. package/chunks/i18n-FMM5FDXR.js +96 -0
  218. package/chunks/{image-gen-Z3VPGKRC.js → image-gen-HHVLF7HS.js} +12 -12
  219. package/chunks/initializer-625TIAIO.js +85 -0
  220. package/chunks/installationInfo-6AM4I2Y3.js +79 -0
  221. package/chunks/{ja-B7DF7DFG.js → ja-F3GSQXMF.js} +6 -1
  222. package/chunks/{keychain-token-storage-MDTG3WRM.js → keychain-token-storage-72IYCAZV.js} +3 -3
  223. package/chunks/lib-RUF3WZA6.js +9 -0
  224. package/chunks/list-L2GA674Y.js +88 -0
  225. package/chunks/{list-agents-5KJJHR6I.js → list-agents-R6KDXQR3.js} +3 -3
  226. package/chunks/loadedSettingsAdapter-SPUTNKAV.js +82 -0
  227. package/chunks/{loggingContentGenerator-HS3S5H3Q.js → loggingContentGenerator-LKOF7XI7.js} +78 -113
  228. package/chunks/{loop-wakeup-FXKNNYSY.js → loop-wakeup-3IQKCYAH.js} +7 -7
  229. package/chunks/{ls-NTK6VOQJ.js → ls-DKZ37A7N.js} +5 -5
  230. package/chunks/{lsp-2JI24STP.js → lsp-QNWN7KN3.js} +3 -3
  231. package/chunks/{managed-npm-update-JYEMMXA3.js → managed-npm-update-ACQGGIN5.js} +47 -48
  232. package/chunks/mcp-SZLHKFJW.js +82 -0
  233. package/chunks/{monitor-R3ODH5U6.js → monitor-DF52UVHI.js} +47 -48
  234. package/chunks/nonInteractiveCli-5T7KYKLK.js +144 -0
  235. package/chunks/{notebook-edit-BNOK452R.js → notebook-edit-FCWS4XVN.js} +47 -48
  236. package/chunks/{openaiContentGenerator-WMCU3O2H.js → openaiContentGenerator-7LDK3DCJ.js} +26 -27
  237. package/chunks/pidfile-6ERW3DF4.js +85 -0
  238. package/chunks/process-registry-2CHQBXH5.js +157 -0
  239. package/chunks/{processUtils-RT7UNCC2.js → processUtils-COKZAMUP.js} +2 -2
  240. package/chunks/{pt-22Q3FP73.js → pt-EQ33KWEN.js} +6 -1
  241. package/chunks/{qwenContentGenerator-HHCRK4SX.js → qwenContentGenerator-TKWUMR7N.js} +52 -53
  242. package/chunks/{qwenOAuth2-OWLB5AKH.js → qwenOAuth2-7HMU47SF.js} +10 -10
  243. package/chunks/read-file-X6DRC574.js +29 -0
  244. package/chunks/{read-mcp-resource-4DKQWGHD.js → read-mcp-resource-GFTWYXMK.js} +4 -4
  245. package/chunks/{record-artifact-RQKFYO5B.js → record-artifact-XAMSFSW4.js} +3 -3
  246. package/chunks/resumeHistoryUtils-PFPM2GWM.js +90 -0
  247. package/chunks/ripGrep-OWV2IVJC.js +72 -0
  248. package/chunks/{ru-FZCNZHDC.js → ru-7OZAUKGG.js} +6 -1
  249. package/chunks/{run-qwen-serve-FU6HEM4J.js → run-qwen-serve-TSTCO4XE.js} +953 -249
  250. package/chunks/{runtime-XXRRTNP6.js → runtime-DAUPSUKI.js} +56 -56
  251. package/chunks/{scheduler-G2ZS2Z7E.js → scheduler-KMADMT26.js} +46 -47
  252. package/chunks/{sdk-exporters-grpc-AK3LGHNO.js → sdk-exporters-grpc-54L4LS5L.js} +4 -4
  253. package/chunks/{sdk-exporters-http-FYBSUCPD.js → sdk-exporters-http-WO556XNU.js} +7 -7
  254. package/chunks/{sdk-impl-GMVPB7NB.js → sdk-impl-LPAVACSF.js} +14 -14
  255. package/chunks/{send-message-Q6OOR6BR.js → send-message-SAWK4DZX.js} +6 -6
  256. package/chunks/serve-NNRWS6F4.js +88 -0
  257. package/chunks/{server-4UMH7OIZ.js → server-WEH7DVCH.js} +3691 -823
  258. package/chunks/{session-K3O3Q2SV.js → session-WXC56V2I.js} +98 -95
  259. package/chunks/{settings-CR2EWTBA.js → settings-DJDXFDZ3.js} +55 -56
  260. package/chunks/shell-JN5VRQXD.js +82 -0
  261. package/chunks/{skill-I3SDA4MB.js → skill-SGXPKJCS.js} +20 -21
  262. package/chunks/skill-settings-VJ5PDMZI.js +90 -0
  263. package/chunks/spawnChannel-ETMJW7YX.js +81 -0
  264. package/chunks/standalone-update-MK3Z7KBI.js +91 -0
  265. package/chunks/{startInteractiveUI-SLZGHRPH.js → startInteractiveUI-ZCGIXPGT.js} +724 -383
  266. package/chunks/{syntheticOutput-I3757IWH.js → syntheticOutput-355CB6CJ.js} +4 -4
  267. package/chunks/{task-create-N7WQSGYA.js → task-create-INGWNUG4.js} +10 -10
  268. package/chunks/{task-list-FOPULZEP.js → task-list-5XNNGTF4.js} +7 -7
  269. package/chunks/{task-stop-H6RHXFVQ.js → task-stop-4ROAOBXH.js} +3 -3
  270. package/chunks/{task-update-M57TFZJT.js → task-update-CRK5VWWZ.js} +10 -10
  271. package/chunks/{team-create-YJALH5D2.js → team-create-QQGAJG7P.js} +49 -50
  272. package/chunks/{team-delete-QE2UXJL7.js → team-delete-S2RCXA4P.js} +7 -7
  273. package/chunks/{team-plan-approval-34QFYKGN.js → team-plan-approval-RT7Q5R6O.js} +47 -48
  274. package/chunks/theme-manager-EEWIQJ7J.js +76 -0
  275. package/chunks/{todoWrite-VQ7FKOHL.js → todoWrite-7WM3VDMY.js} +7 -7
  276. package/chunks/{tool-search-NF7GB6LE.js → tool-search-Z3Z4AYKP.js} +19 -21
  277. package/chunks/total-session-admission-44JKRWQD.js +84 -0
  278. package/chunks/trustedFolders-X2JEIO57.js +94 -0
  279. package/chunks/{update-relaunch-WBUZJC5O.js → update-relaunch-VWNPYDIP.js} +5 -5
  280. package/chunks/updateCheck-KAQH67DV.js +91 -0
  281. package/chunks/useAutoAcceptIndicator-JH6BCF7S.js +92 -0
  282. package/chunks/{validateNonInterActiveAuth-3R223G3R.js → validateNonInterActiveAuth-GIUJ2UFS.js} +93 -90
  283. package/chunks/{version-HS7YSFHV.js → version-BGLYIJUY.js} +1 -1
  284. package/chunks/{web-fetch-NKCSG7ZE.js → web-fetch-OTDU4VQF.js} +19 -21
  285. package/chunks/{web-search-S62WAP4S.js → web-search-FP6SIHPR.js} +13 -13
  286. package/chunks/{workflow-QAGU5RU4.js → workflow-YCIVBYSB.js} +48 -49
  287. package/chunks/workspace-providers-status-S35YAIUS.js +85 -0
  288. package/chunks/{workspace-registration-store-24JMHDGF.js → workspace-registration-store-OTMS3H4C.js} +1 -1
  289. package/chunks/workspace-registry-O63R6IZ4.js +92 -0
  290. package/chunks/workspace-service-M6LLHKJ5.js +99 -0
  291. package/chunks/workspace-skills-status-C2V7BAIS.js +85 -0
  292. package/chunks/workspace-trust-reconciler-IBUPOUJN.js +345 -0
  293. package/chunks/write-file-3BZC3EAE.js +72 -0
  294. package/chunks/xterm-headless-NTYVIBT3.js +3475 -0
  295. package/chunks/{zh-LUIGBD55.js → zh-H3YDK5QW.js} +9 -1
  296. package/chunks/{zh-TW-F5KG2IYD.js → zh-TW-JYCP7XUA.js} +9 -1
  297. package/chunks/zoom-image-TZ6S2O57.js +351 -0
  298. package/cli.js +13 -13
  299. package/locales/ca.js +7 -2
  300. package/locales/de.js +7 -2
  301. package/locales/en.js +10 -2
  302. package/locales/fr.js +7 -2
  303. package/locales/ja.js +7 -2
  304. package/locales/pt.js +7 -2
  305. package/locales/ru.js +7 -2
  306. package/locales/zh-TW.js +10 -2
  307. package/locales/zh.js +10 -2
  308. package/package.json +5 -4
  309. package/web-shell/assets/{arc-DcbWnB9T.js → arc-75-Wdeo3.js} +1 -1
  310. package/web-shell/assets/{architectureDiagram-3BPJPVTR-kMMF5sud.js → architectureDiagram-3BPJPVTR-FKeXQbyP.js} +1 -1
  311. package/web-shell/assets/{blockDiagram-GPEHLZMM-Htl9vTJS.js → blockDiagram-GPEHLZMM-CY0vc-A3.js} +1 -1
  312. package/web-shell/assets/{c4Diagram-AAUBKEIU-BnZnm0mQ.js → c4Diagram-AAUBKEIU-CNP-A-8u.js} +1 -1
  313. package/web-shell/assets/channel-DPYMT76A.js +1 -0
  314. package/web-shell/assets/{chunk-2J33WTMH-DziB7kDG.js → chunk-2J33WTMH-GybS4Gii.js} +1 -1
  315. package/web-shell/assets/{chunk-4BX2VUAB-CmkD8daw.js → chunk-4BX2VUAB-02H91V8v.js} +1 -1
  316. package/web-shell/assets/{chunk-55IACEB6-CHAd9A_U.js → chunk-55IACEB6-D3M-2VT6.js} +1 -1
  317. package/web-shell/assets/{chunk-727SXJPM-Dqaam3fE.js → chunk-727SXJPM-CCu29u4H.js} +1 -1
  318. package/web-shell/assets/{chunk-AQP2D5EJ-D_-saBYM.js → chunk-AQP2D5EJ-CaFKWgrn.js} +1 -1
  319. package/web-shell/assets/{chunk-FMBD7UC4-B9r_veWD.js → chunk-FMBD7UC4-ZZpPqIwQ.js} +1 -1
  320. package/web-shell/assets/{chunk-ND2GUHAM-B3EaCSpL.js → chunk-ND2GUHAM-D22DqGs8.js} +1 -1
  321. package/web-shell/assets/{chunk-QZHKN3VN-CYq8x9mn.js → chunk-QZHKN3VN-Bu85S0fw.js} +1 -1
  322. package/web-shell/assets/classDiagram-4FO5ZUOK--JstsIgL.js +1 -0
  323. package/web-shell/assets/classDiagram-v2-Q7XG4LA2--JstsIgL.js +1 -0
  324. package/web-shell/assets/{cose-bilkent-S5V4N54A-D0ng4uiB.js → cose-bilkent-S5V4N54A-f1CK1Gwe.js} +1 -1
  325. package/web-shell/assets/{dagre-BM42HDAG-DCZollQv.js → dagre-BM42HDAG-D0Ow8F_n.js} +1 -1
  326. package/web-shell/assets/{diagram-2AECGRRQ-Dfk2pWS0.js → diagram-2AECGRRQ-BPrmTWp8.js} +1 -1
  327. package/web-shell/assets/{diagram-5GNKFQAL-kX38ltWR.js → diagram-5GNKFQAL-HccuFAzy.js} +1 -1
  328. package/web-shell/assets/{diagram-KO2AKTUF-CJz2vsXh.js → diagram-KO2AKTUF-BrS76mbA.js} +1 -1
  329. package/web-shell/assets/{diagram-LMA3HP47-BvMLZm_7.js → diagram-LMA3HP47-V7T9lU-5.js} +1 -1
  330. package/web-shell/assets/{diagram-OG6HWLK6-l7kfStkO.js → diagram-OG6HWLK6-DKidyJMR.js} +1 -1
  331. package/web-shell/assets/{erDiagram-TEJ5UH35-BSVa8GGT.js → erDiagram-TEJ5UH35-DBadZIkp.js} +1 -1
  332. package/web-shell/assets/{flowDiagram-I6XJVG4X-CoawKIXH.js → flowDiagram-I6XJVG4X-BymfqdNJ.js} +1 -1
  333. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DFUDH0zF.js → ganttDiagram-6RSMTGT7-DOw340jf.js} +1 -1
  334. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Y2pvpT4e.js → gitGraphDiagram-PVQCEYII-_8EiD8sl.js} +1 -1
  335. package/web-shell/assets/{index-D0GX0zZf.js → index-CKIadvET.js} +1 -1
  336. package/web-shell/assets/index-D1eXNRHe.js +1389 -0
  337. package/web-shell/assets/index-DVLD4CQq.css +5 -0
  338. package/web-shell/assets/{infoDiagram-5YYISTIA-CU8_zLiX.js → infoDiagram-5YYISTIA-D61KYQBu.js} +1 -1
  339. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-AVQiV0DU.js → ishikawaDiagram-YF4QCWOH-CsiXSpNx.js} +1 -1
  340. package/web-shell/assets/{journeyDiagram-JHISSGLW-DQ0VSKa3.js → journeyDiagram-JHISSGLW-Sdfionyh.js} +1 -1
  341. package/web-shell/assets/{kanban-definition-UN3LZRKU-BqnWqsE_.js → kanban-definition-UN3LZRKU-C3WI3Cnl.js} +1 -1
  342. package/web-shell/assets/{linear-BkoihsaA.js → linear-Dpigcc62.js} +1 -1
  343. package/web-shell/assets/{mermaid.core-5RJs-31j.js → mermaid.core-Ct97pqgW.js} +5 -5
  344. package/web-shell/assets/{mindmap-definition-RKZ34NQL-D33Bxnpd.js → mindmap-definition-RKZ34NQL-BzeaN0rB.js} +1 -1
  345. package/web-shell/assets/{pieDiagram-4H26LBE5-BuEAw3BH.js → pieDiagram-4H26LBE5-CvjgcbVD.js} +1 -1
  346. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Kox_usEq.js → quadrantDiagram-W4KKPZXB-BUzgTNdH.js} +1 -1
  347. package/web-shell/assets/{requirementDiagram-4Y6WPE33-CNjeUif0.js → requirementDiagram-4Y6WPE33-B7zKlgUQ.js} +1 -1
  348. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-BCd2OL_U.js → sankeyDiagram-5OEKKPKP-Bb9CQgrT.js} +1 -1
  349. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CF2ZTsz0.js → sequenceDiagram-3UESZ5HK-DJ6V7itG.js} +1 -1
  350. package/web-shell/assets/{stateDiagram-AJRCARHV-qenSzHtm.js → stateDiagram-AJRCARHV-IImflERY.js} +1 -1
  351. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CYI_YoNR.js +1 -0
  352. package/web-shell/assets/{timeline-definition-PNZ67QCA-B5DyWdgs.js → timeline-definition-PNZ67QCA-6Q_uWHKh.js} +1 -1
  353. package/web-shell/assets/{vennDiagram-CIIHVFJN-DqP4I_o_.js → vennDiagram-CIIHVFJN-TmyKyjwv.js} +1 -1
  354. package/web-shell/assets/{wardley-L42UT6IY-CJe2e4mg.js → wardley-L42UT6IY-CRh9uiPv.js} +1 -1
  355. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BMDSw-Rr.js → wardleyDiagram-YWT4CUSO-59TKAW8w.js} +1 -1
  356. package/web-shell/assets/{xychartDiagram-2RQKCTM6-BTVZYkxD.js → xychartDiagram-2RQKCTM6-GCSUIK2L.js} +1 -1
  357. package/web-shell/index.html +2 -2
  358. package/chunks/MaxSizedBox-5DPPWPGT.js +0 -85
  359. package/chunks/agent-6ODUANDO.js +0 -81
  360. package/chunks/agent-headless-7BYQTMHW.js +0 -75
  361. package/chunks/bridge-ZUB64FAE.js +0 -90
  362. package/chunks/chunk-LEH5C7FV.js +0 -232
  363. package/chunks/chunk-SZRN75WQ.js +0 -29
  364. package/chunks/chunk-UGYMA4EI.js +0 -219
  365. package/chunks/chunk-Z2BC6UJ5.js +0 -8575
  366. package/chunks/contextCommand-JLHYA34Z.js +0 -80
  367. package/chunks/daemon-status-provider-2233Q37D.js +0 -89
  368. package/chunks/earlyInputCapture-A7NDU3PF.js +0 -82
  369. package/chunks/errors-M7CLORXH.js +0 -88
  370. package/chunks/exitPlanMode-GXTBWQAR.js +0 -403
  371. package/chunks/handleAutoUpdate-6DBEZYPV.js +0 -81
  372. package/chunks/i18n-VUJJZIMU.js +0 -97
  373. package/chunks/initializer-UWAK5U5O.js +0 -86
  374. package/chunks/installationInfo-6O2YAA52.js +0 -80
  375. package/chunks/list-GB4ESM3T.js +0 -89
  376. package/chunks/loadedSettingsAdapter-OT6JVQ7U.js +0 -83
  377. package/chunks/mcp-6DBDJPFU.js +0 -83
  378. package/chunks/nonInteractiveCli-MOYCYBBU.js +0 -141
  379. package/chunks/pidfile-TFRZZZIO.js +0 -86
  380. package/chunks/read-file-APMO3PSX.js +0 -31
  381. package/chunks/resumeHistoryUtils-6KRYEAWZ.js +0 -91
  382. package/chunks/ripGrep-BEJDEDXW.js +0 -73
  383. package/chunks/serve-7BSTXJ4T.js +0 -89
  384. package/chunks/shell-HH3PF3A2.js +0 -83
  385. package/chunks/spawnChannel-RWNDBXGA.js +0 -82
  386. package/chunks/src-GE4TTTML.js +0 -3147
  387. package/chunks/standalone-update-Q6WFRZZQ.js +0 -92
  388. package/chunks/theme-manager-SWRILQHI.js +0 -77
  389. package/chunks/total-session-admission-DLHHHLD3.js +0 -84
  390. package/chunks/trustedFolders-KHXHY6PY.js +0 -93
  391. package/chunks/updateCheck-RKL6M5XN.js +0 -92
  392. package/chunks/useAutoAcceptIndicator-CFQ5BUJL.js +0 -93
  393. package/chunks/workspace-providers-status-QSVZUETE.js +0 -86
  394. package/chunks/workspace-registry-UT4RBNBM.js +0 -88
  395. package/chunks/workspace-service-JFWRUS4V.js +0 -98
  396. package/chunks/workspace-skills-status-ZBBKJOI2.js +0 -85
  397. package/chunks/write-file-VHIXW5M7.js +0 -73
  398. package/web-shell/assets/channel-Cq7YKtfC.js +0 -1
  399. package/web-shell/assets/classDiagram-4FO5ZUOK-CQ9aC1Tg.js +0 -1
  400. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CQ9aC1Tg.js +0 -1
  401. package/web-shell/assets/index-D9haPt0X.css +0 -5
  402. package/web-shell/assets/index-ckX9Pq5k.js +0 -1230
  403. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-B7W4zlCr.js +0 -1
  404. package/chunks/{chunk-TARRHLLG.js → chunk-QUGAUQGJ.js} +25 -25
  405. package/chunks/{chunk-U7ZFW55U.js → chunk-VOQXFAY5.js} +977 -977
  406. /package/chunks/{chunk-LXXMOYPL.js → chunk-VXZBKKQR.js} +0 -0
@@ -12,90 +12,6 @@ import {
12
12
  __name
13
13
  } from "./chunk-J2S4EL5Y.js";
14
14
 
15
- // packages/channels/base/dist/sanitize.js
16
- init_esbuild_shims();
17
- var PROMPT_UNSAFE_INVISIBLES = new RegExp("[\\u0080-\\u009f\\p{Cf}\\u2028\\u2029]|\\p{Variation_Selector}", "gu");
18
- function truncateCodePoints(str, max) {
19
- const cp = Array.from(str);
20
- return cp.length > max ? cp.slice(0, max).join("") : str;
21
- }
22
- __name(truncateCodePoints, "truncateCodePoints");
23
- function sanitizeSenderName(name) {
24
- const cleaned = name.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/[[\]\r\n]/g, " ");
25
- return truncateCodePoints(cleaned, 64).trim() || "unknown";
26
- }
27
- __name(sanitizeSenderName, "sanitizeSenderName");
28
- function sanitizeQuotedText(text, maxLen) {
29
- const cleaned = text.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/["[\]]/g, " ");
30
- const cp = Array.from(cleaned);
31
- return cp.length > maxLen ? cp.slice(0, maxLen - 1).join("") + "\u2026" : cleaned;
32
- }
33
- __name(sanitizeQuotedText, "sanitizeQuotedText");
34
- function sanitizePromptText(text) {
35
- return text.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/^([ \t]*)\[([^\]\r\n]{1,64})\](:?)/gm, "$1$2$3").replace(/[\u0000-\u001f\u007f]/g, " ");
36
- }
37
- __name(sanitizePromptText, "sanitizePromptText");
38
- function sanitizePromptPath(path4) {
39
- const cleaned = path4.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ");
40
- return truncateCodePoints(cleaned, 1024);
41
- }
42
- __name(sanitizePromptPath, "sanitizePromptPath");
43
- function sanitizeLogText(text, maxLen) {
44
- return truncateCodePoints(text, maxLen).replace(/\n/g, "\\n").replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ");
45
- }
46
- __name(sanitizeLogText, "sanitizeLogText");
47
-
48
- // packages/channels/base/dist/index.js
49
- init_esbuild_shims();
50
-
51
- // packages/channels/base/dist/paths.js
52
- init_esbuild_shims();
53
- import * as crypto from "node:crypto";
54
- import * as fs from "node:fs";
55
- import * as path from "node:path";
56
- import * as os from "node:os";
57
- function resolvePath(dir) {
58
- let resolved = dir;
59
- if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
60
- const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
61
- resolved = path.join(os.homedir(), ...relativeSegments);
62
- }
63
- return path.resolve(resolved);
64
- }
65
- __name(resolvePath, "resolvePath");
66
- function getGlobalQwenDir() {
67
- const envDir = process.env["QWEN_HOME"];
68
- if (envDir) {
69
- return resolvePath(envDir);
70
- }
71
- const homeDir = os.homedir();
72
- return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
73
- }
74
- __name(getGlobalQwenDir, "getGlobalQwenDir");
75
- function canonicalizeWorkspacePath(workspaceCwd) {
76
- const resolved = resolvePath(workspaceCwd);
77
- try {
78
- return fs.realpathSync.native(resolved);
79
- } catch {
80
- return resolved;
81
- }
82
- }
83
- __name(canonicalizeWorkspacePath, "canonicalizeWorkspacePath");
84
- function getWorkspaceScopeDirName(workspaceCwd) {
85
- const resolved = canonicalizeWorkspacePath(workspaceCwd);
86
- const hash = crypto.createHash("sha256").update(resolved).digest("hex").slice(0, 12);
87
- const base = path.basename(resolved).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 32);
88
- return base ? `${base}-${hash}` : hash;
89
- }
90
- __name(getWorkspaceScopeDirName, "getWorkspaceScopeDirName");
91
-
92
- // packages/channels/base/dist/AcpBridge.js
93
- init_esbuild_shims();
94
- import { spawn } from "node:child_process";
95
- import { randomUUID } from "node:crypto";
96
- import { Readable, Writable } from "node:stream";
97
- import { EventEmitter } from "node:events";
98
-
99
15
  // packages/channels/base/dist/ChannelLoopTools.js
100
16
  init_esbuild_shims();
101
17
  var CHANNEL_LOOP_MCP_SERVER_NAME = "channel_loop";
@@ -253,8 +169,290 @@ function readId(args) {
253
169
  }
254
170
  __name(readId, "readId");
255
171
 
172
+ // packages/channels/base/dist/sanitize.js
173
+ init_esbuild_shims();
174
+ var PROMPT_UNSAFE_INVISIBLES = new RegExp("[\\u0080-\\u009f\\p{Cf}\\u2028\\u2029]|\\p{Variation_Selector}", "gu");
175
+ function truncateCodePoints(str, max) {
176
+ const cp = Array.from(str);
177
+ return cp.length > max ? cp.slice(0, max).join("") : str;
178
+ }
179
+ __name(truncateCodePoints, "truncateCodePoints");
180
+ function sanitizeSenderName(name) {
181
+ const cleaned = name.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/[[\]\r\n]/g, " ");
182
+ return truncateCodePoints(cleaned, 64).trim() || "unknown";
183
+ }
184
+ __name(sanitizeSenderName, "sanitizeSenderName");
185
+ function sanitizeQuotedText(text, maxLen) {
186
+ const cleaned = text.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/["[\]]/g, " ");
187
+ const cp = Array.from(cleaned);
188
+ return cp.length > maxLen ? cp.slice(0, maxLen - 1).join("") + "\u2026" : cleaned;
189
+ }
190
+ __name(sanitizeQuotedText, "sanitizeQuotedText");
191
+ function sanitizePromptText(text) {
192
+ return text.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/^([ \t]*)\[([^\]\r\n]{1,64})\](:?)/gm, "$1$2$3").replace(/[\u0000-\u001f\u007f]/g, " ");
193
+ }
194
+ __name(sanitizePromptText, "sanitizePromptText");
195
+ function sanitizePromptPath(path4) {
196
+ const cleaned = path4.replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ");
197
+ return truncateCodePoints(cleaned, 1024);
198
+ }
199
+ __name(sanitizePromptPath, "sanitizePromptPath");
200
+ function sanitizeLogText(text, maxLen) {
201
+ return truncateCodePoints(text, maxLen).replace(/\n/g, "\\n").replace(PROMPT_UNSAFE_INVISIBLES, " ").replace(/[\u0000-\u001f\u007f]/g, " ");
202
+ }
203
+ __name(sanitizeLogText, "sanitizeLogText");
204
+
205
+ // packages/channels/base/dist/PairingStore.js
206
+ init_esbuild_shims();
207
+ import * as crypto2 from "node:crypto";
208
+ import * as fs2 from "node:fs";
209
+ import * as path2 from "node:path";
210
+
211
+ // packages/channels/base/dist/paths.js
212
+ init_esbuild_shims();
213
+ import * as crypto from "node:crypto";
214
+ import * as fs from "node:fs";
215
+ import * as path from "node:path";
216
+ import * as os from "node:os";
217
+ function resolvePath(dir) {
218
+ let resolved = dir;
219
+ if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
220
+ const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
221
+ resolved = path.join(os.homedir(), ...relativeSegments);
222
+ }
223
+ return path.resolve(resolved);
224
+ }
225
+ __name(resolvePath, "resolvePath");
226
+ function getGlobalQwenDir() {
227
+ const envDir = process.env["QWEN_HOME"];
228
+ if (envDir) {
229
+ return resolvePath(envDir);
230
+ }
231
+ const homeDir = os.homedir();
232
+ return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
233
+ }
234
+ __name(getGlobalQwenDir, "getGlobalQwenDir");
235
+ function canonicalizeWorkspacePath(workspaceCwd) {
236
+ const resolved = resolvePath(workspaceCwd);
237
+ try {
238
+ return fs.realpathSync.native(resolved);
239
+ } catch {
240
+ return resolved;
241
+ }
242
+ }
243
+ __name(canonicalizeWorkspacePath, "canonicalizeWorkspacePath");
244
+ function getWorkspaceScopeDirName(workspaceCwd) {
245
+ const resolved = canonicalizeWorkspacePath(workspaceCwd);
246
+ const hash = crypto.createHash("sha256").update(resolved).digest("hex").slice(0, 12);
247
+ const base = path.basename(resolved).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 32);
248
+ return base ? `${base}-${hash}` : hash;
249
+ }
250
+ __name(getWorkspaceScopeDirName, "getWorkspaceScopeDirName");
251
+
252
+ // packages/channels/base/dist/PairingStore.js
253
+ var SAFE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
254
+ var CODE_LENGTH = 8;
255
+ var EXPIRY_MS = 60 * 60 * 1e3;
256
+ var MAX_PENDING = 3;
257
+ var PairingStore = class {
258
+ static {
259
+ __name(this, "PairingStore");
260
+ }
261
+ dir;
262
+ pendingPath;
263
+ allowlistPath;
264
+ migratedSentinelPath;
265
+ /**
266
+ * @param channelName Channel name the state is keyed by.
267
+ * @param workspaceCwd Workspace working directory to scope the state to.
268
+ * When provided, files live under
269
+ * `<qwen-home>/channels/<workspace-scope>/` so two workspaces using the
270
+ * same channel name never share pairing requests or allowlist entries
271
+ * (see #7017 — sharing them is an authorization-boundary violation in
272
+ * multi-workspace daemon deployments). Omitting it preserves the legacy
273
+ * global layout (`<qwen-home>/channels/`).
274
+ */
275
+ constructor(channelName, workspaceCwd) {
276
+ const channelsRoot = path2.join(getGlobalQwenDir(), "channels");
277
+ this.dir = workspaceCwd ? path2.join(channelsRoot, getWorkspaceScopeDirName(workspaceCwd)) : channelsRoot;
278
+ const safeChannelName = encodeURIComponent(channelName);
279
+ this.pendingPath = path2.join(this.dir, `${safeChannelName}-pairing.json`);
280
+ this.allowlistPath = path2.join(this.dir, `${safeChannelName}-allowlist.json`);
281
+ this.migratedSentinelPath = path2.join(this.dir, `${safeChannelName}.migrated`);
282
+ if (workspaceCwd) {
283
+ this.migrateLegacyState(channelsRoot, channelName);
284
+ }
285
+ }
286
+ /**
287
+ * One-time grandfathering of pre-scoping state: the first time this
288
+ * (workspace, channel) pair is constructed, copy the legacy GLOBAL files in
289
+ * so senders that were already approved stay approved after upgrading.
290
+ *
291
+ * Gated by a per-channel sentinel file inside the scope directory — NOT by
292
+ * the directory itself: one workspace can start several channels in turn,
293
+ * and a directory-level gate would let only the first channel ever migrate.
294
+ * The sentinel is written even when there was nothing to copy, so a legacy
295
+ * file written later (e.g. by an older version still running concurrently)
296
+ * is never absorbed into a scope that already went through this decision.
297
+ *
298
+ * Each file is copied independently and best-effort (an unreadable pairing
299
+ * file must not block the allowlist, and vice versa), via a
300
+ * uniquely-named temp file + atomic rename so a crash mid-copy cannot
301
+ * leave a truncated scoped file behind the closed gate. A file the scoped
302
+ * store already has is never overwritten.
303
+ *
304
+ * Copy, not move: another workspace upgrading later must be able to
305
+ * grandfather the same baseline, and an older qwen version running
306
+ * concurrently still reads the global files.
307
+ *
308
+ * Revocation therefore means REMOVING ENTRIES from the scoped allowlist
309
+ * (and from the legacy global file, while it exists) — not deleting files.
310
+ */
311
+ migrateLegacyState(channelsRoot, channelName) {
312
+ try {
313
+ if (fs2.existsSync(this.migratedSentinelPath)) {
314
+ return;
315
+ }
316
+ const legacyPairs = [
317
+ [
318
+ path2.join(channelsRoot, `${channelName}-pairing.json`),
319
+ this.pendingPath
320
+ ],
321
+ [
322
+ path2.join(channelsRoot, `${channelName}-allowlist.json`),
323
+ this.allowlistPath
324
+ ]
325
+ ];
326
+ this.ensureDir();
327
+ let allSucceeded = true;
328
+ for (const [legacyPath, scopedPath] of legacyPairs) {
329
+ try {
330
+ if (path2.dirname(path2.resolve(legacyPath)) !== channelsRoot) {
331
+ continue;
332
+ }
333
+ if (fs2.existsSync(scopedPath) || !fs2.existsSync(legacyPath)) {
334
+ continue;
335
+ }
336
+ const tmpPath = `${scopedPath}.${process.pid}.migrating`;
337
+ fs2.copyFileSync(legacyPath, tmpPath);
338
+ fs2.renameSync(tmpPath, scopedPath);
339
+ } catch (err) {
340
+ allSucceeded = false;
341
+ process.stderr.write(`[PairingStore] legacy migration of ${path2.basename(legacyPath)} failed for channel "${channelName}": ${err?.message}; will retry on next start
342
+ `);
343
+ }
344
+ }
345
+ if (allSucceeded) {
346
+ fs2.writeFileSync(this.migratedSentinelPath, "");
347
+ }
348
+ } catch (err) {
349
+ process.stderr.write(`[PairingStore] legacy migration failed for channel "${channelName}": ${err?.message}; scoped store starts empty
350
+ `);
351
+ }
352
+ }
353
+ isApproved(senderId) {
354
+ const list = this.readAllowlist();
355
+ return list.includes(senderId);
356
+ }
357
+ /**
358
+ * Create a pairing request for an unknown sender.
359
+ * Returns the code if created, or null if the pending cap is reached.
360
+ * If the sender already has a non-expired pending request, returns that code.
361
+ */
362
+ createRequest(senderId, senderName) {
363
+ const pending = this.readPending();
364
+ const now = Date.now();
365
+ const active = pending.filter((r) => now - r.createdAt < EXPIRY_MS);
366
+ const existing = active.find((r) => r.senderId === senderId);
367
+ if (existing) {
368
+ return existing.code;
369
+ }
370
+ if (active.length >= MAX_PENDING) {
371
+ return null;
372
+ }
373
+ const code = generateCode();
374
+ active.push({ senderId, senderName, code, createdAt: now });
375
+ this.writePending(active);
376
+ return code;
377
+ }
378
+ /**
379
+ * Approve a pairing request by code.
380
+ * Returns the sender ID if found, or null if not found / expired.
381
+ */
382
+ approve(code) {
383
+ const pending = this.readPending();
384
+ const now = Date.now();
385
+ const idx = pending.findIndex((r) => r.code === code.toUpperCase() && now - r.createdAt < EXPIRY_MS);
386
+ if (idx === -1)
387
+ return null;
388
+ const request = pending[idx];
389
+ pending.splice(idx, 1);
390
+ this.writePending(pending);
391
+ const list = this.readAllowlist();
392
+ if (!list.includes(request.senderId)) {
393
+ list.push(request.senderId);
394
+ this.writeAllowlist(list);
395
+ }
396
+ return request;
397
+ }
398
+ listPending() {
399
+ const pending = this.readPending();
400
+ const now = Date.now();
401
+ return pending.filter((r) => now - r.createdAt < EXPIRY_MS);
402
+ }
403
+ getAllowlist() {
404
+ return this.readAllowlist();
405
+ }
406
+ ensureDir() {
407
+ if (!fs2.existsSync(this.dir)) {
408
+ fs2.mkdirSync(this.dir, { recursive: true });
409
+ }
410
+ }
411
+ readPending() {
412
+ try {
413
+ const data = fs2.readFileSync(this.pendingPath, "utf-8");
414
+ return JSON.parse(data);
415
+ } catch {
416
+ return [];
417
+ }
418
+ }
419
+ writePending(requests) {
420
+ this.ensureDir();
421
+ fs2.writeFileSync(this.pendingPath, JSON.stringify(requests, null, 2));
422
+ }
423
+ readAllowlist() {
424
+ try {
425
+ const data = fs2.readFileSync(this.allowlistPath, "utf-8");
426
+ return JSON.parse(data);
427
+ } catch {
428
+ return [];
429
+ }
430
+ }
431
+ writeAllowlist(list) {
432
+ this.ensureDir();
433
+ fs2.writeFileSync(this.allowlistPath, JSON.stringify(list, null, 2));
434
+ }
435
+ };
436
+ function generateCode() {
437
+ let code = "";
438
+ for (let i = 0; i < CODE_LENGTH; i++) {
439
+ code += SAFE_ALPHABET[crypto2.randomInt(SAFE_ALPHABET.length)];
440
+ }
441
+ return code;
442
+ }
443
+ __name(generateCode, "generateCode");
444
+
445
+ // packages/channels/base/dist/index.js
446
+ init_esbuild_shims();
447
+
256
448
  // packages/channels/base/dist/AcpBridge.js
449
+ init_esbuild_shims();
450
+ import { spawn } from "node:child_process";
451
+ import { randomUUID } from "node:crypto";
452
+ import { Readable, Writable } from "node:stream";
453
+ import { EventEmitter } from "node:events";
257
454
  var MID_TURN_QUEUE_DRAIN_METHOD = "craft/drainMidTurnQueue";
455
+ var TODO_STOP_GUARD_CONTINUATION_CLAIM_METHOD = "craft/claimTodoStopGuardContinuation";
258
456
  var ACP_EVENT_LOOP_STALL_RESTART_MS = 5 * 60 * 1e3;
259
457
  var ACP_PERMISSION_RESPONSE_TIMEOUT_MS = 5 * 60 * 1e3;
260
458
  var ACP_EVENT_LOOP_STALL_RE = /^\[perf\] acp agent event loop stall: max=(\d+(?:\.\d+)?)ms/m;
@@ -281,6 +479,8 @@ var AcpBridge = class extends EventEmitter {
281
479
  _availableCommands = [];
282
480
  channelLoopMcpServer;
283
481
  channelLoopToolHandlers = [];
482
+ knownSessionIds = /* @__PURE__ */ new Set();
483
+ sessionBindingTokens = /* @__PURE__ */ new Map();
284
484
  channelLoopMcpRegistered = false;
285
485
  channelLoopMcpRegistration = null;
286
486
  pendingPermissions = /* @__PURE__ */ new Map();
@@ -319,6 +519,8 @@ var AcpBridge = class extends EventEmitter {
319
519
  process.stderr.write(`[AcpBridge] Process exited (code=${code}, signal=${signal})
320
520
  `);
321
521
  this.resolvePendingPermissions();
522
+ this.knownSessionIds.clear();
523
+ this.sessionBindingTokens.clear();
322
524
  this.connection = null;
323
525
  this.child = null;
324
526
  this.emit("disconnected", code, signal);
@@ -357,21 +559,25 @@ var AcpBridge = class extends EventEmitter {
357
559
  });
358
560
  void this.registerChannelLoopMcpServer();
359
561
  }
360
- async newSession(cwd) {
562
+ async newSession(cwd, _options, bindingToken) {
361
563
  const conn = this.ensureConnection();
362
564
  await this.registerChannelLoopMcpServer();
363
565
  const response = await conn.newSession({ cwd, mcpServers: [] });
566
+ this.knownSessionIds.add(response.sessionId);
567
+ this.sessionBindingTokens.set(response.sessionId, bindingToken);
364
568
  return response.sessionId;
365
569
  }
366
- async loadSession(sessionId, cwd) {
570
+ async loadSession(sessionId, cwd, _options, bindingToken) {
367
571
  const conn = this.ensureConnection();
368
572
  await this.registerChannelLoopMcpServer();
369
- const response = await conn.loadSession({
573
+ await conn.loadSession({
370
574
  sessionId,
371
575
  cwd,
372
576
  mcpServers: []
373
577
  });
374
- return response.sessionId;
578
+ this.knownSessionIds.add(sessionId);
579
+ this.sessionBindingTokens.set(sessionId, bindingToken);
580
+ return sessionId;
375
581
  }
376
582
  async prompt(sessionId, text, options) {
377
583
  const conn = this.ensureConnection();
@@ -423,6 +629,19 @@ var AcpBridge = class extends EventEmitter {
423
629
  this.resolvePendingPermissions(sessionId);
424
630
  }
425
631
  }
632
+ async discardSession(sessionId, expectedBindingToken) {
633
+ if (expectedBindingToken !== void 0 && this.sessionBindingTokens.get(sessionId) !== expectedBindingToken) {
634
+ return;
635
+ }
636
+ if (!this.knownSessionIds.delete(sessionId))
637
+ return;
638
+ this.sessionBindingTokens.delete(sessionId);
639
+ this.resolvePendingPermissions(sessionId);
640
+ const conn = this.connection;
641
+ if (!conn || !this.isConnected)
642
+ return;
643
+ await conn.extMethod("qwen/control/session/close", { sessionId });
644
+ }
426
645
  async respondToPermission(requestId, response) {
427
646
  const pending = this.pendingPermissions.get(requestId);
428
647
  if (!pending) {
@@ -439,6 +658,8 @@ var AcpBridge = class extends EventEmitter {
439
658
  }
440
659
  stop() {
441
660
  this.resolvePendingPermissions();
661
+ this.knownSessionIds.clear();
662
+ this.sessionBindingTokens.clear();
442
663
  if (this.child) {
443
664
  this.child.kill();
444
665
  this.child = null;
@@ -615,7 +836,14 @@ var AcpBridge = class extends EventEmitter {
615
836
  return this.handleClientMcpMessage(params);
616
837
  }
617
838
  if (method === MID_TURN_QUEUE_DRAIN_METHOD) {
618
- return { messages: [] };
839
+ return { messages: [], hasQueuedPrompt: false };
840
+ }
841
+ if (method === TODO_STOP_GUARD_CONTINUATION_CLAIM_METHOD) {
842
+ const sessionId = typeof params["sessionId"] === "string" ? params["sessionId"] : "";
843
+ return {
844
+ claimed: this.knownSessionIds.has(sessionId),
845
+ hasQueuedPrompt: false
846
+ };
619
847
  }
620
848
  throw new Error(`Method not found: ${method}`);
621
849
  }
@@ -749,6 +977,10 @@ var DaemonChannelBridge = class extends EventEmitter2 {
749
977
  activePromptControllers = /* @__PURE__ */ new Map();
750
978
  availableCommandsBySession = /* @__PURE__ */ new Map();
751
979
  turnBarriers = /* @__PURE__ */ new Map();
980
+ channelLoopToolHandlers = [];
981
+ registeredChannelLoopMcpSessions = /* @__PURE__ */ new Set();
982
+ channelLoopMcpRegistrations = /* @__PURE__ */ new Map();
983
+ channelLoopMcpServer;
752
984
  connected = false;
753
985
  lifecycleGeneration = 0;
754
986
  latestAvailableCommandsSessionId;
@@ -799,6 +1031,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
799
1031
  await this.rejectStaleSession(session);
800
1032
  }
801
1033
  this.attachSession(session, bindingToken);
1034
+ await this.registerChannelLoopMcpForSession(session.sessionId);
802
1035
  return session.sessionId;
803
1036
  }
804
1037
  async loadSession(sessionId, cwd, options, bindingToken) {
@@ -820,8 +1053,22 @@ var DaemonChannelBridge = class extends EventEmitter2 {
820
1053
  throw new Error(`Daemon returned session ${session.sessionId} while loading ${sessionId}`);
821
1054
  }
822
1055
  this.attachSession(session, bindingToken);
1056
+ await this.registerChannelLoopMcpForSession(session.sessionId);
823
1057
  return session.sessionId;
824
1058
  }
1059
+ registerChannelLoopToolHandler(handler) {
1060
+ if (!this.channelLoopToolHandlers.includes(handler)) {
1061
+ this.channelLoopToolHandlers.push(handler);
1062
+ }
1063
+ this.channelLoopMcpServer ??= new ChannelLoopMcpServer({
1064
+ create: /* @__PURE__ */ __name((sessionId, input) => this.resolveChannelLoopToolHandler(sessionId).create(sessionId, input), "create"),
1065
+ list: /* @__PURE__ */ __name((sessionId) => this.resolveChannelLoopToolHandler(sessionId).list(sessionId), "list"),
1066
+ cancel: /* @__PURE__ */ __name((sessionId, id) => this.resolveChannelLoopToolHandler(sessionId).cancel(sessionId, id), "cancel")
1067
+ });
1068
+ for (const sessionId of this.sessions.keys()) {
1069
+ void this.registerChannelLoopMcpForSession(sessionId);
1070
+ }
1071
+ }
825
1072
  async prompt(sessionId, text, options) {
826
1073
  const session = this.ensureSession(sessionId);
827
1074
  if (this.activePrompts.has(sessionId)) {
@@ -978,7 +1225,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
978
1225
  return this.connected;
979
1226
  }
980
1227
  attachSession(session, bindingToken) {
981
- const replacedSession = this.removeSessionBinding(session.sessionId);
1228
+ const replacedSession = this.removeSessionBinding(session.sessionId, false);
982
1229
  if (replacedSession) {
983
1230
  void this.releaseSessionClient(replacedSession).catch((error) => {
984
1231
  this.lastError = error;
@@ -1242,7 +1489,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
1242
1489
  }
1243
1490
  this.emit("sessionDied", { sessionId, reason });
1244
1491
  }
1245
- removeSessionBinding(sessionId) {
1492
+ removeSessionBinding(sessionId, unregisterChannelLoopMcp = true) {
1246
1493
  const session = this.sessions.get(sessionId);
1247
1494
  if (!session)
1248
1495
  return void 0;
@@ -1266,8 +1513,51 @@ var DaemonChannelBridge = class extends EventEmitter2 {
1266
1513
  if (mappedSessionId === sessionId) {
1267
1514
  this.respondedRequestToSession.delete(requestId);
1268
1515
  }
1269
- }
1270
- return session;
1516
+ }
1517
+ if (unregisterChannelLoopMcp) {
1518
+ this.unregisterChannelLoopMcpForSession(sessionId);
1519
+ }
1520
+ return session;
1521
+ }
1522
+ async registerChannelLoopMcpForSession(sessionId) {
1523
+ const host = this.options.channelLoopMcpHost;
1524
+ const server = this.channelLoopMcpServer;
1525
+ if (!host || !server || this.registeredChannelLoopMcpSessions.has(sessionId)) {
1526
+ return;
1527
+ }
1528
+ const pending = this.channelLoopMcpRegistrations.get(sessionId);
1529
+ if (pending) {
1530
+ await pending;
1531
+ return;
1532
+ }
1533
+ const registration = host.register(sessionId, (message) => server.handleMessage(message, { sessionId })).then(async () => {
1534
+ if (this.sessions.has(sessionId)) {
1535
+ this.registeredChannelLoopMcpSessions.add(sessionId);
1536
+ } else {
1537
+ await host.unregister(sessionId);
1538
+ }
1539
+ }).catch((error) => {
1540
+ this.lastError = error;
1541
+ }).finally(() => {
1542
+ if (this.channelLoopMcpRegistrations.get(sessionId) === registration) {
1543
+ this.channelLoopMcpRegistrations.delete(sessionId);
1544
+ }
1545
+ });
1546
+ this.channelLoopMcpRegistrations.set(sessionId, registration);
1547
+ await registration;
1548
+ }
1549
+ unregisterChannelLoopMcpForSession(sessionId) {
1550
+ if (!this.registeredChannelLoopMcpSessions.delete(sessionId))
1551
+ return;
1552
+ void this.options.channelLoopMcpHost?.unregister(sessionId).catch((error) => {
1553
+ this.lastError = error;
1554
+ });
1555
+ }
1556
+ resolveChannelLoopToolHandler(sessionId) {
1557
+ const handler = this.channelLoopToolHandlers.find((candidate) => candidate.canHandle?.(sessionId) === true || this.channelLoopToolHandlers.length === 1 && !candidate.canHandle);
1558
+ if (handler)
1559
+ return handler;
1560
+ throw new Error(`No channel loop handler matched session ${sessionId}.`);
1271
1561
  }
1272
1562
  getStringField(data, field, fallback) {
1273
1563
  return isRecord(data) && typeof data[field] === "string" ? data[field] : fallback;
@@ -1515,8 +1805,8 @@ var DmGate = class {
1515
1805
 
1516
1806
  // packages/channels/base/dist/group-history-store.js
1517
1807
  init_esbuild_shims();
1518
- import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
1519
- import { dirname, join as join2 } from "node:path";
1808
+ import { appendFileSync, chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
1809
+ import { dirname as dirname2, join as join3 } from "node:path";
1520
1810
  var DEFAULT_MAX_KEYS = 1e3;
1521
1811
  var DEFAULT_COMPACT_AFTER_RECORDS = 1e3;
1522
1812
  var GroupHistoryStore = class {
@@ -1628,12 +1918,12 @@ var GroupHistoryStore = class {
1628
1918
  };
1629
1919
  }
1630
1920
  readRecords() {
1631
- if (!existsSync(this.filePath)) {
1921
+ if (!existsSync2(this.filePath)) {
1632
1922
  return { records: [], hadInvalidRecords: false };
1633
1923
  }
1634
1924
  let data;
1635
1925
  try {
1636
- data = readFileSync(this.filePath, "utf-8");
1926
+ data = readFileSync2(this.filePath, "utf-8");
1637
1927
  } catch (err) {
1638
1928
  if (isErrnoCode(err, "ENOENT")) {
1639
1929
  return { records: [], hadInvalidRecords: false };
@@ -1660,8 +1950,8 @@ var GroupHistoryStore = class {
1660
1950
  return { records, hadInvalidRecords };
1661
1951
  }
1662
1952
  append(record) {
1663
- const dir = dirname(this.filePath);
1664
- mkdirSync(dir, { recursive: true, mode: 448 });
1953
+ const dir = dirname2(this.filePath);
1954
+ mkdirSync2(dir, { recursive: true, mode: 448 });
1665
1955
  chmodPrivate(dir, 448);
1666
1956
  appendFileSync(this.filePath, `${JSON.stringify(record)}
1667
1957
  `, {
@@ -1671,8 +1961,8 @@ var GroupHistoryStore = class {
1671
1961
  chmodPrivate(this.filePath, 384);
1672
1962
  }
1673
1963
  compact(state, limits) {
1674
- const dir = dirname(this.filePath);
1675
- mkdirSync(dir, { recursive: true, mode: 448 });
1964
+ const dir = dirname2(this.filePath);
1965
+ mkdirSync2(dir, { recursive: true, mode: 448 });
1676
1966
  chmodPrivate(dir, 448);
1677
1967
  const records = [];
1678
1968
  const recordedAt = Date.now();
@@ -1689,10 +1979,10 @@ var GroupHistoryStore = class {
1689
1979
  }
1690
1980
  const data = records.length > 0 ? `${records.map((record) => JSON.stringify(record)).join("\n")}
1691
1981
  ` : "";
1692
- const tempPath = join2(dir, `${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2)}.tmp`);
1693
- writeFileSync(tempPath, data, { encoding: "utf-8", mode: 384 });
1982
+ const tempPath = join3(dir, `${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2)}.tmp`);
1983
+ writeFileSync2(tempPath, data, { encoding: "utf-8", mode: 384 });
1694
1984
  chmodPrivate(tempPath, 384);
1695
- renameSync(tempPath, this.filePath);
1985
+ renameSync2(tempPath, this.filePath);
1696
1986
  chmodPrivate(this.filePath, 384);
1697
1987
  }
1698
1988
  };
@@ -1764,6 +2054,9 @@ var SenderGate = class {
1764
2054
  this.allowedUsers = new Set(allowedUsers);
1765
2055
  this.pairingStore = pairingStore || null;
1766
2056
  }
2057
+ replaceAllowedUsers(users) {
2058
+ this.allowedUsers = new Set(users);
2059
+ }
1767
2060
  isAllowed(senderId) {
1768
2061
  switch (this.policy) {
1769
2062
  case "open":
@@ -1798,203 +2091,6 @@ var SenderGate = class {
1798
2091
  }
1799
2092
  };
1800
2093
 
1801
- // packages/channels/base/dist/PairingStore.js
1802
- init_esbuild_shims();
1803
- import * as crypto2 from "node:crypto";
1804
- import * as fs2 from "node:fs";
1805
- import * as path2 from "node:path";
1806
- var SAFE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
1807
- var CODE_LENGTH = 8;
1808
- var EXPIRY_MS = 60 * 60 * 1e3;
1809
- var MAX_PENDING = 3;
1810
- var PairingStore = class {
1811
- static {
1812
- __name(this, "PairingStore");
1813
- }
1814
- dir;
1815
- pendingPath;
1816
- allowlistPath;
1817
- migratedSentinelPath;
1818
- /**
1819
- * @param channelName Channel name the state is keyed by.
1820
- * @param workspaceCwd Workspace working directory to scope the state to.
1821
- * When provided, files live under
1822
- * `<qwen-home>/channels/<workspace-scope>/` so two workspaces using the
1823
- * same channel name never share pairing requests or allowlist entries
1824
- * (see #7017 — sharing them is an authorization-boundary violation in
1825
- * multi-workspace daemon deployments). Omitting it preserves the legacy
1826
- * global layout (`<qwen-home>/channels/`).
1827
- */
1828
- constructor(channelName, workspaceCwd) {
1829
- const channelsRoot = path2.join(getGlobalQwenDir(), "channels");
1830
- this.dir = workspaceCwd ? path2.join(channelsRoot, getWorkspaceScopeDirName(workspaceCwd)) : channelsRoot;
1831
- const safeChannelName = encodeURIComponent(channelName);
1832
- this.pendingPath = path2.join(this.dir, `${safeChannelName}-pairing.json`);
1833
- this.allowlistPath = path2.join(this.dir, `${safeChannelName}-allowlist.json`);
1834
- this.migratedSentinelPath = path2.join(this.dir, `${safeChannelName}.migrated`);
1835
- if (workspaceCwd) {
1836
- this.migrateLegacyState(channelsRoot, channelName);
1837
- }
1838
- }
1839
- /**
1840
- * One-time grandfathering of pre-scoping state: the first time this
1841
- * (workspace, channel) pair is constructed, copy the legacy GLOBAL files in
1842
- * so senders that were already approved stay approved after upgrading.
1843
- *
1844
- * Gated by a per-channel sentinel file inside the scope directory — NOT by
1845
- * the directory itself: one workspace can start several channels in turn,
1846
- * and a directory-level gate would let only the first channel ever migrate.
1847
- * The sentinel is written even when there was nothing to copy, so a legacy
1848
- * file written later (e.g. by an older version still running concurrently)
1849
- * is never absorbed into a scope that already went through this decision.
1850
- *
1851
- * Each file is copied independently and best-effort (an unreadable pairing
1852
- * file must not block the allowlist, and vice versa), via a
1853
- * uniquely-named temp file + atomic rename so a crash mid-copy cannot
1854
- * leave a truncated scoped file behind the closed gate. A file the scoped
1855
- * store already has is never overwritten.
1856
- *
1857
- * Copy, not move: another workspace upgrading later must be able to
1858
- * grandfather the same baseline, and an older qwen version running
1859
- * concurrently still reads the global files.
1860
- *
1861
- * Revocation therefore means REMOVING ENTRIES from the scoped allowlist
1862
- * (and from the legacy global file, while it exists) — not deleting files.
1863
- */
1864
- migrateLegacyState(channelsRoot, channelName) {
1865
- try {
1866
- if (fs2.existsSync(this.migratedSentinelPath)) {
1867
- return;
1868
- }
1869
- const legacyPairs = [
1870
- [
1871
- path2.join(channelsRoot, `${channelName}-pairing.json`),
1872
- this.pendingPath
1873
- ],
1874
- [
1875
- path2.join(channelsRoot, `${channelName}-allowlist.json`),
1876
- this.allowlistPath
1877
- ]
1878
- ];
1879
- this.ensureDir();
1880
- let allSucceeded = true;
1881
- for (const [legacyPath, scopedPath] of legacyPairs) {
1882
- try {
1883
- if (path2.dirname(path2.resolve(legacyPath)) !== channelsRoot) {
1884
- continue;
1885
- }
1886
- if (fs2.existsSync(scopedPath) || !fs2.existsSync(legacyPath)) {
1887
- continue;
1888
- }
1889
- const tmpPath = `${scopedPath}.${process.pid}.migrating`;
1890
- fs2.copyFileSync(legacyPath, tmpPath);
1891
- fs2.renameSync(tmpPath, scopedPath);
1892
- } catch (err) {
1893
- allSucceeded = false;
1894
- process.stderr.write(`[PairingStore] legacy migration of ${path2.basename(legacyPath)} failed for channel "${channelName}": ${err?.message}; will retry on next start
1895
- `);
1896
- }
1897
- }
1898
- if (allSucceeded) {
1899
- fs2.writeFileSync(this.migratedSentinelPath, "");
1900
- }
1901
- } catch (err) {
1902
- process.stderr.write(`[PairingStore] legacy migration failed for channel "${channelName}": ${err?.message}; scoped store starts empty
1903
- `);
1904
- }
1905
- }
1906
- isApproved(senderId) {
1907
- const list = this.readAllowlist();
1908
- return list.includes(senderId);
1909
- }
1910
- /**
1911
- * Create a pairing request for an unknown sender.
1912
- * Returns the code if created, or null if the pending cap is reached.
1913
- * If the sender already has a non-expired pending request, returns that code.
1914
- */
1915
- createRequest(senderId, senderName) {
1916
- const pending = this.readPending();
1917
- const now = Date.now();
1918
- const active = pending.filter((r) => now - r.createdAt < EXPIRY_MS);
1919
- const existing = active.find((r) => r.senderId === senderId);
1920
- if (existing) {
1921
- return existing.code;
1922
- }
1923
- if (active.length >= MAX_PENDING) {
1924
- return null;
1925
- }
1926
- const code = generateCode();
1927
- active.push({ senderId, senderName, code, createdAt: now });
1928
- this.writePending(active);
1929
- return code;
1930
- }
1931
- /**
1932
- * Approve a pairing request by code.
1933
- * Returns the sender ID if found, or null if not found / expired.
1934
- */
1935
- approve(code) {
1936
- const pending = this.readPending();
1937
- const now = Date.now();
1938
- const idx = pending.findIndex((r) => r.code === code.toUpperCase() && now - r.createdAt < EXPIRY_MS);
1939
- if (idx === -1)
1940
- return null;
1941
- const request = pending[idx];
1942
- pending.splice(idx, 1);
1943
- this.writePending(pending);
1944
- const list = this.readAllowlist();
1945
- if (!list.includes(request.senderId)) {
1946
- list.push(request.senderId);
1947
- this.writeAllowlist(list);
1948
- }
1949
- return request;
1950
- }
1951
- listPending() {
1952
- const pending = this.readPending();
1953
- const now = Date.now();
1954
- return pending.filter((r) => now - r.createdAt < EXPIRY_MS);
1955
- }
1956
- getAllowlist() {
1957
- return this.readAllowlist();
1958
- }
1959
- ensureDir() {
1960
- if (!fs2.existsSync(this.dir)) {
1961
- fs2.mkdirSync(this.dir, { recursive: true });
1962
- }
1963
- }
1964
- readPending() {
1965
- try {
1966
- const data = fs2.readFileSync(this.pendingPath, "utf-8");
1967
- return JSON.parse(data);
1968
- } catch {
1969
- return [];
1970
- }
1971
- }
1972
- writePending(requests) {
1973
- this.ensureDir();
1974
- fs2.writeFileSync(this.pendingPath, JSON.stringify(requests, null, 2));
1975
- }
1976
- readAllowlist() {
1977
- try {
1978
- const data = fs2.readFileSync(this.allowlistPath, "utf-8");
1979
- return JSON.parse(data);
1980
- } catch {
1981
- return [];
1982
- }
1983
- }
1984
- writeAllowlist(list) {
1985
- this.ensureDir();
1986
- fs2.writeFileSync(this.allowlistPath, JSON.stringify(list, null, 2));
1987
- }
1988
- };
1989
- function generateCode() {
1990
- let code = "";
1991
- for (let i = 0; i < CODE_LENGTH; i++) {
1992
- code += SAFE_ALPHABET[crypto2.randomInt(SAFE_ALPHABET.length)];
1993
- }
1994
- return code;
1995
- }
1996
- __name(generateCode, "generateCode");
1997
-
1998
2094
  // packages/channels/base/dist/SessionRouter.js
1999
2095
  init_esbuild_shims();
2000
2096
  import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, rmSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
@@ -2049,6 +2145,8 @@ var SessionRouter = class {
2049
2145
  switch (scope) {
2050
2146
  case "thread":
2051
2147
  return `${channelName}:${threadId || chatId}`;
2148
+ case "chat_thread":
2149
+ return threadId ? `${channelName}:${chatId}:${threadId}` : `${channelName}:${chatId}`;
2052
2150
  case "single":
2053
2151
  return `${channelName}:__single__`;
2054
2152
  case "user":
@@ -3423,7 +3521,7 @@ var ChannelBase = class {
3423
3521
  if (target.threadId !== void 0 && this.supportsProactiveSend() && this.supportsProactiveTarget(target)) {
3424
3522
  await this.pushProactive(target, text);
3425
3523
  } else {
3426
- await this.sendMessage(target.chatId, text);
3524
+ await this.sendThreadMessage(target.chatId, target.threadId, text);
3427
3525
  }
3428
3526
  } catch (err) {
3429
3527
  this.removePendingPermission(event.requestId);
@@ -3492,6 +3590,14 @@ var ChannelBase = class {
3492
3590
  this.attachBridgeEvents(bridge);
3493
3591
  }
3494
3592
  }
3593
+ /**
3594
+ * Thread-targeted delivery. Polling adapters override this to post comments
3595
+ * on a specific issue/PR. The default falls through to sendMessage(chatId,
3596
+ * text), ignoring threadId — existing IM adapters are behaviorally unchanged.
3597
+ */
3598
+ async sendThreadMessage(chatId, _threadId, text) {
3599
+ await this.sendMessage(chatId, text);
3600
+ }
3495
3601
  /**
3496
3602
  * Adapter hook for task lifecycle events — the canonical way to track task
3497
3603
  * state (onPromptStart/onPromptEnd are retained for back-compat). The prompt
@@ -3622,7 +3728,7 @@ var ChannelBase = class {
3622
3728
  if (target.threadId) {
3623
3729
  throw new Error("Channel does not support proactive loop messages for threaded targets.");
3624
3730
  }
3625
- await this.sendMessage(target.chatId, text);
3731
+ await this.sendThreadMessage(target.chatId, target.threadId, text);
3626
3732
  }
3627
3733
  async pushProactiveDelivery(target, text) {
3628
3734
  try {
@@ -3805,6 +3911,7 @@ var ChannelBase = class {
3805
3911
  alreadyPrefixed: true,
3806
3912
  referencedText: void 0,
3807
3913
  attachments: void 0,
3914
+ metadata: void 0,
3808
3915
  imageBase64: void 0,
3809
3916
  imageMimeType: void 0
3810
3917
  };
@@ -4272,6 +4379,7 @@ ${promptText}` : promptText;
4272
4379
  this.router.removeSessionId(sessionId);
4273
4380
  this.instructedSessions.delete(sessionId);
4274
4381
  this.unattendedMemorySessions.delete(sessionId);
4382
+ this.discardRetiredSession(promptBridge, sessionId, `timed-out loop ${jobId}`);
4275
4383
  process.stderr.write(`[${this.name}] retired timed out loop ${jobId} session ${sessionId} after cancel did not settle
4276
4384
  `);
4277
4385
  }
@@ -4282,6 +4390,19 @@ ${promptText}` : promptText;
4282
4390
  clearTimeout(graceTimer);
4283
4391
  }
4284
4392
  }
4393
+ discardRetiredSession(promptBridge, sessionId, reason) {
4394
+ const safeSessionId = sanitizeLogText(sessionId, 64);
4395
+ const safeReason = sanitizeLogText(reason, 128);
4396
+ try {
4397
+ void promptBridge.discardSession?.(sessionId).catch((err) => {
4398
+ process.stderr.write(`[${this.name}] failed to discard ${safeReason} session ${safeSessionId}: ${this.lifecycleError(err)}
4399
+ `);
4400
+ });
4401
+ } catch (err) {
4402
+ process.stderr.write(`[${this.name}] failed to discard ${safeReason} session ${safeSessionId}: ${this.lifecycleError(err)}
4403
+ `);
4404
+ }
4405
+ }
4285
4406
  requestActivePromptCancellation(sessionId, reason = "cancel_command") {
4286
4407
  const active = this.activePrompts.get(sessionId);
4287
4408
  if (!active) {
@@ -4420,8 +4541,11 @@ ${promptText}` : promptText;
4420
4541
  */
4421
4542
  onResponseBoundary(_chatId, _sessionId) {
4422
4543
  }
4423
- async sendResponseMessage(chatId, text, _sessionId) {
4424
- await this.sendMessage(chatId, text);
4544
+ async sendResponseMessage(chatId, text, sessionId) {
4545
+ const active = this.activePrompts.get(sessionId);
4546
+ const target = this.router.getTarget(sessionId);
4547
+ const threadId = active?.threadId ?? target?.threadId;
4548
+ await this.sendThreadMessage(chatId, threadId, text);
4425
4549
  }
4426
4550
  /**
4427
4551
  * Called when the agent's full response is ready.
@@ -4442,21 +4566,21 @@ ${promptText}` : promptText;
4442
4566
  registerCancelCommand(name = "cancel") {
4443
4567
  this.registerCommand(name, async (envelope) => {
4444
4568
  if (!this.isAuthorizedForSharedSession(envelope)) {
4445
- await this.sendMessage(envelope.chatId, "Only authorized members can cancel requests in this shared session.");
4569
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can cancel requests in this shared session.");
4446
4570
  return true;
4447
4571
  }
4448
4572
  const activeSessionId = this.findActiveSessionId(envelope);
4449
4573
  if (!activeSessionId) {
4450
- await this.sendMessage(envelope.chatId, "No request is currently running.");
4574
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No request is currently running.");
4451
4575
  return true;
4452
4576
  }
4453
4577
  const active = this.activePrompts.get(activeSessionId);
4454
4578
  if (!active) {
4455
- await this.sendMessage(envelope.chatId, "No request is currently running.");
4579
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No request is currently running.");
4456
4580
  return true;
4457
4581
  }
4458
4582
  const cancelSucceeded = await this.requestActivePromptCancellation(activeSessionId, "cancel_command");
4459
- await this.sendMessage(envelope.chatId, cancelSucceeded ? "Cancelled current request." : "Failed to cancel current request.");
4583
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, cancelSucceeded ? "Cancelled current request." : "Failed to cancel current request.");
4460
4584
  return true;
4461
4585
  });
4462
4586
  }
@@ -4588,7 +4712,7 @@ ${promptText}` : promptText;
4588
4712
  }
4589
4713
  async handlePermissionResponseCommand(envelope, args, decision) {
4590
4714
  if (!this.isAuthorizedForSharedSession(envelope)) {
4591
- await this.sendMessage(envelope.chatId, "Only authorized members can answer permission requests in this shared session.");
4715
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can answer permission requests in this shared session.");
4592
4716
  return true;
4593
4717
  }
4594
4718
  const lookup = this.pendingPermissionForEnvelope(envelope, args);
@@ -4598,16 +4722,16 @@ ${promptText}` : promptText;
4598
4722
  const title = pending2 ? `: ${sanitizeQuotedText(pending2.request.toolCall.title || "Tool use", 160)}` : "";
4599
4723
  return `- ${sanitizeQuotedText(id, 128)}${title}`;
4600
4724
  }).join("\n");
4601
- await this.sendMessage(envelope.chatId, `Multiple permission requests are pending for this chat. Reply with /${decision} <request-id>.
4725
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Multiple permission requests are pending for this chat. Reply with /${decision} <request-id>.
4602
4726
  ${requestList}`);
4603
4727
  return true;
4604
4728
  }
4605
4729
  if (lookup.kind === "none") {
4606
- await this.sendMessage(envelope.chatId, lookup.explicit ? "No pending permission request with that id for this chat." : "No pending permission request for this chat.");
4730
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, lookup.explicit ? "No pending permission request with that id for this chat." : "No pending permission request for this chat.");
4607
4731
  return true;
4608
4732
  }
4609
4733
  if (!this.bridge.respondToPermission) {
4610
- await this.sendMessage(envelope.chatId, "Permission relay is not available for this session.");
4734
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Permission relay is not available for this session.");
4611
4735
  return true;
4612
4736
  }
4613
4737
  const { pending } = lookup;
@@ -4619,7 +4743,7 @@ ${requestList}`);
4619
4743
  return optionId ? { outcome: { outcome: "selected", optionId } } : void 0;
4620
4744
  })();
4621
4745
  if (!response) {
4622
- await this.sendMessage(envelope.chatId, decision === "approve-always" ? "This permission request has no always-allow option." : "This permission request has no approvable option.");
4746
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, decision === "approve-always" ? "This permission request has no always-allow option." : "This permission request has no approvable option.");
4623
4747
  return true;
4624
4748
  }
4625
4749
  let accepted;
@@ -4629,11 +4753,11 @@ ${requestList}`);
4629
4753
  this.removePendingPermission(pending.requestId);
4630
4754
  process.stderr.write(`[${this.name}] permission response failed for request ${sanitizeLogText(pending.requestId, 128)}: ${this.lifecycleError(err)}
4631
4755
  `);
4632
- await this.sendMessage(envelope.chatId, "Failed to answer the permission request.");
4756
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Failed to answer the permission request.");
4633
4757
  return true;
4634
4758
  }
4635
4759
  this.removePendingPermission(pending.requestId);
4636
- await this.sendMessage(envelope.chatId, accepted ? decision === "approve" ? "Permission approved." : decision === "approve-always" ? "Permission approved always." : "Permission denied." : "Permission request is no longer pending.");
4760
+ 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.");
4637
4761
  return true;
4638
4762
  }
4639
4763
  /** Register shared slash commands. Called from constructor. */
@@ -4683,19 +4807,20 @@ ${requestList}`);
4683
4807
  } else {
4684
4808
  this.sessionGenerations.delete(id);
4685
4809
  }
4810
+ this.discardRetiredSession(this.bridge, id, "cleared");
4686
4811
  }
4687
- await this.sendMessage(envelope.chatId, "Session cleared. The next message starts a fresh conversation.");
4812
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Session cleared. The next message starts a fresh conversation.");
4688
4813
  } else {
4689
- await this.sendMessage(envelope.chatId, "No active session to clear.");
4814
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No active session to clear.");
4690
4815
  }
4691
4816
  }, "doClear");
4692
4817
  const clearHandler = /* @__PURE__ */ __name(async (envelope, args) => {
4693
4818
  if (!this.isAuthorizedForSharedSession(envelope)) {
4694
- await this.sendMessage(envelope.chatId, "Only authorized members can clear this shared session.");
4819
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can clear this shared session.");
4695
4820
  return true;
4696
4821
  }
4697
4822
  if (this.isSharedSession(envelope) && args.toLowerCase() !== "confirm") {
4698
- await this.sendMessage(envelope.chatId, 'This clears the shared session for everyone who shares it. Re-send with "confirm" (e.g. /clear confirm) to proceed.');
4823
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, 'This clears the shared session for everyone who shares it. Re-send with "confirm" (e.g. /clear confirm) to proceed.');
4699
4824
  return true;
4700
4825
  }
4701
4826
  await doClear(envelope);
@@ -4709,12 +4834,12 @@ ${requestList}`);
4709
4834
  this.registerCommand("deny", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "deny"));
4710
4835
  this.registerCommand("who", async (envelope) => {
4711
4836
  if (!this.isAuthorizedForSharedSession(envelope)) {
4712
- await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
4837
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can view this shared session.");
4713
4838
  return true;
4714
4839
  }
4715
4840
  const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
4716
4841
  const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
4717
- await this.sendMessage(envelope.chatId, [
4842
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, [
4718
4843
  `Channel: ${this.name}`,
4719
4844
  // Identity/memory lines only for channels that opted in — keep
4720
4845
  // unconfigured channels' output unchanged.
@@ -4768,12 +4893,12 @@ ${requestList}`);
4768
4893
  }
4769
4894
  }
4770
4895
  lines.push("", "Send any text to chat with the agent.");
4771
- await this.sendMessage(envelope.chatId, lines.join("\n"));
4896
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, lines.join("\n"));
4772
4897
  return true;
4773
4898
  });
4774
4899
  this.registerCommand("status", async (envelope) => {
4775
4900
  if (!this.isAuthorizedForSharedSession(envelope)) {
4776
- await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
4901
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can view this shared session.");
4777
4902
  return true;
4778
4903
  }
4779
4904
  const hasSession = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
@@ -4787,18 +4912,18 @@ ${requestList}`);
4787
4912
  `Memory: ${this.memoryScope.mode}`
4788
4913
  ] : []
4789
4914
  ];
4790
- await this.sendMessage(envelope.chatId, lines.join("\n"));
4915
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, lines.join("\n"));
4791
4916
  return true;
4792
4917
  });
4793
4918
  this.registerCommand("loop", async (envelope, args) => this.handleLoopCommand(envelope, args));
4794
4919
  }
4795
4920
  async handleLoopCommand(envelope, args) {
4796
4921
  if (!this.loopController) {
4797
- await this.sendMessage(envelope.chatId, "Loops are not available.");
4922
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Loops are not available.");
4798
4923
  return true;
4799
4924
  }
4800
4925
  if (!this.isAuthorizedForSharedSession(envelope)) {
4801
- await this.sendMessage(envelope.chatId, "Only authorized members can use loops in this shared session.");
4926
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Only authorized members can use loops in this shared session.");
4802
4927
  return true;
4803
4928
  }
4804
4929
  const [subcommand = "", ...rest] = args.trim().split(/\s+/u);
@@ -4812,7 +4937,7 @@ ${requestList}`);
4812
4937
  case "cancel":
4813
4938
  return this.handleLoopCancel(envelope, rest[0]);
4814
4939
  default:
4815
- await this.sendMessage(envelope.chatId, 'Usage: /loop add "<cron>" <prompt> | /loop list | /loop inspect <id> | /loop cancel <id>');
4940
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, 'Usage: /loop add "<cron>" <prompt> | /loop list | /loop inspect <id> | /loop cancel <id>');
4816
4941
  return true;
4817
4942
  }
4818
4943
  }
@@ -4820,32 +4945,32 @@ ${requestList}`);
4820
4945
  if (!this.loopController)
4821
4946
  return true;
4822
4947
  if (!this.supportsProactiveSend()) {
4823
- await this.sendMessage(envelope.chatId, "This channel does not support proactive loop messages.");
4948
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "This channel does not support proactive loop messages.");
4824
4949
  return true;
4825
4950
  }
4826
4951
  if (this.config.sessionScope === "single") {
4827
- await this.sendMessage(envelope.chatId, "Loops are not supported when sessionScope is single.");
4952
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Loops are not supported when sessionScope is single.");
4828
4953
  return true;
4829
4954
  }
4830
4955
  const parsed = parseLoopAddArgs(args);
4831
4956
  if (!parsed) {
4832
- await this.sendMessage(envelope.chatId, 'Usage: /loop add "<cron>" <prompt>');
4957
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, 'Usage: /loop add "<cron>" <prompt>');
4833
4958
  return true;
4834
4959
  }
4835
4960
  try {
4836
4961
  this.loopController.validateCron(parsed.cron);
4837
4962
  } catch (err) {
4838
- await this.sendMessage(envelope.chatId, `Invalid cron expression: ${err instanceof Error ? err.message : String(err)}`);
4963
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Invalid cron expression: ${err instanceof Error ? err.message : String(err)}`);
4839
4964
  return true;
4840
4965
  }
4841
4966
  const target = this.loopTargetFromEnvelope(envelope);
4842
4967
  if (!this.supportsProactiveTarget(target)) {
4843
- await this.sendMessage(envelope.chatId, "This channel does not support proactive loop messages for this chat target.");
4968
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "This channel does not support proactive loop messages for this chat target.");
4844
4969
  return true;
4845
4970
  }
4846
4971
  const prompt = sanitizePromptText(parsed.prompt.trim());
4847
4972
  if (Array.from(prompt).length > MAX_LOOP_PROMPT_CHARS) {
4848
- await this.sendMessage(envelope.chatId, `Loop prompt is too long; keep it under ${MAX_LOOP_PROMPT_CHARS} characters.`);
4973
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Loop prompt is too long; keep it under ${MAX_LOOP_PROMPT_CHARS} characters.`);
4849
4974
  return true;
4850
4975
  }
4851
4976
  const input = {
@@ -4868,10 +4993,10 @@ ${requestList}`);
4868
4993
  }
4869
4994
  }
4870
4995
  if (!job) {
4871
- await this.sendMessage(envelope.chatId, `Too many loops for this chat. Cancel an existing loop before adding another.`);
4996
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Too many loops for this chat. Cancel an existing loop before adding another.`);
4872
4997
  return true;
4873
4998
  }
4874
- await this.sendMessage(envelope.chatId, `Loop ${job.id}: ${job.cron}`);
4999
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Loop ${job.id}: ${job.cron}`);
4875
5000
  return true;
4876
5001
  }
4877
5002
  async createLoopFromTool(sessionId, input) {
@@ -4973,23 +5098,23 @@ ${requestList}`);
4973
5098
  return true;
4974
5099
  const jobs = await this.loopController.listForTarget(this.name, this.loopTargetFromEnvelope(envelope));
4975
5100
  if (jobs.length === 0) {
4976
- await this.sendMessage(envelope.chatId, "No loops.");
5101
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No loops.");
4977
5102
  return true;
4978
5103
  }
4979
- await this.sendMessage(envelope.chatId, jobs.map((job) => this.formatLoopListLine(job)).join("\n"));
5104
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, jobs.map((job) => this.formatLoopListLine(job)).join("\n"));
4980
5105
  return true;
4981
5106
  }
4982
5107
  async handleLoopInspect(envelope, id) {
4983
5108
  if (!this.loopController)
4984
5109
  return true;
4985
5110
  if (!id) {
4986
- await this.sendMessage(envelope.chatId, "Usage: /loop inspect <id>");
5111
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Usage: /loop inspect <id>");
4987
5112
  return true;
4988
5113
  }
4989
5114
  const jobs = await this.loopController.listForTarget(this.name, this.loopTargetFromEnvelope(envelope));
4990
5115
  const job = jobs.find((candidate) => candidate.id === id);
4991
5116
  if (!job) {
4992
- await this.sendMessage(envelope.chatId, `No loop ${id}.`);
5117
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `No loop ${id}.`);
4993
5118
  return true;
4994
5119
  }
4995
5120
  const lines = [
@@ -5011,7 +5136,7 @@ ${requestList}`);
5011
5136
  lines.push(`Last result: ${job.lastResultPreview}`);
5012
5137
  }
5013
5138
  lines.push(`Prompt: ${job.prompt}`);
5014
- await this.sendMessage(envelope.chatId, lines.join("\n"));
5139
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, lines.join("\n"));
5015
5140
  return true;
5016
5141
  }
5017
5142
  formatLoopListLine(job) {
@@ -5043,17 +5168,17 @@ ${requestList}`);
5043
5168
  if (!this.loopController)
5044
5169
  return true;
5045
5170
  if (!id) {
5046
- await this.sendMessage(envelope.chatId, "Usage: /loop cancel <id>");
5171
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Usage: /loop cancel <id>");
5047
5172
  return true;
5048
5173
  }
5049
5174
  const jobs = await this.loopController.listForTarget(this.name, this.loopTargetFromEnvelope(envelope));
5050
5175
  const match = jobs.find((job) => job.id === id);
5051
5176
  if (!match) {
5052
- await this.sendMessage(envelope.chatId, `No loop ${id}.`);
5177
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `No loop ${id}.`);
5053
5178
  return true;
5054
5179
  }
5055
5180
  const disabled = await this.loopController.disable(id);
5056
- await this.sendMessage(envelope.chatId, disabled ? `Cancelled loop ${id}.` : `Failed to cancel loop ${id}.`);
5181
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, disabled ? `Cancelled loop ${id}.` : `Failed to cancel loop ${id}.`);
5057
5182
  return true;
5058
5183
  }
5059
5184
  loopTargetFromEnvelope(envelope) {
@@ -5170,7 +5295,7 @@ ${requestList}`);
5170
5295
  }
5171
5296
  async getChannelMemory(envelope) {
5172
5297
  if (!this.channelMemory) {
5173
- await this.sendMessage(envelope.chatId, "Channel memory is not configured for this channel.");
5298
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Channel memory is not configured for this channel.");
5174
5299
  return void 0;
5175
5300
  }
5176
5301
  return this.channelMemory;
@@ -5188,7 +5313,7 @@ ${requestList}`);
5188
5313
  }
5189
5314
  async handleChannelMemoryIntent(envelope, intent, options = {}) {
5190
5315
  if (intent.kind === "no_match") {
5191
- await this.sendMessage(envelope.chatId, "No matching channel memory entry.");
5316
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No matching channel memory entry.");
5192
5317
  return;
5193
5318
  }
5194
5319
  if (intent.kind === "ambiguous") {
@@ -5200,11 +5325,11 @@ ${requestList}`);
5200
5325
  entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
5201
5326
  } catch (error) {
5202
5327
  this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
5203
- await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5328
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5204
5329
  return;
5205
5330
  }
5206
5331
  const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
5207
- await this.sendMessage(envelope.chatId, [
5332
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, [
5208
5333
  "Multiple channel memory entries match:",
5209
5334
  ...this.renderChannelMemoryCandidates(selected)
5210
5335
  ].join("\n"));
@@ -5219,11 +5344,11 @@ ${requestList}`);
5219
5344
  entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
5220
5345
  } catch (error) {
5221
5346
  this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
5222
- await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5347
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5223
5348
  return;
5224
5349
  }
5225
5350
  const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
5226
- await this.sendMessage(envelope.chatId, [
5351
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, [
5227
5352
  "Channel memory (page 1/1):",
5228
5353
  ...this.renderChannelMemoryCandidates(selected)
5229
5354
  ].join("\n"));
@@ -5236,7 +5361,7 @@ ${requestList}`);
5236
5361
  if (intent.kind === "update_confirm" || intent.kind === "remove_confirm") {
5237
5362
  const pending = intent.kind === "update_confirm" ? this.takePendingChannelMemoryMutation(envelope, "update") : this.takePendingChannelMemoryMutation(envelope, "remove");
5238
5363
  if (!pending) {
5239
- await this.sendMessage(envelope.chatId, intent.kind === "update_confirm" ? "No pending channel memory update. Start a new update request first." : "No pending channel memory removal. Start a new removal request first.");
5364
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, intent.kind === "update_confirm" ? "No pending channel memory update. Start a new update request first." : "No pending channel memory removal. Start a new removal request first.");
5240
5365
  return;
5241
5366
  }
5242
5367
  const channelMemory2 = await this.getChannelMemory(envelope);
@@ -5260,15 +5385,15 @@ ${requestList}`);
5260
5385
  } catch (error) {
5261
5386
  const message = this.channelMemoryErrorMessage(error);
5262
5387
  this.logChannelMemoryError(isUpdate ? "update" : "remove", envelope, message);
5263
- await this.sendMessage(envelope.chatId, message === "Channel memory entry changed" ? "That channel memory entry changed since it was selected. View channel memory and start the operation again." : `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
5388
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, message === "Channel memory entry changed" ? "That channel memory entry changed since it was selected. View channel memory and start the operation again." : `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
5264
5389
  return;
5265
5390
  }
5266
5391
  if (!changed) {
5267
- await this.sendMessage(envelope.chatId, `No channel memory entry ${pending.id}.`);
5392
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `No channel memory entry ${pending.id}.`);
5268
5393
  return;
5269
5394
  }
5270
5395
  this.invalidateUnattendedMemory(envelope);
5271
- await this.sendMessage(envelope.chatId, `Channel memory ${pending.id} ${isUpdate ? "updated" : "removed"}.`);
5396
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Channel memory ${pending.id} ${isUpdate ? "updated" : "removed"}.`);
5272
5397
  return;
5273
5398
  }
5274
5399
  if (intent.kind === "natural_update") {
@@ -5308,7 +5433,7 @@ ${requestList}`);
5308
5433
  } catch (error) {
5309
5434
  const message = this.channelMemoryErrorMessage(error);
5310
5435
  this.logChannelMemoryError("save", envelope, message);
5311
- await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
5436
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
5312
5437
  return;
5313
5438
  }
5314
5439
  if (result.changed) {
@@ -5319,11 +5444,11 @@ ${requestList}`);
5319
5444
  }
5320
5445
  if (result.added.length > 0) {
5321
5446
  const ids = result.added.map((entry) => entry.id);
5322
- await this.sendMessage(envelope.chatId, result.duplicateIds.length > 0 ? `Channel memory saved: ${ids.join(", ")}. Skipped duplicates: ${result.duplicateIds.join(", ")}.` : ids.length === 1 ? `Channel memory ${ids[0]} saved.` : `Channel memory saved: ${ids.join(", ")}.`);
5447
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, result.duplicateIds.length > 0 ? `Channel memory saved: ${ids.join(", ")}. Skipped duplicates: ${result.duplicateIds.join(", ")}.` : ids.length === 1 ? `Channel memory ${ids[0]} saved.` : `Channel memory saved: ${ids.join(", ")}.`);
5323
5448
  } else if (result.duplicateIds.length > 0) {
5324
- await this.sendMessage(envelope.chatId, `Channel memory already contains ${result.duplicateIds.join(", ")}.`);
5449
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Channel memory already contains ${result.duplicateIds.join(", ")}.`);
5325
5450
  } else {
5326
- await this.sendMessage(envelope.chatId, "Channel memory updated.");
5451
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Channel memory updated.");
5327
5452
  }
5328
5453
  return;
5329
5454
  }
@@ -5334,27 +5459,27 @@ ${requestList}`);
5334
5459
  } catch (error) {
5335
5460
  const message = this.channelMemoryErrorMessage(error);
5336
5461
  this.logChannelMemoryError("read", envelope, message);
5337
- await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5462
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
5338
5463
  return;
5339
5464
  }
5340
5465
  if (intent.kind === "inspect") {
5341
5466
  const entry = entries.find((candidate) => candidate.id === intent.id);
5342
- await this.sendMessage(envelope.chatId, entry ? `Channel memory ${entry.id}:
5467
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, entry ? `Channel memory ${entry.id}:
5343
5468
  ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id}.`);
5344
5469
  return;
5345
5470
  }
5346
5471
  const totalPages = Math.max(1, Math.ceil(entries.length / CHANNEL_MEMORY_PAGE_SIZE));
5347
5472
  if (intent.page > totalPages) {
5348
- await this.sendMessage(envelope.chatId, `Channel memory page ${intent.page} does not exist.`);
5473
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Channel memory page ${intent.page} does not exist.`);
5349
5474
  return;
5350
5475
  }
5351
5476
  if (entries.length === 0) {
5352
- await this.sendMessage(envelope.chatId, "No channel memory saved.");
5477
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "No channel memory saved.");
5353
5478
  return;
5354
5479
  }
5355
5480
  const pageStart = (intent.page - 1) * CHANNEL_MEMORY_PAGE_SIZE;
5356
5481
  const lines = entries.slice(pageStart, pageStart + CHANNEL_MEMORY_PAGE_SIZE).map((entry) => this.renderChannelMemoryCandidate(entry));
5357
- await this.sendMessage(envelope.chatId, [`Channel memory (page ${intent.page}/${totalPages}):`, ...lines].join("\n"));
5482
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, [`Channel memory (page ${intent.page}/${totalPages}):`, ...lines].join("\n"));
5358
5483
  return;
5359
5484
  }
5360
5485
  if (intent.kind === "update" || intent.kind === "remove") {
@@ -5370,21 +5495,21 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
5370
5495
  } catch (error) {
5371
5496
  const message = this.channelMemoryErrorMessage(error);
5372
5497
  this.logChannelMemoryError(isUpdate ? "update" : "remove", envelope, message);
5373
- await this.sendMessage(envelope.chatId, `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
5498
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
5374
5499
  return;
5375
5500
  }
5376
5501
  if (!changed) {
5377
- await this.sendMessage(envelope.chatId, `No channel memory entry ${id}.`);
5502
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `No channel memory entry ${id}.`);
5378
5503
  return;
5379
5504
  }
5380
5505
  this.invalidateUnattendedMemory(envelope);
5381
- await this.sendMessage(envelope.chatId, `Channel memory ${id} ${isUpdate ? "updated" : "removed"}.`);
5506
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Channel memory ${id} ${isUpdate ? "updated" : "removed"}.`);
5382
5507
  return;
5383
5508
  }
5384
5509
  if (intent.kind === "clear_confirm") {
5385
5510
  const pending = this.takePendingChannelMemoryMutation(envelope, "clear");
5386
5511
  if (!pending) {
5387
- await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
5512
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
5388
5513
  return;
5389
5514
  }
5390
5515
  let result;
@@ -5393,13 +5518,13 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
5393
5518
  } catch (error) {
5394
5519
  const message = this.channelMemoryErrorMessage(error);
5395
5520
  this.logChannelMemoryError("clear", envelope, message);
5396
- await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
5521
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
5397
5522
  return;
5398
5523
  }
5399
5524
  if (result.changed) {
5400
5525
  this.invalidateUnattendedMemory(envelope);
5401
5526
  }
5402
- await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
5527
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
5403
5528
  return;
5404
5529
  }
5405
5530
  const unhandled = intent;
@@ -5428,7 +5553,7 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
5428
5553
  const key = this.channelMemoryPendingKey(envelope);
5429
5554
  this.pendingChannelMemoryMutationDeliveries.set(key, mutation);
5430
5555
  try {
5431
- await this.sendMessage(envelope.chatId, message);
5556
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, message);
5432
5557
  } catch (error) {
5433
5558
  if (this.pendingChannelMemoryMutationDeliveries.get(key) === mutation) {
5434
5559
  this.pendingChannelMemoryMutationDeliveries.delete(key);
@@ -5582,15 +5707,17 @@ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id
5582
5707
  * Whether the resolved session is SHARED across senders. `single` collapses
5583
5708
  * the whole channel to one `__single__` session for EVERY sender — group OR
5584
5709
  * DM — so it is ALWAYS shared (even a DM maps to `__single__`). `thread` is
5585
- * shared only in a group (a DM maps to the lone caller's own chat). `user` is
5586
- * per-sender, never shared. Drives both the destructive-/clear confirm gate
5587
- * and the host-shell (`!`) gate.
5710
+ * shared only in a group (a DM maps to the lone caller's own chat).
5711
+ * `chat_thread` is always shared: it scopes by chat+thread, and a thread
5712
+ * (issue/PR discussion) can carry multiple participants even outside a
5713
+ * group. `user` is per-sender, never shared. Drives both the
5714
+ * destructive-/clear confirm gate and the host-shell (`!`) gate.
5588
5715
  */
5589
5716
  isSharedSession(envelope) {
5590
5717
  return this.isSharedSessionTarget(envelope);
5591
5718
  }
5592
5719
  isSharedSessionTarget(target) {
5593
- return this.config.sessionScope === "single" || target.isGroup === true && this.config.sessionScope === "thread";
5720
+ return this.config.sessionScope === "single" || this.config.sessionScope === "chat_thread" || target.isGroup === true && this.config.sessionScope === "thread";
5594
5721
  }
5595
5722
  /**
5596
5723
  * Whether `envelope.senderId` may act on the resolved session's destructive or
@@ -5847,7 +5974,7 @@ ${promptText}`;
5847
5974
  if (!result.allowed) {
5848
5975
  if (result.pairingCode !== void 0) {
5849
5976
  this.logPreflightRejected("sender_pairing_required");
5850
- return this.onPairingRequired(envelope.chatId, result.pairingCode).then(() => false).catch((err) => {
5977
+ return this.onPairingRequired(envelope.chatId, result.pairingCode, envelope.threadId).then(() => false).catch((err) => {
5851
5978
  process.stderr.write(`[Channel:${this.name}] pairing notification failed: ${sanitizeLogText(err instanceof Error ? err.message : String(err), 200)}
5852
5979
  `);
5853
5980
  return false;
@@ -5960,11 +6087,11 @@ ${promptText}`;
5960
6087
  `);
5961
6088
  }
5962
6089
  if (envelope.isGroup) {
5963
- await this.sendMessage(envelope.chatId, "Shell commands (`!`) are disabled in group chats.");
6090
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Shell commands (`!`) are disabled in group chats.");
5964
6091
  return;
5965
6092
  }
5966
6093
  if (this.isSharedSession(envelope)) {
5967
- await this.sendMessage(envelope.chatId, "Shell commands (`!`) are disabled in shared sessions.");
6094
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, "Shell commands (`!`) are disabled in shared sessions.");
5968
6095
  return;
5969
6096
  }
5970
6097
  }
@@ -5982,10 +6109,10 @@ ${result.output}
5982
6109
  ${fence}` : "(no output)";
5983
6110
  const exitLine = result.exitCode !== null && result.exitCode !== 0 ? `
5984
6111
  Exit code: ${result.exitCode}` : "";
5985
- await this.sendMessage(envelope.chatId, `$ ${cmd}
6112
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `$ ${cmd}
5986
6113
  ${output}${exitLine}`);
5987
6114
  } catch (error) {
5988
- await this.sendMessage(envelope.chatId, `Shell command failed: ${error instanceof Error ? error.message : String(error)}`);
6115
+ await this.sendThreadMessage(envelope.chatId, envelope.threadId, `Shell command failed: ${error instanceof Error ? error.message : String(error)}`);
5989
6116
  }
5990
6117
  return;
5991
6118
  }
@@ -6021,6 +6148,9 @@ ${promptText}`;
6021
6148
  promptText = promptText + "\n\n" + filePaths.join("\n");
6022
6149
  }
6023
6150
  }
6151
+ if (envelope.metadata) {
6152
+ promptText = promptText + "\n\n" + sanitizePromptText(envelope.metadata);
6153
+ }
6024
6154
  const groupCfg = envelope.isGroup ? this.config.groups[envelope.chatId] || this.config.groups["*"] : void 0;
6025
6155
  const mode = groupCfg?.dispatchMode || this.config.dispatchMode || "steer";
6026
6156
  const active = this.activePrompts.get(sessionId);
@@ -6298,6 +6428,7 @@ ${promptToSend}`;
6298
6428
  // Clear attachments/references — already resolved in original text
6299
6429
  referencedText: void 0,
6300
6430
  attachments: void 0,
6431
+ metadata: void 0,
6301
6432
  imageBase64: void 0,
6302
6433
  imageMimeType: void 0
6303
6434
  };
@@ -6313,14 +6444,14 @@ ${promptToSend}`;
6313
6444
  }));
6314
6445
  await current;
6315
6446
  }
6316
- async onPairingRequired(chatId, code) {
6447
+ async onPairingRequired(chatId, code, threadId) {
6317
6448
  if (code) {
6318
- await this.sendMessage(chatId, `Your pairing code is: ${code}
6449
+ await this.sendThreadMessage(chatId, threadId, `Your pairing code is: ${code}
6319
6450
 
6320
6451
  Ask the bot operator to approve you with:
6321
6452
  qwen channel pairing approve ${this.name} ${code}`);
6322
6453
  } else {
6323
- await this.sendMessage(chatId, "Too many pending pairing requests. Please try again later.");
6454
+ await this.sendThreadMessage(chatId, threadId, "Too many pending pairing requests. Please try again later.");
6324
6455
  }
6325
6456
  }
6326
6457
  };
@@ -6533,9 +6664,114 @@ function isTerminalTaskLifecycleType(type) {
6533
6664
  }
6534
6665
  __name(isTerminalTaskLifecycleType, "isTerminalTaskLifecycleType");
6535
6666
 
6667
+ // packages/channels/base/dist/PollingChannelBase.js
6668
+ init_esbuild_shims();
6669
+ import { createHash as createHash2 } from "node:crypto";
6670
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
6671
+ import { join as join6 } from "node:path";
6672
+ import process3 from "node:process";
6673
+ var INITIAL_BACKOFF = 2e3;
6674
+ var MAX_BACKOFF = 3e4;
6675
+ var PollingChannelBase = class extends ChannelBase {
6676
+ static {
6677
+ __name(this, "PollingChannelBase");
6678
+ }
6679
+ cursor;
6680
+ abortController = new AbortController();
6681
+ running = false;
6682
+ consecutiveErrors = 0;
6683
+ abortableSleep(ms) {
6684
+ const signal = this.abortController.signal;
6685
+ return new Promise((resolve3) => {
6686
+ if (signal.aborted) {
6687
+ resolve3();
6688
+ return;
6689
+ }
6690
+ const timer = setTimeout(() => {
6691
+ signal.removeEventListener("abort", onAbort);
6692
+ resolve3();
6693
+ }, ms);
6694
+ const onAbort = /* @__PURE__ */ __name(() => {
6695
+ clearTimeout(timer);
6696
+ resolve3();
6697
+ }, "onAbort");
6698
+ signal.addEventListener("abort", onAbort, { once: true });
6699
+ });
6700
+ }
6701
+ constructor(name, config, bridge, options) {
6702
+ super(name, config, bridge, options);
6703
+ this.cursor = this.loadCursorFromDisk() ?? this.createInitialCursor();
6704
+ }
6705
+ validateCursor(parsed) {
6706
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
6707
+ return null;
6708
+ return parsed;
6709
+ }
6710
+ get pollInterval() {
6711
+ const configured = this.config.pollInterval;
6712
+ if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) {
6713
+ return configured;
6714
+ }
6715
+ return 6e4;
6716
+ }
6717
+ saveCursor() {
6718
+ const path4 = this.cursorPath();
6719
+ mkdirSync4(join6(getGlobalQwenDir(), "channels"), { recursive: true });
6720
+ const tmp = `${path4}.tmp`;
6721
+ writeFileSync4(tmp, JSON.stringify(this.cursor) + "\n", "utf-8");
6722
+ renameSync4(tmp, path4);
6723
+ }
6724
+ startPollLoop() {
6725
+ if (this.running)
6726
+ return;
6727
+ this.running = true;
6728
+ this.consecutiveErrors = 0;
6729
+ this.abortController = new AbortController();
6730
+ this.runLoop();
6731
+ }
6732
+ stopPollLoop() {
6733
+ this.running = false;
6734
+ this.abortController.abort();
6735
+ }
6736
+ async runLoop() {
6737
+ const signal = this.abortController.signal;
6738
+ while (this.running && !signal.aborted) {
6739
+ try {
6740
+ await this.pollOnce();
6741
+ this.saveCursor();
6742
+ this.consecutiveErrors = 0;
6743
+ } catch (err) {
6744
+ this.consecutiveErrors++;
6745
+ const backoff = Math.min(INITIAL_BACKOFF * 2 ** (this.consecutiveErrors - 1), MAX_BACKOFF);
6746
+ process3.stderr.write(`[Channel:${this.name}] poll error (attempt ${this.consecutiveErrors}), backing off ${backoff}ms: ${err}
6747
+ `);
6748
+ await this.abortableSleep(backoff);
6749
+ continue;
6750
+ }
6751
+ await this.abortableSleep(this.pollInterval);
6752
+ }
6753
+ }
6754
+ loadCursorFromDisk() {
6755
+ try {
6756
+ const raw = readFileSync4(this.cursorPath(), "utf-8").trim();
6757
+ if (!raw)
6758
+ return null;
6759
+ return this.validateCursor(JSON.parse(raw));
6760
+ } catch {
6761
+ return null;
6762
+ }
6763
+ }
6764
+ cursorPath() {
6765
+ const encoded = this.name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 200);
6766
+ const hash = createHash2("sha256").update(this.name).digest("hex").slice(0, 16);
6767
+ return join6(getGlobalQwenDir(), "channels", `${encoded}-${hash}-poll-cursor.json`);
6768
+ }
6769
+ };
6770
+
6536
6771
  export {
6537
6772
  resolvePath,
6538
6773
  getGlobalQwenDir,
6774
+ CHANNEL_LOOP_MCP_SERVER_NAME,
6539
6775
  sanitizeSenderName,
6540
6776
  sanitizePromptText,
6541
6777
  sanitizeLogText,
@@ -6548,7 +6784,8 @@ export {
6548
6784
  ChannelLoopScheduler,
6549
6785
  ChannelBase,
6550
6786
  ChannelLoopStore,
6551
- isTerminalTaskLifecycleType
6787
+ isTerminalTaskLifecycleType,
6788
+ PollingChannelBase
6552
6789
  };
6553
6790
  /**
6554
6791
  * @license