@qwen-code/qwen-code 0.19.9 → 0.19.10-nightly.20260716.506ce0a1a

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 (323) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +14 -6
  2. package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
  3. package/bundled/qc-helper/docs/features/channels/dingtalk.md +33 -0
  4. package/bundled/qc-helper/docs/features/channels/overview.md +64 -20
  5. package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
  6. package/bundled/qc-helper/docs/features/code-review.md +88 -44
  7. package/bundled/qc-helper/docs/features/commands.md +6 -6
  8. package/bundled/qc-helper/docs/features/hooks.md +29 -0
  9. package/bundled/qc-helper/docs/features/sandbox.md +2 -0
  10. package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
  11. package/bundled/qc-helper/docs/qwen-serve.md +49 -20
  12. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
  13. package/bundled/review/DESIGN.md +219 -33
  14. package/bundled/review/SKILL.md +429 -382
  15. package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-WOC3YDWA.js} +31 -32
  16. package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-H5HZCAFD.js} +49 -48
  17. package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-55YDJDNM.js} +922 -550
  18. package/chunks/{agent-HOLHB3RT.js → agent-H6VE5W3L.js} +26 -27
  19. package/chunks/{agent-headless-SXL6H56A.js → agent-headless-T4XJOCRU.js} +26 -27
  20. package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-HBRXJSP4.js} +78 -16
  21. package/chunks/{artifact-tool-U7IRTLIV.js → artifact-tool-MIZLXBLF.js} +2 -2
  22. package/chunks/{askUserQuestion-2DLUUZZG.js → askUserQuestion-XMJVPNWM.js} +2 -2
  23. package/chunks/{bridge-BCJQ7BBB.js → bridge-FTB6ZP3R.js} +31 -34
  24. package/chunks/{ca-UJ6HC4H2.js → ca-CODEN7TD.js} +9 -1
  25. package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
  26. package/chunks/channel-worker-manager-CUDPU4CN.js +418 -0
  27. package/chunks/channel-worker-supervisor-4XTO2ZD3.js +20 -0
  28. package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
  29. package/chunks/{chunk-VA4KQY6V.js → chunk-2JNR4VP2.js} +3 -3
  30. package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
  31. package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
  32. package/chunks/{chunk-CUMMSHH6.js → chunk-3DWIFU7L.js} +1 -1
  33. package/chunks/chunk-3MX7D6QN.js +516 -0
  34. package/chunks/{chunk-SJHDYNHF.js → chunk-4BJVSIS3.js} +3 -3
  35. package/chunks/{chunk-TO6QE22P.js → chunk-5CNYZ7TN.js} +26 -22
  36. package/chunks/{chunk-N3EMS75V.js → chunk-5DEJ4T6C.js} +1333 -1232
  37. package/chunks/chunk-5HBA2Z7V.js +28 -0
  38. package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
  39. package/chunks/{chunk-SCGXUJBT.js → chunk-6LI3L22E.js} +3 -3
  40. package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
  41. package/chunks/{chunk-YAUFFXDS.js → chunk-7GM2RWCR.js} +12 -11
  42. package/chunks/{chunk-OQ4DRIOA.js → chunk-7HWE2W74.js} +2 -2
  43. package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
  44. package/chunks/{chunk-MC23XKFE.js → chunk-A2HWMJVO.js} +37 -3
  45. package/chunks/{chunk-3G7CIHVV.js → chunk-ABNYOMDG.js} +4 -4
  46. package/chunks/{chunk-3AHXV67U.js → chunk-AGZLXLBY.js} +1 -1
  47. package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
  48. package/chunks/{chunk-Q4YQW46J.js → chunk-AMRZVQUY.js} +43 -40
  49. package/chunks/{chunk-W3JHSWRP.js → chunk-AN6C2U46.js} +4 -4
  50. package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
  51. package/chunks/{chunk-5SFOMFG4.js → chunk-AVEOWVOM.js} +36 -2
  52. package/chunks/{chunk-34MW4KTI.js → chunk-BA5JGE5F.js} +2 -2
  53. package/chunks/{chunk-5HOMWMCL.js → chunk-BSJAQUFD.js} +5492 -1336
  54. package/chunks/{chunk-L6P4KPHR.js → chunk-BWJKL5DB.js} +58 -38
  55. package/chunks/{chunk-PVZM22CK.js → chunk-C32JFRGV.js} +5 -5
  56. package/chunks/{chunk-AKIVHSJR.js → chunk-CZIHPO7L.js} +163 -782
  57. package/chunks/chunk-DL7RCO6V.js +493 -0
  58. package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
  59. package/chunks/{chunk-5VXNZWGF.js → chunk-ENUQSKEY.js} +1 -1
  60. package/chunks/{chunk-PDZ7MBDG.js → chunk-EWILX3BM.js} +27 -6
  61. package/chunks/{chunk-BMGVRZN4.js → chunk-EZWX232B.js} +1 -1
  62. package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
  63. package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
  64. package/chunks/chunk-FEOZBUMT.js +77 -0
  65. package/chunks/{chunk-5U27BZ72.js → chunk-FKEGVMPX.js} +269 -83
  66. package/chunks/chunk-FNX3LGAK.js +34 -0
  67. package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
  68. package/chunks/{chunk-PODM4SZ4.js → chunk-G3BIBPI7.js} +5 -5
  69. package/chunks/{chunk-A3XKDTSH.js → chunk-GA65O2TB.js} +4 -4
  70. package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
  71. package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-GXGIM7QP.js} +67 -35
  72. package/chunks/{chunk-6PESIEKJ.js → chunk-GXUWGPYX.js} +68 -6
  73. package/chunks/chunk-GYTKQYDB.js +23 -0
  74. package/chunks/{chunk-GZRTYZ2R.js → chunk-H3XMJV7T.js} +218 -1
  75. package/chunks/{chunk-WQUQVGTF.js → chunk-HGRXW4HQ.js} +467 -106
  76. package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
  77. package/chunks/{chunk-ECNYL4AA.js → chunk-HUEWOHKV.js} +1 -1
  78. package/chunks/chunk-IDS7MSUP.js +74 -0
  79. package/chunks/{chunk-KHUQZZJ6.js → chunk-IHDRJLLR.js} +382 -36
  80. package/chunks/{chunk-CLFKOZEK.js → chunk-J4SEAF4X.js} +114 -4
  81. package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
  82. package/chunks/{chunk-P67PFTUT.js → chunk-KEYEYCHZ.js} +4 -4
  83. package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
  84. package/chunks/{chunk-7PU4FYLG.js → chunk-KOXFAG6P.js} +4 -18
  85. package/chunks/{chunk-EGYZ275M.js → chunk-KWLVWNF5.js} +55 -7
  86. package/chunks/{chunk-XLA62MYB.js → chunk-KXECVZPD.js} +2 -2
  87. package/chunks/{chunk-IAVB3HM3.js → chunk-L4Y55KIS.js} +33 -1
  88. package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
  89. package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
  90. package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
  91. package/chunks/chunk-LXXMOYPL.js +22 -0
  92. package/chunks/{chunk-Q6I5QHMH.js → chunk-MFNKBXYH.js} +1 -1
  93. package/chunks/chunk-MR3PXB6E.js +48 -0
  94. package/chunks/{chunk-JZETEN3Z.js → chunk-N45S36AH.js} +3 -3
  95. package/chunks/{chunk-GWLSNBG4.js → chunk-NA3IG6XG.js} +748 -27
  96. package/chunks/{chunk-D5SKC4YG.js → chunk-O3M25JXE.js} +213 -29
  97. package/chunks/{chunk-EAXLGSFP.js → chunk-O6XGHDS5.js} +11 -11
  98. package/chunks/{chunk-WL4L7EZH.js → chunk-OA4JVLSA.js} +27 -1
  99. package/chunks/{chunk-X4NKFGFJ.js → chunk-OJAMDVF5.js} +0 -15
  100. package/chunks/{chunk-BZIFY5TF.js → chunk-OKAIGAYW.js} +3 -3
  101. package/chunks/{chunk-CNEIYWSA.js → chunk-OVIV236K.js} +5 -5
  102. package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
  103. package/chunks/{chunk-E2IY465S.js → chunk-PWNOAWXB.js} +59 -12
  104. package/chunks/{chunk-B4G2WOFA.js → chunk-Q5MKHNIR.js} +28 -5
  105. package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
  106. package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
  107. package/chunks/{chunk-HKMAENAO.js → chunk-QDTGDM2T.js} +14 -9
  108. package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
  109. package/chunks/{chunk-W2UIXQDL.js → chunk-RTV5TUYB.js} +12 -4
  110. package/chunks/chunk-RW7DUKFO.js +91 -0
  111. package/chunks/{chunk-NVYTCB5Z.js → chunk-SA6QVLWI.js} +17325 -16259
  112. package/chunks/chunk-SJSI7PXU.js +59 -0
  113. package/chunks/{chunk-HVY356M2.js → chunk-SMGBWLNU.js} +3 -3
  114. package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
  115. package/chunks/{chunk-CC2ITGCF.js → chunk-STZQCNN3.js} +49 -6
  116. package/chunks/{chunk-HPDUL5MF.js → chunk-T2ZDAER2.js} +1 -1
  117. package/chunks/{chunk-XUOOWUZS.js → chunk-T3TQ3ACP.js} +1 -1
  118. package/chunks/{chunk-4C5BQ2D2.js → chunk-TIKDHS6V.js} +100 -17
  119. package/chunks/chunk-TV6K2FB4.js +224 -0
  120. package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
  121. package/chunks/{chunk-D2GFWEXB.js → chunk-UCUUH2JV.js} +6 -6
  122. package/chunks/{chunk-BAPGSC7U.js → chunk-UZP7K33Y.js} +23 -9
  123. package/chunks/{chunk-77XJ3SWN.js → chunk-VDAR6UO2.js} +8 -6
  124. package/chunks/{chunk-XYQSMABS.js → chunk-VKLVGA2D.js} +4 -4
  125. package/chunks/{chunk-JSG7ZSBC.js → chunk-VRR65QYW.js} +251 -3
  126. package/chunks/{chunk-U2NNEY4R.js → chunk-VT5AWJN4.js} +1 -1
  127. package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
  128. package/chunks/{chunk-X6TJ3YZV.js → chunk-WKEO3GLZ.js} +160 -60
  129. package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
  130. package/chunks/{chunk-VWPVHAMO.js → chunk-XIWQ5QST.js} +8 -1
  131. package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
  132. package/chunks/{chunk-3VAGG5T5.js → chunk-YYBZUIPL.js} +1015 -100
  133. package/chunks/{chunk-CCDMCZPP.js → chunk-YZ3SBNP7.js} +1 -1
  134. package/chunks/{chunk-ATAKVRIF.js → chunk-Z3XA2TNG.js} +7 -7
  135. package/chunks/{chunk-EMDMPBJ4.js → chunk-Z7SVC7PJ.js} +10 -3
  136. package/chunks/{chunk-AURZZYMD.js → chunk-ZIVSSTUG.js} +4 -4
  137. package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
  138. package/chunks/{chunk-34Z3U5RQ.js → chunk-ZQIYGQCG.js} +765 -168
  139. package/chunks/{computer-use-HM37RX6A.js → computer-use-NADT7ULB.js} +26 -27
  140. package/chunks/{config-utils-NV2SVGPB.js → config-utils-IQQT3GCI.js} +3 -2
  141. package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-U7NEJYJ7.js} +28 -29
  142. package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
  143. package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-SUN33INC.js} +26 -27
  144. package/chunks/{cron-create-AMBKGZX6.js → cron-create-GMVKSXZT.js} +4 -4
  145. package/chunks/{cron-delete-LRU4OJYG.js → cron-delete-VDZKUAVK.js} +4 -4
  146. package/chunks/{cron-list-WVP2JXER.js → cron-list-UG7C7RAR.js} +4 -4
  147. package/chunks/{daemon-ARHTSTXP.js → daemon-SJXEKP3H.js} +773 -126
  148. package/chunks/daemon-status-provider-WIIYLGZJ.js +74 -0
  149. package/chunks/{de-EBJN3OVN.js → de-NOXPCSYN.js} +9 -1
  150. package/chunks/{dist-XKU3ABM5.js → dist-4WCQEZIN.js} +4 -51
  151. package/chunks/{dist-QYCAEZIT.js → dist-DOPL5LSQ.js} +5 -1
  152. package/chunks/{dist-WKPOYU7O.js → dist-GXJVCOS7.js} +1 -1
  153. package/chunks/{dist-R7LN5AZE.js → dist-PX2ERZ6I.js} +2 -2
  154. package/chunks/{dist-PNVLTKTL.js → dist-V2YVLYOW.js} +215 -33
  155. package/chunks/{dist-VHV4EVHG.js → dist-VYWUKURL.js} +1 -1
  156. package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-6FRM6UMU.js} +27 -28
  157. package/chunks/{edit-VNI4NJ73.js → edit-7GOIQTCZ.js} +27 -28
  158. package/chunks/{en-5A6LA7RK.js → en-JFVULHTB.js} +11 -1
  159. package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-476E6WIK.js} +26 -27
  160. package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-IRJM6W3C.js} +42 -28
  161. package/chunks/{environment-5HSSRMJ7.js → environment-ROMULS2X.js} +30 -30
  162. package/chunks/{errors-HMFCJJ7P.js → errors-OUIWPUDY.js} +28 -29
  163. package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-PPSFK753.js} +26 -27
  164. package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-YKQMD4D7.js} +26 -27
  165. package/chunks/{fast-path-FRDMDVHG.js → fast-path-CNK2HHKH.js} +3 -3
  166. package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
  167. package/chunks/{fr-YXRABLYZ.js → fr-HVFNU42H.js} +9 -1
  168. package/chunks/{gemini-QYSEGHAX.js → gemini-WQNFT6TR.js} +216 -90
  169. package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-4QJH2JDP.js} +4 -4
  170. package/chunks/{glob-BRCSGFOT.js → glob-36TVLBWW.js} +28 -28
  171. package/chunks/{grep-EE2DUOSY.js → grep-QTYLNO2M.js} +26 -27
  172. package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-36FQFODK.js} +30 -31
  173. package/chunks/{i18n-BASPENNQ.js → i18n-JUGYPVSP.js} +27 -28
  174. package/chunks/initializer-OBBJUS25.js +72 -0
  175. package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-MCKTPX64.js} +27 -28
  176. package/chunks/{ja-7VQOANVG.js → ja-PY5AF544.js} +10 -2
  177. package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
  178. package/chunks/list-VW5QY4VJ.js +75 -0
  179. package/chunks/loadedSettingsAdapter-IELOOXG6.js +69 -0
  180. package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-QXWZSCYM.js} +5 -5
  181. package/chunks/{ls-ZB2BDP6T.js → ls-2OUTG3IZ.js} +4 -4
  182. package/chunks/{lsp-V5DN4YUJ.js → lsp-4VMNXZW6.js} +2 -2
  183. package/chunks/mcp-Q3EC37ZS.js +69 -0
  184. package/chunks/{monitor-X5Z3H4FY.js → monitor-DCZ27AFR.js} +26 -27
  185. package/chunks/nonInteractiveCli-KXD7PFO4.js +128 -0
  186. package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-YU4XF5LI.js} +27 -28
  187. package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KL5WER2D.js} +13 -13
  188. package/chunks/{pidfile-D4I4FTVA.js → pidfile-WBOD7EJV.js} +27 -28
  189. package/chunks/processUtils-AOV4R34M.js +29 -0
  190. package/chunks/{pt-2C6YCSHL.js → pt-A3PRQXMU.js} +9 -1
  191. package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-YIGBHYE3.js} +28 -29
  192. package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
  193. package/chunks/{read-file-7SZSIZOL.js → read-file-WVL4Y76X.js} +9 -9
  194. package/chunks/{read-mcp-resource-SM5DA4RG.js → read-mcp-resource-JUFHCKSC.js} +2 -2
  195. package/chunks/{record-artifact-4XKZX3UW.js → record-artifact-DWSMBXYY.js} +2 -2
  196. package/chunks/{ripGrep-YNPFVCZP.js → ripGrep-6GSWJERP.js} +26 -27
  197. package/chunks/{ru-6BBHVZZV.js → ru-IBCWUTOC.js} +9 -1
  198. package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-QYUQMEDT.js} +1233 -371
  199. package/chunks/{runtime-57WWRVHN.js → runtime-K2YZCNB3.js} +42 -38
  200. package/chunks/{scheduler-YBLGWSIL.js → scheduler-EQCSN7QV.js} +26 -27
  201. package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
  202. package/chunks/{serve-R63NK3CV.js → serve-DX5UGZD4.js} +36 -35
  203. package/chunks/{server-Z22GCAXP.js → server-T6HJH3DR.js} +5869 -1398
  204. package/chunks/{session-HKAAI7BN.js → session-SNU6ACY6.js} +299 -100
  205. package/chunks/{settings-3EYN66GK.js → settings-AKHZZNEL.js} +34 -33
  206. package/chunks/{shell-6YXINTWJ.js → shell-EY74IEZK.js} +28 -27
  207. package/chunks/{skill-OO57P4X6.js → skill-DPU62O3H.js} +11 -11
  208. package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-RQZRWJ2V.js} +28 -30
  209. package/chunks/{src-G5UPLZSZ.js → src-7FITDSVC.js} +164 -52
  210. package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-XO3RK6DO.js} +28 -29
  211. package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-DVWZRHYQ.js} +728 -382
  212. package/chunks/{syntheticOutput-34H7LGA7.js → syntheticOutput-LELY6HAI.js} +3 -3
  213. package/chunks/{task-create-FRGOEIKY.js → task-create-QY3BIMNM.js} +8 -7
  214. package/chunks/{task-list-OW766BXZ.js → task-list-D2U47WBJ.js} +6 -5
  215. package/chunks/{task-stop-SIR5SNBN.js → task-stop-N6E5IYLH.js} +2 -2
  216. package/chunks/{task-update-YRA532MT.js → task-update-HJCQILLB.js} +8 -7
  217. package/chunks/{team-create-PECAAPXK.js → team-create-FOSRT62K.js} +26 -27
  218. package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
  219. package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-6VUDV27J.js} +26 -27
  220. package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-6UT6IO5T.js} +27 -28
  221. package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
  222. package/chunks/{tool-search-THVIWAPB.js → tool-search-ASSFMMN5.js} +10 -10
  223. package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-YYWUO23H.js} +32 -35
  224. package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
  225. package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-4BWV2IBK.js} +29 -29
  226. package/chunks/types-ML3TRJQ5.js +16 -0
  227. package/chunks/update-relaunch-74DLGH73.js +87 -0
  228. package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-CRFCGFO5.js} +31 -30
  229. package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-BTTEPBGQ.js} +76 -73
  230. package/chunks/{version-3UEA6ZIR.js → version-Y5JE5Q63.js} +1 -1
  231. package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-CFCWTCAP.js} +5 -6
  232. package/chunks/{workflow-QCCCMYP3.js → workflow-6WC7VPQN.js} +27 -28
  233. package/chunks/workspace-providers-status-RVG2C5ZS.js +72 -0
  234. package/chunks/workspace-registration-store-SLEU3D3X.js +27 -0
  235. package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-QMWGVOTF.js} +32 -35
  236. package/chunks/workspace-service-G572JSEU.js +84 -0
  237. package/chunks/workspace-skills-status-VSSMSMNK.js +71 -0
  238. package/chunks/{write-file-I3MUDRIE.js → write-file-5XVDRORP.js} +27 -28
  239. package/chunks/{zh-RQE7I22T.js → zh-PAUNIMHQ.js} +12 -2
  240. package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-GNEUIUFF.js} +12 -2
  241. package/cli-entry.js +92 -8
  242. package/cli.js +11 -11
  243. package/locales/ca.js +16 -0
  244. package/locales/de.js +16 -0
  245. package/locales/en.js +19 -0
  246. package/locales/fr.js +16 -0
  247. package/locales/ja.js +17 -1
  248. package/locales/pt.js +16 -0
  249. package/locales/ru.js +16 -0
  250. package/locales/zh-TW.js +20 -1
  251. package/locales/zh.js +20 -1
  252. package/package.json +3 -3
  253. package/web-shell/assets/{arc-C15hqnJe.js → arc-vx1tRwnX.js} +1 -1
  254. package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-DBi6iUA1.js} +1 -1
  255. package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-Ga9JJ4Ak.js} +1 -1
  256. package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-D8Vi5FYw.js} +1 -1
  257. package/web-shell/assets/channel-B29zQDTL.js +1 -0
  258. package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-CSV6yQpU.js} +1 -1
  259. package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-toYlppdI.js} +1 -1
  260. package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-DbjzuyAr.js} +1 -1
  261. package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-IkkSjSkk.js} +1 -1
  262. package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-D5wUL6Zm.js} +1 -1
  263. package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-C3o2DXG0.js} +1 -1
  264. package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CutIi14T.js} +1 -1
  265. package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-DZ0NRHH-.js} +1 -1
  266. package/web-shell/assets/classDiagram-4FO5ZUOK-BNGI2SvC.js +1 -0
  267. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BNGI2SvC.js +1 -0
  268. package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-B3Dl88UJ.js} +1 -1
  269. package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-DfTxfF6-.js} +1 -1
  270. package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-CJyH98yO.js} +1 -1
  271. package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-EbOiJNmW.js} +1 -1
  272. package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-AYNqpqqA.js} +1 -1
  273. package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BY5VPa4H.js} +1 -1
  274. package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-BhMYAKlk.js} +1 -1
  275. package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-Bp8S_F9l.js} +1 -1
  276. package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-az3TE9PU.js} +1 -1
  277. package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-CfkAEpCe.js} +3 -3
  278. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-D1QmjMCy.js} +1 -1
  279. package/web-shell/assets/index-C8sDwQUv.js +1130 -0
  280. package/web-shell/assets/index-CaBoc5bb.js +3 -0
  281. package/web-shell/assets/index-Dpg5Wymg.css +5 -0
  282. package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-D3ompLrG.js} +1 -1
  283. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-D3MRWp9I.js} +1 -1
  284. package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-DVkKCa44.js} +1 -1
  285. package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-BLif81wF.js} +1 -1
  286. package/web-shell/assets/{linear-C8wKCbIC.js → linear-BDU96EGS.js} +1 -1
  287. package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-B-CwC26B.js} +5 -5
  288. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-CS1WOJ4G.js} +1 -1
  289. package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-BzgtNXVP.js} +1 -1
  290. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-BRfGC8MA.js} +1 -1
  291. package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-CPBZkC7g.js} +1 -1
  292. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-nqNvinIk.js} +1 -1
  293. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-CM_Wdjh3.js} +1 -1
  294. package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-L0y-48VE.js} +1 -1
  295. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BX1DdF8s.js +1 -0
  296. package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-B_n5rb3A.js} +1 -1
  297. package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-C9NmLV5e.js} +1 -1
  298. package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-CrefK9gt.js} +1 -1
  299. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BUccf-bC.js} +1 -1
  300. package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-DM6ef92l.js} +1 -1
  301. package/web-shell/index.html +2 -2
  302. package/chunks/chunk-524RQP4Q.js +0 -305
  303. package/chunks/chunk-CARU2RR2.js +0 -24
  304. package/chunks/chunk-CU3L64TP.js +0 -93
  305. package/chunks/chunk-OCPBI7J5.js +0 -18
  306. package/chunks/chunk-TEGEBB2I.js +0 -122
  307. package/chunks/chunk-VTU57BWZ.js +0 -30
  308. package/chunks/daemon-status-provider-B2UTZUJ2.js +0 -76
  309. package/chunks/initializer-UTQ7FB7G.js +0 -71
  310. package/chunks/list-DEICDL65.js +0 -74
  311. package/chunks/loadedSettingsAdapter-NOWEGDYJ.js +0 -68
  312. package/chunks/mcp-L5JXEEIA.js +0 -68
  313. package/chunks/nonInteractiveCli-LS2K4X6A.js +0 -124
  314. package/chunks/types-JNKGKUJT.js +0 -12
  315. package/chunks/workspace-providers-status-4KMGETOJ.js +0 -71
  316. package/chunks/workspace-service-RVLBMSMZ.js +0 -80
  317. package/chunks/workspace-skills-status-DS4ZVFTO.js +0 -70
  318. package/web-shell/assets/channel-CLiQD50f.js +0 -1
  319. package/web-shell/assets/classDiagram-4FO5ZUOK-D3sYqow5.js +0 -1
  320. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-D3sYqow5.js +0 -1
  321. package/web-shell/assets/index-D5IWFVk1.css +0 -5
  322. package/web-shell/assets/index-KFJRDhX7.js +0 -783
  323. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BhQMwgpl.js +0 -1
