@qwen-code/qwen-code 0.21.7 → 0.21.8

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 (314) hide show
  1. package/README.md +2 -0
  2. package/bundled/qc-helper/docs/configuration/settings.md +43 -30
  3. package/bundled/qc-helper/docs/features/channels/dingtalk.md +40 -2
  4. package/bundled/qc-helper/docs/features/channels/feishu.md +13 -2
  5. package/bundled/qc-helper/docs/features/channels/github.md +13 -11
  6. package/bundled/qc-helper/docs/features/channels/gitlab.md +13 -11
  7. package/bundled/qc-helper/docs/features/channels/overview.md +49 -31
  8. package/bundled/qc-helper/docs/features/channels/plugins.md +2 -2
  9. package/bundled/qc-helper/docs/features/channels/qqbot.md +4 -2
  10. package/bundled/qc-helper/docs/features/channels/telegram.md +4 -2
  11. package/bundled/qc-helper/docs/features/channels/wecom.md +1 -1
  12. package/bundled/qc-helper/docs/features/code-review.md +4 -0
  13. package/bundled/qc-helper/docs/features/commands.md +1 -1
  14. package/bundled/qc-helper/docs/features/hooks.md +52 -0
  15. package/bundled/qc-helper/docs/integration-jetbrains.md +1 -0
  16. package/bundled/qc-helper/docs/qwen-serve.md +4 -1
  17. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +50 -36
  18. package/bundled/review/SKILL.md +28 -5
  19. package/chunks/{MaxSizedBox-ANWZBPTS.js → MaxSizedBox-7PM6BGJ5.js} +26 -22
  20. package/chunks/{StandaloneSessionPicker-XKS3VU3A.js → StandaloneSessionPicker-3UQHM7GV.js} +44 -40
  21. package/chunks/{acp-startup-profiler-ORIQ2CCQ.js → acp-startup-profiler-B5BYAMYQ.js} +2 -2
  22. package/chunks/{acpAgent-KUAZ3GCZ.js → acpAgent-5UWLFV6V.js} +534 -262
  23. package/chunks/{agent-T6PTGX5R.js → agent-624T2BLO.js} +26 -22
  24. package/chunks/{agent-headless-PR7YCB7S.js → agent-headless-2EE5J2KX.js} +26 -22
  25. package/chunks/{artifact-tool-U4VOZIK5.js → artifact-tool-N652YE4L.js} +1 -1
  26. package/chunks/{askUserQuestion-XOBQLPFA.js → askUserQuestion-ONW74PKJ.js} +1 -1
  27. package/chunks/{bridge-NU6YEEHK.js → bridge-JENKGFFP.js} +29 -25
  28. package/chunks/{ca-NYKNH222.js → ca-ZLKAB4K3.js} +6 -0
  29. package/chunks/{channel-management-service-FSQ7SHYI.js → channel-management-service-DDWUPHMU.js} +19 -10
  30. package/chunks/{channel-settings-store-35VQVUVV.js → channel-settings-store-SA6JZSPH.js} +34 -30
  31. package/chunks/{channel-worker-group-JWQK224X.js → channel-worker-group-E67EN3RV.js} +5 -5
  32. package/chunks/{channel-worker-manager-77E3OXRQ.js → channel-worker-manager-SW4C45CF.js} +5 -5
  33. package/chunks/{channel-worker-supervisor-62YWUGP2.js → channel-worker-supervisor-5SRD24FG.js} +3 -3
  34. package/chunks/{chunk-CJXIIILK.js → chunk-2FRY5CRX.js} +1 -1
  35. package/chunks/{chunk-ZJ3VGYHK.js → chunk-2ILAOM2I.js} +34 -17
  36. package/chunks/{chunk-6XJMFJ4D.js → chunk-2M4K4KYS.js} +177 -120
  37. package/chunks/{chunk-CNIID3TV.js → chunk-2UUMVNYT.js} +1 -1
  38. package/chunks/{chunk-22NBYCPD.js → chunk-3P2LV43B.js} +1 -1
  39. package/chunks/{chunk-2U3WZGZG.js → chunk-3PY4LPJF.js} +19 -131
  40. package/chunks/{chunk-SPMY6CX6.js → chunk-3SE7J4DR.js} +3 -3
  41. package/chunks/{chunk-6UWFTUQL.js → chunk-3WNQOYHQ.js} +66 -22
  42. package/chunks/{chunk-KXSDEOFU.js → chunk-4ALIARFY.js} +1 -1
  43. package/chunks/{chunk-D3UEZIQH.js → chunk-4DU3NCHG.js} +48 -55
  44. package/chunks/{chunk-BGG4MBYD.js → chunk-4PYCZH2V.js} +4 -187
  45. package/chunks/{chunk-H2UQ2M5Z.js → chunk-4WU6NY7F.js} +96 -22
  46. package/chunks/{chunk-TLV2IMHR.js → chunk-5ZGR6RKJ.js} +3 -3
  47. package/chunks/{chunk-3K7FH2KQ.js → chunk-67N6HB5H.js} +1310 -171
  48. package/chunks/{chunk-EORNAQDT.js → chunk-6TR7CFXH.js} +1 -1
  49. package/chunks/{chunk-NG2R4N5O.js → chunk-6ZRFAKXK.js} +1 -1
  50. package/chunks/{chunk-P2AJ7FTI.js → chunk-757GB46F.js} +1 -1
  51. package/chunks/{chunk-72LNFGUY.js → chunk-77QVBFCU.js} +3 -3
  52. package/chunks/{chunk-OH2VKQXH.js → chunk-7DVT4LVV.js} +37 -30
  53. package/chunks/{chunk-KKJJB5X6.js → chunk-7VUERJHS.js} +1503 -815
  54. package/chunks/{chunk-VOARQPTA.js → chunk-B52AWKBB.js} +65 -21
  55. package/chunks/{chunk-Y4EWSQF7.js → chunk-BF224XHL.js} +2 -2
  56. package/chunks/{chunk-PJOBIWUG.js → chunk-BF52U4XJ.js} +1 -1
  57. package/chunks/{chunk-55LYDVPU.js → chunk-C5VWPTGT.js} +1 -1
  58. package/chunks/{chunk-W7U4ESW2.js → chunk-CG3WBKJK.js} +1 -1
  59. package/chunks/chunk-COBO5EBO.js +135 -0
  60. package/chunks/chunk-CPG6P4GG.js +82 -0
  61. package/chunks/{chunk-DIEFUBV6.js → chunk-DIWZNWZT.js} +205 -35
  62. package/chunks/{chunk-AE77C5ZU.js → chunk-DQSDACD2.js} +1 -1
  63. package/chunks/{chunk-P3LEG54R.js → chunk-DX5W5AON.js} +2 -2
  64. package/chunks/{chunk-EUQTXRKZ.js → chunk-E4ZBKMSF.js} +5 -5
  65. package/chunks/{chunk-FPM27XN4.js → chunk-EIVICVHM.js} +4 -4
  66. package/chunks/{chunk-YHEEE624.js → chunk-EN2TKTFH.js} +1 -1
  67. package/chunks/chunk-F6WFNA7U.js +22 -0
  68. package/chunks/{chunk-FZBZSYKU.js → chunk-FN6YXJOP.js} +1 -1
  69. package/chunks/{chunk-KR4ZSC7K.js → chunk-FWBXMANW.js} +3 -3
  70. package/chunks/{chunk-LA7YLSR6.js → chunk-FYAXKJK7.js} +327 -67
  71. package/chunks/{chunk-CSZEXZBE.js → chunk-GBDINRIL.js} +3 -3
  72. package/chunks/{chunk-SCI7K3GM.js → chunk-GOEVOFQI.js} +19 -10
  73. package/chunks/{chunk-LEMXGVEP.js → chunk-GQCEQPYQ.js} +3 -3
  74. package/chunks/{chunk-Y7E5LNLO.js → chunk-GXSNGY5M.js} +1027 -876
  75. package/chunks/{chunk-6XU3PH66.js → chunk-HA3SAB64.js} +22 -69
  76. package/chunks/{chunk-Y4NGLFGJ.js → chunk-HUWENAHO.js} +1 -1
  77. package/chunks/{chunk-3ULCB3NE.js → chunk-HV76SFIA.js} +1 -1
  78. package/chunks/{chunk-CB2464BK.js → chunk-HWX5HPUG.js} +14 -4
  79. package/chunks/{chunk-LZC3B5N2.js → chunk-IA7TGCN2.js} +2 -2
  80. package/chunks/{chunk-RERATVSK.js → chunk-IBYULW65.js} +6 -6
  81. package/chunks/{chunk-HYRDKNUY.js → chunk-IUQ52YJK.js} +1 -1
  82. package/chunks/{chunk-TDXGKHDN.js → chunk-IYES5WOT.js} +2 -2
  83. package/chunks/{chunk-RGSBTHSU.js → chunk-KAQCJO6Y.js} +131 -4
  84. package/chunks/{chunk-VWOVHOTT.js → chunk-KJZ26VBX.js} +1 -1
  85. package/chunks/{chunk-6GONZVLS.js → chunk-KKDVZLGL.js} +1 -1
  86. package/chunks/{chunk-MKVZE4ZJ.js → chunk-KTJFU7RT.js} +3 -2
  87. package/chunks/{chunk-R574ATRM.js → chunk-M2PNLYGY.js} +41 -0
  88. package/chunks/{chunk-6EOI4HOK.js → chunk-M3STHEMM.js} +12 -17
  89. package/chunks/chunk-NGYI5EF5.js +244 -0
  90. package/chunks/{chunk-ALGGS7UH.js → chunk-NPQ5ZKRP.js} +82 -1
  91. package/chunks/{chunk-HQB2KUAN.js → chunk-NPUXXRJI.js} +1 -1
  92. package/chunks/{chunk-QETYKPMG.js → chunk-NVRDQFCX.js} +1 -1
  93. package/chunks/{chunk-PQBHU2IA.js → chunk-OHKJVAKG.js} +10 -10
  94. package/chunks/{chunk-CYR3HI5X.js → chunk-OQTXYMKW.js} +2 -2
  95. package/chunks/{chunk-DBOFL3LQ.js → chunk-PG62DFWD.js} +10 -10
  96. package/chunks/{chunk-2VSTGY6M.js → chunk-PJRW65JO.js} +1 -1
  97. package/chunks/{chunk-33ACCIIY.js → chunk-PLFATELK.js} +1 -1
  98. package/chunks/{chunk-IC4Z6LX6.js → chunk-PYQADEFD.js} +5 -0
  99. package/chunks/{chunk-MAJS7AT4.js → chunk-QGHSP65Z.js} +2 -2
  100. package/chunks/{chunk-OHJLEW5J.js → chunk-QQWD7LZV.js} +4 -4
  101. package/chunks/{chunk-ZXU5UHMI.js → chunk-QXVSWG66.js} +2 -2
  102. package/chunks/{chunk-E33LOKRA.js → chunk-RPWVIXDB.js} +18 -1
  103. package/chunks/{chunk-TYKC75AX.js → chunk-S3Y3GBFD.js} +1 -1
  104. package/chunks/{chunk-7UFKAV7Y.js → chunk-S6HYI3MF.js} +2 -2
  105. package/chunks/chunk-SAH4BD2J.js +92 -0
  106. package/chunks/{chunk-OMKQH5C5.js → chunk-SNRT2TJJ.js} +6 -23
  107. package/chunks/chunk-SR7RZ4MS.js +202 -0
  108. package/chunks/{chunk-CXE7E23H.js → chunk-TE3ZAJE7.js} +45 -17
  109. package/chunks/{chunk-S7CV4KO6.js → chunk-TKSZJ5BV.js} +3 -3
  110. package/chunks/{chunk-3NB7TSE2.js → chunk-U5SLIG7E.js} +1 -1
  111. package/chunks/chunk-UA5H3DS2.js +203 -0
  112. package/chunks/{chunk-24ER7UV4.js → chunk-UFALT4LK.js} +1 -1
  113. package/chunks/{chunk-YJQCUTT2.js → chunk-VWMUDKLC.js} +3 -3
  114. package/chunks/{chunk-RMH5OWLD.js → chunk-VXZ5HAOV.js} +1 -1
  115. package/chunks/{chunk-BVWVWGLE.js → chunk-WAUGQKUU.js} +4 -64
  116. package/chunks/{chunk-SHZYHGQH.js → chunk-WG6542MA.js} +1 -1
  117. package/chunks/{chunk-5KH532V7.js → chunk-WV5J6Q6N.js} +1 -1
  118. package/chunks/{chunk-RNVQB725.js → chunk-XHD7CRP2.js} +2 -2
  119. package/chunks/{chunk-W4B7UBUS.js → chunk-XZKQT2B2.js} +5 -5
  120. package/chunks/{chunk-6HVUFDS2.js → chunk-Y4TETC74.js} +22 -13
  121. package/chunks/{chunk-RZHU3ILK.js → chunk-YEF7XEO2.js} +4 -4
  122. package/chunks/{chunk-RUL4S3K3.js → chunk-YHJFF7KH.js} +146 -45
  123. package/chunks/{chunk-23RZCH76.js → chunk-YOM7DEGB.js} +3 -3
  124. package/chunks/{chunk-OFI7IGST.js → chunk-ZCLLJARV.js} +9 -9
  125. package/chunks/{chunk-GSS34377.js → chunk-ZHA242R4.js} +2 -2
  126. package/chunks/{chunk-TRLYP7OF.js → chunk-ZPLALRXZ.js} +17 -9
  127. package/chunks/{chunk-WUC6ZFXO.js → chunk-ZWBUH5UP.js} +1 -1
  128. package/chunks/{computer-use-KEAPATUY.js → computer-use-ESQYJ3JY.js} +26 -22
  129. package/chunks/{config-utils-K7SCOWHD.js → config-utils-XQHBJP7G.js} +4 -4
  130. package/chunks/{contextCommand-ZJA6A5K5.js → contextCommand-CX3YF4ZE.js} +28 -24
  131. package/chunks/{core-runtime-QMJPWHCI.js → core-runtime-DIAU7JMG.js} +30 -26
  132. package/chunks/{create-sub-session-DJE6XICH.js → create-sub-session-HDPD6HOA.js} +26 -22
  133. package/chunks/{create-sub-session-E4PBYXV5.js → create-sub-session-QIDZUOPU.js} +1 -1
  134. package/chunks/{cron-create-GRBWYMIJ.js → cron-create-VONA5JYY.js} +1 -1
  135. package/chunks/{cron-delete-4CMKBR2M.js → cron-delete-5JXSP2MI.js} +1 -1
  136. package/chunks/{cron-list-W7K4ASOA.js → cron-list-KE4F2CIR.js} +1 -1
  137. package/chunks/{daemon-SCTQMM7Z.js → daemon-VZBGJUNL.js} +30 -0
  138. package/chunks/{daemon-status-provider-FSWDPE2G.js → daemon-status-provider-H6O4UQ4F.js} +33 -29
  139. package/chunks/{daemon-trust-policy-P5L5VFAY.js → daemon-trust-policy-BNUXG6MT.js} +33 -29
  140. package/chunks/{daemon-trust-policy-monitor-73JYN6ET.js → daemon-trust-policy-monitor-E4EQ7GF4.js} +33 -29
  141. package/chunks/{de-VL76CPLV.js → de-LIW4XVLN.js} +5 -0
  142. package/chunks/{deferred-core-runtime-BWRCCFTE.js → deferred-core-runtime-CBMSHPAU.js} +26 -22
  143. package/chunks/{display-image-O2XFPQTC.js → display-image-NQRSIBXM.js} +2 -2
  144. package/chunks/{dist-DPPHJAVL.js → dist-EEEQGCZA.js} +918 -142
  145. package/chunks/{dist-K4WWQBHS.js → dist-HIACTZEK.js} +55 -15
  146. package/chunks/{dist-3BMEUGTG.js → dist-IRL7WA5Z.js} +1 -1
  147. package/chunks/{dist-HVBMEYWK.js → dist-KVISB2O2.js} +1 -1
  148. package/chunks/{dist-KS4O2NKE.js → dist-MBF3I5MX.js} +14 -8
  149. package/chunks/{dist-SFQ34F4M.js → dist-MKX5OSFF.js} +5 -4
  150. package/chunks/{dist-7JGAAQSC.js → dist-RCH3I7SS.js} +2 -2
  151. package/chunks/{dist-C5U4LJKW.js → dist-TUSWNE2I.js} +5 -4
  152. package/chunks/{earlyInputCapture-L5ST23A6.js → earlyInputCapture-UIOP7OIN.js} +26 -22
  153. package/chunks/{edit-LHHRFNFK.js → edit-ITMZYFKA.js} +26 -22
  154. package/chunks/{en-IRJ2WN5T.js → en-SY5GTIGX.js} +6 -0
  155. package/chunks/{enter-worktree-6NXCRZPF.js → enter-worktree-S4PL5UV6.js} +26 -22
  156. package/chunks/{enterPlanMode-ZVQT4U7D.js → enterPlanMode-YV52NNJT.js} +26 -22
  157. package/chunks/{environment-GJ2HWJOS.js → environment-NGOWPRZV.js} +30 -26
  158. package/chunks/{errors-6RLH3XXC.js → errors-BU26DTDX.js} +28 -24
  159. package/chunks/{exit-worktree-I2YLUHHY.js → exit-worktree-XRM6LH5F.js} +26 -22
  160. package/chunks/{exitPlanMode-7CCWKO7I.js → exitPlanMode-ZLI5F7KR.js} +26 -22
  161. package/chunks/{fast-path-DVFD4HQD.js → fast-path-UJWORIED.js} +23 -3
  162. package/chunks/{fast-path-settings-WQJU2LAT.js → fast-path-settings-37WQD5B2.js} +6 -3
  163. package/chunks/{fr-GK3HQYVB.js → fr-RQFO7U4P.js} +5 -0
  164. package/chunks/{gemini-7FWGOYD4.js → gemini-ZSKNDUMU.js} +77 -65
  165. package/chunks/{geminiContentGenerator-V2WVLIXU.js → geminiContentGenerator-YGEXOEKD.js} +1 -1
  166. package/chunks/{glob-3N6GGI75.js → glob-7KZG44BR.js} +26 -22
  167. package/chunks/{goal-tools-APOW6UXL.js → goal-tools-PXWN5VK3.js} +4 -2
  168. package/chunks/{grep-V43ILZVX.js → grep-6ZFC7RJ5.js} +26 -22
  169. package/chunks/{handleAutoUpdate-A5WFVWIA.js → handleAutoUpdate-KSEL3TQS.js} +30 -26
  170. package/chunks/{i18n-PLVQ4FBZ.js → i18n-ZIUXBW5V.js} +27 -23
  171. package/chunks/{image-gen-7C6IK6DC.js → image-gen-AUIZJJNK.js} +7 -5
  172. package/chunks/{initializer-CVAIKZYL.js → initializer-7AHY3N6Q.js} +33 -29
  173. package/chunks/{installationInfo-J6QDHNTK.js → installationInfo-VGBXMYLY.js} +27 -23
  174. package/chunks/{ja-3FA46IKD.js → ja-KOZKHJHZ.js} +5 -0
  175. package/chunks/{list-ZZ4OUUWV.js → list-PSFKQHLB.js} +36 -32
  176. package/chunks/{list-agents-KFFIIS2G.js → list-agents-Z4WABFDZ.js} +1 -1
  177. package/chunks/{loadedSettingsAdapter-QRYRJSWL.js → loadedSettingsAdapter-FTMRCTOF.js} +33 -29
  178. package/chunks/{loggingContentGenerator-OJCO75HM.js → loggingContentGenerator-MZAN52UV.js} +7 -5
  179. package/chunks/{loop-wakeup-TLMJPMMP.js → loop-wakeup-UZ5RL5Y2.js} +2 -2
  180. package/chunks/{ls-UVVE2XGE.js → ls-TVHDGIES.js} +1 -1
  181. package/chunks/{lsp-QMEA2VLB.js → lsp-CVN6OQPI.js} +1 -1
  182. package/chunks/{managed-npm-update-PCOSCP2N.js → managed-npm-update-O4NHK45X.js} +27 -23
  183. package/chunks/{mcp-M3WKKWKY.js → mcp-6CFP2AYQ.js} +33 -29
  184. package/chunks/{monitor-GN24FH6C.js → monitor-DAKD6OU4.js} +26 -22
  185. package/chunks/{nonInteractiveCli-KPTU3VSQ.js → nonInteractiveCli-RC7VIUZL.js} +66 -60
  186. package/chunks/{notebook-edit-4YM65BBO.js → notebook-edit-474DPMRL.js} +34 -22
  187. package/chunks/{openaiContentGenerator-EDQT6GTV.js → openaiContentGenerator-2NFY2MWO.js} +19 -9
  188. package/chunks/{pidfile-JOIIRN2C.js → pidfile-KBFVDNQP.js} +26 -22
  189. package/chunks/{process-registry-2CHQBXH5.js → process-registry-PMJOA5CO.js} +15 -0
  190. package/chunks/{processUtils-5SV4MX3Q.js → processUtils-6GRYH4Y3.js} +2 -2
  191. package/chunks/{pt-3AOBKPIJ.js → pt-U6AOCTMF.js} +5 -0
  192. package/chunks/{qwenContentGenerator-ODRJSUGR.js → qwenContentGenerator-KAHU6IZY.js} +33 -28
  193. package/chunks/{qwenOAuth2-NESCMZ47.js → qwenOAuth2-RRQTCP4W.js} +7 -5
  194. package/chunks/{read-file-HPSODLPK.js → read-file-3M6WXDXP.js} +6 -4
  195. package/chunks/{read-mcp-resource-2TNSJTC3.js → read-mcp-resource-PZ4ZF6YL.js} +1 -1
  196. package/chunks/{record-artifact-RAON52FC.js → record-artifact-P4HFMS7X.js} +2 -2
  197. package/chunks/{resumeHistoryUtils-TXCOFFMQ.js → resumeHistoryUtils-D6TAY3HX.js} +30 -26
  198. package/chunks/{ripGrep-ZKQGTQAO.js → ripGrep-PLPENT3E.js} +26 -22
  199. package/chunks/{ru-VJRAMC4W.js → ru-CMX4UMYP.js} +5 -0
  200. package/chunks/{run-qwen-serve-ZPKPKECF.js → run-qwen-serve-ZAFIJKJC.js} +168 -54
  201. package/chunks/{runtime-2FLNNM36.js → runtime-ZED7CYOZ.js} +38 -34
  202. package/chunks/{scheduler-365PJHNR.js → scheduler-MD3AL2W5.js} +26 -22
  203. package/chunks/{send-message-ZM7MRUGP.js → send-message-CAMSLG2L.js} +4 -3
  204. package/chunks/{serve-QD2RNLKJ.js → serve-E3VUDRZN.js} +33 -29
  205. package/chunks/{server-XLJVLTYM.js → server-OWMEMAKR.js} +450 -231
  206. package/chunks/{session-3VTUHH4Q.js → session-HZ57QK7K.js} +158 -97
  207. package/chunks/{settings-KULVPCQC.js → settings-V7BR3RKP.js} +32 -28
  208. package/chunks/{shell-3SWW22MH.js → shell-23OMNMW6.js} +26 -22
  209. package/chunks/{skill-KDHWYS7W.js → skill-6HBDYZRS.js} +7 -5
  210. package/chunks/{skill-settings-NMY4JEJC.js → skill-settings-HWJLTU7M.js} +32 -28
  211. package/chunks/{spawnChannel-ZKS4Q5OU.js → spawnChannel-N6KKUW5B.js} +27 -23
  212. package/chunks/{standalone-update-7CXPGAQ4.js → standalone-update-QGIKHATD.js} +28 -24
  213. package/chunks/{startInteractiveUI-2QQLEKM6.js → startInteractiveUI-GX2CRL42.js} +365 -155
  214. package/chunks/{syntheticOutput-ZLCUTKO2.js → syntheticOutput-PEBJQYJV.js} +2 -2
  215. package/chunks/{task-create-CQP5UEA3.js → task-create-5NWCQSJF.js} +5 -4
  216. package/chunks/{task-list-XLEZOJXP.js → task-list-53265TRZ.js} +1 -1
  217. package/chunks/{task-stop-7ZQM5CFF.js → task-stop-FPCOIRYX.js} +1 -1
  218. package/chunks/{task-update-JA75U2SN.js → task-update-5HN577LS.js} +5 -4
  219. package/chunks/{team-create-2WTNGAOX.js → team-create-CFFKU7KL.js} +26 -22
  220. package/chunks/{team-delete-MHY3UZGY.js → team-delete-MMQB4OSC.js} +1 -1
  221. package/chunks/{team-plan-approval-LZTYLEG4.js → team-plan-approval-6EFOKR6A.js} +26 -22
  222. package/chunks/{terminal-image-renderer-R5HHAFJN.js → terminal-image-renderer-TLDNACQY.js} +28 -24
  223. package/chunks/{theme-manager-PAUCSJFF.js → theme-manager-5LJ3H7VO.js} +26 -22
  224. package/chunks/{todoWrite-UPVOHYGD.js → todoWrite-JGV6VLOX.js} +1 -1
  225. package/chunks/{tool-search-2BFCGLI6.js → tool-search-UJV3A24H.js} +9 -6
  226. package/chunks/{total-session-admission-MK4SINFK.js → total-session-admission-D63QYXGO.js} +29 -25
  227. package/chunks/{trustedFolders-TJ5S26N7.js → trustedFolders-KZCOB53W.js} +30 -24
  228. package/chunks/{update-relaunch-N7AYLARF.js → update-relaunch-IFILM3SA.js} +5 -5
  229. package/chunks/{updateCheck-QRZ3DVT5.js → updateCheck-YZ2CRCFC.js} +29 -25
  230. package/chunks/{useAutoAcceptIndicator-DBJ7Y5AF.js → useAutoAcceptIndicator-AXEVNA3Q.js} +35 -31
  231. package/chunks/{validateNonInterActiveAuth-6ZQWUDS3.js → validateNonInterActiveAuth-3WTOJFWA.js} +61 -57
  232. package/chunks/{version-AJQGQWXC.js → version-GXK7OHZY.js} +1 -1
  233. package/chunks/{web-fetch-QWJYRXFL.js → web-fetch-ILB4GAVR.js} +12 -8
  234. package/chunks/{web-search-2AOXJGHU.js → web-search-HKRPGPZZ.js} +8 -6
  235. package/chunks/{workflow-ERH3SJG2.js → workflow-FXIPRQQA.js} +750 -147
  236. package/chunks/{workspace-providers-status-HZ474RA4.js → workspace-providers-status-NYHC7HSR.js} +35 -31
  237. package/chunks/{workspace-registration-store-6EUP4JXG.js → workspace-registration-store-AKEB7OMW.js} +1 -1
  238. package/chunks/{workspace-registry-R4APRRNC.js → workspace-registry-CDAS5TVZ.js} +29 -25
  239. package/chunks/{workspace-service-HFIFDMU7.js → workspace-service-PAMUKMAV.js} +36 -32
  240. package/chunks/{workspace-skills-status-HAHEIHGK.js → workspace-skills-status-YQSHCCMS.js} +33 -29
  241. package/chunks/{workspace-trust-reconciler-65GTAGDK.js → workspace-trust-reconciler-RPTXOIY2.js} +36 -32
  242. package/chunks/{write-file-B34CDELV.js → write-file-CGS57TS4.js} +26 -22
  243. package/chunks/{zh-ARWDLDLR.js → zh-AGL2FVBI.js} +6 -0
  244. package/chunks/{zh-TW-Y4RGI3P7.js → zh-TW-KI66MHQY.js} +6 -0
  245. package/chunks/{zoom-image-HPRBZHSS.js → zoom-image-E7D72GYV.js} +6 -4
  246. package/cli.js +13 -13
  247. package/locales/ca.js +10 -0
  248. package/locales/de.js +9 -0
  249. package/locales/en.js +10 -0
  250. package/locales/fr.js +9 -0
  251. package/locales/ja.js +9 -0
  252. package/locales/pt.js +9 -0
  253. package/locales/ru.js +9 -0
  254. package/locales/zh-TW.js +10 -0
  255. package/locales/zh.js +10 -0
  256. package/package.json +3 -3
  257. package/web-shell/assets/{arc-Ip-FFDJ0.js → arc-DybZaz32.js} +1 -1
  258. package/web-shell/assets/{architectureDiagram-3BPJPVTR-CChqgwIb.js → architectureDiagram-3BPJPVTR-jN3qBd19.js} +1 -1
  259. package/web-shell/assets/{blockDiagram-GPEHLZMM-BHN-Tfss.js → blockDiagram-GPEHLZMM-Ct5DZPrj.js} +1 -1
  260. package/web-shell/assets/{c4Diagram-AAUBKEIU-BhyjzDjN.js → c4Diagram-AAUBKEIU-CUAFMlUG.js} +1 -1
  261. package/web-shell/assets/channel-BMwLrwLW.js +1 -0
  262. package/web-shell/assets/{chunk-2J33WTMH-BB9eyHrx.js → chunk-2J33WTMH-CuV8n90B.js} +1 -1
  263. package/web-shell/assets/{chunk-4BX2VUAB-BeV7ce_J.js → chunk-4BX2VUAB-BUzl_kls.js} +1 -1
  264. package/web-shell/assets/{chunk-55IACEB6-DO7kXDiV.js → chunk-55IACEB6-BnDBLX6A.js} +1 -1
  265. package/web-shell/assets/{chunk-727SXJPM-B27MPznD.js → chunk-727SXJPM-B83uTOjm.js} +1 -1
  266. package/web-shell/assets/{chunk-AQP2D5EJ-DHIjqjD_.js → chunk-AQP2D5EJ-DM3HLgpT.js} +1 -1
  267. package/web-shell/assets/{chunk-FMBD7UC4-DabMqyN2.js → chunk-FMBD7UC4-CSQ5hgyb.js} +1 -1
  268. package/web-shell/assets/{chunk-ND2GUHAM-Dw7Nnnxc.js → chunk-ND2GUHAM-BWOF4SxX.js} +1 -1
  269. package/web-shell/assets/{chunk-QZHKN3VN-DdaZew1Q.js → chunk-QZHKN3VN-BsOH9LMi.js} +1 -1
  270. package/web-shell/assets/classDiagram-4FO5ZUOK-BGDv98jY.js +1 -0
  271. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BGDv98jY.js +1 -0
  272. package/web-shell/assets/{cose-bilkent-S5V4N54A-CgBpCYH5.js → cose-bilkent-S5V4N54A-IENqH2iJ.js} +1 -1
  273. package/web-shell/assets/{dagre-BM42HDAG-BB4IU8G0.js → dagre-BM42HDAG--dyzDTGo.js} +1 -1
  274. package/web-shell/assets/{diagram-2AECGRRQ-BcUTHU37.js → diagram-2AECGRRQ-BE7Dcqof.js} +1 -1
  275. package/web-shell/assets/{diagram-5GNKFQAL-B6Lyihyv.js → diagram-5GNKFQAL-Cr8-5OTj.js} +1 -1
  276. package/web-shell/assets/{diagram-KO2AKTUF-CRIJOjpG.js → diagram-KO2AKTUF-Bzey3uAY.js} +1 -1
  277. package/web-shell/assets/{diagram-LMA3HP47-DdNiwWWT.js → diagram-LMA3HP47-sErl28Xb.js} +1 -1
  278. package/web-shell/assets/{diagram-OG6HWLK6-Dz4b32Do.js → diagram-OG6HWLK6-Dq30ATIo.js} +1 -1
  279. package/web-shell/assets/{erDiagram-TEJ5UH35-D-8NGw77.js → erDiagram-TEJ5UH35-BkCoEfVW.js} +1 -1
  280. package/web-shell/assets/{flowDiagram-I6XJVG4X-Dun26LyM.js → flowDiagram-I6XJVG4X-DHwO0rrI.js} +1 -1
  281. package/web-shell/assets/{ganttDiagram-6RSMTGT7-F10Hu1Gc.js → ganttDiagram-6RSMTGT7-s7vAPxWq.js} +1 -1
  282. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Bf8Ez6-D.js → gitGraphDiagram-PVQCEYII-CQxhwPOU.js} +1 -1
  283. package/web-shell/assets/index-Bckpjr-I.css +5 -0
  284. package/web-shell/assets/{index-BXqw-nGq.js → index-CF4wApWp.js} +1 -1
  285. package/web-shell/assets/index-DwEr9HEW.js +1768 -0
  286. package/web-shell/assets/{infoDiagram-5YYISTIA-DVgTMLvj.js → infoDiagram-5YYISTIA-BnFrD0bq.js} +1 -1
  287. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-uT-KepvK.js → ishikawaDiagram-YF4QCWOH-Bf9zK5NK.js} +1 -1
  288. package/web-shell/assets/{journeyDiagram-JHISSGLW-Vg_XadQf.js → journeyDiagram-JHISSGLW-CyGAhsxi.js} +1 -1
  289. package/web-shell/assets/{kanban-definition-UN3LZRKU-Dyv1ESBE.js → kanban-definition-UN3LZRKU-CbsK5akB.js} +1 -1
  290. package/web-shell/assets/{linear-BMIepYX3.js → linear-cQsF4P8D.js} +1 -1
  291. package/web-shell/assets/{mermaid.core-zA8pJ9ag.js → mermaid.core-Z4HVqrKY.js} +5 -5
  292. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BCW_BZ_5.js → mindmap-definition-RKZ34NQL-CYnrBo_f.js} +1 -1
  293. package/web-shell/assets/{pieDiagram-4H26LBE5-DseNEGp2.js → pieDiagram-4H26LBE5-CBzOfhrs.js} +1 -1
  294. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-6Z7wr1Fi.js → quadrantDiagram-W4KKPZXB-D4LK1Ebn.js} +1 -1
  295. package/web-shell/assets/{requirementDiagram-4Y6WPE33-CVOlCRPf.js → requirementDiagram-4Y6WPE33-Bzti2Lcj.js} +1 -1
  296. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CGhgrUJZ.js → sankeyDiagram-5OEKKPKP-yTBw5Z2s.js} +1 -1
  297. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-dlqmpLuQ.js → sequenceDiagram-3UESZ5HK-D07UVRiZ.js} +1 -1
  298. package/web-shell/assets/{stateDiagram-AJRCARHV-B9EW10Xb.js → stateDiagram-AJRCARHV-UE_lHsTn.js} +1 -1
  299. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DC6xgXjX.js +1 -0
  300. package/web-shell/assets/{timeline-definition-PNZ67QCA-BBRh0mgZ.js → timeline-definition-PNZ67QCA-DRvYdiTs.js} +1 -1
  301. package/web-shell/assets/{vennDiagram-CIIHVFJN-B8Gs-REP.js → vennDiagram-CIIHVFJN-CQLIXs0u.js} +1 -1
  302. package/web-shell/assets/{wardley-L42UT6IY-D_y80Ur7.js → wardley-L42UT6IY-JZz_Xqse.js} +1 -1
  303. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-D-CNfHJ-.js → wardleyDiagram-YWT4CUSO--i7BiJwB.js} +1 -1
  304. package/web-shell/assets/{xychartDiagram-2RQKCTM6-DQ5CvELo.js → xychartDiagram-2RQKCTM6-Bkc-bW0S.js} +1 -1
  305. package/web-shell/index.html +2 -2
  306. package/chunks/chunk-6PEXNQTX.js +0 -68
  307. package/chunks/chunk-IUFV6FYU.js +0 -81
  308. package/web-shell/assets/channel-Cu8qd6OB.js +0 -1
  309. package/web-shell/assets/classDiagram-4FO5ZUOK-BI3KrXhq.js +0 -1
  310. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BI3KrXhq.js +0 -1
  311. package/web-shell/assets/index-QQlUCJGg.css +0 -5
  312. package/web-shell/assets/index-hcgjV7vS.js +0 -1768
  313. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CJTZJJ5X.js +0 -1
  314. package/chunks/{anthropicContentGenerator-DTMVEL5M.js → anthropicContentGenerator-SSFE2753.js} +9 -9
