activeclaw 2026.2.12 → 2026.2.13

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 (364) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/{accounts-DbzMEfKN.js → accounts-DCDeFTra.js} +2 -2
  3. package/dist/{accounts-DimKrt7j.js → accounts-DeqIQjo1.js} +2 -2
  4. package/dist/{acp-cli-Cs1ai4XO.js → acp-cli-CeYI4XRd.js} +15 -16
  5. package/dist/{acp-cli-oV2dodPg.js → acp-cli-rNbGXICg.js} +14 -15
  6. package/dist/{agent-BndgzkUe.js → agent-BvNJF5QL.js} +19 -16
  7. package/dist/{agent-DZvDwqnd.js → agent-CyMxTyrG.js} +20 -17
  8. package/dist/{agent-scope-rXQ7WARN.js → agent-scope-BIEhVP4_.js} +1 -1
  9. package/dist/{agent-scope---6LLHj0.js → agent-scope-CQCus0rI.js} +2 -2
  10. package/dist/{agent-scope-RCSw6gHy.js → agent-scope-CsRbLH4l.js} +3 -3
  11. package/dist/{agent-scope-CN8DM4Xb.js → agent-scope-DPIFau3f.js} +1 -1
  12. package/dist/{audio-preflight-SZRntkxo.js → audio-preflight-BU8W7uxc.js} +10 -10
  13. package/dist/{audio-preflight-ClVNINDs.js → audio-preflight-CGsumMzb.js} +10 -10
  14. package/dist/{audio-preflight-txAP3v-C.js → audio-preflight-SLmkJI6-.js} +22 -22
  15. package/dist/{audio-preflight-BP6s-UPp.js → audio-preflight-jZc5mFCZ.js} +23 -23
  16. package/dist/{audit-CQzrm61N.js → audit-Dmww_503.js} +70 -18
  17. package/dist/{audit-DMH3CSXY.js → audit-wPu26VMb.js} +72 -20
  18. package/dist/{tailscale-DU6DgqVy.js → auth-9x3lqfIY.js} +208 -3
  19. package/dist/{tailscale-DHfcfRCx.js → auth-CQNl_IaI.js} +190 -3
  20. package/dist/{auth-health-BB3e3OmN.js → auth-health-C4L4FGBA.js} +1 -1
  21. package/dist/{auth-health-zZ9dnQGC.js → auth-health-j6epgQbq.js} +1 -1
  22. package/dist/{auth-profiles-CcJ3hrog.js → auth-profiles-ByNs3eEm.js} +60 -22
  23. package/dist/build-info.json +3 -3
  24. package/dist/bundled/boot-md/handler.js +19 -16
  25. package/dist/bundled/session-memory/handler.js +16 -15
  26. package/dist/{call-Yxns4CVq.js → call-DVYCIV8m.js} +5 -5
  27. package/dist/{call-C9az806y.js → call-SolyGS1r.js} +4 -4
  28. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  29. package/dist/{channel-options-CjXPwMWu.js → channel-options-BwC2yQcR.js} +4 -4
  30. package/dist/{channel-options-CX4iYQfR.js → channel-options-Cq9BVDkP.js} +7 -7
  31. package/dist/{channel-selection-BoQ7GurB.js → channel-selection-D4D6ImhN.js} +2 -2
  32. package/dist/{channel-selection-C78IwbD-.js → channel-selection-MZAHm4U8.js} +2 -2
  33. package/dist/{channels-cli-DUHsmX3q.js → channels-cli-9Dsk9Qm7.js} +53 -51
  34. package/dist/{channels-cli-BXMQPB4x.js → channels-cli-BJUppQll.js} +52 -50
  35. package/dist/{channels-status-issues-Ca9--azp.js → channels-status-issues-D7GSV1GS.js} +1 -1
  36. package/dist/{channels-status-issues-CbULFg2X.js → channels-status-issues-DDAWeT-6.js} +1 -1
  37. package/dist/{chrome-svgmQ8T_.js → chrome-BfB6JdKF.js} +2 -1
  38. package/dist/{chrome-juQxt0zf.js → chrome-Cvr-57lg.js} +4 -3
  39. package/dist/{chrome-BCPPeLQ6.js → chrome-DL0avO8n.js} +2 -1
  40. package/dist/{chrome-yIKmOzCO.js → chrome-foEwx3lN.js} +5 -4
  41. package/dist/{clack-prompter-Dmvcu3gn.js → clack-prompter-Bz3Mmcl-.js} +5 -5
  42. package/dist/{clack-prompter-DuBVnTKy.js → clack-prompter-ChCGXfyt.js} +4 -4
  43. package/dist/cli/daemon-cli.js +1 -1
  44. package/dist/{cli-FdxAcu_y.js → cli-ZR9ugUBX.js} +42 -40
  45. package/dist/{cli-By331Q9f.js → cli-miPe4Ujz.js} +42 -40
  46. package/dist/{client-B0_GiCjB.js → client-BrYfyoDK.js} +52 -3
  47. package/dist/{client-D7wrC1Ug.js → client-CTwXnRl7.js} +53 -4
  48. package/dist/{command-format-ayFsmwwz.js → command-format-Bxe0mWee.js} +1 -1
  49. package/dist/{command-options-BSDiKuyX.js → command-options-BvgxzPbK.js} +4 -4
  50. package/dist/{commands-BG25qku5.js → commands-BX_OIIVR.js} +4 -4
  51. package/dist/{completion-cli-C4zxjkC1.js → completion-cli-CR77-jyv.js} +3 -3
  52. package/dist/{completion-cli-DECEgBWR.js → completion-cli-DnjpxAag.js} +29 -29
  53. package/dist/{config-B7sno9eI.js → config-Bdhomfei.js} +15 -6
  54. package/dist/{config-BuF7vm-v.js → config-BvMsmctM.js} +13 -4
  55. package/dist/{config-D50SQVar.js → config-QYrbd7x7.js} +13 -4
  56. package/dist/{config-DH9TLUNc.js → config-aFQssWKX.js} +15 -6
  57. package/dist/{config-guard-DPxxY1iw.js → config-guard-CljaSxJd.js} +39 -39
  58. package/dist/{configure-BZQ9uSVX.js → configure-BXLiucXo.js} +19 -19
  59. package/dist/{configure-Cg5IKSUy.js → configure-BYPqXzGZ.js} +19 -19
  60. package/dist/control-auth-8Cf4WXpR.js +54 -0
  61. package/dist/control-auth-DBCu3qyv.js +54 -0
  62. package/dist/{control-service-CBlMVTRu.js → control-service-B5KnPqGP.js} +11 -5
  63. package/dist/{control-service-B2er20Ke.js → control-service-DKnttEus.js} +10 -4
  64. package/dist/{cron-cli-B2Zwhy_r.js → cron-cli-D7BRjDv2.js} +17 -17
  65. package/dist/{cron-cli-EaRUVd0p.js → cron-cli-z1zk_FXQ.js} +16 -16
  66. package/dist/{daemon-cli-CVNzObIF.js → daemon-cli-BDkU2ocb.js} +18 -18
  67. package/dist/{daemon-cli-DF6Rxjy6.js → daemon-cli-cNSF93-v.js} +19 -19
  68. package/dist/{daemon-runtime-BHF5NjQ7.js → daemon-runtime-B0tg_LsX.js} +2 -2
  69. package/dist/{daemon-runtime-B05PME1z.js → daemon-runtime-Bsjeut6m.js} +3 -3
  70. package/dist/{deliver-DzcxEcza.js → deliver-CIU9Npgs.js} +306 -12
  71. package/dist/{deliver-COf5XFo_.js → deliver-DYYCo1G7.js} +302 -8
  72. package/dist/{deliver-B1jsU2r7.js → deliver-LsxKETro.js} +306 -12
  73. package/dist/{deliver-CLwC284e.js → deliver-xUU3mGHo.js} +302 -8
  74. package/dist/{deps-Cva7QM_t.js → deps-QSwGcoNZ.js} +2 -2
  75. package/dist/{deps-B6602Wid.js → deps-lAAA2zYI.js} +2 -2
  76. package/dist/{devices-cli-DPg_4aW8.js → devices-cli-BG3-2oqt.js} +13 -13
  77. package/dist/{devices-cli-D8K3hZR5.js → devices-cli-VIQtOvt_.js} +13 -13
  78. package/dist/{directory-cli-OGBSVKAZ.js → directory-cli-BCJwjVC0.js} +15 -15
  79. package/dist/{directory-cli-Bn47fFX7.js → directory-cli-jYzZ02gk.js} +14 -14
  80. package/dist/{dispatcher-BHsNwFe-.js → dispatcher-DY51b-Zc.js} +2 -2
  81. package/dist/{dns-cli-DmTHXgwU.js → dns-cli-DHIiMJjS.js} +11 -11
  82. package/dist/{dns-cli-kk2rysJh.js → dns-cli-pZlv87Ib.js} +11 -11
  83. package/dist/{docs-cli-CB77CeM4.js → docs-cli-2JDiwfzP.js} +7 -7
  84. package/dist/{docs-cli-DUcyw0X0.js → docs-cli-BhkYqoIQ.js} +6 -6
  85. package/dist/{doctor-DwqdkfPa.js → doctor-Bf8EhNtA.js} +33 -33
  86. package/dist/{doctor-BZfxDGUg.js → doctor-sYG5V4Co.js} +32 -32
  87. package/dist/entry.js +36 -14
  88. package/dist/{env-DE9xvYOL.js → env-ONzUVAG2.js} +1 -1
  89. package/dist/{exec-4WHuOniw.js → exec-B8lXct-k.js} +31 -13
  90. package/dist/{exec-B8JKbXKW.js → exec-CACT5OAW.js} +1 -1
  91. package/dist/{exec-D12IZYtJ.js → exec-CJFFoM7H.js} +31 -13
  92. package/dist/{exec-DXtR2fhb.js → exec-YIosokWE.js} +1 -1
  93. package/dist/{exec-approvals-cli-GizapOX5.js → exec-approvals-cli-7LH0lwhO.js} +19 -19
  94. package/dist/{exec-approvals-cli-BWO0Rs-a.js → exec-approvals-cli-apGnQbpj.js} +19 -19
  95. package/dist/extensionAPI.js +1108 -661
  96. package/dist/{fetch-CqZP8jwB.js → fetch-DmiOpALK.js} +5 -3
  97. package/dist/{fetch-timeout-B2KlHXi3.js → fetch-timeout-BEtUjM1S.js} +5 -3
  98. package/dist/{fetch-timeout-ohY5QmsW.js → fetch-timeout-DEoXG_SF.js} +5 -3
  99. package/dist/{fetch-timeout-4UKsdtE1.js → fetch-timeout-DTK9vxex.js} +5 -3
  100. package/dist/{gateway-cli-Bbd1Xbsc.js → gateway-cli-DUdYxlZS.js} +315 -103
  101. package/dist/{gateway-cli-PR1S0BTe.js → gateway-cli-DbvWmE-9.js} +314 -102
  102. package/dist/{gateway-rpc-8gue7Qjt.js → gateway-rpc-BByb2Snz.js} +3 -3
  103. package/dist/{gateway-rpc-DjuxyOm-.js → gateway-rpc-wXSCUZXj.js} +3 -3
  104. package/dist/{github-copilot-auth-B3chCDfc.js → github-copilot-auth-D7ewvpMd.js} +16 -8
  105. package/dist/{github-copilot-auth-Cm2SB8Qf.js → github-copilot-auth-DDispnyz.js} +16 -8
  106. package/dist/{github-copilot-token-SLWintYd.js → github-copilot-token-Cfs0Wxr8.js} +1 -1
  107. package/dist/{gmail-setup-utils-Cgh0ptgA.js → gmail-setup-utils-Cfns8TQx.js} +3 -3
  108. package/dist/{gmail-setup-utils-WDyf1gTU.js → gmail-setup-utils-DJb-_5kO.js} +4 -4
  109. package/dist/{health-format-C0C_Apce.js → health-format-KGPokKJH.js} +68 -28
  110. package/dist/{health-format-gLMfE2wf.js → health-format-LZDxu3rv.js} +67 -27
  111. package/dist/{help-format-5iAL_46a.js → help-format-C48TXngO.js} +1 -1
  112. package/dist/{help-format-DUy1KRxq.js → help-format-R5fLToDw.js} +1 -1
  113. package/dist/{hooks-cli-CEN1h1ya.js → hooks-cli-CT8JCRkH.js} +46 -44
  114. package/dist/{hooks-cli-DrchIqSi.js → hooks-cli-S1MKumJO.js} +47 -45
  115. package/dist/{hooks-status-Cgy6AtQk.js → hooks-status-Cw0xD8Lt.js} +3 -3
  116. package/dist/{hooks-status--xVLpAXz.js → hooks-status-D9MhwHRp.js} +3 -3
  117. package/dist/{image-Dkawt9Kg.js → image-Brk1sJbw.js} +4 -4
  118. package/dist/{image-DI9s9eEx.js → image-C4Nn2p3e.js} +5 -5
  119. package/dist/{image-LxFvu0wL.js → image-DgtfXMcX.js} +5 -5
  120. package/dist/{image-B4mDPdyz.js → image-RKwc3fsL.js} +4 -4
  121. package/dist/index.js +83 -83
  122. package/dist/{installs-NS0VMPN7.js → installs-CrLcWYHe.js} +4 -4
  123. package/dist/{installs-DA-eSN1B.js → installs-DscWb9b9.js} +5 -5
  124. package/dist/{links-CV4oki2u.js → links-B8LAzWwg.js} +1 -1
  125. package/dist/{links-7M-j83As.js → links-Eax1UO3w.js} +1 -1
  126. package/dist/llm-slug-generator.js +15 -15
  127. package/dist/{loader-Caow9TPA.js → loader-KjT074JR.js} +1105 -762
  128. package/dist/{logging-CeHn2itV.js → logging-BAyPwvdH.js} +1 -1
  129. package/dist/{logging-D0MyqUlV.js → logging-CRq4h04P.js} +2 -2
  130. package/dist/{login-qr-Xx8yJrSc.js → login-qr-B6ZgAuIf.js} +5 -5
  131. package/dist/{login-qr-CoskdtvN.js → login-qr-Bua-p0nG.js} +2 -2
  132. package/dist/{login-qr-CAk9D-FM.js → login-qr-CuvemJj4.js} +6 -6
  133. package/dist/{login-qr-kUyMWXV1.js → login-qr-Djr1JfIf.js} +2 -2
  134. package/dist/{logs-cli-B476pzJS.js → logs-cli-9IAV7rWY.js} +15 -15
  135. package/dist/{logs-cli-BQRUI_PO.js → logs-cli-EiKzUFPa.js} +14 -14
  136. package/dist/{manager-CBApH7eR.js → manager-BIMh_eSm.js} +5 -5
  137. package/dist/{manager-CyJH6WMg.js → manager-CwinWQoz.js} +5 -5
  138. package/dist/{manager-DScY_ZTT.js → manager-DkqF1GiK.js} +7 -7
  139. package/dist/{manager-DseK7RWj.js → manager-T1XfGchB.js} +8 -8
  140. package/dist/{manifest-registry-DFckk-L8.js → manifest-registry-CQhdnDBZ.js} +2 -2
  141. package/dist/{manifest-registry-BTgLN_W2.js → manifest-registry-u0okVSkU.js} +2 -2
  142. package/dist/{message-channel-0717wOz-.js → message-channel-BLi2a6Yw.js} +1 -1
  143. package/dist/{message-channel-BlgPSDAh.js → message-channel-C_MmebBt.js} +1 -1
  144. package/dist/{model-auth-CbqRVYRp.js → model-auth-CabXIF6O.js} +57 -19
  145. package/dist/{model-selection-unMJyUIE.js → model-selection-BLuqsGVB.js} +59 -21
  146. package/dist/{model-selection-B9Y7dKQd.js → model-selection-C1GmkTAV.js} +57 -19
  147. package/dist/{models-cli-B1cLGcRz.js → models-cli-9jmDv-h3.js} +50 -48
  148. package/dist/{models-cli-D7sChCi6.js → models-cli-zS9rtWz8.js} +48 -46
  149. package/dist/{node-cli-ic2C1xs2.js → node-cli-CrpTxTTs.js} +26 -24
  150. package/dist/{node-cli-CS3KwBh1.js → node-cli-wemUMCg-.js} +25 -23
  151. package/dist/{node-service-D_Cdq1JI.js → node-service-C8DTHTMg.js} +2 -2
  152. package/dist/{node-service-_vgO5xR-.js → node-service-WQuEKz6W.js} +1 -1
  153. package/dist/{nodes-cli-CipcvVMc.js → nodes-cli-BaU2SIFw.js} +16 -16
  154. package/dist/{nodes-cli-B1meaW7S.js → nodes-cli-Dx23D72n.js} +16 -16
  155. package/dist/{nodes-screen-N-4_0VIu.js → nodes-screen-C0IuBqUL.js} +1 -1
  156. package/dist/{note-CAM9PbSJ.js → note-BhRSeNeu.js} +2 -2
  157. package/dist/{note-Ci08TSbV.js → note-hhtubr2j.js} +1 -1
  158. package/dist/{onboard-channels-DMcOT0dj.js → onboard-channels-C501x8GI.js} +8 -8
  159. package/dist/{onboard-channels-CsT3E4bT.js → onboard-channels-Dxzroasd.js} +8 -8
  160. package/dist/{onboard-skills-DoxkpnEU.js → onboard-skills-DV0Qzvjj.js} +19 -19
  161. package/dist/{onboard-skills-D-BrCoRN.js → onboard-skills-rlBHcu3Q.js} +18 -18
  162. package/dist/{onboarding-B92952fz.js → onboarding-CN-EDLjd.js} +34 -34
  163. package/dist/{pairing-cli-BDUJ5VoX.js → pairing-cli-CDHG4xuI.js} +15 -15
  164. package/dist/{pairing-cli-0wbU1u8d.js → pairing-cli-CQP34Dlx.js} +14 -14
  165. package/dist/{pairing-labels-3o3QO3Qn.js → pairing-labels-B6CN0SNH.js} +1 -1
  166. package/dist/{pairing-labels-Bin1K7_f.js → pairing-labels-CgNHnjzT.js} +1 -1
  167. package/dist/{pairing-store-CL4rJ7m7.js → pairing-store-CmlRVqOz.js} +2 -2
  168. package/dist/{pairing-store-fIWI3pXG.js → pairing-store-Dp5_JGnG.js} +3 -3
  169. package/dist/{path-env-CXWUFfFv.js → path-env-CLvYNwtL.js} +1 -1
  170. package/dist/{path-env-C5FR_Eay.js → path-env-CaYUVIML.js} +2 -2
  171. package/dist/{paths-DwKNqk_S.js → paths-B0a4ywSO.js} +30 -5
  172. package/dist/{paths-RITJT4UY.js → paths-B49s6UZQ.js} +30 -5
  173. package/dist/{paths-CB2fqqbX.js → paths-D0O87MfH.js} +30 -5
  174. package/dist/{paths-IivnSNkP.js → paths-DLINmNFQ.js} +31 -6
  175. package/dist/{pi-embedded-DhYItk8O.js → pi-embedded-Ctrt2kz0.js} +1109 -662
  176. package/dist/{pi-embedded-helpers-CmftU5Zj.js → pi-embedded-helpers-CMKLjW6X.js} +8 -5
  177. package/dist/{pi-embedded-helpers-CfXnSIFx.js → pi-embedded-helpers-CUzTc1v6.js} +170 -19
  178. package/dist/{pi-embedded-helpers-Uan-3N1T.js → pi-embedded-helpers-DfwkwPYD.js} +7 -4
  179. package/dist/{pi-embedded-helpers-Bri9tk9g.js → pi-embedded-helpers-WDwx99UA.js} +170 -19
  180. package/dist/{pi-tools.policy-CJFi1sny.js → pi-tools.policy-BpsROZbz.js} +4 -4
  181. package/dist/{plugin-auto-enable-BY4CqJbD.js → plugin-auto-enable-Bqhc3w5n.js} +5 -5
  182. package/dist/{plugin-auto-enable-DbQrtQjL.js → plugin-auto-enable-PW76g_PJ.js} +5 -5
  183. package/dist/plugin-sdk/agents/pi-embedded-runner/run/params.d.ts +2 -0
  184. package/dist/plugin-sdk/agents/pi-embedded-runner/run/types.d.ts +2 -0
  185. package/dist/plugin-sdk/agents/pi-embedded-runner/types.d.ts +15 -0
  186. package/dist/plugin-sdk/agents/pi-embedded-subscribe.handlers.tools.d.ts +1 -1
  187. package/dist/plugin-sdk/agents/pi-embedded-subscribe.handlers.types.d.ts +2 -0
  188. package/dist/plugin-sdk/agents/pi-embedded-subscribe.types.d.ts +2 -0
  189. package/dist/plugin-sdk/agents/session-tool-result-guard-wrapper.d.ts +2 -0
  190. package/dist/plugin-sdk/agents/session-tool-result-guard.d.ts +4 -0
  191. package/dist/plugin-sdk/agents/tools/agent-step.d.ts +3 -0
  192. package/dist/plugin-sdk/agents/usage.d.ts +1 -0
  193. package/dist/plugin-sdk/auto-reply/reply/reply-reference.d.ts +1 -1
  194. package/dist/plugin-sdk/auto-reply/reply/session-run-accounting.d.ts +11 -0
  195. package/dist/plugin-sdk/auto-reply/reply/session-usage.d.ts +8 -0
  196. package/dist/plugin-sdk/browser/control-auth.d.ts +13 -0
  197. package/dist/plugin-sdk/channels/plugins/onboarding/signal.d.ts +1 -0
  198. package/dist/plugin-sdk/cli/prompt.d.ts +1 -0
  199. package/dist/plugin-sdk/commands/agent/types.d.ts +2 -0
  200. package/dist/plugin-sdk/config/sessions/paths.d.ts +7 -2
  201. package/dist/plugin-sdk/config/types.agents.d.ts +2 -0
  202. package/dist/plugin-sdk/config/types.discord.d.ts +5 -0
  203. package/dist/plugin-sdk/config/types.gateway.d.ts +15 -0
  204. package/dist/plugin-sdk/config/types.hooks.d.ts +15 -0
  205. package/dist/plugin-sdk/config/zod-schema.agents.d.ts +1 -0
  206. package/dist/plugin-sdk/config/zod-schema.d.ts +11 -0
  207. package/dist/plugin-sdk/config/zod-schema.providers-core.d.ts +9 -0
  208. package/dist/plugin-sdk/config/zod-schema.providers.d.ts +4 -0
  209. package/dist/plugin-sdk/discord/monitor/allow-list.d.ts +15 -0
  210. package/dist/plugin-sdk/discord/send.types.d.ts +3 -0
  211. package/dist/plugin-sdk/gateway/auth.d.ts +36 -0
  212. package/dist/plugin-sdk/gateway/protocol/schema/agent.d.ts +6 -0
  213. package/dist/plugin-sdk/gateway/session-utils.fs.d.ts +3 -1
  214. package/dist/plugin-sdk/index.js +295 -99
  215. package/dist/plugin-sdk/infra/binaries.d.ts +3 -0
  216. package/dist/plugin-sdk/infra/heartbeat-runner.d.ts +1 -0
  217. package/dist/plugin-sdk/infra/net/fetch-guard.d.ts +1 -0
  218. package/dist/plugin-sdk/infra/net/ssrf.d.ts +1 -0
  219. package/dist/plugin-sdk/infra/tailscale.d.ts +34 -0
  220. package/dist/plugin-sdk/infra/tmp-openclaw-dir.d.ts +10 -0
  221. package/dist/plugin-sdk/logging/logger.d.ts +1 -1
  222. package/dist/plugin-sdk/media/input-files.d.ts +5 -0
  223. package/dist/plugin-sdk/routing/resolve-route.d.ts +3 -1
  224. package/dist/plugin-sdk/security/external-content.d.ts +1 -1
  225. package/dist/plugin-sdk/security/secret-equal.d.ts +1 -0
  226. package/dist/plugin-sdk/sessions/input-provenance.d.ts +16 -0
  227. package/dist/plugin-sdk/signal/monitor/event-handler.types.d.ts +8 -0
  228. package/dist/plugin-sdk/signal/monitor/mentions.d.ts +2 -0
  229. package/dist/{plugins-3GyCj5KL.js → plugins-4Hqd1WGf.js} +3 -3
  230. package/dist/{plugins-BL9lIXSA.js → plugins-X7d_tfTE.js} +4 -4
  231. package/dist/{plugins-cli-Ce7VsvZh.js → plugins-cli-Bgku3EGj.js} +253 -46
  232. package/dist/{plugins-cli-e9gUebMd.js → plugins-cli-CVToH3if.js} +254 -47
  233. package/dist/{ports-DupIRXQ0.js → ports-qkt29rdC.js} +2 -2
  234. package/dist/{program-u22vbFpH.js → program-Cf7lkBur.js} +82 -82
  235. package/dist/{progress-g9R--HZD.js → progress-C9kngsTD.js} +1 -1
  236. package/dist/{progress-Da1ehW-x.js → progress-DWqhRakV.js} +1 -1
  237. package/dist/{prompt-style-Dc0C5HC9.js → prompt-style-BFH5D5LN.js} +1 -1
  238. package/dist/{prompt-style-lmJDcgtA.js → prompt-style-CIbmaxSa.js} +1 -1
  239. package/dist/{pw-ai-C43wv1ZF.js → pw-ai-8mdv3h-d.js} +7 -6
  240. package/dist/{pw-ai-DTZVjndL.js → pw-ai-CM1IsSgZ.js} +5 -5
  241. package/dist/{pw-ai-zVebjrSG.js → pw-ai-FGoRVblI.js} +3 -3
  242. package/dist/{pw-ai-CWrnJ98b.js → pw-ai-sS1fRKW_.js} +3 -3
  243. package/dist/{qmd-manager-NPD5Yh_4.js → qmd-manager-C67Fc8aN.js} +4 -4
  244. package/dist/{qmd-manager-ozZ933qc.js → qmd-manager-CXVbfg99.js} +7 -7
  245. package/dist/{qmd-manager-DBCZ1sio.js → qmd-manager-RMRE8Tqt.js} +6 -6
  246. package/dist/{qmd-manager-a9Bt0405.js → qmd-manager-pyc_MTIe.js} +4 -4
  247. package/dist/{register.subclis-BpX3ulH1.js → register.subclis-C02e4zuJ.js} +28 -28
  248. package/dist/{reply-m467_fOC.js → reply-DICXkh_C.js} +911 -568
  249. package/dist/{routes-82Ywfho6.js → routes-CmOI1hIH.js} +29 -11
  250. package/dist/{routes-BqxA3ZYr.js → routes-DewK5tq2.js} +29 -12
  251. package/dist/{rpc-DcGBG-Fp.js → rpc-DHr30euf.js} +3 -3
  252. package/dist/{rpc-CfdBHlnp.js → rpc-T300F8zI.js} +3 -3
  253. package/dist/{run-main-aolvSfj3.js → run-main-C5wpthq1.js} +84 -84
  254. package/dist/{runner-C1G8RFWl.js → runner-CY0nmVme.js} +9 -9
  255. package/dist/{runner-BCBs8JKA.js → runner-Cfm5nTMc.js} +6 -6
  256. package/dist/{runner-CInKPsiP.js → runner-D_dujMod.js} +8 -8
  257. package/dist/{runner-Cwfn-VOM.js → runner-DrGYLH5K.js} +6 -6
  258. package/dist/{sandbox-B0K9e6Fw.js → sandbox-BKYnhYQH.js} +23 -15
  259. package/dist/{sandbox-BW8Xnkw1.js → sandbox-Bhjnh1Xg.js} +21 -13
  260. package/dist/{sandbox-cli-mKCs2J0i.js → sandbox-cli-DBsAjZJN.js} +20 -20
  261. package/dist/{sandbox-cli-BD5LkZ0B.js → sandbox-cli-rV9LtFeu.js} +19 -19
  262. package/dist/{security-cli-kgI4soGy.js → security-cli-BIwJM_rs.js} +27 -27
  263. package/dist/{security-cli-kz8TiyqU.js → security-cli-BRjny8Yu.js} +26 -26
  264. package/dist/{server-context-fX4xiYRh.js → server-context-BGpGs3qd.js} +7 -7
  265. package/dist/{server-context-Lb-eUZG_.js → server-context-Cl0U0vE3.js} +5 -5
  266. package/dist/{server-node-events-Dx18uVrH.js → server-node-events-CBfTbiTA.js} +45 -43
  267. package/dist/{server-node-events-KqZMN30F.js → server-node-events-QCvh8EgI.js} +45 -43
  268. package/dist/{service-DZMXgMra.js → service--nPk7DvT.js} +3 -3
  269. package/dist/{service-DNcIZ5Kp.js → service-99RDXwX4.js} +2 -2
  270. package/dist/{service-audit-0WLGnoNT.js → service-audit-DnLmRGQt.js} +4 -4
  271. package/dist/{service-audit-uhZSlxeb.js → service-audit-ckBaRCVC.js} +3 -3
  272. package/dist/{session-cost-usage-HU4OeRgw.js → session-cost-usage-D7HuoSSD.js} +10 -8
  273. package/dist/{session-cost-usage-CL8gnHRN.js → session-cost-usage-D9hHANWI.js} +10 -8
  274. package/dist/{shared-j4Qtr475.js → shared-Bs4vduG4.js} +3 -3
  275. package/dist/{shared-BBw6F-YC.js → shared-CEY5IkwG.js} +2 -2
  276. package/dist/{shared-DOZs2SoH.js → shared-DRohONn_.js} +3 -3
  277. package/dist/{shared-CtP9K-o2.js → shared-ICqOZibV.js} +3 -3
  278. package/dist/{skill-scanner-C_fQzVDu.js → skill-scanner-rHMtUHtP.js} +1 -1
  279. package/dist/{skills-BvPUNjxo.js → skills-DRjfSQT3.js} +128 -4
  280. package/dist/{skills-aFOsriMP.js → skills-DprQj9X2.js} +129 -5
  281. package/dist/{skills-cli-oWaTJzZd.js → skills-cli-9WO-C55s.js} +12 -12
  282. package/dist/{skills-cli-E6shXpdd.js → skills-cli-B9eej-EW.js} +13 -13
  283. package/dist/{skills-status-D4vbIMnz.js → skills-status-5U3P3YfJ.js} +3 -3
  284. package/dist/{skills-status-DJDaA2Ur.js → skills-status-TDIgVd1K.js} +2 -2
  285. package/dist/{sqlite-B7FPASCO.js → sqlite-BINzs1U0.js} +2 -2
  286. package/dist/{sqlite-B4Z1_Ioc.js → sqlite-D4w5TejA.js} +2 -2
  287. package/dist/{sqlite-BkYnxkQO.js → sqlite-DRRHmlug.js} +2 -2
  288. package/dist/{sqlite-EuQPVXvn.js → sqlite-F6PGkEm1.js} +2 -2
  289. package/dist/{status-B2Yr-2J5.js → status-BKGkKC_v.js} +3 -3
  290. package/dist/{status-DW7m5xUN.js → status-CiHtHdaa.js} +4 -4
  291. package/dist/{status-CxhnUa5J.js → status-DDWoOpeB.js} +33 -33
  292. package/dist/{subsystem-Bv7dGhES.js → subsystem-BoExtIHo.js} +32 -13
  293. package/dist/{system-cli-0JXhJNWm.js → system-cli-B6lr60Io.js} +14 -14
  294. package/dist/{system-cli-D-0OaMtH.js → system-cli-CprW9G3h.js} +14 -14
  295. package/dist/{systemd-CNTodvCO.js → systemd-C0VZriGM.js} +2 -2
  296. package/dist/{systemd-CUJJHgHa.js → systemd-DrmBtJ5T.js} +3 -3
  297. package/dist/{systemd-hints-cmHtrXUl.js → systemd-hints-DZtXiVHa.js} +1 -1
  298. package/dist/{systemd-linger-CArPbmvv.js → systemd-linger-NC2kl1SC.js} +2 -2
  299. package/dist/{systemd-linger-XvT9Y9sb.js → systemd-linger-xdn3BdPh.js} +2 -2
  300. package/dist/{table-DzBBIqHO.js → table-B8dx3v4v.js} +2 -2
  301. package/dist/{table-oJQPTUL6.js → table-CwulTLQp.js} +1 -1
  302. package/dist/{tool-display-Na-EVL83.js → tool-display-CZRIDMRm.js} +1 -1
  303. package/dist/{tool-display-sHJa3kRs.js → tool-display-ClRud3pg.js} +2 -2
  304. package/dist/{tui-nGp8ltQK.js → tui-CVTQn-dC.js} +9 -9
  305. package/dist/{tui-Biw7aqPj.js → tui-Lu8FdrlK.js} +9 -9
  306. package/dist/{tui-cli-C9FEfG7C.js → tui-cli-BLpTj1X9.js} +25 -25
  307. package/dist/{tui-cli-Dxnu5JGl.js → tui-cli-BLx5kL2I.js} +25 -25
  308. package/dist/{tui-formatters-BiNTNGwg.js → tui-formatters-CNySEfJN.js} +5 -5
  309. package/dist/{tui-formatters-C_baVYUz.js → tui-formatters-DePhZK3J.js} +5 -5
  310. package/dist/{update-C4rsLj2F.js → update-DHVxMTpQ.js} +3 -3
  311. package/dist/{update-uwUWrKFu.js → update-DU1geolI.js} +3 -3
  312. package/dist/{update-cli-cNd_G9E6.js → update-cli-C0hUvJWK.js} +66 -66
  313. package/dist/{update-cli-CBXp-c4C.js → update-cli-Wb1GB3rL.js} +68 -68
  314. package/dist/{update-runner-BLsqC24J.js → update-runner--ixK4J3W.js} +10 -10
  315. package/dist/{update-runner-C_FDpmA3.js → update-runner-7Qa1T9y6.js} +9 -9
  316. package/dist/{utils-Dk86IbEs.js → utils-BLJAc3ZV.js} +1 -1
  317. package/dist/{utils-BHPdZE4h.js → utils-Cd9QdCHh.js} +1 -1
  318. package/dist/{webhooks-cli-BpBKXL7W.js → webhooks-cli-DgcMy7RG.js} +12 -12
  319. package/dist/{webhooks-cli-wNfhfKqm.js → webhooks-cli-aVzUcJY9.js} +11 -11
  320. package/dist/{widearea-dns-WVCWJTEb.js → widearea-dns-BaIgNEhY.js} +1 -1
  321. package/dist/{widearea-dns-BWYPcfby.js → widearea-dns-DzuRdwk5.js} +1 -1
  322. package/dist/{ws-log-Cafylho7.js → ws-log-CIXbLCka.js} +1 -1
  323. package/dist/{ws-log-DTUOUVgR.js → ws-log-DcQFZByi.js} +1 -1
  324. package/dist/{wsl-B-H6Z5wp.js → wsl-BUOkxKJu.js} +2 -2
  325. package/docs/automation/webhook.md +43 -2
  326. package/docs/channels/discord.md +29 -1
  327. package/docs/cli/plugins.md +20 -1
  328. package/docs/cli/security.md +1 -0
  329. package/docs/concepts/session-tool.md +1 -0
  330. package/docs/gateway/configuration-reference.md +11 -0
  331. package/docs/gateway/configuration.md +3 -0
  332. package/docs/gateway/openresponses-http-api.md +15 -0
  333. package/docs/gateway/security/index.md +3 -0
  334. package/docs/help/faq.md +9 -0
  335. package/docs/install/installer.md +20 -0
  336. package/docs/reference/transcript-hygiene.md +18 -0
  337. package/docs/tools/browser.md +6 -0
  338. package/extensions/diagnostics-otel/package.json +9 -9
  339. package/extensions/feishu/package.json +1 -1
  340. package/extensions/feishu/src/config-schema.ts +6 -0
  341. package/extensions/feishu/src/reply-dispatcher.test.ts +116 -0
  342. package/extensions/feishu/src/reply-dispatcher.ts +124 -67
  343. package/extensions/feishu/src/streaming-card.ts +223 -0
  344. package/extensions/feishu/src/targets.test.ts +16 -0
  345. package/extensions/feishu/src/targets.ts +1 -1
  346. package/extensions/irc/src/client.ts +1 -1
  347. package/extensions/minimax-portal-auth/index.ts +7 -5
  348. package/extensions/nostr/package.json +1 -1
  349. package/package.json +13 -13
  350. package/dist/auth-BcNHFK-i.js +0 -184
  351. package/dist/auth-jrfLXze7.js +0 -184
  352. /package/dist/{archive-DqNr5i8b.js → archive-beaSfAzA.js} +0 -0
  353. /package/dist/{brew-BIrWdDps.js → brew-BUIxHEkn.js} +0 -0
  354. /package/dist/{brew-6UyogeLe.js → brew-ROHf0-Xp.js} +0 -0
  355. /package/dist/{constants-DuoCkWRh.js → constants-BvQ6S8j5.js} +0 -0
  356. /package/dist/{errors-x4NYs-1P.js → errors-DjZBTJJ3.js} +0 -0
  357. /package/dist/{helpers-BDvtkJjw.js → helpers-HyeZXsnu.js} +0 -0
  358. /package/dist/{is-main-CE1eOBYb.js → is-main-BWoXGz7p.js} +0 -0
  359. /package/dist/{parse-Cjiudy6x.js → parse-Bw0oH-rT.js} +0 -0
  360. /package/dist/{parse-timeout-DFSPLxpY.js → parse-timeout-D1XX_zN_.js} +0 -0
  361. /package/dist/{prompts-BOz5176z.js → prompts-Bg96reub.js} +0 -0
  362. /package/dist/{redact-DuEEf1p1.js → redact-Br9GfacZ.js} +0 -0
  363. /package/dist/{skill-scanner-CprFkZib.js → skill-scanner-CucvxYhu.js} +0 -0
  364. /package/dist/{transcript-events-CZ8CG4ht.js → transcript-events-BtNd-j6q.js} +0 -0