@@ -12,32 +12,6 @@ import {
12
12
  __name
13
13
  } from "./chunk-J2S4EL5Y.js";
14
14
 
15
- // packages/channels/base/dist/paths.js
16
- init_esbuild_shims();
17
- import * as path from "node:path";
18
- import * as os from "node:os";
19
- function resolvePath(dir) {
20
- let resolved = dir;
21
- if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
22
- const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
23
- resolved = path.join(os.homedir(), ...relativeSegments);
24
- }
25
- if (!path.isAbsolute(resolved)) {
26
- resolved = path.resolve(resolved);
27
- }
28
- return resolved;
29
- }
30
- __name(resolvePath, "resolvePath");
31
- function getGlobalQwenDir() {
32
- const envDir = process.env["QWEN_HOME"];
33
- if (envDir) {
34
- return resolvePath(envDir);
35
- }
36
- const homeDir = os.homedir();
37
- return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
38
- }
39
- __name(getGlobalQwenDir, "getGlobalQwenDir");
40
-
41
15
  // packages/channels/base/dist/sanitize.js
42
16
  init_esbuild_shims();
43
17
  var PROMPT_UNSAFE_INVISIBLES = new RegExp("[\\u0080-\\u009f\\p{Cf}\\u2028\\u2029]|\\p{Variation_Selector}", "gu");