@@ -14,8 +14,9 @@ import {
14
14
  ChannelBase,
15
15
  ChannelProactiveDeliveryError,
16
16
  isChannelProactiveDeliveryError,
17
- isTerminalTaskLifecycleType
18
- } from "./chunk-DIEFUBV6.js";
17
+ isTerminalTaskLifecycleType,
18
+ sanitizeSenderName
19
+ } from "./chunk-DIWZNWZT.js";
19
20
  import "./chunk-UDXSXLER.js";
20
21
  import "./chunk-H6XPXXMH.js";
21
22
  import {
@@ -88996,8 +88997,443 @@ async function downloadMedia(messageId, fileKey, resourceType, accessToken) {
88996
88997
  }
88997
88998
  __name(downloadMedia, "downloadMedia");
88998
88999
 
89000
+ // packages/channels/feishu/dist/question-card-controller.js
89001
+ init_esbuild_shims();
89002
+
89003
+ // packages/channels/feishu/dist/question-card.js
89004
+ init_esbuild_shims();
89005
+ var terminalLabels = {
89006
+ processing: "\u6B63\u5728\u5904\u7406...",
89007
+ submitted: "\u5DF2\u63D0\u4EA4",
89008
+ cancelled: "\u5DF2\u53D6\u6D88",
89009
+ expired: "\u5DF2\u8FC7\u671F"
89010
+ };
89011
+ function buildQuestionCard(context) {
89012
+ const elements = [];
89013
+ for (const question of context.questions) {
89014
+ const descriptions = question.options.map((option) => `> **${option.label}**: ${option.description}`).join("\n");
89015
+ elements.push({
89016
+ tag: "markdown",
89017
+ text_size: "notation",
89018
+ content: `**${question.header}**
89019
+ > ${question.question}
89020
+
89021
+ ${descriptions}`
89022
+ });
89023
+ elements.push({
89024
+ tag: question.multiSelect ? "multi_select_static" : "select_static",
89025
+ name: question.answerKey,
89026
+ options: question.options.map((option) => ({
89027
+ text: { tag: "plain_text", content: option.label },
89028
+ value: option.label
89029
+ }))
89030
+ });
89031
+ }
89032
+ elements.push({
89033
+ tag: "button",
89034
+ text: { tag: "plain_text", content: "\u63D0\u4EA4" },
89035
+ type: "primary",
89036
+ name: `qwen_ask_submit_${context.requestId}`,
89037
+ form_action_type: "submit",
89038
+ value: {
89039
+ action: "qwen_ask_submit",
89040
+ operation_id: context.requestId
89041
+ }
89042
+ }, {
89043
+ tag: "button",
89044
+ text: { tag: "plain_text", content: "\u53D6\u6D88" },
89045
+ name: `qwen_ask_cancel_${context.requestId}`,
89046
+ value: {
89047
+ action: "qwen_ask_cancel",
89048
+ operation_id: context.requestId
89049
+ }
89050
+ });
89051
+ return {
89052
+ schema: "2.0",
89053
+ body: { elements: [{ tag: "form", name: "qwen_ask_form", elements }] }
89054
+ };
89055
+ }
89056
+ __name(buildQuestionCard, "buildQuestionCard");
89057
+ function buildQuestionTerminalCard(questions, state, answers) {
89058
+ const details = questions.map((question) => {
89059
+ const answer = answers?.[question.answerKey];
89060
+ return answer ? `**${question.header}**
89061
+ ${answer}` : `**${question.header}**
89062
+ ${question.question}`;
89063
+ }).join("\n\n");
89064
+ return {
89065
+ schema: "2.0",
89066
+ body: {
89067
+ elements: [
89068
+ {
89069
+ tag: "markdown",
89070
+ content: `**${terminalLabels[state]}**
89071
+
89072
+ ${details}`
89073
+ }
89074
+ ]
89075
+ }
89076
+ };
89077
+ }
89078
+ __name(buildQuestionTerminalCard, "buildQuestionTerminalCard");
89079
+ function record(value) {
89080
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
89081
+ return void 0;
89082
+ }
89083
+ return value;
89084
+ }
89085
+ __name(record, "record");
89086
+ function nonEmptyString(value) {
89087
+ return typeof value === "string" && value ? value : void 0;
89088
+ }
89089
+ __name(nonEmptyString, "nonEmptyString");
89090
+ function parseQuestionAction(data) {
89091
+ const payload = record(data);
89092
+ const action = record(payload?.["action"]);
89093
+ const rawValue = action?.["value"];
89094
+ const value = record(rawValue);
89095
+ let requestId = nonEmptyString(value?.["operation_id"]);
89096
+ let actionId = nonEmptyString(value?.["action"]);
89097
+ const name = action?.["name"];
89098
+ if (rawValue === void 0 && typeof name === "string" && name.startsWith("qwen_ask_submit_")) {
89099
+ requestId = nonEmptyString(name.slice("qwen_ask_submit_".length));
89100
+ actionId = requestId ? "qwen_ask_submit" : void 0;
89101
+ }
89102
+ if (rawValue === void 0 && typeof name === "string" && name.startsWith("qwen_ask_cancel_")) {
89103
+ requestId = nonEmptyString(name.slice("qwen_ask_cancel_".length));
89104
+ actionId = requestId ? "qwen_ask_cancel" : void 0;
89105
+ }
89106
+ if (!requestId || !actionId || typeof name !== "string") {
89107
+ return { kind: "unhandled" };
89108
+ }
89109
+ const operator = record(payload?.["operator"]);
89110
+ const operatorId = nonEmptyString(operator?.["open_id"]);
89111
+ const operatorResult = operatorId ? { operatorId } : void 0;
89112
+ const context = record(payload?.["context"]);
89113
+ const chatId = nonEmptyString(context?.["open_chat_id"]) ?? nonEmptyString(payload?.["open_chat_id"]);
89114
+ const messageId = nonEmptyString(context?.["open_message_id"]) ?? nonEmptyString(payload?.["open_message_id"]);
89115
+ const correlation = {
89116
+ ...chatId ? { chatId } : {},
89117
+ ...messageId ? { messageId } : {}
89118
+ };
89119
+ if (actionId === "qwen_ask_submit" && name === `qwen_ask_submit_${requestId}`) {
89120
+ const formValue = record(action?.["form_value"]);
89121
+ return {
89122
+ kind: "submit",
89123
+ requestId,
89124
+ ...operatorResult,
89125
+ ...correlation,
89126
+ ...formValue ? { formValue } : {}
89127
+ };
89128
+ }
89129
+ if (actionId === "qwen_ask_cancel" && name === `qwen_ask_cancel_${requestId}`) {
89130
+ return { kind: "cancel", requestId, ...operatorResult, ...correlation };
89131
+ }
89132
+ return { kind: "unhandled" };
89133
+ }
89134
+ __name(parseQuestionAction, "parseQuestionAction");
89135
+ function parseQuestionAnswers(questions, formValue) {
89136
+ if (!formValue)
89137
+ return void 0;
89138
+ const answerKeys = new Set(questions.map((question) => question.answerKey));
89139
+ const submittedKeys = Object.keys(formValue);
89140
+ if (submittedKeys.length !== questions.length || submittedKeys.some((key) => !answerKeys.has(key))) {
89141
+ return void 0;
89142
+ }
89143
+ const answers = {};
89144
+ for (const question of questions) {
89145
+ const rawAnswer = formValue[question.answerKey];
89146
+ let values;
89147
+ if (question.multiSelect) {
89148
+ if (Array.isArray(rawAnswer)) {
89149
+ values = rawAnswer;
89150
+ } else if (typeof rawAnswer === "string") {
89151
+ try {
89152
+ const parsed = JSON.parse(rawAnswer);
89153
+ if (!Array.isArray(parsed))
89154
+ return void 0;
89155
+ values = parsed;
89156
+ } catch {
89157
+ return void 0;
89158
+ }
89159
+ } else {
89160
+ return void 0;
89161
+ }
89162
+ } else if (typeof rawAnswer === "string" && rawAnswer) {
89163
+ values = [rawAnswer];
89164
+ } else {
89165
+ return void 0;
89166
+ }
89167
+ if (values.length === 0 || !question.multiSelect && values.length !== 1 || question.multiSelect && new Set(values).size !== values.length || values.some((value) => typeof value !== "string" || !question.options.some((option) => option.label === value))) {
89168
+ return void 0;
89169
+ }
89170
+ answers[question.answerKey] = values.join(", ");
89171
+ }
89172
+ return answers;
89173
+ }
89174
+ __name(parseQuestionAnswers, "parseQuestionAnswers");
89175
+
89176
+ // packages/channels/feishu/dist/question-card-controller.js
89177
+ var FeishuQuestionCardController = class {
89178
+ static {
89179
+ __name(this, "FeishuQuestionCardController");
89180
+ }
89181
+ options;
89182
+ byRequest = /* @__PURE__ */ new Map();
89183
+ activeByScope = /* @__PURE__ */ new Map();
89184
+ disposed = false;
89185
+ constructor(options) {
89186
+ this.options = options;
89187
+ }
89188
+ async present(context) {
89189
+ if (this.disposed)
89190
+ return { kind: "unsupported" };
89191
+ const scopeKey = this.scopeKey(context);
89192
+ const active = this.activeByScope.get(scopeKey);
89193
+ if (active && active.state !== "terminal")
89194
+ return { kind: "unsupported" };
89195
+ const record2 = {
89196
+ context,
89197
+ requestId: context.requestId,
89198
+ runId: context.runId,
89199
+ ownerId: context.owner.id,
89200
+ chatId: context.target.chatId,
89201
+ scopeKey,
89202
+ state: "reserved"
89203
+ };
89204
+ this.byRequest.set(context.requestId, record2);
89205
+ this.activeByScope.set(scopeKey, record2);
89206
+ const unsubscribe = context.onSettled((reason) => {
89207
+ if (record2.state !== "claimed" || !record2.responding) {
89208
+ void this.finalize(record2, reason === "resolved_outside_presenter" ? "expired" : "cancelled");
89209
+ }
89210
+ });
89211
+ record2.unsubscribe = unsubscribe;
89212
+ if (record2.state === "terminal") {
89213
+ unsubscribe();
89214
+ record2.unsubscribe = void 0;
89215
+ return { kind: "presented" };
89216
+ }
89217
+ try {
89218
+ const messageId = await this.options.sendCard(record2.chatId, buildQuestionCard(context));
89219
+ if (!messageId)
89220
+ throw new Error("Feishu card delivery returned no message id");
89221
+ if (record2.state !== "reserved" || this.byRequest.get(record2.requestId) !== record2 || this.activeByScope.get(record2.scopeKey) !== record2) {
89222
+ await this.projectTerminal(record2, messageId);
89223
+ return { kind: "presented" };
89224
+ }
89225
+ record2.messageId = messageId;
89226
+ } catch (error) {
89227
+ if (this.isTerminated(record2))
89228
+ return { kind: "presented" };
89229
+ this.options.onError?.("question card delivery", error);
89230
+ await this.finalize(record2, "cancelled");
89231
+ try {
89232
+ await this.options.sendFallback(record2.chatId, this.fallbackText(record2.context));
89233
+ } catch (fallbackError) {
89234
+ this.options.onError?.("question fallback delivery", fallbackError);
89235
+ }
89236
+ try {
89237
+ await context.respond({ outcome: { outcome: "cancelled" } });
89238
+ } catch (respondError) {
89239
+ this.options.onError?.("question delivery cancellation", respondError);
89240
+ }
89241
+ return { kind: "handled" };
89242
+ }
89243
+ record2.state = "pending";
89244
+ record2.timer = setTimeout(() => {
89245
+ void this.expire(record2);
89246
+ }, this.options.timeoutMs);
89247
+ record2.timer.unref?.();
89248
+ return { kind: "presented" };
89249
+ }
89250
+ claim(data) {
89251
+ const action = parseQuestionAction(data);
89252
+ if (action.kind === "unhandled")
89253
+ return { kind: "unhandled" };
89254
+ const record2 = this.byRequest.get(action.requestId);
89255
+ if (!record2 || record2.state !== "pending")
89256
+ return this.expiredResponse();
89257
+ if (!action.operatorId || !action.chatId || !action.messageId || action.operatorId !== record2.ownerId || action.chatId !== record2.chatId || action.messageId !== record2.messageId) {
89258
+ return this.expiredResponse();
89259
+ }
89260
+ if (action.kind === "submit") {
89261
+ const answers = parseQuestionAnswers(record2.context.questions, action.formValue);
89262
+ if (!answers) {
89263
+ return {
89264
+ kind: "handled",
89265
+ response: {
89266
+ toast: { type: "warning", content: "\u8BF7\u5B8C\u6574\u9009\u62E9\u6709\u6548\u7B54\u6848\u3002" }
89267
+ }
89268
+ };
89269
+ }
89270
+ this.markClaimed(record2);
89271
+ return {
89272
+ kind: "handled",
89273
+ response: {
89274
+ toast: { type: "success", content: "\u7B54\u6848\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u5904\u7406\u3002" },
89275
+ card: {
89276
+ type: "raw",
89277
+ data: buildQuestionTerminalCard(record2.context.questions, "processing", answers)
89278
+ }
89279
+ },
89280
+ execute: /* @__PURE__ */ __name(() => this.respond(record2, "submitted", answers), "execute")
89281
+ };
89282
+ }
89283
+ this.markClaimed(record2);
89284
+ record2.terminalDeliveredByClaim = true;
89285
+ return {
89286
+ kind: "handled",
89287
+ response: {
89288
+ toast: { type: "info", content: "\u5DF2\u53D6\u6D88\u3002" },
89289
+ card: {
89290
+ type: "raw",
89291
+ data: buildQuestionTerminalCard(record2.context.questions, "cancelled")
89292
+ }
89293
+ },
89294
+ execute: /* @__PURE__ */ __name(() => this.respond(record2, "cancelled"), "execute")
89295
+ };
89296
+ }
89297
+ cancelRun(runId, terminalState = "cancelled") {
89298
+ for (const record2 of [...this.byRequest.values()]) {
89299
+ if (record2.runId === runId)
89300
+ void this.finalize(record2, terminalState);
89301
+ }
89302
+ }
89303
+ dispose() {
89304
+ this.disposed = true;
89305
+ for (const record2 of [...this.byRequest.values()]) {
89306
+ record2.ignoreResponseProjection = true;
89307
+ void this.finalize(record2, "expired");
89308
+ }
89309
+ }
89310
+ async expire(record2) {
89311
+ if (record2.state !== "pending")
89312
+ return;
89313
+ await this.finalize(record2, "expired");
89314
+ try {
89315
+ await record2.context.respond({ outcome: { outcome: "cancelled" } });
89316
+ } catch (error) {
89317
+ this.options.onError?.("expired question cancellation", error);
89318
+ }
89319
+ }
89320
+ async respond(record2, terminalState, answers) {
89321
+ if (record2.state !== "claimed")
89322
+ return;
89323
+ record2.responding = true;
89324
+ try {
89325
+ const accepted = await record2.context.respond(terminalState === "submitted" ? {
89326
+ outcome: {
89327
+ outcome: "selected",
89328
+ optionId: record2.context.submitOptionId
89329
+ },
89330
+ answers
89331
+ } : { outcome: { outcome: "cancelled" } });
89332
+ record2.responding = false;
89333
+ if (!accepted) {
89334
+ this.options.onError?.("question response", new Error("Question response was no longer accepted"));
89335
+ } else if (terminalState === "submitted") {
89336
+ record2.terminalAnswers = answers;
89337
+ }
89338
+ await this.completeResponse(record2, accepted ? terminalState : "expired");
89339
+ } catch (error) {
89340
+ record2.responding = false;
89341
+ this.options.onError?.("question response", error);
89342
+ await this.completeResponse(record2, "expired");
89343
+ }
89344
+ }
89345
+ isTerminated(record2) {
89346
+ return record2.state === "terminal";
89347
+ }
89348
+ async finalize(record2, terminalState) {
89349
+ if (record2.state === "terminal")
89350
+ return;
89351
+ record2.state = "terminal";
89352
+ record2.terminalState = terminalState;
89353
+ if (record2.timer)
89354
+ clearTimeout(record2.timer);
89355
+ record2.timer = void 0;
89356
+ record2.unsubscribe?.();
89357
+ record2.unsubscribe = void 0;
89358
+ this.byRequest.delete(record2.requestId);
89359
+ if (this.activeByScope.get(record2.scopeKey) === record2) {
89360
+ this.activeByScope.delete(record2.scopeKey);
89361
+ }
89362
+ await this.projectTerminal(record2);
89363
+ }
89364
+ async completeResponse(record2, terminalState) {
89365
+ if (record2.state !== "terminal") {
89366
+ await this.finalize(record2, terminalState);
89367
+ return;
89368
+ }
89369
+ if (record2.ignoreResponseProjection)
89370
+ return;
89371
+ if (terminalState === "expired" && record2.terminalState)
89372
+ return;
89373
+ record2.terminalState = terminalState;
89374
+ await this.projectTerminal(record2);
89375
+ }
89376
+ projectTerminal(record2, messageId = record2.messageId) {
89377
+ if (!messageId || !record2.terminalState)
89378
+ return Promise.resolve();
89379
+ if (record2.terminalDeliveredByClaim)
89380
+ return Promise.resolve();
89381
+ const terminalState = record2.terminalState;
89382
+ const answers = record2.terminalAnswers;
89383
+ const card = buildQuestionTerminalCard(record2.context.questions, terminalState, answers);
89384
+ const projection = (record2.projection ?? Promise.resolve()).then(async () => {
89385
+ let patched = false;
89386
+ try {
89387
+ patched = await this.options.patchCard(messageId, card);
89388
+ if (!patched) {
89389
+ this.options.onError?.("question card finalization", new Error("Feishu card patch was not accepted"));
89390
+ }
89391
+ } catch (error) {
89392
+ this.options.onError?.("question card finalization", error);
89393
+ }
89394
+ if (!patched) {
89395
+ const details = record2.context.questions.map((question) => {
89396
+ const answer = answers?.[question.answerKey];
89397
+ return `${question.header}: ${answer ?? question.question}`;
89398
+ }).join("\n");
89399
+ try {
89400
+ await this.options.sendFallback(record2.chatId, `${terminalLabels[terminalState]}
89401
+ ${details}`);
89402
+ } catch (fallbackError) {
89403
+ this.options.onError?.("question terminal fallback delivery", fallbackError);
89404
+ }
89405
+ }
89406
+ });
89407
+ record2.projection = projection;
89408
+ return projection;
89409
+ }
89410
+ expiredResponse() {
89411
+ return {
89412
+ kind: "handled",
89413
+ response: {
89414
+ toast: { type: "warning", content: "\u8BE5\u95EE\u9898\u5DF2\u8FC7\u671F\u6216\u5DF2\u5904\u7406\u3002" }
89415
+ }
89416
+ };
89417
+ }
89418
+ markClaimed(record2) {
89419
+ record2.state = "claimed";
89420
+ if (record2.timer)
89421
+ clearTimeout(record2.timer);
89422
+ record2.timer = void 0;
89423
+ }
89424
+ scopeKey(context) {
89425
+ return `${context.sessionId}\0${context.owner.id}`;
89426
+ }
89427
+ fallbackText(context) {
89428
+ const questions = context.questions.map((question) => `- ${question.question}: ${question.options.map((option) => option.label).join(", ")}`).join("\n");
89429
+ return `\u4E92\u52A8\u95EE\u9898\u5361\u7247\u6295\u9012\u5931\u8D25\uFF0C\u8BE5\u8BF7\u6C42\u5DF2\u53D6\u6D88\uFF0C\u8BF7\u91CD\u8BD5\u3002
89430
+ ${questions}`;
89431
+ }
89432
+ };
89433
+
88999
89434
  // packages/channels/feishu/dist/FeishuAdapter.js