@@ -265,6 +265,9 @@ tool calls. Reduce the blast radius by:
265
265
  - Using a read-only or tool-disabled **reader agent** to summarize untrusted content,
266
266
  then pass the summary to your main agent.
267
267
  - Keeping `web_search` / `web_fetch` / `browser` off for tool-enabled agents unless needed.
268
+ - For OpenResponses URL inputs (`input_file` / `input_image`), set tight
269
+ `gateway.http.endpoints.responses.files.urlAllowlist` and
270
+ `gateway.http.endpoints.responses.images.urlAllowlist`, and keep `maxUrlParts` low.
268
271
  - Enabling sandboxing and strict tool allowlists for any agent that touches untrusted input.
269
272
  - Keeping secrets out of prompts; pass them via env/config on the gateway host instead.
270
273
 
package/docs/help/faq.md CHANGED
@@ -546,6 +546,15 @@ For a hackable (git) install:
546
546
  curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git --verbose
547
547
  ```
548
548
 
549
+ Windows (PowerShell) equivalent:
550
+
551
+ ```powershell
552
+ # install.ps1 has no dedicated -Verbose flag yet.
553
+ Set-PSDebug -Trace 1
554
+ & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
555
+ Set-PSDebug -Trace 0
556
+ ```
557
+
549
558
  More options: [Installer flags](/install/installer).
550
559
 
551
560
  ### Windows install says git not found or openclaw not recognized
@@ -286,6 +286,14 @@ Designed for environments where you want everything under a local prefix (defaul
286
286
  & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -DryRun
287
287
  ```