@@ -74,6 +48,32 @@ __name(sanitizeLogText, "sanitizeLogText");
74
48
  // packages/channels/base/dist/index.js
75
49
  init_esbuild_shims();
76
50
 
51
+ // packages/channels/base/dist/paths.js
52
+ init_esbuild_shims();
53
+ import * as path from "node:path";
54
+ import * as os from "node:os";
55
+ function resolvePath(dir) {
56
+ let resolved = dir;
57
+ if (resolved === "~" || resolved.startsWith("~/") || resolved.startsWith("~\\")) {
58
+ const relativeSegments = resolved === "~" ? [] : resolved.slice(2).split(/[/\\]+/).filter(Boolean);
59
+ resolved = path.join(os.homedir(), ...relativeSegments);
60
+ }
61
+ if (!path.isAbsolute(resolved)) {
62
+ resolved = path.resolve(resolved);
63
+ }
64
+ return resolved;
65
+ }
66
+ __name(resolvePath, "resolvePath");
67
+ function getGlobalQwenDir() {
68
+ const envDir = process.env["QWEN_HOME"];
69
+ if (envDir) {
70
+ return resolvePath(envDir);
71
+ }
72
+ const homeDir = os.homedir();
73
+ return homeDir ? path.join(homeDir, ".qwen") : path.join(os.tmpdir(), ".qwen");
74
+ }
75
+ __name(getGlobalQwenDir, "getGlobalQwenDir");
76
+
77
77
  // packages/channels/base/dist/AcpBridge.js
78
78
  init_esbuild_shims();
79
79
  import { spawn } from "node:child_process";