89000
89435
  var DEDUP_TTL_MS = 5 * 60 * 1e3;
89436
+ var OBSERVED_LABEL_CACHE_LIMIT = 500;
89001
89437
  var CARD_UPDATE_INTERVAL_MS = 1500;
89002
89438
  var FEISHU_RUNNING_STATUS_LABEL = "\u8FD0\u884C\u4E2D...";
89003
89439
  var FEISHU_STOPPED_STATUS_LABEL = "\u5DF2\u505C\u6B62\u751F\u6210";
@@ -89023,6 +89459,17 @@ var FEISHU_STATUS_LABELS = `(?:${FEISHU_STATUS_STRINGS.map(escapeRegExp).join("|
89023
89459
  var FEISHU_STATUS_BLOCK_RE = new RegExp(`(?:^|\\n)---\\n\\*${FEISHU_STATUS_LABELS}\\*(?=\\n|$)`, "g");
89024
89460
  var BASE_URL2 = "https://open.feishu.cn/open-apis";
89025
89461
  var FEISHU_ID_RE2 = /^[a-zA-Z0-9_.:-]+$/;
89462
+ var FeishuCardDeliveryError = class extends Error {
89463
+ static {
89464
+ __name(this, "FeishuCardDeliveryError");
89465
+ }
89466
+ detail;
89467
+ constructor(message, detail) {
89468
+ super(message);
89469
+ this.detail = detail;
89470
+ this.name = "FeishuCardDeliveryError";
89471
+ }
89472
+ };
89026
89473
  var FeishuChannel = class extends ChannelBase {
89027
89474
  static {
89028
89475
  __name(this, "FeishuChannel");
@@ -89047,6 +89494,16 @@ var FeishuChannel = class extends ChannelBase {
89047
89494
  botOpenId;
89048
89495
  tokenCache;
89049
89496
  tokenRefreshPromise;
89497
+ questionCardController;
89498
+ // Core (non-silent) callers waiting on the shared token refresh, so a
89499
+ // silent-initiated refresh still logs token errors for them.
89500
+ tokenRefreshHasCoreWaiters = false;
89501
+ observedUserNames = /* @__PURE__ */ new Map();
89502
+ observedChatNames = /* @__PURE__ */ new Map();
89503
+ observedUserLookups = /* @__PURE__ */ new Map();
89504
+ observedChatLookups = /* @__PURE__ */ new Map();
89505
+ observedContactWrites = /* @__PURE__ */ new Map();
89506
+ hydratedObservedNames = false;
89050
89507
  collapsible;
89051
89508
  collapsibleThreshold;
89052
89509
  constructor(name, config, bridge, options) {
@@ -89057,6 +89514,16 @@ var FeishuChannel = class extends ChannelBase {
89057
89514
  const feishuCfg = config;
89058
89515
  this.collapsible = feishuCfg["collapsible"] || false;
89059
89516
  this.collapsibleThreshold = feishuCfg["collapsibleThreshold"] || 500;
89517
+ this.questionCardController = new FeishuQuestionCardController({
89518
+ timeoutMs: 27e4,
89519
+ sendCard: /* @__PURE__ */ __name((chatId, card) => this.sendInteractiveCard(chatId, card), "sendCard"),
89520
+ patchCard: /* @__PURE__ */ __name((messageId, card) => this.patchInteractiveCard(messageId, card), "patchCard"),
89521
+ sendFallback: /* @__PURE__ */ __name((chatId, text) => this.sendMessageInternal(chatId, text, true), "sendFallback"),
89522
+ onError: /* @__PURE__ */ __name((operation, error) => {
89523
+ process.stderr.write(`[Feishu:${this.name}] ${operation} error: ${error instanceof Error ? error.message : error}
89524
+ `);
89525
+ }, "onError")
89526
+ });
89060
89527
  }
89061
89528
  supportsProactiveSend() {
89062
89529
  return true;
@@ -89072,6 +89539,19 @@ var FeishuChannel = class extends ChannelBase {
89072
89539
  "card.action.trigger": /* @__PURE__ */ __name((data) => {
89073
89540
  const payload = data;
89074
89541
  this.logDebugPayload("Feishu", payload);
89542
+ const question = this.questionCardController.claim(payload);
89543
+ if (question.kind === "handled") {
89544
+ const execute = question.execute;
89545
+ if (execute) {
89546
+ setImmediate(() => {
89547
+ execute().catch((error) => {
89548
+ process.stderr.write(`[Feishu:${this.name}] question action execution error: ${error instanceof Error ? error.message : error}
89549
+ `);
89550
+ });
89551
+ });
89552
+ }
89553
+ return question.response;
89554
+ }
89075
89555
  const stopped = this.onCardAction(payload);
89076
89556
  if (stopped) {
89077
89557
  return { toast: { type: "info", content: "\u5DF2\u505C\u6B62" } };
@@ -89385,10 +89865,12 @@ var FeishuChannel = class extends ChannelBase {
89385
89865
  text = text.replace(/^好的,<at[^>]*><\/at>\s*\n*/, "");
89386
89866
  return text.trim() || void 0;
89387
89867
  }
89388
- async getTenantAccessToken() {
89868
+ async getTenantAccessToken(options) {
89389
89869
  if (this.tokenCache && Date.now() < this.tokenCache.expiresAt) {
89390
89870
  return this.tokenCache.token;
89391
89871
  }
89872
+ if (!options?.silent)
89873
+ this.tokenRefreshHasCoreWaiters = true;
89392
89874
  if (this.tokenRefreshPromise)
89393
89875
  return this.tokenRefreshPromise;
89394
89876
  this.tokenRefreshPromise = this.refreshToken();
@@ -89396,6 +89878,7 @@ var FeishuChannel = class extends ChannelBase {
89396
89878
  return await this.tokenRefreshPromise;
89397
89879
  } finally {
89398
89880
  this.tokenRefreshPromise = void 0;
89881
+ this.tokenRefreshHasCoreWaiters = false;
89399
89882
  }
89400
89883
  }
89401
89884
  async refreshToken() {
@@ -89410,8 +89893,10 @@ var FeishuChannel = class extends ChannelBase {
89410
89893
  signal: AbortSignal.timeout(15e3)
89411
89894
  });
89412
89895
  if (!resp.ok) {
89413
- process.stderr.write(`[Feishu:${this.name}] getTenantAccessToken failed: HTTP ${resp.status}
89896
+ if (this.tokenRefreshHasCoreWaiters) {
89897
+ process.stderr.write(`[Feishu:${this.name}] getTenantAccessToken failed: HTTP ${resp.status}
89414
89898
  `);
89899
+ }
89415
89900
  if (resp.status === 401)