288
288
  </Tab>
289
+ <Tab title="Debug trace">
290
+ ```powershell
291
+ # install.ps1 has no dedicated -Verbose flag yet.
292
+ Set-PSDebug -Trace 1
293
+ & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
294
+ Set-PSDebug -Trace 0
295
+ ```
296
+ </Tab>
289
297
  </Tabs>
290
298
 
291
299
  <AccordionGroup>
@@ -379,6 +387,18 @@ Use non-interactive flags/env vars for predictable runs.
379
387
  Run `npm config get prefix`, append `\bin`, add that directory to user PATH, then reopen PowerShell.
380
388
  </Accordion>
381
389
 
390
+ <Accordion title="Windows: how to get verbose installer output">
391
+ `install.ps1` does not currently expose a `-Verbose` switch.
392
+ Use PowerShell tracing for script-level diagnostics:
393
+
394
+ ```powershell
395
+ Set-PSDebug -Trace 1
396
+ & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
397
+ Set-PSDebug -Trace 0
398
+ ```
399
+
400
+ </Accordion>
401
+
382
402
  <Accordion title="openclaw not found after install">
383
403
  Usually a PATH issue. See [Node.js troubleshooting](/install/node#troubleshooting).
384
404
  </Accordion>
@@ -24,6 +24,7 @@ Scope includes:
24
24
  - Turn validation / ordering
25
25
  - Thought signature cleanup
26
26
  - Image payload sanitization
27
+ - User-input provenance tagging (for inter-session routed prompts)
27
28
 
28
29
  If you need transcript storage details, see:
29
30
 
@@ -72,6 +73,23 @@ Implementation:
72
73
 
73
74
  ---
74
75
 
76
+ ## Global rule: inter-session input provenance
77
+
78
+ When an agent sends a prompt into another session via `sessions_send` (including
79
+ agent-to-agent reply/announce steps), OpenClaw persists the created user turn with:
80
+
81
+ - `message.provenance.kind = "inter_session"`
82
+
83
+ This metadata is written at transcript append time and does not change role
84
+ (`role: "user"` remains for provider compatibility). Transcript readers can use
85
+ this to avoid treating routed internal prompts as end-user-authored instructions.
86
+
87
+ During context rebuild, OpenClaw also prepends a short `[Inter-session message]`
88
+ marker to those user turns in-memory so the model can distinguish them from
89
+ external end-user instructions.
90
+
91
+ ---
92
+
75
93
  ## Provider matrix (current behavior)
76
94
 
77
95
  **OpenAI / OpenAI Codex**
@@ -192,6 +192,7 @@ Notes:
192
192
  Key ideas:
193
193
 
194
194
  - Browser control is loopback-only; access flows through the Gateway’s auth or node pairing.
195
+ - If browser control is enabled and no auth is configured, OpenClaw auto-generates `gateway.auth.token` on startup and persists it to config.
195
196
  - Keep the Gateway and any node hosts on a private network (Tailscale); avoid public exposure.
196
197
  - Treat remote CDP URLs/tokens as secrets; prefer env vars or a secrets manager.
197
198
 
@@ -315,6 +316,11 @@ For local integrations only, the Gateway exposes a small loopback HTTP API:
315
316
 
316
317
  All endpoints accept `?profile=<name>`.
317
318
 
319
+ If gateway auth is configured, browser HTTP routes require auth too:
320
+
321
+ - `Authorization: Bearer <gateway token>`
322
+ - `x-openclaw-password: <gateway password>` or HTTP Basic auth with that password
323
+
318
324
  ### Playwright requirement
319
325
 
320
326
  Some features (navigate/act/AI snapshot/role snapshot, element screenshots, PDF) require
@@ -5,15 +5,15 @@
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@opentelemetry/api": "^1.9.0",
8
- "@opentelemetry/api-logs": "^0.211.0",
9
- "@opentelemetry/exporter-logs-otlp-http": "^0.211.0",
10
- "@opentelemetry/exporter-metrics-otlp-http": "^0.211.0",
11
- "@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
12
- "@opentelemetry/resources": "^2.5.0",
13
- "@opentelemetry/sdk-logs": "^0.211.0",
14
- "@opentelemetry/sdk-metrics": "^2.5.0",
15
- "@opentelemetry/sdk-node": "^0.211.0",
16
- "@opentelemetry/sdk-trace-base": "^2.5.0",
8
+ "@opentelemetry/api-logs": "^0.212.0",
9
+ "@opentelemetry/exporter-logs-otlp-http": "^0.212.0",
10
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.212.0",
11
+ "@opentelemetry/exporter-trace-otlp-http": "^0.212.0",
12
+ "@opentelemetry/resources": "^2.5.1",
13
+ "@opentelemetry/sdk-logs": "^0.212.0",
14
+ "@opentelemetry/sdk-metrics": "^2.5.1",
15
+ "@opentelemetry/sdk-node": "^0.212.0",
16
+ "@opentelemetry/sdk-trace-base": "^2.5.1",
17
17
  "@opentelemetry/semantic-conventions": "^1.39.0"
18
18
  },
