@qwen-code/qwen-code 0.19.6 → 0.19.7-nightly.20260708.394c1a289

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 (267) hide show
  1. package/bundled/qc-helper/docs/configuration/model-providers.md +5 -1
  2. package/bundled/qc-helper/docs/configuration/settings.md +33 -1
  3. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  4. package/bundled/qc-helper/docs/features/channels/overview.md +41 -31
  5. package/bundled/qc-helper/docs/features/channels/wecom.md +111 -0
  6. package/bundled/qc-helper/docs/features/code-review.md +16 -6
  7. package/bundled/qc-helper/docs/features/commands.md +1 -1
  8. package/bundled/qc-helper/docs/features/hooks.md +6 -0
  9. package/bundled/qc-helper/docs/features/skills.md +5 -3
  10. package/bundled/qc-helper/docs/integration-github-action.md +1 -1
  11. package/bundled/review/DESIGN.md +50 -18
  12. package/bundled/review/SKILL.md +102 -12
  13. package/chunks/{MaxSizedBox-SK7CUWZQ.js → MaxSizedBox-XS37LWTD.js} +31 -29
  14. package/chunks/{StandaloneSessionPicker-G44HGSAP.js → StandaloneSessionPicker-LPALJTKN.js} +44 -41
  15. package/chunks/{acpAgent-PKCTYWJV.js → acpAgent-4VE3FGJX.js} +769 -366
  16. package/chunks/{agent-IYMHUXWB.js → agent-CCHERW6L.js} +24 -24
  17. package/chunks/{agent-headless-L2DAW6I5.js → agent-headless-55N6UBUU.js} +24 -24
  18. package/chunks/{anthropicContentGenerator-H5ZOEENQ.js → anthropicContentGenerator-AKYPSZIV.js} +7 -7
  19. package/chunks/{artifact-tool-SLYPWG3C.js → artifact-tool-D233YJFH.js} +27 -8
  20. package/chunks/{askUserQuestion-OKPTECON.js → askUserQuestion-MKL5ZTMC.js} +2 -2
  21. package/chunks/{bridge-DF3IJQ5V.js → bridge-U6HXOHE7.js} +34 -32
  22. package/chunks/{channel-worker-supervisor-JUYQ5Z4R.js → channel-worker-supervisor-CRCVYQIE.js} +1 -1
  23. package/chunks/{chunk-AVQDCKNF.js → chunk-22MNNNXE.js} +4 -0
  24. package/chunks/chunk-2DYY5XUZ.js +8223 -0
  25. package/chunks/chunk-2FHWCKWA.js +262 -0
  26. package/chunks/{chunk-6BEOH4KK.js → chunk-2NPS2UDH.js} +767 -122
  27. package/chunks/{chunk-N2IJLN2L.js → chunk-2SWMCXVR.js} +13 -5
  28. package/chunks/{chunk-OBVBTAX5.js → chunk-2YELHTUE.js} +2 -2
  29. package/chunks/chunk-332PWN27.js +19 -0
  30. package/chunks/{chunk-CLQPBI4H.js → chunk-3B26UVCX.js} +132 -26
  31. package/chunks/{chunk-HCFSKO6K.js → chunk-3QDZDAJG.js} +1 -1
  32. package/chunks/{chunk-G7OQ3RFJ.js → chunk-42XGFRJS.js} +3 -3
  33. package/chunks/{chunk-SL2P3JUA.js → chunk-43W4YSO6.js} +1 -12
  34. package/chunks/{chunk-JA5KWZTJ.js → chunk-44NROQYV.js} +5 -3
  35. package/chunks/{chunk-BOAWGUY6.js → chunk-4AFOWB47.js} +121 -49
  36. package/chunks/{chunk-MOUXUCXQ.js → chunk-4KJ2BPIT.js} +1 -1
  37. package/chunks/{chunk-YTWX5TT2.js → chunk-5FL2K3ZB.js} +1 -1
  38. package/chunks/{chunk-UNXGEDX2.js → chunk-5OSSOBZC.js} +133 -25
  39. package/chunks/{chunk-JN2VJ33O.js → chunk-7I4MGFBN.js} +966 -121
  40. package/chunks/{chunk-T42ACHFI.js → chunk-7LTB54MK.js} +1 -1
  41. package/chunks/chunk-A2X3KLC3.js +3807 -0
  42. package/chunks/{chunk-EWALXUAD.js → chunk-AGHU5VRK.js} +8 -0
  43. package/chunks/{chunk-GLPV75ES.js → chunk-AHNJGLFV.js} +2 -2
  44. package/chunks/{chunk-IUSKVKH5.js → chunk-AXTPFMRS.js} +1 -1
  45. package/chunks/{chunk-T22H4V4R.js → chunk-B34OV7K2.js} +1 -1
  46. package/chunks/{chunk-FZ5NVRVK.js → chunk-B5FOCTEZ.js} +3 -3
  47. package/chunks/{chunk-3UC7ZC43.js → chunk-B6WUEODT.js} +7 -7
  48. package/chunks/{chunk-MJKEQSZI.js → chunk-BGL43SJ3.js} +1 -1
  49. package/chunks/{chunk-OAYOHSGP.js → chunk-BHRU4SDF.js} +4 -4
  50. package/chunks/{chunk-YPCPZSZB.js → chunk-CCGOFQV3.js} +56 -4
  51. package/chunks/{chunk-FDY3XOTM.js → chunk-CR5IU2RX.js} +4 -4
  52. package/chunks/{chunk-LWGLBVWA.js → chunk-CSOTA7KX.js} +1 -1
  53. package/chunks/{chunk-AGZF43UV.js → chunk-E7HM76PR.js} +7153 -4406
  54. package/chunks/{chunk-NIOPRZNN.js → chunk-E7KNELIZ.js} +1 -1
  55. package/chunks/{chunk-YSU33ACT.js → chunk-ELMPRVCB.js} +5 -13
  56. package/chunks/{chunk-SEZC2725.js → chunk-ER3BKOLB.js} +13 -0
  57. package/chunks/{chunk-3VJ7MT3N.js → chunk-EXPMGZZV.js} +14 -3
  58. package/chunks/{chunk-DBF3HTLT.js → chunk-FB2ULV4M.js} +4 -4
  59. package/chunks/{chunk-RZORUN6X.js → chunk-FEJ2FZ3U.js} +1 -1
  60. package/chunks/chunk-FK77ILF5.js +2477 -0
  61. package/chunks/{chunk-DMSNJDWG.js → chunk-FV7425LN.js} +38 -3
  62. package/chunks/{chunk-ALX6BUYW.js → chunk-G7ZG7CA6.js} +186 -27
  63. package/chunks/{chunk-2INJBYLJ.js → chunk-GIY6JTTC.js} +6 -6
  64. package/chunks/{chunk-D5KISTLW.js → chunk-H6EMK6QK.js} +1 -1
  65. package/chunks/{chunk-KYTQOCDE.js → chunk-HW4N45EE.js} +17 -46
  66. package/chunks/{chunk-VXGPYF7U.js → chunk-IFEWJXFS.js} +1 -1
  67. package/chunks/chunk-II73RK2S.js +158 -0
  68. package/chunks/{chunk-TENOUWY2.js → chunk-IJRL2S3D.js} +3 -3
  69. package/chunks/{chunk-GQBRGBLS.js → chunk-J43WPR6U.js} +9 -9
  70. package/chunks/{chunk-SRNPMG7J.js → chunk-JYOWO2F7.js} +16 -10
  71. package/chunks/{chunk-57NRQM3P.js → chunk-K34DD7FH.js} +2 -2
  72. package/chunks/{chunk-O2RJARYU.js → chunk-KKWO4IX2.js} +1409 -4088
  73. package/chunks/{chunk-SOT7OMGL.js → chunk-KT3SI3CQ.js} +2 -2
  74. package/chunks/{chunk-NUK2PFSU.js → chunk-L7IWK7JY.js} +1 -1
  75. package/chunks/{chunk-MHQKYQDS.js → chunk-LC4SMGYY.js} +158 -3
  76. package/chunks/chunk-LGFAYIKX.js +115 -0
  77. package/chunks/{chunk-MBWLP5OT.js → chunk-LKXDC3AW.js} +162 -40
  78. package/chunks/{chunk-7Z6UEJA4.js → chunk-ME344634.js} +5 -2
  79. package/chunks/{chunk-V6NH3CUC.js → chunk-MOQOAH7N.js} +3 -3
  80. package/chunks/{chunk-FPHA7WIZ.js → chunk-MYZWWRVW.js} +3 -3
  81. package/chunks/{chunk-YHTNWGRR.js → chunk-MZ7BABX3.js} +1 -1
  82. package/chunks/chunk-N74BA4VP.js +949 -0
  83. package/chunks/{chunk-B236XPGF.js → chunk-NQKLOAVJ.js} +29 -2
  84. package/chunks/{chunk-LXFCHX4X.js → chunk-OU6FPTJZ.js} +312 -25
  85. package/chunks/{chunk-HTWHAN44.js → chunk-PC4ZXHU2.js} +1 -1
  86. package/chunks/{chunk-3X76L4UF.js → chunk-PLGONYEL.js} +5 -5
  87. package/chunks/{chunk-WXUDZHOJ.js → chunk-PVXPDMGP.js} +10 -2
  88. package/chunks/{chunk-ZO5EA3XJ.js → chunk-QCSLZO6J.js} +1 -1
  89. package/chunks/{chunk-CEYA7K7C.js → chunk-QHT5USLK.js} +62 -12
  90. package/chunks/{chunk-NPQWQYU6.js → chunk-QYNNN7BK.js} +1 -1
  91. package/chunks/{chunk-N4YJQTRL.js → chunk-RFIL6REB.js} +71 -2
  92. package/chunks/{chunk-KSPVDFE4.js → chunk-SAIILPQ3.js} +0 -3
  93. package/chunks/{chunk-OIFSBXSP.js → chunk-SJHAUELE.js} +3 -3
  94. package/chunks/{chunk-BZHLWC6T.js → chunk-SUAKHHK7.js} +2 -2
  95. package/chunks/{chunk-QOKV6AO4.js → chunk-T2EJHSE3.js} +184 -147
  96. package/chunks/{chunk-ZI4MGBB5.js → chunk-TBAZMRW3.js} +1 -1
  97. package/chunks/{chunk-6QVRLKTZ.js → chunk-TBLJNMI7.js} +7 -7
  98. package/chunks/{chunk-J6ABRKAB.js → chunk-TDGF35EN.js} +2 -2
  99. package/chunks/chunk-TEYGKLIZ.js +167 -0
  100. package/chunks/{chunk-TOAUDIS7.js → chunk-TLWA7TPR.js} +6 -2
  101. package/chunks/chunk-UIDXQNMV.js +13 -0
  102. package/chunks/{chunk-MX7CTJHR.js → chunk-UZCT5OLN.js} +9 -9
  103. package/chunks/{chunk-LM3YCCZJ.js → chunk-VEB3NYSO.js} +1 -1
  104. package/chunks/{chunk-UTL7KABL.js → chunk-VQJ64BIQ.js} +7 -7
  105. package/chunks/{chunk-C2QKQZEQ.js → chunk-VTCPREC7.js} +3 -3
  106. package/chunks/{chunk-5ES5YPED.js → chunk-VZ7HY3YU.js} +1 -1
  107. package/chunks/{chunk-QOMAHFYI.js → chunk-W7EEOR7D.js} +3 -3
  108. package/chunks/{chunk-NVFJSIAX.js → chunk-WMPVYQ4P.js} +1 -1
  109. package/chunks/{chunk-V5VTULL5.js → chunk-X265R5C6.js} +3 -3
  110. package/chunks/{chunk-LKWAVAB5.js → chunk-X2XNQQJI.js} +2 -2
  111. package/chunks/{chunk-MJKMIQMK.js → chunk-X3YGAX7V.js} +1 -1
  112. package/chunks/{chunk-5WQF27GW.js → chunk-XQ2GVLNJ.js} +1 -1
  113. package/chunks/chunk-XUSONNJ4.js +28 -0
  114. package/chunks/{chunk-DXXNMPJH.js → chunk-YMWIKAEE.js} +460 -93
  115. package/chunks/{chunk-A34EPIUV.js → chunk-YYU6H66M.js} +18 -15
  116. package/chunks/{chunk-XH7H6YG4.js → chunk-ZK5EI6NR.js} +4 -107
  117. package/chunks/{computer-use-5S3NVXRA.js → computer-use-4CTF6WS3.js} +24 -24
  118. package/chunks/{contextCommand-DPBALZFK.js → contextCommand-Z3XWQCY6.js} +28 -27
  119. package/chunks/{cron-create-7JYUDTUY.js → cron-create-JSXEIPVS.js} +4 -4
  120. package/chunks/{cron-delete-YPULQQAK.js → cron-delete-OIFVEPGU.js} +4 -4
  121. package/chunks/{cron-list-HJIW5MHP.js → cron-list-D4ZX4IOE.js} +11 -7
  122. package/chunks/{daemon-7XYW4BC3.js → daemon-F3I2RXP6.js} +208 -63
  123. package/chunks/daemon-status-provider-6A4QCG6Q.js +74 -0
  124. package/chunks/dist-573HNSVO.js +3217 -0
  125. package/chunks/{dist-ABQ7VWRR.js → dist-FQ5WRJPL.js} +2 -2
  126. package/chunks/{dist-JPSVN367.js → dist-IMFFBMAT.js} +6 -3792
  127. package/chunks/{dist-BV56HW3W.js → dist-OT7G2WNM.js} +250 -1
  128. package/chunks/{dist-AW5ZYMUI.js → dist-PKFTNUHO.js} +10 -11
  129. package/chunks/{dist-AAO65DPC.js → dist-YTRKAVUB.js} +1 -1
  130. package/chunks/{earlyInputCapture-GGPV4IFT.js → earlyInputCapture-7O47HW62.js} +25 -25
  131. package/chunks/{edit-HJ7ISN4C.js → edit-E32KWLF2.js} +25 -25
  132. package/chunks/{en-XR3S5VWY.js → en-GA2RMXY5.js} +6 -1
  133. package/chunks/{enter-worktree-2BQT675D.js → enter-worktree-ZKFFMHUD.js} +24 -24
  134. package/chunks/{enterPlanMode-SJXHJ3WD.js → enterPlanMode-HLDC6NGX.js} +24 -24
  135. package/chunks/{errors-EVGER4AZ.js → errors-MTIDDXX7.js} +26 -26
  136. package/chunks/{exit-worktree-RPDDOSPM.js → exit-worktree-YHY72XA2.js} +24 -24
  137. package/chunks/{exitPlanMode-BQEROAJ7.js → exitPlanMode-JNXKBZ2C.js} +24 -24
  138. package/chunks/{fast-path-FX2ICJ2O.js → fast-path-DVAGBROV.js} +5 -2
  139. package/chunks/{fr-MBMNQSQ6.js → fr-GWNQG4XH.js} +4 -0
  140. package/chunks/{gemini-EHUXCOUI.js → gemini-2TMHJVRC.js} +444 -256
  141. package/chunks/{geminiContentGenerator-YDUUKAM2.js → geminiContentGenerator-WCH4GWD3.js} +4 -4
  142. package/chunks/{glob-3VIGV2DL.js → glob-I6Y4AGKO.js} +52 -28
  143. package/chunks/{grep-4D3S4NUC.js → grep-3P2J3LU5.js} +24 -24
  144. package/chunks/handleAutoUpdate-4IVRMRG4.js +65 -0
  145. package/chunks/{initializer-QZTZSSLW.js → initializer-DVNCPVTC.js} +31 -29
  146. package/chunks/{ja-HFV5QCHR.js → ja-2HOTA47X.js} +4 -0
  147. package/chunks/{keychain-token-storage-GPAKRDKQ.js → keychain-token-storage-UJV5XP4Z.js} +2 -2
  148. package/chunks/{list-WQ24EAMK.js → list-4D6QK2KZ.js} +30 -30
  149. package/chunks/{loadedSettingsAdapter-XV74KOSR.js → loadedSettingsAdapter-GNGELH6Q.js} +28 -28
  150. package/chunks/{loop-wakeup-34YK7T7O.js → loop-wakeup-OHWEMFP5.js} +5 -5
  151. package/chunks/{ls-MPD5OJUX.js → ls-L654WOAT.js} +4 -4
  152. package/chunks/{lsp-72PWTDW7.js → lsp-M35KE54Y.js} +2 -2
  153. package/chunks/{mcp-CO3MKM7N.js → mcp-2IL72YJP.js} +28 -28
  154. package/chunks/{monitor-GB56T65A.js → monitor-BLVCZAVX.js} +32 -27
  155. package/chunks/nonInteractiveCli-UD3V7UOO.js +116 -0
  156. package/chunks/{notebook-edit-VMXAAE3R.js → notebook-edit-5TVMWIWY.js} +25 -25
  157. package/chunks/{openaiContentGenerator-GM77FLII.js → openaiContentGenerator-5LJ5A7YY.js} +12 -12
  158. package/chunks/{pidfile-HFXSHR64.js → pidfile-AN5JQJ2T.js} +25 -25
  159. package/chunks/{qwenContentGenerator-QSCXQIKJ.js → qwenContentGenerator-E2JSB4FJ.js} +26 -26
  160. package/chunks/{qwenOAuth2-LWLA6MQG.js → qwenOAuth2-ZV7YLMND.js} +5 -5
  161. package/chunks/{read-file-SVH6CGQY.js → read-file-N5DEFUDU.js} +8 -8
  162. package/chunks/{read-mcp-resource-OWOBJY72.js → read-mcp-resource-CNQHBSJM.js} +2 -2
  163. package/chunks/{record-artifact-URK3YUDJ.js → record-artifact-PP3LKHTS.js} +2 -2
  164. package/chunks/{ripGrep-JD5O2FLX.js → ripGrep-BLJHTHKE.js} +24 -24
  165. package/chunks/{run-qwen-serve-FADLRJUN.js → run-qwen-serve-4JDO64RN.js} +785 -35
  166. package/chunks/{scheduler-Q65SB7DJ.js → scheduler-FQR4XA7J.js} +24 -24
  167. package/chunks/{send-message-L7OLQEKH.js → send-message-OA6MV4EU.js} +3 -3
  168. package/chunks/{serve-6ZXAMQ4M.js → serve-ZOCFC7YM.js} +29 -29
  169. package/chunks/{server-WKDQA6XR.js → server-GEOYEPYT.js} +2504 -439
  170. package/chunks/{session-STWOX7RA.js → session-NJCONHGX.js} +66 -61
  171. package/chunks/{settings-LC4CCWQQ.js → settings-QBGGXANI.js} +27 -27
  172. package/chunks/{shell-FEG3RLPW.js → shell-2DVPSEKT.js} +24 -24
  173. package/chunks/{skill-XTXAMDAP.js → skill-HIPXUHV7.js} +24 -12
  174. package/chunks/{spawnChannel-B6JJPBPV.js → spawnChannel-3JYXY52G.js} +27 -27
  175. package/chunks/{src-HITDGVRM.js → src-NLEX4CUC.js} +91 -36
  176. package/chunks/{startInteractiveUI-IT423PW4.js → startInteractiveUI-TYGZIU27.js} +6213 -14273
  177. package/chunks/{syntheticOutput-J3MLCQAR.js → syntheticOutput-F7LSDCAR.js} +3 -3
  178. package/chunks/{task-create-ELEBZ7H2.js → task-create-RPFZNB4B.js} +7 -7
  179. package/chunks/{task-list-IEUZLF3Y.js → task-list-TGGJX7EA.js} +5 -5
  180. package/chunks/{task-stop-QEZW3UDY.js → task-stop-W7NGTMYQ.js} +2 -2
  181. package/chunks/{task-update-DW36J5P5.js → task-update-5WUG5MVQ.js} +7 -7
  182. package/chunks/{team-create-DAG6SNHZ.js → team-create-MGX57SZJ.js} +24 -24
  183. package/chunks/{team-delete-SVITIMBO.js → team-delete-UHQQ2QQX.js} +5 -5
  184. package/chunks/{team-plan-approval-DRDY5OPC.js → team-plan-approval-BO2N7J3E.js} +24 -24
  185. package/chunks/{theme-manager-N67EZC6B.js → theme-manager-WU7LOA64.js} +25 -25
  186. package/chunks/{todoWrite-SFFQHZYY.js → todoWrite-C4ZAMSR3.js} +4 -4
  187. package/chunks/{tool-search-CMDJ5HGM.js → tool-search-CLBKVEVK.js} +11 -28
  188. package/chunks/{trustedFolders-JD4QX6UJ.js → trustedFolders-GAQM2GHB.js} +25 -25
  189. package/chunks/updateCheck-RIK2YIQE.js +65 -0
  190. package/chunks/{validateNonInterActiveAuth-ADDCGZ6A.js → validateNonInterActiveAuth-NS3GBIJZ.js} +61 -56
  191. package/chunks/{version-VAONYVE5.js → version-B3RSLP54.js} +2 -1
  192. package/chunks/{web-fetch-SXAXJHIO.js → web-fetch-UYGMOHW4.js} +5 -5
  193. package/chunks/{workflow-DG2BR42M.js → workflow-7APPIGND.js} +25 -25
  194. package/chunks/{workspace-providers-status-XGW5OZTD.js → workspace-providers-status-SC67GLMY.js} +30 -30
  195. package/chunks/{workspace-service-GX3GGZLU.js → workspace-service-ZJHF22WA.js} +35 -35
  196. package/chunks/{workspace-skills-status-LFK5WV2V.js → workspace-skills-status-NJEK6P6Y.js} +29 -29
  197. package/chunks/{write-file-UR7FXWOU.js → write-file-R6Z3VLRY.js} +25 -25
  198. package/chunks/{zh-FSVJTXA4.js → zh-7XVVRTDH.js} +6 -1
  199. package/chunks/{zh-TW-66MG4LWL.js → zh-TW-DPH554OG.js} +6 -1
  200. package/cli.js +19 -11
  201. package/locales/en.js +9 -2
  202. package/locales/fr.js +6 -0
  203. package/locales/ja.js +6 -0
  204. package/locales/zh-TW.js +9 -2
  205. package/locales/zh.js +9 -2
  206. package/node_modules/@qwen-code/audio-capture/package.json +1 -1
  207. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  208. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  209. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  210. package/package.json +3 -3
  211. package/web-shell/assets/{arc-CUpe0ibu.js → arc-C7hjaa7g.js} +1 -1
  212. package/web-shell/assets/{architectureDiagram-3BPJPVTR-JvyrY_mK.js → architectureDiagram-3BPJPVTR-pm9KtMZY.js} +1 -1
  213. package/web-shell/assets/{blockDiagram-GPEHLZMM-CK3Y_vom.js → blockDiagram-GPEHLZMM-CApElKsU.js} +1 -1
  214. package/web-shell/assets/{c4Diagram-AAUBKEIU-DprSnyrf.js → c4Diagram-AAUBKEIU-BeDe0-9N.js} +1 -1
  215. package/web-shell/assets/channel-BNf1dW-j.js +1 -0
  216. package/web-shell/assets/{chunk-2J33WTMH-DJtRJPmu.js → chunk-2J33WTMH-DJEkmLdl.js} +1 -1
  217. package/web-shell/assets/{chunk-4BX2VUAB-ON6Q2-BG.js → chunk-4BX2VUAB-DXX8gdpe.js} +1 -1
  218. package/web-shell/assets/{chunk-55IACEB6-c60ou5HZ.js → chunk-55IACEB6-DORmk1kQ.js} +1 -1
  219. package/web-shell/assets/{chunk-727SXJPM-BamtPKxx.js → chunk-727SXJPM-DWmO4mCZ.js} +1 -1
  220. package/web-shell/assets/{chunk-AQP2D5EJ-CsVgpu-T.js → chunk-AQP2D5EJ-C7LRaYw2.js} +1 -1
  221. package/web-shell/assets/{chunk-FMBD7UC4-vZrpjAx4.js → chunk-FMBD7UC4-CCdXgyC5.js} +1 -1
  222. package/web-shell/assets/{chunk-ND2GUHAM-qxyNOd5t.js → chunk-ND2GUHAM-SyL_xvWc.js} +1 -1
  223. package/web-shell/assets/{chunk-QZHKN3VN-BvTJSM_S.js → chunk-QZHKN3VN-BzOuCKxa.js} +1 -1
  224. package/web-shell/assets/classDiagram-4FO5ZUOK-uOIGlzgi.js +1 -0
  225. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-uOIGlzgi.js +1 -0
  226. package/web-shell/assets/{cose-bilkent-S5V4N54A-1tXB4pju.js → cose-bilkent-S5V4N54A-BMPWyDKc.js} +1 -1
  227. package/web-shell/assets/{dagre-BM42HDAG-DglBzme8.js → dagre-BM42HDAG-B_GnPWik.js} +1 -1
  228. package/web-shell/assets/{diagram-2AECGRRQ-DEJpqsWz.js → diagram-2AECGRRQ-fJqMc3S_.js} +1 -1
  229. package/web-shell/assets/{diagram-5GNKFQAL-CsQ1NrMG.js → diagram-5GNKFQAL-ximV3O9D.js} +1 -1
  230. package/web-shell/assets/{diagram-KO2AKTUF-Z-3codAi.js → diagram-KO2AKTUF-2vVyjzqw.js} +1 -1
  231. package/web-shell/assets/{diagram-LMA3HP47-mBuPTA2i.js → diagram-LMA3HP47-Dckcx1sT.js} +1 -1
  232. package/web-shell/assets/{diagram-OG6HWLK6-tcA3K3s9.js → diagram-OG6HWLK6-BAVv47ga.js} +1 -1
  233. package/web-shell/assets/{erDiagram-TEJ5UH35-D9bXFRyZ.js → erDiagram-TEJ5UH35-Bn3nf5J0.js} +1 -1
  234. package/web-shell/assets/{flowDiagram-I6XJVG4X-Ck0Py04s.js → flowDiagram-I6XJVG4X-BIbGF9JT.js} +1 -1
  235. package/web-shell/assets/{ganttDiagram-6RSMTGT7-rOevCekE.js → ganttDiagram-6RSMTGT7-CDbhb3AH.js} +1 -1
  236. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CoPQaLj0.js → gitGraphDiagram-PVQCEYII-CbKG1a_w.js} +1 -1
  237. package/web-shell/assets/index-CnE2ur2L.js +779 -0
  238. package/web-shell/assets/index-hSKXrlSE.css +5 -0
  239. package/web-shell/assets/{infoDiagram-5YYISTIA-a77CUKoI.js → infoDiagram-5YYISTIA-DUFxTy8m.js} +1 -1
  240. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DlLgUAO-.js → ishikawaDiagram-YF4QCWOH-D69hrBG8.js} +1 -1
  241. package/web-shell/assets/{journeyDiagram-JHISSGLW-BXR5kVAZ.js → journeyDiagram-JHISSGLW-DsvEw51Y.js} +1 -1
  242. package/web-shell/assets/{kanban-definition-UN3LZRKU-h5CoHZg7.js → kanban-definition-UN3LZRKU-lFFjZEYd.js} +1 -1
  243. package/web-shell/assets/{linear-BkaREbyD.js → linear-Bo5bWzvo.js} +1 -1
  244. package/web-shell/assets/{mermaid.core-Bkagz0ng.js → mermaid.core-C_HKMJx5.js} +5 -5
  245. package/web-shell/assets/{mindmap-definition-RKZ34NQL-D7EMKR_5.js → mindmap-definition-RKZ34NQL-DlV-NUTs.js} +1 -1
  246. package/web-shell/assets/{pieDiagram-4H26LBE5-DAmPOjsL.js → pieDiagram-4H26LBE5-B2e6FH2a.js} +1 -1
  247. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-e4WFQkQu.js → quadrantDiagram-W4KKPZXB-D75kSk-b.js} +1 -1
  248. package/web-shell/assets/{requirementDiagram-4Y6WPE33-v1zo7OiV.js → requirementDiagram-4Y6WPE33-CQ6xakhM.js} +1 -1
  249. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Bstm4aW_.js → sankeyDiagram-5OEKKPKP-J_XTKrcY.js} +1 -1
  250. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DzcZy6xN.js → sequenceDiagram-3UESZ5HK-D7jTcBtf.js} +1 -1
  251. package/web-shell/assets/{stateDiagram-AJRCARHV-BEJH6YbH.js → stateDiagram-AJRCARHV-CrlM_OT3.js} +1 -1
  252. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Bs4TK_84.js +1 -0
  253. package/web-shell/assets/{timeline-definition-PNZ67QCA-TI1wH-Pm.js → timeline-definition-PNZ67QCA-5oZi76Ef.js} +1 -1
  254. package/web-shell/assets/{vennDiagram-CIIHVFJN-YaH8VDMS.js → vennDiagram-CIIHVFJN-DO5YptPK.js} +1 -1
  255. package/web-shell/assets/{wardley-L42UT6IY-B80co7OP.js → wardley-L42UT6IY-4t1eJDvM.js} +1 -1
  256. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-4fHNDEMl.js → wardleyDiagram-YWT4CUSO-DKZc661S.js} +1 -1
  257. package/web-shell/assets/{xychartDiagram-2RQKCTM6-DT3q4Z3J.js → xychartDiagram-2RQKCTM6-su9hp08G.js} +1 -1
  258. package/web-shell/index.html +2 -2
  259. package/chunks/chunk-L7QPM2YD.js +0 -481
  260. package/chunks/daemon-status-provider-2EWTHT7Y.js +0 -73
  261. package/chunks/nonInteractiveCli-HNZRIM5I.js +0 -111
  262. package/web-shell/assets/channel-BAxQ2-aZ.js +0 -1
  263. package/web-shell/assets/classDiagram-4FO5ZUOK-Cvd_xhZI.js +0 -1
  264. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvd_xhZI.js +0 -1
  265. package/web-shell/assets/index-Cr7MYW6T.css +0 -5
  266. package/web-shell/assets/index-DCHPAUp3.js +0 -730
  267. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BopifCBI.js +0 -1