89416
89901
  this.tokenCache = void 0;
89417
89902
  return void 0;
@@ -89424,11 +89909,172 @@ var FeishuChannel = class extends ChannelBase {
89424
89909
  };
89425
89910
  return this.tokenCache.token;
89426
89911
  } catch (err) {
89427
- process.stderr.write(`[Feishu:${this.name}] getTenantAccessToken error: ${err}
89912
+ if (this.tokenRefreshHasCoreWaiters) {
89913
+ process.stderr.write(`[Feishu:${this.name}] getTenantAccessToken error: ${err}
89428
89914
  `);
89915
+ }
89429
89916
  return void 0;
89430
89917
  }
89431
89918
  }
89919
+ hydrateObservedNames() {
89920
+ if (this.hydratedObservedNames)
89921
+ return;
89922
+ this.hydratedObservedNames = true;
89923
+ const graph = this.persistedObservedContacts();
89924
+ if (!graph)
89925
+ return;
89926
+ const newestUser = /* @__PURE__ */ new Map();
89927
+ const newestChat = /* @__PURE__ */ new Map();
89928
+ const consider = /* @__PURE__ */ __name((best, id, label, at) => {
89929
+ if (label === id)
89930
+ return;
89931
+ const current = best.get(id);
89932
+ if (!current || at >= current.at)
89933
+ best.set(id, { label, at });
89934
+ }, "consider");
89935
+ for (const user of graph.users) {
89936
+ consider(newestUser, user.id, user.label, user.lastObservedAt);
89937
+ }
89938
+ for (const group of graph.groups) {
89939
+ consider(newestChat, group.id, group.label, group.lastObservedAt);
89940
+ for (const member of group.users) {
89941
+ consider(newestUser, member.id, member.label, member.lastObservedAt);
89942
+ }
89943
+ }
89944
+ for (const [id, entry] of newestUser) {
89945
+ this.observedUserNames.set(id, entry.label);
89946
+ }
89947
+ for (const [id, entry] of newestChat) {
89948
+ this.observedChatNames.set(id, entry.label);
89949
+ }
89950
+ this.capObservedCache(this.observedUserNames);
89951
+ this.capObservedCache(this.observedChatNames);
89952
+ }
89953
+ /** Evicts the oldest-inserted entries once a runtime cache exceeds the cap. */
89954
+ capObservedCache(cache) {
89955
+ let evicted = false;
89956
+ while (cache.size > OBSERVED_LABEL_CACHE_LIMIT) {
89957
+ const oldest = cache.keys().next();
89958
+ if (oldest.done)
89959
+ break;
89960
+ cache.delete(oldest.value);
89961
+ evicted = true;
89962
+ }
89963
+ return evicted;
89964
+ }
89965
+ observedUserName(userId) {
89966
+ const userIdType = userId.startsWith("ou_") ? "open_id" : userId.startsWith("on_") ? "union_id" : "user_id";
89967
+ return this.observedNameLookup({
89968
+ lookups: this.observedUserLookups,
89969
+ names: this.observedUserNames,
89970
+ id: userId,
89971
+ request: /* @__PURE__ */ __name((token) => fetch(`${BASE_URL2}/contact/v3/users/basic_batch?user_id_type=${userIdType}`, {
89972
+ method: "POST",
89973
+ headers: {
89974
+ Authorization: `Bearer ${token}`,
89975
+ "Content-Type": "application/json"
89976
+ },
89977
+ body: JSON.stringify({ user_ids: [userId] }),
89978
+ signal: AbortSignal.timeout(15e3)
89979
+ }), "request"),
89980
+ extractName: /* @__PURE__ */ __name((body) => {
89981
+ const data = body;
89982
+ return data.code === 0 ? data.data?.users?.[0]?.name : void 0;
89983
+ }, "extractName")
89984
+ });
89985
+ }
89986
+ observedChatName(chatId) {
89987
+ return this.observedNameLookup({
89988
+ lookups: this.observedChatLookups,
89989
+ names: this.observedChatNames,
89990
+ id: chatId,
89991
+ request: /* @__PURE__ */ __name((token) => fetch(`${BASE_URL2}/im/v1/chats/${encodeURIComponent(chatId)}`, {
89992
+ headers: { Authorization: `Bearer ${token}` },
89993
+ signal: AbortSignal.timeout(15e3)
89994
+ }), "request"),
89995
+ extractName: /* @__PURE__ */ __name((body) => {
89996
+ const data = body;
89997
+ return data.code === 0 ? data.data?.name : void 0;
89998
+ }, "extractName")
89999
+ });
90000
+ }
90001
+ observedNameLookup(options) {
90002
+ const cached = options.names.get(options.id);
90003
+ if (cached)
90004
+ return Promise.resolve(cached);
90005
+ const existing = options.lookups.get(options.id);
90006
+ if (existing)
90007
+ return existing;
90008
+ const lookup = (async () => {
90009
+ try {
90010
+ const token = await this.getTenantAccessToken({ silent: true });
90011
+ if (!token) {
90012
+ options.lookups.delete(options.id);
90013
+ return void 0;
90014
+ }
90015
+ const response = await options.request(token);
90016
+ if (!response.ok) {
90017
+ if (response.status === 401) {
90018
+ this.tokenCache = void 0;
90019
+ options.lookups.delete(options.id);
90020
+ }
90021
+ return void 0;
90022
+ }
90023
+ const name = options.extractName(await response.json())?.trim();
90024
+ if (!name)
90025
+ return void 0;
90026
+ const label = sanitizeSenderName(name);
90027
+ if (label === "unknown")
90028
+ return void 0;
90029
+ options.names.set(options.id, label);
90030
+ if (this.capObservedCache(options.names)) {
90031
+ this.hydratedObservedNames = false;
90032
+ }
90033
+ return label;
90034
+ } catch {
90035
+ return void 0;
90036
+ }
90037
+ })();
90038
+ options.lookups.set(options.id, lookup);
90039
+ this.capObservedCache(options.lookups);
90040
+ return lookup;
90041
+ }
90042
+ onObservedContact(envelope) {
90043
+ this.observedContactWrites.set(this.observedContactKey(envelope), {
90044
+ senderName: envelope.senderName,
90045
+ chatName: envelope.chatName
90046
+ });
90047
+ this.capObservedCache(this.observedContactWrites);
90048
+ void this.enrichObservedContact(envelope).catch(() => {
90049
+ });
90050
+ }
90051
+ observedContactKey(envelope) {
90052
+ return envelope.isGroup ? `${envelope.senderId}\0${envelope.chatId}\0${envelope.threadId ?? ""}` : envelope.senderId;
90053
+ }
90054
+ async enrichObservedContact(envelope) {
90055
+ const [senderName, chatName] = await Promise.all([
90056
+ this.observedUserName(envelope.senderId),
90057
+ envelope.isGroup ? this.observedChatName(envelope.chatId) : Promise.resolve(void 0)
90058
+ ]);
90059
+ if (!senderName && !chatName)
90060
+ return;
90061
+ const key = this.observedContactKey(envelope);
90062
+ const nextLabels = {
90063
+ senderName: senderName ?? envelope.senderName,
90064
+ chatName: chatName ?? envelope.chatName
90065
+ };
90066
+ const persistedLabels = this.observedContactWrites.get(key);
90067
+ if (persistedLabels && persistedLabels.senderName === nextLabels.senderName && persistedLabels.chatName === nextLabels.chatName) {
90068
+ return;
90069
+ }
90070
+ this.observedContactWrites.set(key, nextLabels);
90071
+ this.capObservedCache(this.observedContactWrites);
90072
+ await this.recordObservedContact({
90073
+ ...envelope,
90074
+ ...senderName ? { senderName } : {},
90075
+ ...chatName ? { chatName } : {}
90076
+ });
90077
+ }
89432
90078
  async sendMessage(chatId, text) {
89433
90079
  await this.sendMessageInternal(chatId, text, false);
89434
90080
  }
@@ -89502,65 +90148,40 @@ var FeishuChannel = class extends ChannelBase {
89502
90148
  }
89503
90149
  }
89504
90150
  // ----- Interactive Card Streaming -----
89505
- async createStreamingCard(chatId, text, title, inboundMsgId) {
90151
+ async sendInteractiveCard(chatId, card) {
89506
90152
  const token = await this.getTenantAccessToken();
89507
90153
  if (!token)
89508
- return { messageId: "", success: false };
89509
- const cardTitle = title || inboundMsgId && this.msgToQuestion.get(inboundMsgId) || "Qwen";
89510
- const card = buildCardContent(text, {
89511
- title: cardTitle,
89512
- showStopButton: true,
89513
- isStreaming: true,
89514
- statusLabel: this.statusLabelFor(),
89515
- collapsible: this.collapsible,
89516
- collapsibleThreshold: this.collapsibleThreshold
90154
+ throw new FeishuCardDeliveryError("Feishu card delivery failed: no access token");
90155
+ const resp = await fetch(`${BASE_URL2}/im/v1/messages?receive_id_type=chat_id`, {
90156
+ method: "POST",
90157
+ headers: {
90158
+ Authorization: `Bearer ${token}`,
90159
+ "Content-Type": "application/json"
90160
+ },
90161
+ body: JSON.stringify({
90162
+ receive_id: chatId,
90163
+ msg_type: "interactive",
90164
+ content: JSON.stringify(card)
90165
+ }),
90166
+ signal: AbortSignal.timeout(15e3)
89517
90167
  });
89518
- const body = {
89519
- receive_id: chatId,
89520
- msg_type: "interactive",
89521
- content: JSON.stringify(card)
89522
- };
89523
- try {
89524
- const resp = await fetch(`${BASE_URL2}/im/v1/messages?receive_id_type=chat_id`, {
89525
- method: "POST",
89526
- headers: {
89527
- Authorization: `Bearer ${token}`,
89528
- "Content-Type": "application/json"
89529
- },
89530
- body: JSON.stringify(body),
89531
- signal: AbortSignal.timeout(15e3)
89532
- });
89533
- if (!resp.ok) {
89534
- if (resp.status === 401)
89535
- this.tokenCache = void 0;
89536
- const detail = await resp.text().catch(() => "");
89537
- process.stderr.write(`[Feishu:${this.name}] createStreamingCard failed: HTTP ${resp.status} ${detail}
89538
- `);
89539
- return { messageId: "", success: false };
89540
- }
89541
- const data = await resp.json();
89542
- const messageId = data.data?.message_id || "";
89543
- return { messageId, success: !!messageId };
89544
- } catch (err) {
89545
- process.stderr.write(`[Feishu:${this.name}] createStreamingCard error: ${err}
89546
- `);
89547
- return { messageId: "", success: false };
90168
+ if (!resp.ok) {
90169
+ if (resp.status === 401)
90170
+ this.tokenCache = void 0;
90171
+ const detail = await resp.text().catch(() => "");
90172
+ const errorDetail = `HTTP ${resp.status} ${detail}`;
90173
+ throw new FeishuCardDeliveryError(`Feishu card delivery failed: ${errorDetail}`, errorDetail);
90174
+ }
90175
+ const data = await resp.json();
90176
+ const messageId = data.data?.message_id;
90177
+ if (!messageId) {
90178
+ throw new FeishuCardDeliveryError("Feishu card delivery returned no message id");
89548
90179
  }
90180
+ return messageId;
89549
90181
  }
89550
- async updateCard(messageId, text, finished = false, inboundMsgId, statusLabel) {
90182
+ async patchInteractiveCard(messageId, card) {
89551
90183
  const token = await this.getTenantAccessToken();
89552
- if (!token)
89553
- return false;
89554
- const cardTitle = inboundMsgId ? this.msgToQuestion.get(inboundMsgId) || "Qwen" : "Qwen";
89555
- const card = buildCardContent(text, {
89556
- title: cardTitle,
89557
- showStopButton: !finished,
89558
- isStreaming: !finished,
89559
- statusLabel: statusLabel ?? (!finished ? this.statusLabelFor() : void 0),
89560
- collapsible: this.collapsible,
89561
- collapsibleThreshold: this.collapsibleThreshold
89562
- });
89563
- if (!FEISHU_ID_RE2.test(messageId))
90184
+ if (!token || !FEISHU_ID_RE2.test(messageId))
89564
90185
  return false;
89565
90186
  try {
89566
90187
  const resp = await fetch(`${BASE_URL2}/im/v1/messages/${messageId}`, {
@@ -89590,6 +90211,52 @@ var FeishuChannel = class extends ChannelBase {
89590
90211
  return false;
89591
90212
  }
89592
90213
  }
90214
+ async createStreamingCard(chatId, text, title, inboundMsgId) {
90215
+ const cardTitle = title || inboundMsgId && this.msgToQuestion.get(inboundMsgId) || "Qwen";
90216
+ const card = buildCardContent(text, {
90217
+ title: cardTitle,
90218
+ showStopButton: true,
90219
+ isStreaming: true,
90220
+ statusLabel: this.statusLabelFor(),
90221
+ collapsible: this.collapsible,
90222
+ collapsibleThreshold: this.collapsibleThreshold
90223
+ });
90224
+ try {
90225
+ const messageId = await this.sendInteractiveCard(chatId, card);
90226
+ return { messageId, success: true };
90227
+ } catch (err) {
90228
+ if (err instanceof FeishuCardDeliveryError) {
90229
+ process.stderr.write(`[Feishu:${this.name}] createStreamingCard failed: ${err.detail ?? err.message}
90230
+ `);
90231
+ return { messageId: "", success: false };
90232
+ }
90233
+ process.stderr.write(`[Feishu:${this.name}] createStreamingCard error: ${err}
90234
+ `);
90235
+ return { messageId: "", success: false };
90236
+ }
90237
+ }
90238
+ async updateCard(messageId, text, finished = false, inboundMsgId, statusLabel) {
90239
+ const cardTitle = inboundMsgId ? this.msgToQuestion.get(inboundMsgId) || "Qwen" : "Qwen";
90240
+ const card = buildCardContent(text, {
90241
+ title: cardTitle,
90242
+ showStopButton: !finished,
90243
+ isStreaming: !finished,
90244
+ statusLabel: statusLabel ?? (!finished ? this.statusLabelFor() : void 0),
90245
+ collapsible: this.collapsible,
90246
+ collapsibleThreshold: this.collapsibleThreshold
90247
+ });
90248
+ return this.patchInteractiveCard(messageId, card);
90249
+ }
90250
+ async presentUserInputRequest(context) {
90251
+ if (!context.precedingSegmentId) {
90252
+ const inboundMsgId = this.sessionToInboundMsg.get(context.sessionId);
90253
+ const cardState = inboundMsgId ? this.cardSessions.get(inboundMsgId) : void 0;
90254
+ if (inboundMsgId && cardState) {
90255
+ await this.endOutputCardBeforeInputRequest(context.target.chatId, inboundMsgId, cardState);
90256
+ }
90257
+ }
90258
+ return this.questionCardController.present(context);
90259
+ }
89593
90260
  /** Delete a card message from Feishu to prevent orphaned "思考中..." cards. */
89594
90261
  async deleteCard(messageId) {
89595
90262
  const token = await this.getTenantAccessToken();
@@ -89641,6 +90308,7 @@ var FeishuChannel = class extends ChannelBase {
89641
90308
  }
89642
90309
  if (cardState.stopped)
89643
90310
  return;
90311
+ cardState.boundaryText = void 0;
89644
90312
  const MAX_ACCUMULATE = 25e3;
89645
90313
  cardState.accumulatedText += chunk;
89646
90314
  if (cardState.accumulatedText.length > MAX_ACCUMULATE) {
@@ -89650,12 +90318,14 @@ var FeishuChannel = class extends ChannelBase {
89650
90318
  return;
89651
90319
  if (!cardState.created && !cardState.cardCreationFailed) {
89652
90320
  cardState.creating = true;
90321
+ cardState.lastUpdateAt = Date.now();
89653
90322
  const cs = cardState;
89654
90323
  cardState.creationTimer = setTimeout(async () => {
89655
90324
  try {
89656
90325
  if (cs.stopped || this.stoppedMessages.has(inboundMsgId)) {
89657
90326
  cs.creating = false;
89658
- this.cleanupCard(inboundMsgId);
90327
+ if (!cs.abandoned)
90328
+ this.cleanupCard(inboundMsgId);
89659
90329
  return;
89660
90330
  }
89661
90331
  const atPrefix = this.msgToSenderName.get(inboundMsgId);
@@ -89702,36 +90372,50 @@ ${cs.accumulatedText}` : cs.accumulatedText;
89702
90372
  const cs = cardState;
89703
90373
  const elapsed = Date.now() - cardState.lastUpdateAt;
89704
90374
  const delay = Math.max(0, CARD_UPDATE_INTERVAL_MS - elapsed);
89705
- cardState.pendingUpdateTimer = setTimeout(async () => {
90375
+ cardState.pendingUpdateTimer = setTimeout(() => {
89706
90376
  cs.pendingUpdateTimer = void 0;
89707
90377
  if (cs.stopped || cs.finalizing)
89708
90378
  return;
89709
90379
  cs.lastUpdateAt = Date.now();
89710
- try {
89711
- const MAX_CARD_CHARS = 2e4;
89712
- const atPrefix = this.msgToSenderName.get(inboundMsgId);
89713
- let displayContent = atPrefix ? `${atPrefix}
89714
-
89715
- ${cs.accumulatedText}` : cs.accumulatedText;
89716
- if (displayContent.length > MAX_CARD_CHARS) {
89717
- const marker = "\n\n_(\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\u65E9\u671F\u5185\u5BB9)_";
89718
- displayContent = displayContent.slice(-(MAX_CARD_CHARS - marker.length)) + marker;
89719
- if (this.countFences(displayContent) % 2 === 1) {
89720
- displayContent = "```\n" + displayContent;
89721
- }
89722
- }
89723
- const ok = await this.updateCard(cs.messageId, displayContent, false, inboundMsgId);
89724
- if (!ok) {
89725
- const stripped = this.stripTables(displayContent, "(\u8868\u683C)");
89726
- await this.updateCard(cs.messageId, stripped, false, inboundMsgId);
89727
- }
89728
- } catch (err) {
90380
+ if (cs.pendingUpdatePromise) {
90381
+ cs.updateQueued = true;
90382
+ return;
90383
+ }
90384
+ cs.pendingUpdatePromise = this.runThrottledCardUpdate(inboundMsgId, cs).catch((err) => {
89729
90385
  process.stderr.write(`[Feishu:${this.name}] card update error: ${err}
89730
90386
  `);
89731
- }
90387
+ }).then(() => {
90388
+ cs.pendingUpdatePromise = void 0;
90389
+ });
89732
90390
  }, delay);
89733
90391
  }
89734
90392
  }
90393
+ /** Runs one throttled streaming PATCH, then re-runs once when timer fires
90394
+ * coalesced behind it (`updateQueued`) so the latest buffer still goes out.
90395
+ * `pendingUpdatePromise` covers the whole chain so finalization can drain
90396
+ * every in-flight update before sending the final patch. */
90397
+ async runThrottledCardUpdate(inboundMsgId, cs) {
90398
+ if (cs.stopped || cs.finalizing)
90399
+ return;
90400
+ try {
90401
+ const atPrefix = this.msgToSenderName.get(inboundMsgId);
90402
+ const displayContent = this.truncateCardText(atPrefix ? `${atPrefix}
90403
+
90404
+ ${cs.accumulatedText}` : cs.accumulatedText);
90405
+ const ok = await this.updateCard(cs.messageId, displayContent, false, inboundMsgId);
90406
+ if (!ok && !cs.stopped && !cs.finalizing) {
90407
+ const stripped = this.stripTables(displayContent, "(\u8868\u683C)");
90408
+ await this.updateCard(cs.messageId, stripped, false, inboundMsgId);
90409
+ }
90410
+ } catch (err) {
90411
+ process.stderr.write(`[Feishu:${this.name}] card update error: ${err}
90412
+ `);
90413
+ }
90414
+ if (cs.updateQueued) {
90415
+ cs.updateQueued = false;
90416
+ await this.runThrottledCardUpdate(inboundMsgId, cs);
90417
+ }
90418
+ }
89735
90419
  onResponseBoundary(_chatId, sessionId) {
89736
90420
  if (this.config.blockStreaming === "on")
89737
90421
  return;
@@ -89745,8 +90429,90 @@ ${cs.accumulatedText}` : cs.accumulatedText;
89745
90429
  clearTimeout(cardState.pendingUpdateTimer);
89746
90430
  cardState.pendingUpdateTimer = void 0;
89747
90431
  }
90432
+ cardState.updateQueued = false;
90433
+ if (cardState.accumulatedText) {
90434
+ cardState.boundaryText = cardState.accumulatedText;
90435
+ }
89748
90436
  cardState.accumulatedText = "";
89749
90437
  }
90438
+ async onOutputSegmentEnd(chatId, sessionId, _segment, reason) {
90439
+ if (reason === "response_boundary") {
90440
+ this.onResponseBoundary(chatId, sessionId);
90441
+ return;
90442
+ }
90443
+ if (reason !== "input_requested" || this.config.blockStreaming === "on") {
90444
+ return;
90445
+ }
90446
+ const inboundMsgId = this.sessionToInboundMsg.get(sessionId);
90447
+ if (!inboundMsgId)
90448
+ return;
90449
+ const cardState = this.cardSessions.get(inboundMsgId);
90450
+ if (!cardState)
90451
+ return;
90452
+ await this.endOutputCardBeforeInputRequest(chatId, inboundMsgId, cardState);
90453
+ }
90454
+ async endOutputCardBeforeInputRequest(chatId, inboundMsgId, cardState) {
90455
+ if (cardState.cancelling || cardState.stopped || cardState.finalizing || this.stoppedMessages.has(inboundMsgId)) {
90456
+ return;
90457
+ }
90458
+ const atPrefix = this.msgToSenderName.get(inboundMsgId);
90459
+ const text = cardState.accumulatedText || cardState.boundaryText || "";
90460
+ const displayText = atPrefix ? text ? `${atPrefix}
90461
+
90462
+ ${text}` : atPrefix : text;
90463
+ const completedSuffix = `
90464
+
90465
+ ---
90466
+ *${this.statusLabelFor("completed")}*`;
90467
+ const prefixPart = atPrefix && text ? `${atPrefix}
90468
+
90469
+ ` : "";
90470
+ const finalText = text ? prefixPart + this.truncateCardText(text, prefixPart.length + completedSuffix.length) : displayText;
90471
+ try {
90472
+ if (cardState.created && cardState.messageId && !cardState.stopped) {
90473
+ cardState.finalizing = true;
90474
+ if (cardState.pendingUpdateTimer) {
90475
+ clearTimeout(cardState.pendingUpdateTimer);
90476
+ cardState.pendingUpdateTimer = void 0;
90477
+ }
90478
+ if (cardState.pendingUpdatePromise) {
90479
+ await cardState.pendingUpdatePromise;
90480
+ }
90481
+ let updated = false;
90482
+ try {
90483
+ if (await this.finalizeStoppedCardUpdate(inboundMsgId, cardState, chatId)) {
90484
+ return;
90485
+ }
90486
+ updated = await this.updateCard(cardState.messageId, finalText, true, inboundMsgId, this.statusLabelFor("completed"));
90487
+ if (!updated) {
90488
+ const noTableText = this.stripTables(finalText, "(\u8868\u683C\u5185\u5BB9\u8BF7\u67E5\u770B\u539F\u6587)");
90489
+ updated = await this.updateCard(cardState.messageId, noTableText, true, inboundMsgId, this.statusLabelFor("completed"));
90490
+ }
90491
+ if (await this.finalizeStoppedCardUpdate(inboundMsgId, cardState, chatId)) {
90492
+ return;
90493
+ }
90494
+ } catch (error) {
90495
+ process.stderr.write(`[Feishu:${this.name}] input-request card finalization error: ${error instanceof Error ? error.message : error}
90496
+ `);
90497
+ }
90498
+ if (!updated) {
90499
+ await this.deleteCard(cardState.messageId);
90500
+ if (displayText)
90501
+ await this.sendMessage(chatId, displayText);
90502
+ }
90503
+ } else {
90504
+ if (cardState.creating) {
90505
+ cardState.stopped = true;
90506
+ cardState.abandoned = true;
90507
+ }
90508
+ if (text) {
90509
+ await this.sendMessage(chatId, displayText);
90510
+ }
90511
+ }
90512
+ } finally {
90513
+ this.releaseOutputCard(inboundMsgId);
90514
+ }
90515
+ }
89750
90516
  isKnownInboundMessageId(messageId) {
89751
90517
  return this.msgToQuestion.has(messageId) || this.msgToSenderName.has(messageId) || this.msgToSenderId.has(messageId) || this.cardSessions.has(messageId) || this.stoppedMessages.has(messageId);
89752
90518
  }
@@ -89791,6 +90557,9 @@ ${contentPart}` : contentPart;
89791
90557
  if (!isTerminalTaskLifecycleType(event.type)) {
89792
90558
  return;
89793
90559
  }
90560
+ if (event.runId) {
90561
+ this.questionCardController.cancelRun(event.runId, event.type === "cancelled" && (event.reason === "cancel_command" || event.reason === "clear") ? "cancelled" : "expired");
90562
+ }
89794
90563
  const inboundMsgId = this.knownInboundMessageId(event.sessionId, event.messageId);
89795
90564
  if (!inboundMsgId)
89796
90565
  return;
@@ -89820,34 +90589,22 @@ ${contentPart}` : contentPart;
89820
90589
  return;
89821
90590
  }
89822
90591
  const atSender = this.msgToSenderName.get(inboundMsgId);
89823
- let displayText = atSender ? `${atSender}
89824
-
89825
- ${fullText}` : fullText;
89826
90592
  const completedLabel = this.statusLabelFor("completed");
89827
90593
  const completedSuffix = `
89828
90594
 
89829
90595
  ---
89830
90596
  *${completedLabel}*`;
89831
- const MAX_FINAL_CARD_CHARS = 2e4;
89832
- if (displayText.length + completedSuffix.length > MAX_FINAL_CARD_CHARS) {
89833
- const prefix = atSender ? `${atSender}
90597
+ const atPrefix = atSender ? `${atSender}
89834
90598
 
89835
90599
  ` : "";
89836
- const suffix = "\n\n_(\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\u65E9\u671F\u5185\u5BB9)_";
89837
- const fenceReserve = 4;
89838
- const maxBody = MAX_FINAL_CARD_CHARS - prefix.length - suffix.length - completedSuffix.length - fenceReserve;
89839
- displayText = prefix + fullText.slice(-maxBody) + suffix;
89840
- if (this.countFences(displayText) % 2 === 1) {
89841
- displayText = "```\n" + displayText;
89842
- }
89843
- }
90600
+ const displayText = atPrefix + this.truncateCardText(fullText, atPrefix.length + completedSuffix.length);
89844
90601
  if (cardState)
89845
90602
  cardState.finalizing = true;
89846
90603
  if (cardState?.pendingUpdateTimer) {
89847
90604
  clearTimeout(cardState.pendingUpdateTimer);
89848
90605
  }
89849
- if (cardState?.creationTimer) {
89850
- clearTimeout(cardState.creationTimer);
90606
+ if (cardState?.pendingUpdatePromise) {
90607
+ await cardState.pendingUpdatePromise;
89851
90608
  }
89852
90609
  if (cardState?.creating) {
89853
90610
  await new Promise((resolve) => {
@@ -89922,60 +90679,20 @@ ${fullText}` : fullText);
89922
90679
 
89923
90680
  ${fullText}` : fullText);
89924
90681
  }
89925
- onPromptStart(chatId, sessionId, messageId) {
90682
+ onPromptStart(_chatId, sessionId, messageId) {
89926
90683
  const inboundMsgId = messageId && this.isKnownInboundMessageId(messageId) ? messageId : void 0;
89927
90684
  if (inboundMsgId) {
89928
90685
  this.sessionToInboundMsg.set(sessionId, inboundMsgId);
89929
90686
  this.addReaction(inboundMsgId, "OnIt").catch(() => {
89930
90687
  });
89931
- if (this.config.blockStreaming === "on")
89932
- return;
89933
- if (!this.cardSessions.has(inboundMsgId)) {
89934
- const atSender = this.msgToSenderName.get(inboundMsgId) || "";
89935
- const placeholderText = atSender ? `${atSender}\uFF0C\u601D\u8003\u4E2D...` : "\u601D\u8003\u4E2D...";
89936
- const cardState = {
90688
+ if (this.config.blockStreaming !== "on" && !this.cardSessions.has(inboundMsgId)) {
90689
+ this.cardSessions.set(inboundMsgId, {
89937
90690
  messageId: "",
89938
90691
  created: false,
89939
- creating: true,
90692
+ creating: false,
89940
90693
  stopped: false,
89941
90694
  accumulatedText: "",
89942
90695
  lastUpdateAt: Date.now()
89943
- };
89944
- this.cardSessions.set(inboundMsgId, cardState);
89945
- this.createStreamingCard(chatId, placeholderText, void 0, inboundMsgId).then((result) => {
89946
- if (cardState.stopped || this.stoppedMessages.has(inboundMsgId)) {
89947
- if (cardState.abandoned) {
89948
- if (result.success) {
89949
- this.deleteCard(result.messageId).catch((err) => {
89950
- process.stderr.write(`[Feishu:${this.name}] ORPHANED CARD: failed to delete abandoned card msg=${result.messageId}: ${err instanceof Error ? err.message : err}
89951
- `);
89952
- });
89953
- }
89954
- cardState.creating = false;
89955
- return;
89956
- }
89957
- if (result.success) {
89958
- const prefix = cardState.atPrefix || this.msgToSenderName.get(inboundMsgId) || "";
89959
- this.updateCard(result.messageId, prefix, true, inboundMsgId, this.stopLabelFor(cardState.terminalStatus, cardState.userStopped ?? false)).catch(() => {
89960
- });
89961
- }
89962
- cardState.creating = false;
89963
- this.cleanupCard(inboundMsgId);
89964
- return;
89965
- }
89966
- if (result.success) {
89967
- cardState.messageId = result.messageId;
89968
- cardState.created = true;
89969
- cardState.lastUpdateAt = Date.now();
89970
- } else {
89971
- cardState.cardCreationFailed = true;
89972
- }
89973
- cardState.creating = false;
89974
- }).catch((err) => {
89975
- process.stderr.write(`[Feishu:${this.name}] Processing card error: ${err}
89976
- `);
89977
- cardState.creating = false;
89978
- this.cleanupCard(inboundMsgId);
89979
90696
  });
89980
90697
  }
89981
90698
  }
@@ -89991,6 +90708,14 @@ ${fullText}` : fullText);
89991
90708
  cs.stopped = true;
89992
90709
  } else if (cs.created) {
89993
90710
  cs.stopped = true;
90711
+ cs.finalizing = true;
90712
+ if (cs.pendingUpdateTimer) {
90713
+ clearTimeout(cs.pendingUpdateTimer);
90714
+ cs.pendingUpdateTimer = void 0;
90715
+ }
90716
+ if (cs.pendingUpdatePromise) {
90717
+ await cs.pendingUpdatePromise;
90718
+ }
89994
90719
  const atPrefix = this.msgToSenderName.get(inboundMsgId) || "";
89995
90720
  const terminalStatus = cs.terminalStatus ?? (cs.cancelling ? "cancelled" : "failed");
89996
90721
  const terminalLabel = this.stopLabelFor(terminalStatus, cs.userStopped ?? false);
@@ -90008,7 +90733,7 @@ ${cs.accumulatedText}` : cs.accumulatedText : atPrefix || "";
90008
90733
  ${cs.accumulatedText}` : cs.accumulatedText;
90009
90734
  this.sendMessage(_chatId, fallbackText).catch(() => {
90010
90735
  });
90011
- } else {
90736
+ } else if (cs.terminalStatus !== "completed") {
90012
90737
  const atPrefix = this.msgToSenderName.get(inboundMsgId) || "";
90013
90738
  const fallbackLabel = cs.terminalStatus ? this.statusLabelFor(cs.terminalStatus) : "\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
90014
90739
  const errorText = atPrefix ? `${atPrefix}
@@ -90148,6 +90873,13 @@ ${cs.accumulatedText}` : cs.accumulatedText;
90148
90873
  }
90149
90874
  if (cardState.finalizing)
90150
90875
  return;
90876
+ if (cardState.pendingUpdateTimer) {
90877
+ clearTimeout(cardState.pendingUpdateTimer);
90878
+ cardState.pendingUpdateTimer = void 0;
90879
+ }
90880
+ if (cardState.pendingUpdatePromise) {
90881
+ await cardState.pendingUpdatePromise;
90882
+ }
90151
90883
  if (cardState.created && cardState.messageId) {
90152
90884
  const prefix = cardState.atPrefix || this.msgToSenderName.get(inboundId) || "";
90153
90885
  const stopLabel = cancelSucceeded ? this.stopLabelFor(cardState.terminalStatus, wasUserStop) : FEISHU_STOP_FAILED_STATUS_LABEL;
@@ -90178,6 +90910,7 @@ ${contentPart}` : prefix : contentPart;
90178
90910
  }
90179
90911
  }
90180
90912
  disconnect() {
90913
+ this.questionCardController.dispose();
90181
90914
  if (this.dedupTimer) {
90182
90915
  clearInterval(this.dedupTimer);
90183
90916
  this.dedupTimer = void 0;
@@ -90252,6 +90985,21 @@ ${contentPart}` : prefix : contentPart;
90252
90985
  }
90253
90986
  return result.join("\n");
90254
90987
  }
90988
+ /** Truncate card content to the Feishu card size limit, keeping the tail.
90989
+ * `reservedChars` covers content rendered alongside the text (greeting
90990
+ * prefix, status block) that must fit the same limit. */
90991
+ truncateCardText(text, reservedChars = 0) {
90992
+ const MAX_CARD_CHARS = 2e4;
90993
+ if (text.length + reservedChars <= MAX_CARD_CHARS)
90994
+ return text;
90995
+ const marker = "\n\n_(\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\u65E9\u671F\u5185\u5BB9)_";
90996
+ const fenceReserve = 4;
90997
+ let truncated = text.slice(-(MAX_CARD_CHARS - marker.length - fenceReserve - reservedChars)) + marker;
90998
+ if (this.countFences(truncated) % 2 === 1) {
90999
+ truncated = "```\n" + truncated;
91000
+ }
91001
+ return truncated;
91002
+ }
90255
91003
  cleanupCard(inboundMsgId) {
90256
91004
  const cardState = this.cardSessions.get(inboundMsgId);
90257
91005
  if (cardState?.pendingUpdateTimer) {
@@ -90272,6 +91020,30 @@ ${contentPart}` : prefix : contentPart;
90272
91020
  }
90273
91021
  }
90274
91022
  }
91023
+ releaseOutputCard(inboundMsgId) {
91024
+ const cardState = this.cardSessions.get(inboundMsgId);
91025
+ if (!cardState)
91026
+ return;
91027
+ if (cardState.pendingUpdateTimer) {
91028
+ clearTimeout(cardState.pendingUpdateTimer);
91029
+ }
91030
+ if (cardState.creationTimer) {
91031
+ clearTimeout(cardState.creationTimer);
91032
+ }
91033
+ this.cardSessions.set(inboundMsgId, {
91034
+ messageId: "",
91035
+ created: false,
91036
+ creating: false,
91037
+ // Carry a settled user stop (not the abandoned-creation marker) so a
91038
+ // late-settled stop cannot flip onPromptEnd into a contradictory
91039
+ // terminal message.
91040
+ stopped: cardState.stopped && !cardState.abandoned,
91041
+ accumulatedText: "",
91042
+ lastUpdateAt: Date.now(),
91043
+ userStopped: cardState.userStopped,
91044
+ terminalStatus: cardState.terminalStatus
91045
+ });
91046
+ }
90275
91047
  // ----- Message handling -----
90276
91048
  onMessage(data) {
90277
91049
  try {
@@ -90286,6 +91058,9 @@ ${contentPart}` : prefix : contentPart;
90286
91058
  const isGroup = msg.chat_type === "group";
90287
91059
  const chatId = msg.chat_id;
90288
91060
  const senderId = sender.sender_id?.open_id || sender.sender_id?.user_id || sender.sender_id?.union_id || "";
91061
+ this.hydrateObservedNames();
91062
+ const senderName = this.observedUserNames.get(senderId) || senderId;
91063
+ const chatName = isGroup ? this.observedChatNames.get(chatId) : void 0;
90289
91064
  const content = this.extractContent(msg.message_type, msg.content);
90290
91065
  let isMentioned = false;
90291
91066
  let cleanText = content.text;
@@ -90315,8 +91090,9 @@ ${contentPart}` : prefix : contentPart;
90315
91090
  const envelope = {
90316
91091
  channelName: this.name,
90317
91092
  senderId,
90318
- senderName: senderId,
91093
+ senderName,
90319
91094
  chatId,
91095
+ ...chatName ? { chatName } : {},
90320
91096
  text: cleanText,
90321
91097
  messageId: msgId,
90322
91098
  threadId: msg.root_id || void 0,