19
19
  "devDependencies": {
@@ -4,7 +4,7 @@
4
4
  "description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@larksuiteoapi/node-sdk": "^1.58.0",
7
+ "@larksuiteoapi/node-sdk": "^1.59.0",
8
8
  "@sinclair/typebox": "0.34.48",
9
9
  "zod": "^4.3.6"
10
10
  },
@@ -36,6 +36,10 @@ const MarkdownConfigSchema = z
36
36
  // Message render mode: auto (default) = detect markdown, raw = plain text, card = always card
37
37
  const RenderModeSchema = z.enum(["auto", "raw", "card"]).optional();
38
38
 
39
+ // Streaming card mode: when enabled, card replies use Feishu's Card Kit streaming API
40
+ // for incremental text display with a "Thinking..." placeholder
41
+ const StreamingModeSchema = z.boolean().optional();
42
+
39
43
  const BlockStreamingCoalesceSchema = z
40
44
  .object({
41
45
  enabled: z.boolean().optional(),
@@ -142,6 +146,7 @@ export const FeishuAccountConfigSchema = z
142
146
  mediaMaxMb: z.number().positive().optional(),
143
147
  heartbeat: ChannelHeartbeatVisibilitySchema,
144
148
  renderMode: RenderModeSchema,
149
+ streaming: StreamingModeSchema, // Enable streaming card mode (default: true)
145
150
  tools: FeishuToolsConfigSchema,
146
151
  })