@@ -79,6 +79,168 @@ init_esbuild_shims();
79
79
  import { spawn } from "node:child_process";
80
80
  import { Readable, Writable } from "node:stream";
81
81
  import { EventEmitter } from "node:events";
82
+
83
+ // packages/channels/base/dist/ChannelLoopTools.js
84
+ init_esbuild_shims();
85
+ var CHANNEL_LOOP_MCP_SERVER_NAME = "channel_loop";
86
+ var CLIENT_MCP_MESSAGE_METHOD = "qwen/control/client_mcp/message";
87
+ var WORKSPACE_MCP_RUNTIME_ADD_METHOD = "qwen/control/workspace/mcp/runtime-add";
88
+ var CLIENT_MCP_OVER_WS_CONFIG_FLAG = "__clientMcpOverWs";
89
+ var createTool = {
90
+ name: "channel_loop_create",
91
+ description: "Create a recurring proactive reminder or scheduled prompt for the current channel chat. Use this in channel sessions instead of cron_create.",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ cron: {
96
+ type: "string",
97
+ description: 'Standard 5-field cron expression in local time, for example "*/5 * * * *".'
98
+ },
99
+ prompt: {
100
+ type: "string",
101
+ description: "The message or instruction to run and proactively push to this channel chat."
102
+ },
103
+ recurring: {
104
+ type: "boolean",
105
+ description: "Whether the loop recurs. Defaults to true."
106
+ }
107
+ },
108
+ required: ["cron", "prompt"]
109
+ }
110
+ };
111
+ var listTool = {
112
+ name: "channel_loop_list",
113
+ description: "List proactive loops for the current channel chat.",
114
+ inputSchema: { type: "object", properties: {} }
115
+ };
116
+ var cancelTool = {
117
+ name: "channel_loop_cancel",
118
+ description: "Cancel a proactive loop for the current channel chat.",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ id: { type: "string", description: "Loop id to cancel." }
123
+ },
124
+ required: ["id"]
125
+ }
126
+ };
127
+ var CHANNEL_LOOP_MCP_TOOLS = [createTool, listTool, cancelTool];
128
+ var ChannelLoopMcpServer = class {
129
+ static {
130
+ __name(this, "ChannelLoopMcpServer");
131
+ }
132
+ handler;
133
+ constructor(handler) {
134
+ this.handler = handler;
135
+ }
136
+ async handleMessage(message, context) {
137
+ const id = message["id"];
138
+ if (id === void 0 || id === null) {
139
+ return void 0;
140
+ }
141
+ try {
142
+ const result = await this.dispatch(message, context);
143
+ return { jsonrpc: "2.0", id, result };
144
+ } catch (error) {
145
+ return {
146
+ jsonrpc: "2.0",
147
+ id,
148
+ error: {
149
+ code: -32603,
150
+ message: error instanceof Error ? error.message : String(error)
151
+ }
152
+ };
153
+ }
154
+ }
155
+ async dispatch(message, context) {
156
+ switch (message["method"]) {
157
+ case "initialize":
158
+ return {
159
+ protocolVersion: "2024-11-05",
160
+ capabilities: { tools: {} },
161
+ serverInfo: { name: CHANNEL_LOOP_MCP_SERVER_NAME, version: "0.0.1" }
162
+ };
163
+ case "tools/list":
164
+ return { tools: CHANNEL_LOOP_MCP_TOOLS };
165
+ case "tools/call":
166
+ return this.callTool(message["params"], context);
167
+ case "ping":
168
+ return {};
169
+ default:
170
+ throw new Error(`Method not found: ${String(message["method"])}`);
171
+ }
172
+ }
173
+ async callTool(rawParams, context) {
174
+ if (!context.sessionId) {
175
+ throw new Error("Missing channel session id.");
176
+ }
177
+ if (typeof rawParams !== "object" || rawParams === null) {
178
+ throw new Error("Invalid tools/call params.");
179
+ }
180
+ const params = rawParams;
181
+ const name = params["name"];
182
+ const args = typeof params["arguments"] === "object" && params["arguments"] !== null ? params["arguments"] : {};
183
+ let toolResult;
184
+ switch (name) {
185
+ case createTool.name:
186
+ toolResult = await this.handler.create(context.sessionId, readCreateInput(args));
187
+ break;
188
+ case listTool.name:
189
+ toolResult = await this.handler.list(context.sessionId);
190
+ break;
191
+ case cancelTool.name:
192
+ toolResult = await this.handler.cancel(context.sessionId, readId(args));
193
+ break;
194
+ default:
195
+ throw new Error(`Unknown channel loop tool: ${String(name)}`);
196
+ }
197
+ const result = typeof toolResult === "string" ? { text: toolResult } : toolResult;
198
+ return {
199
+ content: [{ type: "text", text: result.text }],
200
+ ...result.isError ? { isError: true } : {}
201
+ };
202
+ }
203
+ };
204
+ function readCreateInput(args) {
205
+ const cron = args["cron"];
206
+ const prompt = args["prompt"];
207
+ if (typeof cron !== "string" || cron.trim().length === 0) {
208
+ throw new Error("cron must be a non-empty string.");
209
+ }
210
+ if (typeof prompt !== "string" || prompt.trim().length === 0) {
211
+ throw new Error("prompt must be a non-empty string.");
212
+ }
213
+ const recurring = readRecurring(args["recurring"]);
214
+ return {
215
+ cron: cron.trim(),
216
+ prompt: prompt.trim(),
217
+ ...recurring !== void 0 ? { recurring } : {}
218
+ };
219
+ }
220
+ __name(readCreateInput, "readCreateInput");
221
+ function readRecurring(value) {
222
+ if (typeof value === "boolean")
223
+ return value;
224
+ if (value === "false" || value === 0)
225
+ return false;
226
+ if (value === "true" || value === 1)
227
+ return true;
228
+ return void 0;
229
+ }
230
+ __name(readRecurring, "readRecurring");
231
+ function readId(args) {
232
+ const id = args["id"];
233
+ if (typeof id !== "string" || id.trim().length === 0) {
234
+ throw new Error("id must be a non-empty string.");
235
+ }
236
+ return id.trim();
237
+ }
238
+ __name(readId, "readId");
239
+
240
+ // packages/channels/base/dist/AcpBridge.js
241
+ var MID_TURN_QUEUE_DRAIN_METHOD = "craft/drainMidTurnQueue";
242
+ var ACP_EVENT_LOOP_STALL_RESTART_MS = 5 * 60 * 1e3;
243
+ var ACP_EVENT_LOOP_STALL_RE = /^\[perf\] acp agent event loop stall: max=(\d+(?:\.\d+)?)ms/m;
82
244
  function readAvailableCommandAltNames(raw) {
83
245
  if (typeof raw !== "object" || raw === null)
84
246
  return void 0;
@@ -100,6 +262,10 @@ var AcpBridge = class extends EventEmitter {
100
262
  connection = null;
101
263
  options;
102
264
  _availableCommands = [];
265
+ channelLoopMcpServer;
266
+ channelLoopToolHandlers = [];
267
+ channelLoopMcpRegistered = false;
268
+ channelLoopMcpRegistration = null;
103
269
  constructor(options) {
104
270
  super();
105
271
  this.options = options;
@@ -120,7 +286,7 @@ var AcpBridge = class extends EventEmitter {
120
286
  this.child = spawn(process.execPath, args, {
121
287
  cwd,
122
288
  stdio: ["pipe", "pipe", "pipe"],
123
- env: { ...process.env },
289
+ env: { ...process.env, QWEN_CODE_DISABLE_CRON: "1" },
124
290
  shell: false
125
291
  });
126
292
  this.child.stderr?.on("data", (data) => {
@@ -128,6 +294,7 @@ var AcpBridge = class extends EventEmitter {
128
294
  if (msg) {
129
295
  process.stderr.write(`[AcpBridge] ${msg}
130
296
  `);
297
+ this.maybeKillOnEventLoopStall(msg);
131
298
  }
132
299
  });
133
300
  this.child.on("exit", (code, signal) => {
@@ -154,6 +321,7 @@ var AcpBridge = class extends EventEmitter {
154
321
  const optionId = options.find((o) => o.optionId === "proceed_once")?.optionId || options[0]?.optionId || "proceed_once";
155
322
  return { outcome: { outcome: "selected", optionId } };
156
323
  }, "requestPermission"),
324
+ extMethod: /* @__PURE__ */ __name(async (method, params) => this.handleExtMethod(method, params), "extMethod"),
157
325
  extNotification: /* @__PURE__ */ __name(async () => {
158
326
  }, "extNotification")
159
327
  }), stream);
@@ -161,14 +329,28 @@ var AcpBridge = class extends EventEmitter {
161
329
  protocolVersion: PROTOCOL_VERSION,
162
330
  clientCapabilities: {}
163
331
  });
332
+ await this.registerChannelLoopMcpServer();
333
+ }
334
+ registerChannelLoopToolHandler(handler) {
335
+ if (!this.channelLoopToolHandlers.includes(handler)) {
336
+ this.channelLoopToolHandlers.push(handler);
337
+ }
338
+ this.channelLoopMcpServer ??= new ChannelLoopMcpServer({
339
+ create: /* @__PURE__ */ __name((sessionId, input) => this.resolveChannelLoopToolHandler(sessionId).create(sessionId, input), "create"),
340
+ list: /* @__PURE__ */ __name((sessionId) => this.resolveChannelLoopToolHandler(sessionId).list(sessionId), "list"),
341
+ cancel: /* @__PURE__ */ __name((sessionId, id) => this.resolveChannelLoopToolHandler(sessionId).cancel(sessionId, id), "cancel")
342
+ });
343
+ void this.registerChannelLoopMcpServer();
164
344
  }
165
345
  async newSession(cwd) {
166
346
  const conn = this.ensureConnection();
347
+ await this.registerChannelLoopMcpServer();
167
348
  const response = await conn.newSession({ cwd, mcpServers: [] });
168
349
  return response.sessionId;
169
350
  }
170
351
  async loadSession(sessionId, cwd) {
171
352
  const conn = this.ensureConnection();
353
+ await this.registerChannelLoopMcpServer();
172
354
  const response = await conn.loadSession({
173
355
  sessionId,
174
356
  cwd,
@@ -263,7 +445,103 @@ var AcpBridge = class extends EventEmitter {
263
445
  }
264
446
  return this.connection;
265
447
  }
448
+ maybeKillOnEventLoopStall(stderr) {
449
+ const match = ACP_EVENT_LOOP_STALL_RE.exec(stderr);
450
+ if (!match)
451
+ return;
452
+ const maxMs = Number(match[1]);
453
+ if (!Number.isFinite(maxMs) || maxMs < ACP_EVENT_LOOP_STALL_RESTART_MS) {
454
+ return;
455
+ }
456
+ const child = this.child;
457
+ if (!child || child.killed || child.exitCode !== null) {
458
+ return;
459
+ }
460
+ process.stderr.write(`[AcpBridge] ACP agent event loop stalled for ${Math.round(maxMs)}ms; killing child process to trigger restart
461
+ `);
462
+ child.kill("SIGKILL");
463
+ }
464
+ async registerChannelLoopMcpServer() {
465
+ if (!this.connection || !this.channelLoopMcpServer || this.channelLoopMcpRegistered) {
466
+ return;
467
+ }
468
+ if (this.channelLoopMcpRegistration) {
469
+ await this.channelLoopMcpRegistration;
470
+ return;
471
+ }
472
+ this.channelLoopMcpRegistration = this.connection.extMethod(WORKSPACE_MCP_RUNTIME_ADD_METHOD, {
473
+ name: CHANNEL_LOOP_MCP_SERVER_NAME,
474
+ originatorClientId: "channel",
475
+ config: {
476
+ type: "sdk",
477
+ [CLIENT_MCP_OVER_WS_CONFIG_FLAG]: true
478
+ }
479
+ }).then((result) => {
480
+ if (isSkippedMcpRegistration(result)) {
481
+ this.channelLoopMcpRegistered = false;
482
+ process.stderr.write(`[AcpBridge] Channel loop MCP server registration skipped${formatSkippedRegistrationReason(result)}
483
+ `);
484
+ return;
485
+ }
486
+ this.channelLoopMcpRegistered = true;
487
+ }).catch((error) => {
488
+ this.channelLoopMcpRegistered = false;
489
+ process.stderr.write(`[AcpBridge] Failed to register channel loop MCP server: ${error instanceof Error ? error.message : String(error)}
490
+ `);
491
+ }).finally(() => {
492
+ this.channelLoopMcpRegistration = null;
493
+ });
494
+ await this.channelLoopMcpRegistration;
495
+ }
496
+ async handleExtMethod(method, params) {
497
+ if (method === CLIENT_MCP_MESSAGE_METHOD) {
498
+ return this.handleClientMcpMessage(params);
499
+ }
500
+ if (method === MID_TURN_QUEUE_DRAIN_METHOD) {
501
+ return { messages: [] };
502
+ }
503
+ throw new Error(`Method not found: ${method}`);
504
+ }
505
+ async handleClientMcpMessage(params) {
506
+ if (!this.channelLoopMcpServer) {
507
+ throw new Error("Channel loop MCP server is not registered.");
508
+ }
509
+ const server = params["server"];
510
+ if (server !== CHANNEL_LOOP_MCP_SERVER_NAME) {
511
+ throw new Error(`Unknown client MCP server: ${String(server)}`);
512
+ }
513
+ const payload = params["payload"];
514
+ if (typeof payload !== "object" || payload === null) {
515
+ throw new Error("Invalid client MCP payload.");
516
+ }
517
+ const sessionId = typeof params["sessionId"] === "string" ? params["sessionId"] : void 0;
518
+ const response = await this.channelLoopMcpServer.handleMessage(payload, { sessionId });
519
+ if (!response) {
520
+ return { payload: { jsonrpc: "2.0", id: 0, result: {} } };
521
+ }
522
+ return { payload: response };
523
+ }
524
+ resolveChannelLoopToolHandler(sessionId) {
525
+ if (this.channelLoopToolHandlers.length === 1 && !this.channelLoopToolHandlers[0].canHandle) {
526
+ return this.channelLoopToolHandlers[0];
527
+ }
528
+ const handler = this.channelLoopToolHandlers.find((candidate) => candidate.canHandle?.(sessionId) === true);
529
+ if (handler)
530
+ return handler;
531
+ throw new Error(this.channelLoopToolHandlers.length === 0 ? "No channel loop tool handler is registered." : `No channel loop handler matched session ${sessionId}.`);
532
+ }
266
533
  };
534
+ function isSkippedMcpRegistration(result) {
535
+ return typeof result === "object" && result !== null && result.skipped === true;
536
+ }
537
+ __name(isSkippedMcpRegistration, "isSkippedMcpRegistration");
538
+ function formatSkippedRegistrationReason(result) {
539
+ if (typeof result !== "object" || result === null)
540
+ return ".";
541
+ const reason = result.reason;
542
+ return typeof reason === "string" && reason.length > 0 ? `: ${sanitizeLogText(reason, 256)}` : ".";
543
+ }
544
+ __name(formatSkippedRegistrationReason, "formatSkippedRegistrationReason");
267
545
 
268
546
  // packages/channels/base/dist/DaemonChannelBridge.js
269
547
  init_esbuild_shims();
@@ -1404,18 +1682,21 @@ var SessionRouter = class {
1404
1682
  return `${channelName}:${senderId}:${chatId}`;
1405
1683
  }
1406
1684
  }
1407
- async resolve(channelName, senderId, chatId, threadId, cwd) {
1685
+ async resolve(channelName, senderId, chatId, threadId, cwd, isGroup) {
1408
1686
  const key = this.routingKey(channelName, senderId, chatId, threadId);
1409
1687
  let failedCreateWaits = 0;
1410
1688
  for (; ; ) {
1411
1689
  const existing = this.toSession.get(key);
1412
1690
  if (existing) {
1691
+ this.promoteTargetToGroup(existing, isGroup);
1413
1692
  return existing;
1414
1693
  }
1415
1694
  const creating = this.creatingSessions.get(key);
1416
1695
  if (creating) {
1417
1696
  try {
1418
- return await creating;
1697
+ const sessionId = await creating;
1698
+ this.promoteTargetToGroup(sessionId, isGroup);
1699
+ return sessionId;
1419
1700
  } catch (err) {
1420
1701
  if (this.creatingSessions.get(key) === creating) {
1421
1702
  this.creatingSessions.delete(key);
@@ -1437,7 +1718,8 @@ var SessionRouter = class {
1437
1718
  channelName,
1438
1719
  senderId,
1439
1720
  chatId,
1440
- threadId
1721
+ threadId,
1722
+ isGroup
1441
1723
  });
1442
1724
  this.toCwd.set(sessionId, sessionCwd);
1443
1725
  this.persist();
@@ -1538,6 +1820,15 @@ var SessionRouter = class {
1538
1820
  this.toCwd.delete(sessionId);
1539
1821
  return sessionId;
1540
1822
  }
1823
+ promoteTargetToGroup(sessionId, isGroup) {
1824
+ const current = this.toTarget.get(sessionId);
1825
+ if (!current)
1826
+ return;
1827
+ if (current.isGroup === true || isGroup !== true)
1828
+ return;
1829
+ this.toTarget.set(sessionId, { ...current, isGroup: true });
1830
+ this.persist();
1831
+ }
1541
1832
  /** Get all session entries for crash recovery. */
1542
1833
  getAll() {
1543
1834
  const entries = [];
@@ -1976,6 +2267,66 @@ function truncateError(message) {
1976
2267
  }
1977
2268
  __name(truncateError, "truncateError");
1978
2269
 
2270
+ // packages/channels/base/dist/channel-memory-intent.js
2271
+ init_esbuild_shims();
2272
+ var REMEMBER_PATTERNS = [
2273
+ /^记住[::]\s*(.+)$/su,
2274
+ /^记一下[::,,]?\s*(.+)$/su,
2275
+ /^帮我记一下[::,,]?\s*(.+)$/su,
2276
+ /^帮我记住[::,,]?\s*(.+)$/su,
2277
+ /^以后记住[::,,]?\s*(.+)$/su,
2278
+ /^remember:\s*(.+)$/isu
2279
+ ];
2280
+ var LIST_PATTERNS = [
2281
+ /^你现在记住了什么[??]?$/u,
2282
+ /^查看记忆$/u,
2283
+ /^当前记忆$/u,
2284
+ /^这个聊天你记住了什么[??]?$/u,
2285
+ /^what do you remember[??]?$/iu
2286
+ ];
2287
+ var CLEAR_REQUEST_PATTERNS = [
2288
+ /^清空记忆$/u,
2289
+ /^清除记忆$/u,
2290
+ /^忘掉这个聊天的所有记忆$/u,
2291
+ /^把.+的?记忆清空$/u,
2292
+ /^clear memory$/iu
2293
+ ];
2294
+ var CLEAR_CONFIRM_PATTERNS = [
2295
+ /^确认清空记忆$/u,
2296
+ /^确认清除记忆$/u,
2297
+ /^confirm clear memory$/iu
2298
+ ];
2299
+ function parseChannelMemoryIntent(text) {
2300
+ const trimmed = text.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
2301
+ if (!trimmed || trimmed.startsWith("/")) {
2302
+ return null;
2303
+ }
2304
+ for (const pattern of CLEAR_CONFIRM_PATTERNS) {
2305
+ if (pattern.test(trimmed)) {
2306
+ return { kind: "clear_confirm" };
2307
+ }
2308
+ }
2309
+ for (const pattern of CLEAR_REQUEST_PATTERNS) {
2310
+ if (pattern.test(trimmed)) {
2311
+ return { kind: "clear_request" };
2312
+ }
2313
+ }
2314
+ for (const pattern of LIST_PATTERNS) {
2315
+ if (pattern.test(trimmed)) {
2316
+ return { kind: "list" };
2317
+ }
2318
+ }
2319
+ for (const pattern of REMEMBER_PATTERNS) {
2320
+ const match = trimmed.match(pattern);
2321
+ const remembered = match?.[1]?.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
2322
+ if (remembered) {
2323
+ return { kind: "remember", text: remembered };
2324
+ }
2325
+ }
2326
+ return null;
2327
+ }
2328
+ __name(parseChannelMemoryIntent, "parseChannelMemoryIntent");
2329
+
1979
2330
  // packages/channels/base/dist/ChannelBase.js
1980
2331
  var CLEAR_CANCEL_TIMEOUT_MS = 3e3;
1981
2332
  var GROUP_HISTORY_CONTEXT_MARKER = "[Chat messages since your last reply - for context]";
@@ -1983,6 +2334,8 @@ var CURRENT_MESSAGE_MARKER = "[Current message - respond to this]";
1983
2334
  var GROUP_HISTORY_ENTRY_TEXT_LIMIT = 1e3;
1984
2335
  var GROUP_HISTORY_ENTRY_METADATA_LIMIT = 256;
1985
2336
  var LOOP_CANCEL_GRACE_MS = 5e3;
2337
+ var CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE = 0.7;
2338
+ var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|保存|remember|memory|forget)/iu;
1986
2339
  var LOOP_TIMED_OUT_MESSAGE = "loop timed out";
1987
2340
  var COMMAND_TOKEN_CHARS = "a-zA-Z0-9_:-";
1988
2341
  var PARSE_COMMAND_RE = new RegExp(`^\\/([${COMMAND_TOKEN_CHARS}]+)(?:@\\S+)?\\s*(.*)`, "s");
@@ -2015,6 +2368,7 @@ var ChannelBase = class {
2015
2368
  /** Resolved proxy URL, available to subclasses for adapter-specific clients. */
2016
2369
  proxy;
2017
2370
  channelMemory;
2371
+ memoryIntentClassifier;
2018
2372
  groupHistory;
2019
2373
  loopController;
2020
2374
  instructedSessions = /* @__PURE__ */ new Set();
@@ -2028,16 +2382,24 @@ var ChannelBase = class {
2028
2382
  * so a cleared session can't be resurrected by an already-queued prompt.
2029
2383
  */
2030
2384
  sessionGenerations = /* @__PURE__ */ new Map();
2385
+ pendingClears = /* @__PURE__ */ new Map();
2031
2386
  /** Per-session active prompt tracking for dispatch modes. */
2032
2387
  activePrompts = /* @__PURE__ */ new Map();
2033
2388
  /** Per-session message buffer for collect mode. */
2034
2389
  collectBuffers = /* @__PURE__ */ new Map();
2390
+ preflightedEnvelopes = /* @__PURE__ */ new WeakSet();
2035
2391
  bridgeToolCallListener = /* @__PURE__ */ __name((event) => {
2036
2392
  this.dispatchToolCall(event);
2037
2393
  }, "bridgeToolCallListener");
2038
2394
  bridgeSessionDiedListener = /* @__PURE__ */ __name((event) => {
2039
2395
  this.onSessionDied(event.sessionId);
2040
2396
  }, "bridgeSessionDiedListener");
2397
+ channelLoopToolHandler = {
2398
+ canHandle: /* @__PURE__ */ __name((sessionId) => this.router.getTarget(sessionId)?.channelName === this.name, "canHandle"),
2399
+ create: /* @__PURE__ */ __name((sessionId, input) => this.createLoopFromTool(sessionId, input), "create"),
2400
+ list: /* @__PURE__ */ __name((sessionId) => this.listLoopsFromTool(sessionId), "list"),
2401
+ cancel: /* @__PURE__ */ __name((sessionId, id) => this.cancelLoopFromTool(sessionId, id), "cancel")
2402
+ };
2041
2403
  dispatchToolCall(event) {
2042
2404
  const target = this.router.getTarget(event.sessionId);
2043
2405
  const active = this.activePrompts.get(event.sessionId);
@@ -2069,6 +2431,7 @@ var ChannelBase = class {
2069
2431
  this.identity = Object.freeze(this.resolveIdentity(name, config));
2070
2432
  this.memoryScope = Object.freeze(this.resolveMemoryScope(name, config));
2071
2433
  this.channelMemory = options?.channelMemory;
2434
+ this.memoryIntentClassifier = options?.memoryIntentClassifier;
2072
2435
  this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ?? join4(getGlobalQwenDir(), "channels", `${encodeURIComponent(name)}-group-history.jsonl`));
2073
2436
  this.loopController = options?.loopController;
2074
2437
  this.groupGate = new GroupGate(config.groupPolicy, config.groups);
@@ -2076,6 +2439,9 @@ var ChannelBase = class {
2076
2439
  this.gate = new SenderGate(config.senderPolicy, config.allowedUsers, pairingStore);
2077
2440
  this.router = options?.router || new SessionRouter(bridge, config.cwd, config.sessionScope);
2078
2441
  this.registerSharedCommands();
2442
+ if (this.loopController) {
2443
+ bridge.registerChannelLoopToolHandler?.(this.channelLoopToolHandler);
2444
+ }
2079
2445
  this.registerBridgeEvents = options?.registerBridgeEvents ?? !options?.router;
2080
2446
  if (this.registerBridgeEvents) {
2081
2447
  this.attachBridgeEvents(bridge);
@@ -2190,6 +2556,9 @@ var ChannelBase = class {
2190
2556
  }
2191
2557
  this.router.setBridge(bridge);
2192
2558
  this.bridge = bridge;
2559
+ if (this.loopController) {
2560
+ bridge.registerChannelLoopToolHandler?.(this.channelLoopToolHandler);
2561
+ }
2193
2562
  if (this.registerBridgeEvents) {
2194
2563
  this.attachBridgeEvents(bridge);
2195
2564
  }
@@ -2212,7 +2581,7 @@ var ChannelBase = class {
2212
2581
  await this.loopController?.disable(job.id);
2213
2582
  throw new Error(`Loop ${job.id} target is no longer authorized.`);
2214
2583
  }
2215
- const sessionId = await this.router.resolve(this.name, job.target.senderId, job.target.chatId, job.target.threadId, job.cwd);
2584
+ const sessionId = await this.router.resolve(this.name, job.target.senderId, job.target.chatId, job.target.threadId, job.cwd, job.target.isGroup);
2216
2585
  const label = sanitizeQuotedText(job.label || job.id, 80);
2217
2586
  const createdBy = sanitizeSenderName(job.createdBy || "unknown");
2218
2587
  let promptText = `[Loop "${label}" created by ${createdBy}] Scheduled task running unattended: no one is present to answer questions, and your final response is delivered to this chat automatically \u2014 do whatever work the task requires, then put the result in your final response instead of trying to deliver it to this chat yourself.
@@ -2286,6 +2655,8 @@ ${promptText}`;
2286
2655
  resolve: doneResolve,
2287
2656
  chatId: job.target.chatId,
2288
2657
  messageId: job.id,
2658
+ senderId: job.target.senderId,
2659
+ senderName: job.createdBy,
2289
2660
  loopPrompt: true
2290
2661
  };
2291
2662
  this.activePrompts.set(sessionId, promptState);
@@ -2396,6 +2767,7 @@ ${promptText}`;
2396
2767
  const lost = buffer.length;
2397
2768
  const coalesced = buffer.map((b) => b.text).join("\n\n");
2398
2769
  const lastEnvelope = buffer[buffer.length - 1].envelope;
2770
+ this.notifyPromptBufferDrained(lastEnvelope.chatId, sessionId, buffer);
2399
2771
  const syntheticEnvelope = {
2400
2772
  ...lastEnvelope,
2401
2773
  text: coalesced,
@@ -2405,7 +2777,8 @@ ${promptText}`;
2405
2777
  imageBase64: void 0,
2406
2778
  imageMimeType: void 0
2407
2779
  };
2408
- this.handleInbound(syntheticEnvelope).catch((err) => {
2780
+ this.markPreflighted(syntheticEnvelope);
2781
+ this.processInbound(syntheticEnvelope).catch((err) => {
2409
2782
  process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) after loop ${job.id} for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
2410
2783
  `);
2411
2784
  });
@@ -2495,11 +2868,39 @@ ${promptText}`;
2495
2868
  }
2496
2869
  active.cancelled = true;
2497
2870
  this.stopActiveStreaming(active, sessionId, reason);
2498
- this.collectBuffers.delete(sessionId);
2871
+ this.dropCollectBuffer(sessionId);
2499
2872
  this.emitTaskCancellation(active, sessionId, reason);
2500
2873
  return true;
2501
2874
  });
2502
2875
  }
2876
+ dropCollectBuffer(sessionId) {
2877
+ const buffer = this.collectBuffers.get(sessionId);
2878
+ if (!buffer)
2879
+ return;
2880
+ this.collectBuffers.delete(sessionId);
2881
+ const chatId = buffer[0]?.envelope.chatId ?? "";
2882
+ const messageIds = this.collectBufferMessageIds(buffer);
2883
+ try {
2884
+ this.onPromptBufferDropped(chatId, sessionId, messageIds);
2885
+ } catch (err) {
2886
+ process.stderr.write(`[${this.name}] onPromptBufferDropped threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
2887
+ `);
2888
+ }
2889
+ }
2890
+ notifyPromptBufferDrained(chatId, sessionId, buffer) {
2891
+ const messageIds = this.collectBufferMessageIds(buffer);
2892
+ if (messageIds.length === 0)
2893
+ return;
2894
+ try {
2895
+ this.onPromptBufferDrained(chatId, sessionId, messageIds);
2896
+ } catch (err) {
2897
+ process.stderr.write(`[${this.name}] onPromptBufferDrained threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
2898
+ `);
2899
+ }
2900
+ }
2901
+ collectBufferMessageIds(buffer) {
2902
+ return buffer.map((entry) => entry.envelope.messageId).filter((id) => typeof id === "string" && id.length > 0);
2903
+ }
2503
2904
  logCancelSessionFailure(sessionId, err) {
2504
2905
  process.stderr.write(`[${sanitizeLogText(this.name, 64)}] cancelSession failed for session=${sanitizeLogText(sessionId, 64)}: ${this.lifecycleError(err)}
2505
2906
  `);
@@ -2545,6 +2946,12 @@ ${promptText}`;
2545
2946
  */
2546
2947
  onPromptStart(_chatId, _sessionId, _messageId) {
2547
2948
  }
2949
+ onPromptBuffered(_chatId, _sessionId, _messageId) {
2950
+ }
2951
+ onPromptBufferDrained(_chatId, _sessionId, _messageIds) {
2952
+ }
2953
+ onPromptBufferDropped(_chatId, _sessionId, _messageIds) {
2954
+ }
2548
2955
  /**
2549
2956
  * Called when a prompt finishes (response sent or cancelled).
2550
2957
  * Override to hide the working indicator.
@@ -2609,7 +3016,7 @@ ${promptText}`;
2609
3016
  }
2610
3017
  this.sessionGenerations.set(id, (this.sessionGenerations.get(id) ?? 0) + 1);
2611
3018
  const active = this.activePrompts.get(id);
2612
- this.collectBuffers.delete(id);
3019
+ this.dropCollectBuffer(id);
2613
3020
  if (active) {
2614
3021
  const settled = await this.cancelAndAwaitActive(active, id);
2615
3022
  if (!settled) {
@@ -2661,77 +3068,20 @@ ${promptText}`;
2661
3068
  this.registerCommand("clear", clearHandler);
2662
3069
  this.registerCommand("reset", clearHandler);
2663
3070
  this.registerCommand("new", clearHandler);
2664
- this.registerCommand("who", async (envelope) => {
2665
- if (!this.isAuthorizedForSharedSession(envelope)) {
2666
- await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
2667
- return true;
2668
- }
2669
- const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
2670
- const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
2671
- await this.sendMessage(envelope.chatId, [
2672
- `Channel: ${this.name}`,
2673
- // Identity/memory lines only for channels that opted in — keep
2674
- // unconfigured channels' output unchanged.
2675
- ...this.shouldPrependChannelBoundaryPrompt() ? [
2676
- `Identity: ${sanitizeQuotedText(this.identity.displayName, 128)}`,
2677
- `Memory: ${sanitizeQuotedText(this.memoryScope.namespace, 128)}`
2678
- ] : [],
2679
- // Only the basename — don't leak the absolute cwd to group members.
2680
- `Workspace: ${basename(this.config.cwd)}`,
2681
- `Session: ${active ? "active" : "none"}${scopeNote}`
2682
- ].join("\n"));
2683
- return true;
2684
- });
2685
3071
  this.registerCommand("remember-channel", async (envelope, args) => {
2686
- if (!await this.ensureChannelMemoryAuthorized(envelope)) {
2687
- return true;
2688
- }
2689
- if (envelope.isGroup) {
2690
- await this.sendMessage(envelope.chatId, "Channel memory cannot be changed in group chats.");
2691
- return true;
2692
- }
2693
- if (args.trim() === "") {
3072
+ const text = args.trim();
3073
+ if (text === "") {
2694
3074
  await this.sendMessage(envelope.chatId, "Usage: /remember-channel <text>");
2695
3075
  return true;
2696
3076
  }
2697
- const channelMemory = await this.getChannelMemory(envelope);
2698
- if (!channelMemory) {
2699
- return true;
2700
- }
2701
- try {
2702
- await channelMemory.appendChannelMemory(this.channelMemoryTarget(envelope), args.trim());
2703
- } catch (error) {
2704
- const message = this.channelMemoryErrorMessage(error);
2705
- this.logChannelMemoryError("save", envelope, message);
2706
- await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
2707
- return true;
2708
- }
2709
- this.invalidateSessionContext(envelope);
2710
- await this.sendMessage(envelope.chatId, "Channel memory updated.");
3077
+ await this.handleChannelMemoryIntent(envelope, {
3078
+ kind: "remember",
3079
+ text
3080
+ });
2711
3081
  return true;
2712
3082
  });
2713
3083
  this.registerCommand("channel-memory", async (envelope) => {
2714
- if (!await this.ensureChannelMemoryAuthorized(envelope)) {
2715
- return true;
2716
- }
2717
- if (envelope.isGroup) {
2718
- await this.sendMessage(envelope.chatId, "Channel memory cannot be shown in group chats.");
2719
- return true;
2720
- }
2721
- const channelMemory = await this.getChannelMemory(envelope);
2722
- if (!channelMemory) {
2723
- return true;
2724
- }
2725
- let text;
2726
- try {
2727
- text = (await channelMemory.readChannelMemory(this.channelMemoryTarget(envelope))).trim();
2728
- } catch (error) {
2729
- const message = this.channelMemoryErrorMessage(error);
2730
- this.logChannelMemoryError("read", envelope, message);
2731
- await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
2732
- return true;
2733
- }
2734
- await this.sendMessage(envelope.chatId, text === "" ? "No channel memory saved." : sanitizePromptText(text));
3084
+ await this.handleChannelMemoryIntent(envelope, { kind: "list" });
2735
3085
  return true;
2736
3086
  });
2737
3087
  this.registerCommand("forget-channel", async (envelope, args) => {
@@ -2746,21 +3096,28 @@ ${promptText}`;
2746
3096
  await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Re-send with "confirm" (e.g. /forget-channel confirm) to proceed.');
2747
3097
  return true;
2748
3098
  }
2749
- const channelMemory = await this.getChannelMemory(envelope);
2750
- if (!channelMemory) {
2751
- return true;
2752
- }
2753
- let result;
2754
- try {
2755
- result = await channelMemory.clearChannelMemory(this.channelMemoryTarget(envelope));
2756
- } catch (error) {
2757
- const message = this.channelMemoryErrorMessage(error);
2758
- this.logChannelMemoryError("clear", envelope, message);
2759
- await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
3099
+ await this.handleChannelMemoryIntent(envelope, { kind: "clear_confirm" }, { skipPendingClear: true });
3100
+ return true;
3101
+ });
3102
+ this.registerCommand("who", async (envelope) => {
3103
+ if (!this.isAuthorizedForSharedSession(envelope)) {
3104
+ await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
2760
3105
  return true;
2761
3106
  }
2762
- this.invalidateSessionContext(envelope);
2763
- await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
3107
+ const active = this.router.hasSession(this.name, envelope.senderId, envelope.chatId, envelope.threadId);
3108
+ const scopeNote = this.config.sessionScope === "single" ? " (shared channel-wide)" : this.isSharedSession(envelope) ? envelope.isGroup ? " (shared by this group)" : "" : envelope.isGroup ? " (private to you)" : "";
3109
+ await this.sendMessage(envelope.chatId, [
3110
+ `Channel: ${this.name}`,
3111
+ // Identity/memory lines only for channels that opted in — keep
3112
+ // unconfigured channels' output unchanged.
3113
+ ...this.shouldPrependChannelBoundaryPrompt() ? [
3114
+ `Identity: ${sanitizeQuotedText(this.identity.displayName, 128)}`,
3115
+ `Memory: ${sanitizeQuotedText(this.memoryScope.namespace, 128)}`
3116
+ ] : [],
3117
+ // Only the basename — don't leak the absolute cwd to group members.
3118
+ `Workspace: ${basename(this.config.cwd)}`,
3119
+ `Session: ${active ? "active" : "none"}${scopeNote}`
3120
+ ].join("\n"));
2764
3121
  return true;
2765
3122
  });
2766
3123
  this.registerCommand("help", async (envelope) => {
@@ -2769,21 +3126,18 @@ ${promptText}`;
2769
3126
  "/help \u2014 Show this help",
2770
3127
  this.isSharedSession(envelope) ? "/clear confirm \u2014 Clear the shared session (aliases: /reset, /new)" : "/clear \u2014 Clear your session (aliases: /reset, /new)",
2771
3128
  "/who \u2014 Show current session & workspace",
2772
- "/status \u2014 Show session info",
2773
- "/remember-channel <text> \u2014 Save memory for this chat",
2774
- "/channel-memory \u2014 Show memory for this chat",
2775
- "/forget-channel confirm \u2014 Clear memory for this chat"
3129
+ "/status \u2014 Show session info"
2776
3130
  ];
2777
3131
  const sharedCmds = /* @__PURE__ */ new Set([
2778
3132
  "help",
2779
3133
  "clear",
2780
3134
  "reset",
2781
3135
  "new",
2782
- "who",
2783
- "status",
2784
3136
  "remember-channel",
2785
3137
  "channel-memory",
2786
- "forget-channel"
3138
+ "forget-channel",
3139
+ "who",
3140
+ "status"
2787
3141
  ]);
2788
3142
  const platformCmds = [...this.commands.keys()].filter((c) => !sharedCmds.has(c));
2789
3143
  if (platformCmds.length > 0) {
@@ -2906,6 +3260,100 @@ ${promptText}`;
2906
3260
  await this.sendMessage(envelope.chatId, `Loop ${job.id}: ${job.cron}`);
2907
3261
  return true;
2908
3262
  }
3263
+ async createLoopFromTool(sessionId, input) {
3264
+ if (!this.loopController) {
3265
+ return { text: "Channel loops are not configured.", isError: true };
3266
+ }
3267
+ if (!this.supportsProactiveSend()) {
3268
+ return {
3269
+ text: "This channel does not support proactive loop messages.",
3270
+ isError: true
3271
+ };
3272
+ }
3273
+ if (this.config.sessionScope === "single") {
3274
+ return {
3275
+ text: "Loops are not supported when sessionScope is single.",
3276
+ isError: true
3277
+ };
3278
+ }
3279
+ const target = this.loopToolTarget(sessionId);
3280
+ if (typeof target === "string")
3281
+ return { text: target, isError: true };
3282
+ if (!this.supportsProactiveTarget(target)) {
3283
+ return {
3284
+ text: "This channel does not support proactive loop messages for this chat target.",
3285
+ isError: true
3286
+ };
3287
+ }
3288
+ const cron = input.cron.trim();
3289
+ try {
3290
+ this.loopController.validateCron(cron);
3291
+ } catch (err) {
3292
+ return {
3293
+ text: `Invalid cron expression: ${err instanceof Error ? err.message : String(err)}`,
3294
+ isError: true
3295
+ };
3296
+ }
3297
+ const prompt = sanitizePromptText(input.prompt.trim());
3298
+ if (Array.from(prompt).length > MAX_LOOP_PROMPT_CHARS) {
3299
+ return {
3300
+ text: `Loop prompt is too long; keep it under ${MAX_LOOP_PROMPT_CHARS} characters.`,
3301
+ isError: true
3302
+ };
3303
+ }
3304
+ const loopInput = {
3305
+ channelName: this.name,
3306
+ target,
3307
+ cwd: this.config.cwd,
3308
+ cron,
3309
+ prompt,
3310
+ label: truncateLoopLabel(prompt),
3311
+ recurring: input.recurring !== false,
3312
+ createdBy: sanitizeSenderName(this.toolCallerName(sessionId, target))
3313
+ };
3314
+ let job;
3315
+ if (this.loopController.createForTarget) {
3316
+ job = await this.loopController.createForTarget(loopInput, MAX_LOOP_JOBS_PER_TARGET);
3317
+ } else {
3318
+ const existingJobs = await this.loopController.listForTarget(this.name, target);
3319
+ if (existingJobs.filter((existingJob) => existingJob.enabled).length < MAX_LOOP_JOBS_PER_TARGET) {
3320
+ job = await this.loopController.create(loopInput);
3321
+ }
3322
+ }
3323
+ if (!job) {
3324
+ return {
3325
+ text: "Too many loops for this chat. Cancel an existing loop before adding another.",
3326
+ isError: true
3327
+ };
3328
+ }
3329
+ return `Loop ${job.id}: ${job.cron}`;
3330
+ }
3331
+ async listLoopsFromTool(sessionId) {
3332
+ if (!this.loopController) {
3333
+ return { text: "Channel loops are not configured.", isError: true };
3334
+ }
3335
+ const target = this.loopToolTarget(sessionId);
3336
+ if (typeof target === "string")
3337
+ return { text: target, isError: true };
3338
+ const jobs = await this.loopController.listForTarget(this.name, target);
3339
+ if (jobs.length === 0)
3340
+ return "No loops.";
3341
+ return jobs.map((job) => this.formatLoopListLine(job)).join("\n");
3342
+ }
3343
+ async cancelLoopFromTool(sessionId, id) {
3344
+ if (!this.loopController) {
3345
+ return { text: "Channel loops are not configured.", isError: true };
3346
+ }
3347
+ const target = this.loopToolTarget(sessionId);
3348
+ if (typeof target === "string")
3349
+ return { text: target, isError: true };
3350
+ const jobs = await this.loopController.listForTarget(this.name, target);
3351
+ const match = jobs.find((job) => job.id === id);
3352
+ if (!match)
3353
+ return { text: `No loop ${id}.`, isError: true };
3354
+ const disabled = await this.loopController.disable(id);
3355
+ return disabled ? `Cancelled loop ${id}.` : { text: `Failed to cancel loop ${id}.`, isError: true };
3356
+ }
2909
3357
  async handleLoopList(envelope) {
2910
3358
  if (!this.loopController)
2911
3359
  return true;
@@ -2986,35 +3434,55 @@ ${promptText}`;
2986
3434
  }
2987
3435
  const jobs = await this.loopController.listForTarget(this.name, this.loopTargetFromEnvelope(envelope));
2988
3436
  const match = jobs.find((job) => job.id === id);
2989
- const disabled = match ? await this.loopController.disable(id) : false;
2990
- await this.sendMessage(envelope.chatId, disabled ? `Cancelled loop ${id}.` : `No loop ${id}.`);
3437
+ if (!match) {
3438
+ await this.sendMessage(envelope.chatId, `No loop ${id}.`);
3439
+ return true;
3440
+ }
3441
+ const disabled = await this.loopController.disable(id);
3442
+ await this.sendMessage(envelope.chatId, disabled ? `Cancelled loop ${id}.` : `Failed to cancel loop ${id}.`);
2991
3443
  return true;
2992
3444
  }
2993
3445
  loopTargetFromEnvelope(envelope) {
2994
- return {
3446
+ return this.normalizeLoopTarget({
2995
3447
  channelName: this.name,
2996
3448
  senderId: envelope.senderId,
2997
3449
  chatId: envelope.chatId,
2998
3450
  threadId: envelope.threadId,
2999
3451
  isGroup: envelope.isGroup === true
3000
- };
3452
+ });
3001
3453
  }
3002
- isStoredLoopTargetAuthorized(target, senderName) {
3003
- if (target.isGroup === void 0) {
3004
- return false;
3454
+ normalizeLoopTarget(target) {
3455
+ return { ...target, isGroup: target.isGroup === true };
3456
+ }
3457
+ loopToolTarget(sessionId) {
3458
+ const target = this.router.getTarget(sessionId);
3459
+ if (!target || target.channelName !== this.name) {
3460
+ return "No channel target is bound to this session.";
3005
3461
  }
3462
+ if (!this.isAuthorizedForSharedSessionToolCall(target, sessionId)) {
3463
+ return "Only authorized members can use loops in this shared session.";
3464
+ }
3465
+ const senderId = this.activePrompts.get(sessionId)?.senderId;
3466
+ const normalizedTarget = this.normalizeLoopTarget(target);
3467
+ if (senderId && this.isSharedSessionTarget(normalizedTarget)) {
3468
+ return { ...normalizedTarget, senderId };
3469
+ }
3470
+ return normalizedTarget;
3471
+ }
3472
+ isStoredLoopTargetAuthorized(target, senderName) {
3473
+ const normalizedTarget = this.normalizeLoopTarget(target);
3006
3474
  const envelope = {
3007
3475
  channelName: this.name,
3008
- senderId: target.senderId,
3476
+ senderId: normalizedTarget.senderId,
3009
3477
  senderName,
3010
- chatId: target.chatId,
3478
+ chatId: normalizedTarget.chatId,
3011
3479
  text: "",
3012
- threadId: target.threadId,
3013
- isGroup: target.isGroup === true,
3480
+ threadId: normalizedTarget.threadId,
3481
+ isGroup: normalizedTarget.isGroup,
3014
3482
  isMentioned: true,
3015
3483
  isReplyToBot: true
3016
3484
  };
3017
- return this.groupGate.check(envelope).allowed && this.gate.isAllowed(target.senderId) && this.isAuthorizedForSharedSession(envelope);
3485
+ return this.groupGate.check(envelope).allowed && this.gate.isAllowed(normalizedTarget.senderId) && this.isAuthorizedForSharedSession(envelope);
3018
3486
  }
3019
3487
  /** Check if a message text matches a registered local command. */
3020
3488
  isLocalCommand(text) {
@@ -3067,6 +3535,118 @@ ${promptText}`;
3067
3535
  }
3068
3536
  return this.channelMemory;
3069
3537
  }
3538
+ async handleChannelMemoryIntent(envelope, intent, options = {}) {
3539
+ if (!await this.ensureChannelMemoryAuthorized(envelope)) {
3540
+ return;
3541
+ }
3542
+ if (envelope.isGroup && intent.kind !== "list") {
3543
+ await this.sendMessage(envelope.chatId, "Channel memory cannot be changed in group chats.");
3544
+ return;
3545
+ }
3546
+ if (intent.kind === "clear_request") {
3547
+ this.setPendingClear(this.clearPendingKey(envelope));
3548
+ await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Say "\u786E\u8BA4\u6E05\u7A7A\u8BB0\u5FC6" or "confirm clear memory" to proceed.');
3549
+ return;
3550
+ }
3551
+ const channelMemory = await this.getChannelMemory(envelope);
3552
+ if (!channelMemory) {
3553
+ return;
3554
+ }
3555
+ if (intent.kind === "remember") {
3556
+ try {
3557
+ await channelMemory.appendChannelMemory(this.channelMemoryTarget(envelope), intent.text);
3558
+ } catch (error) {
3559
+ const message = this.channelMemoryErrorMessage(error);
3560
+ this.logChannelMemoryError("save", envelope, message);
3561
+ await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
3562
+ return;
3563
+ }
3564
+ this.invalidateSessionContext(envelope);
3565
+ await this.sendMessage(envelope.chatId, "Channel memory updated.");
3566
+ return;
3567
+ }
3568
+ if (intent.kind === "list") {
3569
+ let text;
3570
+ try {
3571
+ text = (await channelMemory.readChannelMemory(this.channelMemoryTarget(envelope))).trim();
3572
+ } catch (error) {
3573
+ const message = this.channelMemoryErrorMessage(error);
3574
+ this.logChannelMemoryError("read", envelope, message);
3575
+ await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
3576
+ return;
3577
+ }
3578
+ await this.sendMessage(envelope.chatId, text === "" ? "No channel memory saved." : sanitizePromptText(text));
3579
+ return;
3580
+ }
3581
+ if (intent.kind === "clear_confirm") {
3582
+ if (!options.skipPendingClear) {
3583
+ const pendingKey = this.clearPendingKey(envelope);
3584
+ const expiresAt = this.pendingClears.get(pendingKey);
3585
+ this.pendingClears.delete(pendingKey);
3586
+ if (expiresAt === void 0 || expiresAt < Date.now()) {
3587
+ await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
3588
+ return;
3589
+ }
3590
+ }
3591
+ let result;
3592
+ try {
3593
+ result = await channelMemory.clearChannelMemory(this.channelMemoryTarget(envelope));
3594
+ } catch (error) {
3595
+ const message = this.channelMemoryErrorMessage(error);
3596
+ this.logChannelMemoryError("clear", envelope, message);
3597
+ await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
3598
+ return;
3599
+ }
3600
+ this.invalidateSessionContext(envelope);
3601
+ await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
3602
+ return;
3603
+ }
3604
+ const unhandled = intent;
3605
+ throw new Error(`Unhandled channel memory intent: ${JSON.stringify(unhandled)}`);
3606
+ }
3607
+ shouldClassifyChannelMemoryIntent(text) {
3608
+ const normalized = text.replace(PROMPT_UNSAFE_INVISIBLES, "").trim();
3609
+ return this.channelMemory !== void 0 && this.memoryIntentClassifier !== void 0 && !normalized.startsWith("/") && CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE.test(normalized);
3610
+ }
3611
+ clearPendingKey(envelope) {
3612
+ return `${this.name}:${envelope.chatId}:${envelope.threadId ?? ""}:${envelope.senderId ?? ""}`;
3613
+ }
3614
+ setPendingClear(key) {
3615
+ const now = Date.now();
3616
+ for (const [pendingKey, expiresAt] of this.pendingClears) {
3617
+ if (expiresAt < now) {
3618
+ this.pendingClears.delete(pendingKey);
3619
+ }
3620
+ }
3621
+ this.pendingClears.set(key, now + 6e4);
3622
+ }
3623
+ async classifyChannelMemoryIntent(text) {
3624
+ if (!this.memoryIntentClassifier) {
3625
+ return null;
3626
+ }
3627
+ let classified;
3628
+ try {
3629
+ classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(text);
3630
+ } catch (error) {
3631
+ process.stderr.write(`[${this.name}] channel memory intent classifier failed: ${sanitizeLogText(this.channelMemoryErrorMessage(error), 200)}
3632
+ `);
3633
+ return null;
3634
+ }
3635
+ if (classified.confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
3636
+ return null;
3637
+ }
3638
+ if (classified.intent === "remember") {
3639
+ const memory = classified.memory?.trim();
3640
+ return memory ? { kind: "remember", text: memory } : null;
3641
+ }
3642
+ if (classified.intent === "list") {
3643
+ return { kind: "list" };
3644
+ }
3645
+ if (classified.intent === "clear_all") {
3646
+ return { kind: "clear_request" };
3647
+ }
3648
+ return null;
3649
+ }
3070
3650
  channelMemoryErrorMessage(error) {
3071
3651
  return error instanceof Error ? error.message : String(error);
3072
3652
  }
@@ -3099,10 +3679,26 @@ ${promptText}`;
3099
3679
  * gate can't drift; each caller sends its own rejection wording.
3100
3680
  */
3101
3681
  isAuthorizedForSharedSession(envelope) {
3102
- if (!this.isSharedSession(envelope))
3682
+ return this.isAuthorizedForSharedSessionTarget(envelope);
3683
+ }
3684
+ isAuthorizedForSharedSessionTarget(target) {
3685
+ if (!this.isSharedSessionTarget(target))
3103
3686
  return true;
3104
3687
  const authorized = this.config.allowedUsers;
3105
- return authorized.length === 0 || authorized.includes(envelope.senderId);
3688
+ return authorized.length === 0 || authorized.includes(target.senderId);
3689
+ }
3690
+ isAuthorizedForSharedSessionToolCall(target, sessionId) {
3691
+ if (!this.isSharedSessionTarget(target))
3692
+ return true;
3693
+ const authorized = this.config.allowedUsers;
3694
+ if (authorized.length === 0)
3695
+ return true;
3696
+ const senderId = this.activePrompts.get(sessionId)?.senderId;
3697
+ return senderId !== void 0 && authorized.includes(senderId);
3698
+ }
3699
+ toolCallerName(sessionId, target) {
3700
+ const active = this.activePrompts.get(sessionId);
3701
+ return active?.senderName || active?.senderId || target.senderId || "agent";
3106
3702
  }
3107
3703
  stopActiveStreaming(active, sessionId, reason) {
3108
3704
  try {
@@ -3311,19 +3907,54 @@ ${formatted.join("\n")}
3311
3907
  ${CURRENT_MESSAGE_MARKER}
3312
3908
  ${promptText}`;
3313
3909
  }
3314
- async handleInbound(envelope) {
3910
+ preflightInbound(envelope) {
3315
3911
  const groupResult = this.groupGate.check(envelope);
3316
3912
  if (!groupResult.allowed) {
3317
3913
  if (groupResult.reason === "mention_required") {
3318
3914
  this.recordPendingGroupHistory(envelope);
3319
3915
  }
3320
- return;
3916
+ return false;
3321
3917
  }
3322
3918
  const result = this.gate.check(envelope.senderId, envelope.senderName);
3323
3919
  if (!result.allowed) {
3324
3920
  if (result.pairingCode !== void 0) {
3325
- await this.onPairingRequired(envelope.chatId, result.pairingCode);
3921
+ return this.onPairingRequired(envelope.chatId, result.pairingCode).then(() => false).catch((err) => {
3922
+ process.stderr.write(`[Channel:${this.name}] pairing notification failed: ${sanitizeLogText(err instanceof Error ? err.message : String(err), 200)}
3923
+ `);
3924
+ return false;
3925
+ });
3326
3926
  }
3927
+ return false;
3928
+ }
3929
+ this.markPreflighted(envelope);
3930
+ return true;
3931
+ }
3932
+ async handleInbound(envelope) {
3933
+ const preflight = this.preflightInbound(envelope);
3934
+ if (!(isPromiseLike(preflight) ? await preflight : preflight))
3935
+ return;
3936
+ await this.processInbound(envelope);
3937
+ }
3938
+ markPreflighted(envelope) {
3939
+ this.preflightedEnvelopes.add(envelope);
3940
+ }
3941
+ /**
3942
+ * Process an inbound message after preflight gates have passed.
3943
+ *
3944
+ * This method does not run group gating, sender allowlisting, or pairing
3945
+ * checks. Callers must run preflightInbound() first unless the envelope was
3946
+ * already preflighted, such as during collect-buffer drain.
3947
+ */
3948
+ async processInbound(envelope) {
3949
+ if (!this.preflightedEnvelopes.delete(envelope)) {
3950
+ throw new Error("processInbound called without a successful preflightInbound check.");
3951
+ }
3952
+ let memoryIntent = parseChannelMemoryIntent(envelope.text);
3953
+ if (!memoryIntent && this.shouldClassifyChannelMemoryIntent(envelope.text)) {
3954
+ memoryIntent = await this.classifyChannelMemoryIntent(envelope.text);
3955
+ }
3956
+ if (memoryIntent) {
3957
+ await this.handleChannelMemoryIntent(envelope, memoryIntent);
3327
3958
  return;
3328
3959
  }
3329
3960
  const parsed = this.parseCommand(envelope.text);
@@ -3351,20 +3982,20 @@ ${promptText}`;
3351
3982
  return;
3352
3983
  }
3353
3984
  }
3354
- const sessionId = await this.router.resolve(this.name, envelope.senderId, envelope.chatId, envelope.threadId, this.config.cwd);
3985
+ const sessionId = await this.router.resolve(this.name, envelope.senderId, envelope.chatId, envelope.threadId, this.config.cwd, envelope.isGroup);
3355
3986
  if (bangText.startsWith("!")) {
3356
3987
  const cmd = bangText.slice(1).trim();
3357
3988
  const bridgeShellCommand = this.bridge.shellCommand;
3358
3989
  if (cmd && bridgeShellCommand) {
3359
3990
  try {
3360
- const result2 = await bridgeShellCommand(sessionId, cmd);
3361
- const longestRun = Math.max(0, ...Array.from((result2.output || "").matchAll(/`+/g), (m) => m[0].length));
3991
+ const result = await bridgeShellCommand(sessionId, cmd);
3992
+ const longestRun = Math.max(0, ...Array.from((result.output || "").matchAll(/`+/g), (m) => m[0].length));
3362
3993
  const fence = "`".repeat(Math.max(3, longestRun + 1));
3363
- const output = result2.output ? `${fence}
3364
- ${result2.output}
3994
+ const output = result.output ? `${fence}
3995
+ ${result.output}
3365
3996
  ${fence}` : "(no output)";
3366
- const exitLine = result2.exitCode !== null && result2.exitCode !== 0 ? `
3367
- Exit code: ${result2.exitCode}` : "";
3997
+ const exitLine = result.exitCode !== null && result.exitCode !== 0 ? `
3998
+ Exit code: ${result.exitCode}` : "";
3368
3999
  await this.sendMessage(envelope.chatId, `$ ${cmd}
3369
4000
  ${output}${exitLine}`);
3370
4001
  } catch (error) {
@@ -3417,6 +4048,12 @@ ${promptText}`;
3417
4048
  this.collectBuffers.set(sessionId, buffer);
3418
4049
  }
3419
4050
  buffer.push({ text: promptText, envelope });
4051
+ try {
4052
+ this.onPromptBuffered(envelope.chatId, sessionId, envelope.messageId);
4053
+ } catch (err) {
4054
+ process.stderr.write(`[${this.name}] onPromptBuffered threw for session ${sessionId}: ${err instanceof Error ? err.message : err}
4055
+ `);
4056
+ }
3420
4057
  return;
3421
4058
  }
3422
4059
  case "steer": {
@@ -3516,7 +4153,9 @@ ${promptToSend}`;
3516
4153
  done,
3517
4154
  resolve: doneResolve,
3518
4155
  chatId: envelope.chatId,
3519
- messageId: envelope.messageId
4156
+ messageId: envelope.messageId,
4157
+ senderId: envelope.senderId,
4158
+ senderName: envelope.senderName
3520
4159
  };
3521
4160
  this.activePrompts.set(sessionId, promptState);
3522
4161
  this.emitTaskLifecycle({
@@ -3627,6 +4266,7 @@ ${promptToSend}`;
3627
4266
  const lost = buffer.length;
3628
4267
  const coalesced = buffer.map((b) => b.text).join("\n\n");
3629
4268
  const lastEnvelope = buffer[buffer.length - 1].envelope;
4269
+ this.notifyPromptBufferDrained(lastEnvelope.chatId, sessionId, buffer);
3630
4270
  const syntheticEnvelope = {
3631
4271
  ...lastEnvelope,
3632
4272
  text: coalesced,
@@ -3638,7 +4278,8 @@ ${promptToSend}`;
3638
4278
  imageBase64: void 0,
3639
4279
  imageMimeType: void 0
3640
4280
  };
3641
- this.handleInbound(syntheticEnvelope).catch((err) => {
4281
+ this.markPreflighted(syntheticEnvelope);
4282
+ this.processInbound(syntheticEnvelope).catch((err) => {
3642
4283
  process.stderr.write(`[${this.name}] dropped ${lost} buffered message(s) on collect re-entry for session ${sessionId} (last sender ${lastEnvelope.senderId}): ${err instanceof Error ? err.message : String(err)}
3643
4284
  `);
3644
4285
  });
@@ -3664,6 +4305,10 @@ function truncateGroupHistoryField(value) {
3664
4305
  return value.slice(0, GROUP_HISTORY_ENTRY_METADATA_LIMIT);
3665
4306
  }
3666
4307
  __name(truncateGroupHistoryField, "truncateGroupHistoryField");
4308
+ function isPromiseLike(value) {
4309
+ return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
4310
+ }
4311
+ __name(isPromiseLike, "isPromiseLike");
3667
4312
  function truncateLoopLabel(prompt) {
3668
4313
  const chars = Array.from(prompt);
3669
4314
  return chars.length > 60 ? `${chars.slice(0, 57).join("")}...` : prompt;
@@ -3809,7 +4454,7 @@ var ChannelLoopStore = class {
3809
4454
  }
3810
4455
  };
3811
4456
  function sameTarget(a, b) {
3812
- return a.channelName === b.channelName && a.senderId === b.senderId && a.chatId === b.chatId && a.threadId === b.threadId && a.isGroup === b.isGroup;
4457
+ return a.channelName === b.channelName && a.senderId === b.senderId && a.chatId === b.chatId && a.threadId === b.threadId;
3813
4458
  }
3814
4459
  __name(sameTarget, "sameTarget");
3815
4460
  function normalizeTarget(target) {
@@ -3852,12 +4497,12 @@ __name(isTerminalTaskLifecycleType, "isTerminalTaskLifecycleType");
3852
4497
  export {
3853
4498
  resolvePath,
3854
4499
  getGlobalQwenDir,
3855
- AcpBridge,
3856
- DaemonChannelBridge,
3857
- PairingStore,
3858
4500
  sanitizeSenderName,
3859
4501
  sanitizePromptText,
3860
4502
  sanitizeLogText,
4503
+ AcpBridge,
4504
+ DaemonChannelBridge,
4505
+ PairingStore,
3861
4506
  SessionRouter,
3862
4507
  ChannelLoopScheduler,
3863
4508
  ChannelBase,