@@ -361,15 +361,23 @@ var AcpBridge = class extends EventEmitter {
361
361
  async prompt(sessionId, text, options) {
362
362
  const conn = this.ensureConnection();
363
363
  const chunks = [];
364
+ let slashCommandOutput = "";
364
365
  const onChunk = /* @__PURE__ */ __name((sid, chunk) => {
365
366
  if (sid === sessionId)
366
367
  chunks.push(chunk);
367
368
  }, "onChunk");
368
- const clearChunks = /* @__PURE__ */ __name((sid) => {
369
+ const onSlashCommandOutput = /* @__PURE__ */ __name((sid, chunk) => {
369
370
  if (sid === sessionId)
371
+ slashCommandOutput = chunk;
372
+ }, "onSlashCommandOutput");
373
+ const clearChunks = /* @__PURE__ */ __name((sid) => {
374
+ if (sid === sessionId) {
370
375
  chunks.length = 0;
376
+ slashCommandOutput = "";
377
+ }
371
378
  }, "clearChunks");
372
379
  this.on("textChunk", onChunk);
380
+ this.on("slashCommandOutput", onSlashCommandOutput);
373
381
  this.on("responseBoundary", clearChunks);
374
382
  const prompt = [];
375
383
  if (options?.imageBase64 && options.imageMimeType) {
@@ -387,9 +395,10 @@ var AcpBridge = class extends EventEmitter {
387
395
  });
388
396
  } finally {
389
397
  this.off("textChunk", onChunk);
398
+ this.off("slashCommandOutput", onSlashCommandOutput);
390
399
  this.off("responseBoundary", clearChunks);
391
400
  }
392
- return chunks.join("");
401
+ return chunks.join("") || slashCommandOutput;
393
402
  }
394
403
  async cancelSession(sessionId) {
395
404
  const conn = this.ensureConnection();
@@ -432,9 +441,13 @@ var AcpBridge = class extends EventEmitter {
432
441
  const type = update["sessionUpdate"];
433
442
  switch (type) {
434
443
  case "agent_message_chunk": {
444
+ const meta = update["_meta"];
445
+ if (typeof meta?.["parentToolCallId"] === "string") {
446
+ break;
447
+ }
435
448
  const content = update["content"];
436
449
  if (content?.type === "text" && content.text) {
437
- this.emit("textChunk", sessionId, content.text);
450
+ this.emit(meta?.["source"] === "slash_command" ? "slashCommandOutput" : "textChunk", sessionId, content.text);
438
451
  }
439
452
  break;
440
453
  }
@@ -707,6 +720,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
707
720
  }
708
721
  options;
709
722
  sessions = /* @__PURE__ */ new Map();
723
+ sessionBindingTokens = /* @__PURE__ */ new Map();
710
724
  eventControllers = /* @__PURE__ */ new Map();
711
725
  requestToSession = /* @__PURE__ */ new Map();
712
726
  respondedRequestToSession = /* @__PURE__ */ new Map();
@@ -715,6 +729,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
715
729
  availableCommandsBySession = /* @__PURE__ */ new Map();
716
730
  turnBarriers = /* @__PURE__ */ new Map();
717
731
  connected = false;
732
+ lifecycleGeneration = 0;
718
733
  latestAvailableCommandsSessionId;
719
734
  lastError;
720
735
  constructor(options) {
@@ -750,17 +765,22 @@ var DaemonChannelBridge = class extends EventEmitter2 {
750
765
  async start() {
751
766
  this.connected = true;
752
767
  }
753
- async newSession(cwd, options) {
768
+ async newSession(cwd, options, bindingToken) {
769
+ const lifecycleGeneration = this.lifecycleGeneration;
754
770
  const session = await this.options.sessionFactory({
755
771
  workspaceCwd: cwd || this.options.cwd,
756
772
  modelServiceId: this.options.modelServiceId,
757
773
  sessionScope: this.options.sessionScope ?? "thread",
758
774
  ...options?.approvalMode ? { approvalMode: options.approvalMode } : {}
759
775
  });
760
- this.attachSession(session);
776
+ if (lifecycleGeneration !== this.lifecycleGeneration) {
777
+ await this.rejectStaleSession(session);
778
+ }
779
+ this.attachSession(session, bindingToken);
761
780
  return session.sessionId;
762
781
  }
763
- async loadSession(sessionId, cwd, options) {
782
+ async loadSession(sessionId, cwd, options, bindingToken) {
783
+ const lifecycleGeneration = this.lifecycleGeneration;
764
784
  const session = await this.options.sessionFactory({
765
785
  workspaceCwd: cwd || this.options.cwd,
766
786
  modelServiceId: this.options.modelServiceId,
@@ -768,10 +788,16 @@ var DaemonChannelBridge = class extends EventEmitter2 {
768
788
  sessionScope: this.options.sessionScope ?? "thread",
769
789
  ...options?.approvalMode ? { approvalMode: options.approvalMode } : {}
770
790
  });
791
+ if (lifecycleGeneration !== this.lifecycleGeneration) {
792
+ await this.rejectStaleSession(session);
793
+ }
771
794
  if (session.sessionId !== sessionId) {
795
+ void this.releaseSessionClient(session).catch((error) => {
796
+ this.lastError = error;
797
+ });
772
798
  throw new Error(`Daemon returned session ${session.sessionId} while loading ${sessionId}`);
773
799
  }
774
- this.attachSession(session);
800
+ this.attachSession(session, bindingToken);
775
801
  return session.sessionId;
776
802
  }
777
803
  async prompt(sessionId, text, options) {
@@ -788,14 +814,21 @@ var DaemonChannelBridge = class extends EventEmitter2 {
788
814
  }
789
815
  controllers.add(controller);
790
816
  const chunks = [];
817
+ let slashCommandOutput = "";
791
818
  const onChunk = /* @__PURE__ */ __name((sid, chunk) => {
792
819
  if (sid === sessionId) {
793
820
  chunks.push(chunk);
794
821
  }
795
822
  }, "onChunk");
823
+ const onSlashCommandOutput = /* @__PURE__ */ __name((sid, chunk) => {
824
+ if (sid === sessionId) {
825
+ slashCommandOutput = chunk;
826
+ }
827
+ }, "onSlashCommandOutput");
796
828
  const clearChunks = /* @__PURE__ */ __name((sid) => {
797
829
  if (sid === sessionId) {
798
830
  chunks.length = 0;
831
+ slashCommandOutput = "";
799
832
  }
800
833
  }, "clearChunks");
801
834
  const onSessionDied = /* @__PURE__ */ __name((info) => {
@@ -804,6 +837,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
804
837
  }
805
838
  }, "onSessionDied");
806
839
  this.on("textChunk", onChunk);
840
+ this.on("slashCommandOutput", onSlashCommandOutput);
807
841
  this.on("responseBoundary", clearChunks);
808
842
  this.on("sessionDied", onSessionDied);
809
843
  const turnBarrier = this.createTurnBarrier(sessionId);
@@ -822,7 +856,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
822
856
  turnBarrier,
823
857
  new Promise((resolve2) => setTimeout(resolve2, 0))
824
858
  ]);
825
- const textResult = chunks.join("");
859
+ const textResult = chunks.join("") || slashCommandOutput;
826
860
  this.emit("promptComplete", {
827
861
  sessionId,
828
862
  text: textResult,
@@ -832,6 +866,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
832
866
  } finally {
833
867
  this.clearTurnBarrier(sessionId);
834
868
  this.off("textChunk", onChunk);
869
+ this.off("slashCommandOutput", onSlashCommandOutput);
835
870
  this.off("responseBoundary", clearChunks);
836
871
  this.off("sessionDied", onSessionDied);
837
872
  this.activePrompts.delete(sessionId);
@@ -855,6 +890,25 @@ var DaemonChannelBridge = class extends EventEmitter2 {
855
890
  this.activePrompts.delete(sessionId);
856
891
  await session.cancel();
857
892
  }
893
+ async discardSession(sessionId, expectedBindingToken) {
894
+ if (expectedBindingToken !== void 0 && this.sessionBindingTokens.get(sessionId) !== expectedBindingToken) {
895
+ return;
896
+ }
897
+ const session = this.removeSessionBinding(sessionId);
898
+ if (!session)
899
+ return;
900
+ await this.releaseSessionClient(session);
901
+ }
902
+ async releaseSessionClient(session) {
903
+ if (session.detach) {
904
+ try {
905
+ await session.detach();
906
+ return;
907
+ } catch {
908
+ }
909
+ }
910
+ await session.cancel();
911
+ }
858
912
  async setSessionModel(sessionId, modelId) {
859
913
  return await this.ensureSession(sessionId).setModel(modelId);
860
914
  }
@@ -885,6 +939,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
885
939
  }
886
940
  }
887
941
  stop() {
942
+ this.lifecycleGeneration++;
888
943
  for (const sessionId of Array.from(this.sessions.keys())) {
889
944
  const session = this.sessions.get(sessionId);
890
945
  if (session) {
@@ -892,7 +947,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
892
947
  this.lastError = error;
893
948
  });
894
949
  }
895
- this.dropSession(sessionId, "bridge_stopped");
950
+ this.dropSession(sessionId, "bridge_stopped", false);
896
951
  }
897
952
  this.latestAvailableCommandsSessionId = void 0;
898
953
  this.connected = false;
@@ -900,15 +955,29 @@ var DaemonChannelBridge = class extends EventEmitter2 {
900
955
  get isConnected() {
901
956
  return this.connected;
902
957
  }
903
- attachSession(session) {
904
- if (this.sessions.has(session.sessionId)) {
905
- this.dropSession(session.sessionId, "session_replaced");
958
+ attachSession(session, bindingToken) {
959
+ const replacedSession = this.removeSessionBinding(session.sessionId);
960
+ if (replacedSession) {
961
+ void this.releaseSessionClient(replacedSession).catch((error) => {
962
+ this.lastError = error;
963
+ });
964
+ this.emit("sessionDied", {
965
+ sessionId: session.sessionId,
966
+ reason: "session_replaced"
967
+ });
906
968
  }
907
969
  this.sessions.set(session.sessionId, session);
970
+ this.sessionBindingTokens.set(session.sessionId, bindingToken);
908
971
  const controller = new AbortController();
909
972
  this.eventControllers.set(session.sessionId, controller);
910
973
  void this.pumpEvents(session, controller.signal);
911
974
  }
975
+ async rejectStaleSession(session) {
976
+ void this.releaseSessionClient(session).catch((error) => {
977
+ this.lastError = error;
978
+ });
979
+ throw new Error("Daemon channel bridge stopped during session creation");
980
+ }
912
981
  ensureSession(sessionId) {
913
982
  const session = this.sessions.get(sessionId);
914
983
  if (!session) {
@@ -944,6 +1013,9 @@ var DaemonChannelBridge = class extends EventEmitter2 {
944
1013
  handleEvent(session, event) {
945
1014
  switch (event.type) {
946
1015
  case "session_update":
1016
+ if (isRecord(event.data) && typeof event.data["sessionId"] === "string" && event.data["sessionId"] !== session.sessionId) {
1017
+ break;
1018
+ }
947
1019
  this.handleSessionUpdate(session.sessionId, event.data);
948
1020
  break;
949
1021
  case "permission_request":
@@ -987,9 +1059,13 @@ var DaemonChannelBridge = class extends EventEmitter2 {
987
1059
  const type = getString(update["sessionUpdate"]);
988
1060
  switch (type) {
989
1061
  case "agent_message_chunk": {
1062
+ const meta = isRecord(update["_meta"]) ? update["_meta"] : void 0;
1063
+ if (typeof meta?.["parentToolCallId"] === "string") {
1064
+ break;
1065
+ }
990
1066
  const text = getTextContent(update["content"]);
991
1067
  if (text) {
992
- this.emit("textChunk", sessionId, text);
1068
+ this.emit(meta?.["source"] === "slash_command" ? "slashCommandOutput" : "textChunk", sessionId, text);
993
1069
  }
994
1070
  break;
995
1071
  }
@@ -1004,6 +1080,10 @@ var DaemonChannelBridge = class extends EventEmitter2 {
1004
1080
  case "tool_call_update": {
1005
1081
  const toolCallId = getString(update["toolCallId"]);
1006
1082
  const kind = getString(update["kind"]);
1083
+ const meta = isRecord(update["_meta"]) ? update["_meta"] : void 0;
1084
+ if (!kind && toolCallId && getString(update["status"]) === "in_progress" && meta?.["shellProgress"] !== void 0) {
1085
+ break;
1086
+ }
1007
1087
  if (!toolCallId || !kind) {
1008
1088
  this.emitProtocolError(`Malformed daemon ${type} event`, update);
1009
1089
  break;
@@ -1123,14 +1203,26 @@ var DaemonChannelBridge = class extends EventEmitter2 {
1123
1203
  handleSessionDied(sessionId, data) {
1124
1204
  this.dropSession(sessionId, this.getStringField(data, "reason", "session_died"));
1125
1205
  }
1126
- dropSession(sessionId, reason) {
1127
- if (!this.sessions.has(sessionId)) {
1206
+ dropSession(sessionId, reason, releaseClient = true) {
1207
+ const session = this.removeSessionBinding(sessionId);
1208
+ if (!session)
1128
1209
  return;
1210
+ if (releaseClient) {
1211
+ void this.releaseSessionClient(session).catch((error) => {
1212
+ this.lastError = error;
1213
+ });
1129
1214
  }
1215
+ this.emit("sessionDied", { sessionId, reason });
1216
+ }
1217
+ removeSessionBinding(sessionId) {
1218
+ const session = this.sessions.get(sessionId);
1219
+ if (!session)
1220
+ return void 0;
1130
1221
  this.resolveTurnBarrier(sessionId);
1131
1222
  this.eventControllers.get(sessionId)?.abort();
1132
1223
  this.eventControllers.delete(sessionId);
1133
1224
  this.sessions.delete(sessionId);
1225
+ this.sessionBindingTokens.delete(sessionId);
1134
1226
  this.abortActivePrompts(sessionId);
1135
1227
  this.activePrompts.delete(sessionId);
1136
1228
  this.availableCommandsBySession.delete(sessionId);
@@ -1147,7 +1239,7 @@ var DaemonChannelBridge = class extends EventEmitter2 {
1147
1239
  this.respondedRequestToSession.delete(requestId);
1148
1240
  }
1149
1241
  }
1150
- this.emit("sessionDied", { sessionId, reason });
1242
+ return session;
1151
1243
  }
1152
1244
  getStringField(data, field, fallback) {
1153
1245
  return isRecord(data) && typeof data[field] === "string" ? data[field] : fallback;
@@ -1295,7 +1387,7 @@ var BlockStreamer = class {
1295
1387
 
1296
1388
  // packages/channels/base/dist/ChannelBase.js
1297
1389
  init_esbuild_shims();
1298
- import { basename, join as join4 } from "node:path";
1390
+ import { basename, join as join5 } from "node:path";
1299
1391
 
1300
1392
  // packages/channels/base/dist/GroupGate.js
1301
1393
  init_esbuild_shims();
@@ -1770,7 +1862,8 @@ __name(generateCode, "generateCode");
1770
1862
 
1771
1863
  // packages/channels/base/dist/SessionRouter.js
1772
1864
  init_esbuild_shims();
1773
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, unlinkSync } from "node:fs";
1865
+ import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, rmSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
1866
+ import { dirname as dirname2, join as join4 } from "node:path";
1774
1867
  import process2 from "node:process";
1775
1868
  var SessionRouter = class {
1776
1869
  static {
@@ -1784,17 +1877,22 @@ var SessionRouter = class {
1784
1877
  // session ID → cwd
1785
1878
  creatingSessions = /* @__PURE__ */ new Map();
1786
1879
  sessionLoadWindows = /* @__PURE__ */ new Set();
1880
+ liveSessionIds = /* @__PURE__ */ new Set();
1881
+ routeTokens = /* @__PURE__ */ new Map();
1882
+ lifecycleGeneration = 0;
1787
1883
  bridge;
1788
1884
  defaultCwd;
1789
1885
  defaultScope;
1790
1886
  channelScopes = /* @__PURE__ */ new Map();
1791
1887
  channelApprovalModes = /* @__PURE__ */ new Map();
1792
1888
  persistPath;
1793
- constructor(bridge, defaultCwd, scope = "user", persistPath) {
1889
+ recoveryMode;
1890
+ constructor(bridge, defaultCwd, scope = "user", persistPath, options = {}) {
1794
1891
  this.bridge = bridge;
1795
1892
  this.defaultCwd = defaultCwd;
1796
1893
  this.defaultScope = scope;
1797
1894
  this.persistPath = persistPath;
1895
+ this.recoveryMode = options.recoveryMode ?? "eager";
1798
1896
  }
1799
1897
  /** Replace the bridge instance (used after crash recovery restart). */
1800
1898
  setBridge(bridge) {
@@ -1829,58 +1927,166 @@ var SessionRouter = class {
1829
1927
  }
1830
1928
  async resolve(channelName, senderId, chatId, threadId, cwd, isGroup, options) {
1831
1929
  const key = this.routingKey(channelName, senderId, chatId, options?.routingThreadId ?? threadId);
1832
- let failedCreateWaits = 0;
1930
+ const input = {
1931
+ channelName,
1932
+ senderId,
1933
+ chatId,
1934
+ threadId,
1935
+ cwd: cwd || this.defaultCwd,
1936
+ isGroup
1937
+ };
1938
+ let failedWaits = 0;
1833
1939
  for (; ; ) {
1834
1940
  const existing = this.toSession.get(key);
1835
- if (existing) {
1941
+ if (existing && this.isLive(existing)) {
1836
1942
  this.promoteTargetToGroup(existing, isGroup);
1837
1943
  return existing;
1838
1944
  }
1839
1945
  const creating = this.creatingSessions.get(key);
1840
1946
  if (creating) {
1841
1947
  try {
1842
- const sessionId = await creating;
1948
+ const sessionId = await creating.promise;
1949
+ try {
1950
+ this.assertOperationResultCurrent(key, sessionId, creating);
1951
+ } catch (error) {
1952
+ this.scheduleDiscardInvalidatedSession(sessionId, creating);
1953
+ throw error;
1954
+ }
1843
1955
  this.promoteTargetToGroup(sessionId, isGroup);
1844
1956
  return sessionId;
1845
- } catch (err) {
1957
+ } catch (error) {
1958
+ if (creating.invalidationError) {
1959
+ throw creating.invalidationError;
1960
+ }
1846
1961
  if (this.creatingSessions.get(key) === creating) {
1847
1962
  this.creatingSessions.delete(key);
1848
1963
  }
1849
- failedCreateWaits++;
1850
- if (failedCreateWaits > 3) {
1851
- throw err;
1852
- }
1964
+ this.releaseRouteToken(key, creating);
1965
+ failedWaits++;
1966
+ if (failedWaits > 3)
1967
+ throw error;
1853
1968
  continue;
1854
1969
  }
1855
1970
  }
1856
- const created = Promise.resolve().then(async () => {
1857
- const sessionCwd = cwd || this.defaultCwd;
1858
- const loadWindow = this.beginSessionLoad();
1971
+ const operation = this.createSessionOperation(key, {
1972
+ channelName: input.channelName,
1973
+ senderId: input.senderId,
1974
+ chatId: input.chatId,
1975
+ threadId: input.threadId,
1976
+ isGroup: input.isGroup
1977
+ }, (currentOperation) => existing ? this.loadOrReplaceSession(key, existing, input, currentOperation) : this.createAndStoreSession(key, input, currentOperation));
1978
+ this.creatingSessions.set(key, operation);
1979
+ try {
1980
+ const sessionId = await operation.promise;
1859
1981
  try {
1860
- const sessionId = await this.createLiveSession(sessionCwd, loadWindow, key, this.sessionOptions(channelName));
1861
- this.toSession.set(key, sessionId);
1862
- this.toTarget.set(sessionId, {
1863
- channelName,
1864
- senderId,
1865
- chatId,
1866
- threadId,
1867
- isGroup
1868
- });
1869
- this.toCwd.set(sessionId, sessionCwd);
1870
- this.persist();
1871
- return sessionId;
1872
- } finally {
1873
- this.endSessionLoad(loadWindow);
1982
+ this.assertOperationResultCurrent(key, sessionId, operation);
1983
+ } catch (error) {
1984
+ this.scheduleDiscardInvalidatedSession(sessionId, operation);
1985
+ throw error;
1874
1986
  }
1875
- });
1876
- this.creatingSessions.set(key, created);
1877
- try {
1878
- return await created;
1987
+ this.promoteTargetToGroup(sessionId, isGroup);
1988
+ return sessionId;
1879
1989
  } finally {
1880
- if (this.creatingSessions.get(key) === created) {
1990
+ if (this.creatingSessions.get(key) === operation) {
1881
1991
  this.creatingSessions.delete(key);
1882
1992
  }
1993
+ this.releaseRouteToken(key, operation);
1994
+ }
1995
+ }
1996
+ }
1997
+ isLive(sessionId) {
1998
+ return this.recoveryMode === "eager" || this.liveSessionIds.has(sessionId);
1999
+ }
2000
+ async createAndStoreSession(key, input, operation) {
2001
+ const loadWindow = this.beginSessionLoad();
2002
+ try {
2003
+ const sessionId = await this.createLiveSession(input.cwd, loadWindow, key, this.sessionOptions(input.channelName), operation);
2004
+ try {
2005
+ this.assertOperationCurrent(operation);
2006
+ } catch (error) {
2007
+ this.scheduleDiscardInvalidatedSession(sessionId, operation);
2008
+ throw error;
2009
+ }
2010
+ this.toSession.set(key, sessionId);
2011
+ this.toTarget.set(sessionId, {
2012
+ channelName: input.channelName,
2013
+ senderId: input.senderId,
2014
+ chatId: input.chatId,
2015
+ threadId: input.threadId,
2016
+ isGroup: input.isGroup
2017
+ });
2018
+ this.toCwd.set(sessionId, input.cwd);
2019
+ this.liveSessionIds.add(sessionId);
2020
+ this.persist();
2021
+ return sessionId;
2022
+ } finally {
2023
+ this.endSessionLoad(loadWindow);
2024
+ }
2025
+ }
2026
+ async loadOrReplaceSession(key, savedSessionId, input, operation) {
2027
+ const savedCwd = this.toCwd.get(savedSessionId) ?? input.cwd;
2028
+ const loadWindow = this.beginSessionLoad();
2029
+ try {
2030
+ try {
2031
+ const loadedSessionId = await this.bridge.loadSession(savedSessionId, savedCwd, this.sessionOptions(input.channelName), operation);
2032
+ try {
2033
+ this.assertOperationCurrent(operation);
2034
+ if (this.toSession.get(key) !== savedSessionId) {
2035
+ this.invalidateOperation(operation);
2036
+ this.assertOperationCurrent(operation);
2037
+ }
2038
+ } catch (error) {
2039
+ this.scheduleDiscardInvalidatedSession(loadedSessionId, operation);
2040
+ throw error;
2041
+ }
2042
+ if (typeof loadedSessionId !== "string" || loadedSessionId.length === 0 || loadWindow.delete(loadedSessionId)) {
2043
+ throw new Error("Invalid or dead restored session ID");
2044
+ }
2045
+ if (loadedSessionId !== savedSessionId) {
2046
+ const target = this.toTarget.get(savedSessionId);
2047
+ this.deleteByKey(key);
2048
+ this.toSession.set(key, loadedSessionId);
2049
+ if (target)
2050
+ this.toTarget.set(loadedSessionId, target);
2051
+ this.toCwd.set(loadedSessionId, savedCwd);
2052
+ this.persist();
2053
+ }
2054
+ this.liveSessionIds.add(loadedSessionId);
2055
+ return loadedSessionId;
2056
+ } catch (loadError) {
2057
+ this.assertOperationCurrent(operation);
2058
+ try {
2059
+ const replacement = await this.createLiveSession(input.cwd, loadWindow, key, this.sessionOptions(input.channelName), operation);
2060
+ try {
2061
+ this.assertOperationCurrent(operation);
2062
+ } catch (error) {
2063
+ this.scheduleDiscardInvalidatedSession(replacement, operation);
2064
+ throw error;
2065
+ }
2066
+ this.deleteByKey(key);
2067
+ this.toSession.set(key, replacement);
2068
+ this.toTarget.set(replacement, {
2069
+ channelName: input.channelName,
2070
+ senderId: input.senderId,
2071
+ chatId: input.chatId,
2072
+ threadId: input.threadId,
2073
+ isGroup: input.isGroup
2074
+ });
2075
+ this.toCwd.set(replacement, input.cwd);
2076
+ this.liveSessionIds.add(replacement);
2077
+ this.persist();
2078
+ process2.stderr.write(`[SessionRouter] Replaced unavailable session ${sanitizeLogText(savedSessionId, 128)} for key ${sanitizeLogText(key, 256)} after load failed: ${sanitizeLogText(loadError instanceof Error ? loadError.message : String(loadError), 512)}
2079
+ `);
2080
+ return replacement;
2081
+ } catch (createError) {
2082
+ this.assertOperationCurrent(operation);
2083
+ process2.stderr.write(`[SessionRouter] Failed to load session ${sanitizeLogText(savedSessionId, 128)} for key ${sanitizeLogText(key, 256)} (${sanitizeLogText(loadError instanceof Error ? loadError.message : String(loadError), 512)}) and failed to create a replacement (${sanitizeLogText(createError instanceof Error ? createError.message : String(createError), 512)})
2084
+ `);
2085
+ throw createError;
2086
+ }
1883
2087
  }
2088
+ } finally {
2089
+ this.endSessionLoad(loadWindow);
1884
2090
  }
1885
2091
  }
1886
2092
  getTarget(sessionId) {
@@ -1912,6 +2118,7 @@ var SessionRouter = class {
1912
2118
  const scope = this.channelScopes.get(channelName) || this.defaultScope;
1913
2119
  if (chatId) {
1914
2120
  const key = this.routingKey(channelName, senderId, chatId, threadId);
2121
+ this.invalidateRouteOperation(key);
1915
2122
  const sessionId = this.deleteByKey(key);
1916
2123
  if (sessionId)
1917
2124
  removedIds.push(sessionId);
@@ -1921,11 +2128,17 @@ var SessionRouter = class {
1921
2128
  for (const [k, mappedSessionId] of [...this.toSession.entries()]) {
1922
2129
  const target = this.toTarget.get(mappedSessionId);
1923
2130
  if (target?.channelName === channelName && target.senderId === senderId) {
2131
+ this.invalidateRouteOperation(k);
1924
2132
  const sessionId = this.deleteByKey(k);
1925
2133
  if (sessionId)
1926
2134
  removedIds.push(sessionId);
1927
2135
  }
1928
2136
  }
2137
+ for (const [key, operation] of [...this.creatingSessions]) {
2138
+ if (operation.target.channelName === channelName && operation.target.senderId === senderId) {
2139
+ this.invalidateRouteOperation(key);
2140
+ }
2141
+ }
1929
2142
  }
1930
2143
  if (removedIds.length > 0)
1931
2144
  this.persist();
@@ -1936,6 +2149,7 @@ var SessionRouter = class {
1936
2149
  let removed = false;
1937
2150
  for (const [key, mappedSessionId] of [...this.toSession.entries()]) {
1938
2151
  if (mappedSessionId === sessionId) {
2152
+ this.invalidateRouteOperation(key);
1939
2153
  this.toSession.delete(key);
1940
2154
  removed = true;
1941
2155
  }
@@ -1946,6 +2160,7 @@ var SessionRouter = class {
1946
2160
  if (this.toCwd.delete(sessionId)) {
1947
2161
  removed = true;
1948
2162
  }
2163
+ this.liveSessionIds.delete(sessionId);
1949
2164
  if (!removed && this.sessionLoadWindows.size > 0) {
1950
2165
  for (const loadWindow of this.sessionLoadWindows) {
1951
2166
  loadWindow.add(sessionId);
@@ -1956,6 +2171,17 @@ var SessionRouter = class {
1956
2171
  }
1957
2172
  return removed;
1958
2173
  }
2174
+ handleSessionDied(sessionId) {
2175
+ if (this.recoveryMode === "eager") {
2176
+ return this.removeSessionId(sessionId);
2177
+ }
2178
+ const known = this.toTarget.has(sessionId);
2179
+ this.liveSessionIds.delete(sessionId);
2180
+ for (const loadWindow of this.sessionLoadWindows) {
2181
+ loadWindow.add(sessionId);
2182
+ }
2183
+ return known;
2184
+ }
1959
2185
  deleteByKey(key) {
1960
2186
  const sessionId = this.toSession.get(key);
1961
2187
  if (!sessionId)
@@ -1963,6 +2189,7 @@ var SessionRouter = class {
1963
2189
  this.toSession.delete(key);
1964
2190
  this.toTarget.delete(sessionId);
1965
2191
  this.toCwd.delete(sessionId);
2192
+ this.liveSessionIds.delete(sessionId);
1966
2193
  return sessionId;
1967
2194
  }
1968
2195
  promoteTargetToGroup(sessionId, isGroup) {
@@ -1985,45 +2212,69 @@ var SessionRouter = class {
1985
2212
  }
1986
2213
  return entries;
1987
2214
  }
2215
+ restoreRoutes() {
2216
+ if (this.recoveryMode !== "lazy") {
2217
+ throw new Error("restoreRoutes requires lazy recovery mode");
2218
+ }
2219
+ const persisted = this.readPersistedEntries();
2220
+ if (!persisted)
2221
+ return { restored: 0, dropped: 0 };
2222
+ this.dispose();
2223
+ let restored = 0;
2224
+ for (const [key, entry] of Object.entries(persisted.entries)) {
2225
+ this.toSession.set(key, entry.sessionId);
2226
+ this.toTarget.set(entry.sessionId, entry.target);
2227
+ this.toCwd.set(entry.sessionId, entry.cwd);
2228
+ restored++;
2229
+ }
2230
+ if (persisted.dropped > 0)
2231
+ this.persist();
2232
+ return { restored, dropped: persisted.dropped };
2233
+ }
1988
2234
  /**
1989
2235
  * Restore session mappings from a previous bridge.
1990
2236
  * Called after bridge restart — attempts loadSession for each saved mapping.
1991
2237
  * Failed loads are dropped (new session on next message).
1992
2238
  */
1993
2239
  async restoreSessions() {
1994
- const persistPath = this.persistPath;
1995
- if (!persistPath || !existsSync3(persistPath)) {
1996
- return { restored: 0, failed: 0 };
1997
- }
1998
- let entries;
1999
- try {
2000
- entries = JSON.parse(readFileSync3(persistPath, "utf-8"));
2001
- } catch (err) {
2002
- const reason = err instanceof Error ? err.message : String(err);
2003
- process2.stderr.write(`[SessionRouter] Corrupted persist file at ${sanitizeLogText(persistPath, 1024)}: ${sanitizeLogText(reason, 512)}
2004
- `);
2240
+ const persisted = this.readPersistedEntries();
2241
+ if (!persisted)
2005
2242
  return { restored: 0, failed: 0 };
2006
- }
2243
+ const entries = persisted.entries;
2244
+ const restoreGeneration = this.lifecycleGeneration;
2007
2245
  let restored = 0;
2008
2246
  let failed = 0;
2009
- let changed = false;
2247
+ let changed = persisted.dropped > 0;
2010
2248
  const reservations = /* @__PURE__ */ new Map();
2249
+ for (const key of persisted.droppedKeys) {
2250
+ this.deleteByKey(key);
2251
+ }
2011
2252
  for (const key of Object.keys(entries)) {
2012
2253
  this.deleteByKey(key);
2013
2254
  const reservation = this.createSessionReservation();
2014
2255
  reservation.promise.catch(() => void 0);
2015
- this.creatingSessions.set(key, reservation.promise);
2016
- reservations.set(key, reservation);
2256
+ const operation = this.createSessionOperation(key, entries[key].target, () => reservation.promise);
2257
+ operation.promise.catch(() => void 0);
2258
+ this.creatingSessions.set(key, operation);
2259
+ reservations.set(key, { reservation, operation });
2017
2260
  }
2018
2261
  const loadWindow = this.beginSessionLoad();
2019
2262
  try {
2020
2263
  for (const [key, entry] of Object.entries(entries)) {
2021
- const reservation = reservations.get(key);
2022
- if (!reservation)
2264
+ const reserved = reservations.get(key);
2265
+ if (!reserved)
2023
2266
  continue;
2267
+ const { reservation, operation } = reserved;
2024
2268
  try {
2269
+ this.assertOperationCurrent(operation);
2025
2270
  const options = this.sessionOptions(entry.target.channelName);
2026
- const sessionId = options ? await this.bridge.loadSession(entry.sessionId, entry.cwd, options) : await this.bridge.loadSession(entry.sessionId, entry.cwd);
2271
+ const sessionId = await this.bridge.loadSession(entry.sessionId, entry.cwd, options, operation);
2272
+ try {
2273
+ this.assertOperationCurrent(operation);
2274
+ } catch (error) {
2275
+ this.scheduleDiscardInvalidatedSession(sessionId, operation);
2276
+ throw error;
2277
+ }
2027
2278
  if (typeof sessionId !== "string" || sessionId.length === 0) {
2028
2279
  throw new Error("Invalid restored session ID");
2029
2280
  }
@@ -2046,26 +2297,36 @@ var SessionRouter = class {
2046
2297
  failed++;
2047
2298
  changed = true;
2048
2299
  } finally {
2049
- if (this.creatingSessions.get(key) === reservation.promise) {
2300
+ if (this.creatingSessions.get(key) === operation) {
2050
2301
  this.creatingSessions.delete(key);
2051
2302
  }
2303
+ this.releaseRouteToken(key, operation);
2052
2304
  }
2053
2305
  }
2054
2306
  } finally {
2055
2307
  this.endSessionLoad(loadWindow);
2056
2308
  }
2057
- if (changed) {
2309
+ if (changed && restoreGeneration === this.lifecycleGeneration) {
2058
2310
  this.persist();
2059
2311
  }
2060
2312
  return { restored, failed };
2061
2313
  }
2062
- /** Clear in-memory state and delete persist file. Used on clean shutdown. */
2063
- clearAll() {
2314
+ dispose() {
2315
+ this.lifecycleGeneration++;
2316
+ for (const operation of this.creatingSessions.values()) {
2317
+ this.invalidateOperation(operation);
2318
+ }
2064
2319
  this.toSession.clear();
2065
2320
  this.toTarget.clear();
2066
2321
  this.toCwd.clear();
2067
2322
  this.creatingSessions.clear();
2068
2323
  this.sessionLoadWindows.clear();
2324
+ this.liveSessionIds.clear();
2325
+ this.routeTokens.clear();
2326
+ }
2327
+ /** Clear in-memory state and delete persist file. Used on clean shutdown. */
2328
+ clearAll() {
2329
+ this.dispose();
2069
2330
  if (this.persistPath && existsSync3(this.persistPath)) {
2070
2331
  try {
2071
2332
  unlinkSync(this.persistPath);
@@ -2073,30 +2334,105 @@ var SessionRouter = class {
2073
2334
  }
2074
2335
  }
2075
2336
  }
2337
+ readPersistedEntries() {
2338
+ const persistPath = this.persistPath;
2339
+ if (!persistPath || !existsSync3(persistPath))
2340
+ return void 0;
2341
+ let parsed;
2342
+ try {
2343
+ parsed = JSON.parse(readFileSync3(persistPath, "utf-8"));
2344
+ } catch (error) {
2345
+ const quarantinePath = `${persistPath}.corrupt-${Date.now()}`;
2346
+ try {
2347
+ renameSync2(persistPath, quarantinePath);
2348
+ } catch {
2349
+ }
2350
+ process2.stderr.write(`[SessionRouter] Corrupted persist file at ${sanitizeLogText(persistPath, 1024)}: ${sanitizeLogText(error instanceof Error ? error.message : String(error), 512)}
2351
+ `);
2352
+ return void 0;
2353
+ }
2354
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2355
+ const quarantinePath = `${persistPath}.corrupt-${Date.now()}`;
2356
+ try {
2357
+ renameSync2(persistPath, quarantinePath);
2358
+ } catch {
2359
+ }
2360
+ process2.stderr.write(`[SessionRouter] Invalid route store at ${sanitizeLogText(persistPath, 1024)}: expected an object
2361
+ `);
2362
+ return void 0;
2363
+ }
2364
+ const entries = {};
2365
+ const droppedKeys = [];
2366
+ for (const [key, value] of Object.entries(parsed)) {
2367
+ if (this.isPersistedEntry(value))
2368
+ entries[key] = value;
2369
+ else
2370
+ droppedKeys.push(key);
2371
+ }
2372
+ return { entries, dropped: droppedKeys.length, droppedKeys };
2373
+ }
2374
+ isPersistedEntry(value) {
2375
+ if (typeof value !== "object" || value === null)
2376
+ return false;
2377
+ const entry = value;
2378
+ const target = entry["target"];
2379
+ if (typeof target !== "object" || target === null)
2380
+ return false;
2381
+ const typedTarget = target;
2382
+ return typeof entry["sessionId"] === "string" && entry["sessionId"].length > 0 && typeof entry["cwd"] === "string" && entry["cwd"].length > 0 && typeof typedTarget["channelName"] === "string" && typeof typedTarget["senderId"] === "string" && typeof typedTarget["chatId"] === "string" && (typedTarget["threadId"] === void 0 || typeof typedTarget["threadId"] === "string") && (typedTarget["isGroup"] === void 0 || typeof typedTarget["isGroup"] === "boolean");
2383
+ }
2076
2384
  persist() {
2077
2385
  if (!this.persistPath)
2078
2386
  return;
2079
2387
  const data = {};
2080
2388
  for (const [key, sessionId] of this.toSession) {
2081
2389
  const target = this.toTarget.get(sessionId);
2082
- if (target) {
2083
- data[key] = {
2084
- sessionId,
2085
- target,
2086
- cwd: this.toCwd.get(sessionId) || this.defaultCwd
2087
- };
2088
- }
2390
+ if (!target)
2391
+ continue;
2392
+ data[key] = {
2393
+ sessionId,
2394
+ target,
2395
+ cwd: this.toCwd.get(sessionId) ?? this.defaultCwd
2396
+ };
2089
2397
  }
2398
+ const dir = dirname2(this.persistPath);
2399
+ const tempPath = join4(dir, `${Date.now()}-${process2.pid}-${Math.random().toString(16).slice(2)}.tmp`);
2090
2400
  try {
2091
- writeFileSync3(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
2092
- } catch {
2401
+ mkdirSync3(dir, { recursive: true, mode: 448 });
2402
+ try {
2403
+ chmodSync2(dir, 448);
2404
+ } catch {
2405
+ }
2406
+ writeFileSync3(tempPath, JSON.stringify(data, null, 2), {
2407
+ encoding: "utf-8",
2408
+ mode: 384
2409
+ });
2410
+ renameSync2(tempPath, this.persistPath);
2411
+ try {
2412
+ chmodSync2(this.persistPath, 384);
2413
+ } catch {
2414
+ }
2415
+ } catch (error) {
2416
+ process2.stderr.write(`[SessionRouter] Failed to persist routes at ${sanitizeLogText(this.persistPath, 1024)}: ${sanitizeLogText(error instanceof Error ? error.message : String(error), 512)}
2417
+ `);
2418
+ } finally {
2419
+ try {
2420
+ rmSync(tempPath, { force: true });
2421
+ } catch {
2422
+ }
2093
2423
  }
2094
2424
  }
2095
- async createLiveSession(cwd, loadWindow, routingKey, options) {
2425
+ async createLiveSession(cwd, loadWindow, routingKey, options, operation) {
2096
2426
  const maxAttempts = 2;
2097
2427
  let lastDeadSessionId;
2098
2428
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
2099
- const sessionId = options ? await this.bridge.newSession(cwd, options) : await this.bridge.newSession(cwd);
2429
+ const sessionId = await this.bridge.newSession(cwd, options, operation);
2430
+ try {
2431
+ this.assertOperationCurrent(operation);
2432
+ } catch (error) {
2433
+ this.scheduleDiscardInvalidatedSession(sessionId, operation);
2434
+ throw error;
2435
+ }
2100
2436
  if (typeof sessionId !== "string" || sessionId.length === 0) {
2101
2437
  throw new Error("Invalid session ID from bridge");
2102
2438
  }
@@ -2112,6 +2448,65 @@ var SessionRouter = class {
2112
2448
  this.sessionLoadWindows.add(loadWindow);
2113
2449
  return loadWindow;
2114
2450
  }
2451
+ createSessionOperation(key, target, run) {
2452
+ let routeToken = this.routeTokens.get(key);
2453
+ if (!routeToken) {
2454
+ routeToken = {};
2455
+ this.routeTokens.set(key, routeToken);
2456
+ }
2457
+ const operation = {
2458
+ promise: Promise.resolve(""),
2459
+ target,
2460
+ lifecycleGeneration: this.lifecycleGeneration,
2461
+ routeToken
2462
+ };
2463
+ operation.promise = Promise.resolve().then(() => run(operation)).catch((error) => {
2464
+ this.assertOperationCurrent(operation);
2465
+ throw error;
2466
+ });
2467
+ return operation;
2468
+ }
2469
+ invalidateRouteOperation(key) {
2470
+ this.routeTokens.delete(key);
2471
+ const operation = this.creatingSessions.get(key);
2472
+ if (!operation)
2473
+ return;
2474
+ this.invalidateOperation(operation);
2475
+ this.creatingSessions.delete(key);
2476
+ }
2477
+ invalidateOperation(operation) {
2478
+ operation.invalidationError ??= new Error("Session route operation was invalidated");
2479
+ }
2480
+ assertOperationCurrent(operation) {
2481
+ if (operation.lifecycleGeneration !== this.lifecycleGeneration) {
2482
+ this.invalidateOperation(operation);
2483
+ }
2484
+ if (operation.invalidationError) {
2485
+ throw operation.invalidationError;
2486
+ }
2487
+ }
2488
+ assertOperationResultCurrent(key, sessionId, operation) {
2489
+ if (operation.routeToken !== this.routeTokens.get(key)) {
2490
+ this.invalidateOperation(operation);
2491
+ }
2492
+ if (this.toSession.get(key) !== sessionId) {
2493
+ this.invalidateOperation(operation);
2494
+ }
2495
+ this.assertOperationCurrent(operation);
2496
+ }
2497
+ releaseRouteToken(key, operation) {
2498
+ if (this.routeTokens.get(key) === operation.routeToken && !this.toSession.has(key) && !this.creatingSessions.has(key)) {
2499
+ this.routeTokens.delete(key);
2500
+ }
2501
+ }
2502
+ scheduleDiscardInvalidatedSession(sessionId, operation) {
2503
+ if ([...this.toSession.values()].includes(sessionId))
2504
+ return;
2505
+ try {
2506
+ void this.bridge.discardSession?.(sessionId, operation).catch(() => void 0);
2507
+ } catch {
2508
+ }
2509
+ }
2115
2510
  createSessionReservation() {
2116
2511
  let resolveReservation;
2117
2512
  let rejectReservation;
@@ -2488,6 +2883,29 @@ var LIST_PATTERNS = [
2488
2883
  /^这个聊天你记住了什么[??]?$/u,
2489
2884
  /^what do you remember[??]?$/iu
2490
2885
  ];
2886
+ var LIST_PAGE_PATTERNS = [
2887
+ /^查看第\s*(\d+)\s*页记忆$/u,
2888
+ /^show memory page\s+(\d+)$/iu
2889
+ ];
2890
+ var INSPECT_PATTERNS = [
2891
+ /^查看记忆\s+(\S+)$/u,
2892
+ /^show memory\s+(\S+)$/iu
2893
+ ];
2894
+ var REMOVE_PATTERNS = [
2895
+ /^忘掉\s+(\S+)$/u,
2896
+ /^删除\s+(\S+)$/u,
2897
+ /^删掉\s+(\S+)$/u,
2898
+ /^forget\s+(\S+)$/iu,
2899
+ /^delete\s+(\S+)$/iu,
2900
+ /^remove\s+(\S+)$/iu
2901
+ ];
2902
+ var UPDATE_PATTERNS = [
2903
+ /^把\s+(\S+)\s+改成\s*(.+)$/su,
2904
+ /^更新\s+(\S+)\s+为\s*(.+)$/su,
2905
+ /^update\s+(\S+)\s+to\s+(.+)$/isu,
2906
+ /^change\s+(\S+)\s+to\s+(.+)$/isu
2907
+ ];
2908
+ var MEMORY_ID_PATTERN = /^m-[a-f0-9]{12}$/u;
2491
2909
  var CLEAR_REQUEST_PATTERNS = [
2492
2910
  /^清空记忆$/u,
2493
2911
  /^清除记忆$/u,
@@ -2510,14 +2928,41 @@ function parseChannelMemoryIntent(text) {
2510
2928
  return { kind: "clear_confirm" };
2511
2929
  }
2512
2930
  }
2931
+ for (const pattern of REMOVE_PATTERNS) {
2932
+ const match = trimmed.match(pattern);
2933
+ if (match?.[1] && MEMORY_ID_PATTERN.test(match[1])) {
2934
+ return { kind: "remove", id: match[1] };
2935
+ }
2936
+ }
2937
+ for (const pattern of UPDATE_PATTERNS) {
2938
+ const match = trimmed.match(pattern);
2939
+ const id = match?.[1];
2940
+ const updated = match?.[2]?.trim();
2941
+ if (id && updated && MEMORY_ID_PATTERN.test(id)) {
2942
+ return { kind: "update", id, text: updated };
2943
+ }
2944
+ }
2513
2945
  for (const pattern of CLEAR_REQUEST_PATTERNS) {
2514
2946
  if (pattern.test(trimmed)) {
2515
2947
  return { kind: "clear_request" };
2516
2948
  }
2517
2949
  }
2950
+ for (const pattern of INSPECT_PATTERNS) {
2951
+ const match = trimmed.match(pattern);
2952
+ if (match?.[1] && MEMORY_ID_PATTERN.test(match[1])) {
2953
+ return { kind: "inspect", id: match[1] };
2954
+ }
2955
+ }
2956
+ for (const pattern of LIST_PAGE_PATTERNS) {
2957
+ const match = trimmed.match(pattern);
2958
+ if (match?.[1]) {
2959
+ const page = Number(match[1]);
2960
+ return Number.isSafeInteger(page) && page > 0 ? { kind: "list", page } : null;
2961
+ }
2962
+ }
2518
2963
  for (const pattern of LIST_PATTERNS) {
2519
2964
  if (pattern.test(trimmed)) {
2520
- return { kind: "list" };
2965
+ return { kind: "list", page: 1 };
2521
2966
  }
2522
2967
  }
2523
2968
  for (const pattern of REMEMBER_PATTERNS) {
@@ -2539,8 +2984,10 @@ var GROUP_HISTORY_ENTRY_TEXT_LIMIT = 1e3;
2539
2984
  var GROUP_HISTORY_ENTRY_METADATA_LIMIT = 256;
2540
2985
  var LOOP_CANCEL_GRACE_MS = 5e3;
2541
2986
  var CHANNEL_MEMORY_PROMPT_CODE_POINT_LIMIT = 12e3;
2987
+ var CHANNEL_MEMORY_PAGE_SIZE = 20;
2988
+ var CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT = 160;
2542
2989
  var CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE = 0.7;
2543
- var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|保存|remember|memory|forget)/iu;
2990
+ var CHANNEL_MEMORY_CLASSIFIER_TRIGGER_RE = /(?:记住|记得|记一下|记忆|忘掉|忘记|清空|清除|删除|删掉|改成|更新|刚才那条|保存|(?:只|仅)(?:看|列出)[\p{Script=Han}\s]{0,12}(?:偏好|习惯)|\b(?:remember|memory|forget|delete|remove|update|change)\b)/iu;
2544
2991
  var LOOP_TIMED_OUT_MESSAGE = "loop timed out";
2545
2992
  var DEBUG_PAYLOAD_ENV = "QWEN_CHANNEL_DEBUG_PAYLOAD";
2546
2993
  var DEBUG_PAYLOAD_LIMIT = 12e3;
@@ -2750,7 +3197,7 @@ var ChannelBase = class {
2750
3197
  this.memoryScope = Object.freeze(this.resolveMemoryScope(name, config));
2751
3198
  this.channelMemory = options?.channelMemory;
2752
3199
  this.memoryIntentClassifier = options?.memoryIntentClassifier;
2753
- this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ?? join4(getGlobalQwenDir(), "channels", `${encodeURIComponent(name)}-group-history.jsonl`));
3200
+ this.groupHistory = new GroupHistoryStore(options?.groupHistoryPath ?? join5(getGlobalQwenDir(), "channels", `${encodeURIComponent(name)}-group-history.jsonl`));
2754
3201
  this.loopController = options?.loopController;
2755
3202
  this.groupGate = new GroupGate(config.groupPolicy, config.groups);
2756
3203
  this.dmGate = new DmGate(config.dmPolicy);
@@ -2862,6 +3309,9 @@ var ChannelBase = class {
2862
3309
  supportsProactiveTarget(target) {
2863
3310
  return target.threadId === void 0;
2864
3311
  }
3312
+ supportsProactiveWebhookTarget(target) {
3313
+ return this.supportsProactiveTarget(target);
3314
+ }
2865
3315
  async pushProactive(target, text) {
2866
3316
  if (target.threadId) {
2867
3317
  throw new Error("Channel does not support proactive loop messages for threaded targets.");
@@ -3147,7 +3597,7 @@ ${sanitizePromptText(job.prompt)}`;
3147
3597
  throw new Error(`Unknown webhook source "${task.source}".`);
3148
3598
  }
3149
3599
  const target = resolveChannelWebhookTarget(this.name, this.config.webhooks, task.source, task.targetRef);
3150
- if (!this.supportsProactiveTarget(target)) {
3600
+ if (!this.supportsProactiveWebhookTarget(target)) {
3151
3601
  throw new Error("Channel does not support proactive webhook messages for this chat target.");
3152
3602
  }
3153
3603
  return target;
@@ -3444,7 +3894,7 @@ ${sanitizePromptText(job.prompt)}`;
3444
3894
  onToolCall(_chatId, _event) {
3445
3895
  }
3446
3896
  onSessionDied(sessionId) {
3447
- this.router.removeSessionId(sessionId);
3897
+ this.router.handleSessionDied(sessionId);
3448
3898
  this.instructedSessions.delete(sessionId);
3449
3899
  this.removePendingPermissionsForSession(sessionId);
3450
3900
  }
@@ -3492,13 +3942,16 @@ ${sanitizePromptText(job.prompt)}`;
3492
3942
  */
3493
3943
  onResponseBoundary(_chatId, _sessionId) {
3494
3944
  }
3945
+ async sendResponseMessage(chatId, text, _sessionId) {
3946
+ await this.sendMessage(chatId, text);
3947
+ }
3495
3948
  /**
3496
3949
  * Called when the agent's full response is ready.
3497
3950
  * Override to customize delivery (e.g., finalize an AI card).
3498
- * Default: calls sendMessage() with the full response text.
3951
+ * Default: sends the full response text.
3499
3952
  */
3500
- async onResponseComplete(chatId, fullText, _sessionId) {
3501
- await this.sendMessage(chatId, fullText);
3953
+ async onResponseComplete(chatId, fullText, sessionId) {
3954
+ await this.sendResponseMessage(chatId, fullText, sessionId);
3502
3955
  }
3503
3956
  /**
3504
3957
  * Register a slash command handler. Subclasses can call this to add
@@ -3775,30 +4228,6 @@ ${requestList}`);
3775
4228
  this.registerCommand("approve", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve"));
3776
4229
  this.registerCommand("approve-always", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "approve-always"));
3777
4230
  this.registerCommand("deny", (envelope, args) => this.handlePermissionResponseCommand(envelope, args, "deny"));
3778
- this.registerCommand("remember-channel", async (envelope, args) => {
3779
- const text = args.trim();
3780
- if (text === "") {
3781
- await this.sendMessage(envelope.chatId, "Usage: /remember-channel <text>");
3782
- return true;
3783
- }
3784
- await this.handleChannelMemoryIntent(envelope, {
3785
- kind: "remember",
3786
- text
3787
- });
3788
- return true;
3789
- });
3790
- this.registerCommand("channel-memory", async (envelope) => {
3791
- await this.handleChannelMemoryIntent(envelope, { kind: "list" });
3792
- return true;
3793
- });
3794
- this.registerCommand("forget-channel", async (envelope, args) => {
3795
- if (args.toLowerCase() !== "confirm") {
3796
- await this.sendMessage(envelope.chatId, 'This clears channel memory for this chat. Re-send with "confirm" (e.g. /forget-channel confirm) to proceed.');
3797
- return true;
3798
- }
3799
- await this.handleChannelMemoryIntent(envelope, { kind: "clear_confirm" }, { skipPendingClear: true });
3800
- return true;
3801
- });
3802
4231
  this.registerCommand("who", async (envelope) => {
3803
4232
  if (!this.isAuthorizedForSharedSession(envelope)) {
3804
4233
  await this.sendMessage(envelope.chatId, "Only authorized members can view this shared session.");
@@ -4253,7 +4682,60 @@ ${requestList}`);
4253
4682
  }
4254
4683
  return this.channelMemory;
4255
4684
  }
4256
- async handleChannelMemoryIntent(envelope, intent, options = {}) {
4685
+ entriesForChannelMemoryIds(entries, ids) {
4686
+ const selected = new Set(ids);
4687
+ return entries.filter((entry) => selected.has(entry.id));
4688
+ }
4689
+ renderChannelMemoryCandidate(entry) {
4690
+ const preview = truncateCodePoints(sanitizePromptText(entry.text).replace(/[\r\n]+/gu, " ").trim(), CHANNEL_MEMORY_PREVIEW_CODE_POINT_LIMIT);
4691
+ return `${entry.id} ${preview}`;
4692
+ }
4693
+ renderChannelMemoryCandidates(entries) {
4694
+ return entries.map((entry) => this.renderChannelMemoryCandidate(entry));
4695
+ }
4696
+ async handleChannelMemoryIntent(envelope, intent) {
4697
+ if (intent.kind === "no_match") {
4698
+ await this.sendMessage(envelope.chatId, "No matching channel memory entry.");
4699
+ return;
4700
+ }
4701
+ if (intent.kind === "ambiguous") {
4702
+ const channelMemory2 = await this.getChannelMemory(envelope);
4703
+ if (!channelMemory2)
4704
+ return;
4705
+ let entries;
4706
+ try {
4707
+ entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
4708
+ } catch (error) {
4709
+ this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
4710
+ await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
4711
+ return;
4712
+ }
4713
+ const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
4714
+ await this.sendMessage(envelope.chatId, [
4715
+ "Multiple channel memory entries match:",
4716
+ ...this.renderChannelMemoryCandidates(selected)
4717
+ ].join("\n"));
4718
+ return;
4719
+ }
4720
+ if (intent.kind === "list_matches") {
4721
+ const channelMemory2 = await this.getChannelMemory(envelope);
4722
+ if (!channelMemory2)
4723
+ return;
4724
+ let entries;
4725
+ try {
4726
+ entries = await channelMemory2.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
4727
+ } catch (error) {
4728
+ this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
4729
+ await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
4730
+ return;
4731
+ }
4732
+ const selected = this.entriesForChannelMemoryIds(entries, intent.ids);
4733
+ await this.sendMessage(envelope.chatId, [
4734
+ "Channel memory (page 1/1):",
4735
+ ...this.renderChannelMemoryCandidates(selected)
4736
+ ].join("\n"));
4737
+ return;
4738
+ }
4257
4739
  if (intent.kind === "clear_request") {
4258
4740
  this.setPendingClear(this.clearPendingKey(envelope));
4259
4741
  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.');
@@ -4264,40 +4746,96 @@ ${requestList}`);
4264
4746
  return;
4265
4747
  }
4266
4748
  if (intent.kind === "remember") {
4749
+ let result;
4267
4750
  try {
4268
- await channelMemory.appendChannelMemory(this.channelMemoryTarget(envelope), intent.text);
4751
+ result = await channelMemory.addChannelMemoryEntries(this.channelMemoryTarget(envelope), [intent.text], envelope.senderId);
4269
4752
  } catch (error) {
4270
4753
  const message = this.channelMemoryErrorMessage(error);
4271
4754
  this.logChannelMemoryError("save", envelope, message);
4272
4755
  await this.sendMessage(envelope.chatId, `Failed to save channel memory: ${this.channelMemoryUserErrorMessage()}`);
4273
4756
  return;
4274
4757
  }
4275
- this.invalidateSessionContext(envelope);
4276
- await this.sendMessage(envelope.chatId, "Channel memory updated.");
4758
+ if (result.changed) {
4759
+ this.invalidateSessionContext(envelope);
4760
+ }
4761
+ if (result.added.length > 0) {
4762
+ const ids = result.added.map((entry) => entry.id);
4763
+ await this.sendMessage(envelope.chatId, ids.length === 1 ? `Channel memory ${ids[0]} saved.` : `Channel memory saved: ${ids.join(", ")}.`);
4764
+ } else if (result.duplicateIds.length > 0) {
4765
+ await this.sendMessage(envelope.chatId, `Channel memory already contains ${result.duplicateIds.join(", ")}.`);
4766
+ } else {
4767
+ await this.sendMessage(envelope.chatId, "Channel memory updated.");
4768
+ }
4277
4769
  return;
4278
4770
  }
4279
- if (intent.kind === "list") {
4280
- let text;
4771
+ if (intent.kind === "list" || intent.kind === "inspect") {
4772
+ let entries;
4281
4773
  try {
4282
- text = (await channelMemory.readChannelMemory(this.channelMemoryTarget(envelope))).trim();
4774
+ entries = await channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
4283
4775
  } catch (error) {
4284
4776
  const message = this.channelMemoryErrorMessage(error);
4285
4777
  this.logChannelMemoryError("read", envelope, message);
4286
4778
  await this.sendMessage(envelope.chatId, `Failed to read channel memory: ${this.channelMemoryUserErrorMessage()}`);
4287
4779
  return;
4288
4780
  }
4289
- await this.sendMessage(envelope.chatId, text === "" ? "No channel memory saved." : sanitizePromptText(text));
4781
+ if (intent.kind === "inspect") {
4782
+ const entry = entries.find((candidate) => candidate.id === intent.id);
4783
+ await this.sendMessage(envelope.chatId, entry ? `Channel memory ${entry.id}:
4784
+ ${sanitizePromptText(entry.text).trim()}` : `No channel memory entry ${intent.id}.`);
4785
+ return;
4786
+ }
4787
+ const totalPages = Math.max(1, Math.ceil(entries.length / CHANNEL_MEMORY_PAGE_SIZE));
4788
+ if (intent.page > totalPages) {
4789
+ await this.sendMessage(envelope.chatId, `Channel memory page ${intent.page} does not exist.`);
4790
+ return;
4791
+ }
4792
+ if (entries.length === 0) {
4793
+ await this.sendMessage(envelope.chatId, "No channel memory saved.");
4794
+ return;
4795
+ }
4796
+ const pageStart = (intent.page - 1) * CHANNEL_MEMORY_PAGE_SIZE;
4797
+ const lines = entries.slice(pageStart, pageStart + CHANNEL_MEMORY_PAGE_SIZE).map((entry) => this.renderChannelMemoryCandidate(entry));
4798
+ await this.sendMessage(envelope.chatId, [`Channel memory (page ${intent.page}/${totalPages}):`, ...lines].join("\n"));
4290
4799
  return;
4291
4800
  }
4292
- if (intent.kind === "clear_confirm") {
4293
- if (!options.skipPendingClear) {
4294
- const pendingKey = this.clearPendingKey(envelope);
4295
- const expiresAt = this.pendingClears.get(pendingKey);
4296
- this.pendingClears.delete(pendingKey);
4297
- if (expiresAt === void 0 || expiresAt < Date.now()) {
4298
- await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
4299
- return;
4801
+ if (intent.kind === "update" || intent.kind === "remove" || intent.kind === "natural_update" || intent.kind === "natural_remove") {
4802
+ let changed;
4803
+ const isUpdate = intent.kind === "update" || intent.kind === "natural_update";
4804
+ const id = intent.id;
4805
+ try {
4806
+ if (isUpdate) {
4807
+ ({ changed } = await channelMemory.updateChannelMemoryEntry(this.channelMemoryTarget(envelope), intent.kind === "natural_update" ? {
4808
+ id: intent.id,
4809
+ text: intent.text,
4810
+ expectedText: intent.expectedText
4811
+ } : { id: intent.id, text: intent.text }));
4812
+ } else {
4813
+ ({ changed } = await channelMemory.removeChannelMemoryEntries(this.channelMemoryTarget(envelope), intent.kind === "natural_remove" ? {
4814
+ ids: [intent.id],
4815
+ expectedTextById: { [intent.id]: intent.expectedText }
4816
+ } : { ids: [intent.id] }));
4300
4817
  }
4818
+ } catch (error) {
4819
+ const message = this.channelMemoryErrorMessage(error);
4820
+ this.logChannelMemoryError(isUpdate ? "update" : "remove", envelope, message);
4821
+ await this.sendMessage(envelope.chatId, `Failed to ${isUpdate ? "update" : "remove"} channel memory: ${this.channelMemoryUserErrorMessage()}`);
4822
+ return;
4823
+ }
4824
+ if (!changed) {
4825
+ await this.sendMessage(envelope.chatId, `No channel memory entry ${id}.`);
4826
+ return;
4827
+ }
4828
+ this.invalidateSessionContext(envelope);
4829
+ await this.sendMessage(envelope.chatId, `Channel memory ${id} ${isUpdate ? "updated" : "removed"}.`);
4830
+ return;
4831
+ }
4832
+ if (intent.kind === "clear_confirm") {
4833
+ const pendingKey = this.clearPendingKey(envelope);
4834
+ const expiresAt = this.pendingClears.get(pendingKey);
4835
+ this.pendingClears.delete(pendingKey);
4836
+ if (expiresAt === void 0 || expiresAt < Date.now()) {
4837
+ await this.sendMessage(envelope.chatId, 'No pending clear request. Say "\u6E05\u7A7A\u8BB0\u5FC6" first.');
4838
+ return;
4301
4839
  }
4302
4840
  let result;
4303
4841
  try {
@@ -4308,7 +4846,9 @@ ${requestList}`);
4308
4846
  await this.sendMessage(envelope.chatId, `Failed to clear channel memory: ${this.channelMemoryUserErrorMessage()}`);
4309
4847
  return;
4310
4848
  }
4311
- this.invalidateSessionContext(envelope);
4849
+ if (result.changed) {
4850
+ this.invalidateSessionContext(envelope);
4851
+ }
4312
4852
  await this.sendMessage(envelope.chatId, result.changed ? "Channel memory cleared." : "No channel memory saved.");
4313
4853
  return;
4314
4854
  }
@@ -4331,31 +4871,82 @@ ${requestList}`);
4331
4871
  }
4332
4872
  this.pendingClears.set(key, now + 6e4);
4333
4873
  }
4334
- async classifyChannelMemoryIntent(text) {
4335
- if (!this.memoryIntentClassifier) {
4874
+ async classifyChannelMemoryIntent(envelope) {
4875
+ if (!this.memoryIntentClassifier || !this.channelMemory) {
4876
+ return null;
4877
+ }
4878
+ let entries;
4879
+ try {
4880
+ entries = await this.channelMemory.listChannelMemoryEntries(this.channelMemoryTarget(envelope));
4881
+ } catch (error) {
4882
+ this.logChannelMemoryError("read", envelope, this.channelMemoryErrorMessage(error));
4336
4883
  return null;
4337
4884
  }
4338
4885
  let classified;
4339
4886
  try {
4340
- classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(text);
4887
+ classified = await this.memoryIntentClassifier.classifyChannelMemoryIntent(envelope.text, entries);
4341
4888
  } catch (error) {
4342
4889
  process.stderr.write(`[${this.name}] channel memory intent classifier failed: ${sanitizeLogText(this.channelMemoryErrorMessage(error), 200)}
4343
4890
  `);
4344
4891
  return null;
4345
4892
  }
4346
- if (classified.confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
4893
+ const confidence = classified && typeof classified === "object" ? classified.confidence : void 0;
4894
+ if (typeof confidence !== "number" || !Number.isFinite(confidence) || confidence < 0 || confidence > 1 || confidence < CHANNEL_MEMORY_CLASSIFIER_MIN_CONFIDENCE) {
4347
4895
  return null;
4348
4896
  }
4349
- if (classified.intent === "remember") {
4350
- const memory = classified.memory?.trim();
4897
+ const result = classified;
4898
+ const targetIds = result.targetIds;
4899
+ const entryById = new Map(entries.map((entry2) => [entry2.id, entry2]));
4900
+ const resolvedEntries = targetIds === void 0 ? void 0 : Array.isArray(targetIds) && targetIds.every((id) => typeof id === "string" && entryById.has(id)) && new Set(targetIds).size === targetIds.length ? this.entriesForChannelMemoryIds(entries, targetIds) : null;
4901
+ if (result.intent === "remember") {
4902
+ const memory = typeof result.memory === "string" ? result.memory.trim() : "";
4351
4903
  return memory ? { kind: "remember", text: memory } : null;
4352
4904
  }
4353
- if (classified.intent === "list") {
4354
- return { kind: "list" };
4905
+ if (result.intent === "list") {
4906
+ if (resolvedEntries === void 0)
4907
+ return { kind: "list", page: 1 };
4908
+ if (resolvedEntries === null)
4909
+ return null;
4910
+ return resolvedEntries.length === 0 ? { kind: "no_match" } : {
4911
+ kind: "list_matches",
4912
+ ids: resolvedEntries.map((entry2) => entry2.id)
4913
+ };
4355
4914
  }
4356
- if (classified.intent === "clear_all") {
4915
+ if (result.intent === "clear_all") {
4357
4916
  return { kind: "clear_request" };
4358
4917
  }
4918
+ if (result.intent !== "inspect" && result.intent !== "update" && result.intent !== "remove") {
4919
+ return null;
4920
+ }
4921
+ if (resolvedEntries === null || resolvedEntries === void 0)
4922
+ return null;
4923
+ if (resolvedEntries.length === 0)
4924
+ return { kind: "no_match" };
4925
+ if (resolvedEntries.length > 1) {
4926
+ return {
4927
+ kind: "ambiguous",
4928
+ ids: resolvedEntries.map((entry2) => entry2.id)
4929
+ };
4930
+ }
4931
+ const entry = resolvedEntries[0];
4932
+ if (result.intent === "inspect")
4933
+ return { kind: "inspect", id: entry.id };
4934
+ if (result.intent === "remove") {
4935
+ return {
4936
+ kind: "natural_remove",
4937
+ id: entry.id,
4938
+ expectedText: entry.text
4939
+ };
4940
+ }
4941
+ const text = typeof result.memory === "string" ? result.memory.trim() : "";
4942
+ if (text) {
4943
+ return {
4944
+ kind: "natural_update",
4945
+ id: entry.id,
4946
+ text,
4947
+ expectedText: entry.text
4948
+ };
4949
+ }
4359
4950
  return null;
4360
4951
  }
4361
4952
  channelMemoryErrorMessage(error) {
@@ -4687,7 +5278,7 @@ ${promptText}`;
4687
5278
  }
4688
5279
  let memoryIntent = parseChannelMemoryIntent(envelope.text);
4689
5280
  if (!memoryIntent && this.shouldClassifyChannelMemoryIntent(envelope.text)) {
4690
- memoryIntent = await this.classifyChannelMemoryIntent(envelope.text);
5281
+ memoryIntent = await this.classifyChannelMemoryIntent(envelope);
4691
5282
  }
4692
5283
  if (memoryIntent) {
4693
5284
  await this.handleChannelMemoryIntent(envelope, memoryIntent);
@@ -4909,12 +5500,14 @@ ${promptToSend}`;
4909
5500
  minChars: this.config.blockStreamingChunk?.minChars ?? 400,
4910
5501
  maxChars: this.config.blockStreamingChunk?.maxChars ?? 1e3,
4911
5502
  idleMs: this.config.blockStreamingCoalesce?.idleMs ?? 1500,
4912
- send: /* @__PURE__ */ __name((text) => this.sendMessage(envelope.chatId, text), "send")
5503
+ send: /* @__PURE__ */ __name((text) => this.sendResponseMessage(envelope.chatId, text, sessionId), "send")
4913
5504
  }) : null;
4914
5505
  promptState.stopStreaming = () => streamer?.stop();
4915
5506
  const heldChunks = [];
5507
+ let hasStreamedText = false;
4916
5508
  const releaseHeldChunks = /* @__PURE__ */ __name(() => {
4917
5509
  for (const held of heldChunks.splice(0)) {
5510
+ hasStreamedText = true;
4918
5511
  this.emitTaskLifecycle({
4919
5512
  ...this.lifecycleBase(envelope.chatId, sessionId, envelope.messageId),
4920
5513
  type: "text_chunk",
@@ -4938,6 +5531,7 @@ ${promptToSend}`;
4938
5531
  return;
4939
5532
  }
4940
5533
  heldChunks.length = 0;
5534
+ hasStreamedText = false;
4941
5535
  this.onResponseBoundary(envelope.chatId, sessionId);
4942
5536
  streamer?.stop();
4943
5537
  }, "onResponseBoundary");
@@ -4956,6 +5550,9 @@ ${promptToSend}`;
4956
5550
  if (!promptState.cancelled && response) {
4957
5551
  promptState.deliveryStarted = true;
4958
5552
  if (streamer) {
5553
+ if (!hasStreamedText) {
5554
+ streamer.push(response);
5555
+ }
4959
5556
  await streamer.flush();
4960
5557
  } else {
4961
5558
  await this.onResponseComplete(envelope.chatId, response, sessionId);