147
152
  .strict();
@@ -177,6 +182,7 @@ export const FeishuConfigSchema = z
177
182
  mediaMaxMb: z.number().positive().optional(),
178
183
  heartbeat: ChannelHeartbeatVisibilitySchema,
179
184
  renderMode: RenderModeSchema, // raw = plain text (default), card = interactive card with markdown
185
+ streaming: StreamingModeSchema, // Enable streaming card mode (default: true)
180
186
  tools: FeishuToolsConfigSchema,
181
187
  // Dynamic agent creation for DM users
182
188
  dynamicAgentCreation: DynamicAgentCreationSchema,
@@ -0,0 +1,116 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const resolveFeishuAccountMock = vi.hoisted(() => vi.fn());
4
+ const getFeishuRuntimeMock = vi.hoisted(() => vi.fn());
5
+ const sendMessageFeishuMock = vi.hoisted(() => vi.fn());
6
+ const sendMarkdownCardFeishuMock = vi.hoisted(() => vi.fn());
7
+ const createFeishuClientMock = vi.hoisted(() => vi.fn());
8
+ const resolveReceiveIdTypeMock = vi.hoisted(() => vi.fn());
9
+ const createReplyDispatcherWithTypingMock = vi.hoisted(() => vi.fn());
10
+ const streamingInstances = vi.hoisted(() => [] as any[]);
11
+
12
+ vi.mock("./accounts.js", () => ({ resolveFeishuAccount: resolveFeishuAccountMock }));
13
+ vi.mock("./runtime.js", () => ({ getFeishuRuntime: getFeishuRuntimeMock }));
14
+ vi.mock("./send.js", () => ({
15
+ sendMessageFeishu: sendMessageFeishuMock,
16
+ sendMarkdownCardFeishu: sendMarkdownCardFeishuMock,
17
+ }));
18
+ vi.mock("./client.js", () => ({ createFeishuClient: createFeishuClientMock }));
19
+ vi.mock("./targets.js", () => ({ resolveReceiveIdType: resolveReceiveIdTypeMock }));
20
+ vi.mock("./streaming-card.js", () => ({
21
+ FeishuStreamingSession: class {
22
+ active = false;
23
+ start = vi.fn(async () => {
24
+ this.active = true;
25
+ });
26
+ update = vi.fn(async () => {});
27
+ close = vi.fn(async () => {
28
+ this.active = false;
29
+ });
30
+ isActive = vi.fn(() => this.active);
31
+
32
+ constructor() {
33
+ streamingInstances.push(this);
34
+ }
35
+ },
36
+ }));
37
+
38
+ import { createFeishuReplyDispatcher } from "./reply-dispatcher.js";
39
+
40
+ describe("createFeishuReplyDispatcher streaming behavior", () => {
41
+ beforeEach(() => {
42
+ vi.clearAllMocks();
43
+ streamingInstances.length = 0;
44
+
45
+ resolveFeishuAccountMock.mockReturnValue({
46
+ accountId: "main",
47
+ appId: "app_id",
48
+ appSecret: "app_secret",
49
+ domain: "feishu",
50
+ config: {
51
+ renderMode: "auto",
52
+ streaming: true,
53
+ },
54
+ });
55
+
56
+ resolveReceiveIdTypeMock.mockReturnValue("chat_id");
57
+ createFeishuClientMock.mockReturnValue({});
58
+
59
+ createReplyDispatcherWithTypingMock.mockImplementation((opts) => ({
60
+ dispatcher: {},
61
+ replyOptions: {},
62
+ markDispatchIdle: vi.fn(),
63
+ _opts: opts,
64
+ }));
65
+
66
+ getFeishuRuntimeMock.mockReturnValue({
67
+ channel: {
68
+ text: {
69
+ resolveTextChunkLimit: vi.fn(() => 4000),
70
+ resolveChunkMode: vi.fn(() => "line"),
71
+ resolveMarkdownTableMode: vi.fn(() => "preserve"),
72
+ convertMarkdownTables: vi.fn((text) => text),
73
+ chunkTextWithMode: vi.fn((text) => [text]),
74
+ },
75
+ reply: {
76
+ createReplyDispatcherWithTyping: createReplyDispatcherWithTypingMock,
77
+ resolveHumanDelayConfig: vi.fn(() => undefined),
78
+ },
79
+ },
80
+ });
81
+ });
82
+
83
+ it("keeps auto mode plain text on non-streaming send path", async () => {
84
+ createFeishuReplyDispatcher({
85
+ cfg: {} as never,
86
+ agentId: "agent",
87
+ runtime: {} as never,
88
+ chatId: "oc_chat",
89
+ });
90
+
91
+ const options = createReplyDispatcherWithTypingMock.mock.calls[0]?.[0];
92
+ await options.deliver({ text: "plain text" }, { kind: "final" });
93
+
94
+ expect(streamingInstances).toHaveLength(0);
95
+ expect(sendMessageFeishuMock).toHaveBeenCalledTimes(1);
96
+ expect(sendMarkdownCardFeishuMock).not.toHaveBeenCalled();
97
+ });
98
+
99
+ it("uses streaming session for auto mode markdown payloads", async () => {
100
+ createFeishuReplyDispatcher({
101
+ cfg: {} as never,
102
+ agentId: "agent",
103
+ runtime: { log: vi.fn(), error: vi.fn() } as never,
104
+ chatId: "oc_chat",
105
+ });
106
+
107
+ const options = createReplyDispatcherWithTypingMock.mock.calls[0]?.[0];
108
+ await options.deliver({ text: "```ts\nconst x = 1\n```" }, { kind: "final" });
109
+
110
+ expect(streamingInstances).toHaveLength(1);
111
+ expect(streamingInstances[0].start).toHaveBeenCalledTimes(1);
112
+ expect(streamingInstances[0].close).toHaveBeenCalledTimes(1);
113
+ expect(sendMessageFeishuMock).not.toHaveBeenCalled();
114
+ expect(sendMarkdownCardFeishuMock).not.toHaveBeenCalled();
115
+ });
116
+ });
@@ -3,29 +3,22 @@ import {
3
3
  createTypingCallbacks,
4
4
  logTypingFailure,
5
5
  type ClawdbotConfig,
6
- type RuntimeEnv,
7
6
  type ReplyPayload,
7
+ type RuntimeEnv,
8
8
  } from "openclaw/plugin-sdk";
9
9
  import type { MentionTarget } from "./mention.js";
10
10
  import { resolveFeishuAccount } from "./accounts.js";
11
+ import { createFeishuClient } from "./client.js";
12
+ import { buildMentionedCardContent } from "./mention.js";
11
13
  import { getFeishuRuntime } from "./runtime.js";
12
- import { sendMessageFeishu, sendMarkdownCardFeishu } from "./send.js";
14
+ import { sendMarkdownCardFeishu, sendMessageFeishu } from "./send.js";
15
+ import { FeishuStreamingSession } from "./streaming-card.js";
16
+ import { resolveReceiveIdType } from "./targets.js";
13
17
  import { addTypingIndicator, removeTypingIndicator, type TypingIndicatorState } from "./typing.js";
14
18
 
15
- /**
16
- * Detect if text contains markdown elements that benefit from card rendering.
17
- * Used by auto render mode.
18
- */
19
+ /** Detect if text contains markdown elements that benefit from card rendering */
19
20
  function shouldUseCard(text: string): boolean {
20
- // Code blocks (fenced)
21
- if (/```[\s\S]*?```/.test(text)) {
22
- return true;
23
- }
24
- // Tables (at least header + separator row with |)
25
- if (/\|.+\|[\r\n]+\|[-:| ]+\|/.test(text)) {
26
- return true;
27
- }
28
- return false;
21
+ return /```[\s\S]*?```/.test(text) || /\|.+\|[\r\n]+\|[-:| ]+\|/.test(text);
29
22
  }
30
23
 
31
24
  export type CreateFeishuReplyDispatcherParams = {
@@ -34,35 +27,23 @@ export type CreateFeishuReplyDispatcherParams = {
34
27
  runtime: RuntimeEnv;
35
28
  chatId: string;
36
29
  replyToMessageId?: string;
37
- /** Mention targets, will be auto-included in replies */
38
30
  mentionTargets?: MentionTarget[];
39
- /** Account ID for multi-account support */
40
31
  accountId?: string;
41
32
  };
42
33
 
43
34
  export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherParams) {
44
35
  const core = getFeishuRuntime();
45
36
  const { cfg, agentId, chatId, replyToMessageId, mentionTargets, accountId } = params;
46
-
47
- // Resolve account for config access
48
37
  const account = resolveFeishuAccount({ cfg, accountId });
38
+ const prefixContext = createReplyPrefixContext({ cfg, agentId });
49
39
 
50
- const prefixContext = createReplyPrefixContext({
51
- cfg,
52
- agentId,
53
- });
54
-
55
- // Feishu doesn't have a native typing indicator API.
56
- // We use message reactions as a typing indicator substitute.
57
40
  let typingState: TypingIndicatorState | null = null;
58
-
59
41
  const typingCallbacks = createTypingCallbacks({
60
42
  start: async () => {
61
43
  if (!replyToMessageId) {
62
44
  return;
63
45
  }
64
46
  typingState = await addTypingIndicator({ cfg, messageId: replyToMessageId, accountId });
65
- params.runtime.log?.(`feishu[${account.accountId}]: added typing indicator reaction`);
66
47
  },
67
48
  stop: async () => {
68
49
  if (!typingState) {
@@ -70,24 +51,21 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
70
51
  }
71
52
  await removeTypingIndicator({ cfg, state: typingState, accountId });
72
53
  typingState = null;
73
- params.runtime.log?.(`feishu[${account.accountId}]: removed typing indicator reaction`);
74
54
  },
75
- onStartError: (err) => {
55
+ onStartError: (err) =>
76
56
  logTypingFailure({
77
57
  log: (message) => params.runtime.log?.(message),
78
58
  channel: "feishu",
79
59
  action: "start",
80
60
  error: err,
81
- });
82
- },
83
- onStopError: (err) => {
61
+ }),
62
+ onStopError: (err) =>
84
63
  logTypingFailure({
85
64
  log: (message) => params.runtime.log?.(message),
86
65
  channel: "feishu",
87
66
  action: "stop",
88
67
  error: err,
89
- });
90
- },
68
+ }),
91
69
  });
92
70
 
93
71
  const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg, "feishu", accountId, {
@@ -95,77 +73,139 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
95
73
  });
96
74
  const chunkMode = core.channel.text.resolveChunkMode(cfg, "feishu");
97
75
  const tableMode = core.channel.text.resolveMarkdownTableMode({ cfg, channel: "feishu" });
76
+ const renderMode = account.config?.renderMode ?? "auto";
77
+ const streamingEnabled = account.config?.streaming !== false && renderMode !== "raw";
78
+
79
+ let streaming: FeishuStreamingSession | null = null;
80
+ let streamText = "";
81
+ let lastPartial = "";
82
+ let partialUpdateQueue: Promise<void> = Promise.resolve();
83
+ let streamingStartPromise: Promise<void> | null = null;
84
+
85
+ const startStreaming = () => {
86
+ if (!streamingEnabled || streamingStartPromise || streaming) {
87
+ return;
88
+ }
89
+ streamingStartPromise = (async () => {
90
+ const creds =
91
+ account.appId && account.appSecret
92
+ ? { appId: account.appId, appSecret: account.appSecret, domain: account.domain }
93
+ : null;
94
+ if (!creds) {
95
+ return;
96
+ }
97
+
98
+ streaming = new FeishuStreamingSession(createFeishuClient(account), creds, (message) =>
99
+ params.runtime.log?.(`feishu[${account.accountId}] ${message}`),
100
+ );
101
+ try {
102
+ await streaming.start(chatId, resolveReceiveIdType(chatId));
103
+ } catch (error) {
104
+ params.runtime.error?.(`feishu: streaming start failed: ${String(error)}`);
105
+ streaming = null;
106
+ }
107
+ })();
108
+ };
109
+
110
+ const closeStreaming = async () => {
111
+ if (streamingStartPromise) {
112
+ await streamingStartPromise;
113
+ }
114
+ await partialUpdateQueue;
115
+ if (streaming?.isActive()) {
116
+ let text = streamText;
117
+ if (mentionTargets?.length) {
118
+ text = buildMentionedCardContent(mentionTargets, text);
119
+ }
120
+ await streaming.close(text);
121
+ }
122
+ streaming = null;
123
+ streamingStartPromise = null;
124
+ streamText = "";
125
+ lastPartial = "";
126
+ };
98
127
 
99
128
  const { dispatcher, replyOptions, markDispatchIdle } =
100
129
  core.channel.reply.createReplyDispatcherWithTyping({
101
130
  responsePrefix: prefixContext.responsePrefix,
102
131
  responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
103
132
  humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, agentId),
104
- onReplyStart: typingCallbacks.onReplyStart,
105
- deliver: async (payload: ReplyPayload) => {
106
- params.runtime.log?.(
107
- `feishu[${account.accountId}] deliver called: text=${payload.text?.slice(0, 100)}`,
108
- );
133
+ onReplyStart: () => {
134
+ if (streamingEnabled && renderMode === "card") {
135
+ startStreaming();
136
+ }
137
+ void typingCallbacks.onReplyStart?.();
138
+ },
139
+ deliver: async (payload: ReplyPayload, info) => {
109
140
  const text = payload.text ?? "";
110
141
  if (!text.trim()) {
111
- params.runtime.log?.(`feishu[${account.accountId}] deliver: empty text, skipping`);
112
142
  return;
113
143
  }
114
144
 
115
- // Check render mode: auto (default), raw, or card
116
- const feishuCfg = account.config;
117
- const renderMode = feishuCfg?.renderMode ?? "auto";
118
-
119
- // Determine if we should use card for this message
120
145
  const useCard = renderMode === "card" || (renderMode === "auto" && shouldUseCard(text));
121
146
 
122
- // Only include @mentions in the first chunk (avoid duplicate @s)
123
- let isFirstChunk = true;
147
+ if ((info?.kind === "block" || info?.kind === "final") && streamingEnabled && useCard) {
148
+ startStreaming();
149
+ if (streamingStartPromise) {
150
+ await streamingStartPromise;
151
+ }
152
+ }
153
+
154
+ if (streaming?.isActive()) {
155
+ if (info?.kind === "final") {
156
+ streamText = text;
157
+ await closeStreaming();
158
+ }
159
+ return;
160
+ }
124
161
 
162
+ let first = true;
125
163
  if (useCard) {
126
- // Card mode: send as interactive card with markdown rendering
127
- const chunks = core.channel.text.chunkTextWithMode(text, textChunkLimit, chunkMode);
128
- params.runtime.log?.(
129
- `feishu[${account.accountId}] deliver: sending ${chunks.length} card chunks to ${chatId}`,
130
- );
131
- for (const chunk of chunks) {
164
+ for (const chunk of core.channel.text.chunkTextWithMode(
165
+ text,
166
+ textChunkLimit,
167
+ chunkMode,
168
+ )) {
132
169
  await sendMarkdownCardFeishu({
133
170
  cfg,
134
171
  to: chatId,
135
172
  text: chunk,
136
173
  replyToMessageId,
137
- mentions: isFirstChunk ? mentionTargets : undefined,
174
+ mentions: first ? mentionTargets : undefined,
138
175
  accountId,
139
176
  });
140
- isFirstChunk = false;
177
+ first = false;
141
178
  }
142
179
  } else {
143
- // Raw mode: send as plain text with table conversion
144
180
  const converted = core.channel.text.convertMarkdownTables(text, tableMode);
145
- const chunks = core.channel.text.chunkTextWithMode(converted, textChunkLimit, chunkMode);
146
- params.runtime.log?.(
147
- `feishu[${account.accountId}] deliver: sending ${chunks.length} text chunks to ${chatId}`,
148
- );
149
- for (const chunk of chunks) {
181
+ for (const chunk of core.channel.text.chunkTextWithMode(
182
+ converted,
183
+ textChunkLimit,
184
+ chunkMode,
185
+ )) {
150
186
  await sendMessageFeishu({
151
187
  cfg,
152
188
  to: chatId,
153
189
  text: chunk,
154
190
  replyToMessageId,
155
- mentions: isFirstChunk ? mentionTargets : undefined,
191
+ mentions: first ? mentionTargets : undefined,
156
192
  accountId,
157
193
  });
158
- isFirstChunk = false;
194
+ first = false;
159
195
  }
160
196
  }
161
197
  },
162
- onError: (err, info) => {
198
+ onError: async (error, info) => {
163
199
  params.runtime.error?.(
164
- `feishu[${account.accountId}] ${info.kind} reply failed: ${String(err)}`,
200
+ `feishu[${account.accountId}] ${info.kind} reply failed: ${String(error)}`,
165
201
  );
202
+ await closeStreaming();
203
+ typingCallbacks.onIdle?.();
204
+ },
205
+ onIdle: async () => {
206
+ await closeStreaming();
166
207
  typingCallbacks.onIdle?.();
167
208
  },
168
- onIdle: typingCallbacks.onIdle,
169
209
  });
170
210
 
171
211
  return {
@@ -173,6 +213,23 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
173
213
  replyOptions: {
174
214
  ...replyOptions,
175
215
  onModelSelected: prefixContext.onModelSelected,
216
+ onPartialReply: streamingEnabled
217
+ ? (payload: ReplyPayload) => {
218
+ if (!payload.text || payload.text === lastPartial) {
219
+ return;
220
+ }
221
+ lastPartial = payload.text;
222
+ streamText = payload.text;
223
+ partialUpdateQueue = partialUpdateQueue.then(async () => {
224
+ if (streamingStartPromise) {
225
+ await streamingStartPromise;
226
+ }
227
+ if (streaming?.isActive()) {
228
+ await streaming.update(streamText);
229
+ }
230
+ });
231
+ }
232
+ : undefined,
176
233
  },
177
234
  markDispatchIdle,
178
235
  };