silentlake 2026.3.24

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 (1893) hide show
  1. package/CHANGELOG.md +4587 -0
  2. package/LICENSE +21 -0
  3. package/README.md +248 -0
  4. package/assets/avatar-placeholder.svg +19 -0
  5. package/assets/chrome-extension/icons/icon128.png +0 -0
  6. package/assets/chrome-extension/icons/icon16.png +0 -0
  7. package/assets/chrome-extension/icons/icon32.png +0 -0
  8. package/assets/chrome-extension/icons/icon48.png +0 -0
  9. package/assets/dmg-background-small.png +0 -0
  10. package/assets/dmg-background.png +0 -0
  11. package/assets/silentlake-banner.png +0 -0
  12. package/dist/APEv2Parser-BZv_dP9t.js +269 -0
  13. package/dist/APEv2Parser-CPzxFNBB.js +5 -0
  14. package/dist/AbstractID3Parser-mvDFcjYV.js +47 -0
  15. package/dist/AiffParser-BXQ9SRZk.js +145 -0
  16. package/dist/AsfParser-CmBDUlZE.js +631 -0
  17. package/dist/BasicParser-DhmXREDo.js +853 -0
  18. package/dist/DsdiffParser-CTKKGyZg.js +150 -0
  19. package/dist/DsfParser-Ds-YQe4Z.js +101 -0
  20. package/dist/FlacParser-B1XVPgXF.js +5 -0
  21. package/dist/FlacParser-DMPyL1y4.js +367 -0
  22. package/dist/ID3v1Parser-BICWWVDG.js +289 -0
  23. package/dist/ID3v2Parser-BmZHSUqs.js +650 -0
  24. package/dist/ID3v2Token-DeJf4tYQ.js +145 -0
  25. package/dist/MP4Parser-Cjf-Zs8T.js +1061 -0
  26. package/dist/MatroskaParser-DgBzBe8t.js +909 -0
  27. package/dist/MpegParser-D5swTpA1.js +744 -0
  28. package/dist/MusepackParser-D8EQXnpK.js +285 -0
  29. package/dist/OggParser-BcIYPHwP.js +390 -0
  30. package/dist/Util-D_zGsr97.js +170 -0
  31. package/dist/WavPackParser-hosU8gfo.js +166 -0
  32. package/dist/WaveParser-CA00FZrC.js +273 -0
  33. package/dist/abort-cutoff-CERmtgZI.js +56 -0
  34. package/dist/abort-cutoff.runtime-DZkGKKzv.js +61 -0
  35. package/dist/abort-signal-CsrBEr94.js +13 -0
  36. package/dist/account-helpers-D3c_eI7c.js +37 -0
  37. package/dist/account-helpers-ru3jdZSV.js +12 -0
  38. package/dist/account-id-DZnNZg8x.js +1 -0
  39. package/dist/account-id-ZCrgXl7Z.js +44 -0
  40. package/dist/account-lookup-nkoa-foB.js +10 -0
  41. package/dist/account-snapshot-fields-Cvq7803C.js +116 -0
  42. package/dist/account-summary-B5Xzvntm.js +36 -0
  43. package/dist/accounts-43SvCDEA.js +212 -0
  44. package/dist/accounts-CYgFhv2o.js +105 -0
  45. package/dist/accounts-ChlyF7cx.js +112 -0
  46. package/dist/ack-reactions-CNVwfOBj.js +43 -0
  47. package/dist/acp-cli-B4Rv7-xU.js +2033 -0
  48. package/dist/acp-runtime-BdLdT-QY.js +1 -0
  49. package/dist/actions.runtime-CqnQssoB.js +217 -0
  50. package/dist/actions.runtime-FLmCvVRd.js +236 -0
  51. package/dist/agent-CBOdzEvR.js +1 -0
  52. package/dist/agent-scope-BLhzf-o0.js +17 -0
  53. package/dist/agent-scope-DPP4Z_UU.js +193 -0
  54. package/dist/agents-D8pBK0II.js +855 -0
  55. package/dist/agents-Dihz1Ihx.js +323 -0
  56. package/dist/agents.config-C_lrnc9J.js +18 -0
  57. package/dist/agents.config-D1VqC78r.js +121 -0
  58. package/dist/allow-from-BPSBITdd.js +9 -0
  59. package/dist/allow-from-BwTLpvhp.js +20 -0
  60. package/dist/allow-from-C4iBpqFI.js +62 -0
  61. package/dist/allowlist-config-edit-CKbnMmwS.js +279 -0
  62. package/dist/allowlist-match-CYmPgg1K.js +63 -0
  63. package/dist/ansi-BEJF8NKS.js +54 -0
  64. package/dist/anthropic-vertex-provider-Dd5agCN9.js +60 -0
  65. package/dist/apply.runtime-DhKxNSJE.js +370 -0
  66. package/dist/apply.runtime-ghlh-P6X.js +211 -0
  67. package/dist/archive-Tr0wIUO-.js +532 -0
  68. package/dist/arg-split-Dtda0YDl.js +38 -0
  69. package/dist/artifacts-C_4LekPC.js +39 -0
  70. package/dist/audit-BOPSQQtd.js +54 -0
  71. package/dist/audit-C5kdrCi_.js +788 -0
  72. package/dist/audit-channel.allow-from.runtime-B7BHNblL.js +17 -0
  73. package/dist/audit-channel.collect.runtime-CjAbXFBV.js +521 -0
  74. package/dist/audit-channel.discord.runtime-BBY6S9lg.js +5 -0
  75. package/dist/audit-channel.telegram.runtime-SJnxOJH2.js +8 -0
  76. package/dist/audit-channel.zalouser.runtime-SGRWvHxT.js +5 -0
  77. package/dist/audit-extra.async-DY8v7LXH.js +817 -0
  78. package/dist/audit-fs-oDMUa5N_.js +375 -0
  79. package/dist/audit-membership-runtime-BPjFryEx.js +261 -0
  80. package/dist/audit.deep.runtime-WFf-TpsD.js +31 -0
  81. package/dist/audit.nondeep.runtime-B4BaEaRU.js +842 -0
  82. package/dist/audit.runtime-rFjCrods.js +74 -0
  83. package/dist/auth-O6LQFLHJ.js +416 -0
  84. package/dist/auth-choice-DIBaxmAQ.js +219 -0
  85. package/dist/auth-choice-PrbpIjyg.js +610 -0
  86. package/dist/auth-choice-legacy-Clyw2lVc.js +17 -0
  87. package/dist/auth-choice-options-ohUw8QR-.js +127 -0
  88. package/dist/auth-choice-prompt-Cm0s-9Du.js +215 -0
  89. package/dist/auth-choice-prompt-DI-Xl1Nv.js +36 -0
  90. package/dist/auth-choice-rKBOd02a.js +64 -0
  91. package/dist/auth-choice.apply-helpers-BibBSEl9.js +66 -0
  92. package/dist/auth-choice.plugin-providers.runtime-gqF9NO7_.js +219 -0
  93. package/dist/auth-health-TWboMYA5.js +166 -0
  94. package/dist/auth-mode-policy-DywddkT-.js +18 -0
  95. package/dist/auth-profiles-CWEIQV77.js +1047 -0
  96. package/dist/auth-profiles.runtime-B98lwopF.js +48 -0
  97. package/dist/avatar-policy-Ds9e6uHI.js +67 -0
  98. package/dist/axios-xDDnM0KG.js +12831 -0
  99. package/dist/backup-create-B6JAR6jJ.js +461 -0
  100. package/dist/banner-bez5CpOK.js +351 -0
  101. package/dist/base-session-key-Cf2rkwag.js +14 -0
  102. package/dist/bindings-BV4AtNSY.js +21 -0
  103. package/dist/bindings-kjwuC11Q.js +69 -0
  104. package/dist/bluebubbles-C1M3Geg0.js +87 -0
  105. package/dist/bluebubbles-DRW3JdOY.js +603 -0
  106. package/dist/bluebubbles-dEl4QpYz.js +37 -0
  107. package/dist/bonjour-discovery-C2oY96BG.js +376 -0
  108. package/dist/boolean-DKtCJu_W.js +29 -0
  109. package/dist/boolean-param-xAGXUSSN.js +13 -0
  110. package/dist/boundary-file-read-BP6VMpqH.js +106 -0
  111. package/dist/boundary-path-B3FFLYNx.js +557 -0
  112. package/dist/brave-CkimJe4j.js +405 -0
  113. package/dist/brew-DSwWqzLd.js +44 -0
  114. package/dist/browser-cli-D3kBUBNc.js +1502 -0
  115. package/dist/bundled/boot-md/handler.js +381 -0
  116. package/dist/bundled/bootstrap-extra-files/handler.js +56 -0
  117. package/dist/bundled/command-logger/handler.js +62 -0
  118. package/dist/bundled/session-memory/handler.js +401 -0
  119. package/dist/call-BDvaXe4i.js +44 -0
  120. package/dist/call-BmLt3xO1.js +639 -0
  121. package/dist/catalog-BwAYUfL7.js +240 -0
  122. package/dist/channel-BBCuV5OT.js +4945 -0
  123. package/dist/channel-BDBXuqeg.js +321 -0
  124. package/dist/channel-C8h1Irxm.js +1284 -0
  125. package/dist/channel-CbGpFzo4.js +1602 -0
  126. package/dist/channel-Ci3K8fI9.js +1006 -0
  127. package/dist/channel-DGT5N1v7.js +1077 -0
  128. package/dist/channel-account-context-Bwa-YH_o.js +104 -0
  129. package/dist/channel-actions-DU2CR3xW.js +37 -0
  130. package/dist/channel-activity-B8aReQoE.js +35 -0
  131. package/dist/channel-config-3Uv6ve2_.js +115 -0
  132. package/dist/channel-config-helpers-CieQWILI.js +377 -0
  133. package/dist/channel-config-schema-DEVsCZpj.js +1 -0
  134. package/dist/channel-feedback-G6zh8efr.js +245 -0
  135. package/dist/channel-inbound-DwzVf2PK.js +395 -0
  136. package/dist/channel-lifecycle-CpU1dRbh.js +354 -0
  137. package/dist/channel-options-DJaIP4Dv.js +38 -0
  138. package/dist/channel-pairing-D54mn51y.js +66 -0
  139. package/dist/channel-plugin-common-BhTxCE5t.js +1 -0
  140. package/dist/channel-plugin-ids-CFeS3qir.js +26 -0
  141. package/dist/channel-plugin-resolution-DUngfdFj.js +112 -0
  142. package/dist/channel-policy-C4GKHvhz.js +1 -0
  143. package/dist/channel-reply-pipeline-CPTuaW8n.js +15 -0
  144. package/dist/channel-send-result-By8EpCPw.js +40 -0
  145. package/dist/channel-setup-Ck35g7zI.js +49 -0
  146. package/dist/channel-shared-LkXtTPXk.js +308 -0
  147. package/dist/channel-summary-CdYLGMVt.js +137 -0
  148. package/dist/channel-summary-D33z52ft.js +41 -0
  149. package/dist/channel-targets-DfnKGXez.js +87 -0
  150. package/dist/channel.runtime-DAyBR2A5.js +324 -0
  151. package/dist/channel.runtime-DVq5tC2D.js +35 -0
  152. package/dist/channel.runtime-DaLTDGtF.js +288 -0
  153. package/dist/channel.runtime-FKfTev2g.js +512 -0
  154. package/dist/channel.runtime-owqedh1t.js +268 -0
  155. package/dist/channel.runtime-wOTeiifp.js +230 -0
  156. package/dist/channels-CIHgkPea.js +408 -0
  157. package/dist/channels-ZXK6Jiuk.js +1393 -0
  158. package/dist/channels-cli-Bj6qSlkE.js +412 -0
  159. package/dist/channels-status-issues-C_U44M8Y.js +16 -0
  160. package/dist/chat-type-C-n03mQY.js +10 -0
  161. package/dist/clack-prompter-DuzDnaLi.js +112 -0
  162. package/dist/clawbot-cli-YNPuwmTB.js +218 -0
  163. package/dist/cli/daemon-cli.js +88 -0
  164. package/dist/cli-CW46WAZn.js +254 -0
  165. package/dist/cli-name-Daok7A7-.js +25 -0
  166. package/dist/cli-runtime-aAVwbEYy.js +7 -0
  167. package/dist/cli-utils-Np4NAAtt.js +39 -0
  168. package/dist/command-format-CYK9XiUC.js +16 -0
  169. package/dist/command-format-g8YUHNir.js +2 -0
  170. package/dist/command-gating-BQXGSqc9.js +40 -0
  171. package/dist/command-options-5coRiipK.js +25 -0
  172. package/dist/command-poll-backoff-CpkSns-6.js +56 -0
  173. package/dist/command-poll-backoff.runtime-YT6EGcLN.js +7 -0
  174. package/dist/command-registry-BI2MOs89.js +242 -0
  175. package/dist/command-registry-BMsxnuoC.js +14 -0
  176. package/dist/command-secret-gateway-ChXyZwos.js +211 -0
  177. package/dist/command-secret-targets-COcwhn-D.js +88 -0
  178. package/dist/command-secret-targets-CQJT3viO.js +3 -0
  179. package/dist/commands-Bb9xUwz9.js +42 -0
  180. package/dist/commands-core-C1usZXC2.js +4923 -0
  181. package/dist/commands-core.runtime-OTZivlO2.js +232 -0
  182. package/dist/commands-registry-ChCep1KJ.js +295 -0
  183. package/dist/commands-registry.data-XyUTELK9.js +904 -0
  184. package/dist/commands-registry.runtime-m5WTxFtv.js +25 -0
  185. package/dist/commands-status.runtime-C8_hpNgj.js +211 -0
  186. package/dist/commands.runtime-BZPnQKcW.js +232 -0
  187. package/dist/common-CUBlLRXB.js +457 -0
  188. package/dist/compact.runtime-Djmzpbn6.js +216 -0
  189. package/dist/completion-cli-D8tLgE5W.js +445 -0
  190. package/dist/completion-cli-Dz89naVA.js +17 -0
  191. package/dist/config-6sZwvXJD.js +88 -0
  192. package/dist/config-B7tPwoHZ.js +38 -0
  193. package/dist/config-DdDLrP_v.js +273 -0
  194. package/dist/config-cli-C10R8azD.js +945 -0
  195. package/dist/config-guard-B1c73BYQ.js +126 -0
  196. package/dist/config-helpers-3u5wfLBu.js +117 -0
  197. package/dist/config-pn7LKJdW.js +23 -0
  198. package/dist/config-presence-BmUF_5K9.js +79 -0
  199. package/dist/config-regex-CvZFnWkO.js +39 -0
  200. package/dist/config-runtime-CstET7fq.js +142 -0
  201. package/dist/config-schema-5YkIW1xw.js +270 -0
  202. package/dist/config-schema-B1UGMwZ8.js +31 -0
  203. package/dist/config-schema-DzlnsY3D.js +33 -0
  204. package/dist/config-state-CE0CGjey.js +288 -0
  205. package/dist/config-validation-CkVqgkHr.js +272 -0
  206. package/dist/config-value-DgJrpclm.js +25 -0
  207. package/dist/configure-DMkp7Sr4.js +1126 -0
  208. package/dist/configure-DOrQthLy.js +344 -0
  209. package/dist/connection-auth-BSQJeDOU.js +30 -0
  210. package/dist/constants-C_Scc680.js +71 -0
  211. package/dist/control-ui-assets-DjqeIg6A.js +232 -0
  212. package/dist/control-ui-shared-DP000Pxd.js +29 -0
  213. package/dist/conversation-runtime-1O0Aaolb.js +1458 -0
  214. package/dist/core-C7aHA4Aq.js +187 -0
  215. package/dist/core-command-descriptors-DCUYAEZd.js +96 -0
  216. package/dist/credentials-BPwBlm1X.js +265 -0
  217. package/dist/cron-cli-N2Hw_02d.js +579 -0
  218. package/dist/daemon-cli-DgfaF9xx.js +354 -0
  219. package/dist/daemon-install-CbclJo5M.js +134 -0
  220. package/dist/daemon-install-plan.shared-DK6BHlWI.js +222 -0
  221. package/dist/daemon-runtime-CbClrCwc.js +12 -0
  222. package/dist/dangerous-config-flags-BJtLWIk7.js +15 -0
  223. package/dist/dangerous-name-matching-DZa_t0RM.js +44 -0
  224. package/dist/dangerous-tools-yGPDFTHh.js +27 -0
  225. package/dist/date-time-DCAyaBop.js +118 -0
  226. package/dist/dedupe-Cgnk5BbX.js +55 -0
  227. package/dist/defaults-CEdZhIIb.js +6 -0
  228. package/dist/delegate-D4ql5N70.js +43 -0
  229. package/dist/deliver-B004w1Mv.js +212 -0
  230. package/dist/deliver-runtime-IYvc0giI.js +211 -0
  231. package/dist/delivery-queue-B19wDCjT.js +3 -0
  232. package/dist/delivery-queue-DrrqB4Hi.js +299 -0
  233. package/dist/device-auth-GEXe9vqR.js +15 -0
  234. package/dist/device-bootstrap-CwwokLEY.js +96 -0
  235. package/dist/device-bootstrap-Dbhe6oe8.js +1 -0
  236. package/dist/device-metadata-normalization-BDSQ_eA7.js +21 -0
  237. package/dist/device-pairing-cFWbBray.js +553 -0
  238. package/dist/devices-cli-DzycjFzS.js +366 -0
  239. package/dist/diagnostic-DqJXx_4Q.js +310 -0
  240. package/dist/diagnostic-events-ktCoG8Br.js +48 -0
  241. package/dist/diagnostics-CMhyGsPu.js +33 -0
  242. package/dist/diagnostics-DpLHpQ9c.js +14 -0
  243. package/dist/directive-handling.fast-lane-toP_ri_H.js +273 -0
  244. package/dist/directive-handling.impl-BRARyrsT.js +638 -0
  245. package/dist/directive-handling.impl-CUB4MOnK.js +214 -0
  246. package/dist/directive-handling.levels-8vnMeuGX.js +2 -0
  247. package/dist/directive-handling.levels-CoruY1AA.js +13 -0
  248. package/dist/directive-handling.persist.runtime-78Du6PgL.js +170 -0
  249. package/dist/directive-handling.shared-DCGUCHjn.js +147 -0
  250. package/dist/directory-cli-DVsDcgIU.js +437 -0
  251. package/dist/directory-config-helpers-CURJ8mj7.js +129 -0
  252. package/dist/directory-runtime-DhC8QkMq.js +19 -0
  253. package/dist/directory.static-DQaG9ohH.js +44 -0
  254. package/dist/discord-CYj8s73O.js +214 -0
  255. package/dist/discord-L9zvSHVn.js +635 -0
  256. package/dist/discord-core-5tkl-BzP.js +1 -0
  257. package/dist/dm-policy-shared-6bCJzHOS.js +188 -0
  258. package/dist/dns-cli-BMvHy265.js +223 -0
  259. package/dist/docker-XFNiArwM.js +1254 -0
  260. package/dist/docs-cli-BTaH94wD.js +176 -0
  261. package/dist/doctor-completion-DKx5m2UC.js +90 -0
  262. package/dist/doctor-config-preflight-BzQgc3_t.js +40 -0
  263. package/dist/doctor-config-preflight-DxVCut8L.js +150 -0
  264. package/dist/doctor-state-migrations-CTF66iAy.js +732 -0
  265. package/dist/doctor-state-migrations-D0VP4dUh.js +212 -0
  266. package/dist/entry-status-B2OWAf0s.js +172 -0
  267. package/dist/entry.js +210 -0
  268. package/dist/env-BP70DGuy.js +30 -0
  269. package/dist/env-overrides-JneV60sd.js +434 -0
  270. package/dist/env-overrides.runtime-DLrwions.js +18 -0
  271. package/dist/env-substitution-D6t_sLS_.js +136 -0
  272. package/dist/errors-BxyFnvP3.js +58 -0
  273. package/dist/exec-Dmex2w_d.js +310 -0
  274. package/dist/exec-approvals-BJhuySBz.js +386 -0
  275. package/dist/exec-approvals-allowlist-B_wPddCb.js +384 -0
  276. package/dist/exec-approvals-cli-C2dwhSkX.js +427 -0
  277. package/dist/exec-safe-bin-runtime-policy-BZkObC8r.js +89 -0
  278. package/dist/exec-safety-CaaBy-Zw.js +24 -0
  279. package/dist/extension-shared-5txN7IXK.js +74 -0
  280. package/dist/extensionAPI.js +218 -0
  281. package/dist/extensions/amazon-bedrock/index.js +231 -0
  282. package/dist/extensions/anthropic/index.js +330 -0
  283. package/dist/extensions/bluebubbles/index.js +224 -0
  284. package/dist/extensions/bluebubbles/setup-entry.js +289 -0
  285. package/dist/extensions/brave/index.js +23 -0
  286. package/dist/extensions/byteplus/index.js +112 -0
  287. package/dist/extensions/chutes/index.js +221 -0
  288. package/dist/extensions/cloudflare-ai-gateway/index.js +218 -0
  289. package/dist/extensions/copilot-proxy/index.js +125 -0
  290. package/dist/extensions/device-pair/index.js +1040 -0
  291. package/dist/extensions/discord/index.js +215 -0
  292. package/dist/extensions/discord/setup-entry.js +215 -0
  293. package/dist/extensions/elevenlabs/index.js +223 -0
  294. package/dist/extensions/fal/index.js +112 -0
  295. package/dist/extensions/feishu/index.js +227 -0
  296. package/dist/extensions/feishu/setup-entry.js +112 -0
  297. package/dist/extensions/firecrawl/index.js +211 -0
  298. package/dist/extensions/github-copilot/index.js +490 -0
  299. package/dist/extensions/google/index.js +211 -0
  300. package/dist/extensions/huggingface/index.js +108 -0
  301. package/dist/extensions/imessage/index.js +223 -0
  302. package/dist/extensions/imessage/setup-entry.js +220 -0
  303. package/dist/extensions/irc/index.js +220 -0
  304. package/dist/extensions/irc/setup-entry.js +222 -0
  305. package/dist/extensions/kilocode/index.js +282 -0
  306. package/dist/extensions/kimi-coding/index.js +148 -0
  307. package/dist/extensions/line/index.js +57 -0
  308. package/dist/extensions/line/setup-entry.js +49 -0
  309. package/dist/extensions/llm-task/index.js +157 -0
  310. package/dist/extensions/lobster/index.js +261 -0
  311. package/dist/extensions/mattermost/index.js +220 -0
  312. package/dist/extensions/mattermost/setup-entry.js +222 -0
  313. package/dist/extensions/memory-core/index.js +36 -0
  314. package/dist/extensions/microsoft/index.js +223 -0
  315. package/dist/extensions/minimax/index.js +437 -0
  316. package/dist/extensions/mistral/index.js +149 -0
  317. package/dist/extensions/modelstudio/index.js +144 -0
  318. package/dist/extensions/moonshot/index.js +211 -0
  319. package/dist/extensions/nextcloud-talk/index.js +221 -0
  320. package/dist/extensions/nextcloud-talk/setup-entry.js +223 -0
  321. package/dist/extensions/nvidia/index.js +29 -0
  322. package/dist/extensions/ollama/index.js +118 -0
  323. package/dist/extensions/open-prose/index.js +10 -0
  324. package/dist/extensions/openai/index.js +677 -0
  325. package/dist/extensions/opencode/index.js +116 -0
  326. package/dist/extensions/opencode-go/index.js +114 -0
  327. package/dist/extensions/openrouter/index.js +398 -0
  328. package/dist/extensions/openshell/index.js +923 -0
  329. package/dist/extensions/perplexity/index.js +23 -0
  330. package/dist/extensions/phone-control/index.js +276 -0
  331. package/dist/extensions/qianfan/index.js +114 -0
  332. package/dist/extensions/qwen-portal-auth/index.js +350 -0
  333. package/dist/extensions/sglang/index.js +285 -0
  334. package/dist/extensions/signal/index.js +218 -0
  335. package/dist/extensions/signal/setup-entry.js +218 -0
  336. package/dist/extensions/slack/index.js +222 -0
  337. package/dist/extensions/slack/setup-entry.js +220 -0
  338. package/dist/extensions/synology-chat/index.js +56 -0
  339. package/dist/extensions/synology-chat/setup-entry.js +58 -0
  340. package/dist/extensions/synthetic/index.js +112 -0
  341. package/dist/extensions/talk-voice/index.js +197 -0
  342. package/dist/extensions/tavily/index.js +211 -0
  343. package/dist/extensions/telegram/index.js +221 -0
  344. package/dist/extensions/telegram/setup-entry.js +221 -0
  345. package/dist/extensions/thread-ownership/index.js +70 -0
  346. package/dist/extensions/together/index.js +113 -0
  347. package/dist/extensions/venice/index.js +132 -0
  348. package/dist/extensions/vercel-ai-gateway/index.js +86 -0
  349. package/dist/extensions/vllm/index.js +285 -0
  350. package/dist/extensions/voice-call/index.js +5715 -0
  351. package/dist/extensions/volcengine/index.js +112 -0
  352. package/dist/extensions/xai/index.js +211 -0
  353. package/dist/extensions/xiaomi/index.js +115 -0
  354. package/dist/extensions/zai/index.js +559 -0
  355. package/dist/extensions/zalo/index.js +225 -0
  356. package/dist/extensions/zalo/setup-entry.js +226 -0
  357. package/dist/external-content-BUdUOqkv.js +238 -0
  358. package/dist/feishu-CgbwAF0e.js +2664 -0
  359. package/dist/feishu-Dh5fEbh5.js +59127 -0
  360. package/dist/fetch-guard-DIyN1HW5.js +165 -0
  361. package/dist/fetch-timeout-C5xpMuGd.js +36 -0
  362. package/dist/file-identity-Cw0fQxYY.js +11 -0
  363. package/dist/file-lock-WbEmczmY.js +107 -0
  364. package/dist/filter-oMGaNOM1.js +20 -0
  365. package/dist/format-DH8ysi7s.js +19 -0
  366. package/dist/format-datetime-BGS6tLDE.js +73 -0
  367. package/dist/format-duration-CO0BGWB0.js +57 -0
  368. package/dist/format-relative-C3nDxnXz.js +54 -0
  369. package/dist/frontmatter-S5vS-I4a.js +309 -0
  370. package/dist/fs-safe-D3qzH-ab.js +731 -0
  371. package/dist/gateway-cli-PQNp7o0j.js +28378 -0
  372. package/dist/gateway-install-token-DV5KjD4F.js +164 -0
  373. package/dist/gateway-rpc-C0Ey-rik.js +26 -0
  374. package/dist/gateway-runtime-ih2e7a2K.js +42 -0
  375. package/dist/gaxios-fetch-compat-KX6bsqFm.js +165 -0
  376. package/dist/gemini-auth-B5ljg7jr.js +29 -0
  377. package/dist/git-commit-BIdLubm5.js +2 -0
  378. package/dist/git-commit-OvUvjri2.js +177 -0
  379. package/dist/github-copilot-auth-Ccm-cBwy.js +104 -0
  380. package/dist/global-singleton-4KwY5RvX.js +13 -0
  381. package/dist/globals-41sdSaKv.js +38 -0
  382. package/dist/gmail-setup-utils-BX68dZla.js +419 -0
  383. package/dist/group-access-DJZrYPx1.js +113 -0
  384. package/dist/group-keys-BD_IYSMs.js +44 -0
  385. package/dist/group-policy-CWFxv3iB.js +201 -0
  386. package/dist/group-policy-warnings-Ddu6lBkh.js +175 -0
  387. package/dist/health-Bu1sbyYy.js +573 -0
  388. package/dist/health-Cbxc9Bn3.js +59 -0
  389. package/dist/health-format-B5XfOTuJ.js +26 -0
  390. package/dist/heartbeat-7aHh0m3d.js +169 -0
  391. package/dist/heartbeat-summary-Das49TYq.js +57 -0
  392. package/dist/help-CcbF7-ha.js +81 -0
  393. package/dist/help-format-Dv45FpYu.js +15 -0
  394. package/dist/helpers-DJ-5HEbE.js +24 -0
  395. package/dist/helpers-MxyaLZUk.js +32 -0
  396. package/dist/history-CHjo8B5W.js +102 -0
  397. package/dist/hook-runtime-BnNBi_q4.js +1 -0
  398. package/dist/hooks-cli-DUYK4RM1.js +1102 -0
  399. package/dist/hooks-policy-BL6HDLUn.js +20 -0
  400. package/dist/hooks-status-gzNmo3li.js +78 -0
  401. package/dist/host-env-security-BogNN146.js +223 -0
  402. package/dist/http-body-CCiSfloA.js +237 -0
  403. package/dist/http-registry-WFFbLYRd.js +153 -0
  404. package/dist/identity-DovQV4zD.js +112 -0
  405. package/dist/identity-cyBYcoXS.js +84 -0
  406. package/dist/identity-file-EndG1nfc.js +60 -0
  407. package/dist/image-generation-CNKc-mFK.js +441 -0
  408. package/dist/image-kJ7Tbov4.js +211 -0
  409. package/dist/image-ops-j01UkxEv.js +371 -0
  410. package/dist/imessage-B5pSMT47.js +219 -0
  411. package/dist/imessage-CoIuY1Ro.js +1451 -0
  412. package/dist/imessage-Cqjsq4VW.js +190 -0
  413. package/dist/imessage-core-CsYJuaRZ.js +1 -0
  414. package/dist/inbound-envelope-4P3IIJc3.js +61 -0
  415. package/dist/inbound-reply-dispatch-i2Vekqyy.js +72 -0
  416. package/dist/includes-7XyL3p1c.js +188 -0
  417. package/dist/includes-scan-y-rS6tTw.js +55 -0
  418. package/dist/index.js +57 -0
  419. package/dist/infra/warning-filter.js +2 -0
  420. package/dist/inspect-CcxlJ1ba.js +279 -0
  421. package/dist/install-safe-path-Rwbw1XCZ.js +62 -0
  422. package/dist/installs-iHi2aSjM.js +532 -0
  423. package/dist/interactive-F7iY0yED.js +8 -0
  424. package/dist/interactive-runtime-OweOj_Vv.js +90 -0
  425. package/dist/internal-hooks-0uipqzRY.js +156 -0
  426. package/dist/io-BX49DsSJ.js +35 -0
  427. package/dist/io-jOnQRia2.js +7178 -0
  428. package/dist/ip-C8vmzVu0.js +203 -0
  429. package/dist/ipv4-DAmsJVOV.js +82 -0
  430. package/dist/irc-AZ-Ec8be.js +12 -0
  431. package/dist/irc-CCSRuEC2.js +660 -0
  432. package/dist/is-main-YViS6wOn.js +27 -0
  433. package/dist/issue-format-CBEXVico.js +31 -0
  434. package/dist/issue-format-D3HehoKZ.js +4 -0
  435. package/dist/json-file-C2zjA0Gv.js +23 -0
  436. package/dist/json-files-WW-H_psG.js +60 -0
  437. package/dist/json-pointer-f9dEnBoR.js +43 -0
  438. package/dist/json-store-O1LwpnBH.js +37 -0
  439. package/dist/kb-cli-DMZs6PCu.js +65 -0
  440. package/dist/keyed-async-queue-CPUWV5Pm.js +32 -0
  441. package/dist/kill-tree-CbjXBw3z.js +149 -0
  442. package/dist/kilocode-shared-DS7_0IMs.js +29 -0
  443. package/dist/launchd-tyqGVx9U.js +491 -0
  444. package/dist/lazy-runtime-BcXbyAaC.js +1 -0
  445. package/dist/lazy-runtime-bWkd2cs3.js +29 -0
  446. package/dist/legacy-names-CUNZ4vHN.js +7 -0
  447. package/dist/legacy-web-search-BgZjNG2h.js +222 -0
  448. package/dist/lib-CERS7N4b.js +503 -0
  449. package/dist/lib-PPICrHv1.js +1938 -0
  450. package/dist/library-CZ461krl.js +211 -0
  451. package/dist/lifecycle-core-Dnxnw0oy.js +382 -0
  452. package/dist/line/accounts.js +10 -0
  453. package/dist/line/send.js +39 -0
  454. package/dist/line/template-messages.js +2 -0
  455. package/dist/line-CJSvwApm.js +1 -0
  456. package/dist/line-N9vL-2JB.js +688 -0
  457. package/dist/line-core-BOIxkjgu.js +1 -0
  458. package/dist/links-Bilm-v0z.js +13 -0
  459. package/dist/llm-slug-generator-BuAuQ5Ft.js +68 -0
  460. package/dist/llm-slug-generator.js +212 -0
  461. package/dist/llm-task-Dx8ymRFr.js +1 -0
  462. package/dist/local-roots-DAzCjWbC.js +34 -0
  463. package/dist/location-DefAH9WS.js +42 -0
  464. package/dist/logger-CoEtkjhn.js +550 -0
  465. package/dist/logger-Cqy7-Maj.js +70 -0
  466. package/dist/logging-B2wMcpWV.js +13 -0
  467. package/dist/logging-Bz1qZDPg.js +16 -0
  468. package/dist/logging-CArEWRgI.js +36 -0
  469. package/dist/logging-CbTTfADU.js +1 -0
  470. package/dist/logs-cli-BSjKwaur.js +261 -0
  471. package/dist/magic-string.es-DJPWMt-n.js +1011 -0
  472. package/dist/main-session-DKr0lBVk.js +36 -0
  473. package/dist/manager-ChTGDe87.js +2005 -0
  474. package/dist/manager-DuwFn87U.js +4226 -0
  475. package/dist/manager-runtime-E16jsvRe.js +59 -0
  476. package/dist/manager.runtime-F9F1eFiB.js +827 -0
  477. package/dist/manifest-registry-B90TyTWl.js +1350 -0
  478. package/dist/map-size-CMTQVKUV.js +15 -0
  479. package/dist/markdown-to-line-BWwaRx5F.js +640 -0
  480. package/dist/mask-api-key-CprzEe7l.js +10 -0
  481. package/dist/matrix-DzvdUw97.js +228 -0
  482. package/dist/matrix-migration-snapshot-adoDbNii.js +702 -0
  483. package/dist/mattermost-DO0BCfF3.js +1 -0
  484. package/dist/mattermost-SjOt4QDb.js +15 -0
  485. package/dist/mcp-cli-BC_VPl_o.js +94 -0
  486. package/dist/mcp-config-Coky4zS4.js +108 -0
  487. package/dist/media-limits-Cuvmmhop.js +14 -0
  488. package/dist/media-understanding-DD2uMjK8.js +48 -0
  489. package/dist/media-understanding.runtime-Kbb2bRmk.js +216 -0
  490. package/dist/memory-DBjQ0TPd.js +1 -0
  491. package/dist/memory-cli-Cm4Df0hJ.js +215 -0
  492. package/dist/memory-cli-yzqneSF8.js +541 -0
  493. package/dist/memory-search-Das1tiuB.js +204 -0
  494. package/dist/memory-search-DxmSTjHq.js +18 -0
  495. package/dist/mention-gating-B_q-EHFx.js +25 -0
  496. package/dist/mentions-Bxys_va0.js +154 -0
  497. package/dist/message-channel-Cy-gN4K2.js +106 -0
  498. package/dist/message-hook-mappers-BBTV3JRQ.js +249 -0
  499. package/dist/method-scopes-DgypDW23.js +2649 -0
  500. package/dist/mime-C4vVTBso.js +150 -0
  501. package/dist/minimal-C5yUxtHy.js +2120 -0
  502. package/dist/model-auth-B__TJTPw.js +309 -0
  503. package/dist/model-auth-env-CF9ts7Th.js +111 -0
  504. package/dist/model-catalog.runtime-CWh17vcc.js +211 -0
  505. package/dist/model-id-normalization-Y-MIsyK_.js +16 -0
  506. package/dist/model-input-BB2wSAHb.js +20 -0
  507. package/dist/model-overrides-sIzKU2wo.js +84 -0
  508. package/dist/model-param-b-DIFEhICm.js +15 -0
  509. package/dist/model-picker-CAPjetT3.js +400 -0
  510. package/dist/model-picker-DEw9viWc.js +215 -0
  511. package/dist/model-picker.runtime-ixYl7lB5.js +224 -0
  512. package/dist/model-selection-BTpJnslv.js +437 -0
  513. package/dist/model-selection-Ci9cPkL2.js +765 -0
  514. package/dist/model-suppression.runtime-D8cIb6Y5.js +216 -0
  515. package/dist/models-BQtc3khN.js +226 -0
  516. package/dist/models-CQgBV5dW.js +2536 -0
  517. package/dist/models-cli-DbQ-QpQk.js +418 -0
  518. package/dist/models-config-D2xK-G6c.js +211 -0
  519. package/dist/models-config.providers.discovery-BaIk1NKL.js +141 -0
  520. package/dist/models-config.runtime-Cf7q9uAQ.js +211 -0
  521. package/dist/monitor-B5QmKaD7.js +3272 -0
  522. package/dist/monitor-CL5OYLih.js +878 -0
  523. package/dist/monitor-CNZxrM4d.js +3145 -0
  524. package/dist/monitor-CyQVZdDh.js +223 -0
  525. package/dist/multimodal-DC43jYNv.js +75 -0
  526. package/dist/mutable-allowlist-detectors-C6EAzWYE.js +62 -0
  527. package/dist/net-DlJFp95v.js +270 -0
  528. package/dist/network-mode-DOgvmom4.js +17 -0
  529. package/dist/nextcloud-talk-ChMP88s-.js +12 -0
  530. package/dist/nextcloud-talk-CwnkUy8E.js +1 -0
  531. package/dist/node-cli-BZDC7rXg.js +2484 -0
  532. package/dist/node-command-policy-Bg2g6Xjp.js +192 -0
  533. package/dist/node-commands-B6W6Eo0b.js +11 -0
  534. package/dist/node-require-BgDD9bTi.js +14 -0
  535. package/dist/node-resolve-BunMro3f.js +69 -0
  536. package/dist/node-service-CEZZaqba.js +65 -0
  537. package/dist/node-startup-env-Gz8ZQniA.js +50 -0
  538. package/dist/nodes-cli-B4Jr9vct.js +1330 -0
  539. package/dist/nodes-screen-CQ7IvP62.js +401 -0
  540. package/dist/normalize-secret-input-_PgpexOG.js +32 -0
  541. package/dist/note-dfjacCV8.js +109 -0
  542. package/dist/npm-pack-install-CYNRv-vM.js +574 -0
  543. package/dist/npm-resolution-Ml2aA6Nu.js +60 -0
  544. package/dist/oauth.runtime-DA_48MPQ.js +687 -0
  545. package/dist/oauth.runtime-DS1ry5__.js +318 -0
  546. package/dist/oauth.runtime-qCkidk8J.js +180 -0
  547. package/dist/ollama-defaults-asNuGW4_.js +4 -0
  548. package/dist/onboard-BM6gO6Uw.js +589 -0
  549. package/dist/onboard-D9IU-7uw.js +48 -0
  550. package/dist/onboard-DQaHGPRm.js +25 -0
  551. package/dist/onboard-channels-BdQtLjYb.js +300 -0
  552. package/dist/onboard-channels-DIVUygs5.js +1257 -0
  553. package/dist/onboard-config-DFKb-0sE.js +29 -0
  554. package/dist/onboard-config-DYykzJhx.js +2 -0
  555. package/dist/onboard-custom-CDP4w1AT.js +216 -0
  556. package/dist/onboard-custom-DhJN13UV.js +644 -0
  557. package/dist/onboard-helpers-B7XTd4Pw.js +335 -0
  558. package/dist/onboard-helpers-BUKtx5Bq.js +54 -0
  559. package/dist/onboard-hooks-BHSSLAhI.js +73 -0
  560. package/dist/onboard-remote-BOzEPdHA.js +59 -0
  561. package/dist/onboard-remote-DVza19_k.js +182 -0
  562. package/dist/onboard-search-CrS-n9_3.js +446 -0
  563. package/dist/onboard-skills-BojzIPvk.js +133 -0
  564. package/dist/onboard-skills-D7HyCVjz.js +69 -0
  565. package/dist/openai-codex-provider.runtime-BFsopDHI.js +2 -0
  566. package/dist/openai-defaults-B7FUywsh.js +10 -0
  567. package/dist/openclaw-exec-env-AcZ9we1N.js +14 -0
  568. package/dist/openclaw-root-TUHYdr9B.js +88 -0
  569. package/dist/openclaw-tools.runtime-draZJo5r.js +211 -0
  570. package/dist/outbound-media-69yrWRDt.js +11 -0
  571. package/dist/outbound-runtime-ic_7ulJJ.js +1 -0
  572. package/dist/pairing-challenge-CNrPmmi9.js +48 -0
  573. package/dist/pairing-cli-BohXW2BK.js +150 -0
  574. package/dist/pairing-labels-CNKCSmBK.js +7 -0
  575. package/dist/pairing-message-CBv2njJT.js +4 -0
  576. package/dist/pairing-store-C4lsd4pO.js +590 -0
  577. package/dist/pairing-token-gKj4SNFJ.js +55 -0
  578. package/dist/parse-duration-BBGYkY0S.js +41 -0
  579. package/dist/parse-finite-number-CP4MQF_w.js +30 -0
  580. package/dist/parse-log-line-CVh9zu3Q.js +43 -0
  581. package/dist/parse-port-COyt3COn.js +8 -0
  582. package/dist/path-alias-guards-ZTKqurNH.js +40 -0
  583. package/dist/path-env-CPkz6U0Y.js +87 -0
  584. package/dist/paths-CTjJI9l0.js +179 -0
  585. package/dist/paths-GHJ97ebE.js +268 -0
  586. package/dist/paths-nCHyK08H.js +56 -0
  587. package/dist/perplexity-Beshd9zu.js +422 -0
  588. package/dist/persistent-dedupe-bjKjVI5u.js +116 -0
  589. package/dist/pi-embedded-CSQySvOV.js +168518 -0
  590. package/dist/pi-model-discovery-CuX5CDyZ.js +125 -0
  591. package/dist/pi-model-discovery-runtime-DNsMrX1n.js +44 -0
  592. package/dist/pi-tools.before-tool-call.runtime-DxVqzMVf.js +387 -0
  593. package/dist/platform-launcher-CqGy6UhP.js +83 -0
  594. package/dist/plugin-entry-CwuwM1jC.js +17 -0
  595. package/dist/plugin-install-JJwfOXtg.js +216 -0
  596. package/dist/plugin-install-plan-cixz1_W4.js +49 -0
  597. package/dist/plugin-install-vkpI1UNd.js +184 -0
  598. package/dist/plugin-registry-C3j_DUnj.js +51 -0
  599. package/dist/plugin-registry-DB_yxabS.js +213 -0
  600. package/dist/plugin-sdk/account-helpers.js +3 -0
  601. package/dist/plugin-sdk/account-id.js +2 -0
  602. package/dist/plugin-sdk/account-resolution.js +216 -0
  603. package/dist/plugin-sdk/acp-runtime.js +46 -0
  604. package/dist/plugin-sdk/agent-runtime.js +215 -0
  605. package/dist/plugin-sdk/allow-from.js +17 -0
  606. package/dist/plugin-sdk/allowlist-config-edit.js +2 -0
  607. package/dist/plugin-sdk/bluebubbles.js +232 -0
  608. package/dist/plugin-sdk/boolean-param.js +2 -0
  609. package/dist/plugin-sdk/channel-actions.js +16 -0
  610. package/dist/plugin-sdk/channel-config-helpers.js +15 -0
  611. package/dist/plugin-sdk/channel-config-schema.js +5 -0
  612. package/dist/plugin-sdk/channel-contract.js +1 -0
  613. package/dist/plugin-sdk/channel-feedback.js +4 -0
  614. package/dist/plugin-sdk/channel-inbound.js +53 -0
  615. package/dist/plugin-sdk/channel-lifecycle.js +2 -0
  616. package/dist/plugin-sdk/channel-pairing.js +2 -0
  617. package/dist/plugin-sdk/channel-policy.js +19 -0
  618. package/dist/plugin-sdk/channel-reply-pipeline.js +23 -0
  619. package/dist/plugin-sdk/channel-runtime.js +33 -0
  620. package/dist/plugin-sdk/channel-send-result.js +2 -0
  621. package/dist/plugin-sdk/channel-setup.js +24 -0
  622. package/dist/plugin-sdk/channel-targets.js +3 -0
  623. package/dist/plugin-sdk/cli-runtime.js +5 -0
  624. package/dist/plugin-sdk/command-auth.js +212 -0
  625. package/dist/plugin-sdk/compat.js +59 -0
  626. package/dist/plugin-sdk/config-runtime.js +51 -0
  627. package/dist/plugin-sdk/conversation-runtime.js +55 -0
  628. package/dist/plugin-sdk/core.js +40 -0
  629. package/dist/plugin-sdk/device-bootstrap.js +6 -0
  630. package/dist/plugin-sdk/diagnostics-otel.js +7 -0
  631. package/dist/plugin-sdk/diffs.js +3 -0
  632. package/dist/plugin-sdk/directory-runtime.js +5 -0
  633. package/dist/plugin-sdk/discord-core.js +26 -0
  634. package/dist/plugin-sdk/discord.js +219 -0
  635. package/dist/plugin-sdk/extension-shared.js +15 -0
  636. package/dist/plugin-sdk/feishu.js +101 -0
  637. package/dist/plugin-sdk/gateway-runtime.js +46 -0
  638. package/dist/plugin-sdk/googlechat.js +93 -0
  639. package/dist/plugin-sdk/group-access.js +2 -0
  640. package/dist/plugin-sdk/hook-runtime.js +12 -0
  641. package/dist/plugin-sdk/image-generation.js +51 -0
  642. package/dist/plugin-sdk/imessage-core.js +214 -0
  643. package/dist/plugin-sdk/imessage.js +223 -0
  644. package/dist/plugin-sdk/index.js +55 -0
  645. package/dist/plugin-sdk/infra-runtime.js +223 -0
  646. package/dist/plugin-sdk/interactive-runtime.js +3 -0
  647. package/dist/plugin-sdk/irc.js +232 -0
  648. package/dist/plugin-sdk/json-store.js +9 -0
  649. package/dist/plugin-sdk/keyed-async-queue.js +2 -0
  650. package/dist/plugin-sdk/lazy-runtime.js +2 -0
  651. package/dist/plugin-sdk/line-core.js +29 -0
  652. package/dist/plugin-sdk/line.js +22 -0
  653. package/dist/plugin-sdk/llm-task.js +7 -0
  654. package/dist/plugin-sdk/matrix-runtime-heavy.js +223 -0
  655. package/dist/plugin-sdk/matrix-runtime-shared.js +2 -0
  656. package/dist/plugin-sdk/matrix.js +84 -0
  657. package/dist/plugin-sdk/mattermost.js +233 -0
  658. package/dist/plugin-sdk/media-runtime.js +212 -0
  659. package/dist/plugin-sdk/media-understanding-runtime.js +211 -0
  660. package/dist/plugin-sdk/media-understanding.js +15 -0
  661. package/dist/plugin-sdk/memory-core.js +2 -0
  662. package/dist/plugin-sdk/memory-lancedb.js +2 -0
  663. package/dist/plugin-sdk/msteams.js +244 -0
  664. package/dist/plugin-sdk/nextcloud-talk.js +231 -0
  665. package/dist/plugin-sdk/nostr.js +50 -0
  666. package/dist/plugin-sdk/ollama-setup.js +33 -0
  667. package/dist/plugin-sdk/outbound-runtime.js +23 -0
  668. package/dist/plugin-sdk/plugin-entry.js +3 -0
  669. package/dist/plugin-sdk/plugin-runtime.js +211 -0
  670. package/dist/plugin-sdk/process-runtime.js +12 -0
  671. package/dist/plugin-sdk/provider-auth-api-key.js +53 -0
  672. package/dist/plugin-sdk/provider-auth-login.js +2 -0
  673. package/dist/plugin-sdk/provider-auth.js +37 -0
  674. package/dist/plugin-sdk/provider-catalog.js +2 -0
  675. package/dist/plugin-sdk/provider-env-vars.js +2 -0
  676. package/dist/plugin-sdk/provider-google.js +3 -0
  677. package/dist/plugin-sdk/provider-models.js +27 -0
  678. package/dist/plugin-sdk/provider-onboard.js +20 -0
  679. package/dist/plugin-sdk/provider-setup.js +58 -0
  680. package/dist/plugin-sdk/provider-stream.js +211 -0
  681. package/dist/plugin-sdk/provider-usage.js +18 -0
  682. package/dist/plugin-sdk/provider-web-search.js +23 -0
  683. package/dist/plugin-sdk/provider-zai-endpoint.js +3 -0
  684. package/dist/plugin-sdk/reply-history.js +23 -0
  685. package/dist/plugin-sdk/reply-payload.js +2 -0
  686. package/dist/plugin-sdk/reply-runtime.js +211 -0
  687. package/dist/plugin-sdk/request-url.js +2 -0
  688. package/dist/plugin-sdk/routing.js +25 -0
  689. package/dist/plugin-sdk/runtime-env.js +15 -0
  690. package/dist/plugin-sdk/runtime-store.js +2 -0
  691. package/dist/plugin-sdk/runtime.js +15 -0
  692. package/dist/plugin-sdk/sandbox.js +66 -0
  693. package/dist/plugin-sdk/secret-input.js +3 -0
  694. package/dist/plugin-sdk/security-runtime.js +18 -0
  695. package/dist/plugin-sdk/self-hosted-provider-setup.js +33 -0
  696. package/dist/plugin-sdk/setup-adapter-runtime.js +2 -0
  697. package/dist/plugin-sdk/setup-runtime.js +17 -0
  698. package/dist/plugin-sdk/setup-tools.js +21 -0
  699. package/dist/plugin-sdk/setup.js +26 -0
  700. package/dist/plugin-sdk/signal.js +220 -0
  701. package/dist/plugin-sdk/slack-core.js +22 -0
  702. package/dist/plugin-sdk/slack.js +223 -0
  703. package/dist/plugin-sdk/speech-runtime.js +213 -0
  704. package/dist/plugin-sdk/speech.js +212 -0
  705. package/dist/plugin-sdk/ssrf-runtime.js +5 -0
  706. package/dist/plugin-sdk/state-paths.js +3 -0
  707. package/dist/plugin-sdk/status-helpers.js +9 -0
  708. package/dist/plugin-sdk/telegram-core.js +23 -0
  709. package/dist/plugin-sdk/telegram.js +224 -0
  710. package/dist/plugin-sdk/testing.js +13174 -0
  711. package/dist/plugin-sdk/text-runtime.js +45 -0
  712. package/dist/plugin-sdk/thread-bindings-runtime.js +2 -0
  713. package/dist/plugin-sdk/thread-ownership.js +2 -0
  714. package/dist/plugin-sdk/tlon.js +57 -0
  715. package/dist/plugin-sdk/tool-send.js +2 -0
  716. package/dist/plugin-sdk/twitch.js +46 -0
  717. package/dist/plugin-sdk/voice-call.js +213 -0
  718. package/dist/plugin-sdk/web-media.js +28 -0
  719. package/dist/plugin-sdk/webhook-ingress.js +7 -0
  720. package/dist/plugin-sdk/webhook-path.js +2 -0
  721. package/dist/plugin-sdk/whatsapp-core.js +219 -0
  722. package/dist/plugin-sdk/whatsapp-shared.js +18 -0
  723. package/dist/plugin-sdk/windows-spawn.js +2 -0
  724. package/dist/plugin-sdk/zalo.js +239 -0
  725. package/dist/plugin-sdk/zalouser.js +240 -0
  726. package/dist/plugins/build-smoke-entry.js +211 -0
  727. package/dist/plugins/runtime/index.js +229 -0
  728. package/dist/plugins-1Z50ecJ6.js +1 -0
  729. package/dist/plugins-C6fKmNuA.js +7 -0
  730. package/dist/plugins-cli-BkgQkGaU.js +1192 -0
  731. package/dist/policy-CpkbSAfm.js +60 -0
  732. package/dist/polls-B2VH7SN9.js +35 -0
  733. package/dist/ports-BjWuIIQw.js +262 -0
  734. package/dist/ports-DFiK_Jc-.js +385 -0
  735. package/dist/ports-lsof-DtJqhFOr.js +25 -0
  736. package/dist/ports-probe-BQqp8l8E.js +14 -0
  737. package/dist/preflight-audio.runtime-Fi9mofpp.js +216 -0
  738. package/dist/probe-BM9sbCgS.js +20 -0
  739. package/dist/probe-DLBOZftS.js +134 -0
  740. package/dist/probe-auth-Bjp3G4CI.js +48 -0
  741. package/dist/probe-auth-DMSPTRRk.js +45 -0
  742. package/dist/process-runtime-C7el-Ri4.js +1 -0
  743. package/dist/process-scoped-map-C4gOa-gv.js +61 -0
  744. package/dist/profile-utils-BcMYGFPT.js +15 -0
  745. package/dist/profiles-D17eMKQZ.js +683 -0
  746. package/dist/program-Ch-76sgl.js +155 -0
  747. package/dist/program-context-BMWNUfqL.js +10 -0
  748. package/dist/program-context-CD_RvRYh.js +2 -0
  749. package/dist/progress-D1r9bZU1.js +132 -0
  750. package/dist/prompt-select-styled-NUKYS9QR.js +4879 -0
  751. package/dist/prompt-style-BvciNCqy.js +7 -0
  752. package/dist/prompts-NtuylUyl.js +9 -0
  753. package/dist/prototype-keys-Cm_8mWvq.js +11 -0
  754. package/dist/provider-api-key-auth-BE0taXiB.js +108 -0
  755. package/dist/provider-api-key-auth.runtime-jDZZUAMX.js +34 -0
  756. package/dist/provider-auth-Bw8x1a3o.js +58 -0
  757. package/dist/provider-auth-api-key-BrQYvdxi.js +1 -0
  758. package/dist/provider-auth-choice-BYbPq0eC.js +128 -0
  759. package/dist/provider-auth-choice-helpers-Bj1GkOSn.js +48 -0
  760. package/dist/provider-auth-choice-preference-tKq5gaJL.js +192 -0
  761. package/dist/provider-auth-choice.runtime-DegPpvRJ.js +223 -0
  762. package/dist/provider-auth-choices-QSilukI1.js +58 -0
  763. package/dist/provider-auth-guidance-gninjjq8.js +34 -0
  764. package/dist/provider-auth-helpers-B0dS-1WK.js +86 -0
  765. package/dist/provider-auth-input-BftBdgvW.js +112 -0
  766. package/dist/provider-auth-login-D0n0lMuc.js +8 -0
  767. package/dist/provider-auth-login.runtime-LvuBkQrc.js +243 -0
  768. package/dist/provider-auth-mode-sTdccIKL.js +20 -0
  769. package/dist/provider-auth-ref-BS3gwrNr.js +168 -0
  770. package/dist/provider-auth-ref-BmEcEN7K.js +3 -0
  771. package/dist/provider-catalog--18-pW5t.js +11 -0
  772. package/dist/provider-catalog-2P2hel74.js +48 -0
  773. package/dist/provider-catalog-B0FqWSwe.js +48 -0
  774. package/dist/provider-catalog-BvORKzzD.js +91 -0
  775. package/dist/provider-catalog-C34j1_or.js +26 -0
  776. package/dist/provider-catalog-C5vmXjmb.js +11 -0
  777. package/dist/provider-catalog-CBufm2Dr.js +36 -0
  778. package/dist/provider-catalog-D7QvsUXS.js +12 -0
  779. package/dist/provider-catalog-DKy_dzQZ.js +41 -0
  780. package/dist/provider-env-vars-CsQlY7bF.js +110 -0
  781. package/dist/provider-id-BpXo5t6v.js +31 -0
  782. package/dist/provider-model-allowlist-4HSOnlX-.js +24 -0
  783. package/dist/provider-model-primary-NJ-xlhec.js +53 -0
  784. package/dist/provider-models-C2EjYMwW.js +2416 -0
  785. package/dist/provider-oauth-flow-BQN6F6EC.js +33 -0
  786. package/dist/provider-ollama-setup-DhQvDwAj.js +309 -0
  787. package/dist/provider-onboard-CjOfyeQG.js +1 -0
  788. package/dist/provider-onboarding-config-DOZ3pFA6.js +165 -0
  789. package/dist/provider-openai-codex-oauth-tls-Bo8U4D3E.js +101 -0
  790. package/dist/provider-runtime.runtime-DnP2jpoM.js +211 -0
  791. package/dist/provider-self-hosted-setup-CUrmsugW.js +182 -0
  792. package/dist/provider-usage-ClDVmkhl.js +633 -0
  793. package/dist/provider-usage-DIC6cn-3.js +211 -0
  794. package/dist/provider-web-search-NzK8ep1E.js +507 -0
  795. package/dist/provider-wizard-C6jCuyQe.js +236 -0
  796. package/dist/provider-zai-endpoint-DeDABzT4.js +106 -0
  797. package/dist/proxy-H5O2p6AP.js +121 -0
  798. package/dist/proxy-env-DG2u55RW.js +40 -0
  799. package/dist/push-apns-D4zD2tmP.js +1050 -0
  800. package/dist/pw-ai-BuPUVeUK.js +1876 -0
  801. package/dist/qmd-manager-BpygGMW9.js +1571 -0
  802. package/dist/qr-cli-DnWHXcxh.js +370 -0
  803. package/dist/qr-cli-yaZ0FZ6z.js +213 -0
  804. package/dist/query-expansion-Do45hILP.js +1114 -0
  805. package/dist/reactions-BcC_XZqD.js +281 -0
  806. package/dist/read-only-account-inspect-DPJzadPo.js +42 -0
  807. package/dist/read-only-account-inspect.discord.runtime-CW9DDKH8.js +216 -0
  808. package/dist/read-only-account-inspect.slack.runtime-BcXBPyh3.js +216 -0
  809. package/dist/read-only-account-inspect.telegram.runtime-Y7h0Jbdj.js +216 -0
  810. package/dist/redact-BDinS1q9.js +102 -0
  811. package/dist/redact-identifier-FUiWQxv5.js +13 -0
  812. package/dist/redact-snapshot-DBPmeYy2.js +2654 -0
  813. package/dist/ref-contract-CCBBbf1r.js +53 -0
  814. package/dist/register-CppP7Ddc.js +43 -0
  815. package/dist/register.agent-BOD5ROGQ.js +546 -0
  816. package/dist/register.backup-Y2VGqcRu.js +269 -0
  817. package/dist/register.configure-1qiTINph.js +354 -0
  818. package/dist/register.maintenance-shn-zigv.js +694 -0
  819. package/dist/register.message-mR4CLSoo.js +812 -0
  820. package/dist/register.onboard-CkDryVid.js +298 -0
  821. package/dist/register.setup-B0xW5olD.js +318 -0
  822. package/dist/register.status-health-sessions-CuhWc03j.js +604 -0
  823. package/dist/register.subclis-BazXM5TW.js +315 -0
  824. package/dist/register.subclis-C2d8UDhH.js +13 -0
  825. package/dist/registry-C3q59Qj0.js +55 -0
  826. package/dist/registry-CPsHw6xU.js +219 -0
  827. package/dist/registry-CxgtJ09C.js +28 -0
  828. package/dist/registry-rgYi7KoO.js +160 -0
  829. package/dist/repair-qXnOAvDy.js +105 -0
  830. package/dist/replies-EiwmmZ_W.js +122 -0
  831. package/dist/reply-history-CVCD5oE9.js +1 -0
  832. package/dist/reply-payload-DBGc074f.js +232 -0
  833. package/dist/report-cli-DB1jQx32.js +42 -0
  834. package/dist/request-url-BKfWAQx8.js +10 -0
  835. package/dist/resolve-Ckjd8TAk.js +14 -0
  836. package/dist/resolve-T2q_0ARF.js +619 -0
  837. package/dist/resolve-route-vEY3ONZ2.js +466 -0
  838. package/dist/resolve-utils-CbqJY2bs.js +102 -0
  839. package/dist/response-generator-VdoCcQ3y.js +153 -0
  840. package/dist/restart-stale-pids-CLGiqU2E.js +187 -0
  841. package/dist/retry-D15TD1S3.js +168 -0
  842. package/dist/root-help-B9Aou4ho.js +32 -0
  843. package/dist/routes-TpLEcKO8.js +7084 -0
  844. package/dist/routing-Y3m0o-kB.js +26 -0
  845. package/dist/rpc-C6MN-nVc.js +67 -0
  846. package/dist/run-command-DRKv5Lj6.js +32 -0
  847. package/dist/run-main-YZSMdx0B.js +424 -0
  848. package/dist/run-with-concurrency-BrSjWzpg.js +41 -0
  849. package/dist/runtime-B66W9flm.js +43 -0
  850. package/dist/runtime-C9VaVKYZ.js +2338 -0
  851. package/dist/runtime-CT2LIJZu.js +91 -0
  852. package/dist/runtime-CqDQ81eY.js +143 -0
  853. package/dist/runtime-CuvWMN7E.js +89 -0
  854. package/dist/runtime-D4_OpzA1.js +5 -0
  855. package/dist/runtime-DP-4DZja.js +5 -0
  856. package/dist/runtime-Dl17x_cV.js +1 -0
  857. package/dist/runtime-Z35JoYPC.js +30 -0
  858. package/dist/runtime-api-D79M0lQN.js +1 -0
  859. package/dist/runtime-api-y3zfnQGK.js +39 -0
  860. package/dist/runtime-discord-ops.runtime-Bg5h5v9-.js +234 -0
  861. package/dist/runtime-env-a_iwdJIv.js +1 -0
  862. package/dist/runtime-forwarders-DtMc8rBP.js +44 -0
  863. package/dist/runtime-group-policy-B7irU4eu.js +59 -0
  864. package/dist/runtime-guard-y62lPDGY.js +58 -0
  865. package/dist/runtime-parse-CeqXmZHJ.js +84 -0
  866. package/dist/runtime-paths-CstaCCMi.js +334 -0
  867. package/dist/runtime-slack-ops.runtime-BumgKDhS.js +226 -0
  868. package/dist/runtime-status-CgL02wYX.js +15 -0
  869. package/dist/runtime-store-Bt3Sdbrn.js +22 -0
  870. package/dist/runtime-telegram-ops.runtime-rSLQ3KrE.js +233 -0
  871. package/dist/runtime-whatsapp-boundary-xZem0NyQ.js +364 -0
  872. package/dist/safe-open-sync-Bt9R1Mnf.js +83 -0
  873. package/dist/safe-regex-tLlDZYfM.js +244 -0
  874. package/dist/safe-text-B_CQuica.js +16 -0
  875. package/dist/sandbox-CUUouiKs.js +2795 -0
  876. package/dist/sandbox-cli-BN8y0Get.js +499 -0
  877. package/dist/sandbox-paths-fqp_TZdO.js +144 -0
  878. package/dist/sandbox-qSs4h3sk.js +1 -0
  879. package/dist/sanitize-env-vars-vNSNqm0y.js +74 -0
  880. package/dist/scan-paths-BJmvUZ1E.js +28 -0
  881. package/dist/search-manager-DWhFgwyp.js +17 -0
  882. package/dist/search-manager-r8Cw4ZRv.js +392 -0
  883. package/dist/secret-equal-ObQfyZGa.js +9 -0
  884. package/dist/secret-file-Ch0yuOXR.js +11 -0
  885. package/dist/secret-file-DYJtH6kf.js +92 -0
  886. package/dist/secret-input-4REZ4sHo.js +35 -0
  887. package/dist/secrets-cli-D1df8b0o.js +2304 -0
  888. package/dist/secure-random-Cs8tw_HQ.js +10 -0
  889. package/dist/security-cli-V66ESmdT.js +676 -0
  890. package/dist/security-runtime-BuEhpJVE.js +23 -0
  891. package/dist/send-3tabvle6.js +100 -0
  892. package/dist/send-CC5J3tyW.js +1026 -0
  893. package/dist/send-deps-CrFMNvqO.js +19 -0
  894. package/dist/send-i2-mdtiE.js +250 -0
  895. package/dist/server-BTOjmlyi.js +116 -0
  896. package/dist/server-middleware-CCqKhKUb.js +106 -0
  897. package/dist/server-node-events-D6y22Tt8.js +611 -0
  898. package/dist/server-startup-matrix-migration-DHWSoS73.js +1595 -0
  899. package/dist/service-Bxc9uL2e.js +774 -0
  900. package/dist/service-CBLajPZL.js +21 -0
  901. package/dist/session-cost-usage-BmbaBvk4.js +212 -0
  902. package/dist/session-cost-usage-C30Jl2SI.js +615 -0
  903. package/dist/session-fork.runtime-BZfcC1Nc.js +51 -0
  904. package/dist/session-key-gFFk3uv9.js +216 -0
  905. package/dist/session-write-lock-DNKvpjKf.js +324 -0
  906. package/dist/sessions-BIH_j_XS.js +222 -0
  907. package/dist/sessions-D5dWcxC_.js +212 -0
  908. package/dist/sessions-DaSBVNwD.js +669 -0
  909. package/dist/setup-C2XF1YH3.js +397 -0
  910. package/dist/setup-CN-teRpz.js +8 -0
  911. package/dist/setup-adapter-runtime-Bjv2adwG.js +1 -0
  912. package/dist/setup-binary-BOJA7zdN.js +30 -0
  913. package/dist/setup-browser-BhNPCUtK.js +71 -0
  914. package/dist/setup-core-BsG09DZH.js +149 -0
  915. package/dist/setup-core-D-O1GQax.js +162 -0
  916. package/dist/setup-core-Dtm54Rcq.js +510 -0
  917. package/dist/setup-entry-B1mTa7bU.js +10 -0
  918. package/dist/setup-entry-CTMgw-K5.js +13 -0
  919. package/dist/setup-entry-Cmd_cufO.js +13 -0
  920. package/dist/setup-entry-CybgA3zP.js +12 -0
  921. package/dist/setup-entry-DED_hL6i.js +12 -0
  922. package/dist/setup-entry-WCq9VMWx.js +14 -0
  923. package/dist/setup-group-access-BtPApRvE.js +70 -0
  924. package/dist/setup-helpers-B62Ecg9r.js +362 -0
  925. package/dist/setup-surface-B7A7qowY.js +452 -0
  926. package/dist/setup-surface-BBYJVRXc.js +380 -0
  927. package/dist/setup-surface-CFUz_BJi.js +298 -0
  928. package/dist/setup-tools-BPiMjAN7.js +1 -0
  929. package/dist/setup-wizard-helpers-COZ1UAdX.js +770 -0
  930. package/dist/setup-wizard-proxy-Slwi-1gX.js +116 -0
  931. package/dist/setup.finalize-B8O01nge.js +633 -0
  932. package/dist/setup.gateway-config-BPDIFk__.js +288 -0
  933. package/dist/setup.secret-input-BL-bqJpt.js +25 -0
  934. package/dist/shared-AygSbeCK.js +50 -0
  935. package/dist/shared-BHqDLkMG.js +127 -0
  936. package/dist/shared-BPtG8PgB.js +70 -0
  937. package/dist/shared-BU0QgVMZ.js +36 -0
  938. package/dist/shared-Bzr2UyEm.js +351 -0
  939. package/dist/shared-C_XXbGIF.js +87 -0
  940. package/dist/shared-Diw3KzwZ.js +82 -0
  941. package/dist/shared-DngjQumT.js +196 -0
  942. package/dist/shared-DzH3zmAy.js +64 -0
  943. package/dist/shared-LeP8iUTz.js +54 -0
  944. package/dist/shell-argv-DWV43Vya.js +72 -0
  945. package/dist/shell-env-cD92jEyV.js +181 -0
  946. package/dist/signal-BQd9f9dF.js +315 -0
  947. package/dist/signal-Ca7y47bM.js +46 -0
  948. package/dist/signal-Did9U_fa.js +214 -0
  949. package/dist/signal-cli-install-DxoL8CgF.js +188 -0
  950. package/dist/skill-commands-CiSwTFBQ.js +652 -0
  951. package/dist/skill-commands.runtime-CEwlWT4j.js +34 -0
  952. package/dist/skill-scanner-DG7MT7pu.js +354 -0
  953. package/dist/skills-BC8GJ9Rp.js +22 -0
  954. package/dist/skills-CCgKs_NJ.js +863 -0
  955. package/dist/skills-cli-dhYXJCuL.js +339 -0
  956. package/dist/skills-install-DiriUXJd.js +763 -0
  957. package/dist/skills-status-BmQTn4jL.js +23 -0
  958. package/dist/skills-status-a9b899Y3.js +169 -0
  959. package/dist/slack-CXgv7nu7.js +730 -0
  960. package/dist/slack-CcSByPzI.js +217 -0
  961. package/dist/slack-CtcCh0Lj.js +24537 -0
  962. package/dist/slack-core-DcsbATUs.js +1 -0
  963. package/dist/slash-commands.runtime-kO8EUKYW.js +228 -0
  964. package/dist/slash-dispatch.runtime-Bu2yMeFy.js +238 -0
  965. package/dist/slash-skill-commands.runtime-wwX3tF84.js +216 -0
  966. package/dist/speech-bSreRuDH.js +1 -0
  967. package/dist/speech-runtime-y1FcnGVA.js +1 -0
  968. package/dist/src-CmXHIz5f.js +846 -0
  969. package/dist/ssh-config-ChqR6ijV.js +77 -0
  970. package/dist/ssh-tunnel-Cz51VBAt.js +159 -0
  971. package/dist/ssh-tunnel-DWze2IQS.js +16 -0
  972. package/dist/ssrf-Dk9XaoKN.js +220 -0
  973. package/dist/ssrf-policy-Dk6oMa20.js +69 -0
  974. package/dist/ssrf-runtime-C-mAQLVA.js +1 -0
  975. package/dist/stagger-DU7FjHYo.js +54 -0
  976. package/dist/state-paths-DJIGEFq_.js +1 -0
  977. package/dist/status-69r8-Zey.js +75 -0
  978. package/dist/status-BdLTvZOL.js +44 -0
  979. package/dist/status-Bt7DQmRI.js +1665 -0
  980. package/dist/status-CoUFSBgt.js +202 -0
  981. package/dist/status-DbI3Kbh5.js +235 -0
  982. package/dist/status-DeKlzu_o.js +212 -0
  983. package/dist/status-Haie42Fc.js +606 -0
  984. package/dist/status-helpers-Cda-rGLX.js +101 -0
  985. package/dist/status-json-DS1M_MWJ.js +322 -0
  986. package/dist/status.link-channel-Cb8bZ_Od.js +40 -0
  987. package/dist/status.scan.deps.runtime-7_6VUs50.js +77 -0
  988. package/dist/status.scan.runtime-DtR8BIE9.js +14 -0
  989. package/dist/status.summary-l_Bi1buR.js +600 -0
  990. package/dist/status.summary.runtime-Cng6MzRU.js +151 -0
  991. package/dist/status.update-DtbnnPKx.js +79 -0
  992. package/dist/store-CvL8MPei.js +1446 -0
  993. package/dist/store.runtime-hgnvmZgO.js +43 -0
  994. package/dist/string-normalization-CvzuCAZv.js +19 -0
  995. package/dist/string-sample-BOLqzr4Y.js +11 -0
  996. package/dist/subagent-orphan-recovery-si1z2iBu.js +407 -0
  997. package/dist/subagent-registry-runtime-CXUDI8gL.js +211 -0
  998. package/dist/subcli-descriptors-CY_nHzpZ.js +151 -0
  999. package/dist/subsystem-CUp-6QQf.js +421 -0
  1000. package/dist/synology-chat-CdejNfs0.js +12 -0
  1001. package/dist/system-cli-DkOaXHkQ.js +99 -0
  1002. package/dist/system-events-mAu6Ap6K.js +75 -0
  1003. package/dist/system-message-DA9eUYzB.js +16 -0
  1004. package/dist/system-run-command-Cxq2F1MB.js +258 -0
  1005. package/dist/systemd-CrxZBFae.js +557 -0
  1006. package/dist/systemd-hints-y-zJ9aTm.js +315 -0
  1007. package/dist/systemd-linger-BdklDcLg.js +16 -0
  1008. package/dist/systemd-linger-DLrbG9_d.js +68 -0
  1009. package/dist/table-DFMOhmNZ.js +305 -0
  1010. package/dist/tailnet-ofqBrXzu.js +38 -0
  1011. package/dist/tailscale-Cbsx-2HB.js +254 -0
  1012. package/dist/target-errors-ksphhzJg.js +26 -0
  1013. package/dist/target-registry-krAVlXi_.js +1321 -0
  1014. package/dist/telegram/audit.js +2 -0
  1015. package/dist/telegram/token.js +211 -0
  1016. package/dist/telegram-BjDUP22F.js +10910 -0
  1017. package/dist/telegram-DMiNSGAJ.js +575 -0
  1018. package/dist/telegram-Dt11B3JL.js +218 -0
  1019. package/dist/telegram-core-B4Jo-uko.js +1 -0
  1020. package/dist/template-messages-kh7VfgOb.js +214 -0
  1021. package/dist/text-chunking-CUf5WgqG.js +19 -0
  1022. package/dist/text-format-sFXlJfHH.js +8 -0
  1023. package/dist/text-runtime-C_Roi_Je.js +1418 -0
  1024. package/dist/theme-B5HDbQfl.js +2 -0
  1025. package/dist/theme-CdOoMzRk.js +34 -0
  1026. package/dist/thinking-BBD_0HSp.js +68 -0
  1027. package/dist/thinking.shared-CncvRHts.js +246 -0
  1028. package/dist/thread-bindings-messages-Cdo8jSa9.js +229 -0
  1029. package/dist/thread-bindings-policy-DMjOaNyR.js +119 -0
  1030. package/dist/thread-bindings-runtime-Ckwk3Uuz.js +1 -0
  1031. package/dist/threading-helpers-Cq55SUtb.js +14 -0
  1032. package/dist/timeouts-BwR1sGom.js +72 -0
  1033. package/dist/tmp-openclaw-dir-idKIOMmb.js +102 -0
  1034. package/dist/token-Bgv8XEsC.js +50 -0
  1035. package/dist/tool-catalog-BV6FcEWS.js +337 -0
  1036. package/dist/tool-policy-match-CHqTCSdK.js +46 -0
  1037. package/dist/tool-send-9LXKcrda.js +16 -0
  1038. package/dist/topology-cli-BhUXVViF.js +43 -0
  1039. package/dist/transcript-events-B1V6z5ct.js +29 -0
  1040. package/dist/tui-DDJMGCFK.js +3838 -0
  1041. package/dist/tui-cli-ByN-ZH6y.js +237 -0
  1042. package/dist/typebox-D0SHDJST.js +175 -0
  1043. package/dist/types-BCKGVVld.js +83 -0
  1044. package/dist/types-CtpUGsDP.js +30 -0
  1045. package/dist/types.secrets-BWSeXrF4.js +80 -0
  1046. package/dist/types.tools-BBO8HCi6.js +22 -0
  1047. package/dist/typing-DG_YqWJ7.js +224 -0
  1048. package/dist/unhandled-rejections-CDJ8dOVP.js +170 -0
  1049. package/dist/unhandled-rejections-O6cVOz2D.js +4 -0
  1050. package/dist/update-Br8U-txJ.js +1039 -0
  1051. package/dist/update-check-C3TeQaWg.js +464 -0
  1052. package/dist/update-cli-XHfIntD0.js +1625 -0
  1053. package/dist/update-offset-store-36vzzZXw.js +211 -0
  1054. package/dist/upsert-with-lock-Bb96JHpb.js +34 -0
  1055. package/dist/url-userinfo-Db63ng4y.js +14 -0
  1056. package/dist/utils-Bxk6BLTg.js +236 -0
  1057. package/dist/utils-vDeUf98G.js +7 -0
  1058. package/dist/version-DCY9_obP.js +64 -0
  1059. package/dist/version-DRF-wKTV.js +2 -0
  1060. package/dist/voice-call-D4fgwZNO.js +1 -0
  1061. package/dist/warning-filter-CgvLQB4Y.js +56 -0
  1062. package/dist/web-media-BfBb8i48.js +1 -0
  1063. package/dist/web-media-CtU6jM5V.js +498 -0
  1064. package/dist/webhook-ingress-CupqYpKM.js +338 -0
  1065. package/dist/webhook-memory-guards-BHrFZ4yq.js +129 -0
  1066. package/dist/webhook-path-BGFZ55ML.js +22 -0
  1067. package/dist/webhook-shared-Cvk3b0ac.js +349 -0
  1068. package/dist/webhooks-cli-vOAoBF9b.js +357 -0
  1069. package/dist/whatsapp-D5nD0rGG.js +58 -0
  1070. package/dist/whatsapp-DXbWlm3A.js +82 -0
  1071. package/dist/whatsapp-core-C2WGMsaY.js +89451 -0
  1072. package/dist/whatsapp-heartbeat-CSWnPQ7q.js +84 -0
  1073. package/dist/whatsapp-shared-BmHKqTtR.js +95 -0
  1074. package/dist/widearea-dns-CXimgJzu.js +125 -0
  1075. package/dist/windows-argv-IXrdWrJj.js +145 -0
  1076. package/dist/windows-spawn-vMJGZo89.js +154 -0
  1077. package/dist/with-timeout-2AKTISee.js +58 -0
  1078. package/dist/workspace-BH7CXmrr.js +479 -0
  1079. package/dist/workspace-dirs-_O4V3xCR.js +13 -0
  1080. package/dist/workspace-v5XppK5M.js +302 -0
  1081. package/dist/ws-By-QcLjg.js +11 -0
  1082. package/dist/wsl-BV3Cb66X.js +57 -0
  1083. package/dist/zalo-CHQzsLhE.js +301 -0
  1084. package/dist/zalo-CcJ3J9f2.js +13 -0
  1085. package/dist/zod-schema.agent-runtime-T_EC_6fg.js +600 -0
  1086. package/dist/zod-schema.core-BdgRr-F1.js +545 -0
  1087. package/dist/zod-schema.providers-core-Dgq7MTqU.js +1613 -0
  1088. package/docs/.i18n/README.md +31 -0
  1089. package/docs/.i18n/glossary.ja-JP.json +14 -0
  1090. package/docs/.i18n/glossary.zh-CN.json +242 -0
  1091. package/docs/.i18n/ja-JP.tm.jsonl +0 -0
  1092. package/docs/assets/install-script.svg +1 -0
  1093. package/docs/assets/macos-onboarding/01-macos-warning.jpeg +0 -0
  1094. package/docs/assets/macos-onboarding/02-local-networks.jpeg +0 -0
  1095. package/docs/assets/macos-onboarding/03-security-notice.png +0 -0
  1096. package/docs/assets/macos-onboarding/04-choose-gateway.png +0 -0
  1097. package/docs/assets/macos-onboarding/05-permissions.png +0 -0
  1098. package/docs/assets/openclaw-logo-text-dark.png +0 -0
  1099. package/docs/assets/openclaw-logo-text-dark.svg +418 -0
  1100. package/docs/assets/openclaw-logo-text.png +0 -0
  1101. package/docs/assets/openclaw-logo-text.svg +418 -0
  1102. package/docs/assets/pixel-lobster.svg +60 -0
  1103. package/docs/assets/showcase/agents-ui.jpg +0 -0
  1104. package/docs/assets/showcase/bambu-cli.png +0 -0
  1105. package/docs/assets/showcase/codexmonitor.png +0 -0
  1106. package/docs/assets/showcase/gohome-grafana.png +0 -0
  1107. package/docs/assets/showcase/ios-testflight.jpg +0 -0
  1108. package/docs/assets/showcase/oura-health.png +0 -0
  1109. package/docs/assets/showcase/padel-cli.svg +11 -0
  1110. package/docs/assets/showcase/padel-screenshot.jpg +0 -0
  1111. package/docs/assets/showcase/papla-tts.jpg +0 -0
  1112. package/docs/assets/showcase/pr-review-telegram.jpg +0 -0
  1113. package/docs/assets/showcase/roborock-screenshot.jpg +0 -0
  1114. package/docs/assets/showcase/roborock-status.svg +13 -0
  1115. package/docs/assets/showcase/roof-camera-sky.jpg +0 -0
  1116. package/docs/assets/showcase/snag.png +0 -0
  1117. package/docs/assets/showcase/tesco-shop.jpg +0 -0
  1118. package/docs/assets/showcase/wienerlinien.png +0 -0
  1119. package/docs/assets/showcase/wine-cellar-skill.jpg +0 -0
  1120. package/docs/assets/showcase/winix-air-purifier.jpg +0 -0
  1121. package/docs/assets/showcase/xuezh-pronunciation.jpeg +0 -0
  1122. package/docs/assets/sponsors/blacksmith.svg +14 -0
  1123. package/docs/assets/sponsors/convex.svg +16 -0
  1124. package/docs/assets/sponsors/openai.svg +3 -0
  1125. package/docs/assets/sponsors/vercel.svg +5 -0
  1126. package/docs/auth-credential-semantics.md +53 -0
  1127. package/docs/automation/auth-monitoring.md +44 -0
  1128. package/docs/automation/cron-jobs.md +727 -0
  1129. package/docs/automation/cron-vs-heartbeat.md +286 -0
  1130. package/docs/automation/gmail-pubsub.md +256 -0
  1131. package/docs/automation/hooks.md +1049 -0
  1132. package/docs/automation/poll.md +86 -0
  1133. package/docs/automation/standing-orders.md +251 -0
  1134. package/docs/automation/troubleshooting.md +122 -0
  1135. package/docs/automation/webhook.md +217 -0
  1136. package/docs/brave-search.md +93 -0
  1137. package/docs/channels/bluebubbles.md +347 -0
  1138. package/docs/channels/broadcast-groups.md +442 -0
  1139. package/docs/channels/channel-routing.md +139 -0
  1140. package/docs/channels/discord.md +1229 -0
  1141. package/docs/channels/feishu.md +747 -0
  1142. package/docs/channels/googlechat.md +261 -0
  1143. package/docs/channels/group-messages.md +84 -0
  1144. package/docs/channels/groups.md +379 -0
  1145. package/docs/channels/imessage.md +367 -0
  1146. package/docs/channels/index.md +47 -0
  1147. package/docs/channels/irc.md +242 -0
  1148. package/docs/channels/line.md +194 -0
  1149. package/docs/channels/location.md +56 -0
  1150. package/docs/channels/matrix.md +677 -0
  1151. package/docs/channels/mattermost.md +427 -0
  1152. package/docs/channels/msteams.md +780 -0
  1153. package/docs/channels/nextcloud-talk.md +138 -0
  1154. package/docs/channels/nostr.md +242 -0
  1155. package/docs/channels/pairing.md +114 -0
  1156. package/docs/channels/signal.md +329 -0
  1157. package/docs/channels/slack.md +603 -0
  1158. package/docs/channels/synology-chat.md +132 -0
  1159. package/docs/channels/telegram.md +987 -0
  1160. package/docs/channels/tlon.md +276 -0
  1161. package/docs/channels/troubleshooting.md +118 -0
  1162. package/docs/channels/twitch.md +379 -0
  1163. package/docs/channels/whatsapp.md +460 -0
  1164. package/docs/channels/zalo.md +243 -0
  1165. package/docs/channels/zalouser.md +181 -0
  1166. package/docs/ci.md +55 -0
  1167. package/docs/cli/acp.md +288 -0
  1168. package/docs/cli/agent.md +29 -0
  1169. package/docs/cli/agents.md +123 -0
  1170. package/docs/cli/approvals.md +50 -0
  1171. package/docs/cli/backup.md +76 -0
  1172. package/docs/cli/browser.md +106 -0
  1173. package/docs/cli/channels.md +102 -0
  1174. package/docs/cli/clawbot.md +21 -0
  1175. package/docs/cli/completion.md +35 -0
  1176. package/docs/cli/config.md +295 -0
  1177. package/docs/cli/configure.md +36 -0
  1178. package/docs/cli/cron.md +77 -0
  1179. package/docs/cli/daemon.md +53 -0
  1180. package/docs/cli/dashboard.md +22 -0
  1181. package/docs/cli/devices.md +139 -0
  1182. package/docs/cli/directory.md +63 -0
  1183. package/docs/cli/dns.md +23 -0
  1184. package/docs/cli/docs.md +15 -0
  1185. package/docs/cli/doctor.md +48 -0
  1186. package/docs/cli/gateway.md +235 -0
  1187. package/docs/cli/health.md +21 -0
  1188. package/docs/cli/hooks.md +318 -0
  1189. package/docs/cli/index.md +1147 -0
  1190. package/docs/cli/logs.md +28 -0
  1191. package/docs/cli/memory.md +66 -0
  1192. package/docs/cli/message.md +278 -0
  1193. package/docs/cli/models.md +81 -0
  1194. package/docs/cli/node.md +127 -0
  1195. package/docs/cli/nodes.md +75 -0
  1196. package/docs/cli/onboard.md +157 -0
  1197. package/docs/cli/pairing.md +32 -0
  1198. package/docs/cli/plugins.md +186 -0
  1199. package/docs/cli/qr.md +46 -0
  1200. package/docs/cli/reset.md +20 -0
  1201. package/docs/cli/sandbox.md +197 -0
  1202. package/docs/cli/secrets.md +188 -0
  1203. package/docs/cli/security.md +79 -0
  1204. package/docs/cli/sessions.md +110 -0
  1205. package/docs/cli/setup.md +29 -0
  1206. package/docs/cli/skills.md +26 -0
  1207. package/docs/cli/status.md +30 -0
  1208. package/docs/cli/system.md +60 -0
  1209. package/docs/cli/tui.md +30 -0
  1210. package/docs/cli/uninstall.md +20 -0
  1211. package/docs/cli/update.md +103 -0
  1212. package/docs/cli/voicecall.md +34 -0
  1213. package/docs/cli/webhooks.md +25 -0
  1214. package/docs/concepts/agent-loop.md +148 -0
  1215. package/docs/concepts/agent-workspace.md +236 -0
  1216. package/docs/concepts/agent.md +122 -0
  1217. package/docs/concepts/architecture.md +137 -0
  1218. package/docs/concepts/compaction.md +123 -0
  1219. package/docs/concepts/context-engine.md +268 -0
  1220. package/docs/concepts/context.md +172 -0
  1221. package/docs/concepts/delegate-architecture.md +296 -0
  1222. package/docs/concepts/features.md +73 -0
  1223. package/docs/concepts/markdown-formatting.md +130 -0
  1224. package/docs/concepts/memory.md +108 -0
  1225. package/docs/concepts/messages.md +154 -0
  1226. package/docs/concepts/model-failover.md +152 -0
  1227. package/docs/concepts/model-providers.md +607 -0
  1228. package/docs/concepts/models.md +225 -0
  1229. package/docs/concepts/multi-agent.md +552 -0
  1230. package/docs/concepts/oauth.md +158 -0
  1231. package/docs/concepts/presence.md +102 -0
  1232. package/docs/concepts/queue.md +89 -0
  1233. package/docs/concepts/retry.md +69 -0
  1234. package/docs/concepts/session-pruning.md +121 -0
  1235. package/docs/concepts/session-tool.md +242 -0
  1236. package/docs/concepts/session.md +310 -0
  1237. package/docs/concepts/streaming.md +155 -0
  1238. package/docs/concepts/system-prompt.md +132 -0
  1239. package/docs/concepts/timezone.md +91 -0
  1240. package/docs/concepts/typebox.md +291 -0
  1241. package/docs/concepts/typing-indicators.md +68 -0
  1242. package/docs/concepts/usage-tracking.md +35 -0
  1243. package/docs/date-time.md +128 -0
  1244. package/docs/debug/node-issue.md +85 -0
  1245. package/docs/diagnostics/flags.md +91 -0
  1246. package/docs/docs.json +2061 -0
  1247. package/docs/gateway/authentication.md +179 -0
  1248. package/docs/gateway/background-process.md +97 -0
  1249. package/docs/gateway/bonjour.md +177 -0
  1250. package/docs/gateway/bridge-protocol.md +91 -0
  1251. package/docs/gateway/cli-backends.md +225 -0
  1252. package/docs/gateway/configuration-examples.md +651 -0
  1253. package/docs/gateway/configuration-reference.md +3123 -0
  1254. package/docs/gateway/configuration.md +633 -0
  1255. package/docs/gateway/discovery.md +123 -0
  1256. package/docs/gateway/doctor.md +362 -0
  1257. package/docs/gateway/gateway-lock.md +34 -0
  1258. package/docs/gateway/health.md +44 -0
  1259. package/docs/gateway/heartbeat.md +393 -0
  1260. package/docs/gateway/index.md +261 -0
  1261. package/docs/gateway/local-models.md +152 -0
  1262. package/docs/gateway/logging.md +113 -0
  1263. package/docs/gateway/multiple-gateways.md +112 -0
  1264. package/docs/gateway/network-model.md +22 -0
  1265. package/docs/gateway/openai-http-api.md +132 -0
  1266. package/docs/gateway/openresponses-http-api.md +295 -0
  1267. package/docs/gateway/openshell.md +307 -0
  1268. package/docs/gateway/pairing.md +99 -0
  1269. package/docs/gateway/protocol.md +267 -0
  1270. package/docs/gateway/remote-gateway-readme.md +158 -0
  1271. package/docs/gateway/remote.md +153 -0
  1272. package/docs/gateway/sandbox-vs-tool-policy-vs-elevated.md +134 -0
  1273. package/docs/gateway/sandboxing.md +469 -0
  1274. package/docs/gateway/secrets-plan-contract.md +116 -0
  1275. package/docs/gateway/secrets.md +503 -0
  1276. package/docs/gateway/security/index.md +1213 -0
  1277. package/docs/gateway/tailscale.md +132 -0
  1278. package/docs/gateway/tools-invoke-http-api.md +110 -0
  1279. package/docs/gateway/troubleshooting.md +378 -0
  1280. package/docs/gateway/trusted-proxy-auth.md +330 -0
  1281. package/docs/help/debugging.md +168 -0
  1282. package/docs/help/environment.md +163 -0
  1283. package/docs/help/faq.md +2999 -0
  1284. package/docs/help/index.md +28 -0
  1285. package/docs/help/scripts.md +28 -0
  1286. package/docs/help/testing.md +524 -0
  1287. package/docs/help/troubleshooting.md +297 -0
  1288. package/docs/images/configure-model-picker-unsearchable.png +0 -0
  1289. package/docs/images/feishu-step2-create-app.png +0 -0
  1290. package/docs/images/feishu-step3-credentials.png +0 -0
  1291. package/docs/images/feishu-step4-permissions.png +0 -0
  1292. package/docs/images/feishu-step5-bot-capability.png +0 -0
  1293. package/docs/images/feishu-step6-event-subscription.png +0 -0
  1294. package/docs/images/feishu-verification-token.png +0 -0
  1295. package/docs/images/groups-flow.svg +52 -0
  1296. package/docs/images/mobile-ui-screenshot.png +0 -0
  1297. package/docs/index.md +196 -0
  1298. package/docs/install/ansible.md +230 -0
  1299. package/docs/install/azure.md +311 -0
  1300. package/docs/install/bun.md +55 -0
  1301. package/docs/install/development-channels.md +120 -0
  1302. package/docs/install/digitalocean.md +129 -0
  1303. package/docs/install/docker-vm-runtime.md +142 -0
  1304. package/docs/install/docker.md +375 -0
  1305. package/docs/install/exe-dev.md +126 -0
  1306. package/docs/install/fly.md +501 -0
  1307. package/docs/install/gcp.md +402 -0
  1308. package/docs/install/hetzner.md +251 -0
  1309. package/docs/install/index.md +183 -0
  1310. package/docs/install/installer.md +415 -0
  1311. package/docs/install/kubernetes.md +191 -0
  1312. package/docs/install/macos-vm.md +281 -0
  1313. package/docs/install/migrating-matrix.md +346 -0
  1314. package/docs/install/migrating.md +110 -0
  1315. package/docs/install/nix.md +89 -0
  1316. package/docs/install/node.md +138 -0
  1317. package/docs/install/northflank.mdx +54 -0
  1318. package/docs/install/oracle.md +156 -0
  1319. package/docs/install/podman.md +133 -0
  1320. package/docs/install/railway.mdx +100 -0
  1321. package/docs/install/raspberry-pi.md +159 -0
  1322. package/docs/install/render.mdx +169 -0
  1323. package/docs/install/uninstall.md +128 -0
  1324. package/docs/install/updating.md +128 -0
  1325. package/docs/ja-JP/index.md +186 -0
  1326. package/docs/ja-JP/start/getting-started.md +125 -0
  1327. package/docs/ja-JP/start/wizard.md +77 -0
  1328. package/docs/logging.md +352 -0
  1329. package/docs/nav-tabs-underline.js +100 -0
  1330. package/docs/network.md +54 -0
  1331. package/docs/nodes/audio.md +187 -0
  1332. package/docs/nodes/camera.md +162 -0
  1333. package/docs/nodes/images.md +72 -0
  1334. package/docs/nodes/index.md +393 -0
  1335. package/docs/nodes/location-command.md +98 -0
  1336. package/docs/nodes/media-understanding.md +394 -0
  1337. package/docs/nodes/talk.md +92 -0
  1338. package/docs/nodes/troubleshooting.md +114 -0
  1339. package/docs/nodes/voicewake.md +66 -0
  1340. package/docs/perplexity.md +174 -0
  1341. package/docs/pi-dev.md +80 -0
  1342. package/docs/pi.md +567 -0
  1343. package/docs/platforms/android.md +168 -0
  1344. package/docs/platforms/digitalocean.md +266 -0
  1345. package/docs/platforms/index.md +54 -0
  1346. package/docs/platforms/ios.md +220 -0
  1347. package/docs/platforms/linux.md +94 -0
  1348. package/docs/platforms/mac/bundled-gateway.md +73 -0
  1349. package/docs/platforms/mac/canvas.md +125 -0
  1350. package/docs/platforms/mac/child-process.md +69 -0
  1351. package/docs/platforms/mac/dev-setup.md +104 -0
  1352. package/docs/platforms/mac/health.md +34 -0
  1353. package/docs/platforms/mac/icon.md +31 -0
  1354. package/docs/platforms/mac/logging.md +57 -0
  1355. package/docs/platforms/mac/menu-bar.md +81 -0
  1356. package/docs/platforms/mac/peekaboo.md +65 -0
  1357. package/docs/platforms/mac/permissions.md +50 -0
  1358. package/docs/platforms/mac/remote.md +84 -0
  1359. package/docs/platforms/mac/signing.md +47 -0
  1360. package/docs/platforms/mac/skills.md +33 -0
  1361. package/docs/platforms/mac/voice-overlay.md +60 -0
  1362. package/docs/platforms/mac/voicewake.md +67 -0
  1363. package/docs/platforms/mac/webchat.md +43 -0
  1364. package/docs/platforms/mac/xpc.md +61 -0
  1365. package/docs/platforms/macos.md +226 -0
  1366. package/docs/platforms/oracle.md +303 -0
  1367. package/docs/platforms/raspberry-pi.md +412 -0
  1368. package/docs/platforms/windows.md +241 -0
  1369. package/docs/plugins/agent-tools.md +10 -0
  1370. package/docs/plugins/architecture.md +1363 -0
  1371. package/docs/plugins/building-extensions.md +10 -0
  1372. package/docs/plugins/building-plugins.md +376 -0
  1373. package/docs/plugins/bundles.md +181 -0
  1374. package/docs/plugins/community.md +141 -0
  1375. package/docs/plugins/manifest.md +145 -0
  1376. package/docs/plugins/sdk-migration.md +169 -0
  1377. package/docs/plugins/voice-call.md +380 -0
  1378. package/docs/plugins/zalouser.md +77 -0
  1379. package/docs/prose.md +134 -0
  1380. package/docs/providers/anthropic.md +259 -0
  1381. package/docs/providers/bedrock.md +176 -0
  1382. package/docs/providers/claude-max-api-proxy.md +154 -0
  1383. package/docs/providers/cloudflare-ai-gateway.md +71 -0
  1384. package/docs/providers/deepgram.md +93 -0
  1385. package/docs/providers/github-copilot.md +72 -0
  1386. package/docs/providers/glm.md +43 -0
  1387. package/docs/providers/google.md +78 -0
  1388. package/docs/providers/groq.md +96 -0
  1389. package/docs/providers/huggingface.md +209 -0
  1390. package/docs/providers/index.md +69 -0
  1391. package/docs/providers/kilocode.md +74 -0
  1392. package/docs/providers/litellm.md +154 -0
  1393. package/docs/providers/minimax.md +224 -0
  1394. package/docs/providers/mistral.md +54 -0
  1395. package/docs/providers/models.md +45 -0
  1396. package/docs/providers/modelstudio.md +66 -0
  1397. package/docs/providers/moonshot.md +175 -0
  1398. package/docs/providers/nvidia.md +55 -0
  1399. package/docs/providers/ollama.md +352 -0
  1400. package/docs/providers/openai.md +303 -0
  1401. package/docs/providers/opencode-go.md +45 -0
  1402. package/docs/providers/opencode.md +64 -0
  1403. package/docs/providers/openrouter.md +37 -0
  1404. package/docs/providers/perplexity-provider.md +62 -0
  1405. package/docs/providers/qianfan.md +38 -0
  1406. package/docs/providers/qwen.md +53 -0
  1407. package/docs/providers/sglang.md +104 -0
  1408. package/docs/providers/synthetic.md +99 -0
  1409. package/docs/providers/together.md +66 -0
  1410. package/docs/providers/venice.md +282 -0
  1411. package/docs/providers/vercel-ai-gateway.md +60 -0
  1412. package/docs/providers/vllm.md +92 -0
  1413. package/docs/providers/volcengine.md +74 -0
  1414. package/docs/providers/xai.md +60 -0
  1415. package/docs/providers/xiaomi.md +86 -0
  1416. package/docs/providers/zai.md +46 -0
  1417. package/docs/reference/AGENTS.default.md +126 -0
  1418. package/docs/reference/RELEASING.md +42 -0
  1419. package/docs/reference/api-usage-costs.md +144 -0
  1420. package/docs/reference/credits.md +30 -0
  1421. package/docs/reference/device-models.md +47 -0
  1422. package/docs/reference/memory-config.md +711 -0
  1423. package/docs/reference/prompt-caching.md +185 -0
  1424. package/docs/reference/rpc.md +43 -0
  1425. package/docs/reference/secretref-credential-surface.md +140 -0
  1426. package/docs/reference/secretref-user-supplied-credentials-matrix.json +563 -0
  1427. package/docs/reference/session-management-compaction.md +324 -0
  1428. package/docs/reference/templates/AGENTS.dev.md +83 -0
  1429. package/docs/reference/templates/AGENTS.md +219 -0
  1430. package/docs/reference/templates/BOOT.md +11 -0
  1431. package/docs/reference/templates/BOOTSTRAP.md +62 -0
  1432. package/docs/reference/templates/HEARTBEAT.md +14 -0
  1433. package/docs/reference/templates/IDENTITY.dev.md +47 -0
  1434. package/docs/reference/templates/IDENTITY.md +29 -0
  1435. package/docs/reference/templates/SOUL.dev.md +76 -0
  1436. package/docs/reference/templates/SOUL.md +43 -0
  1437. package/docs/reference/templates/TOOLS.dev.md +24 -0
  1438. package/docs/reference/templates/TOOLS.md +47 -0
  1439. package/docs/reference/templates/USER.dev.md +18 -0
  1440. package/docs/reference/templates/USER.md +23 -0
  1441. package/docs/reference/test.md +90 -0
  1442. package/docs/reference/token-use.md +175 -0
  1443. package/docs/reference/transcript-hygiene.md +151 -0
  1444. package/docs/reference/wizard.md +235 -0
  1445. package/docs/security/CONTRIBUTING-THREAT-MODEL.md +98 -0
  1446. package/docs/security/THREAT-MODEL-ATLAS.md +611 -0
  1447. package/docs/security/formal-verification.md +167 -0
  1448. package/docs/start/bootstrapping.md +41 -0
  1449. package/docs/start/docs-directory.md +66 -0
  1450. package/docs/start/getting-started.md +116 -0
  1451. package/docs/start/hubs.md +198 -0
  1452. package/docs/start/lore.md +219 -0
  1453. package/docs/start/onboarding-overview.md +67 -0
  1454. package/docs/start/onboarding.md +91 -0
  1455. package/docs/start/openclaw.md +216 -0
  1456. package/docs/start/quickstart.md +22 -0
  1457. package/docs/start/setup.md +164 -0
  1458. package/docs/start/showcase.md +418 -0
  1459. package/docs/start/wizard-cli-automation.md +215 -0
  1460. package/docs/start/wizard-cli-reference.md +299 -0
  1461. package/docs/start/wizard.md +125 -0
  1462. package/docs/style.css +37 -0
  1463. package/docs/tools/acp-agents.md +623 -0
  1464. package/docs/tools/agent-send.md +100 -0
  1465. package/docs/tools/apply-patch.md +51 -0
  1466. package/docs/tools/brave-search.md +93 -0
  1467. package/docs/tools/browser-linux-troubleshooting.md +138 -0
  1468. package/docs/tools/browser-login.md +73 -0
  1469. package/docs/tools/browser-wsl2-windows-remote-cdp-troubleshooting.md +211 -0
  1470. package/docs/tools/browser.md +731 -0
  1471. package/docs/tools/btw.md +142 -0
  1472. package/docs/tools/capability-cookbook.md +119 -0
  1473. package/docs/tools/clawhub.md +257 -0
  1474. package/docs/tools/creating-skills.md +117 -0
  1475. package/docs/tools/diffs.md +386 -0
  1476. package/docs/tools/elevated.md +114 -0
  1477. package/docs/tools/exec-approvals.md +400 -0
  1478. package/docs/tools/exec.md +204 -0
  1479. package/docs/tools/firecrawl.md +140 -0
  1480. package/docs/tools/index.md +137 -0
  1481. package/docs/tools/llm-task.md +119 -0
  1482. package/docs/tools/lobster.md +340 -0
  1483. package/docs/tools/loop-detection.md +100 -0
  1484. package/docs/tools/multi-agent-sandbox-tools.md +364 -0
  1485. package/docs/tools/pdf.md +156 -0
  1486. package/docs/tools/perplexity-search.md +174 -0
  1487. package/docs/tools/plugin.md +251 -0
  1488. package/docs/tools/reactions.md +64 -0
  1489. package/docs/tools/skills-config.md +86 -0
  1490. package/docs/tools/skills.md +306 -0
  1491. package/docs/tools/slash-commands.md +294 -0
  1492. package/docs/tools/subagents.md +295 -0
  1493. package/docs/tools/tavily.md +125 -0
  1494. package/docs/tools/thinking.md +96 -0
  1495. package/docs/tools/tts.md +406 -0
  1496. package/docs/tools/web.md +516 -0
  1497. package/docs/tts.md +406 -0
  1498. package/docs/vps.md +112 -0
  1499. package/docs/web/control-ui.md +275 -0
  1500. package/docs/web/dashboard.md +54 -0
  1501. package/docs/web/index.md +120 -0
  1502. package/docs/web/tui.md +170 -0
  1503. package/docs/web/webchat.md +61 -0
  1504. package/docs/whatsapp-openclaw-ai-zh.jpg +0 -0
  1505. package/docs/whatsapp-openclaw.jpg +0 -0
  1506. package/docs/zh-CN/AGENTS.md +61 -0
  1507. package/docs/zh-CN/automation/auth-monitoring.md +47 -0
  1508. package/docs/zh-CN/automation/cron-jobs.md +435 -0
  1509. package/docs/zh-CN/automation/cron-vs-heartbeat.md +286 -0
  1510. package/docs/zh-CN/automation/gmail-pubsub.md +249 -0
  1511. package/docs/zh-CN/automation/hooks.md +1051 -0
  1512. package/docs/zh-CN/automation/poll.md +76 -0
  1513. package/docs/zh-CN/automation/troubleshooting.md +8 -0
  1514. package/docs/zh-CN/automation/webhook.md +163 -0
  1515. package/docs/zh-CN/brave-search.md +60 -0
  1516. package/docs/zh-CN/channels/bluebubbles.md +354 -0
  1517. package/docs/zh-CN/channels/broadcast-groups.md +449 -0
  1518. package/docs/zh-CN/channels/channel-routing.md +117 -0
  1519. package/docs/zh-CN/channels/discord.md +468 -0
  1520. package/docs/zh-CN/channels/feishu.md +728 -0
  1521. package/docs/zh-CN/channels/googlechat.md +257 -0
  1522. package/docs/zh-CN/channels/grammy.md +38 -0
  1523. package/docs/zh-CN/channels/group-messages.md +91 -0
  1524. package/docs/zh-CN/channels/groups.md +379 -0
  1525. package/docs/zh-CN/channels/imessage.md +302 -0
  1526. package/docs/zh-CN/channels/index.md +53 -0
  1527. package/docs/zh-CN/channels/line.md +180 -0
  1528. package/docs/zh-CN/channels/location.md +63 -0
  1529. package/docs/zh-CN/channels/matrix.md +221 -0
  1530. package/docs/zh-CN/channels/mattermost.md +144 -0
  1531. package/docs/zh-CN/channels/msteams.md +775 -0
  1532. package/docs/zh-CN/channels/nextcloud-talk.md +142 -0
  1533. package/docs/zh-CN/channels/nostr.md +249 -0
  1534. package/docs/zh-CN/channels/pairing.md +89 -0
  1535. package/docs/zh-CN/channels/signal.md +209 -0
  1536. package/docs/zh-CN/channels/slack.md +531 -0
  1537. package/docs/zh-CN/channels/synology-chat.md +138 -0
  1538. package/docs/zh-CN/channels/telegram.md +751 -0
  1539. package/docs/zh-CN/channels/tlon.md +136 -0
  1540. package/docs/zh-CN/channels/troubleshooting.md +36 -0
  1541. package/docs/zh-CN/channels/twitch.md +385 -0
  1542. package/docs/zh-CN/channels/whatsapp.md +411 -0
  1543. package/docs/zh-CN/channels/zalo.md +196 -0
  1544. package/docs/zh-CN/channels/zalouser.md +147 -0
  1545. package/docs/zh-CN/cli/acp.md +173 -0
  1546. package/docs/zh-CN/cli/agent.md +30 -0
  1547. package/docs/zh-CN/cli/agents.md +82 -0
  1548. package/docs/zh-CN/cli/approvals.md +57 -0
  1549. package/docs/zh-CN/cli/browser.md +114 -0
  1550. package/docs/zh-CN/cli/channels.md +86 -0
  1551. package/docs/zh-CN/cli/config.md +57 -0
  1552. package/docs/zh-CN/cli/configure.md +38 -0
  1553. package/docs/zh-CN/cli/cron.md +43 -0
  1554. package/docs/zh-CN/cli/dashboard.md +23 -0
  1555. package/docs/zh-CN/cli/devices.md +74 -0
  1556. package/docs/zh-CN/cli/directory.md +70 -0
  1557. package/docs/zh-CN/cli/dns.md +30 -0
  1558. package/docs/zh-CN/cli/docs.md +22 -0
  1559. package/docs/zh-CN/cli/doctor.md +48 -0
  1560. package/docs/zh-CN/cli/gateway.md +206 -0
  1561. package/docs/zh-CN/cli/health.md +28 -0
  1562. package/docs/zh-CN/cli/hooks.md +298 -0
  1563. package/docs/zh-CN/cli/index.md +1143 -0
  1564. package/docs/zh-CN/cli/logs.md +31 -0
  1565. package/docs/zh-CN/cli/memory.md +52 -0
  1566. package/docs/zh-CN/cli/message.md +246 -0
  1567. package/docs/zh-CN/cli/models.md +85 -0
  1568. package/docs/zh-CN/cli/node.md +115 -0
  1569. package/docs/zh-CN/cli/nodes.md +80 -0
  1570. package/docs/zh-CN/cli/onboard.md +164 -0
  1571. package/docs/zh-CN/cli/pairing.md +28 -0
  1572. package/docs/zh-CN/cli/plugins.md +66 -0
  1573. package/docs/zh-CN/cli/reset.md +24 -0
  1574. package/docs/zh-CN/cli/sandbox.md +158 -0
  1575. package/docs/zh-CN/cli/security.md +33 -0
  1576. package/docs/zh-CN/cli/sessions.md +23 -0
  1577. package/docs/zh-CN/cli/setup.md +36 -0
  1578. package/docs/zh-CN/cli/skills.md +33 -0
  1579. package/docs/zh-CN/cli/status.md +33 -0
  1580. package/docs/zh-CN/cli/system.md +63 -0
  1581. package/docs/zh-CN/cli/tui.md +30 -0
  1582. package/docs/zh-CN/cli/uninstall.md +24 -0
  1583. package/docs/zh-CN/cli/update.md +101 -0
  1584. package/docs/zh-CN/cli/voicecall.md +41 -0
  1585. package/docs/zh-CN/cli/webhooks.md +32 -0
  1586. package/docs/zh-CN/concepts/agent-loop.md +146 -0
  1587. package/docs/zh-CN/concepts/agent-workspace.md +219 -0
  1588. package/docs/zh-CN/concepts/agent.md +115 -0
  1589. package/docs/zh-CN/concepts/architecture.md +123 -0
  1590. package/docs/zh-CN/concepts/compaction.md +67 -0
  1591. package/docs/zh-CN/concepts/context.md +168 -0
  1592. package/docs/zh-CN/concepts/features.md +59 -0
  1593. package/docs/zh-CN/concepts/markdown-formatting.md +117 -0
  1594. package/docs/zh-CN/concepts/memory.md +412 -0
  1595. package/docs/zh-CN/concepts/messages.md +141 -0
  1596. package/docs/zh-CN/concepts/model-failover.md +145 -0
  1597. package/docs/zh-CN/concepts/model-providers.md +606 -0
  1598. package/docs/zh-CN/concepts/models.md +225 -0
  1599. package/docs/zh-CN/concepts/multi-agent.md +372 -0
  1600. package/docs/zh-CN/concepts/oauth.md +164 -0
  1601. package/docs/zh-CN/concepts/presence.md +99 -0
  1602. package/docs/zh-CN/concepts/queue.md +94 -0
  1603. package/docs/zh-CN/concepts/retry.md +76 -0
  1604. package/docs/zh-CN/concepts/session-pruning.md +129 -0
  1605. package/docs/zh-CN/concepts/session-tool.md +200 -0
  1606. package/docs/zh-CN/concepts/session.md +166 -0
  1607. package/docs/zh-CN/concepts/streaming.md +133 -0
  1608. package/docs/zh-CN/concepts/system-prompt.md +101 -0
  1609. package/docs/zh-CN/concepts/timezone.md +96 -0
  1610. package/docs/zh-CN/concepts/typebox.md +284 -0
  1611. package/docs/zh-CN/concepts/typing-indicators.md +74 -0
  1612. package/docs/zh-CN/concepts/usage-tracking.md +42 -0
  1613. package/docs/zh-CN/date-time.md +129 -0
  1614. package/docs/zh-CN/debug/node-issue.md +90 -0
  1615. package/docs/zh-CN/diagnostics/flags.md +98 -0
  1616. package/docs/zh-CN/gateway/authentication.md +184 -0
  1617. package/docs/zh-CN/gateway/background-process.md +100 -0
  1618. package/docs/zh-CN/gateway/bonjour.md +174 -0
  1619. package/docs/zh-CN/gateway/bridge-protocol.md +86 -0
  1620. package/docs/zh-CN/gateway/cli-backends.md +213 -0
  1621. package/docs/zh-CN/gateway/configuration-examples.md +587 -0
  1622. package/docs/zh-CN/gateway/configuration-reference.md +3103 -0
  1623. package/docs/zh-CN/gateway/configuration.md +640 -0
  1624. package/docs/zh-CN/gateway/discovery.md +123 -0
  1625. package/docs/zh-CN/gateway/doctor.md +238 -0
  1626. package/docs/zh-CN/gateway/gateway-lock.md +41 -0
  1627. package/docs/zh-CN/gateway/health.md +42 -0
  1628. package/docs/zh-CN/gateway/heartbeat.md +274 -0
  1629. package/docs/zh-CN/gateway/index.md +335 -0
  1630. package/docs/zh-CN/gateway/local-models.md +159 -0
  1631. package/docs/zh-CN/gateway/logging.md +114 -0
  1632. package/docs/zh-CN/gateway/multiple-gateways.md +119 -0
  1633. package/docs/zh-CN/gateway/network-model.md +23 -0
  1634. package/docs/zh-CN/gateway/openai-http-api.md +125 -0
  1635. package/docs/zh-CN/gateway/openresponses-http-api.md +317 -0
  1636. package/docs/zh-CN/gateway/pairing.md +99 -0
  1637. package/docs/zh-CN/gateway/protocol.md +220 -0
  1638. package/docs/zh-CN/gateway/remote-gateway-readme.md +164 -0
  1639. package/docs/zh-CN/gateway/remote.md +133 -0
  1640. package/docs/zh-CN/gateway/sandbox-vs-tool-policy-vs-elevated.md +135 -0
  1641. package/docs/zh-CN/gateway/sandboxing.md +188 -0
  1642. package/docs/zh-CN/gateway/security/index.md +777 -0
  1643. package/docs/zh-CN/gateway/tailscale.md +124 -0
  1644. package/docs/zh-CN/gateway/tools-invoke-http-api.md +92 -0
  1645. package/docs/zh-CN/gateway/troubleshooting.md +771 -0
  1646. package/docs/zh-CN/help/debugging.md +160 -0
  1647. package/docs/zh-CN/help/environment.md +88 -0
  1648. package/docs/zh-CN/help/faq.md +2640 -0
  1649. package/docs/zh-CN/help/index.md +28 -0
  1650. package/docs/zh-CN/help/scripts.md +35 -0
  1651. package/docs/zh-CN/help/testing.md +375 -0
  1652. package/docs/zh-CN/help/troubleshooting.md +104 -0
  1653. package/docs/zh-CN/index.md +186 -0
  1654. package/docs/zh-CN/install/ansible.md +215 -0
  1655. package/docs/zh-CN/install/bun.md +65 -0
  1656. package/docs/zh-CN/install/development-channels.md +81 -0
  1657. package/docs/zh-CN/install/docker.md +532 -0
  1658. package/docs/zh-CN/install/exe-dev.md +133 -0
  1659. package/docs/zh-CN/install/fly.md +490 -0
  1660. package/docs/zh-CN/install/gcp.md +510 -0
  1661. package/docs/zh-CN/install/hetzner.md +337 -0
  1662. package/docs/zh-CN/install/index.md +235 -0
  1663. package/docs/zh-CN/install/installer.md +422 -0
  1664. package/docs/zh-CN/install/macos-vm.md +288 -0
  1665. package/docs/zh-CN/install/migrating.md +199 -0
  1666. package/docs/zh-CN/install/nix.md +99 -0
  1667. package/docs/zh-CN/install/node.md +8 -0
  1668. package/docs/zh-CN/install/northflank.mdx +60 -0
  1669. package/docs/zh-CN/install/railway.mdx +106 -0
  1670. package/docs/zh-CN/install/render.mdx +169 -0
  1671. package/docs/zh-CN/install/uninstall.md +135 -0
  1672. package/docs/zh-CN/install/updating.md +233 -0
  1673. package/docs/zh-CN/logging.md +329 -0
  1674. package/docs/zh-CN/network.md +59 -0
  1675. package/docs/zh-CN/nodes/audio.md +120 -0
  1676. package/docs/zh-CN/nodes/camera.md +162 -0
  1677. package/docs/zh-CN/nodes/images.md +79 -0
  1678. package/docs/zh-CN/nodes/index.md +348 -0
  1679. package/docs/zh-CN/nodes/location-command.md +120 -0
  1680. package/docs/zh-CN/nodes/media-understanding.md +380 -0
  1681. package/docs/zh-CN/nodes/talk.md +97 -0
  1682. package/docs/zh-CN/nodes/troubleshooting.md +8 -0
  1683. package/docs/zh-CN/nodes/voicewake.md +72 -0
  1684. package/docs/zh-CN/perplexity.md +102 -0
  1685. package/docs/zh-CN/pi-dev.md +77 -0
  1686. package/docs/zh-CN/pi.md +619 -0
  1687. package/docs/zh-CN/platforms/android.md +155 -0
  1688. package/docs/zh-CN/platforms/digitalocean.md +273 -0
  1689. package/docs/zh-CN/platforms/index.md +60 -0
  1690. package/docs/zh-CN/platforms/ios.md +114 -0
  1691. package/docs/zh-CN/platforms/linux.md +100 -0
  1692. package/docs/zh-CN/platforms/mac/bundled-gateway.md +75 -0
  1693. package/docs/zh-CN/platforms/mac/canvas.md +128 -0
  1694. package/docs/zh-CN/platforms/mac/child-process.md +73 -0
  1695. package/docs/zh-CN/platforms/mac/dev-setup.md +109 -0
  1696. package/docs/zh-CN/platforms/mac/health.md +41 -0
  1697. package/docs/zh-CN/platforms/mac/icon.md +38 -0
  1698. package/docs/zh-CN/platforms/mac/logging.md +64 -0
  1699. package/docs/zh-CN/platforms/mac/menu-bar.md +88 -0
  1700. package/docs/zh-CN/platforms/mac/peekaboo.md +62 -0
  1701. package/docs/zh-CN/platforms/mac/permissions.md +46 -0
  1702. package/docs/zh-CN/platforms/mac/remote.md +90 -0
  1703. package/docs/zh-CN/platforms/mac/signing.md +54 -0
  1704. package/docs/zh-CN/platforms/mac/skills.md +40 -0
  1705. package/docs/zh-CN/platforms/mac/voice-overlay.md +67 -0
  1706. package/docs/zh-CN/platforms/mac/voicewake.md +74 -0
  1707. package/docs/zh-CN/platforms/mac/webchat.md +43 -0
  1708. package/docs/zh-CN/platforms/mac/xpc.md +68 -0
  1709. package/docs/zh-CN/platforms/macos.md +193 -0
  1710. package/docs/zh-CN/platforms/oracle.md +310 -0
  1711. package/docs/zh-CN/platforms/raspberry-pi.md +416 -0
  1712. package/docs/zh-CN/platforms/windows.md +247 -0
  1713. package/docs/zh-CN/plugins/agent-tools.md +99 -0
  1714. package/docs/zh-CN/plugins/manifest.md +68 -0
  1715. package/docs/zh-CN/plugins/voice-call.md +250 -0
  1716. package/docs/zh-CN/plugins/zalouser.md +88 -0
  1717. package/docs/zh-CN/prose.md +141 -0
  1718. package/docs/zh-CN/providers/anthropic.md +265 -0
  1719. package/docs/zh-CN/providers/bedrock.md +170 -0
  1720. package/docs/zh-CN/providers/claude-max-api-proxy.md +155 -0
  1721. package/docs/zh-CN/providers/cloudflare-ai-gateway.md +78 -0
  1722. package/docs/zh-CN/providers/deepgram.md +97 -0
  1723. package/docs/zh-CN/providers/github-copilot.md +67 -0
  1724. package/docs/zh-CN/providers/glm.md +50 -0
  1725. package/docs/zh-CN/providers/huggingface.md +216 -0
  1726. package/docs/zh-CN/providers/index.md +69 -0
  1727. package/docs/zh-CN/providers/kilocode.md +80 -0
  1728. package/docs/zh-CN/providers/litellm.md +160 -0
  1729. package/docs/zh-CN/providers/minimax.md +222 -0
  1730. package/docs/zh-CN/providers/mistral.md +61 -0
  1731. package/docs/zh-CN/providers/models.md +51 -0
  1732. package/docs/zh-CN/providers/moonshot.md +182 -0
  1733. package/docs/zh-CN/providers/nvidia.md +62 -0
  1734. package/docs/zh-CN/providers/ollama.md +359 -0
  1735. package/docs/zh-CN/providers/openai.md +308 -0
  1736. package/docs/zh-CN/providers/opencode-go.md +52 -0
  1737. package/docs/zh-CN/providers/opencode.md +71 -0
  1738. package/docs/zh-CN/providers/openrouter.md +44 -0
  1739. package/docs/zh-CN/providers/qianfan.md +45 -0
  1740. package/docs/zh-CN/providers/qwen.md +55 -0
  1741. package/docs/zh-CN/providers/sglang.md +111 -0
  1742. package/docs/zh-CN/providers/synthetic.md +106 -0
  1743. package/docs/zh-CN/providers/together.md +72 -0
  1744. package/docs/zh-CN/providers/venice.md +289 -0
  1745. package/docs/zh-CN/providers/vercel-ai-gateway.md +66 -0
  1746. package/docs/zh-CN/providers/xiaomi.md +93 -0
  1747. package/docs/zh-CN/providers/zai.md +53 -0
  1748. package/docs/zh-CN/reference/AGENTS.default.md +131 -0
  1749. package/docs/zh-CN/reference/RELEASING.md +48 -0
  1750. package/docs/zh-CN/reference/api-usage-costs.md +141 -0
  1751. package/docs/zh-CN/reference/credits.md +34 -0
  1752. package/docs/zh-CN/reference/device-models.md +54 -0
  1753. package/docs/zh-CN/reference/rpc.md +48 -0
  1754. package/docs/zh-CN/reference/session-management-compaction.md +287 -0
  1755. package/docs/zh-CN/reference/templates/AGENTS.dev.md +89 -0
  1756. package/docs/zh-CN/reference/templates/AGENTS.md +225 -0
  1757. package/docs/zh-CN/reference/templates/BOOT.md +17 -0
  1758. package/docs/zh-CN/reference/templates/BOOTSTRAP.md +68 -0
  1759. package/docs/zh-CN/reference/templates/HEARTBEAT.md +18 -0
  1760. package/docs/zh-CN/reference/templates/IDENTITY.dev.md +54 -0
  1761. package/docs/zh-CN/reference/templates/IDENTITY.md +36 -0
  1762. package/docs/zh-CN/reference/templates/SOUL.dev.md +83 -0
  1763. package/docs/zh-CN/reference/templates/SOUL.md +49 -0
  1764. package/docs/zh-CN/reference/templates/TOOLS.dev.md +31 -0
  1765. package/docs/zh-CN/reference/templates/TOOLS.md +53 -0
  1766. package/docs/zh-CN/reference/templates/USER.dev.md +25 -0
  1767. package/docs/zh-CN/reference/templates/USER.md +30 -0
  1768. package/docs/zh-CN/reference/test.md +57 -0
  1769. package/docs/zh-CN/reference/token-use.md +119 -0
  1770. package/docs/zh-CN/reference/transcript-hygiene.md +109 -0
  1771. package/docs/zh-CN/reference/wizard.md +242 -0
  1772. package/docs/zh-CN/security/formal-verification.md +171 -0
  1773. package/docs/zh-CN/start/bootstrapping.md +9 -0
  1774. package/docs/zh-CN/start/docs-directory.md +70 -0
  1775. package/docs/zh-CN/start/getting-started.md +143 -0
  1776. package/docs/zh-CN/start/hubs.md +194 -0
  1777. package/docs/zh-CN/start/lore.md +226 -0
  1778. package/docs/zh-CN/start/onboarding-overview.md +58 -0
  1779. package/docs/zh-CN/start/onboarding.md +105 -0
  1780. package/docs/zh-CN/start/openclaw.md +248 -0
  1781. package/docs/zh-CN/start/quickstart.md +88 -0
  1782. package/docs/zh-CN/start/setup.md +153 -0
  1783. package/docs/zh-CN/start/showcase.md +423 -0
  1784. package/docs/zh-CN/start/wizard-cli-automation.md +222 -0
  1785. package/docs/zh-CN/start/wizard-cli-reference.md +306 -0
  1786. package/docs/zh-CN/start/wizard.md +132 -0
  1787. package/docs/zh-CN/tools/agent-send.md +59 -0
  1788. package/docs/zh-CN/tools/apply-patch.md +57 -0
  1789. package/docs/zh-CN/tools/browser-linux-troubleshooting.md +144 -0
  1790. package/docs/zh-CN/tools/browser-login.md +75 -0
  1791. package/docs/zh-CN/tools/browser.md +553 -0
  1792. package/docs/zh-CN/tools/chrome-extension.md +183 -0
  1793. package/docs/zh-CN/tools/clawhub.md +209 -0
  1794. package/docs/zh-CN/tools/creating-skills.md +61 -0
  1795. package/docs/zh-CN/tools/elevated.md +64 -0
  1796. package/docs/zh-CN/tools/exec-approvals.md +234 -0
  1797. package/docs/zh-CN/tools/exec.md +169 -0
  1798. package/docs/zh-CN/tools/firecrawl.md +68 -0
  1799. package/docs/zh-CN/tools/index.md +515 -0
  1800. package/docs/zh-CN/tools/llm-task.md +117 -0
  1801. package/docs/zh-CN/tools/lobster.md +349 -0
  1802. package/docs/zh-CN/tools/multi-agent-sandbox-tools.md +401 -0
  1803. package/docs/zh-CN/tools/plugin.md +1612 -0
  1804. package/docs/zh-CN/tools/reactions.md +29 -0
  1805. package/docs/zh-CN/tools/skills-config.md +78 -0
  1806. package/docs/zh-CN/tools/skills.md +279 -0
  1807. package/docs/zh-CN/tools/slash-commands.md +205 -0
  1808. package/docs/zh-CN/tools/subagents.md +167 -0
  1809. package/docs/zh-CN/tools/thinking.md +80 -0
  1810. package/docs/zh-CN/tools/web.md +289 -0
  1811. package/docs/zh-CN/tts.md +375 -0
  1812. package/docs/zh-CN/vps.md +47 -0
  1813. package/docs/zh-CN/web/control-ui.md +191 -0
  1814. package/docs/zh-CN/web/dashboard.md +53 -0
  1815. package/docs/zh-CN/web/index.md +118 -0
  1816. package/docs/zh-CN/web/tui.md +166 -0
  1817. package/docs/zh-CN/web/webchat.md +56 -0
  1818. package/openclaw.mjs +135 -0
  1819. package/package.json +835 -0
  1820. package/skills/1password/SKILL.md +70 -0
  1821. package/skills/1password/references/cli-examples.md +29 -0
  1822. package/skills/1password/references/get-started.md +17 -0
  1823. package/skills/apple-notes/SKILL.md +77 -0
  1824. package/skills/apple-reminders/SKILL.md +118 -0
  1825. package/skills/bear-notes/SKILL.md +107 -0
  1826. package/skills/blogwatcher/SKILL.md +69 -0
  1827. package/skills/blucli/SKILL.md +47 -0
  1828. package/skills/bluebubbles/SKILL.md +131 -0
  1829. package/skills/camsnap/SKILL.md +45 -0
  1830. package/skills/canvas/SKILL.md +198 -0
  1831. package/skills/clawhub/SKILL.md +77 -0
  1832. package/skills/coding-agent/SKILL.md +295 -0
  1833. package/skills/discord/SKILL.md +197 -0
  1834. package/skills/doubao-code/SKILL.md +43 -0
  1835. package/skills/eightctl/SKILL.md +50 -0
  1836. package/skills/gemini/SKILL.md +43 -0
  1837. package/skills/gh-issues/SKILL.md +865 -0
  1838. package/skills/gifgrep/SKILL.md +79 -0
  1839. package/skills/github/SKILL.md +163 -0
  1840. package/skills/gog/SKILL.md +116 -0
  1841. package/skills/goplaces/SKILL.md +52 -0
  1842. package/skills/healthcheck/SKILL.md +245 -0
  1843. package/skills/himalaya/SKILL.md +257 -0
  1844. package/skills/himalaya/references/configuration.md +184 -0
  1845. package/skills/himalaya/references/message-composition.md +199 -0
  1846. package/skills/imsg/SKILL.md +122 -0
  1847. package/skills/kimi-code/SKILL.md +42 -0
  1848. package/skills/mcporter/SKILL.md +61 -0
  1849. package/skills/model-usage/SKILL.md +69 -0
  1850. package/skills/model-usage/references/codexbar-cli.md +33 -0
  1851. package/skills/model-usage/scripts/model_usage.py +320 -0
  1852. package/skills/model-usage/scripts/test_model_usage.py +40 -0
  1853. package/skills/nano-pdf/SKILL.md +38 -0
  1854. package/skills/node-connect/SKILL.md +142 -0
  1855. package/skills/notion/SKILL.md +174 -0
  1856. package/skills/obsidian/SKILL.md +81 -0
  1857. package/skills/openai-image-gen/SKILL.md +92 -0
  1858. package/skills/openai-image-gen/scripts/gen.py +328 -0
  1859. package/skills/openai-image-gen/scripts/test_gen.py +140 -0
  1860. package/skills/openai-whisper/SKILL.md +38 -0
  1861. package/skills/openai-whisper-api/SKILL.md +52 -0
  1862. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  1863. package/skills/openhue/SKILL.md +112 -0
  1864. package/skills/oracle/SKILL.md +125 -0
  1865. package/skills/ordercli/SKILL.md +78 -0
  1866. package/skills/peekaboo/SKILL.md +190 -0
  1867. package/skills/sag/SKILL.md +87 -0
  1868. package/skills/session-logs/SKILL.md +115 -0
  1869. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  1870. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  1871. package/skills/skill-creator/SKILL.md +372 -0
  1872. package/skills/skill-creator/license.txt +202 -0
  1873. package/skills/skill-creator/scripts/init_skill.py +378 -0
  1874. package/skills/skill-creator/scripts/package_skill.py +139 -0
  1875. package/skills/skill-creator/scripts/quick_validate.py +159 -0
  1876. package/skills/skill-creator/scripts/test_package_skill.py +160 -0
  1877. package/skills/skill-creator/scripts/test_quick_validate.py +72 -0
  1878. package/skills/slack/SKILL.md +144 -0
  1879. package/skills/songsee/SKILL.md +49 -0
  1880. package/skills/sonoscli/SKILL.md +65 -0
  1881. package/skills/spotify-player/SKILL.md +64 -0
  1882. package/skills/summarize/SKILL.md +87 -0
  1883. package/skills/things-mac/SKILL.md +86 -0
  1884. package/skills/tmux/SKILL.md +153 -0
  1885. package/skills/tmux/scripts/find-sessions.sh +112 -0
  1886. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  1887. package/skills/trello/SKILL.md +95 -0
  1888. package/skills/video-frames/SKILL.md +46 -0
  1889. package/skills/video-frames/scripts/frame.sh +81 -0
  1890. package/skills/voice-call/SKILL.md +45 -0
  1891. package/skills/wacli/SKILL.md +72 -0
  1892. package/skills/weather/SKILL.md +112 -0
  1893. package/skills/xurl/SKILL.md +461 -0
@@ -0,0 +1,4923 @@
1
+ import { a as logVerbose } from "./globals-41sdSaKv.js";
2
+ import { i as clampInt } from "./utils-Bxk6BLTg.js";
3
+ import { d as normalizeUsageDisplay, p as resolveResponseUsageMode, s as normalizeFastMode } from "./thinking.shared-CncvRHts.js";
4
+ import { S as parseAgentSessionKey, c as normalizeAgentId, u as resolveAgentIdFromSessionKey, v as isAcpSessionKey, x as isSubagentSessionKey } from "./session-key-gFFk3uv9.js";
5
+ import { n as normalizeAccountId, r as normalizeOptionalAccountId } from "./account-id-ZCrgXl7Z.js";
6
+ import { r as normalizeStringEntries } from "./string-normalization-CvzuCAZv.js";
7
+ import { v as resolveSessionAgentId } from "./agent-scope-DPP4Z_UU.js";
8
+ import { A as getConfigOverrides, F as parseConfigPath, I as setConfigValueAtPath, L as unsetConfigValueAtPath, M as setConfigOverride, N as unsetConfigOverride, P as getConfigValueAtPath, b as validateConfigObjectWithPlugins, d as readConfigFileSnapshot, g as writeConfigFile, j as resetConfigOverrides } from "./io-jOnQRia2.js";
9
+ import { o as normalizeChannelId } from "./registry-rgYi7KoO.js";
10
+ import { t as parseDurationMs } from "./parse-duration-BBGYkY0S.js";
11
+ import { a as isInternalMessageChannel, h as GATEWAY_CLIENT_NAMES, m as GATEWAY_CLIENT_MODES } from "./message-channel-Cy-gN4K2.js";
12
+ import { l as updateSessionStore, n as loadSessionStore } from "./store-CvL8MPei.js";
13
+ import { t as getChannelPlugin } from "./registry-C3q59Qj0.js";
14
+ import { i as resolveSessionFilePathOptions, l as resolveStorePath, r as resolveSessionFilePath } from "./paths-CTjJI9l0.js";
15
+ import { a as resolveFreshSessionTotalTokens } from "./types-BCKGVVld.js";
16
+ import { n as callGateway } from "./call-BmLt3xO1.js";
17
+ import { r as isRestartEnabled, t as isCommandFlagEnabled } from "./commands-Bb9xUwz9.js";
18
+ import { $d as setTtsEnabled, $r as extractBtwQuestion, Aa as buildDisabledCommandReply, Al as normalizeConversationText, Ap as resolveAcpThreadSessionDetailLines, Ba as handleStatusCommand, Bd as isTtsEnabled, Cf as killProcessTree, Cl as looksLikeSessionId, Ct as isTelegramExecApprovalClientEnabled, Dl as resolveEffectiveResetTargetSessionKey, El as parseDiscordParentChannelFromSessionKey, Fl as incrementCompactionCount, Fs as getFinishedSession, Gd as resolveTtsApiKey, Gm as parseExplicitTargetForChannel, Ia as handleCommandsListCommand, Id as getLastTtsAttempt, Il as stripToolResultDetails, Is as getSession, Jd as resolveTtsPrefsPath, La as handleContextCommand, Ld as getTtsMaxLength, Ls as markExited, Ma as rejectUnauthorizedCommand, Mp as resolveAcpAgentPolicyError, Na as requireCommandFlagEnabled, Nf as resolveSendPolicy, Np as resolveAcpDispatchPolicyError, Oa as handleModelsCommand, Ol as resolveConversationIdFromTargets, Op as resolveAcpSessionCwd, Pa as requireGatewayClientScopeForInternalChannel, Pp as resolveAcpDispatchPolicyMessage, Ps as createExecTool, Ra as handleExportSessionCommand, Rd as getTtsProvider, Rl as clearSessionQueues, Rm as executePluginCommand, Sl as SESSION_ID_RE, St as isTelegramExecApprovalApprover, Us as formatContextUsageShort, Va as handleWhoamiCommand, Vd as isTtsProviderConfigured, Vm as matchPluginCommand, Ws as formatTokenCount, Xd as setLastTtsAttempt, Yl as formatElevatedUnavailableMessage, Zd as setSummarizationEnabled, Zl as parseActivationCommand, a as isEmbeddedPiRunActive, af as listSpeechProviders, am as EmbeddedBlockChunker, as as triggerOpenClawRestart, bl as resolveInternalSessionKey, c as compactEmbeddedPiSession, cd as formatUsd, co as formatDurationCompact, do as resolveSubagentTargetFromRuns, ef as setTtsMaxLength, el as formatAcpRuntimeErrorText, fl as listSubagentRunsForController, fm as ensureOpenClawModelsJson, fo as sortSubagentRuns, go as cleanupFailedAcpSpawn, ho as resolveAcpSpawnRuntimePolicyError, i as getActiveEmbeddedRunSnapshot, il as stopSubagentsForRequester, im as extractTextFromChatContent, ja as rejectNonOwnerCommand, jl as parseTelegramChatIdFromTarget, jp as isAcpEnabledByPolicy, kl as buildTelegramTopicConversationId, km as getGlobalHookRunner, kp as resolveAcpSessionIdentifierLinesFromIdentity, lo as formatRunLabel, mo as resolveStoredSubagentCapabilities, n as abortEmbeddedPiRun, nl as formatAbortReplyText, no as killAllControlledSubagentRuns, ns as scheduleGatewaySigusr1Restart, of as normalizeSpeechProviderId, ol as countPendingDescendantRuns, oo as sendControlledSubagentMessage, po as spawnSubagentDirect, qd as resolveTtsConfig, rf as textToSpeech, rl as resolveSessionEntryForKey, ro as killControlledSubagentRun, s as waitForEmbeddedPiRunEnd, sd as formatTokenCount$1, so as steerControlledSubagentRun, tf as setTtsProvider, tl as toAcpRuntimeErrorText, to as buildSubagentList, u as mapThinkingLevel, uo as formatRunStatus, vf as resolveModelWithRegistry, vl as sanitizeTextContent, xl as resolveMainSessionAlias, xp as resolveFastModeState, yl as stripToolMessages, za as handleHelpCommand, zd as isSummarizationEnabled, zl as routeReply } from "./pi-embedded-CSQySvOV.js";
19
+ import { n as getApiKeyForModel, o as requireApiKey } from "./model-auth-B__TJTPw.js";
20
+ import { t as diag } from "./diagnostic-DqJXx_4Q.js";
21
+ import { i as resolveThreadBindingThreadName, o as getSessionBindingService, r as resolveThreadBindingIntroText, t as formatThreadBindingDurationLabel } from "./thread-bindings-messages-Cdo8jSa9.js";
22
+ import { c as resetConfiguredBindingTargetInPlace } from "./conversation-runtime-1O0Aaolb.js";
23
+ import { d as triggerInternalHook, n as createInternalHookEvent } from "./internal-hooks-0uipqzRY.js";
24
+ import { P as resolveSandboxRuntimeStatus } from "./sandbox-CUUouiKs.js";
25
+ import { r as setPluginEnabledInConfig } from "./provider-web-search-NzK8ep1E.js";
26
+ import { b as toAcpRuntimeError, c as parseRuntimeTimeoutSecondsInput, d as validateRuntimeModeInput, f as validateRuntimeModelInput, h as resolveAcpSessionResolutionError, i as getAcpRuntimeBackend, l as validateRuntimeConfigOptionInput, n as readAcpSessionEntry, o as requireAcpRuntimeBackend, p as validateRuntimePermissionProfileInput, r as resolveSessionStorePathForAcp, t as getAcpSessionManager, u as validateRuntimeCwdInput } from "./manager-ChTGDe87.js";
27
+ import { _ as authorizeConfigWrite, v as canBypassConfigWritePolicy, x as resolveConfigWriteTargetFromPath, y as formatConfigWriteDeniedMessage } from "./channel-config-helpers-CieQWILI.js";
28
+ import { a as readChannelAllowFromStore, l as removeChannelAllowFromStoreEntry, t as addChannelAllowFromStoreEntry } from "./pairing-store-C4lsd4pO.js";
29
+ import { d as resolveSessionAuthProfileOverride } from "./model-selection-Ci9cPkL2.js";
30
+ import { r as enqueueSystemEvent } from "./system-events-mAu6Ap6K.js";
31
+ import { i as discoverModels, r as discoverAuthStorage } from "./pi-model-discovery-CuX5CDyZ.js";
32
+ import { o as stripMentions, s as stripStructuralPrefixes } from "./mentions-Bxys_va0.js";
33
+ import { a as shouldPersistAbortCutoff, i as resolveAbortCutoffFromContext, t as applyAbortCutoffToSessionEntry } from "./abort-cutoff-CERmtgZI.js";
34
+ import { p as normalizeCommandBody, y as shouldHandleTextCommands } from "./commands-registry-ChCep1KJ.js";
35
+ import { v as isAbortTrigger, y as setAbortMemory } from "./channel-inbound-DwzVf2PK.js";
36
+ import { n as formatTimeAgo } from "./format-relative-C3nDxnXz.js";
37
+ import { d as resolveThreadBindingSpawnPolicy, i as formatThreadBindingSpawnDisabledError, r as formatThreadBindingDisabledError, s as resolveThreadBindingIdleTimeoutMsForChannel, u as resolveThreadBindingMaxAgeMsForChannel } from "./thread-bindings-policy-DMjOaNyR.js";
38
+ import { i as unsetConfiguredMcpServer, r as setConfiguredMcpServer, t as listConfiguredMcpServers } from "./mcp-config-Coky4zS4.js";
39
+ import { n as createPluginRuntime } from "./runtime-C9VaVKYZ.js";
40
+ import { t as parseConfigValue } from "./config-value-DgJrpclm.js";
41
+ import { a as buildPluginStatusReport, i as buildPluginInspectReport, o as formatPluginCompatibilityNotice, t as buildAllPluginInspectReports } from "./status-CoUFSBgt.js";
42
+ import { n as loadCostUsageSummary, r as loadSessionCostSummary } from "./session-cost-usage-C30Jl2SI.js";
43
+ import { existsSync } from "node:fs";
44
+ import path from "node:path";
45
+ import fs$1 from "node:fs/promises";
46
+ import { randomUUID } from "node:crypto";
47
+ import { SessionManager } from "@mariozechner/pi-coding-agent";
48
+ import { streamSimple } from "@mariozechner/pi-ai";
49
+ //#region src/auto-reply/reply/matrix-context.ts
50
+ function normalizeMatrixTarget(value) {
51
+ return typeof value === "string" ? value.trim() : "";
52
+ }
53
+ function resolveMatrixRoomIdFromTarget(raw) {
54
+ let target = normalizeMatrixTarget(raw);
55
+ if (!target) return;
56
+ if (target.toLowerCase().startsWith("matrix:")) target = target.slice(7).trim();
57
+ if (/^(room|channel):/i.test(target)) return target.replace(/^(room|channel):/i, "").trim() || void 0;
58
+ if (target.startsWith("!") || target.startsWith("#")) return target;
59
+ }
60
+ function resolveMatrixParentConversationId(params) {
61
+ const targets = [
62
+ params.ctx.OriginatingTo,
63
+ params.command.to,
64
+ params.ctx.To
65
+ ];
66
+ for (const candidate of targets) {
67
+ const roomId = resolveMatrixRoomIdFromTarget(candidate ?? "");
68
+ if (roomId) return roomId;
69
+ }
70
+ }
71
+ function resolveMatrixConversationId(params) {
72
+ const threadId = params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId).trim() : "";
73
+ if (threadId) return threadId;
74
+ return resolveMatrixParentConversationId(params);
75
+ }
76
+ //#endregion
77
+ //#region src/auto-reply/reply/telegram-context.ts
78
+ function resolveTelegramConversationId(params) {
79
+ const threadId = (params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId).trim() : "") || void 0;
80
+ const chatId = [
81
+ typeof params.ctx.OriginatingTo === "string" ? params.ctx.OriginatingTo : "",
82
+ typeof params.command.to === "string" ? params.command.to : "",
83
+ typeof params.ctx.To === "string" ? params.ctx.To : ""
84
+ ].map((value) => value.trim()).filter(Boolean).map((candidate) => parseExplicitTargetForChannel("telegram", candidate)?.to.trim() ?? "").find((candidate) => candidate.length > 0);
85
+ if (!chatId) return;
86
+ if (threadId) return `${chatId}:topic:${threadId}`;
87
+ if (chatId.startsWith("-")) return;
88
+ return chatId;
89
+ }
90
+ //#endregion
91
+ //#region src/auto-reply/reply/commands-acp/context.ts
92
+ function buildFeishuConversationId(params) {
93
+ const chatId = normalizeConversationText(params.chatId) ?? "unknown";
94
+ const senderOpenId = normalizeConversationText(params.senderOpenId);
95
+ const topicId = normalizeConversationText(params.topicId);
96
+ switch (params.scope) {
97
+ case "group_sender": return senderOpenId ? `${chatId}:sender:${senderOpenId}` : chatId;
98
+ case "group_topic": return topicId ? `${chatId}:topic:${topicId}` : chatId;
99
+ case "group_topic_sender":
100
+ if (topicId && senderOpenId) return `${chatId}:topic:${topicId}:sender:${senderOpenId}`;
101
+ if (topicId) return `${chatId}:topic:${topicId}`;
102
+ return senderOpenId ? `${chatId}:sender:${senderOpenId}` : chatId;
103
+ default: return chatId;
104
+ }
105
+ }
106
+ function parseFeishuTargetId(raw) {
107
+ const target = normalizeConversationText(raw);
108
+ if (!target) return;
109
+ const withoutProvider = target.replace(/^(feishu|lark):/i, "").trim();
110
+ if (!withoutProvider) return;
111
+ const lowered = withoutProvider.toLowerCase();
112
+ for (const prefix of [
113
+ "chat:",
114
+ "group:",
115
+ "channel:",
116
+ "user:",
117
+ "dm:",
118
+ "open_id:"
119
+ ]) if (lowered.startsWith(prefix)) return normalizeConversationText(withoutProvider.slice(prefix.length));
120
+ return withoutProvider;
121
+ }
122
+ function parseFeishuDirectConversationId(raw) {
123
+ const target = normalizeConversationText(raw);
124
+ if (!target) return;
125
+ const withoutProvider = target.replace(/^(feishu|lark):/i, "").trim();
126
+ if (!withoutProvider) return;
127
+ const lowered = withoutProvider.toLowerCase();
128
+ for (const prefix of [
129
+ "user:",
130
+ "dm:",
131
+ "open_id:"
132
+ ]) if (lowered.startsWith(prefix)) return normalizeConversationText(withoutProvider.slice(prefix.length));
133
+ const id = parseFeishuTargetId(target);
134
+ if (!id) return;
135
+ if (id.startsWith("ou_") || id.startsWith("on_")) return id;
136
+ }
137
+ function resolveFeishuSenderScopedConversationId(params) {
138
+ const parentConversationId = normalizeConversationText(params.parentConversationId);
139
+ const threadId = normalizeConversationText(params.threadId);
140
+ const senderId = normalizeConversationText(params.senderId);
141
+ const expectedScopePrefix = `feishu:group:${parentConversationId?.toLowerCase()}:topic:${threadId?.toLowerCase()}:sender:`;
142
+ const isSenderScopedSession = [params.sessionKey, params.parentSessionKey].some((candidate) => {
143
+ const scopedRest = parseAgentSessionKey(candidate)?.rest?.trim().toLowerCase() ?? "";
144
+ return Boolean(scopedRest && expectedScopePrefix && scopedRest.startsWith(expectedScopePrefix));
145
+ });
146
+ if (!parentConversationId || !threadId || !senderId) return;
147
+ if (!isSenderScopedSession && params.sessionKey?.trim()) {
148
+ const boundConversation = getSessionBindingService().listBySession(params.sessionKey).find((binding) => {
149
+ if (binding.conversation.channel !== "feishu" || binding.conversation.accountId !== params.accountId) return false;
150
+ return binding.conversation.conversationId === buildFeishuConversationId({
151
+ chatId: parentConversationId,
152
+ scope: "group_topic_sender",
153
+ topicId: threadId,
154
+ senderOpenId: senderId
155
+ });
156
+ });
157
+ if (boundConversation) return boundConversation.conversation.conversationId;
158
+ return;
159
+ }
160
+ return buildFeishuConversationId({
161
+ chatId: parentConversationId,
162
+ scope: "group_topic_sender",
163
+ topicId: threadId,
164
+ senderOpenId: senderId
165
+ });
166
+ }
167
+ function resolveAcpCommandChannel(params) {
168
+ return normalizeConversationText(params.ctx.OriginatingChannel ?? params.command.channel ?? params.ctx.Surface ?? params.ctx.Provider).toLowerCase();
169
+ }
170
+ function resolveAcpCommandAccountId(params) {
171
+ return normalizeConversationText(params.ctx.AccountId) || "default";
172
+ }
173
+ function resolveAcpCommandThreadId(params) {
174
+ return (params.ctx.MessageThreadId != null ? normalizeConversationText(String(params.ctx.MessageThreadId)) : "") || void 0;
175
+ }
176
+ function resolveAcpCommandConversationId(params) {
177
+ const channel = resolveAcpCommandChannel(params);
178
+ if (channel === "matrix") return resolveMatrixConversationId({
179
+ ctx: {
180
+ MessageThreadId: params.ctx.MessageThreadId,
181
+ OriginatingTo: params.ctx.OriginatingTo,
182
+ To: params.ctx.To
183
+ },
184
+ command: { to: params.command.to }
185
+ });
186
+ if (channel === "telegram") {
187
+ const telegramConversationId = resolveTelegramConversationId({
188
+ ctx: {
189
+ MessageThreadId: params.ctx.MessageThreadId,
190
+ OriginatingTo: params.ctx.OriginatingTo,
191
+ To: params.ctx.To
192
+ },
193
+ command: { to: params.command.to }
194
+ });
195
+ if (telegramConversationId) return telegramConversationId;
196
+ const threadId = resolveAcpCommandThreadId(params);
197
+ const parentConversationId = resolveAcpCommandParentConversationId(params);
198
+ if (threadId && parentConversationId) return buildTelegramTopicConversationId({
199
+ chatId: parentConversationId,
200
+ topicId: threadId
201
+ }) ?? threadId;
202
+ }
203
+ if (channel === "feishu") {
204
+ const threadId = resolveAcpCommandThreadId(params);
205
+ const parentConversationId = resolveAcpCommandParentConversationId(params);
206
+ if (threadId && parentConversationId) return resolveFeishuSenderScopedConversationId({
207
+ accountId: resolveAcpCommandAccountId(params),
208
+ parentConversationId,
209
+ threadId,
210
+ senderId: params.command.senderId ?? params.ctx.SenderId,
211
+ sessionKey: params.sessionKey,
212
+ parentSessionKey: params.ctx.ParentSessionKey
213
+ }) ?? buildFeishuConversationId({
214
+ chatId: parentConversationId,
215
+ scope: "group_topic",
216
+ topicId: threadId
217
+ });
218
+ return parseFeishuDirectConversationId(params.ctx.OriginatingTo) ?? parseFeishuDirectConversationId(params.command.to) ?? parseFeishuDirectConversationId(params.ctx.To);
219
+ }
220
+ return resolveConversationIdFromTargets({
221
+ threadId: params.ctx.MessageThreadId,
222
+ targets: [
223
+ params.ctx.OriginatingTo,
224
+ params.command.to,
225
+ params.ctx.To
226
+ ]
227
+ });
228
+ }
229
+ function parseDiscordParentChannelFromContext(raw) {
230
+ const parentId = normalizeConversationText(raw);
231
+ if (!parentId) return;
232
+ return parentId;
233
+ }
234
+ function resolveAcpCommandParentConversationId(params) {
235
+ const channel = resolveAcpCommandChannel(params);
236
+ if (channel === "matrix") return resolveMatrixParentConversationId({
237
+ ctx: {
238
+ MessageThreadId: params.ctx.MessageThreadId,
239
+ OriginatingTo: params.ctx.OriginatingTo,
240
+ To: params.ctx.To
241
+ },
242
+ command: { to: params.command.to }
243
+ });
244
+ if (channel === "telegram") return parseTelegramChatIdFromTarget(params.ctx.OriginatingTo) ?? parseTelegramChatIdFromTarget(params.command.to) ?? parseTelegramChatIdFromTarget(params.ctx.To);
245
+ if (channel === "feishu") {
246
+ if (!resolveAcpCommandThreadId(params)) return;
247
+ return parseFeishuTargetId(params.ctx.OriginatingTo) ?? parseFeishuTargetId(params.command.to) ?? parseFeishuTargetId(params.ctx.To);
248
+ }
249
+ if (channel === "discord") {
250
+ const threadId = resolveAcpCommandThreadId(params);
251
+ if (!threadId) return;
252
+ const fromContext = parseDiscordParentChannelFromContext(params.ctx.ThreadParentId);
253
+ if (fromContext && fromContext !== threadId) return fromContext;
254
+ const fromParentSession = parseDiscordParentChannelFromSessionKey(params.ctx.ParentSessionKey);
255
+ if (fromParentSession && fromParentSession !== threadId) return fromParentSession;
256
+ const fromTargets = resolveConversationIdFromTargets({ targets: [
257
+ params.ctx.OriginatingTo,
258
+ params.command.to,
259
+ params.ctx.To
260
+ ] });
261
+ if (fromTargets && fromTargets !== threadId) return fromTargets;
262
+ }
263
+ }
264
+ function resolveAcpCommandBindingContext(params) {
265
+ const parentConversationId = resolveAcpCommandParentConversationId(params);
266
+ return {
267
+ channel: resolveAcpCommandChannel(params),
268
+ accountId: resolveAcpCommandAccountId(params),
269
+ threadId: resolveAcpCommandThreadId(params),
270
+ conversationId: resolveAcpCommandConversationId(params),
271
+ ...parentConversationId ? { parentConversationId } : {}
272
+ };
273
+ }
274
+ //#endregion
275
+ //#region src/auto-reply/reply/commands-acp/install-hints.ts
276
+ function resolveConfiguredAcpBackendId(cfg) {
277
+ return cfg.acp?.backend?.trim() || "acpx";
278
+ }
279
+ function resolveAcpInstallCommandHint(cfg) {
280
+ const configured = cfg.acp?.runtime?.installCommand?.trim();
281
+ if (configured) return configured;
282
+ const backendId = resolveConfiguredAcpBackendId(cfg).toLowerCase();
283
+ if (backendId === "acpx") {
284
+ const localPath = path.resolve(process.cwd(), "extensions/acpx");
285
+ if (existsSync(localPath)) return `openclaw plugins install ${localPath}`;
286
+ return "openclaw plugins install acpx";
287
+ }
288
+ return `Install and enable the plugin that provides ACP backend "${backendId}".`;
289
+ }
290
+ const ACP_SPAWN_USAGE = "Usage: /acp spawn [harness-id] [--mode persistent|oneshot] [--thread auto|here|off] [--cwd <path>] [--label <label>].";
291
+ const ACP_STEER_USAGE = "Usage: /acp steer [--session <session-key|session-id|session-label>] <instruction>";
292
+ const ACP_SET_MODE_USAGE = "Usage: /acp set-mode <mode> [session-key|session-id|session-label]";
293
+ const ACP_SET_USAGE = "Usage: /acp set <key> <value> [session-key|session-id|session-label]";
294
+ const ACP_CWD_USAGE = "Usage: /acp cwd <path> [session-key|session-id|session-label]";
295
+ const ACP_PERMISSIONS_USAGE = "Usage: /acp permissions <profile> [session-key|session-id|session-label]";
296
+ const ACP_TIMEOUT_USAGE = "Usage: /acp timeout <seconds> [session-key|session-id|session-label]";
297
+ const ACP_MODEL_USAGE = "Usage: /acp model <model-id> [session-key|session-id|session-label]";
298
+ const ACP_RESET_OPTIONS_USAGE = "Usage: /acp reset-options [session-key|session-id|session-label]";
299
+ const ACP_STATUS_USAGE = "Usage: /acp status [session-key|session-id|session-label]";
300
+ const ACP_INSTALL_USAGE = "Usage: /acp install";
301
+ const ACP_DOCTOR_USAGE = "Usage: /acp doctor";
302
+ const ACP_SESSIONS_USAGE = "Usage: /acp sessions";
303
+ const ACP_UNICODE_DASH_PREFIX_RE = /^[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]+/;
304
+ function stopWithText$1(text) {
305
+ return {
306
+ shouldContinue: false,
307
+ reply: { text }
308
+ };
309
+ }
310
+ function resolveAcpAction(tokens) {
311
+ const action = tokens[0]?.trim().toLowerCase();
312
+ if (action === "spawn" || action === "cancel" || action === "steer" || action === "close" || action === "sessions" || action === "status" || action === "set-mode" || action === "set" || action === "cwd" || action === "permissions" || action === "timeout" || action === "model" || action === "reset-options" || action === "doctor" || action === "install" || action === "help") {
313
+ tokens.shift();
314
+ return action;
315
+ }
316
+ return "help";
317
+ }
318
+ function readOptionValue(params) {
319
+ const token = normalizeAcpOptionToken(params.tokens[params.index] ?? "");
320
+ if (token === params.flag) {
321
+ const nextValue = normalizeAcpOptionToken(params.tokens[params.index + 1] ?? "");
322
+ if (!nextValue || nextValue.startsWith("--")) return {
323
+ matched: true,
324
+ nextIndex: params.index + 1,
325
+ error: `${params.flag} requires a value`
326
+ };
327
+ return {
328
+ matched: true,
329
+ value: nextValue,
330
+ nextIndex: params.index + 2
331
+ };
332
+ }
333
+ if (token.startsWith(`${params.flag}=`)) {
334
+ const value = token.slice(`${params.flag}=`.length).trim();
335
+ if (!value) return {
336
+ matched: true,
337
+ nextIndex: params.index + 1,
338
+ error: `${params.flag} requires a value`
339
+ };
340
+ return {
341
+ matched: true,
342
+ value,
343
+ nextIndex: params.index + 1
344
+ };
345
+ }
346
+ return { matched: false };
347
+ }
348
+ function normalizeAcpOptionToken(raw) {
349
+ const token = raw.trim();
350
+ if (!token || token.startsWith("--")) return token;
351
+ const dashPrefix = token.match(ACP_UNICODE_DASH_PREFIX_RE)?.[0];
352
+ if (!dashPrefix) return token;
353
+ return `--${token.slice(dashPrefix.length)}`;
354
+ }
355
+ function resolveDefaultSpawnThreadMode(params) {
356
+ const channel = resolveAcpCommandChannel(params);
357
+ if (channel !== "discord" && channel !== "matrix") return "off";
358
+ return resolveAcpCommandThreadId(params) ? "here" : "auto";
359
+ }
360
+ function parseSpawnInput(params, tokens) {
361
+ const normalizedTokens = tokens.map((token) => normalizeAcpOptionToken(token));
362
+ let mode = "persistent";
363
+ let thread = resolveDefaultSpawnThreadMode(params);
364
+ let cwd;
365
+ let label;
366
+ let rawAgentId;
367
+ for (let i = 0; i < normalizedTokens.length;) {
368
+ const token = normalizedTokens[i] ?? "";
369
+ const modeOption = readOptionValue({
370
+ tokens: normalizedTokens,
371
+ index: i,
372
+ flag: "--mode"
373
+ });
374
+ if (modeOption.matched) {
375
+ if (modeOption.error) return {
376
+ ok: false,
377
+ error: `${modeOption.error}. ${ACP_SPAWN_USAGE}`
378
+ };
379
+ const raw = modeOption.value?.trim().toLowerCase();
380
+ if (raw !== "persistent" && raw !== "oneshot") return {
381
+ ok: false,
382
+ error: `Invalid --mode value "${modeOption.value}". Use persistent or oneshot.`
383
+ };
384
+ mode = raw;
385
+ i = modeOption.nextIndex;
386
+ continue;
387
+ }
388
+ const threadOption = readOptionValue({
389
+ tokens: normalizedTokens,
390
+ index: i,
391
+ flag: "--thread"
392
+ });
393
+ if (threadOption.matched) {
394
+ if (threadOption.error) return {
395
+ ok: false,
396
+ error: `${threadOption.error}. ${ACP_SPAWN_USAGE}`
397
+ };
398
+ const raw = threadOption.value?.trim().toLowerCase();
399
+ if (raw !== "auto" && raw !== "here" && raw !== "off") return {
400
+ ok: false,
401
+ error: `Invalid --thread value "${threadOption.value}". Use auto, here, or off.`
402
+ };
403
+ thread = raw;
404
+ i = threadOption.nextIndex;
405
+ continue;
406
+ }
407
+ const cwdOption = readOptionValue({
408
+ tokens: normalizedTokens,
409
+ index: i,
410
+ flag: "--cwd"
411
+ });
412
+ if (cwdOption.matched) {
413
+ if (cwdOption.error) return {
414
+ ok: false,
415
+ error: `${cwdOption.error}. ${ACP_SPAWN_USAGE}`
416
+ };
417
+ cwd = cwdOption.value?.trim();
418
+ i = cwdOption.nextIndex;
419
+ continue;
420
+ }
421
+ const labelOption = readOptionValue({
422
+ tokens: normalizedTokens,
423
+ index: i,
424
+ flag: "--label"
425
+ });
426
+ if (labelOption.matched) {
427
+ if (labelOption.error) return {
428
+ ok: false,
429
+ error: `${labelOption.error}. ${ACP_SPAWN_USAGE}`
430
+ };
431
+ label = labelOption.value?.trim();
432
+ i = labelOption.nextIndex;
433
+ continue;
434
+ }
435
+ if (token.startsWith("--")) return {
436
+ ok: false,
437
+ error: `Unknown option: ${token}. ${ACP_SPAWN_USAGE}`
438
+ };
439
+ if (!rawAgentId) {
440
+ rawAgentId = token.trim();
441
+ i += 1;
442
+ continue;
443
+ }
444
+ return {
445
+ ok: false,
446
+ error: `Unexpected argument: ${token}. ${ACP_SPAWN_USAGE}`
447
+ };
448
+ }
449
+ const fallbackAgent = params.cfg.acp?.defaultAgent?.trim() || "";
450
+ const selectedAgent = (rawAgentId?.trim() || fallbackAgent).trim();
451
+ if (!selectedAgent) return {
452
+ ok: false,
453
+ error: `ACP target harness id is required. Pass an ACP harness id (for example codex) or configure acp.defaultAgent. ${ACP_SPAWN_USAGE}`
454
+ };
455
+ return {
456
+ ok: true,
457
+ value: {
458
+ agentId: normalizeAgentId(selectedAgent),
459
+ mode,
460
+ thread,
461
+ cwd,
462
+ label: label || void 0
463
+ }
464
+ };
465
+ }
466
+ function parseSteerInput(tokens) {
467
+ const normalizedTokens = tokens.map((token) => normalizeAcpOptionToken(token));
468
+ let sessionToken;
469
+ const instructionTokens = [];
470
+ for (let i = 0; i < normalizedTokens.length;) {
471
+ const sessionOption = readOptionValue({
472
+ tokens: normalizedTokens,
473
+ index: i,
474
+ flag: "--session"
475
+ });
476
+ if (sessionOption.matched) {
477
+ if (sessionOption.error) return {
478
+ ok: false,
479
+ error: `${sessionOption.error}. ${ACP_STEER_USAGE}`
480
+ };
481
+ sessionToken = sessionOption.value?.trim() || void 0;
482
+ i = sessionOption.nextIndex;
483
+ continue;
484
+ }
485
+ instructionTokens.push(tokens[i] ?? "");
486
+ i += 1;
487
+ }
488
+ const instruction = instructionTokens.join(" ").trim();
489
+ if (!instruction) return {
490
+ ok: false,
491
+ error: ACP_STEER_USAGE
492
+ };
493
+ return {
494
+ ok: true,
495
+ value: {
496
+ sessionToken,
497
+ instruction
498
+ }
499
+ };
500
+ }
501
+ function parseSingleValueCommandInput(tokens, usage) {
502
+ const value = tokens[0]?.trim() || "";
503
+ if (!value) return {
504
+ ok: false,
505
+ error: usage
506
+ };
507
+ if (tokens.length > 2) return {
508
+ ok: false,
509
+ error: usage
510
+ };
511
+ return {
512
+ ok: true,
513
+ value: {
514
+ value,
515
+ sessionToken: tokens[1]?.trim() || void 0
516
+ }
517
+ };
518
+ }
519
+ function parseSetCommandInput(tokens) {
520
+ const key = tokens[0]?.trim() || "";
521
+ const value = tokens[1]?.trim() || "";
522
+ if (!key || !value) return {
523
+ ok: false,
524
+ error: ACP_SET_USAGE
525
+ };
526
+ if (tokens.length > 3) return {
527
+ ok: false,
528
+ error: ACP_SET_USAGE
529
+ };
530
+ return {
531
+ ok: true,
532
+ value: {
533
+ key,
534
+ value,
535
+ sessionToken: tokens[2]?.trim() || void 0
536
+ }
537
+ };
538
+ }
539
+ function parseOptionalSingleTarget(tokens, usage) {
540
+ if (tokens.length > 1) return {
541
+ ok: false,
542
+ error: usage
543
+ };
544
+ const token = tokens[0]?.trim() || "";
545
+ return {
546
+ ok: true,
547
+ ...token ? { sessionToken: token } : {}
548
+ };
549
+ }
550
+ function resolveAcpHelpText() {
551
+ return [
552
+ "ACP commands:",
553
+ "-----",
554
+ "/acp spawn [harness-id] [--mode persistent|oneshot] [--thread auto|here|off] [--cwd <path>] [--label <label>]",
555
+ "/acp cancel [session-key|session-id|session-label]",
556
+ "/acp steer [--session <session-key|session-id|session-label>] <instruction>",
557
+ "/acp close [session-key|session-id|session-label]",
558
+ "/acp status [session-key|session-id|session-label]",
559
+ "/acp set-mode <mode> [session-key|session-id|session-label]",
560
+ "/acp set <key> <value> [session-key|session-id|session-label]",
561
+ "/acp cwd <path> [session-key|session-id|session-label]",
562
+ "/acp permissions <profile> [session-key|session-id|session-label]",
563
+ "/acp timeout <seconds> [session-key|session-id|session-label]",
564
+ "/acp model <model-id> [session-key|session-id|session-label]",
565
+ "/acp reset-options [session-key|session-id|session-label]",
566
+ "/acp doctor",
567
+ "/acp install",
568
+ "/acp sessions",
569
+ "",
570
+ "Notes:",
571
+ "- /acp spawn harness-id is an ACP runtime harness alias (for example codex), not an OpenClaw agents.list id.",
572
+ "- /focus and /unfocus also work with ACP session keys.",
573
+ "- ACP dispatch of normal thread messages is controlled by acp.dispatch.enabled."
574
+ ].join("\n");
575
+ }
576
+ function formatRuntimeOptionsText(options) {
577
+ const extras = options.backendExtras ? Object.entries(options.backendExtras).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${key}=${value}`).join(", ") : "";
578
+ const parts = [
579
+ options.runtimeMode ? `runtimeMode=${options.runtimeMode}` : null,
580
+ options.model ? `model=${options.model}` : null,
581
+ options.cwd ? `cwd=${options.cwd}` : null,
582
+ options.permissionProfile ? `permissionProfile=${options.permissionProfile}` : null,
583
+ typeof options.timeoutSeconds === "number" ? `timeoutSeconds=${options.timeoutSeconds}` : null,
584
+ extras ? `extras={${extras}}` : null
585
+ ].filter(Boolean);
586
+ if (parts.length === 0) return "(none)";
587
+ return parts.join(", ");
588
+ }
589
+ function formatAcpCapabilitiesText(controls) {
590
+ if (controls.length === 0) return "(none)";
591
+ return controls.toSorted().join(", ");
592
+ }
593
+ function resolveCommandRequestId(params) {
594
+ const value = params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast;
595
+ if (typeof value === "string" && value.trim()) return value.trim();
596
+ if (typeof value === "number" || typeof value === "bigint") return String(value);
597
+ return randomUUID();
598
+ }
599
+ function collectAcpErrorText(params) {
600
+ return toAcpRuntimeErrorText({
601
+ error: params.error,
602
+ fallbackCode: params.fallbackCode,
603
+ fallbackMessage: params.fallbackMessage
604
+ });
605
+ }
606
+ async function withAcpCommandErrorBoundary(params) {
607
+ try {
608
+ const result = await params.run();
609
+ return params.onSuccess(result);
610
+ } catch (error) {
611
+ return stopWithText$1(collectAcpErrorText({
612
+ error,
613
+ fallbackCode: params.fallbackCode,
614
+ fallbackMessage: params.fallbackMessage
615
+ }));
616
+ }
617
+ }
618
+ //#endregion
619
+ //#region src/auto-reply/reply/channel-context.ts
620
+ function isDiscordSurface(params) {
621
+ return resolveCommandSurfaceChannel(params) === "discord";
622
+ }
623
+ function isTelegramSurface(params) {
624
+ return resolveCommandSurfaceChannel(params) === "telegram";
625
+ }
626
+ function isMatrixSurface(params) {
627
+ return resolveCommandSurfaceChannel(params) === "matrix";
628
+ }
629
+ function resolveCommandSurfaceChannel(params) {
630
+ const channel = params.ctx.OriginatingChannel ?? params.command.channel ?? params.ctx.Surface ?? params.ctx.Provider;
631
+ return String(channel ?? "").trim().toLowerCase();
632
+ }
633
+ function resolveChannelAccountId(params) {
634
+ return (typeof params.ctx.AccountId === "string" ? params.ctx.AccountId.trim() : "") || "default";
635
+ }
636
+ //#endregion
637
+ //#region src/auto-reply/reply/commands-subagents/shared.ts
638
+ const COMMAND = "/subagents";
639
+ const COMMAND_KILL = "/kill";
640
+ const COMMAND_STEER = "/steer";
641
+ const COMMAND_TELL = "/tell";
642
+ const COMMAND_FOCUS = "/focus";
643
+ const COMMAND_UNFOCUS = "/unfocus";
644
+ const COMMAND_AGENTS = "/agents";
645
+ const ACTIONS$1 = new Set([
646
+ "list",
647
+ "kill",
648
+ "log",
649
+ "send",
650
+ "steer",
651
+ "info",
652
+ "spawn",
653
+ "focus",
654
+ "unfocus",
655
+ "agents",
656
+ "help"
657
+ ]);
658
+ function resolveDisplayStatus(entry, options) {
659
+ const pendingDescendants = Math.max(0, options?.pendingDescendants ?? 0);
660
+ if (pendingDescendants > 0) return `active (waiting on ${pendingDescendants} ${pendingDescendants === 1 ? "child" : "children"})`;
661
+ const status = formatRunStatus(entry);
662
+ return status === "error" ? "failed" : status;
663
+ }
664
+ function formatTimestamp(valueMs) {
665
+ if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) return "n/a";
666
+ return new Date(valueMs).toISOString();
667
+ }
668
+ function formatTimestampWithAge(valueMs) {
669
+ if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) return "n/a";
670
+ return `${formatTimestamp(valueMs)} (${formatTimeAgo(Date.now() - valueMs, { fallback: "n/a" })})`;
671
+ }
672
+ function stopWithText(text) {
673
+ return {
674
+ shouldContinue: false,
675
+ reply: { text }
676
+ };
677
+ }
678
+ function stopWithUnknownTargetError(error) {
679
+ return stopWithText(`⚠️ ${error ?? "Unknown subagent."}`);
680
+ }
681
+ function resolveSubagentTarget(runs, token) {
682
+ return resolveSubagentTargetFromRuns({
683
+ runs,
684
+ token,
685
+ recentWindowMinutes: 30,
686
+ label: (entry) => formatRunLabel(entry),
687
+ isActive: (entry) => !entry.endedAt || Math.max(0, countPendingDescendantRuns(entry.childSessionKey)) > 0,
688
+ errors: {
689
+ missingTarget: "Missing subagent id.",
690
+ invalidIndex: (value) => `Invalid subagent index: ${value}`,
691
+ unknownSession: (value) => `Unknown subagent session: ${value}`,
692
+ ambiguousLabel: (value) => `Ambiguous subagent label: ${value}`,
693
+ ambiguousLabelPrefix: (value) => `Ambiguous subagent label prefix: ${value}`,
694
+ ambiguousRunIdPrefix: (value) => `Ambiguous run id prefix: ${value}`,
695
+ unknownTarget: (value) => `Unknown subagent id: ${value}`
696
+ }
697
+ });
698
+ }
699
+ function resolveSubagentEntryForToken(runs, token) {
700
+ const resolved = resolveSubagentTarget(runs, token);
701
+ if (!resolved.entry) return { reply: stopWithUnknownTargetError(resolved.error) };
702
+ return { entry: resolved.entry };
703
+ }
704
+ function resolveRequesterSessionKey(params, opts) {
705
+ const commandTarget = params.ctx.CommandTargetSessionKey?.trim();
706
+ const commandSession = params.sessionKey?.trim();
707
+ const raw = opts?.preferCommandTarget ?? params.ctx.CommandSource === "native" ? commandTarget || commandSession : commandSession || commandTarget;
708
+ if (!raw) return;
709
+ const { mainKey, alias } = resolveMainSessionAlias(params.cfg);
710
+ return resolveInternalSessionKey({
711
+ key: raw,
712
+ alias,
713
+ mainKey
714
+ });
715
+ }
716
+ function resolveCommandSubagentController(params, requesterKey) {
717
+ if (!isSubagentSessionKey(requesterKey)) return {
718
+ controllerSessionKey: requesterKey,
719
+ callerSessionKey: requesterKey,
720
+ callerIsSubagent: false,
721
+ controlScope: "children"
722
+ };
723
+ return {
724
+ controllerSessionKey: requesterKey,
725
+ callerSessionKey: requesterKey,
726
+ callerIsSubagent: true,
727
+ controlScope: resolveStoredSubagentCapabilities(requesterKey, { cfg: params.cfg }).controlScope
728
+ };
729
+ }
730
+ function resolveHandledPrefix(normalized) {
731
+ return normalized.startsWith("/subagents") ? COMMAND : normalized.startsWith("/kill") ? COMMAND_KILL : normalized.startsWith("/steer") ? COMMAND_STEER : normalized.startsWith("/tell") ? COMMAND_TELL : normalized.startsWith("/focus") ? COMMAND_FOCUS : normalized.startsWith("/unfocus") ? COMMAND_UNFOCUS : normalized.startsWith("/agents") ? COMMAND_AGENTS : null;
732
+ }
733
+ function resolveSubagentsAction(params) {
734
+ if (params.handledPrefix === "/subagents") {
735
+ const [actionRaw] = params.restTokens;
736
+ const action = actionRaw?.toLowerCase() || "list";
737
+ if (!ACTIONS$1.has(action)) return null;
738
+ params.restTokens.splice(0, 1);
739
+ return action;
740
+ }
741
+ if (params.handledPrefix === "/kill") return "kill";
742
+ if (params.handledPrefix === "/focus") return "focus";
743
+ if (params.handledPrefix === "/unfocus") return "unfocus";
744
+ if (params.handledPrefix === "/agents") return "agents";
745
+ return "steer";
746
+ }
747
+ function resolveDiscordChannelIdForFocus(params) {
748
+ const toCandidates = [
749
+ typeof params.ctx.OriginatingTo === "string" ? params.ctx.OriginatingTo.trim() : "",
750
+ typeof params.command.to === "string" ? params.command.to.trim() : "",
751
+ typeof params.ctx.To === "string" ? params.ctx.To.trim() : ""
752
+ ].filter(Boolean);
753
+ for (const candidate of toCandidates) {
754
+ const target = parseExplicitTargetForChannel("discord", candidate);
755
+ if (target?.chatType === "channel" && target.to) return target.to;
756
+ }
757
+ }
758
+ async function resolveFocusTargetSession(params) {
759
+ const subagentMatch = resolveSubagentTarget(params.runs, params.token);
760
+ if (subagentMatch.entry) {
761
+ const key = subagentMatch.entry.childSessionKey;
762
+ return {
763
+ targetKind: "subagent",
764
+ targetSessionKey: key,
765
+ agentId: parseAgentSessionKey(key)?.agentId ?? "main",
766
+ label: formatRunLabel(subagentMatch.entry)
767
+ };
768
+ }
769
+ const token = params.token.trim();
770
+ if (!token) return null;
771
+ const attempts = [];
772
+ attempts.push({ key: token });
773
+ if (looksLikeSessionId(token)) attempts.push({ sessionId: token });
774
+ attempts.push({ label: token });
775
+ for (const attempt of attempts) try {
776
+ const resolved = await callGateway({
777
+ method: "sessions.resolve",
778
+ params: attempt
779
+ });
780
+ const key = typeof resolved?.key === "string" ? resolved.key.trim() : "";
781
+ if (!key) continue;
782
+ const parsed = parseAgentSessionKey(key);
783
+ return {
784
+ targetKind: key.includes(":subagent:") ? "subagent" : "acp",
785
+ targetSessionKey: key,
786
+ agentId: parsed?.agentId ?? "main",
787
+ label: token
788
+ };
789
+ } catch {}
790
+ return null;
791
+ }
792
+ function buildSubagentsHelp() {
793
+ return [
794
+ "Subagents",
795
+ "Usage:",
796
+ "- /subagents list",
797
+ "- /subagents kill <id|#|all>",
798
+ "- /subagents log <id|#> [limit] [tools]",
799
+ "- /subagents info <id|#>",
800
+ "- /subagents send <id|#> <message>",
801
+ "- /subagents steer <id|#> <message>",
802
+ "- /subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]",
803
+ "- /focus <subagent-label|session-key|session-id|session-label>",
804
+ "- /unfocus",
805
+ "- /agents",
806
+ "- /session idle <duration|off>",
807
+ "- /session max-age <duration|off>",
808
+ "- /kill <id|#|all>",
809
+ "- /steer <id|#> <message>",
810
+ "- /tell <id|#> <message>",
811
+ "",
812
+ "Ids: use the list index (#), runId/session prefix, label, or full session key."
813
+ ].join("\n");
814
+ }
815
+ function extractMessageText(message) {
816
+ const role = typeof message.role === "string" ? message.role : "";
817
+ const shouldSanitize = role === "assistant";
818
+ const text = extractTextFromChatContent(message.content, { sanitizeText: shouldSanitize ? sanitizeTextContent : void 0 });
819
+ return text ? {
820
+ role,
821
+ text
822
+ } : null;
823
+ }
824
+ function formatLogLines(messages) {
825
+ const lines = [];
826
+ for (const msg of messages) {
827
+ const extracted = extractMessageText(msg);
828
+ if (!extracted) continue;
829
+ const label = extracted.role === "assistant" ? "Assistant" : "User";
830
+ lines.push(`${label}: ${extracted.text}`);
831
+ }
832
+ return lines;
833
+ }
834
+ function loadSubagentSessionEntry(params, childKey, loaders, storeCache) {
835
+ const parsed = parseAgentSessionKey(childKey);
836
+ const storePath = loaders.resolveStorePath(params.cfg.session?.store, { agentId: parsed?.agentId });
837
+ let store = storeCache?.get(storePath);
838
+ if (!store) {
839
+ store = loaders.loadSessionStore(storePath);
840
+ storeCache?.set(storePath, store);
841
+ }
842
+ return {
843
+ storePath,
844
+ store,
845
+ entry: store[childKey]
846
+ };
847
+ }
848
+ //#endregion
849
+ //#region src/auto-reply/reply/commands-acp/targets.ts
850
+ async function resolveSessionKeyByToken(token) {
851
+ const trimmed = token.trim();
852
+ if (!trimmed) return null;
853
+ const attempts = [{ key: trimmed }];
854
+ if (SESSION_ID_RE.test(trimmed)) attempts.push({ sessionId: trimmed });
855
+ attempts.push({ label: trimmed });
856
+ for (const params of attempts) try {
857
+ const resolved = await callGateway({
858
+ method: "sessions.resolve",
859
+ params,
860
+ timeoutMs: 8e3
861
+ });
862
+ const key = typeof resolved?.key === "string" ? resolved.key.trim() : "";
863
+ if (key) return key;
864
+ } catch {}
865
+ return null;
866
+ }
867
+ function resolveBoundAcpThreadSessionKey(params) {
868
+ const activeSessionKey = (typeof params.ctx.CommandTargetSessionKey === "string" ? params.ctx.CommandTargetSessionKey.trim() : "") || params.sessionKey.trim();
869
+ const bindingContext = resolveAcpCommandBindingContext(params);
870
+ return resolveEffectiveResetTargetSessionKey({
871
+ cfg: params.cfg,
872
+ channel: bindingContext.channel,
873
+ accountId: bindingContext.accountId,
874
+ conversationId: bindingContext.conversationId,
875
+ parentConversationId: bindingContext.parentConversationId,
876
+ activeSessionKey,
877
+ allowNonAcpBindingSessionKey: true,
878
+ skipConfiguredFallbackWhenActiveSessionNonAcp: false
879
+ });
880
+ }
881
+ async function resolveAcpTargetSessionKey(params) {
882
+ const token = params.token?.trim() || "";
883
+ if (token) {
884
+ const resolved = await resolveSessionKeyByToken(token);
885
+ if (!resolved) return {
886
+ ok: false,
887
+ error: `Unable to resolve session target: ${token}`
888
+ };
889
+ return {
890
+ ok: true,
891
+ sessionKey: resolved
892
+ };
893
+ }
894
+ const threadBound = resolveBoundAcpThreadSessionKey(params.commandParams);
895
+ if (threadBound) return {
896
+ ok: true,
897
+ sessionKey: threadBound
898
+ };
899
+ const fallback = resolveRequesterSessionKey(params.commandParams, { preferCommandTarget: true });
900
+ if (!fallback) return {
901
+ ok: false,
902
+ error: "Missing session key."
903
+ };
904
+ return {
905
+ ok: true,
906
+ sessionKey: fallback
907
+ };
908
+ }
909
+ //#endregion
910
+ //#region src/auto-reply/reply/commands-acp/diagnostics.ts
911
+ async function handleAcpDoctorAction(params, restTokens) {
912
+ if (restTokens.length > 0) return stopWithText$1(`⚠️ ${ACP_DOCTOR_USAGE}`);
913
+ const backendId = resolveConfiguredAcpBackendId(params.cfg);
914
+ const installHint = resolveAcpInstallCommandHint(params.cfg);
915
+ const registeredBackend = getAcpRuntimeBackend(backendId);
916
+ const managerSnapshot = getAcpSessionManager().getObservabilitySnapshot(params.cfg);
917
+ const lines = [
918
+ "ACP doctor:",
919
+ "-----",
920
+ `configuredBackend: ${backendId}`
921
+ ];
922
+ lines.push(`activeRuntimeSessions: ${managerSnapshot.runtimeCache.activeSessions}`);
923
+ lines.push(`runtimeIdleTtlMs: ${managerSnapshot.runtimeCache.idleTtlMs}`);
924
+ lines.push(`evictedIdleRuntimes: ${managerSnapshot.runtimeCache.evictedTotal}`);
925
+ lines.push(`activeTurns: ${managerSnapshot.turns.active}`);
926
+ lines.push(`queueDepth: ${managerSnapshot.turns.queueDepth}`);
927
+ lines.push(`turnLatencyMs: avg=${managerSnapshot.turns.averageLatencyMs}, max=${managerSnapshot.turns.maxLatencyMs}`);
928
+ lines.push(`turnCounts: completed=${managerSnapshot.turns.completed}, failed=${managerSnapshot.turns.failed}`);
929
+ const errorStatsText = Object.entries(managerSnapshot.errorsByCode).map(([code, count]) => `${code}=${count}`).join(", ") || "(none)";
930
+ lines.push(`errorCodes: ${errorStatsText}`);
931
+ if (registeredBackend) lines.push(`registeredBackend: ${registeredBackend.id}`);
932
+ else lines.push("registeredBackend: (none)");
933
+ if (registeredBackend?.runtime.doctor) try {
934
+ const report = await registeredBackend.runtime.doctor();
935
+ lines.push(`runtimeDoctor: ${report.ok ? "ok" : "error"} (${report.message})`);
936
+ if (report.code) lines.push(`runtimeDoctorCode: ${report.code}`);
937
+ if (report.installCommand) lines.push(`runtimeDoctorInstall: ${report.installCommand}`);
938
+ for (const detail of report.details ?? []) lines.push(`runtimeDoctorDetail: ${detail}`);
939
+ } catch (error) {
940
+ lines.push(`runtimeDoctor: error (${toAcpRuntimeError({
941
+ error,
942
+ fallbackCode: "ACP_TURN_FAILED",
943
+ fallbackMessage: "Runtime doctor failed."
944
+ }).message})`);
945
+ }
946
+ try {
947
+ const backend = requireAcpRuntimeBackend(backendId);
948
+ const capabilities = backend.runtime.getCapabilities ? await backend.runtime.getCapabilities({}) : {
949
+ controls: [],
950
+ configOptionKeys: []
951
+ };
952
+ lines.push("healthy: yes");
953
+ lines.push(`capabilities: ${formatAcpCapabilitiesText(capabilities.controls ?? [])}`);
954
+ if ((capabilities.configOptionKeys?.length ?? 0) > 0) lines.push(`configKeys: ${capabilities.configOptionKeys?.join(", ")}`);
955
+ return stopWithText$1(lines.join("\n"));
956
+ } catch (error) {
957
+ const acpError = toAcpRuntimeError({
958
+ error,
959
+ fallbackCode: "ACP_TURN_FAILED",
960
+ fallbackMessage: "ACP backend doctor failed."
961
+ });
962
+ lines.push("healthy: no");
963
+ lines.push(formatAcpRuntimeErrorText(acpError));
964
+ lines.push(`next: ${installHint}`);
965
+ lines.push(`next: openclaw config set plugins.entries.${backendId}.enabled true`);
966
+ if (backendId.toLowerCase() === "acpx") lines.push("next: verify acpx is installed (`acpx --help`).");
967
+ return stopWithText$1(lines.join("\n"));
968
+ }
969
+ }
970
+ function handleAcpInstallAction(params, restTokens) {
971
+ if (restTokens.length > 0) return stopWithText$1(`⚠️ ${ACP_INSTALL_USAGE}`);
972
+ const backendId = resolveConfiguredAcpBackendId(params.cfg);
973
+ const installHint = resolveAcpInstallCommandHint(params.cfg);
974
+ return stopWithText$1([
975
+ "ACP install:",
976
+ "-----",
977
+ `configuredBackend: ${backendId}`,
978
+ `run: ${installHint}`,
979
+ `then: openclaw config set plugins.entries.${backendId}.enabled true`,
980
+ "then: /acp doctor"
981
+ ].join("\n"));
982
+ }
983
+ function formatAcpSessionLine(params) {
984
+ const acp = params.entry.acp;
985
+ if (!acp) return "";
986
+ const marker = params.currentSessionKey === params.key ? "*" : " ";
987
+ const label = params.entry.label?.trim() || acp.agent;
988
+ const threadText = params.threadId ? `, thread:${params.threadId}` : "";
989
+ return `${marker} ${label} (${acp.mode}, ${acp.state}, backend:${acp.backend}${threadText}) -> ${params.key}`;
990
+ }
991
+ function handleAcpSessionsAction(params, restTokens) {
992
+ if (restTokens.length > 0) return stopWithText$1(ACP_SESSIONS_USAGE);
993
+ const currentSessionKey = resolveBoundAcpThreadSessionKey(params) || params.sessionKey;
994
+ if (!currentSessionKey) return stopWithText$1("⚠️ Missing session key.");
995
+ const { storePath } = resolveSessionStorePathForAcp({
996
+ cfg: params.cfg,
997
+ sessionKey: currentSessionKey
998
+ });
999
+ let store;
1000
+ try {
1001
+ store = loadSessionStore(storePath);
1002
+ } catch {
1003
+ store = {};
1004
+ }
1005
+ const bindingContext = resolveAcpCommandBindingContext(params);
1006
+ const normalizedChannel = bindingContext.channel;
1007
+ const normalizedAccountId = bindingContext.accountId || void 0;
1008
+ const bindingService = getSessionBindingService();
1009
+ const rows = Object.entries(store).filter(([, entry]) => Boolean(entry?.acp)).toSorted(([, a], [, b]) => (b?.updatedAt ?? 0) - (a?.updatedAt ?? 0)).slice(0, 20).map(([key, entry]) => {
1010
+ const bindingThreadId = bindingService.listBySession(key).find((binding) => (!normalizedChannel || binding.conversation.channel === normalizedChannel) && (!normalizedAccountId || binding.conversation.accountId === normalizedAccountId))?.conversation.conversationId;
1011
+ return formatAcpSessionLine({
1012
+ key,
1013
+ entry,
1014
+ currentSessionKey,
1015
+ threadId: bindingThreadId
1016
+ });
1017
+ }).filter(Boolean);
1018
+ if (rows.length === 0) return stopWithText$1("ACP sessions:\n-----\n(none)");
1019
+ return stopWithText$1([
1020
+ "ACP sessions:",
1021
+ "-----",
1022
+ ...rows
1023
+ ].join("\n"));
1024
+ }
1025
+ //#endregion
1026
+ //#region src/auto-reply/reply/commands-acp/lifecycle.ts
1027
+ async function bindSpawnedAcpSessionToThread(params) {
1028
+ const { commandParams, threadMode } = params;
1029
+ if (threadMode === "off") return {
1030
+ ok: false,
1031
+ error: "internal: thread binding is disabled for this spawn"
1032
+ };
1033
+ const bindingContext = resolveAcpCommandBindingContext(commandParams);
1034
+ const channel = bindingContext.channel;
1035
+ if (!channel) return {
1036
+ ok: false,
1037
+ error: "ACP thread binding requires a channel context."
1038
+ };
1039
+ const accountId = resolveAcpCommandAccountId(commandParams);
1040
+ const spawnPolicy = resolveThreadBindingSpawnPolicy({
1041
+ cfg: commandParams.cfg,
1042
+ channel,
1043
+ accountId,
1044
+ kind: "acp"
1045
+ });
1046
+ if (!spawnPolicy.enabled) return {
1047
+ ok: false,
1048
+ error: formatThreadBindingDisabledError({
1049
+ channel: spawnPolicy.channel,
1050
+ accountId: spawnPolicy.accountId,
1051
+ kind: "acp"
1052
+ })
1053
+ };
1054
+ if (!spawnPolicy.spawnEnabled) return {
1055
+ ok: false,
1056
+ error: formatThreadBindingSpawnDisabledError({
1057
+ channel: spawnPolicy.channel,
1058
+ accountId: spawnPolicy.accountId,
1059
+ kind: "acp"
1060
+ })
1061
+ };
1062
+ const bindingService = getSessionBindingService();
1063
+ const capabilities = bindingService.getCapabilities({
1064
+ channel: spawnPolicy.channel,
1065
+ accountId: spawnPolicy.accountId
1066
+ });
1067
+ if (!capabilities.adapterAvailable) return {
1068
+ ok: false,
1069
+ error: `Thread bindings are unavailable for ${channel}.`
1070
+ };
1071
+ if (!capabilities.bindSupported) return {
1072
+ ok: false,
1073
+ error: `Thread bindings are unavailable for ${channel}.`
1074
+ };
1075
+ const currentThreadId = bindingContext.threadId ?? "";
1076
+ const currentConversationId = bindingContext.conversationId?.trim() || "";
1077
+ const requiresThreadIdForHere = channel !== "telegram" && channel !== "feishu";
1078
+ if (threadMode === "here" && (requiresThreadIdForHere && !currentThreadId || !requiresThreadIdForHere && !currentConversationId)) return {
1079
+ ok: false,
1080
+ error: `--thread here requires running /acp spawn inside an active ${channel} thread/conversation.`
1081
+ };
1082
+ const placement = channel === "telegram" || channel === "feishu" ? "current" : currentThreadId ? "current" : "child";
1083
+ if (!capabilities.placements.includes(placement)) return {
1084
+ ok: false,
1085
+ error: `Thread bindings do not support ${placement} placement for ${channel}.`
1086
+ };
1087
+ if (!currentConversationId) return {
1088
+ ok: false,
1089
+ error: `Could not resolve a ${channel} conversation for ACP thread spawn.`
1090
+ };
1091
+ const senderId = commandParams.command.senderId?.trim() || "";
1092
+ const parentConversationId = bindingContext.parentConversationId?.trim() || void 0;
1093
+ const conversationRef = {
1094
+ channel: spawnPolicy.channel,
1095
+ accountId: spawnPolicy.accountId,
1096
+ conversationId: currentConversationId,
1097
+ ...parentConversationId && parentConversationId !== currentConversationId ? { parentConversationId } : {}
1098
+ };
1099
+ if (placement === "current") {
1100
+ const existingBinding = bindingService.resolveByConversation(conversationRef);
1101
+ const boundBy = typeof existingBinding?.metadata?.boundBy === "string" ? existingBinding.metadata.boundBy.trim() : "";
1102
+ if (existingBinding && boundBy && boundBy !== "system" && senderId && senderId !== boundBy) return {
1103
+ ok: false,
1104
+ error: `Only ${boundBy} can rebind this ${channel === "telegram" ? "conversation" : "thread"}.`
1105
+ };
1106
+ }
1107
+ const label = params.label || params.agentId;
1108
+ try {
1109
+ return {
1110
+ ok: true,
1111
+ binding: await bindingService.bind({
1112
+ targetSessionKey: params.sessionKey,
1113
+ targetKind: "session",
1114
+ conversation: conversationRef,
1115
+ placement,
1116
+ metadata: {
1117
+ threadName: resolveThreadBindingThreadName({
1118
+ agentId: params.agentId,
1119
+ label
1120
+ }),
1121
+ agentId: params.agentId,
1122
+ label,
1123
+ boundBy: senderId || "unknown",
1124
+ introText: resolveThreadBindingIntroText({
1125
+ agentId: params.agentId,
1126
+ label,
1127
+ idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({
1128
+ cfg: commandParams.cfg,
1129
+ channel: spawnPolicy.channel,
1130
+ accountId: spawnPolicy.accountId
1131
+ }),
1132
+ maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({
1133
+ cfg: commandParams.cfg,
1134
+ channel: spawnPolicy.channel,
1135
+ accountId: spawnPolicy.accountId
1136
+ }),
1137
+ sessionCwd: resolveAcpSessionCwd(params.sessionMeta),
1138
+ sessionDetails: resolveAcpThreadSessionDetailLines({
1139
+ sessionKey: params.sessionKey,
1140
+ meta: params.sessionMeta
1141
+ })
1142
+ })
1143
+ }
1144
+ })
1145
+ };
1146
+ } catch (error) {
1147
+ return {
1148
+ ok: false,
1149
+ error: (error instanceof Error ? error.message : String(error)) || `Failed to bind a ${channel} thread/conversation to the new ACP session.`
1150
+ };
1151
+ }
1152
+ }
1153
+ async function cleanupFailedSpawn(params) {
1154
+ await cleanupFailedAcpSpawn({
1155
+ cfg: params.cfg,
1156
+ sessionKey: params.sessionKey,
1157
+ shouldDeleteSession: params.shouldDeleteSession,
1158
+ deleteTranscript: false,
1159
+ runtimeCloseHandle: params.initializedRuntime
1160
+ });
1161
+ }
1162
+ async function handleAcpSpawnAction(params, restTokens) {
1163
+ if (!isAcpEnabledByPolicy(params.cfg)) return stopWithText$1("ACP is disabled by policy (`acp.enabled=false`).");
1164
+ const parsed = parseSpawnInput(params, restTokens);
1165
+ if (!parsed.ok) return stopWithText$1(`⚠️ ${parsed.error}`);
1166
+ const spawn = parsed.value;
1167
+ const runtimePolicyError = resolveAcpSpawnRuntimePolicyError({
1168
+ cfg: params.cfg,
1169
+ requesterSessionKey: params.sessionKey
1170
+ });
1171
+ if (runtimePolicyError) return stopWithText$1(`⚠️ ${runtimePolicyError}`);
1172
+ const agentPolicyError = resolveAcpAgentPolicyError(params.cfg, spawn.agentId);
1173
+ if (agentPolicyError) return stopWithText$1(collectAcpErrorText({
1174
+ error: agentPolicyError,
1175
+ fallbackCode: "ACP_SESSION_INIT_FAILED",
1176
+ fallbackMessage: "ACP target agent is not allowed by policy."
1177
+ }));
1178
+ const acpManager = getAcpSessionManager();
1179
+ const sessionKey = `agent:${spawn.agentId}:acp:${randomUUID()}`;
1180
+ let initializedBackend = "";
1181
+ let initializedMeta;
1182
+ let initializedRuntime;
1183
+ try {
1184
+ const initialized = await acpManager.initializeSession({
1185
+ cfg: params.cfg,
1186
+ sessionKey,
1187
+ agent: spawn.agentId,
1188
+ mode: spawn.mode,
1189
+ cwd: spawn.cwd
1190
+ });
1191
+ initializedRuntime = {
1192
+ runtime: initialized.runtime,
1193
+ handle: initialized.handle
1194
+ };
1195
+ initializedBackend = initialized.handle.backend || initialized.meta.backend;
1196
+ initializedMeta = initialized.meta;
1197
+ } catch (err) {
1198
+ return stopWithText$1(collectAcpErrorText({
1199
+ error: err,
1200
+ fallbackCode: "ACP_SESSION_INIT_FAILED",
1201
+ fallbackMessage: "Could not initialize ACP session runtime."
1202
+ }));
1203
+ }
1204
+ let binding = null;
1205
+ if (spawn.thread !== "off") {
1206
+ const bound = await bindSpawnedAcpSessionToThread({
1207
+ commandParams: params,
1208
+ sessionKey,
1209
+ agentId: spawn.agentId,
1210
+ label: spawn.label,
1211
+ threadMode: spawn.thread,
1212
+ sessionMeta: initializedMeta
1213
+ });
1214
+ if (!bound.ok) {
1215
+ await cleanupFailedSpawn({
1216
+ cfg: params.cfg,
1217
+ sessionKey,
1218
+ shouldDeleteSession: true,
1219
+ initializedRuntime
1220
+ });
1221
+ return stopWithText$1(`⚠️ ${bound.error}`);
1222
+ }
1223
+ binding = bound.binding;
1224
+ }
1225
+ try {
1226
+ await callGateway({
1227
+ method: "sessions.patch",
1228
+ params: {
1229
+ key: sessionKey,
1230
+ ...spawn.label ? { label: spawn.label } : {}
1231
+ },
1232
+ timeoutMs: 1e4
1233
+ });
1234
+ } catch (err) {
1235
+ await cleanupFailedSpawn({
1236
+ cfg: params.cfg,
1237
+ sessionKey,
1238
+ shouldDeleteSession: true,
1239
+ initializedRuntime
1240
+ });
1241
+ return stopWithText$1(`⚠️ ACP spawn failed: ${err instanceof Error ? err.message : String(err)}`);
1242
+ }
1243
+ const parts = [`✅ Spawned ACP session ${sessionKey} (${spawn.mode}, backend ${initializedBackend}).`];
1244
+ if (binding) {
1245
+ const currentConversationId = resolveAcpCommandConversationId(params)?.trim() || "";
1246
+ const boundConversationId = binding.conversation.conversationId.trim();
1247
+ const placementLabel = binding.conversation.channel === "telegram" ? "conversation" : "thread";
1248
+ if (currentConversationId && boundConversationId === currentConversationId) parts.push(`Bound this ${placementLabel} to ${sessionKey}.`);
1249
+ else parts.push(`Created ${placementLabel} ${boundConversationId} and bound it to ${sessionKey}.`);
1250
+ } else parts.push("Session is unbound (use /focus <session-key> to bind this thread/conversation).");
1251
+ const dispatchNote = resolveAcpDispatchPolicyMessage(params.cfg);
1252
+ if (dispatchNote) parts.push(`ℹ️ ${dispatchNote}`);
1253
+ if (binding?.conversation.channel === "telegram" && binding.conversation.conversationId.includes(":topic:")) return {
1254
+ shouldContinue: false,
1255
+ reply: {
1256
+ text: parts.join(" "),
1257
+ channelData: { telegram: { pin: true } }
1258
+ }
1259
+ };
1260
+ return stopWithText$1(parts.join(" "));
1261
+ }
1262
+ function resolveAcpSessionForCommandOrStop(params) {
1263
+ const error = resolveAcpSessionResolutionError(params.acpManager.resolveSession({
1264
+ cfg: params.cfg,
1265
+ sessionKey: params.sessionKey
1266
+ }));
1267
+ if (error) return stopWithText$1(collectAcpErrorText({
1268
+ error,
1269
+ fallbackCode: "ACP_SESSION_INIT_FAILED",
1270
+ fallbackMessage: error.message
1271
+ }));
1272
+ return null;
1273
+ }
1274
+ async function resolveAcpTokenTargetSessionKeyOrStop(params) {
1275
+ const token = params.restTokens.join(" ").trim() || void 0;
1276
+ const target = await resolveAcpTargetSessionKey({
1277
+ commandParams: params.commandParams,
1278
+ token
1279
+ });
1280
+ if (!target.ok) return stopWithText$1(`⚠️ ${target.error}`);
1281
+ return target.sessionKey;
1282
+ }
1283
+ async function withResolvedAcpSessionTarget(params) {
1284
+ const acpManager = getAcpSessionManager();
1285
+ const targetSessionKey = await resolveAcpTokenTargetSessionKeyOrStop({
1286
+ commandParams: params.commandParams,
1287
+ restTokens: params.restTokens
1288
+ });
1289
+ if (typeof targetSessionKey !== "string") return targetSessionKey;
1290
+ const guardFailure = resolveAcpSessionForCommandOrStop({
1291
+ acpManager,
1292
+ cfg: params.commandParams.cfg,
1293
+ sessionKey: targetSessionKey
1294
+ });
1295
+ if (guardFailure) return guardFailure;
1296
+ return await params.run({
1297
+ acpManager,
1298
+ sessionKey: targetSessionKey
1299
+ });
1300
+ }
1301
+ async function handleAcpCancelAction(params, restTokens) {
1302
+ return await withResolvedAcpSessionTarget({
1303
+ commandParams: params,
1304
+ restTokens,
1305
+ run: async ({ acpManager, sessionKey }) => await withAcpCommandErrorBoundary({
1306
+ run: async () => await acpManager.cancelSession({
1307
+ cfg: params.cfg,
1308
+ sessionKey,
1309
+ reason: "manual-cancel"
1310
+ }),
1311
+ fallbackCode: "ACP_TURN_FAILED",
1312
+ fallbackMessage: "ACP cancel failed before completion.",
1313
+ onSuccess: () => stopWithText$1(`✅ Cancel requested for ACP session ${sessionKey}.`)
1314
+ })
1315
+ });
1316
+ }
1317
+ async function runAcpSteer(params) {
1318
+ const acpManager = getAcpSessionManager();
1319
+ let output = "";
1320
+ await acpManager.runTurn({
1321
+ cfg: params.cfg,
1322
+ sessionKey: params.sessionKey,
1323
+ text: params.instruction,
1324
+ mode: "steer",
1325
+ requestId: params.requestId,
1326
+ onEvent: (event) => {
1327
+ if (event.type !== "text_delta") return;
1328
+ if (event.stream && event.stream !== "output") return;
1329
+ if (event.text) {
1330
+ output += event.text;
1331
+ if (output.length > 800) output = `${output.slice(0, 800)}…`;
1332
+ }
1333
+ }
1334
+ });
1335
+ return output.trim();
1336
+ }
1337
+ async function handleAcpSteerAction(params, restTokens) {
1338
+ const dispatchPolicyError = resolveAcpDispatchPolicyError(params.cfg);
1339
+ if (dispatchPolicyError) return stopWithText$1(collectAcpErrorText({
1340
+ error: dispatchPolicyError,
1341
+ fallbackCode: "ACP_DISPATCH_DISABLED",
1342
+ fallbackMessage: dispatchPolicyError.message
1343
+ }));
1344
+ const parsed = parseSteerInput(restTokens);
1345
+ if (!parsed.ok) return stopWithText$1(`⚠️ ${parsed.error}`);
1346
+ const acpManager = getAcpSessionManager();
1347
+ const target = await resolveAcpTargetSessionKey({
1348
+ commandParams: params,
1349
+ token: parsed.value.sessionToken
1350
+ });
1351
+ if (!target.ok) return stopWithText$1(`⚠️ ${target.error}`);
1352
+ const guardFailure = resolveAcpSessionForCommandOrStop({
1353
+ acpManager,
1354
+ cfg: params.cfg,
1355
+ sessionKey: target.sessionKey
1356
+ });
1357
+ if (guardFailure) return guardFailure;
1358
+ return await withAcpCommandErrorBoundary({
1359
+ run: async () => await runAcpSteer({
1360
+ cfg: params.cfg,
1361
+ sessionKey: target.sessionKey,
1362
+ instruction: parsed.value.instruction,
1363
+ requestId: `${resolveCommandRequestId(params)}:steer`
1364
+ }),
1365
+ fallbackCode: "ACP_TURN_FAILED",
1366
+ fallbackMessage: "ACP steer failed before completion.",
1367
+ onSuccess: (steerOutput) => {
1368
+ if (!steerOutput) return stopWithText$1(`✅ ACP steer sent to ${target.sessionKey}.`);
1369
+ return stopWithText$1(`✅ ACP steer sent to ${target.sessionKey}.\n${steerOutput}`);
1370
+ }
1371
+ });
1372
+ }
1373
+ async function handleAcpCloseAction(params, restTokens) {
1374
+ return await withResolvedAcpSessionTarget({
1375
+ commandParams: params,
1376
+ restTokens,
1377
+ run: async ({ acpManager, sessionKey }) => {
1378
+ let runtimeNotice = "";
1379
+ try {
1380
+ const closed = await acpManager.closeSession({
1381
+ cfg: params.cfg,
1382
+ sessionKey,
1383
+ reason: "manual-close",
1384
+ allowBackendUnavailable: true,
1385
+ clearMeta: true
1386
+ });
1387
+ runtimeNotice = closed.runtimeNotice ? ` (${closed.runtimeNotice})` : "";
1388
+ } catch (error) {
1389
+ return stopWithText$1(collectAcpErrorText({
1390
+ error,
1391
+ fallbackCode: "ACP_TURN_FAILED",
1392
+ fallbackMessage: "ACP close failed before completion."
1393
+ }));
1394
+ }
1395
+ const removedBindings = await getSessionBindingService().unbind({
1396
+ targetSessionKey: sessionKey,
1397
+ reason: "manual"
1398
+ });
1399
+ return stopWithText$1(`✅ Closed ACP session ${sessionKey}${runtimeNotice}. Removed ${removedBindings.length} binding${removedBindings.length === 1 ? "" : "s"}.`);
1400
+ }
1401
+ });
1402
+ }
1403
+ //#endregion
1404
+ //#region src/auto-reply/reply/commands-acp/runtime-options.ts
1405
+ async function resolveTargetSessionKeyOrStop(params) {
1406
+ const target = await resolveAcpTargetSessionKey({
1407
+ commandParams: params.commandParams,
1408
+ token: params.token
1409
+ });
1410
+ if (!target.ok) return stopWithText$1(`⚠️ ${target.error}`);
1411
+ return target.sessionKey;
1412
+ }
1413
+ async function resolveOptionalSingleTargetOrStop(params) {
1414
+ const parsed = parseOptionalSingleTarget(params.restTokens, params.usage);
1415
+ if (!parsed.ok) return stopWithText$1(`⚠️ ${parsed.error}`);
1416
+ return await resolveTargetSessionKeyOrStop({
1417
+ commandParams: params.commandParams,
1418
+ token: parsed.sessionToken
1419
+ });
1420
+ }
1421
+ async function resolveSingleTargetValueOrStop(params) {
1422
+ const parsed = parseSingleValueCommandInput(params.restTokens, params.usage);
1423
+ if (!parsed.ok) return stopWithText$1(`⚠️ ${parsed.error}`);
1424
+ const targetSessionKey = await resolveTargetSessionKeyOrStop({
1425
+ commandParams: params.commandParams,
1426
+ token: parsed.value.sessionToken
1427
+ });
1428
+ if (typeof targetSessionKey !== "string") return targetSessionKey;
1429
+ return {
1430
+ targetSessionKey,
1431
+ value: parsed.value.value
1432
+ };
1433
+ }
1434
+ async function withSingleTargetValue(params) {
1435
+ const resolved = await resolveSingleTargetValueOrStop({
1436
+ commandParams: params.commandParams,
1437
+ restTokens: params.restTokens,
1438
+ usage: params.usage
1439
+ });
1440
+ if (!("targetSessionKey" in resolved)) return resolved;
1441
+ return await params.run(resolved);
1442
+ }
1443
+ async function handleAcpStatusAction(params, restTokens) {
1444
+ const targetSessionKey = await resolveOptionalSingleTargetOrStop({
1445
+ commandParams: params,
1446
+ restTokens,
1447
+ usage: ACP_STATUS_USAGE
1448
+ });
1449
+ if (typeof targetSessionKey !== "string") return targetSessionKey;
1450
+ return await withAcpCommandErrorBoundary({
1451
+ run: async () => await getAcpSessionManager().getSessionStatus({
1452
+ cfg: params.cfg,
1453
+ sessionKey: targetSessionKey
1454
+ }),
1455
+ fallbackCode: "ACP_TURN_FAILED",
1456
+ fallbackMessage: "Could not read ACP session status.",
1457
+ onSuccess: (status) => {
1458
+ const sessionIdentifierLines = resolveAcpSessionIdentifierLinesFromIdentity({
1459
+ backend: status.backend,
1460
+ identity: status.identity
1461
+ });
1462
+ return stopWithText$1([
1463
+ "ACP status:",
1464
+ "-----",
1465
+ `session: ${status.sessionKey}`,
1466
+ `backend: ${status.backend}`,
1467
+ `agent: ${status.agent}`,
1468
+ ...sessionIdentifierLines,
1469
+ `sessionMode: ${status.mode}`,
1470
+ `state: ${status.state}`,
1471
+ `runtimeOptions: ${formatRuntimeOptionsText(status.runtimeOptions)}`,
1472
+ `capabilities: ${formatAcpCapabilitiesText(status.capabilities.controls)}`,
1473
+ `lastActivityAt: ${new Date(status.lastActivityAt).toISOString()}`,
1474
+ ...status.lastError ? [`lastError: ${status.lastError}`] : [],
1475
+ ...status.runtimeStatus?.summary ? [`runtime: ${status.runtimeStatus.summary}`] : [],
1476
+ ...status.runtimeStatus?.details ? [`runtimeDetails: ${JSON.stringify(status.runtimeStatus.details)}`] : []
1477
+ ].join("\n"));
1478
+ }
1479
+ });
1480
+ }
1481
+ async function handleAcpSetModeAction(params, restTokens) {
1482
+ return await withSingleTargetValue({
1483
+ commandParams: params,
1484
+ restTokens,
1485
+ usage: ACP_SET_MODE_USAGE,
1486
+ run: async ({ targetSessionKey, value }) => await withAcpCommandErrorBoundary({
1487
+ run: async () => {
1488
+ const runtimeMode = validateRuntimeModeInput(value);
1489
+ return {
1490
+ runtimeMode,
1491
+ options: await getAcpSessionManager().setSessionRuntimeMode({
1492
+ cfg: params.cfg,
1493
+ sessionKey: targetSessionKey,
1494
+ runtimeMode
1495
+ })
1496
+ };
1497
+ },
1498
+ fallbackCode: "ACP_TURN_FAILED",
1499
+ fallbackMessage: "Could not update ACP runtime mode.",
1500
+ onSuccess: ({ runtimeMode, options }) => stopWithText$1(`✅ Updated ACP runtime mode for ${targetSessionKey}: ${runtimeMode}. Effective options: ${formatRuntimeOptionsText(options)}`)
1501
+ })
1502
+ });
1503
+ }
1504
+ async function handleAcpSetAction(params, restTokens) {
1505
+ const parsed = parseSetCommandInput(restTokens);
1506
+ if (!parsed.ok) return stopWithText$1(`⚠️ ${parsed.error}`);
1507
+ const target = await resolveAcpTargetSessionKey({
1508
+ commandParams: params,
1509
+ token: parsed.value.sessionToken
1510
+ });
1511
+ if (!target.ok) return stopWithText$1(`⚠️ ${target.error}`);
1512
+ const key = parsed.value.key.trim();
1513
+ const value = parsed.value.value.trim();
1514
+ return await withAcpCommandErrorBoundary({
1515
+ run: async () => {
1516
+ if (key.toLowerCase() === "cwd") {
1517
+ const cwd = validateRuntimeCwdInput(value);
1518
+ const options = await getAcpSessionManager().updateSessionRuntimeOptions({
1519
+ cfg: params.cfg,
1520
+ sessionKey: target.sessionKey,
1521
+ patch: { cwd }
1522
+ });
1523
+ return { text: `✅ Updated ACP cwd for ${target.sessionKey}: ${cwd}. Effective options: ${formatRuntimeOptionsText(options)}` };
1524
+ }
1525
+ const validated = validateRuntimeConfigOptionInput(key, value);
1526
+ const options = await getAcpSessionManager().setSessionConfigOption({
1527
+ cfg: params.cfg,
1528
+ sessionKey: target.sessionKey,
1529
+ key: validated.key,
1530
+ value: validated.value
1531
+ });
1532
+ return { text: `✅ Updated ACP config option for ${target.sessionKey}: ${validated.key}=${validated.value}. Effective options: ${formatRuntimeOptionsText(options)}` };
1533
+ },
1534
+ fallbackCode: "ACP_TURN_FAILED",
1535
+ fallbackMessage: "Could not update ACP config option.",
1536
+ onSuccess: ({ text }) => stopWithText$1(text)
1537
+ });
1538
+ }
1539
+ async function handleAcpCwdAction(params, restTokens) {
1540
+ return await withSingleTargetValue({
1541
+ commandParams: params,
1542
+ restTokens,
1543
+ usage: ACP_CWD_USAGE,
1544
+ run: async ({ targetSessionKey, value }) => await withAcpCommandErrorBoundary({
1545
+ run: async () => {
1546
+ const cwd = validateRuntimeCwdInput(value);
1547
+ return {
1548
+ cwd,
1549
+ options: await getAcpSessionManager().updateSessionRuntimeOptions({
1550
+ cfg: params.cfg,
1551
+ sessionKey: targetSessionKey,
1552
+ patch: { cwd }
1553
+ })
1554
+ };
1555
+ },
1556
+ fallbackCode: "ACP_TURN_FAILED",
1557
+ fallbackMessage: "Could not update ACP cwd.",
1558
+ onSuccess: ({ cwd, options }) => stopWithText$1(`✅ Updated ACP cwd for ${targetSessionKey}: ${cwd}. Effective options: ${formatRuntimeOptionsText(options)}`)
1559
+ })
1560
+ });
1561
+ }
1562
+ async function handleAcpPermissionsAction(params, restTokens) {
1563
+ return await withSingleTargetValue({
1564
+ commandParams: params,
1565
+ restTokens,
1566
+ usage: ACP_PERMISSIONS_USAGE,
1567
+ run: async ({ targetSessionKey, value }) => await withAcpCommandErrorBoundary({
1568
+ run: async () => {
1569
+ const permissionProfile = validateRuntimePermissionProfileInput(value);
1570
+ return {
1571
+ permissionProfile,
1572
+ options: await getAcpSessionManager().setSessionConfigOption({
1573
+ cfg: params.cfg,
1574
+ sessionKey: targetSessionKey,
1575
+ key: "approval_policy",
1576
+ value: permissionProfile
1577
+ })
1578
+ };
1579
+ },
1580
+ fallbackCode: "ACP_TURN_FAILED",
1581
+ fallbackMessage: "Could not update ACP permissions profile.",
1582
+ onSuccess: ({ permissionProfile, options }) => stopWithText$1(`✅ Updated ACP permissions profile for ${targetSessionKey}: ${permissionProfile}. Effective options: ${formatRuntimeOptionsText(options)}`)
1583
+ })
1584
+ });
1585
+ }
1586
+ async function handleAcpTimeoutAction(params, restTokens) {
1587
+ return await withSingleTargetValue({
1588
+ commandParams: params,
1589
+ restTokens,
1590
+ usage: ACP_TIMEOUT_USAGE,
1591
+ run: async ({ targetSessionKey, value }) => await withAcpCommandErrorBoundary({
1592
+ run: async () => {
1593
+ const timeoutSeconds = parseRuntimeTimeoutSecondsInput(value);
1594
+ return {
1595
+ timeoutSeconds,
1596
+ options: await getAcpSessionManager().setSessionConfigOption({
1597
+ cfg: params.cfg,
1598
+ sessionKey: targetSessionKey,
1599
+ key: "timeout",
1600
+ value: String(timeoutSeconds)
1601
+ })
1602
+ };
1603
+ },
1604
+ fallbackCode: "ACP_TURN_FAILED",
1605
+ fallbackMessage: "Could not update ACP timeout.",
1606
+ onSuccess: ({ timeoutSeconds, options }) => stopWithText$1(`✅ Updated ACP timeout for ${targetSessionKey}: ${timeoutSeconds}s. Effective options: ${formatRuntimeOptionsText(options)}`)
1607
+ })
1608
+ });
1609
+ }
1610
+ async function handleAcpModelAction(params, restTokens) {
1611
+ return await withSingleTargetValue({
1612
+ commandParams: params,
1613
+ restTokens,
1614
+ usage: ACP_MODEL_USAGE,
1615
+ run: async ({ targetSessionKey, value }) => await withAcpCommandErrorBoundary({
1616
+ run: async () => {
1617
+ const model = validateRuntimeModelInput(value);
1618
+ return {
1619
+ model,
1620
+ options: await getAcpSessionManager().setSessionConfigOption({
1621
+ cfg: params.cfg,
1622
+ sessionKey: targetSessionKey,
1623
+ key: "model",
1624
+ value: model
1625
+ })
1626
+ };
1627
+ },
1628
+ fallbackCode: "ACP_TURN_FAILED",
1629
+ fallbackMessage: "Could not update ACP model.",
1630
+ onSuccess: ({ model, options }) => stopWithText$1(`✅ Updated ACP model for ${targetSessionKey}: ${model}. Effective options: ${formatRuntimeOptionsText(options)}`)
1631
+ })
1632
+ });
1633
+ }
1634
+ async function handleAcpResetOptionsAction(params, restTokens) {
1635
+ const targetSessionKey = await resolveOptionalSingleTargetOrStop({
1636
+ commandParams: params,
1637
+ restTokens,
1638
+ usage: ACP_RESET_OPTIONS_USAGE
1639
+ });
1640
+ if (typeof targetSessionKey !== "string") return targetSessionKey;
1641
+ return await withAcpCommandErrorBoundary({
1642
+ run: async () => await getAcpSessionManager().resetSessionRuntimeOptions({
1643
+ cfg: params.cfg,
1644
+ sessionKey: targetSessionKey
1645
+ }),
1646
+ fallbackCode: "ACP_TURN_FAILED",
1647
+ fallbackMessage: "Could not reset ACP runtime options.",
1648
+ onSuccess: () => stopWithText$1(`✅ Reset ACP runtime options for ${targetSessionKey}.`)
1649
+ });
1650
+ }
1651
+ //#endregion
1652
+ //#region src/auto-reply/reply/commands-acp.ts
1653
+ const ACP_ACTION_HANDLERS = {
1654
+ spawn: handleAcpSpawnAction,
1655
+ cancel: handleAcpCancelAction,
1656
+ steer: handleAcpSteerAction,
1657
+ close: handleAcpCloseAction,
1658
+ status: handleAcpStatusAction,
1659
+ "set-mode": handleAcpSetModeAction,
1660
+ set: handleAcpSetAction,
1661
+ cwd: handleAcpCwdAction,
1662
+ permissions: handleAcpPermissionsAction,
1663
+ timeout: handleAcpTimeoutAction,
1664
+ model: handleAcpModelAction,
1665
+ "reset-options": handleAcpResetOptionsAction,
1666
+ doctor: handleAcpDoctorAction,
1667
+ install: async (params, tokens) => handleAcpInstallAction(params, tokens),
1668
+ sessions: async (params, tokens) => handleAcpSessionsAction(params, tokens)
1669
+ };
1670
+ const ACP_MUTATING_ACTIONS = new Set([
1671
+ "spawn",
1672
+ "cancel",
1673
+ "steer",
1674
+ "close",
1675
+ "status",
1676
+ "set-mode",
1677
+ "set",
1678
+ "cwd",
1679
+ "permissions",
1680
+ "timeout",
1681
+ "model",
1682
+ "reset-options"
1683
+ ]);
1684
+ const handleAcpCommand = async (params, allowTextCommands) => {
1685
+ if (!allowTextCommands) return null;
1686
+ const normalized = params.command.commandBodyNormalized;
1687
+ if (!normalized.startsWith("/acp")) return null;
1688
+ if (!params.command.isAuthorizedSender) {
1689
+ logVerbose(`Ignoring /acp from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
1690
+ return { shouldContinue: false };
1691
+ }
1692
+ const tokens = normalized.slice(4).trim().split(/\s+/).filter(Boolean);
1693
+ const action = resolveAcpAction(tokens);
1694
+ if (action === "help") return stopWithText$1(resolveAcpHelpText());
1695
+ if (ACP_MUTATING_ACTIONS.has(action)) {
1696
+ const scopeBlock = requireGatewayClientScopeForInternalChannel(params, {
1697
+ label: "/acp",
1698
+ allowedScopes: ["operator.admin"],
1699
+ missingText: "This /acp action requires operator.admin on the internal channel."
1700
+ });
1701
+ if (scopeBlock) return scopeBlock;
1702
+ }
1703
+ const handler = ACP_ACTION_HANDLERS[action];
1704
+ return handler ? await handler(params, tokens) : stopWithText$1(resolveAcpHelpText());
1705
+ };
1706
+ //#endregion
1707
+ //#region src/auto-reply/reply/config-write-authorization.ts
1708
+ function resolveConfigWriteDeniedText(params) {
1709
+ const writeAuth = authorizeConfigWrite({
1710
+ cfg: params.cfg,
1711
+ origin: {
1712
+ channelId: params.channelId,
1713
+ accountId: params.accountId
1714
+ },
1715
+ target: params.target,
1716
+ allowBypass: canBypassConfigWritePolicy({
1717
+ channel: params.channel ?? "",
1718
+ gatewayClientScopes: params.gatewayClientScopes
1719
+ })
1720
+ });
1721
+ if (writeAuth.allowed) return null;
1722
+ return formatConfigWriteDeniedMessage({
1723
+ result: writeAuth,
1724
+ fallbackChannelId: params.channelId
1725
+ });
1726
+ }
1727
+ //#endregion
1728
+ //#region src/auto-reply/reply/commands-allowlist.ts
1729
+ const ACTIONS = new Set([
1730
+ "list",
1731
+ "add",
1732
+ "remove"
1733
+ ]);
1734
+ const SCOPES = new Set([
1735
+ "dm",
1736
+ "group",
1737
+ "all"
1738
+ ]);
1739
+ function parseAllowlistCommand(raw) {
1740
+ const trimmed = raw.trim();
1741
+ if (!trimmed.toLowerCase().startsWith("/allowlist")) return null;
1742
+ const rest = trimmed.slice(10).trim();
1743
+ if (!rest) return {
1744
+ action: "list",
1745
+ scope: "dm"
1746
+ };
1747
+ const tokens = rest.split(/\s+/);
1748
+ let action = "list";
1749
+ let scope = "dm";
1750
+ let resolve = false;
1751
+ let target = "both";
1752
+ let channel;
1753
+ let account;
1754
+ const entryTokens = [];
1755
+ let i = 0;
1756
+ if (tokens[i] && ACTIONS.has(tokens[i].toLowerCase())) {
1757
+ action = tokens[i].toLowerCase();
1758
+ i += 1;
1759
+ }
1760
+ if (tokens[i] && SCOPES.has(tokens[i].toLowerCase())) {
1761
+ scope = tokens[i].toLowerCase();
1762
+ i += 1;
1763
+ }
1764
+ for (; i < tokens.length; i += 1) {
1765
+ const token = tokens[i];
1766
+ const lowered = token.toLowerCase();
1767
+ if (lowered === "--resolve" || lowered === "resolve") {
1768
+ resolve = true;
1769
+ continue;
1770
+ }
1771
+ if (lowered === "--config" || lowered === "config") {
1772
+ target = "config";
1773
+ continue;
1774
+ }
1775
+ if (lowered === "--store" || lowered === "store") {
1776
+ target = "store";
1777
+ continue;
1778
+ }
1779
+ if (lowered === "--channel" && tokens[i + 1]) {
1780
+ channel = tokens[i + 1];
1781
+ i += 1;
1782
+ continue;
1783
+ }
1784
+ if (lowered === "--account" && tokens[i + 1]) {
1785
+ account = tokens[i + 1];
1786
+ i += 1;
1787
+ continue;
1788
+ }
1789
+ const kv = token.split("=");
1790
+ if (kv.length === 2) {
1791
+ const key = kv[0]?.trim().toLowerCase();
1792
+ const value = kv[1]?.trim();
1793
+ if (key === "channel") {
1794
+ if (value) channel = value;
1795
+ continue;
1796
+ }
1797
+ if (key === "account") {
1798
+ if (value) account = value;
1799
+ continue;
1800
+ }
1801
+ if (key === "scope" && value && SCOPES.has(value.toLowerCase())) {
1802
+ scope = value.toLowerCase();
1803
+ continue;
1804
+ }
1805
+ }
1806
+ entryTokens.push(token);
1807
+ }
1808
+ if (action === "add" || action === "remove") {
1809
+ const entry = entryTokens.join(" ").trim();
1810
+ if (!entry) return {
1811
+ action: "error",
1812
+ message: "Usage: /allowlist add|remove <entry>"
1813
+ };
1814
+ return {
1815
+ action,
1816
+ scope,
1817
+ entry,
1818
+ channel,
1819
+ account,
1820
+ resolve,
1821
+ target
1822
+ };
1823
+ }
1824
+ return {
1825
+ action: "list",
1826
+ scope,
1827
+ channel,
1828
+ account,
1829
+ resolve
1830
+ };
1831
+ }
1832
+ function normalizeAllowFrom(params) {
1833
+ const plugin = getChannelPlugin(params.channelId);
1834
+ if (plugin?.config.formatAllowFrom) return plugin.config.formatAllowFrom({
1835
+ cfg: params.cfg,
1836
+ accountId: params.accountId,
1837
+ allowFrom: params.values
1838
+ });
1839
+ return normalizeStringEntries(params.values);
1840
+ }
1841
+ function formatEntryList(entries, resolved) {
1842
+ if (entries.length === 0) return "(none)";
1843
+ return entries.map((entry) => {
1844
+ const name = resolved?.get(entry);
1845
+ return name ? `${entry} (${name})` : entry;
1846
+ }).join(", ");
1847
+ }
1848
+ async function updatePairingStoreAllowlist(params) {
1849
+ const storeEntry = {
1850
+ channel: params.channelId,
1851
+ entry: params.entry,
1852
+ accountId: params.accountId
1853
+ };
1854
+ if (params.action === "add") {
1855
+ await addChannelAllowFromStoreEntry(storeEntry);
1856
+ return;
1857
+ }
1858
+ await removeChannelAllowFromStoreEntry(storeEntry);
1859
+ if (params.accountId === "default") await removeChannelAllowFromStoreEntry({
1860
+ channel: params.channelId,
1861
+ entry: params.entry
1862
+ });
1863
+ }
1864
+ function mapResolvedAllowlistNames(entries) {
1865
+ const map = /* @__PURE__ */ new Map();
1866
+ for (const entry of entries) if (entry.resolved && entry.name) map.set(entry.input, entry.name);
1867
+ return map;
1868
+ }
1869
+ async function resolveAllowlistNames(params) {
1870
+ return mapResolvedAllowlistNames(await getChannelPlugin(params.channelId)?.allowlist?.resolveNames?.({
1871
+ cfg: params.cfg,
1872
+ accountId: params.accountId,
1873
+ scope: params.scope,
1874
+ entries: params.entries
1875
+ }) ?? []);
1876
+ }
1877
+ async function readAllowlistConfig(params) {
1878
+ return await getChannelPlugin(params.channelId)?.allowlist?.readConfig?.({
1879
+ cfg: params.cfg,
1880
+ accountId: params.accountId
1881
+ }) ?? {};
1882
+ }
1883
+ const handleAllowlistCommand = async (params, allowTextCommands) => {
1884
+ if (!allowTextCommands) return null;
1885
+ const parsed = parseAllowlistCommand(params.command.commandBodyNormalized);
1886
+ if (!parsed) return null;
1887
+ if (parsed.action === "error") return {
1888
+ shouldContinue: false,
1889
+ reply: { text: `⚠️ ${parsed.message}` }
1890
+ };
1891
+ const unauthorized = rejectUnauthorizedCommand(params, "/allowlist");
1892
+ if (unauthorized) return unauthorized;
1893
+ const channelId = normalizeChannelId(parsed.channel) ?? params.command.channelId ?? normalizeChannelId(params.command.channel);
1894
+ if (!channelId) return {
1895
+ shouldContinue: false,
1896
+ reply: { text: "⚠️ Unknown channel. Add channel=<id> to the command." }
1897
+ };
1898
+ if (parsed.account?.trim() && !normalizeOptionalAccountId(parsed.account)) return {
1899
+ shouldContinue: false,
1900
+ reply: { text: "⚠️ Invalid account id. Reserved keys (__proto__, constructor, prototype) are blocked." }
1901
+ };
1902
+ const accountId = normalizeAccountId(parsed.account ?? params.ctx.AccountId);
1903
+ const plugin = getChannelPlugin(channelId);
1904
+ if (parsed.action === "list") {
1905
+ const supportsStore = Boolean(plugin?.pairing);
1906
+ if (!plugin?.allowlist?.readConfig && !supportsStore) return {
1907
+ shouldContinue: false,
1908
+ reply: { text: `⚠️ ${channelId} does not expose allowlist configuration.` }
1909
+ };
1910
+ const storeAllowFrom = supportsStore ? await readChannelAllowFromStore(channelId, process.env, accountId).catch(() => []) : [];
1911
+ const configState = await readAllowlistConfig({
1912
+ cfg: params.cfg,
1913
+ channelId,
1914
+ accountId
1915
+ });
1916
+ const dmAllowFrom = (configState.dmAllowFrom ?? []).map(String);
1917
+ const groupAllowFrom = (configState.groupAllowFrom ?? []).map(String);
1918
+ const groupOverrides = (configState.groupOverrides ?? []).map((entry) => ({
1919
+ label: entry.label,
1920
+ entries: entry.entries.map(String).filter(Boolean)
1921
+ }));
1922
+ const dmDisplay = normalizeAllowFrom({
1923
+ cfg: params.cfg,
1924
+ channelId,
1925
+ accountId,
1926
+ values: dmAllowFrom
1927
+ });
1928
+ const groupDisplay = normalizeAllowFrom({
1929
+ cfg: params.cfg,
1930
+ channelId,
1931
+ accountId,
1932
+ values: groupAllowFrom
1933
+ });
1934
+ const groupOverrideEntries = groupOverrides.flatMap((entry) => entry.entries);
1935
+ const groupOverrideDisplay = normalizeAllowFrom({
1936
+ cfg: params.cfg,
1937
+ channelId,
1938
+ accountId,
1939
+ values: groupOverrideEntries
1940
+ });
1941
+ const resolvedDm = parsed.resolve && dmDisplay.length > 0 ? await resolveAllowlistNames({
1942
+ cfg: params.cfg,
1943
+ channelId,
1944
+ accountId,
1945
+ scope: "dm",
1946
+ entries: dmDisplay
1947
+ }) : void 0;
1948
+ const resolvedGroup = parsed.resolve && groupOverrideDisplay.length > 0 ? await resolveAllowlistNames({
1949
+ cfg: params.cfg,
1950
+ channelId,
1951
+ accountId,
1952
+ scope: "group",
1953
+ entries: groupOverrideDisplay
1954
+ }) : void 0;
1955
+ const lines = ["🧾 Allowlist"];
1956
+ lines.push(`Channel: ${channelId}${accountId ? ` (account ${accountId})` : ""}`);
1957
+ if (configState.dmPolicy) lines.push(`DM policy: ${configState.dmPolicy}`);
1958
+ if (configState.groupPolicy) lines.push(`Group policy: ${configState.groupPolicy}`);
1959
+ const showDm = parsed.scope === "dm" || parsed.scope === "all";
1960
+ const showGroup = parsed.scope === "group" || parsed.scope === "all";
1961
+ if (showDm) lines.push(`DM allowFrom (config): ${formatEntryList(dmDisplay, resolvedDm)}`);
1962
+ if (supportsStore && storeAllowFrom.length > 0) {
1963
+ const storeLabel = normalizeAllowFrom({
1964
+ cfg: params.cfg,
1965
+ channelId,
1966
+ accountId,
1967
+ values: storeAllowFrom
1968
+ });
1969
+ lines.push(`Paired allowFrom (store): ${formatEntryList(storeLabel)}`);
1970
+ }
1971
+ if (showGroup) {
1972
+ if (groupAllowFrom.length > 0) lines.push(`Group allowFrom (config): ${formatEntryList(groupDisplay, resolvedGroup)}`);
1973
+ if (groupOverrides.length > 0) {
1974
+ lines.push("Group overrides:");
1975
+ for (const entry of groupOverrides) {
1976
+ const normalized = normalizeAllowFrom({
1977
+ cfg: params.cfg,
1978
+ channelId,
1979
+ accountId,
1980
+ values: entry.entries
1981
+ });
1982
+ lines.push(`- ${entry.label}: ${formatEntryList(normalized, resolvedGroup)}`);
1983
+ }
1984
+ }
1985
+ }
1986
+ return {
1987
+ shouldContinue: false,
1988
+ reply: { text: lines.join("\n") }
1989
+ };
1990
+ }
1991
+ const disabled = requireCommandFlagEnabled(params.cfg, {
1992
+ label: "/allowlist edits",
1993
+ configKey: "config",
1994
+ disabledVerb: "are"
1995
+ });
1996
+ if (disabled) return disabled;
1997
+ const shouldUpdateConfig = parsed.target !== "store";
1998
+ const shouldTouchStore = parsed.target !== "config" && Boolean(plugin?.pairing);
1999
+ if (shouldUpdateConfig) {
2000
+ if (parsed.scope === "all") return {
2001
+ shouldContinue: false,
2002
+ reply: { text: "⚠️ /allowlist add|remove requires scope dm or group." }
2003
+ };
2004
+ if (!plugin?.allowlist?.applyConfigEdit) return {
2005
+ shouldContinue: false,
2006
+ reply: { text: `⚠️ ${channelId} does not support ${parsed.scope} allowlist edits via /allowlist.` }
2007
+ };
2008
+ const snapshot = await readConfigFileSnapshot();
2009
+ if (!snapshot.valid || !snapshot.parsed || typeof snapshot.parsed !== "object") return {
2010
+ shouldContinue: false,
2011
+ reply: { text: "⚠️ Config file is invalid; fix it before using /allowlist." }
2012
+ };
2013
+ const parsedConfig = structuredClone(snapshot.parsed);
2014
+ const editResult = await plugin.allowlist.applyConfigEdit({
2015
+ cfg: params.cfg,
2016
+ parsedConfig,
2017
+ accountId,
2018
+ scope: parsed.scope,
2019
+ action: parsed.action,
2020
+ entry: parsed.entry
2021
+ });
2022
+ if (!editResult) return {
2023
+ shouldContinue: false,
2024
+ reply: { text: `⚠️ ${channelId} does not support ${parsed.scope} allowlist edits via /allowlist.` }
2025
+ };
2026
+ if (editResult.kind === "invalid-entry") return {
2027
+ shouldContinue: false,
2028
+ reply: { text: "⚠️ Invalid allowlist entry." }
2029
+ };
2030
+ const deniedText = resolveConfigWriteDeniedText({
2031
+ cfg: params.cfg,
2032
+ channel: params.command.channel,
2033
+ channelId,
2034
+ accountId: params.ctx.AccountId,
2035
+ gatewayClientScopes: params.ctx.GatewayClientScopes,
2036
+ target: editResult.writeTarget
2037
+ });
2038
+ if (deniedText) return {
2039
+ shouldContinue: false,
2040
+ reply: { text: deniedText }
2041
+ };
2042
+ const configChanged = editResult.changed;
2043
+ if (configChanged) {
2044
+ const validated = validateConfigObjectWithPlugins(parsedConfig);
2045
+ if (!validated.ok) {
2046
+ const issue = validated.issues[0];
2047
+ return {
2048
+ shouldContinue: false,
2049
+ reply: { text: `⚠️ Config invalid after update (${issue.path}: ${issue.message}).` }
2050
+ };
2051
+ }
2052
+ await writeConfigFile(validated.config);
2053
+ }
2054
+ if (!configChanged && !shouldTouchStore) return {
2055
+ shouldContinue: false,
2056
+ reply: { text: parsed.action === "add" ? "✅ Already allowlisted." : "⚠️ Entry not found." }
2057
+ };
2058
+ if (shouldTouchStore) await updatePairingStoreAllowlist({
2059
+ action: parsed.action,
2060
+ channelId,
2061
+ accountId,
2062
+ entry: parsed.entry
2063
+ });
2064
+ const actionLabel = parsed.action === "add" ? "added" : "removed";
2065
+ const scopeLabel = parsed.scope === "dm" ? "DM" : "group";
2066
+ const locations = [];
2067
+ if (configChanged) locations.push(editResult.pathLabel);
2068
+ if (shouldTouchStore) locations.push("pairing store");
2069
+ return {
2070
+ shouldContinue: false,
2071
+ reply: { text: `✅ ${scopeLabel} allowlist ${actionLabel}: ${locations.length > 0 ? locations.join(" + ") : "no-op"}.` }
2072
+ };
2073
+ }
2074
+ if (!shouldTouchStore) return {
2075
+ shouldContinue: false,
2076
+ reply: { text: "⚠️ This channel does not support allowlist storage." }
2077
+ };
2078
+ await updatePairingStoreAllowlist({
2079
+ action: parsed.action,
2080
+ channelId,
2081
+ accountId,
2082
+ entry: parsed.entry
2083
+ });
2084
+ const actionLabel = parsed.action === "add" ? "added" : "removed";
2085
+ return {
2086
+ shouldContinue: false,
2087
+ reply: { text: `✅ ${parsed.scope === "dm" ? "DM" : "group"} allowlist ${actionLabel} in pairing store.` }
2088
+ };
2089
+ };
2090
+ //#endregion
2091
+ //#region src/auto-reply/reply/commands-approve.ts
2092
+ const COMMAND_REGEX = /^\/approve(?:\s|$)/i;
2093
+ const FOREIGN_COMMAND_MENTION_REGEX = /^\/approve@([^\s]+)(?:\s|$)/i;
2094
+ const DECISION_ALIASES = {
2095
+ allow: "allow-once",
2096
+ once: "allow-once",
2097
+ "allow-once": "allow-once",
2098
+ allowonce: "allow-once",
2099
+ always: "allow-always",
2100
+ "allow-always": "allow-always",
2101
+ allowalways: "allow-always",
2102
+ deny: "deny",
2103
+ reject: "deny",
2104
+ block: "deny"
2105
+ };
2106
+ function parseApproveCommand(raw) {
2107
+ const trimmed = raw.trim();
2108
+ if (FOREIGN_COMMAND_MENTION_REGEX.test(trimmed)) return {
2109
+ ok: false,
2110
+ error: "❌ This /approve command targets a different Telegram bot."
2111
+ };
2112
+ const commandMatch = trimmed.match(COMMAND_REGEX);
2113
+ if (!commandMatch) return null;
2114
+ const rest = trimmed.slice(commandMatch[0].length).trim();
2115
+ if (!rest) return {
2116
+ ok: false,
2117
+ error: "Usage: /approve <id> allow-once|allow-always|deny"
2118
+ };
2119
+ const tokens = rest.split(/\s+/).filter(Boolean);
2120
+ if (tokens.length < 2) return {
2121
+ ok: false,
2122
+ error: "Usage: /approve <id> allow-once|allow-always|deny"
2123
+ };
2124
+ const first = tokens[0].toLowerCase();
2125
+ const second = tokens[1].toLowerCase();
2126
+ if (DECISION_ALIASES[first]) return {
2127
+ ok: true,
2128
+ decision: DECISION_ALIASES[first],
2129
+ id: tokens.slice(1).join(" ").trim()
2130
+ };
2131
+ if (DECISION_ALIASES[second]) return {
2132
+ ok: true,
2133
+ decision: DECISION_ALIASES[second],
2134
+ id: tokens[0]
2135
+ };
2136
+ return {
2137
+ ok: false,
2138
+ error: "Usage: /approve <id> allow-once|allow-always|deny"
2139
+ };
2140
+ }
2141
+ function buildResolvedByLabel(params) {
2142
+ return `${params.command.channel}:${params.command.senderId ?? "unknown"}`;
2143
+ }
2144
+ const handleApproveCommand = async (params, allowTextCommands) => {
2145
+ if (!allowTextCommands) return null;
2146
+ const normalized = params.command.commandBodyNormalized;
2147
+ const parsed = parseApproveCommand(normalized);
2148
+ if (!parsed) return null;
2149
+ if (!params.command.isAuthorizedSender) {
2150
+ logVerbose(`Ignoring /approve from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
2151
+ return { shouldContinue: false };
2152
+ }
2153
+ if (!parsed.ok) return {
2154
+ shouldContinue: false,
2155
+ reply: { text: parsed.error }
2156
+ };
2157
+ if (params.command.channel === "telegram") {
2158
+ if (!isTelegramExecApprovalClientEnabled({
2159
+ cfg: params.cfg,
2160
+ accountId: params.ctx.AccountId
2161
+ })) return {
2162
+ shouldContinue: false,
2163
+ reply: { text: "❌ Telegram exec approvals are not enabled for this bot account." }
2164
+ };
2165
+ if (!isTelegramExecApprovalApprover({
2166
+ cfg: params.cfg,
2167
+ accountId: params.ctx.AccountId,
2168
+ senderId: params.command.senderId
2169
+ })) return {
2170
+ shouldContinue: false,
2171
+ reply: { text: "❌ You are not authorized to approve exec requests on Telegram." }
2172
+ };
2173
+ }
2174
+ const missingScope = requireGatewayClientScopeForInternalChannel(params, {
2175
+ label: "/approve",
2176
+ allowedScopes: ["operator.approvals", "operator.admin"],
2177
+ missingText: "❌ /approve requires operator.approvals for gateway clients."
2178
+ });
2179
+ if (missingScope) return missingScope;
2180
+ const resolvedBy = buildResolvedByLabel(params);
2181
+ try {
2182
+ await callGateway({
2183
+ method: "exec.approval.resolve",
2184
+ params: {
2185
+ id: parsed.id,
2186
+ decision: parsed.decision
2187
+ },
2188
+ clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
2189
+ clientDisplayName: `Chat approval (${resolvedBy})`,
2190
+ mode: GATEWAY_CLIENT_MODES.BACKEND
2191
+ });
2192
+ } catch (err) {
2193
+ return {
2194
+ shouldContinue: false,
2195
+ reply: { text: `❌ Failed to submit approval: ${String(err)}` }
2196
+ };
2197
+ }
2198
+ return {
2199
+ shouldContinue: false,
2200
+ reply: { text: `✅ Exec approval ${parsed.decision} submitted for ${parsed.id}.` }
2201
+ };
2202
+ };
2203
+ //#endregion
2204
+ //#region src/auto-reply/reply/bash-command.ts
2205
+ const CHAT_BASH_SCOPE_KEY = "chat:bash";
2206
+ const DEFAULT_FOREGROUND_MS = 2e3;
2207
+ const MAX_FOREGROUND_MS = 3e4;
2208
+ let activeJob = null;
2209
+ function resolveForegroundMs(cfg) {
2210
+ const raw = cfg.commands?.bashForegroundMs;
2211
+ if (typeof raw !== "number" || Number.isNaN(raw)) return DEFAULT_FOREGROUND_MS;
2212
+ return clampInt(raw, 0, MAX_FOREGROUND_MS);
2213
+ }
2214
+ function formatSessionSnippet(sessionId) {
2215
+ const trimmed = sessionId.trim();
2216
+ if (trimmed.length <= 12) return trimmed;
2217
+ return `${trimmed.slice(0, 8)}…`;
2218
+ }
2219
+ function formatOutputBlock(text) {
2220
+ const trimmed = text.trim();
2221
+ if (!trimmed) return "(no output)";
2222
+ return `\`\`\`txt\n${trimmed}\n\`\`\``;
2223
+ }
2224
+ function parseBashRequest(raw) {
2225
+ const trimmed = raw.trimStart();
2226
+ let restSource = "";
2227
+ if (trimmed.toLowerCase().startsWith("/bash")) {
2228
+ const match = trimmed.match(/^\/bash(?:\s*:\s*|\s+|$)([\s\S]*)$/i);
2229
+ if (!match) return null;
2230
+ restSource = match[1] ?? "";
2231
+ } else if (trimmed.startsWith("!")) {
2232
+ restSource = trimmed.slice(1);
2233
+ if (restSource.trimStart().startsWith(":")) restSource = restSource.trimStart().slice(1);
2234
+ } else return null;
2235
+ const rest = restSource.trimStart();
2236
+ if (!rest) return { action: "help" };
2237
+ const tokenMatch = rest.match(/^(\S+)(?:\s+([\s\S]+))?$/);
2238
+ const token = tokenMatch?.[1]?.trim() ?? "";
2239
+ const remainder = tokenMatch?.[2]?.trim() ?? "";
2240
+ const lowered = token.toLowerCase();
2241
+ if (lowered === "poll") return {
2242
+ action: "poll",
2243
+ sessionId: remainder || void 0
2244
+ };
2245
+ if (lowered === "stop") return {
2246
+ action: "stop",
2247
+ sessionId: remainder || void 0
2248
+ };
2249
+ if (lowered === "help") return { action: "help" };
2250
+ return {
2251
+ action: "run",
2252
+ command: rest
2253
+ };
2254
+ }
2255
+ function resolveRawCommandBody(params) {
2256
+ const stripped = stripStructuralPrefixes(params.ctx.CommandBody ?? params.ctx.RawBody ?? params.ctx.Body ?? "");
2257
+ return params.isGroup ? stripMentions(stripped, params.ctx, params.cfg, params.agentId) : stripped;
2258
+ }
2259
+ function getScopedSession(sessionId) {
2260
+ const running = getSession(sessionId);
2261
+ if (running && running.scopeKey === CHAT_BASH_SCOPE_KEY) return { running };
2262
+ const finished = getFinishedSession(sessionId);
2263
+ if (finished && finished.scopeKey === CHAT_BASH_SCOPE_KEY) return { finished };
2264
+ return {};
2265
+ }
2266
+ function ensureActiveJobState() {
2267
+ if (!activeJob) return null;
2268
+ if (activeJob.state === "starting") return activeJob;
2269
+ const { running, finished } = getScopedSession(activeJob.sessionId);
2270
+ if (running) return activeJob;
2271
+ if (finished) {
2272
+ activeJob = null;
2273
+ return null;
2274
+ }
2275
+ activeJob = null;
2276
+ return null;
2277
+ }
2278
+ function attachActiveWatcher(sessionId) {
2279
+ if (!activeJob || activeJob.state !== "running") return;
2280
+ if (activeJob.sessionId !== sessionId) return;
2281
+ if (activeJob.watcherAttached) return;
2282
+ const { running } = getScopedSession(sessionId);
2283
+ const child = running?.child;
2284
+ if (!child) return;
2285
+ activeJob.watcherAttached = true;
2286
+ child.once("close", () => {
2287
+ if (activeJob?.state === "running" && activeJob.sessionId === sessionId) activeJob = null;
2288
+ });
2289
+ }
2290
+ function buildUsageReply() {
2291
+ return { text: [
2292
+ "⚙️ Usage:",
2293
+ "- ! <command>",
2294
+ "- !poll | ! poll",
2295
+ "- !stop | ! stop",
2296
+ "- /bash ... (alias; same subcommands as !)"
2297
+ ].join("\n") };
2298
+ }
2299
+ async function handleBashChatCommand(params) {
2300
+ if (!isCommandFlagEnabled(params.cfg, "bash")) return buildDisabledCommandReply({
2301
+ label: "bash",
2302
+ configKey: "bash",
2303
+ docsUrl: "https://docs.openclaw.ai/tools/slash-commands#config"
2304
+ });
2305
+ const agentId = params.agentId ?? resolveSessionAgentId({
2306
+ sessionKey: params.sessionKey,
2307
+ config: params.cfg
2308
+ });
2309
+ if (!params.elevated.enabled || !params.elevated.allowed) {
2310
+ const runtimeSandboxed = resolveSandboxRuntimeStatus({
2311
+ cfg: params.cfg,
2312
+ sessionKey: params.ctx.SessionKey
2313
+ }).sandboxed;
2314
+ return { text: formatElevatedUnavailableMessage({
2315
+ runtimeSandboxed,
2316
+ failures: params.elevated.failures,
2317
+ sessionKey: params.ctx.SessionKey
2318
+ }) };
2319
+ }
2320
+ const request = parseBashRequest(resolveRawCommandBody({
2321
+ ctx: params.ctx,
2322
+ cfg: params.cfg,
2323
+ agentId,
2324
+ isGroup: params.isGroup
2325
+ }).trim());
2326
+ if (!request) return { text: "⚠️ Unrecognized bash request." };
2327
+ const liveJob = ensureActiveJobState();
2328
+ if (request.action === "help") return buildUsageReply();
2329
+ if (request.action === "poll") {
2330
+ const sessionId = request.sessionId?.trim() || (liveJob?.state === "running" ? liveJob.sessionId : "");
2331
+ if (!sessionId) return { text: "⚙️ No active bash job." };
2332
+ const { running, finished } = getScopedSession(sessionId);
2333
+ if (running) {
2334
+ attachActiveWatcher(sessionId);
2335
+ const runtimeSec = Math.max(0, Math.floor((Date.now() - running.startedAt) / 1e3));
2336
+ const tail = running.tail || "(no output yet)";
2337
+ return { text: [
2338
+ `⚙️ bash still running (session ${formatSessionSnippet(sessionId)}, ${runtimeSec}s).`,
2339
+ formatOutputBlock(tail),
2340
+ "Hint: !stop (or /bash stop)"
2341
+ ].join("\n") };
2342
+ }
2343
+ if (finished) {
2344
+ if (activeJob?.state === "running" && activeJob.sessionId === sessionId) activeJob = null;
2345
+ const exitLabel = finished.exitSignal ? `signal ${String(finished.exitSignal)}` : `code ${String(finished.exitCode ?? 0)}`;
2346
+ return { text: [
2347
+ `${finished.status === "completed" ? "⚙️" : "⚠️"} bash finished (session ${formatSessionSnippet(sessionId)}).`,
2348
+ `Exit: ${exitLabel}`,
2349
+ formatOutputBlock(finished.aggregated || finished.tail)
2350
+ ].join("\n") };
2351
+ }
2352
+ if (activeJob?.state === "running" && activeJob.sessionId === sessionId) activeJob = null;
2353
+ return { text: `⚙️ No bash session found for ${formatSessionSnippet(sessionId)}.` };
2354
+ }
2355
+ if (request.action === "stop") {
2356
+ const sessionId = request.sessionId?.trim() || (liveJob?.state === "running" ? liveJob.sessionId : "");
2357
+ if (!sessionId) return { text: "⚙️ No active bash job." };
2358
+ const { running } = getScopedSession(sessionId);
2359
+ if (!running) {
2360
+ if (activeJob?.state === "running" && activeJob.sessionId === sessionId) activeJob = null;
2361
+ return { text: `⚙️ No running bash job found for ${formatSessionSnippet(sessionId)}.` };
2362
+ }
2363
+ if (!running.backgrounded) return { text: `⚠️ Session ${formatSessionSnippet(sessionId)} is not backgrounded.` };
2364
+ const pid = running.pid ?? running.child?.pid;
2365
+ if (pid) killProcessTree(pid);
2366
+ markExited(running, null, "SIGKILL", "failed");
2367
+ if (activeJob?.state === "running" && activeJob.sessionId === sessionId) activeJob = null;
2368
+ return { text: `⚙️ bash stopped (session ${formatSessionSnippet(sessionId)}).` };
2369
+ }
2370
+ if (liveJob) return { text: `⚠️ A bash job is already running (${liveJob.state === "running" ? formatSessionSnippet(liveJob.sessionId) : "starting"}). Use !poll / !stop (or /bash poll / /bash stop).` };
2371
+ const commandText = request.command.trim();
2372
+ if (!commandText) return buildUsageReply();
2373
+ activeJob = {
2374
+ state: "starting",
2375
+ startedAt: Date.now(),
2376
+ command: commandText
2377
+ };
2378
+ try {
2379
+ const foregroundMs = resolveForegroundMs(params.cfg);
2380
+ const shouldBackgroundImmediately = foregroundMs <= 0;
2381
+ const timeoutSec = params.cfg.tools?.exec?.timeoutSec;
2382
+ const notifyOnExit = params.cfg.tools?.exec?.notifyOnExit;
2383
+ const notifyOnExitEmptySuccess = params.cfg.tools?.exec?.notifyOnExitEmptySuccess;
2384
+ const result = await createExecTool({
2385
+ scopeKey: CHAT_BASH_SCOPE_KEY,
2386
+ allowBackground: true,
2387
+ timeoutSec,
2388
+ sessionKey: params.sessionKey,
2389
+ notifyOnExit,
2390
+ notifyOnExitEmptySuccess,
2391
+ elevated: {
2392
+ enabled: params.elevated.enabled,
2393
+ allowed: params.elevated.allowed,
2394
+ defaultLevel: "on"
2395
+ }
2396
+ }).execute("chat-bash", {
2397
+ command: commandText,
2398
+ background: shouldBackgroundImmediately,
2399
+ yieldMs: shouldBackgroundImmediately ? void 0 : foregroundMs,
2400
+ timeout: timeoutSec,
2401
+ elevated: true
2402
+ });
2403
+ if (result.details?.status === "running") {
2404
+ const sessionId = result.details.sessionId;
2405
+ activeJob = {
2406
+ state: "running",
2407
+ sessionId,
2408
+ startedAt: result.details.startedAt,
2409
+ command: commandText,
2410
+ watcherAttached: false
2411
+ };
2412
+ attachActiveWatcher(sessionId);
2413
+ logVerbose(`Started bash session ${formatSessionSnippet(sessionId)}: ${commandText}`);
2414
+ return { text: `⚙️ bash started (session ${sessionId}). Still running; use !poll / !stop (or /bash poll / /bash stop).` };
2415
+ }
2416
+ activeJob = null;
2417
+ const exitCode = result.details?.status === "completed" ? result.details.exitCode : 0;
2418
+ const output = result.details?.status === "completed" ? result.details.aggregated : result.content.map((chunk) => chunk.type === "text" ? chunk.text : "").join("\n");
2419
+ return { text: [
2420
+ `⚙️ bash: ${commandText}`,
2421
+ `Exit: ${exitCode}`,
2422
+ formatOutputBlock(output || "(no output)")
2423
+ ].join("\n") };
2424
+ } catch (err) {
2425
+ activeJob = null;
2426
+ const message = err instanceof Error ? err.message : String(err);
2427
+ return { text: [`⚠️ bash failed: ${commandText}`, formatOutputBlock(message)].join("\n") };
2428
+ }
2429
+ }
2430
+ //#endregion
2431
+ //#region src/auto-reply/reply/commands-bash.ts
2432
+ const handleBashCommand = async (params, allowTextCommands) => {
2433
+ if (!allowTextCommands) return null;
2434
+ const { command } = params;
2435
+ const bashSlashRequested = command.commandBodyNormalized === "/bash" || command.commandBodyNormalized.startsWith("/bash ");
2436
+ const bashBangRequested = command.commandBodyNormalized.startsWith("!");
2437
+ if (!bashSlashRequested && !(bashBangRequested && command.isAuthorizedSender)) return null;
2438
+ const unauthorized = rejectUnauthorizedCommand(params, "/bash");
2439
+ if (unauthorized) return unauthorized;
2440
+ return {
2441
+ shouldContinue: false,
2442
+ reply: await handleBashChatCommand({
2443
+ ctx: params.ctx,
2444
+ cfg: params.cfg,
2445
+ agentId: params.agentId,
2446
+ sessionKey: params.sessionKey,
2447
+ isGroup: params.isGroup,
2448
+ elevated: params.elevated
2449
+ })
2450
+ };
2451
+ };
2452
+ //#endregion
2453
+ //#region src/agents/btw.ts
2454
+ function collectTextContent(content) {
2455
+ return content.filter((part) => part.type === "text").map((part) => part.text).join("");
2456
+ }
2457
+ function collectThinkingContent(content) {
2458
+ return content.filter((part) => part.type === "thinking").map((part) => part.thinking).join("");
2459
+ }
2460
+ function buildBtwSystemPrompt() {
2461
+ return [
2462
+ "You are answering an ephemeral /btw side question about the current conversation.",
2463
+ "Use the conversation only as background context.",
2464
+ "Answer only the side question in the last user message.",
2465
+ "Do not continue, resume, or complete any unfinished task from the conversation.",
2466
+ "Do not emit tool calls, pseudo-tool calls, shell commands, file writes, patches, or code unless the side question explicitly asks for them.",
2467
+ "Do not say you will continue the main task after answering.",
2468
+ "If the question can be answered briefly, answer briefly."
2469
+ ].join("\n");
2470
+ }
2471
+ function buildBtwQuestionPrompt(question, inFlightPrompt) {
2472
+ const lines = ["Answer this side question only.", "Ignore any unfinished task in the conversation while answering it."];
2473
+ const trimmedPrompt = inFlightPrompt?.trim();
2474
+ if (trimmedPrompt) lines.push("", "Current in-flight main task request for background context only:", "<in_flight_main_task>", trimmedPrompt, "</in_flight_main_task>", "Do not continue or complete that task while answering the side question.");
2475
+ lines.push("", "<btw_side_question>", question.trim(), "</btw_side_question>");
2476
+ return lines.join("\n");
2477
+ }
2478
+ function toSimpleContextMessages(messages) {
2479
+ return stripToolResultDetails(messages.filter((message) => {
2480
+ if (!message || typeof message !== "object") return false;
2481
+ const role = message.role;
2482
+ return role === "user" || role === "assistant";
2483
+ }));
2484
+ }
2485
+ function resolveSimpleThinkingLevel(level) {
2486
+ if (!level || level === "off") return;
2487
+ return mapThinkingLevel(level);
2488
+ }
2489
+ function resolveSessionTranscriptPath(params) {
2490
+ try {
2491
+ const agentId = params.sessionKey?.split(":")[1];
2492
+ const pathOpts = resolveSessionFilePathOptions({
2493
+ agentId,
2494
+ storePath: params.storePath
2495
+ });
2496
+ return resolveSessionFilePath(params.sessionId, params.sessionEntry, pathOpts);
2497
+ } catch (error) {
2498
+ diag.debug(`resolveSessionTranscriptPath failed: sessionId=${params.sessionId} err=${String(error)}`);
2499
+ return;
2500
+ }
2501
+ }
2502
+ async function resolveRuntimeModel(params) {
2503
+ await ensureOpenClawModelsJson(params.cfg, params.agentDir);
2504
+ const modelRegistry = discoverModels(discoverAuthStorage(params.agentDir), params.agentDir);
2505
+ const model = resolveModelWithRegistry({
2506
+ provider: params.provider,
2507
+ modelId: params.model,
2508
+ modelRegistry,
2509
+ cfg: params.cfg
2510
+ });
2511
+ if (!model) throw new Error(`Unknown model: ${params.provider}/${params.model}`);
2512
+ return {
2513
+ model,
2514
+ authProfileId: await resolveSessionAuthProfileOverride({
2515
+ cfg: params.cfg,
2516
+ provider: params.provider,
2517
+ agentDir: params.agentDir,
2518
+ sessionEntry: params.sessionEntry,
2519
+ sessionStore: params.sessionStore,
2520
+ sessionKey: params.sessionKey,
2521
+ storePath: params.storePath,
2522
+ isNewSession: params.isNewSession
2523
+ }),
2524
+ authProfileIdSource: params.sessionEntry?.authProfileOverrideSource
2525
+ };
2526
+ }
2527
+ async function runBtwSideQuestion(params) {
2528
+ const sessionId = params.sessionEntry.sessionId?.trim();
2529
+ if (!sessionId) throw new Error("No active session context.");
2530
+ const sessionFile = resolveSessionTranscriptPath({
2531
+ sessionId,
2532
+ sessionEntry: params.sessionEntry,
2533
+ sessionKey: params.sessionKey,
2534
+ storePath: params.storePath
2535
+ });
2536
+ if (!sessionFile) throw new Error("No active session transcript.");
2537
+ const sessionManager = SessionManager.open(sessionFile);
2538
+ const activeRunSnapshot = getActiveEmbeddedRunSnapshot(sessionId);
2539
+ let messages = [];
2540
+ let inFlightPrompt;
2541
+ if (Array.isArray(activeRunSnapshot?.messages) && activeRunSnapshot.messages.length > 0) {
2542
+ messages = toSimpleContextMessages(activeRunSnapshot.messages);
2543
+ inFlightPrompt = activeRunSnapshot.inFlightPrompt;
2544
+ } else if (activeRunSnapshot) {
2545
+ inFlightPrompt = activeRunSnapshot.inFlightPrompt;
2546
+ if (activeRunSnapshot.transcriptLeafId && sessionManager.branch) try {
2547
+ sessionManager.branch(activeRunSnapshot.transcriptLeafId);
2548
+ } catch (error) {
2549
+ diag.debug(`btw snapshot leaf unavailable: sessionId=${sessionId} leaf=${activeRunSnapshot.transcriptLeafId} err=${String(error)}`);
2550
+ sessionManager.resetLeaf?.();
2551
+ }
2552
+ else sessionManager.resetLeaf?.();
2553
+ } else {
2554
+ const leafEntry = sessionManager.getLeafEntry?.();
2555
+ if (leafEntry?.type === "message" && leafEntry.message?.role === "user") if (leafEntry.parentId && sessionManager.branch) sessionManager.branch(leafEntry.parentId);
2556
+ else sessionManager.resetLeaf?.();
2557
+ }
2558
+ if (messages.length === 0) {
2559
+ const sessionContext = sessionManager.buildSessionContext();
2560
+ messages = toSimpleContextMessages(Array.isArray(sessionContext.messages) ? sessionContext.messages : []);
2561
+ }
2562
+ if (messages.length === 0 && !inFlightPrompt?.trim()) throw new Error("No active session context.");
2563
+ const { model, authProfileId } = await resolveRuntimeModel({
2564
+ cfg: params.cfg,
2565
+ provider: params.provider,
2566
+ model: params.model,
2567
+ agentDir: params.agentDir,
2568
+ sessionEntry: params.sessionEntry,
2569
+ sessionStore: params.sessionStore,
2570
+ sessionKey: params.sessionKey,
2571
+ storePath: params.storePath,
2572
+ isNewSession: params.isNewSession
2573
+ });
2574
+ const apiKey = requireApiKey(await getApiKeyForModel({
2575
+ model,
2576
+ cfg: params.cfg,
2577
+ profileId: authProfileId,
2578
+ agentDir: params.agentDir
2579
+ }), model.provider);
2580
+ const chunker = params.opts?.onBlockReply && params.blockReplyChunking ? new EmbeddedBlockChunker(params.blockReplyChunking) : void 0;
2581
+ let emittedBlocks = 0;
2582
+ let blockEmitChain = Promise.resolve();
2583
+ let answerText = "";
2584
+ let reasoningText = "";
2585
+ let assistantStarted = false;
2586
+ let sawTextEvent = false;
2587
+ const emitBlockChunk = async (text) => {
2588
+ if (!text.trim() || !params.opts?.onBlockReply) return;
2589
+ emittedBlocks += 1;
2590
+ blockEmitChain = blockEmitChain.then(async () => {
2591
+ await params.opts?.onBlockReply?.({
2592
+ text,
2593
+ btw: { question: params.question }
2594
+ });
2595
+ });
2596
+ await blockEmitChain;
2597
+ };
2598
+ const stream = streamSimple(model, {
2599
+ systemPrompt: buildBtwSystemPrompt(),
2600
+ messages: [...messages, {
2601
+ role: "user",
2602
+ content: [{
2603
+ type: "text",
2604
+ text: buildBtwQuestionPrompt(params.question, inFlightPrompt)
2605
+ }],
2606
+ timestamp: Date.now()
2607
+ }]
2608
+ }, {
2609
+ apiKey,
2610
+ reasoning: resolveSimpleThinkingLevel(params.resolvedThinkLevel),
2611
+ signal: params.opts?.abortSignal
2612
+ });
2613
+ let finalEvent;
2614
+ for await (const event of stream) {
2615
+ finalEvent = event.type === "done" || event.type === "error" ? event : finalEvent;
2616
+ if (!assistantStarted && (event.type === "text_start" || event.type === "start")) {
2617
+ assistantStarted = true;
2618
+ await params.opts?.onAssistantMessageStart?.();
2619
+ }
2620
+ if (event.type === "text_delta") {
2621
+ sawTextEvent = true;
2622
+ answerText += event.delta;
2623
+ chunker?.append(event.delta);
2624
+ if (chunker && params.resolvedBlockStreamingBreak === "text_end") chunker.drain({
2625
+ force: false,
2626
+ emit: (chunk) => void emitBlockChunk(chunk)
2627
+ });
2628
+ continue;
2629
+ }
2630
+ if (event.type === "text_end" && chunker && params.resolvedBlockStreamingBreak === "text_end") {
2631
+ chunker.drain({
2632
+ force: true,
2633
+ emit: (chunk) => void emitBlockChunk(chunk)
2634
+ });
2635
+ continue;
2636
+ }
2637
+ if (event.type === "thinking_delta") {
2638
+ reasoningText += event.delta;
2639
+ if (params.resolvedReasoningLevel !== "off") await params.opts?.onReasoningStream?.({
2640
+ text: reasoningText,
2641
+ isReasoning: true
2642
+ });
2643
+ continue;
2644
+ }
2645
+ if (event.type === "thinking_end" && params.resolvedReasoningLevel !== "off") await params.opts?.onReasoningEnd?.();
2646
+ }
2647
+ if (chunker && params.resolvedBlockStreamingBreak !== "text_end" && chunker.hasBuffered()) chunker.drain({
2648
+ force: true,
2649
+ emit: (chunk) => void emitBlockChunk(chunk)
2650
+ });
2651
+ await blockEmitChain;
2652
+ if (finalEvent?.type === "error") {
2653
+ const message = collectTextContent(finalEvent.error.content);
2654
+ throw new Error(message || finalEvent.error.errorMessage || "BTW failed.");
2655
+ }
2656
+ const finalMessage = finalEvent?.type === "done" ? finalEvent.message : void 0;
2657
+ if (finalMessage) {
2658
+ if (!sawTextEvent) answerText = collectTextContent(finalMessage.content);
2659
+ if (!reasoningText) reasoningText = collectThinkingContent(finalMessage.content);
2660
+ }
2661
+ const answer = answerText.trim();
2662
+ if (!answer) throw new Error("No BTW response generated.");
2663
+ if (emittedBlocks > 0) return;
2664
+ return { text: answer };
2665
+ }
2666
+ //#endregion
2667
+ //#region src/auto-reply/reply/commands-btw.ts
2668
+ const BTW_USAGE = "Usage: /btw <side question>";
2669
+ const handleBtwCommand = async (params, allowTextCommands) => {
2670
+ if (!allowTextCommands) return null;
2671
+ const question = extractBtwQuestion(params.command.commandBodyNormalized);
2672
+ if (question === null) return null;
2673
+ const unauthorized = rejectUnauthorizedCommand(params, "/btw");
2674
+ if (unauthorized) return unauthorized;
2675
+ if (!question) return {
2676
+ shouldContinue: false,
2677
+ reply: { text: BTW_USAGE }
2678
+ };
2679
+ if (!params.sessionEntry?.sessionId) return {
2680
+ shouldContinue: false,
2681
+ reply: { text: "⚠️ /btw requires an active session with existing context." }
2682
+ };
2683
+ if (!params.agentDir) return {
2684
+ shouldContinue: false,
2685
+ reply: { text: "⚠️ /btw is unavailable because the active agent directory could not be resolved." }
2686
+ };
2687
+ try {
2688
+ await params.typing?.startTypingLoop();
2689
+ const reply = await runBtwSideQuestion({
2690
+ cfg: params.cfg,
2691
+ agentDir: params.agentDir,
2692
+ provider: params.provider,
2693
+ model: params.model,
2694
+ question,
2695
+ sessionEntry: params.sessionEntry,
2696
+ sessionStore: params.sessionStore,
2697
+ sessionKey: params.sessionKey,
2698
+ storePath: params.storePath,
2699
+ resolvedThinkLevel: "off",
2700
+ resolvedReasoningLevel: "off",
2701
+ blockReplyChunking: params.blockReplyChunking,
2702
+ resolvedBlockStreamingBreak: params.resolvedBlockStreamingBreak,
2703
+ opts: params.opts,
2704
+ isNewSession: false
2705
+ });
2706
+ return {
2707
+ shouldContinue: false,
2708
+ reply: reply ? {
2709
+ ...reply,
2710
+ btw: { question }
2711
+ } : reply
2712
+ };
2713
+ } catch (error) {
2714
+ const message = error instanceof Error ? error.message.trim() : "";
2715
+ return {
2716
+ shouldContinue: false,
2717
+ reply: {
2718
+ text: `⚠️ /btw failed${message ? `: ${message}` : "."}`,
2719
+ btw: { question },
2720
+ isError: true
2721
+ }
2722
+ };
2723
+ }
2724
+ };
2725
+ //#endregion
2726
+ //#region src/auto-reply/reply/commands-compact.ts
2727
+ function extractCompactInstructions(params) {
2728
+ const raw = stripStructuralPrefixes(params.rawBody ?? "");
2729
+ const trimmed = (params.isGroup ? stripMentions(raw, params.ctx, params.cfg, params.agentId) : raw).trim();
2730
+ if (!trimmed) return;
2731
+ const prefix = trimmed.toLowerCase().startsWith("/compact") ? "/compact" : null;
2732
+ if (!prefix) return;
2733
+ let rest = trimmed.slice(prefix.length).trimStart();
2734
+ if (rest.startsWith(":")) rest = rest.slice(1).trimStart();
2735
+ return rest.length ? rest : void 0;
2736
+ }
2737
+ const handleCompactCommand = async (params) => {
2738
+ if (!(params.command.commandBodyNormalized === "/compact" || params.command.commandBodyNormalized.startsWith("/compact "))) return null;
2739
+ if (!params.command.isAuthorizedSender) {
2740
+ logVerbose(`Ignoring /compact from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
2741
+ return { shouldContinue: false };
2742
+ }
2743
+ if (!params.sessionEntry?.sessionId) return {
2744
+ shouldContinue: false,
2745
+ reply: { text: "⚙️ Compaction unavailable (missing session id)." }
2746
+ };
2747
+ const sessionId = params.sessionEntry.sessionId;
2748
+ if (isEmbeddedPiRunActive(sessionId)) {
2749
+ abortEmbeddedPiRun(sessionId);
2750
+ await waitForEmbeddedPiRunEnd(sessionId, 15e3);
2751
+ }
2752
+ const customInstructions = extractCompactInstructions({
2753
+ rawBody: params.ctx.CommandBody ?? params.ctx.RawBody ?? params.ctx.Body,
2754
+ ctx: params.ctx,
2755
+ cfg: params.cfg,
2756
+ agentId: params.agentId,
2757
+ isGroup: params.isGroup
2758
+ });
2759
+ const result = await compactEmbeddedPiSession({
2760
+ sessionId,
2761
+ sessionKey: params.sessionKey,
2762
+ allowGatewaySubagentBinding: true,
2763
+ messageChannel: params.command.channel,
2764
+ groupId: params.sessionEntry.groupId,
2765
+ groupChannel: params.sessionEntry.groupChannel,
2766
+ groupSpace: params.sessionEntry.space,
2767
+ spawnedBy: params.sessionEntry.spawnedBy,
2768
+ sessionFile: resolveSessionFilePath(sessionId, params.sessionEntry, resolveSessionFilePathOptions({
2769
+ agentId: params.agentId,
2770
+ storePath: params.storePath
2771
+ })),
2772
+ workspaceDir: params.workspaceDir,
2773
+ agentDir: params.agentDir,
2774
+ config: params.cfg,
2775
+ skillsSnapshot: params.sessionEntry.skillsSnapshot,
2776
+ provider: params.provider,
2777
+ model: params.model,
2778
+ thinkLevel: params.resolvedThinkLevel ?? await params.resolveDefaultThinkingLevel(),
2779
+ bashElevated: {
2780
+ enabled: false,
2781
+ allowed: false,
2782
+ defaultLevel: "off"
2783
+ },
2784
+ customInstructions,
2785
+ trigger: "manual",
2786
+ senderIsOwner: params.command.senderIsOwner,
2787
+ ownerNumbers: params.command.ownerList.length > 0 ? params.command.ownerList : void 0
2788
+ });
2789
+ const compactLabel = result.ok ? result.compacted ? result.result?.tokensBefore != null && result.result?.tokensAfter != null ? `Compacted (${formatTokenCount(result.result.tokensBefore)} → ${formatTokenCount(result.result.tokensAfter)})` : result.result?.tokensBefore ? `Compacted (${formatTokenCount(result.result.tokensBefore)} before)` : "Compacted" : "Compaction skipped" : "Compaction failed";
2790
+ if (result.ok && result.compacted) await incrementCompactionCount({
2791
+ sessionEntry: params.sessionEntry,
2792
+ sessionStore: params.sessionStore,
2793
+ sessionKey: params.sessionKey,
2794
+ storePath: params.storePath,
2795
+ tokensAfter: result.result?.tokensAfter
2796
+ });
2797
+ const totalTokens = result.result?.tokensAfter ?? resolveFreshSessionTotalTokens(params.sessionEntry);
2798
+ const contextSummary = formatContextUsageShort(typeof totalTokens === "number" && totalTokens > 0 ? totalTokens : null, params.contextTokens ?? params.sessionEntry.contextTokens ?? null);
2799
+ const reason = result.reason?.trim();
2800
+ const line = reason ? `${compactLabel}: ${reason} • ${contextSummary}` : `${compactLabel} • ${contextSummary}`;
2801
+ enqueueSystemEvent(line, { sessionKey: params.sessionKey });
2802
+ return {
2803
+ shouldContinue: false,
2804
+ reply: { text: `⚙️ ${line}` }
2805
+ };
2806
+ };
2807
+ //#endregion
2808
+ //#region src/auto-reply/reply/commands-slash-parse.ts
2809
+ function parseSlashCommandActionArgs(raw, slash) {
2810
+ const trimmed = raw.trim();
2811
+ const slashLower = slash.toLowerCase();
2812
+ if (!trimmed.toLowerCase().startsWith(slashLower)) return { kind: "no-match" };
2813
+ const rest = trimmed.slice(slash.length).trim();
2814
+ if (!rest) return { kind: "empty" };
2815
+ const match = rest.match(/^(\S+)(?:\s+([\s\S]+))?$/);
2816
+ if (!match) return { kind: "invalid" };
2817
+ return {
2818
+ kind: "parsed",
2819
+ action: match[1]?.toLowerCase() ?? "",
2820
+ args: (match[2] ?? "").trim()
2821
+ };
2822
+ }
2823
+ function parseSlashCommandOrNull(raw, slash, opts) {
2824
+ const parsed = parseSlashCommandActionArgs(raw, slash);
2825
+ if (parsed.kind === "no-match") return null;
2826
+ if (parsed.kind === "invalid") return {
2827
+ ok: false,
2828
+ message: opts.invalidMessage
2829
+ };
2830
+ if (parsed.kind === "empty") return {
2831
+ ok: true,
2832
+ action: opts.defaultAction ?? "show",
2833
+ args: ""
2834
+ };
2835
+ return {
2836
+ ok: true,
2837
+ action: parsed.action,
2838
+ args: parsed.args
2839
+ };
2840
+ }
2841
+ //#endregion
2842
+ //#region src/auto-reply/reply/commands-setunset.ts
2843
+ function parseSetUnsetCommand(params) {
2844
+ const action = params.action;
2845
+ const args = params.args.trim();
2846
+ if (action === "unset") {
2847
+ if (!args) return {
2848
+ kind: "error",
2849
+ message: `Usage: ${params.slash} unset path`
2850
+ };
2851
+ return {
2852
+ kind: "unset",
2853
+ path: args
2854
+ };
2855
+ }
2856
+ if (!args) return {
2857
+ kind: "error",
2858
+ message: `Usage: ${params.slash} set path=value`
2859
+ };
2860
+ const eqIndex = args.indexOf("=");
2861
+ if (eqIndex <= 0) return {
2862
+ kind: "error",
2863
+ message: `Usage: ${params.slash} set path=value`
2864
+ };
2865
+ const path = args.slice(0, eqIndex).trim();
2866
+ const rawValue = args.slice(eqIndex + 1);
2867
+ if (!path) return {
2868
+ kind: "error",
2869
+ message: `Usage: ${params.slash} set path=value`
2870
+ };
2871
+ const parsed = parseConfigValue(rawValue);
2872
+ if (parsed.error) return {
2873
+ kind: "error",
2874
+ message: parsed.error
2875
+ };
2876
+ return {
2877
+ kind: "set",
2878
+ path,
2879
+ value: parsed.value
2880
+ };
2881
+ }
2882
+ function parseSetUnsetCommandAction(params) {
2883
+ if (params.action !== "set" && params.action !== "unset") return null;
2884
+ const parsed = parseSetUnsetCommand({
2885
+ slash: params.slash,
2886
+ action: params.action,
2887
+ args: params.args
2888
+ });
2889
+ if (parsed.kind === "error") return params.onError(parsed.message);
2890
+ return parsed.kind === "set" ? params.onSet(parsed.path, parsed.value) : params.onUnset(parsed.path);
2891
+ }
2892
+ function parseSlashCommandWithSetUnset(params) {
2893
+ const parsed = parseSlashCommandOrNull(params.raw, params.slash, { invalidMessage: params.invalidMessage });
2894
+ if (!parsed) return null;
2895
+ if (!parsed.ok) return params.onError(parsed.message);
2896
+ const { action, args } = parsed;
2897
+ const setUnset = parseSetUnsetCommandAction({
2898
+ slash: params.slash,
2899
+ action,
2900
+ args,
2901
+ onSet: params.onSet,
2902
+ onUnset: params.onUnset,
2903
+ onError: params.onError
2904
+ });
2905
+ if (setUnset) return setUnset;
2906
+ const knownAction = params.onKnownAction(action, args);
2907
+ if (knownAction) return knownAction;
2908
+ return params.onError(params.usageMessage);
2909
+ }
2910
+ //#endregion
2911
+ //#region src/auto-reply/reply/commands-setunset-standard.ts
2912
+ function parseStandardSetUnsetSlashCommand(params) {
2913
+ return parseSlashCommandWithSetUnset({
2914
+ raw: params.raw,
2915
+ slash: params.slash,
2916
+ invalidMessage: params.invalidMessage,
2917
+ usageMessage: params.usageMessage,
2918
+ onKnownAction: params.onKnownAction,
2919
+ onSet: params.onSet ?? ((path, value) => ({
2920
+ action: "set",
2921
+ path,
2922
+ value
2923
+ })),
2924
+ onUnset: params.onUnset ?? ((path) => ({
2925
+ action: "unset",
2926
+ path
2927
+ })),
2928
+ onError: params.onError ?? ((message) => ({
2929
+ action: "error",
2930
+ message
2931
+ }))
2932
+ });
2933
+ }
2934
+ //#endregion
2935
+ //#region src/auto-reply/reply/config-commands.ts
2936
+ function parseConfigCommand(raw) {
2937
+ return parseStandardSetUnsetSlashCommand({
2938
+ raw,
2939
+ slash: "/config",
2940
+ invalidMessage: "Invalid /config syntax.",
2941
+ usageMessage: "Usage: /config show|set|unset",
2942
+ onKnownAction: (action, args) => {
2943
+ if (action === "show" || action === "get") return {
2944
+ action: "show",
2945
+ path: args || void 0
2946
+ };
2947
+ }
2948
+ });
2949
+ }
2950
+ //#endregion
2951
+ //#region src/auto-reply/reply/debug-commands.ts
2952
+ function parseDebugCommand(raw) {
2953
+ return parseStandardSetUnsetSlashCommand({
2954
+ raw,
2955
+ slash: "/debug",
2956
+ invalidMessage: "Invalid /debug syntax.",
2957
+ usageMessage: "Usage: /debug show|set|unset|reset",
2958
+ onKnownAction: (action) => {
2959
+ if (action === "show") return { action: "show" };
2960
+ if (action === "reset") return { action: "reset" };
2961
+ }
2962
+ });
2963
+ }
2964
+ //#endregion
2965
+ //#region src/auto-reply/reply/commands-config.ts
2966
+ const handleConfigCommand = async (params, allowTextCommands) => {
2967
+ if (!allowTextCommands) return null;
2968
+ const configCommand = parseConfigCommand(params.command.commandBodyNormalized);
2969
+ if (!configCommand) return null;
2970
+ const unauthorized = rejectUnauthorizedCommand(params, "/config");
2971
+ if (unauthorized) return unauthorized;
2972
+ const nonOwner = configCommand.action === "show" && isInternalMessageChannel(params.command.channel) ? null : rejectNonOwnerCommand(params, "/config");
2973
+ if (nonOwner) return nonOwner;
2974
+ const disabled = requireCommandFlagEnabled(params.cfg, {
2975
+ label: "/config",
2976
+ configKey: "config"
2977
+ });
2978
+ if (disabled) return disabled;
2979
+ if (configCommand.action === "error") return {
2980
+ shouldContinue: false,
2981
+ reply: { text: `⚠️ ${configCommand.message}` }
2982
+ };
2983
+ let parsedWritePath;
2984
+ if (configCommand.action === "set" || configCommand.action === "unset") {
2985
+ const missingAdminScope = requireGatewayClientScopeForInternalChannel(params, {
2986
+ label: "/config write",
2987
+ allowedScopes: ["operator.admin"],
2988
+ missingText: "❌ /config set|unset requires operator.admin for gateway clients."
2989
+ });
2990
+ if (missingAdminScope) return missingAdminScope;
2991
+ const parsedPath = parseConfigPath(configCommand.path);
2992
+ if (!parsedPath.ok || !parsedPath.path) return {
2993
+ shouldContinue: false,
2994
+ reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` }
2995
+ };
2996
+ parsedWritePath = parsedPath.path;
2997
+ const channelId = params.command.channelId ?? normalizeChannelId(params.command.channel);
2998
+ const deniedText = resolveConfigWriteDeniedText({
2999
+ cfg: params.cfg,
3000
+ channel: params.command.channel,
3001
+ channelId,
3002
+ accountId: params.ctx.AccountId,
3003
+ gatewayClientScopes: params.ctx.GatewayClientScopes,
3004
+ target: resolveConfigWriteTargetFromPath(parsedWritePath)
3005
+ });
3006
+ if (deniedText) return {
3007
+ shouldContinue: false,
3008
+ reply: { text: deniedText }
3009
+ };
3010
+ }
3011
+ const snapshot = await readConfigFileSnapshot();
3012
+ if (!snapshot.valid || !snapshot.parsed || typeof snapshot.parsed !== "object") return {
3013
+ shouldContinue: false,
3014
+ reply: { text: "⚠️ Config file is invalid; fix it before using /config." }
3015
+ };
3016
+ const parsedBase = structuredClone(snapshot.parsed);
3017
+ if (configCommand.action === "show") {
3018
+ const pathRaw = configCommand.path?.trim();
3019
+ if (pathRaw) {
3020
+ const parsedPath = parseConfigPath(pathRaw);
3021
+ if (!parsedPath.ok || !parsedPath.path) return {
3022
+ shouldContinue: false,
3023
+ reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` }
3024
+ };
3025
+ const value = getConfigValueAtPath(parsedBase, parsedPath.path);
3026
+ return {
3027
+ shouldContinue: false,
3028
+ reply: { text: `⚙️ Config ${pathRaw}:\n\`\`\`json\n${JSON.stringify(value ?? null, null, 2)}\n\`\`\`` }
3029
+ };
3030
+ }
3031
+ return {
3032
+ shouldContinue: false,
3033
+ reply: { text: `⚙️ Config (raw):\n\`\`\`json\n${JSON.stringify(parsedBase, null, 2)}\n\`\`\`` }
3034
+ };
3035
+ }
3036
+ if (configCommand.action === "unset") {
3037
+ if (!unsetConfigValueAtPath(parsedBase, parsedWritePath ?? [])) return {
3038
+ shouldContinue: false,
3039
+ reply: { text: `⚙️ No config value found for ${configCommand.path}.` }
3040
+ };
3041
+ const validated = validateConfigObjectWithPlugins(parsedBase);
3042
+ if (!validated.ok) {
3043
+ const issue = validated.issues[0];
3044
+ return {
3045
+ shouldContinue: false,
3046
+ reply: { text: `⚠️ Config invalid after unset (${issue.path}: ${issue.message}).` }
3047
+ };
3048
+ }
3049
+ await writeConfigFile(validated.config);
3050
+ return {
3051
+ shouldContinue: false,
3052
+ reply: { text: `⚙️ Config updated: ${configCommand.path} removed.` }
3053
+ };
3054
+ }
3055
+ if (configCommand.action === "set") {
3056
+ setConfigValueAtPath(parsedBase, parsedWritePath ?? [], configCommand.value);
3057
+ const validated = validateConfigObjectWithPlugins(parsedBase);
3058
+ if (!validated.ok) {
3059
+ const issue = validated.issues[0];
3060
+ return {
3061
+ shouldContinue: false,
3062
+ reply: { text: `⚠️ Config invalid after set (${issue.path}: ${issue.message}).` }
3063
+ };
3064
+ }
3065
+ await writeConfigFile(validated.config);
3066
+ const valueLabel = typeof configCommand.value === "string" ? `"${configCommand.value}"` : JSON.stringify(configCommand.value);
3067
+ return {
3068
+ shouldContinue: false,
3069
+ reply: { text: `⚙️ Config updated: ${configCommand.path}=${valueLabel ?? "null"}` }
3070
+ };
3071
+ }
3072
+ return null;
3073
+ };
3074
+ const handleDebugCommand = async (params, allowTextCommands) => {
3075
+ if (!allowTextCommands) return null;
3076
+ const debugCommand = parseDebugCommand(params.command.commandBodyNormalized);
3077
+ if (!debugCommand) return null;
3078
+ const unauthorized = rejectUnauthorizedCommand(params, "/debug");
3079
+ if (unauthorized) return unauthorized;
3080
+ const nonOwner = rejectNonOwnerCommand(params, "/debug");
3081
+ if (nonOwner) return nonOwner;
3082
+ const disabled = requireCommandFlagEnabled(params.cfg, {
3083
+ label: "/debug",
3084
+ configKey: "debug"
3085
+ });
3086
+ if (disabled) return disabled;
3087
+ if (debugCommand.action === "error") return {
3088
+ shouldContinue: false,
3089
+ reply: { text: `⚠️ ${debugCommand.message}` }
3090
+ };
3091
+ if (debugCommand.action === "show") {
3092
+ const overrides = getConfigOverrides();
3093
+ if (!(Object.keys(overrides).length > 0)) return {
3094
+ shouldContinue: false,
3095
+ reply: { text: "⚙️ Debug overrides: (none)" }
3096
+ };
3097
+ return {
3098
+ shouldContinue: false,
3099
+ reply: { text: `⚙️ Debug overrides (memory-only):\n\`\`\`json\n${JSON.stringify(overrides, null, 2)}\n\`\`\`` }
3100
+ };
3101
+ }
3102
+ if (debugCommand.action === "reset") {
3103
+ resetConfigOverrides();
3104
+ return {
3105
+ shouldContinue: false,
3106
+ reply: { text: "⚙️ Debug overrides cleared; using config on disk." }
3107
+ };
3108
+ }
3109
+ if (debugCommand.action === "unset") {
3110
+ const result = unsetConfigOverride(debugCommand.path);
3111
+ if (!result.ok) return {
3112
+ shouldContinue: false,
3113
+ reply: { text: `⚠️ ${result.error ?? "Invalid path."}` }
3114
+ };
3115
+ if (!result.removed) return {
3116
+ shouldContinue: false,
3117
+ reply: { text: `⚙️ No debug override found for ${debugCommand.path}.` }
3118
+ };
3119
+ return {
3120
+ shouldContinue: false,
3121
+ reply: { text: `⚙️ Debug override removed for ${debugCommand.path}.` }
3122
+ };
3123
+ }
3124
+ if (debugCommand.action === "set") {
3125
+ const result = setConfigOverride(debugCommand.path, debugCommand.value);
3126
+ if (!result.ok) return {
3127
+ shouldContinue: false,
3128
+ reply: { text: `⚠️ ${result.error ?? "Invalid override."}` }
3129
+ };
3130
+ const valueLabel = typeof debugCommand.value === "string" ? `"${debugCommand.value}"` : JSON.stringify(debugCommand.value);
3131
+ return {
3132
+ shouldContinue: false,
3133
+ reply: { text: `⚙️ Debug override set: ${debugCommand.path}=${valueLabel ?? "null"}` }
3134
+ };
3135
+ }
3136
+ return null;
3137
+ };
3138
+ //#endregion
3139
+ //#region src/auto-reply/reply/mcp-commands.ts
3140
+ function parseMcpCommand(raw) {
3141
+ return parseStandardSetUnsetSlashCommand({
3142
+ raw,
3143
+ slash: "/mcp",
3144
+ invalidMessage: "Invalid /mcp syntax.",
3145
+ usageMessage: "Usage: /mcp show|set|unset",
3146
+ onKnownAction: (action, args) => {
3147
+ if (action === "show" || action === "get") return {
3148
+ action: "show",
3149
+ name: args || void 0
3150
+ };
3151
+ },
3152
+ onSet: (name, value) => ({
3153
+ action: "set",
3154
+ name,
3155
+ value
3156
+ }),
3157
+ onUnset: (name) => ({
3158
+ action: "unset",
3159
+ name
3160
+ })
3161
+ });
3162
+ }
3163
+ //#endregion
3164
+ //#region src/auto-reply/reply/commands-mcp.ts
3165
+ function renderJsonBlock$1(label, value) {
3166
+ return `${label}\n\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``;
3167
+ }
3168
+ const handleMcpCommand = async (params, allowTextCommands) => {
3169
+ if (!allowTextCommands) return null;
3170
+ const mcpCommand = parseMcpCommand(params.command.commandBodyNormalized);
3171
+ if (!mcpCommand) return null;
3172
+ const unauthorized = rejectUnauthorizedCommand(params, "/mcp");
3173
+ if (unauthorized) return unauthorized;
3174
+ const nonOwner = mcpCommand.action === "show" && isInternalMessageChannel(params.command.channel) ? null : rejectNonOwnerCommand(params, "/mcp");
3175
+ if (nonOwner) return nonOwner;
3176
+ const disabled = requireCommandFlagEnabled(params.cfg, {
3177
+ label: "/mcp",
3178
+ configKey: "mcp"
3179
+ });
3180
+ if (disabled) return disabled;
3181
+ if (mcpCommand.action === "error") return {
3182
+ shouldContinue: false,
3183
+ reply: { text: `⚠️ ${mcpCommand.message}` }
3184
+ };
3185
+ if (mcpCommand.action === "show") {
3186
+ const loaded = await listConfiguredMcpServers();
3187
+ if (!loaded.ok) return {
3188
+ shouldContinue: false,
3189
+ reply: { text: `⚠️ ${loaded.error}` }
3190
+ };
3191
+ if (mcpCommand.name) {
3192
+ const server = loaded.mcpServers[mcpCommand.name];
3193
+ if (!server) return {
3194
+ shouldContinue: false,
3195
+ reply: { text: `🔌 No MCP server named "${mcpCommand.name}" in ${loaded.path}.` }
3196
+ };
3197
+ return {
3198
+ shouldContinue: false,
3199
+ reply: { text: renderJsonBlock$1(`🔌 MCP server "${mcpCommand.name}" (${loaded.path})`, server) }
3200
+ };
3201
+ }
3202
+ if (Object.keys(loaded.mcpServers).length === 0) return {
3203
+ shouldContinue: false,
3204
+ reply: { text: `🔌 No MCP servers configured in ${loaded.path}.` }
3205
+ };
3206
+ return {
3207
+ shouldContinue: false,
3208
+ reply: { text: renderJsonBlock$1(`🔌 MCP servers (${loaded.path})`, loaded.mcpServers) }
3209
+ };
3210
+ }
3211
+ const missingAdminScope = requireGatewayClientScopeForInternalChannel(params, {
3212
+ label: "/mcp write",
3213
+ allowedScopes: ["operator.admin"],
3214
+ missingText: "❌ /mcp set|unset requires operator.admin for gateway clients."
3215
+ });
3216
+ if (missingAdminScope) return missingAdminScope;
3217
+ if (mcpCommand.action === "set") {
3218
+ const result = await setConfiguredMcpServer({
3219
+ name: mcpCommand.name,
3220
+ server: mcpCommand.value
3221
+ });
3222
+ if (!result.ok) return {
3223
+ shouldContinue: false,
3224
+ reply: { text: `⚠️ ${result.error}` }
3225
+ };
3226
+ return {
3227
+ shouldContinue: false,
3228
+ reply: { text: `🔌 MCP server "${mcpCommand.name}" saved to ${result.path}.` }
3229
+ };
3230
+ }
3231
+ const result = await unsetConfiguredMcpServer({ name: mcpCommand.name });
3232
+ if (!result.ok) return {
3233
+ shouldContinue: false,
3234
+ reply: { text: `⚠️ ${result.error}` }
3235
+ };
3236
+ if (!result.removed) return {
3237
+ shouldContinue: false,
3238
+ reply: { text: `🔌 No MCP server named "${mcpCommand.name}" in ${result.path}.` }
3239
+ };
3240
+ return {
3241
+ shouldContinue: false,
3242
+ reply: { text: `🔌 MCP server "${mcpCommand.name}" removed from ${result.path}.` }
3243
+ };
3244
+ };
3245
+ //#endregion
3246
+ //#region src/auto-reply/reply/commands-plugin.ts
3247
+ /**
3248
+ * Plugin Command Handler
3249
+ *
3250
+ * Handles commands registered by plugins, bypassing the LLM agent.
3251
+ * This handler is called before built-in command handlers.
3252
+ */
3253
+ /**
3254
+ * Handle plugin-registered commands.
3255
+ * Returns a result if a plugin command was matched and executed,
3256
+ * or null to continue to the next handler.
3257
+ */
3258
+ const handlePluginCommand = async (params, allowTextCommands) => {
3259
+ const { command, cfg } = params;
3260
+ if (!allowTextCommands) return null;
3261
+ const match = matchPluginCommand(command.commandBodyNormalized);
3262
+ if (!match) return null;
3263
+ return {
3264
+ shouldContinue: false,
3265
+ reply: await executePluginCommand({
3266
+ command: match.command,
3267
+ args: match.args,
3268
+ senderId: command.senderId,
3269
+ channel: command.channel,
3270
+ channelId: command.channelId,
3271
+ isAuthorizedSender: command.isAuthorizedSender,
3272
+ commandBody: command.commandBodyNormalized,
3273
+ config: cfg,
3274
+ from: command.from,
3275
+ to: command.to,
3276
+ accountId: params.ctx.AccountId ?? void 0,
3277
+ messageThreadId: typeof params.ctx.MessageThreadId === "string" || typeof params.ctx.MessageThreadId === "number" ? params.ctx.MessageThreadId : void 0
3278
+ })
3279
+ };
3280
+ };
3281
+ //#endregion
3282
+ //#region src/auto-reply/reply/plugins-commands.ts
3283
+ function parsePluginsCommand(raw) {
3284
+ const match = raw.match(/^\/plugins?(?:\s+(.*))?$/i);
3285
+ if (!match) return null;
3286
+ const tail = match[1]?.trim() ?? "";
3287
+ if (!tail) return { action: "list" };
3288
+ const [rawAction, ...rest] = tail.split(/\s+/);
3289
+ const action = rawAction?.trim().toLowerCase();
3290
+ const name = rest.join(" ").trim();
3291
+ if (action === "list") return name ? {
3292
+ action: "error",
3293
+ message: "Usage: /plugins list|inspect|show|get|enable|disable [plugin]"
3294
+ } : { action: "list" };
3295
+ if (action === "inspect" || action === "show" || action === "get") return {
3296
+ action: "inspect",
3297
+ name: name || void 0
3298
+ };
3299
+ if (action === "enable" || action === "disable") {
3300
+ if (!name) return {
3301
+ action: "error",
3302
+ message: `Usage: /plugins ${action} <plugin-id-or-name>`
3303
+ };
3304
+ return {
3305
+ action,
3306
+ name
3307
+ };
3308
+ }
3309
+ return {
3310
+ action: "error",
3311
+ message: "Usage: /plugins list|inspect|show|get|enable|disable [plugin]"
3312
+ };
3313
+ }
3314
+ //#endregion
3315
+ //#region src/auto-reply/reply/commands-plugins.ts
3316
+ function renderJsonBlock(label, value) {
3317
+ return `${label}\n\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``;
3318
+ }
3319
+ function buildPluginInspectJson(params) {
3320
+ const inspect = buildPluginInspectReport({
3321
+ id: params.id,
3322
+ config: params.config,
3323
+ report: params.report
3324
+ });
3325
+ if (!inspect) return null;
3326
+ return {
3327
+ inspect,
3328
+ compatibilityWarnings: inspect.compatibility.map((warning) => ({
3329
+ code: warning.code,
3330
+ severity: warning.severity,
3331
+ message: formatPluginCompatibilityNotice(warning)
3332
+ })),
3333
+ install: params.config.plugins?.installs?.[inspect.plugin.id] ?? null
3334
+ };
3335
+ }
3336
+ function buildAllPluginInspectJson(params) {
3337
+ return buildAllPluginInspectReports({
3338
+ config: params.config,
3339
+ report: params.report
3340
+ }).map((inspect) => ({
3341
+ inspect,
3342
+ compatibilityWarnings: inspect.compatibility.map((warning) => ({
3343
+ code: warning.code,
3344
+ severity: warning.severity,
3345
+ message: formatPluginCompatibilityNotice(warning)
3346
+ })),
3347
+ install: params.config.plugins?.installs?.[inspect.plugin.id] ?? null
3348
+ }));
3349
+ }
3350
+ function formatPluginLabel(plugin) {
3351
+ if (!plugin.name || plugin.name === plugin.id) return plugin.id;
3352
+ return `${plugin.name} (${plugin.id})`;
3353
+ }
3354
+ function formatPluginsList(report) {
3355
+ if (report.plugins.length === 0) return `🔌 No plugins found for workspace ${report.workspaceDir ?? "(unknown workspace)"}.`;
3356
+ return [`🔌 Plugins (${report.plugins.filter((plugin) => plugin.status === "loaded").length}/${report.plugins.length} loaded)`, ...report.plugins.map((plugin) => {
3357
+ const format = plugin.bundleFormat ? `${plugin.format ?? "openclaw"}/${plugin.bundleFormat}` : plugin.format ?? "openclaw";
3358
+ return `- ${formatPluginLabel(plugin)} [${plugin.status}] ${format}`;
3359
+ })].join("\n");
3360
+ }
3361
+ function findPlugin(report, rawName) {
3362
+ const target = rawName.trim().toLowerCase();
3363
+ if (!target) return;
3364
+ return report.plugins.find((plugin) => plugin.id.toLowerCase() === target || plugin.name.toLowerCase() === target);
3365
+ }
3366
+ async function loadPluginCommandState(workspaceDir) {
3367
+ const snapshot = await readConfigFileSnapshot();
3368
+ if (!snapshot.valid) return {
3369
+ ok: false,
3370
+ path: snapshot.path,
3371
+ error: "Config file is invalid; fix it before using /plugins."
3372
+ };
3373
+ const config = structuredClone(snapshot.resolved);
3374
+ return {
3375
+ ok: true,
3376
+ path: snapshot.path,
3377
+ config,
3378
+ report: buildPluginStatusReport({
3379
+ config,
3380
+ workspaceDir
3381
+ })
3382
+ };
3383
+ }
3384
+ const handlePluginsCommand = async (params, allowTextCommands) => {
3385
+ if (!allowTextCommands) return null;
3386
+ const pluginsCommand = parsePluginsCommand(params.command.commandBodyNormalized);
3387
+ if (!pluginsCommand) return null;
3388
+ const unauthorized = rejectUnauthorizedCommand(params, "/plugins");
3389
+ if (unauthorized) return unauthorized;
3390
+ const nonOwner = (pluginsCommand.action === "list" || pluginsCommand.action === "inspect") && isInternalMessageChannel(params.command.channel) ? null : rejectNonOwnerCommand(params, "/plugins");
3391
+ if (nonOwner) return nonOwner;
3392
+ const disabled = requireCommandFlagEnabled(params.cfg, {
3393
+ label: "/plugins",
3394
+ configKey: "plugins"
3395
+ });
3396
+ if (disabled) return disabled;
3397
+ if (pluginsCommand.action === "error") return {
3398
+ shouldContinue: false,
3399
+ reply: { text: `⚠️ ${pluginsCommand.message}` }
3400
+ };
3401
+ const loaded = await loadPluginCommandState(params.workspaceDir);
3402
+ if (!loaded.ok) return {
3403
+ shouldContinue: false,
3404
+ reply: { text: `⚠️ ${loaded.error}` }
3405
+ };
3406
+ if (pluginsCommand.action === "list") return {
3407
+ shouldContinue: false,
3408
+ reply: { text: formatPluginsList(loaded.report) }
3409
+ };
3410
+ if (pluginsCommand.action === "inspect") {
3411
+ if (!pluginsCommand.name) return {
3412
+ shouldContinue: false,
3413
+ reply: { text: formatPluginsList(loaded.report) }
3414
+ };
3415
+ if (pluginsCommand.name.toLowerCase() === "all") return {
3416
+ shouldContinue: false,
3417
+ reply: { text: renderJsonBlock("🔌 Plugins", buildAllPluginInspectJson(loaded)) }
3418
+ };
3419
+ const payload = buildPluginInspectJson({
3420
+ id: pluginsCommand.name,
3421
+ config: loaded.config,
3422
+ report: loaded.report
3423
+ });
3424
+ if (!payload) return {
3425
+ shouldContinue: false,
3426
+ reply: { text: `🔌 No plugin named "${pluginsCommand.name}" found.` }
3427
+ };
3428
+ return {
3429
+ shouldContinue: false,
3430
+ reply: { text: renderJsonBlock(`🔌 Plugin "${payload.inspect.plugin.id}"`, {
3431
+ ...payload.inspect,
3432
+ install: payload.install
3433
+ }) }
3434
+ };
3435
+ }
3436
+ const missingAdminScope = requireGatewayClientScopeForInternalChannel(params, {
3437
+ label: "/plugins write",
3438
+ allowedScopes: ["operator.admin"],
3439
+ missingText: "❌ /plugins enable|disable requires operator.admin for gateway clients."
3440
+ });
3441
+ if (missingAdminScope) return missingAdminScope;
3442
+ const plugin = findPlugin(loaded.report, pluginsCommand.name);
3443
+ if (!plugin) return {
3444
+ shouldContinue: false,
3445
+ reply: { text: `🔌 No plugin named "${pluginsCommand.name}" found.` }
3446
+ };
3447
+ const validated = validateConfigObjectWithPlugins(setPluginEnabledInConfig(structuredClone(loaded.config), plugin.id, pluginsCommand.action === "enable"));
3448
+ if (!validated.ok) {
3449
+ const issue = validated.issues[0];
3450
+ return {
3451
+ shouldContinue: false,
3452
+ reply: { text: `⚠️ Config invalid after /plugins ${pluginsCommand.action} (${issue.path}: ${issue.message}).` }
3453
+ };
3454
+ }
3455
+ await writeConfigFile(validated.config);
3456
+ return {
3457
+ shouldContinue: false,
3458
+ reply: { text: `🔌 Plugin "${plugin.id}" ${pluginsCommand.action}d in ${loaded.path}. Restart the gateway to apply.` }
3459
+ };
3460
+ };
3461
+ //#endregion
3462
+ //#region src/auto-reply/send-policy.ts
3463
+ function normalizeSendPolicyOverride(raw) {
3464
+ const value = raw?.trim().toLowerCase();
3465
+ if (!value) return;
3466
+ if (value === "allow" || value === "on") return "allow";
3467
+ if (value === "deny" || value === "off") return "deny";
3468
+ }
3469
+ function parseSendPolicyCommand(raw) {
3470
+ if (!raw) return { hasCommand: false };
3471
+ const trimmed = raw.trim();
3472
+ if (!trimmed) return { hasCommand: false };
3473
+ const match = normalizeCommandBody(trimmed).match(/^\/send(?:\s+([a-zA-Z]+))?\s*$/i);
3474
+ if (!match) return { hasCommand: false };
3475
+ const token = match[1]?.trim().toLowerCase();
3476
+ if (!token) return { hasCommand: true };
3477
+ if (token === "inherit" || token === "default" || token === "reset") return {
3478
+ hasCommand: true,
3479
+ mode: "inherit"
3480
+ };
3481
+ return {
3482
+ hasCommand: true,
3483
+ mode: normalizeSendPolicyOverride(token)
3484
+ };
3485
+ }
3486
+ //#endregion
3487
+ //#region src/auto-reply/reply/commands-session-store.ts
3488
+ async function persistSessionEntry(params) {
3489
+ if (!params.sessionEntry || !params.sessionStore || !params.sessionKey) return false;
3490
+ params.sessionEntry.updatedAt = Date.now();
3491
+ params.sessionStore[params.sessionKey] = params.sessionEntry;
3492
+ if (params.storePath) await updateSessionStore(params.storePath, (store) => {
3493
+ store[params.sessionKey] = params.sessionEntry;
3494
+ });
3495
+ return true;
3496
+ }
3497
+ async function persistAbortTargetEntry(params) {
3498
+ const { entry, key, sessionStore, storePath, abortCutoff } = params;
3499
+ if (!entry || !key || !sessionStore) return false;
3500
+ entry.abortedLastRun = true;
3501
+ applyAbortCutoffToSessionEntry(entry, abortCutoff);
3502
+ entry.updatedAt = Date.now();
3503
+ sessionStore[key] = entry;
3504
+ if (storePath) await updateSessionStore(storePath, (store) => {
3505
+ const nextEntry = store[key] ?? entry;
3506
+ if (!nextEntry) return;
3507
+ nextEntry.abortedLastRun = true;
3508
+ applyAbortCutoffToSessionEntry(nextEntry, abortCutoff);
3509
+ nextEntry.updatedAt = Date.now();
3510
+ store[key] = nextEntry;
3511
+ });
3512
+ return true;
3513
+ }
3514
+ //#endregion
3515
+ //#region src/auto-reply/reply/commands-session-abort.ts
3516
+ function resolveAbortTarget(params) {
3517
+ const targetSessionKey = params.ctx.CommandTargetSessionKey?.trim() || params.sessionKey;
3518
+ const { entry, key } = resolveSessionEntryForKey(params.sessionStore, targetSessionKey);
3519
+ if (entry && key) return {
3520
+ entry,
3521
+ key,
3522
+ sessionId: entry.sessionId
3523
+ };
3524
+ if (params.sessionEntry && params.sessionKey) return {
3525
+ entry: params.sessionEntry,
3526
+ key: params.sessionKey,
3527
+ sessionId: params.sessionEntry.sessionId
3528
+ };
3529
+ return {
3530
+ entry: void 0,
3531
+ key: targetSessionKey,
3532
+ sessionId: void 0
3533
+ };
3534
+ }
3535
+ function resolveAbortCutoffForTarget(params) {
3536
+ if (!shouldPersistAbortCutoff({
3537
+ commandSessionKey: params.commandSessionKey,
3538
+ targetSessionKey: params.targetSessionKey
3539
+ })) return;
3540
+ return resolveAbortCutoffFromContext(params.ctx);
3541
+ }
3542
+ async function applyAbortTarget(params) {
3543
+ const { abortTarget } = params;
3544
+ if (abortTarget.sessionId) abortEmbeddedPiRun(abortTarget.sessionId);
3545
+ if (!await persistAbortTargetEntry({
3546
+ entry: abortTarget.entry,
3547
+ key: abortTarget.key,
3548
+ sessionStore: params.sessionStore,
3549
+ storePath: params.storePath,
3550
+ abortCutoff: params.abortCutoff
3551
+ }) && params.abortKey) setAbortMemory(params.abortKey, true);
3552
+ }
3553
+ function buildAbortTargetApplyParams(params, abortTarget) {
3554
+ return {
3555
+ abortTarget,
3556
+ sessionStore: params.sessionStore,
3557
+ storePath: params.storePath,
3558
+ abortKey: params.command.abortKey,
3559
+ abortCutoff: resolveAbortCutoffForTarget({
3560
+ ctx: params.ctx,
3561
+ commandSessionKey: params.sessionKey,
3562
+ targetSessionKey: abortTarget.key
3563
+ })
3564
+ };
3565
+ }
3566
+ const handleStopCommand = async (params, allowTextCommands) => {
3567
+ if (!allowTextCommands) return null;
3568
+ if (params.command.commandBodyNormalized !== "/stop") return null;
3569
+ const unauthorizedStop = rejectUnauthorizedCommand(params, "/stop");
3570
+ if (unauthorizedStop) return unauthorizedStop;
3571
+ const abortTarget = resolveAbortTarget({
3572
+ ctx: params.ctx,
3573
+ sessionKey: params.sessionKey,
3574
+ sessionEntry: params.sessionEntry,
3575
+ sessionStore: params.sessionStore
3576
+ });
3577
+ const cleared = clearSessionQueues([abortTarget.key, abortTarget.sessionId]);
3578
+ if (cleared.followupCleared > 0 || cleared.laneCleared > 0) logVerbose(`stop: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`);
3579
+ await applyAbortTarget(buildAbortTargetApplyParams(params, abortTarget));
3580
+ await triggerInternalHook(createInternalHookEvent("command", "stop", abortTarget.key ?? params.sessionKey ?? "", {
3581
+ sessionEntry: abortTarget.entry ?? params.sessionEntry,
3582
+ sessionId: abortTarget.sessionId,
3583
+ commandSource: params.command.surface,
3584
+ senderId: params.command.senderId
3585
+ }));
3586
+ const { stopped } = stopSubagentsForRequester({
3587
+ cfg: params.cfg,
3588
+ requesterSessionKey: abortTarget.key ?? params.sessionKey
3589
+ });
3590
+ return {
3591
+ shouldContinue: false,
3592
+ reply: { text: formatAbortReplyText(stopped) }
3593
+ };
3594
+ };
3595
+ const handleAbortTrigger = async (params, allowTextCommands) => {
3596
+ if (!allowTextCommands) return null;
3597
+ if (!isAbortTrigger(params.command.rawBodyNormalized)) return null;
3598
+ const unauthorizedAbortTrigger = rejectUnauthorizedCommand(params, "abort trigger");
3599
+ if (unauthorizedAbortTrigger) return unauthorizedAbortTrigger;
3600
+ await applyAbortTarget(buildAbortTargetApplyParams(params, resolveAbortTarget({
3601
+ ctx: params.ctx,
3602
+ sessionKey: params.sessionKey,
3603
+ sessionEntry: params.sessionEntry,
3604
+ sessionStore: params.sessionStore
3605
+ })));
3606
+ return {
3607
+ shouldContinue: false,
3608
+ reply: { text: "⚙️ Agent was aborted." }
3609
+ };
3610
+ };
3611
+ //#endregion
3612
+ //#region src/auto-reply/reply/commands-session.ts
3613
+ const SESSION_DURATION_OFF_VALUES = new Set([
3614
+ "off",
3615
+ "disable",
3616
+ "disabled",
3617
+ "none",
3618
+ "0"
3619
+ ]);
3620
+ const SESSION_ACTION_IDLE = "idle";
3621
+ const SESSION_ACTION_MAX_AGE = "max-age";
3622
+ let cachedChannelRuntime;
3623
+ function getChannelRuntime() {
3624
+ cachedChannelRuntime ??= createPluginRuntime().channel;
3625
+ return cachedChannelRuntime;
3626
+ }
3627
+ function resolveSessionCommandUsage() {
3628
+ return "Usage: /session idle <duration|off> | /session max-age <duration|off> (example: /session idle 24h)";
3629
+ }
3630
+ function parseSessionDurationMs(raw) {
3631
+ const normalized = raw.trim().toLowerCase();
3632
+ if (!normalized) throw new Error("missing duration");
3633
+ if (SESSION_DURATION_OFF_VALUES.has(normalized)) return 0;
3634
+ if (/^\d+(?:\.\d+)?$/.test(normalized)) {
3635
+ const hours = Number(normalized);
3636
+ if (!Number.isFinite(hours) || hours < 0) throw new Error("invalid duration");
3637
+ return Math.round(hours * 60 * 60 * 1e3);
3638
+ }
3639
+ return parseDurationMs(normalized, { defaultUnit: "h" });
3640
+ }
3641
+ function formatSessionExpiry(expiresAt) {
3642
+ return new Date(expiresAt).toISOString();
3643
+ }
3644
+ function resolveSessionBindingDurationMs(binding, key, fallbackMs) {
3645
+ const raw = binding.metadata?.[key];
3646
+ if (typeof raw !== "number" || !Number.isFinite(raw)) return fallbackMs;
3647
+ return Math.max(0, Math.floor(raw));
3648
+ }
3649
+ function resolveSessionBindingLastActivityAt(binding) {
3650
+ const raw = binding.metadata?.lastActivityAt;
3651
+ if (typeof raw !== "number" || !Number.isFinite(raw)) return binding.boundAt;
3652
+ return Math.max(Math.floor(raw), binding.boundAt);
3653
+ }
3654
+ function resolveSessionBindingBoundBy(binding) {
3655
+ const raw = binding.metadata?.boundBy;
3656
+ return typeof raw === "string" ? raw.trim() : "";
3657
+ }
3658
+ function isSessionBindingRecord(binding) {
3659
+ return "bindingId" in binding;
3660
+ }
3661
+ function resolveUpdatedLifecycleDurationMs(binding, key) {
3662
+ if (!isSessionBindingRecord(binding)) {
3663
+ const raw = binding[key];
3664
+ if (typeof raw === "number" && Number.isFinite(raw)) return Math.max(0, Math.floor(raw));
3665
+ }
3666
+ if (!isSessionBindingRecord(binding)) return;
3667
+ const raw = binding.metadata?.[key];
3668
+ if (typeof raw !== "number" || !Number.isFinite(raw)) return;
3669
+ return Math.max(0, Math.floor(raw));
3670
+ }
3671
+ function toUpdatedLifecycleBinding(binding) {
3672
+ const lastActivityAt = isSessionBindingRecord(binding) ? resolveSessionBindingLastActivityAt(binding) : Math.max(Math.floor(binding.lastActivityAt), binding.boundAt);
3673
+ return {
3674
+ boundAt: binding.boundAt,
3675
+ lastActivityAt,
3676
+ idleTimeoutMs: resolveUpdatedLifecycleDurationMs(binding, "idleTimeoutMs"),
3677
+ maxAgeMs: resolveUpdatedLifecycleDurationMs(binding, "maxAgeMs")
3678
+ };
3679
+ }
3680
+ function resolveUpdatedBindingExpiry(params) {
3681
+ const expiries = params.bindings.map((binding) => {
3682
+ if (params.action === SESSION_ACTION_IDLE) {
3683
+ const idleTimeoutMs = typeof binding.idleTimeoutMs === "number" && Number.isFinite(binding.idleTimeoutMs) ? Math.max(0, Math.floor(binding.idleTimeoutMs)) : 0;
3684
+ if (idleTimeoutMs <= 0) return;
3685
+ return Math.max(binding.lastActivityAt, binding.boundAt) + idleTimeoutMs;
3686
+ }
3687
+ const maxAgeMs = typeof binding.maxAgeMs === "number" && Number.isFinite(binding.maxAgeMs) ? Math.max(0, Math.floor(binding.maxAgeMs)) : 0;
3688
+ if (maxAgeMs <= 0) return;
3689
+ return binding.boundAt + maxAgeMs;
3690
+ }).filter((expiresAt) => typeof expiresAt === "number");
3691
+ if (expiries.length === 0) return;
3692
+ return Math.min(...expiries);
3693
+ }
3694
+ const handleActivationCommand = async (params, allowTextCommands) => {
3695
+ if (!allowTextCommands) return null;
3696
+ const activationCommand = parseActivationCommand(params.command.commandBodyNormalized);
3697
+ if (!activationCommand.hasCommand) return null;
3698
+ if (!params.isGroup) return {
3699
+ shouldContinue: false,
3700
+ reply: { text: "⚙️ Group activation only applies to group chats." }
3701
+ };
3702
+ if (!params.command.isAuthorizedSender) {
3703
+ logVerbose(`Ignoring /activation from unauthorized sender in group: ${params.command.senderId || "<unknown>"}`);
3704
+ return { shouldContinue: false };
3705
+ }
3706
+ if (!activationCommand.mode) return {
3707
+ shouldContinue: false,
3708
+ reply: { text: "⚙️ Usage: /activation mention|always" }
3709
+ };
3710
+ if (params.sessionEntry && params.sessionStore && params.sessionKey) {
3711
+ params.sessionEntry.groupActivation = activationCommand.mode;
3712
+ params.sessionEntry.groupActivationNeedsSystemIntro = true;
3713
+ await persistSessionEntry(params);
3714
+ }
3715
+ return {
3716
+ shouldContinue: false,
3717
+ reply: { text: `⚙️ Group activation set to ${activationCommand.mode}.` }
3718
+ };
3719
+ };
3720
+ const handleSendPolicyCommand = async (params, allowTextCommands) => {
3721
+ if (!allowTextCommands) return null;
3722
+ const sendPolicyCommand = parseSendPolicyCommand(params.command.commandBodyNormalized);
3723
+ if (!sendPolicyCommand.hasCommand) return null;
3724
+ if (!params.command.isAuthorizedSender) {
3725
+ logVerbose(`Ignoring /send from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
3726
+ return { shouldContinue: false };
3727
+ }
3728
+ if (!sendPolicyCommand.mode) return {
3729
+ shouldContinue: false,
3730
+ reply: { text: "⚙️ Usage: /send on|off|inherit" }
3731
+ };
3732
+ if (params.sessionEntry && params.sessionStore && params.sessionKey) {
3733
+ if (sendPolicyCommand.mode === "inherit") delete params.sessionEntry.sendPolicy;
3734
+ else params.sessionEntry.sendPolicy = sendPolicyCommand.mode;
3735
+ await persistSessionEntry(params);
3736
+ }
3737
+ return {
3738
+ shouldContinue: false,
3739
+ reply: { text: `⚙️ Send policy set to ${sendPolicyCommand.mode === "inherit" ? "inherit" : sendPolicyCommand.mode === "allow" ? "on" : "off"}.` }
3740
+ };
3741
+ };
3742
+ const handleUsageCommand = async (params, allowTextCommands) => {
3743
+ if (!allowTextCommands) return null;
3744
+ const normalized = params.command.commandBodyNormalized;
3745
+ if (normalized !== "/usage" && !normalized.startsWith("/usage ")) return null;
3746
+ if (!params.command.isAuthorizedSender) {
3747
+ logVerbose(`Ignoring /usage from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
3748
+ return { shouldContinue: false };
3749
+ }
3750
+ const rawArgs = normalized === "/usage" ? "" : normalized.slice(6).trim();
3751
+ const requested = rawArgs ? normalizeUsageDisplay(rawArgs) : void 0;
3752
+ if (rawArgs.toLowerCase().startsWith("cost")) {
3753
+ const sessionSummary = await loadSessionCostSummary({
3754
+ sessionId: params.sessionEntry?.sessionId,
3755
+ sessionEntry: params.sessionEntry,
3756
+ sessionFile: params.sessionEntry?.sessionFile,
3757
+ config: params.cfg,
3758
+ agentId: params.agentId
3759
+ });
3760
+ const summary = await loadCostUsageSummary({
3761
+ days: 30,
3762
+ config: params.cfg
3763
+ });
3764
+ const sessionCost = formatUsd(sessionSummary?.totalCost);
3765
+ const sessionTokens = sessionSummary?.totalTokens ? formatTokenCount$1(sessionSummary.totalTokens) : void 0;
3766
+ const sessionSuffix = (sessionSummary?.missingCostEntries ?? 0) > 0 ? " (partial)" : "";
3767
+ const sessionLine = sessionCost || sessionTokens ? `Session ${sessionCost ?? "n/a"}${sessionSuffix}${sessionTokens ? ` · ${sessionTokens} tokens` : ""}` : "Session n/a";
3768
+ const todayKey = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA");
3769
+ const todayEntry = summary.daily.find((entry) => entry.date === todayKey);
3770
+ const todayCost = formatUsd(todayEntry?.totalCost);
3771
+ const todaySuffix = (todayEntry?.missingCostEntries ?? 0) > 0 ? " (partial)" : "";
3772
+ const todayLine = `Today ${todayCost ?? "n/a"}${todaySuffix}`;
3773
+ const last30Cost = formatUsd(summary.totals.totalCost);
3774
+ const last30Suffix = summary.totals.missingCostEntries > 0 ? " (partial)" : "";
3775
+ return {
3776
+ shouldContinue: false,
3777
+ reply: { text: `💸 Usage cost\n${sessionLine}\n${todayLine}\n${`Last 30d ${last30Cost ?? "n/a"}${last30Suffix}`}` }
3778
+ };
3779
+ }
3780
+ if (rawArgs && !requested) return {
3781
+ shouldContinue: false,
3782
+ reply: { text: "⚙️ Usage: /usage off|tokens|full|cost" }
3783
+ };
3784
+ const current = resolveResponseUsageMode(params.sessionEntry?.responseUsage ?? (params.sessionKey ? params.sessionStore?.[params.sessionKey]?.responseUsage : void 0));
3785
+ const next = requested ?? (current === "off" ? "tokens" : current === "tokens" ? "full" : "off");
3786
+ if (params.sessionEntry && params.sessionStore && params.sessionKey) {
3787
+ if (next === "off") delete params.sessionEntry.responseUsage;
3788
+ else params.sessionEntry.responseUsage = next;
3789
+ await persistSessionEntry(params);
3790
+ }
3791
+ return {
3792
+ shouldContinue: false,
3793
+ reply: { text: `⚙️ Usage footer: ${next}.` }
3794
+ };
3795
+ };
3796
+ const handleFastCommand = async (params, allowTextCommands) => {
3797
+ if (!allowTextCommands) return null;
3798
+ const normalized = params.command.commandBodyNormalized;
3799
+ if (normalized !== "/fast" && !normalized.startsWith("/fast ")) return null;
3800
+ if (!params.command.isAuthorizedSender) {
3801
+ logVerbose(`Ignoring /fast from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
3802
+ return { shouldContinue: false };
3803
+ }
3804
+ const rawMode = (normalized === "/fast" ? "" : normalized.slice(5).trim()).toLowerCase();
3805
+ if (!rawMode || rawMode === "status") {
3806
+ const state = resolveFastModeState({
3807
+ cfg: params.cfg,
3808
+ provider: params.provider,
3809
+ model: params.model,
3810
+ agentId: params.agentId,
3811
+ sessionEntry: params.sessionEntry
3812
+ });
3813
+ const suffix = state.source === "agent" ? " (agent)" : state.source === "config" ? " (config)" : state.source === "default" ? " (default)" : "";
3814
+ return {
3815
+ shouldContinue: false,
3816
+ reply: { text: `⚙️ Current fast mode: ${state.enabled ? "on" : "off"}${suffix}.` }
3817
+ };
3818
+ }
3819
+ const nextMode = normalizeFastMode(rawMode);
3820
+ if (nextMode === void 0) return {
3821
+ shouldContinue: false,
3822
+ reply: { text: "⚙️ Usage: /fast status|on|off" }
3823
+ };
3824
+ if (params.sessionEntry && params.sessionStore && params.sessionKey) {
3825
+ params.sessionEntry.fastMode = nextMode;
3826
+ await persistSessionEntry(params);
3827
+ }
3828
+ return {
3829
+ shouldContinue: false,
3830
+ reply: { text: `⚙️ Fast mode ${nextMode ? "enabled" : "disabled"}.` }
3831
+ };
3832
+ };
3833
+ const handleSessionCommand = async (params, allowTextCommands) => {
3834
+ if (!allowTextCommands) return null;
3835
+ const normalized = params.command.commandBodyNormalized;
3836
+ if (!/^\/session(?:\s|$)/.test(normalized)) return null;
3837
+ if (!params.command.isAuthorizedSender) {
3838
+ logVerbose(`Ignoring /session from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
3839
+ return { shouldContinue: false };
3840
+ }
3841
+ const tokens = normalized.slice(8).trim().split(/\s+/).filter(Boolean);
3842
+ const action = tokens[0]?.toLowerCase();
3843
+ if (action !== SESSION_ACTION_IDLE && action !== SESSION_ACTION_MAX_AGE) return {
3844
+ shouldContinue: false,
3845
+ reply: { text: resolveSessionCommandUsage() }
3846
+ };
3847
+ const onDiscord = isDiscordSurface(params);
3848
+ const onMatrix = isMatrixSurface(params);
3849
+ const onTelegram = isTelegramSurface(params);
3850
+ if (!onDiscord && !onMatrix && !onTelegram) return {
3851
+ shouldContinue: false,
3852
+ reply: { text: "⚠️ /session idle and /session max-age are currently available for Discord, Matrix, and Telegram bound sessions." }
3853
+ };
3854
+ const accountId = resolveChannelAccountId(params);
3855
+ const sessionBindingService = getSessionBindingService();
3856
+ const threadId = params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId).trim() : "";
3857
+ const matrixConversationId = onMatrix ? resolveMatrixConversationId({
3858
+ ctx: {
3859
+ MessageThreadId: params.ctx.MessageThreadId,
3860
+ OriginatingTo: params.ctx.OriginatingTo,
3861
+ To: params.ctx.To
3862
+ },
3863
+ command: { to: params.command.to }
3864
+ }) : void 0;
3865
+ const matrixParentConversationId = onMatrix ? resolveMatrixParentConversationId({
3866
+ ctx: {
3867
+ MessageThreadId: params.ctx.MessageThreadId,
3868
+ OriginatingTo: params.ctx.OriginatingTo,
3869
+ To: params.ctx.To
3870
+ },
3871
+ command: { to: params.command.to }
3872
+ }) : void 0;
3873
+ const telegramConversationId = onTelegram ? resolveTelegramConversationId(params) : void 0;
3874
+ const channelRuntime = getChannelRuntime();
3875
+ const discordManager = onDiscord ? channelRuntime.discord.threadBindings.getManager(accountId) : null;
3876
+ if (onDiscord && !discordManager) return {
3877
+ shouldContinue: false,
3878
+ reply: { text: "⚠️ Discord thread bindings are unavailable for this account." }
3879
+ };
3880
+ const discordBinding = onDiscord && threadId ? discordManager?.getByThreadId(threadId) : void 0;
3881
+ const telegramBinding = onTelegram && telegramConversationId ? sessionBindingService.resolveByConversation({
3882
+ channel: "telegram",
3883
+ accountId,
3884
+ conversationId: telegramConversationId
3885
+ }) : null;
3886
+ const matrixBinding = onMatrix && matrixConversationId ? sessionBindingService.resolveByConversation({
3887
+ channel: "matrix",
3888
+ accountId,
3889
+ conversationId: matrixConversationId,
3890
+ ...matrixParentConversationId && matrixParentConversationId !== matrixConversationId ? { parentConversationId: matrixParentConversationId } : {}
3891
+ }) : null;
3892
+ if (onDiscord && !discordBinding) {
3893
+ if (onDiscord && !threadId) return {
3894
+ shouldContinue: false,
3895
+ reply: { text: "⚠️ /session idle and /session max-age must be run inside a focused Discord thread." }
3896
+ };
3897
+ return {
3898
+ shouldContinue: false,
3899
+ reply: { text: "ℹ️ This thread is not currently focused." }
3900
+ };
3901
+ }
3902
+ if (onMatrix && !matrixBinding) {
3903
+ if (!threadId) return {
3904
+ shouldContinue: false,
3905
+ reply: { text: "⚠️ /session idle and /session max-age must be run inside a focused Matrix thread." }
3906
+ };
3907
+ return {
3908
+ shouldContinue: false,
3909
+ reply: { text: "ℹ️ This thread is not currently focused." }
3910
+ };
3911
+ }
3912
+ if (onTelegram && !telegramBinding) {
3913
+ if (!telegramConversationId) return {
3914
+ shouldContinue: false,
3915
+ reply: { text: "⚠️ /session idle and /session max-age on Telegram require a topic context in groups, or a direct-message conversation." }
3916
+ };
3917
+ return {
3918
+ shouldContinue: false,
3919
+ reply: { text: "ℹ️ This conversation is not currently focused." }
3920
+ };
3921
+ }
3922
+ const idleTimeoutMs = onDiscord ? channelRuntime.discord.threadBindings.resolveIdleTimeoutMs({
3923
+ record: discordBinding,
3924
+ defaultIdleTimeoutMs: discordManager.getIdleTimeoutMs()
3925
+ }) : resolveSessionBindingDurationMs(onMatrix ? matrixBinding : telegramBinding, "idleTimeoutMs", 1440 * 60 * 1e3);
3926
+ const idleExpiresAt = onDiscord ? channelRuntime.discord.threadBindings.resolveInactivityExpiresAt({
3927
+ record: discordBinding,
3928
+ defaultIdleTimeoutMs: discordManager.getIdleTimeoutMs()
3929
+ }) : idleTimeoutMs > 0 ? resolveSessionBindingLastActivityAt(onMatrix ? matrixBinding : telegramBinding) + idleTimeoutMs : void 0;
3930
+ const maxAgeMs = onDiscord ? channelRuntime.discord.threadBindings.resolveMaxAgeMs({
3931
+ record: discordBinding,
3932
+ defaultMaxAgeMs: discordManager.getMaxAgeMs()
3933
+ }) : resolveSessionBindingDurationMs(onMatrix ? matrixBinding : telegramBinding, "maxAgeMs", 0);
3934
+ const maxAgeExpiresAt = onDiscord ? channelRuntime.discord.threadBindings.resolveMaxAgeExpiresAt({
3935
+ record: discordBinding,
3936
+ defaultMaxAgeMs: discordManager.getMaxAgeMs()
3937
+ }) : maxAgeMs > 0 ? (onMatrix ? matrixBinding : telegramBinding).boundAt + maxAgeMs : void 0;
3938
+ const durationArgRaw = tokens.slice(1).join("");
3939
+ if (!durationArgRaw) {
3940
+ if (action === SESSION_ACTION_IDLE) {
3941
+ if (typeof idleExpiresAt === "number" && Number.isFinite(idleExpiresAt) && idleExpiresAt > Date.now()) return {
3942
+ shouldContinue: false,
3943
+ reply: { text: `ℹ️ Idle timeout active (${formatThreadBindingDurationLabel(idleTimeoutMs)}, next auto-unfocus at ${formatSessionExpiry(idleExpiresAt)}).` }
3944
+ };
3945
+ return {
3946
+ shouldContinue: false,
3947
+ reply: { text: "ℹ️ Idle timeout is currently disabled for this focused session." }
3948
+ };
3949
+ }
3950
+ if (typeof maxAgeExpiresAt === "number" && Number.isFinite(maxAgeExpiresAt) && maxAgeExpiresAt > Date.now()) return {
3951
+ shouldContinue: false,
3952
+ reply: { text: `ℹ️ Max age active (${formatThreadBindingDurationLabel(maxAgeMs)}, hard auto-unfocus at ${formatSessionExpiry(maxAgeExpiresAt)}).` }
3953
+ };
3954
+ return {
3955
+ shouldContinue: false,
3956
+ reply: { text: "ℹ️ Max age is currently disabled for this focused session." }
3957
+ };
3958
+ }
3959
+ const senderId = params.command.senderId?.trim() || "";
3960
+ const boundBy = onDiscord ? discordBinding.boundBy : resolveSessionBindingBoundBy(onMatrix ? matrixBinding : telegramBinding);
3961
+ if (boundBy && boundBy !== "system" && senderId && senderId !== boundBy) return {
3962
+ shouldContinue: false,
3963
+ reply: { text: onDiscord ? `⚠️ Only ${boundBy} can update session lifecycle settings for this thread.` : onMatrix ? `⚠️ Only ${boundBy} can update session lifecycle settings for this thread.` : `⚠️ Only ${boundBy} can update session lifecycle settings for this conversation.` }
3964
+ };
3965
+ let durationMs;
3966
+ try {
3967
+ durationMs = parseSessionDurationMs(durationArgRaw);
3968
+ } catch {
3969
+ return {
3970
+ shouldContinue: false,
3971
+ reply: { text: resolveSessionCommandUsage() }
3972
+ };
3973
+ }
3974
+ const updatedBindings = (() => {
3975
+ if (onDiscord) return action === SESSION_ACTION_IDLE ? channelRuntime.discord.threadBindings.setIdleTimeoutBySessionKey({
3976
+ targetSessionKey: discordBinding.targetSessionKey,
3977
+ accountId,
3978
+ idleTimeoutMs: durationMs
3979
+ }) : channelRuntime.discord.threadBindings.setMaxAgeBySessionKey({
3980
+ targetSessionKey: discordBinding.targetSessionKey,
3981
+ accountId,
3982
+ maxAgeMs: durationMs
3983
+ });
3984
+ if (onMatrix) return action === SESSION_ACTION_IDLE ? channelRuntime.matrix.threadBindings.setIdleTimeoutBySessionKey({
3985
+ targetSessionKey: matrixBinding.targetSessionKey,
3986
+ accountId,
3987
+ idleTimeoutMs: durationMs
3988
+ }) : channelRuntime.matrix.threadBindings.setMaxAgeBySessionKey({
3989
+ targetSessionKey: matrixBinding.targetSessionKey,
3990
+ accountId,
3991
+ maxAgeMs: durationMs
3992
+ });
3993
+ return action === SESSION_ACTION_IDLE ? channelRuntime.telegram.threadBindings.setIdleTimeoutBySessionKey({
3994
+ targetSessionKey: telegramBinding.targetSessionKey,
3995
+ accountId,
3996
+ idleTimeoutMs: durationMs
3997
+ }) : channelRuntime.telegram.threadBindings.setMaxAgeBySessionKey({
3998
+ targetSessionKey: telegramBinding.targetSessionKey,
3999
+ accountId,
4000
+ maxAgeMs: durationMs
4001
+ });
4002
+ })();
4003
+ if (updatedBindings.length === 0) return {
4004
+ shouldContinue: false,
4005
+ reply: { text: action === SESSION_ACTION_IDLE ? "⚠️ Failed to update idle timeout for the current binding." : "⚠️ Failed to update max age for the current binding." }
4006
+ };
4007
+ if (durationMs <= 0) return {
4008
+ shouldContinue: false,
4009
+ reply: { text: action === SESSION_ACTION_IDLE ? `✅ Idle timeout disabled for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"}.` : `✅ Max age disabled for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"}.` }
4010
+ };
4011
+ const nextExpiry = resolveUpdatedBindingExpiry({
4012
+ action,
4013
+ bindings: updatedBindings.map((binding) => toUpdatedLifecycleBinding(binding))
4014
+ });
4015
+ const expiryLabel = typeof nextExpiry === "number" && Number.isFinite(nextExpiry) ? formatSessionExpiry(nextExpiry) : "n/a";
4016
+ return {
4017
+ shouldContinue: false,
4018
+ reply: { text: action === SESSION_ACTION_IDLE ? `✅ Idle timeout set to ${formatThreadBindingDurationLabel(durationMs)} for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"} (next auto-unfocus at ${expiryLabel}).` : `✅ Max age set to ${formatThreadBindingDurationLabel(durationMs)} for ${updatedBindings.length} binding${updatedBindings.length === 1 ? "" : "s"} (hard auto-unfocus at ${expiryLabel}).` }
4019
+ };
4020
+ };
4021
+ const handleRestartCommand = async (params, allowTextCommands) => {
4022
+ if (!allowTextCommands) return null;
4023
+ if (params.command.commandBodyNormalized !== "/restart") return null;
4024
+ if (!params.command.isAuthorizedSender) {
4025
+ logVerbose(`Ignoring /restart from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
4026
+ return { shouldContinue: false };
4027
+ }
4028
+ if (!isRestartEnabled(params.cfg)) return {
4029
+ shouldContinue: false,
4030
+ reply: { text: "⚠️ /restart is disabled (commands.restart=false)." }
4031
+ };
4032
+ if (process.listenerCount("SIGUSR1") > 0) {
4033
+ scheduleGatewaySigusr1Restart({ reason: "/restart" });
4034
+ return {
4035
+ shouldContinue: false,
4036
+ reply: { text: "⚙️ Restarting OpenClaw in-process (SIGUSR1); back in a few seconds." }
4037
+ };
4038
+ }
4039
+ const restartMethod = triggerOpenClawRestart();
4040
+ if (!restartMethod.ok) {
4041
+ const detail = restartMethod.detail ? ` Details: ${restartMethod.detail}` : "";
4042
+ return {
4043
+ shouldContinue: false,
4044
+ reply: { text: `⚠️ Restart failed (${restartMethod.method}).${detail}` }
4045
+ };
4046
+ }
4047
+ return {
4048
+ shouldContinue: false,
4049
+ reply: { text: `⚙️ Restarting OpenClaw via ${restartMethod.method}; give me a few seconds to come back online.` }
4050
+ };
4051
+ };
4052
+ //#endregion
4053
+ //#region src/auto-reply/reply/commands-subagents/action-agents.ts
4054
+ function formatConversationBindingText(params) {
4055
+ if (params.channel === "discord") return `thread:${params.conversationId}`;
4056
+ if (params.channel === "telegram") return `conversation:${params.conversationId}`;
4057
+ return `binding:${params.conversationId}`;
4058
+ }
4059
+ function handleSubagentsAgentsAction(ctx) {
4060
+ const { params, requesterKey, runs } = ctx;
4061
+ const channel = resolveCommandSurfaceChannel(params);
4062
+ const accountId = resolveChannelAccountId(params);
4063
+ const bindingService = getSessionBindingService();
4064
+ const bindingsBySession = /* @__PURE__ */ new Map();
4065
+ const resolveSessionBindings = (sessionKey) => {
4066
+ const cached = bindingsBySession.get(sessionKey);
4067
+ if (cached) return cached;
4068
+ const resolved = bindingService.listBySession(sessionKey).filter((entry) => entry.status === "active" && entry.conversation.channel === channel && entry.conversation.accountId === accountId);
4069
+ bindingsBySession.set(sessionKey, resolved);
4070
+ return resolved;
4071
+ };
4072
+ const visibleRuns = sortSubagentRuns(runs).filter((entry) => {
4073
+ if (!entry.endedAt) return true;
4074
+ return resolveSessionBindings(entry.childSessionKey).length > 0;
4075
+ });
4076
+ const lines = ["agents:", "-----"];
4077
+ if (visibleRuns.length === 0) lines.push("(none)");
4078
+ else {
4079
+ let index = 1;
4080
+ for (const entry of visibleRuns) {
4081
+ const binding = resolveSessionBindings(entry.childSessionKey)[0];
4082
+ const bindingText = binding ? formatConversationBindingText({
4083
+ channel,
4084
+ conversationId: binding.conversation.conversationId
4085
+ }) : channel === "discord" || channel === "telegram" ? "unbound" : "bindings available on discord/telegram";
4086
+ lines.push(`${index}. ${formatRunLabel(entry)} (${bindingText})`);
4087
+ index += 1;
4088
+ }
4089
+ }
4090
+ const requesterBindings = resolveSessionBindings(requesterKey).filter((entry) => entry.targetKind === "session");
4091
+ if (requesterBindings.length > 0) {
4092
+ lines.push("", "acp/session bindings:", "-----");
4093
+ for (const binding of requesterBindings) {
4094
+ const label = typeof binding.metadata?.label === "string" && binding.metadata.label.trim() ? binding.metadata.label.trim() : binding.targetSessionKey;
4095
+ lines.push(`- ${label} (${formatConversationBindingText({
4096
+ channel,
4097
+ conversationId: binding.conversation.conversationId
4098
+ })}, session:${binding.targetSessionKey})`);
4099
+ }
4100
+ }
4101
+ return stopWithText(lines.join("\n"));
4102
+ }
4103
+ //#endregion
4104
+ //#region src/auto-reply/reply/commands-subagents/action-focus.ts
4105
+ function resolveFocusBindingContext(params) {
4106
+ if (isDiscordSurface(params)) {
4107
+ const currentThreadId = params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId).trim() : "";
4108
+ const parentChannelId = currentThreadId ? void 0 : resolveDiscordChannelIdForFocus(params);
4109
+ const conversationId = currentThreadId || parentChannelId;
4110
+ if (!conversationId) return null;
4111
+ return {
4112
+ channel: "discord",
4113
+ accountId: resolveChannelAccountId(params),
4114
+ conversationId,
4115
+ placement: currentThreadId ? "current" : "child",
4116
+ labelNoun: "thread"
4117
+ };
4118
+ }
4119
+ if (isTelegramSurface(params)) {
4120
+ const conversationId = resolveTelegramConversationId(params);
4121
+ if (!conversationId) return null;
4122
+ return {
4123
+ channel: "telegram",
4124
+ accountId: resolveChannelAccountId(params),
4125
+ conversationId,
4126
+ placement: "current",
4127
+ labelNoun: "conversation"
4128
+ };
4129
+ }
4130
+ if (isMatrixSurface(params)) {
4131
+ const conversationId = resolveMatrixConversationId({
4132
+ ctx: {
4133
+ MessageThreadId: params.ctx.MessageThreadId,
4134
+ OriginatingTo: params.ctx.OriginatingTo,
4135
+ To: params.ctx.To
4136
+ },
4137
+ command: { to: params.command.to }
4138
+ });
4139
+ if (!conversationId) return null;
4140
+ const parentConversationId = resolveMatrixParentConversationId({
4141
+ ctx: {
4142
+ MessageThreadId: params.ctx.MessageThreadId,
4143
+ OriginatingTo: params.ctx.OriginatingTo,
4144
+ To: params.ctx.To
4145
+ },
4146
+ command: { to: params.command.to }
4147
+ });
4148
+ const currentThreadId = params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId).trim() : "";
4149
+ return {
4150
+ channel: "matrix",
4151
+ accountId: resolveChannelAccountId(params),
4152
+ conversationId,
4153
+ ...parentConversationId ? { parentConversationId } : {},
4154
+ placement: currentThreadId ? "current" : "child",
4155
+ labelNoun: "thread"
4156
+ };
4157
+ }
4158
+ return null;
4159
+ }
4160
+ async function handleSubagentsFocusAction(ctx) {
4161
+ const { params, runs, restTokens } = ctx;
4162
+ const channel = resolveCommandSurfaceChannel(params);
4163
+ if (channel !== "discord" && channel !== "matrix" && channel !== "telegram") return stopWithText("⚠️ /focus is only available on Discord, Matrix, and Telegram.");
4164
+ const token = restTokens.join(" ").trim();
4165
+ if (!token) return stopWithText("Usage: /focus <subagent-label|session-key|session-id|session-label>");
4166
+ const accountId = resolveChannelAccountId(params);
4167
+ const bindingService = getSessionBindingService();
4168
+ const capabilities = bindingService.getCapabilities({
4169
+ channel,
4170
+ accountId
4171
+ });
4172
+ if (!capabilities.adapterAvailable || !capabilities.bindSupported) return stopWithText(`⚠️ ${channel === "discord" ? "Discord thread" : channel === "matrix" ? "Matrix thread" : "Telegram conversation"} bindings are unavailable for this account.`);
4173
+ const focusTarget = await resolveFocusTargetSession({
4174
+ runs,
4175
+ token
4176
+ });
4177
+ if (!focusTarget) return stopWithText(`⚠️ Unable to resolve focus target: ${token}`);
4178
+ const bindingContext = resolveFocusBindingContext(params);
4179
+ if (!bindingContext) {
4180
+ if (channel === "telegram") return stopWithText("⚠️ /focus on Telegram requires a topic context in groups, or a direct-message conversation.");
4181
+ if (channel === "matrix") return stopWithText("⚠️ Could not resolve a Matrix room for /focus.");
4182
+ return stopWithText("⚠️ Could not resolve a Discord channel for /focus.");
4183
+ }
4184
+ if (channel === "matrix") {
4185
+ const spawnPolicy = resolveThreadBindingSpawnPolicy({
4186
+ cfg: params.cfg,
4187
+ channel,
4188
+ accountId: bindingContext.accountId,
4189
+ kind: "subagent"
4190
+ });
4191
+ if (!spawnPolicy.enabled) return stopWithText(`⚠️ ${formatThreadBindingDisabledError({
4192
+ channel: spawnPolicy.channel,
4193
+ accountId: spawnPolicy.accountId,
4194
+ kind: "subagent"
4195
+ })}`);
4196
+ if (bindingContext.placement === "child" && !spawnPolicy.spawnEnabled) return stopWithText(`⚠️ ${formatThreadBindingSpawnDisabledError({
4197
+ channel: spawnPolicy.channel,
4198
+ accountId: spawnPolicy.accountId,
4199
+ kind: "subagent"
4200
+ })}`);
4201
+ }
4202
+ const senderId = params.command.senderId?.trim() || "";
4203
+ const existingBinding = bindingService.resolveByConversation({
4204
+ channel: bindingContext.channel,
4205
+ accountId: bindingContext.accountId,
4206
+ conversationId: bindingContext.conversationId,
4207
+ ...bindingContext.parentConversationId && bindingContext.parentConversationId !== bindingContext.conversationId ? { parentConversationId: bindingContext.parentConversationId } : {}
4208
+ });
4209
+ const boundBy = typeof existingBinding?.metadata?.boundBy === "string" ? existingBinding.metadata.boundBy.trim() : "";
4210
+ if (existingBinding && boundBy && boundBy !== "system" && senderId && senderId !== boundBy) return stopWithText(`⚠️ Only ${boundBy} can refocus this ${bindingContext.labelNoun}.`);
4211
+ const label = focusTarget.label || token;
4212
+ const acpMeta = focusTarget.targetKind === "acp" ? readAcpSessionEntry({
4213
+ cfg: params.cfg,
4214
+ sessionKey: focusTarget.targetSessionKey
4215
+ })?.acp : void 0;
4216
+ if (!capabilities.placements.includes(bindingContext.placement)) return stopWithText(`⚠️ ${channel} bindings are unavailable for this account.`);
4217
+ let binding;
4218
+ try {
4219
+ binding = await bindingService.bind({
4220
+ targetSessionKey: focusTarget.targetSessionKey,
4221
+ targetKind: focusTarget.targetKind === "acp" ? "session" : "subagent",
4222
+ conversation: {
4223
+ channel: bindingContext.channel,
4224
+ accountId: bindingContext.accountId,
4225
+ conversationId: bindingContext.conversationId,
4226
+ ...bindingContext.parentConversationId && bindingContext.parentConversationId !== bindingContext.conversationId ? { parentConversationId: bindingContext.parentConversationId } : {}
4227
+ },
4228
+ placement: bindingContext.placement,
4229
+ metadata: {
4230
+ threadName: resolveThreadBindingThreadName({
4231
+ agentId: focusTarget.agentId,
4232
+ label
4233
+ }),
4234
+ agentId: focusTarget.agentId,
4235
+ label,
4236
+ boundBy: senderId || "unknown",
4237
+ introText: resolveThreadBindingIntroText({
4238
+ agentId: focusTarget.agentId,
4239
+ label,
4240
+ idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({
4241
+ cfg: params.cfg,
4242
+ channel: bindingContext.channel,
4243
+ accountId
4244
+ }),
4245
+ maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({
4246
+ cfg: params.cfg,
4247
+ channel: bindingContext.channel,
4248
+ accountId
4249
+ }),
4250
+ sessionCwd: focusTarget.targetKind === "acp" ? resolveAcpSessionCwd(acpMeta) : void 0,
4251
+ sessionDetails: focusTarget.targetKind === "acp" ? resolveAcpThreadSessionDetailLines({
4252
+ sessionKey: focusTarget.targetSessionKey,
4253
+ meta: acpMeta
4254
+ }) : []
4255
+ })
4256
+ }
4257
+ });
4258
+ } catch {
4259
+ return stopWithText(`⚠️ Failed to bind this ${bindingContext.labelNoun} to the target session.`);
4260
+ }
4261
+ return stopWithText(`✅ ${bindingContext.placement === "child" ? `created thread ${binding.conversation.conversationId} and bound it to ${binding.targetSessionKey}` : `bound this ${bindingContext.labelNoun} to ${binding.targetSessionKey}`} (${focusTarget.targetKind}).`);
4262
+ }
4263
+ //#endregion
4264
+ //#region src/auto-reply/reply/commands-subagents/action-help.ts
4265
+ function handleSubagentsHelpAction() {
4266
+ return stopWithText(buildSubagentsHelp());
4267
+ }
4268
+ //#endregion
4269
+ //#region src/auto-reply/reply/commands-subagents/action-info.ts
4270
+ function handleSubagentsInfoAction(ctx) {
4271
+ const { params, runs, restTokens } = ctx;
4272
+ const target = restTokens[0];
4273
+ if (!target) return stopWithText("ℹ️ Usage: /subagents info <id|#>");
4274
+ const targetResolution = resolveSubagentEntryForToken(runs, target);
4275
+ if ("reply" in targetResolution) return targetResolution.reply;
4276
+ const run = targetResolution.entry;
4277
+ const { entry: sessionEntry } = loadSubagentSessionEntry(params, run.childSessionKey, {
4278
+ loadSessionStore,
4279
+ resolveStorePath
4280
+ });
4281
+ const runtime = run.startedAt && Number.isFinite(run.startedAt) ? formatDurationCompact((run.endedAt ?? Date.now()) - run.startedAt) ?? "n/a" : "n/a";
4282
+ const outcome = run.outcome ? `${run.outcome.status}${run.outcome.error ? ` (${run.outcome.error})` : ""}` : "n/a";
4283
+ return stopWithText([
4284
+ "ℹ️ Subagent info",
4285
+ `Status: ${resolveDisplayStatus(run, { pendingDescendants: countPendingDescendantRuns(run.childSessionKey) })}`,
4286
+ `Label: ${formatRunLabel(run)}`,
4287
+ `Task: ${run.task}`,
4288
+ `Run: ${run.runId}`,
4289
+ `Session: ${run.childSessionKey}`,
4290
+ `SessionId: ${sessionEntry?.sessionId ?? "n/a"}`,
4291
+ `Transcript: ${sessionEntry?.sessionFile ?? "n/a"}`,
4292
+ `Runtime: ${runtime}`,
4293
+ `Created: ${formatTimestampWithAge(run.createdAt)}`,
4294
+ `Started: ${formatTimestampWithAge(run.startedAt)}`,
4295
+ `Ended: ${formatTimestampWithAge(run.endedAt)}`,
4296
+ `Cleanup: ${run.cleanup}`,
4297
+ run.archiveAtMs ? `Archive: ${formatTimestampWithAge(run.archiveAtMs)}` : void 0,
4298
+ run.cleanupHandled ? "Cleanup handled: yes" : void 0,
4299
+ `Outcome: ${outcome}`
4300
+ ].filter(Boolean).join("\n"));
4301
+ }
4302
+ //#endregion
4303
+ //#region src/auto-reply/reply/commands-subagents/action-kill.ts
4304
+ async function handleSubagentsKillAction(ctx) {
4305
+ const { params, handledPrefix, requesterKey, runs, restTokens } = ctx;
4306
+ const target = restTokens[0];
4307
+ if (!target) return stopWithText(handledPrefix === "/subagents" ? "Usage: /subagents kill <id|#|all>" : "Usage: /kill <id|#|all>");
4308
+ if (target === "all" || target === "*") {
4309
+ const controller = resolveCommandSubagentController(params, requesterKey);
4310
+ const result = await killAllControlledSubagentRuns({
4311
+ cfg: params.cfg,
4312
+ controller,
4313
+ runs
4314
+ });
4315
+ if (result.status === "forbidden") return stopWithText(`⚠️ ${result.error}`);
4316
+ if (result.killed > 0) return { shouldContinue: false };
4317
+ return { shouldContinue: false };
4318
+ }
4319
+ const targetResolution = resolveSubagentEntryForToken(runs, target);
4320
+ if ("reply" in targetResolution) return targetResolution.reply;
4321
+ if (targetResolution.entry.endedAt) return stopWithText(`${formatRunLabel(targetResolution.entry)} is already finished.`);
4322
+ const controller = resolveCommandSubagentController(params, requesterKey);
4323
+ const result = await killControlledSubagentRun({
4324
+ cfg: params.cfg,
4325
+ controller,
4326
+ entry: targetResolution.entry
4327
+ });
4328
+ if (result.status === "forbidden") return stopWithText(`⚠️ ${result.error}`);
4329
+ if (result.status === "done") return stopWithText(result.text);
4330
+ return { shouldContinue: false };
4331
+ }
4332
+ //#endregion
4333
+ //#region src/auto-reply/reply/commands-subagents/action-list.ts
4334
+ function handleSubagentsListAction(ctx) {
4335
+ const { params, runs } = ctx;
4336
+ const list = buildSubagentList({
4337
+ cfg: params.cfg,
4338
+ runs,
4339
+ recentMinutes: 30,
4340
+ taskMaxChars: 110
4341
+ });
4342
+ const lines = ["active subagents:", "-----"];
4343
+ if (list.active.length === 0) lines.push("(none)");
4344
+ else lines.push(list.active.map((entry) => entry.line).join("\n"));
4345
+ lines.push("", `recent subagents (last 30m):`, "-----");
4346
+ if (list.recent.length === 0) lines.push("(none)");
4347
+ else lines.push(list.recent.map((entry) => entry.line).join("\n"));
4348
+ return stopWithText(lines.join("\n"));
4349
+ }
4350
+ //#endregion
4351
+ //#region src/auto-reply/reply/commands-subagents/action-log.ts
4352
+ async function handleSubagentsLogAction(ctx) {
4353
+ const { runs, restTokens } = ctx;
4354
+ const target = restTokens[0];
4355
+ if (!target) return stopWithText("📜 Usage: /subagents log <id|#> [limit]");
4356
+ const includeTools = restTokens.some((token) => token.toLowerCase() === "tools");
4357
+ const limitToken = restTokens.find((token) => /^\d+$/.test(token));
4358
+ const limit = limitToken ? Math.min(200, Math.max(1, Number.parseInt(limitToken, 10))) : 20;
4359
+ const targetResolution = resolveSubagentEntryForToken(runs, target);
4360
+ if ("reply" in targetResolution) return targetResolution.reply;
4361
+ const history = await callGateway({
4362
+ method: "chat.history",
4363
+ params: {
4364
+ sessionKey: targetResolution.entry.childSessionKey,
4365
+ limit
4366
+ }
4367
+ });
4368
+ const rawMessages = Array.isArray(history?.messages) ? history.messages : [];
4369
+ const lines = formatLogLines(includeTools ? rawMessages : stripToolMessages(rawMessages));
4370
+ const header = `📜 Subagent log: ${formatRunLabel(targetResolution.entry)}`;
4371
+ if (lines.length === 0) return stopWithText(`${header}\n(no messages)`);
4372
+ return stopWithText([header, ...lines].join("\n"));
4373
+ }
4374
+ //#endregion
4375
+ //#region src/auto-reply/reply/commands-subagents/action-send.ts
4376
+ async function handleSubagentsSendAction(ctx, steerRequested) {
4377
+ const { params, handledPrefix, runs, restTokens } = ctx;
4378
+ const target = restTokens[0];
4379
+ const message = restTokens.slice(1).join(" ").trim();
4380
+ if (!target || !message) return stopWithText(steerRequested ? handledPrefix === "/subagents" ? "Usage: /subagents steer <id|#> <message>" : `Usage: ${handledPrefix} <id|#> <message>` : "Usage: /subagents send <id|#> <message>");
4381
+ const targetResolution = resolveSubagentEntryForToken(runs, target);
4382
+ if ("reply" in targetResolution) return targetResolution.reply;
4383
+ if (steerRequested && targetResolution.entry.endedAt) return stopWithText(`${formatRunLabel(targetResolution.entry)} is already finished.`);
4384
+ const controller = resolveCommandSubagentController(params, ctx.requesterKey);
4385
+ if (steerRequested) {
4386
+ const result = await steerControlledSubagentRun({
4387
+ cfg: params.cfg,
4388
+ controller,
4389
+ entry: targetResolution.entry,
4390
+ message
4391
+ });
4392
+ if (result.status === "accepted") return stopWithText(`steered ${formatRunLabel(targetResolution.entry)} (run ${result.runId.slice(0, 8)}).`);
4393
+ if (result.status === "done" && result.text) return stopWithText(result.text);
4394
+ if (result.status === "error") return stopWithText(`send failed: ${result.error ?? "error"}`);
4395
+ return stopWithText(`⚠️ ${result.error ?? "send failed"}`);
4396
+ }
4397
+ const result = await sendControlledSubagentMessage({
4398
+ cfg: params.cfg,
4399
+ controller,
4400
+ entry: targetResolution.entry,
4401
+ message
4402
+ });
4403
+ if (result.status === "timeout") return stopWithText(`⏳ Subagent still running (run ${result.runId.slice(0, 8)}).`);
4404
+ if (result.status === "error") return stopWithText(`⚠️ Subagent error: ${result.error} (run ${result.runId.slice(0, 8)}).`);
4405
+ if (result.status === "forbidden") return stopWithText(`⚠️ ${result.error ?? "send failed"}`);
4406
+ return stopWithText(result.replyText ?? `✅ Sent to ${formatRunLabel(targetResolution.entry)} (run ${result.runId.slice(0, 8)}).`);
4407
+ }
4408
+ //#endregion
4409
+ //#region src/auto-reply/reply/commands-subagents/action-spawn.ts
4410
+ async function handleSubagentsSpawnAction(ctx) {
4411
+ const { params, requesterKey, restTokens } = ctx;
4412
+ const agentId = restTokens[0];
4413
+ const taskParts = [];
4414
+ let model;
4415
+ let thinking;
4416
+ for (let i = 1; i < restTokens.length; i++) if (restTokens[i] === "--model" && i + 1 < restTokens.length) {
4417
+ i += 1;
4418
+ model = restTokens[i];
4419
+ } else if (restTokens[i] === "--thinking" && i + 1 < restTokens.length) {
4420
+ i += 1;
4421
+ thinking = restTokens[i];
4422
+ } else taskParts.push(restTokens[i]);
4423
+ const task = taskParts.join(" ").trim();
4424
+ if (!agentId || !task) return stopWithText("Usage: /subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]");
4425
+ const commandTo = typeof params.command.to === "string" ? params.command.to.trim() : "";
4426
+ const originatingTo = typeof params.ctx.OriginatingTo === "string" ? params.ctx.OriginatingTo.trim() : "";
4427
+ const fallbackTo = typeof params.ctx.To === "string" ? params.ctx.To.trim() : "";
4428
+ const normalizedTo = originatingTo || commandTo || fallbackTo || void 0;
4429
+ const result = await spawnSubagentDirect({
4430
+ task,
4431
+ agentId,
4432
+ model,
4433
+ thinking,
4434
+ mode: "run",
4435
+ cleanup: "keep",
4436
+ expectsCompletionMessage: true
4437
+ }, {
4438
+ agentSessionKey: requesterKey,
4439
+ agentChannel: params.ctx.OriginatingChannel ?? params.command.channel,
4440
+ agentAccountId: params.ctx.AccountId,
4441
+ agentTo: normalizedTo,
4442
+ agentThreadId: params.ctx.MessageThreadId,
4443
+ agentGroupId: params.sessionEntry?.groupId ?? null,
4444
+ agentGroupChannel: params.sessionEntry?.groupChannel ?? null,
4445
+ agentGroupSpace: params.sessionEntry?.space ?? null
4446
+ });
4447
+ if (result.status === "accepted") return stopWithText(`Spawned subagent ${agentId} (session ${result.childSessionKey}, run ${result.runId?.slice(0, 8)}).`);
4448
+ return stopWithText(`Spawn failed: ${result.error ?? result.status}`);
4449
+ }
4450
+ //#endregion
4451
+ //#region src/auto-reply/reply/commands-subagents/action-unfocus.ts
4452
+ async function handleSubagentsUnfocusAction(ctx) {
4453
+ const { params } = ctx;
4454
+ const channel = resolveCommandSurfaceChannel(params);
4455
+ if (channel !== "discord" && channel !== "matrix" && channel !== "telegram") return stopWithText("⚠️ /unfocus is only available on Discord, Matrix, and Telegram.");
4456
+ const accountId = resolveChannelAccountId(params);
4457
+ const bindingService = getSessionBindingService();
4458
+ const conversationId = (() => {
4459
+ if (isDiscordSurface(params)) return (params.ctx.MessageThreadId != null ? String(params.ctx.MessageThreadId) : "").trim() || void 0;
4460
+ if (isTelegramSurface(params)) return resolveTelegramConversationId(params);
4461
+ if (isMatrixSurface(params)) return resolveMatrixConversationId({
4462
+ ctx: {
4463
+ MessageThreadId: params.ctx.MessageThreadId,
4464
+ OriginatingTo: params.ctx.OriginatingTo,
4465
+ To: params.ctx.To
4466
+ },
4467
+ command: { to: params.command.to }
4468
+ });
4469
+ })();
4470
+ const parentConversationId = (() => {
4471
+ if (!isMatrixSurface(params)) return;
4472
+ return resolveMatrixParentConversationId({
4473
+ ctx: {
4474
+ MessageThreadId: params.ctx.MessageThreadId,
4475
+ OriginatingTo: params.ctx.OriginatingTo,
4476
+ To: params.ctx.To
4477
+ },
4478
+ command: { to: params.command.to }
4479
+ });
4480
+ })();
4481
+ if (!conversationId) {
4482
+ if (channel === "discord") return stopWithText("⚠️ /unfocus must be run inside a Discord thread.");
4483
+ if (channel === "matrix") return stopWithText("⚠️ /unfocus must be run inside a Matrix thread.");
4484
+ return stopWithText("⚠️ /unfocus on Telegram requires a topic context in groups, or a direct-message conversation.");
4485
+ }
4486
+ const binding = bindingService.resolveByConversation({
4487
+ channel,
4488
+ accountId,
4489
+ conversationId,
4490
+ ...parentConversationId && parentConversationId !== conversationId ? { parentConversationId } : {}
4491
+ });
4492
+ if (!binding) return stopWithText(channel === "discord" ? "ℹ️ This thread is not currently focused." : channel === "matrix" ? "ℹ️ This thread is not currently focused." : "ℹ️ This conversation is not currently focused.");
4493
+ const senderId = params.command.senderId?.trim() || "";
4494
+ const boundBy = typeof binding.metadata?.boundBy === "string" ? binding.metadata.boundBy.trim() : "";
4495
+ if (boundBy && boundBy !== "system" && senderId && senderId !== boundBy) return stopWithText(channel === "discord" ? `⚠️ Only ${boundBy} can unfocus this thread.` : channel === "matrix" ? `⚠️ Only ${boundBy} can unfocus this thread.` : `⚠️ Only ${boundBy} can unfocus this conversation.`);
4496
+ await bindingService.unbind({
4497
+ bindingId: binding.bindingId,
4498
+ reason: "manual"
4499
+ });
4500
+ return stopWithText(channel === "discord" || channel === "matrix" ? "✅ Thread unfocused." : "✅ Conversation unfocused.");
4501
+ }
4502
+ //#endregion
4503
+ //#region src/auto-reply/reply/commands-subagents.ts
4504
+ const handleSubagentsCommand = async (params, allowTextCommands) => {
4505
+ if (!allowTextCommands) return null;
4506
+ const normalized = params.command.commandBodyNormalized;
4507
+ const handledPrefix = resolveHandledPrefix(normalized);
4508
+ if (!handledPrefix) return null;
4509
+ if (!params.command.isAuthorizedSender) {
4510
+ logVerbose(`Ignoring ${handledPrefix} from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
4511
+ return { shouldContinue: false };
4512
+ }
4513
+ const restTokens = normalized.slice(handledPrefix.length).trim().split(/\s+/).filter(Boolean);
4514
+ const action = resolveSubagentsAction({
4515
+ handledPrefix,
4516
+ restTokens
4517
+ });
4518
+ if (!action) return handleSubagentsHelpAction();
4519
+ const requesterKey = action === "spawn" ? resolveRequesterSessionKey(params, { preferCommandTarget: true }) : resolveRequesterSessionKey(params);
4520
+ if (!requesterKey) return stopWithText("⚠️ Missing session key.");
4521
+ const ctx = {
4522
+ params,
4523
+ handledPrefix,
4524
+ requesterKey,
4525
+ runs: listSubagentRunsForController(requesterKey),
4526
+ restTokens
4527
+ };
4528
+ switch (action) {
4529
+ case "help": return handleSubagentsHelpAction();
4530
+ case "agents": return handleSubagentsAgentsAction(ctx);
4531
+ case "focus": return await handleSubagentsFocusAction(ctx);
4532
+ case "unfocus": return await handleSubagentsUnfocusAction(ctx);
4533
+ case "list": return handleSubagentsListAction(ctx);
4534
+ case "kill": return await handleSubagentsKillAction(ctx);
4535
+ case "info": return handleSubagentsInfoAction(ctx);
4536
+ case "log": return await handleSubagentsLogAction(ctx);
4537
+ case "send": return await handleSubagentsSendAction(ctx, false);
4538
+ case "steer": return await handleSubagentsSendAction(ctx, true);
4539
+ case "spawn": return await handleSubagentsSpawnAction(ctx);
4540
+ default: return handleSubagentsHelpAction();
4541
+ }
4542
+ };
4543
+ //#endregion
4544
+ //#region src/auto-reply/reply/commands-tts.ts
4545
+ function parseTtsCommand(normalized) {
4546
+ if (normalized === "/tts") return {
4547
+ action: "status",
4548
+ args: ""
4549
+ };
4550
+ if (!normalized.startsWith("/tts ")) return null;
4551
+ const rest = normalized.slice(5).trim();
4552
+ if (!rest) return {
4553
+ action: "status",
4554
+ args: ""
4555
+ };
4556
+ const [action, ...tail] = rest.split(/\s+/);
4557
+ return {
4558
+ action: action.toLowerCase(),
4559
+ args: tail.join(" ").trim()
4560
+ };
4561
+ }
4562
+ function ttsUsage() {
4563
+ return { text: "🔊 **TTS (Text-to-Speech) Help**\n\n**Commands:**\n• /tts on — Enable automatic TTS for replies\n• /tts off — Disable TTS\n• /tts status — Show current settings\n• /tts provider [name] — View/change provider\n• /tts limit [number] — View/change text limit\n• /tts summary [on|off] — View/change auto-summary\n• /tts audio <text> — Generate audio from text\n\n**Providers:**\n• microsoft — Microsoft Edge-backed speech (default fallback)\n• openai — High quality (requires API key)\n• elevenlabs — Premium voices (requires API key)\n\n**Text Limit (default: 1500, max: 4096):**\nWhen text exceeds the limit:\n• Summary ON: AI summarizes, then generates audio\n• Summary OFF: Truncates text, then generates audio\n\n**Examples:**\n/tts provider microsoft\n/tts limit 2000\n/tts audio Hello, this is a test!" };
4564
+ }
4565
+ const handleTtsCommands = async (params, allowTextCommands) => {
4566
+ if (!allowTextCommands) return null;
4567
+ const parsed = parseTtsCommand(params.command.commandBodyNormalized);
4568
+ if (!parsed) return null;
4569
+ if (!params.command.isAuthorizedSender) {
4570
+ logVerbose(`Ignoring TTS command from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
4571
+ return { shouldContinue: false };
4572
+ }
4573
+ const config = resolveTtsConfig(params.cfg);
4574
+ const prefsPath = resolveTtsPrefsPath(config);
4575
+ const action = parsed.action;
4576
+ const args = parsed.args;
4577
+ if (action === "help") return {
4578
+ shouldContinue: false,
4579
+ reply: ttsUsage()
4580
+ };
4581
+ if (action === "on") {
4582
+ setTtsEnabled(prefsPath, true);
4583
+ return {
4584
+ shouldContinue: false,
4585
+ reply: { text: "🔊 TTS enabled." }
4586
+ };
4587
+ }
4588
+ if (action === "off") {
4589
+ setTtsEnabled(prefsPath, false);
4590
+ return {
4591
+ shouldContinue: false,
4592
+ reply: { text: "🔇 TTS disabled." }
4593
+ };
4594
+ }
4595
+ if (action === "audio") {
4596
+ if (!args.trim()) return {
4597
+ shouldContinue: false,
4598
+ reply: { text: "🎤 Generate audio from text.\n\nUsage: /tts audio <text>\nExample: /tts audio Hello, this is a test!" }
4599
+ };
4600
+ const start = Date.now();
4601
+ const result = await textToSpeech({
4602
+ text: args,
4603
+ cfg: params.cfg,
4604
+ channel: params.command.channel,
4605
+ prefsPath
4606
+ });
4607
+ if (result.success && result.audioPath) {
4608
+ setLastTtsAttempt({
4609
+ timestamp: Date.now(),
4610
+ success: true,
4611
+ textLength: args.length,
4612
+ summarized: false,
4613
+ provider: result.provider,
4614
+ latencyMs: result.latencyMs
4615
+ });
4616
+ return {
4617
+ shouldContinue: false,
4618
+ reply: {
4619
+ mediaUrl: result.audioPath,
4620
+ audioAsVoice: result.voiceCompatible === true
4621
+ }
4622
+ };
4623
+ }
4624
+ setLastTtsAttempt({
4625
+ timestamp: Date.now(),
4626
+ success: false,
4627
+ textLength: args.length,
4628
+ summarized: false,
4629
+ error: result.error,
4630
+ latencyMs: Date.now() - start
4631
+ });
4632
+ return {
4633
+ shouldContinue: false,
4634
+ reply: { text: `❌ Error generating audio: ${result.error ?? "unknown error"}` }
4635
+ };
4636
+ }
4637
+ if (action === "provider") {
4638
+ const currentProvider = getTtsProvider(config, prefsPath);
4639
+ if (!args.trim()) {
4640
+ const hasOpenAI = Boolean(resolveTtsApiKey(config, "openai"));
4641
+ const hasElevenLabs = Boolean(resolveTtsApiKey(config, "elevenlabs"));
4642
+ const hasMicrosoft = isTtsProviderConfigured(config, "microsoft", params.cfg);
4643
+ return {
4644
+ shouldContinue: false,
4645
+ reply: { text: `🎙️ TTS provider\nPrimary: ${currentProvider}\nOpenAI key: ${hasOpenAI ? "✅" : "❌"}\nElevenLabs key: ${hasElevenLabs ? "✅" : "❌"}\nMicrosoft enabled: ${hasMicrosoft ? "✅" : "❌"}\nUsage: /tts provider openai | elevenlabs | microsoft` }
4646
+ };
4647
+ }
4648
+ const requested = args.trim().toLowerCase();
4649
+ const knownProviders = new Set(listSpeechProviders(params.cfg).map((provider) => provider.id));
4650
+ if (requested !== "edge" && !knownProviders.has(requested)) return {
4651
+ shouldContinue: false,
4652
+ reply: ttsUsage()
4653
+ };
4654
+ const nextProvider = normalizeSpeechProviderId(requested) ?? requested;
4655
+ setTtsProvider(prefsPath, requested);
4656
+ return {
4657
+ shouldContinue: false,
4658
+ reply: { text: `✅ TTS provider set to ${nextProvider}.` }
4659
+ };
4660
+ }
4661
+ if (action === "limit") {
4662
+ if (!args.trim()) return {
4663
+ shouldContinue: false,
4664
+ reply: { text: `📏 TTS limit: ${getTtsMaxLength(prefsPath)} characters.\n\nText longer than this triggers summary (if enabled).\nRange: 100-4096 chars (Telegram max).\n\nTo change: /tts limit <number>\nExample: /tts limit 2000` }
4665
+ };
4666
+ const next = Number.parseInt(args.trim(), 10);
4667
+ if (!Number.isFinite(next) || next < 100 || next > 4096) return {
4668
+ shouldContinue: false,
4669
+ reply: { text: "❌ Limit must be between 100 and 4096 characters." }
4670
+ };
4671
+ setTtsMaxLength(prefsPath, next);
4672
+ return {
4673
+ shouldContinue: false,
4674
+ reply: { text: `✅ TTS limit set to ${next} characters.` }
4675
+ };
4676
+ }
4677
+ if (action === "summary") {
4678
+ if (!args.trim()) {
4679
+ const enabled = isSummarizationEnabled(prefsPath);
4680
+ const maxLen = getTtsMaxLength(prefsPath);
4681
+ return {
4682
+ shouldContinue: false,
4683
+ reply: { text: `📝 TTS auto-summary: ${enabled ? "on" : "off"}.\n\nWhen text exceeds ${maxLen} chars:\n• ON: summarizes text, then generates audio\n• OFF: truncates text, then generates audio\n\nTo change: /tts summary on | off` }
4684
+ };
4685
+ }
4686
+ const requested = args.trim().toLowerCase();
4687
+ if (requested !== "on" && requested !== "off") return {
4688
+ shouldContinue: false,
4689
+ reply: ttsUsage()
4690
+ };
4691
+ setSummarizationEnabled(prefsPath, requested === "on");
4692
+ return {
4693
+ shouldContinue: false,
4694
+ reply: { text: requested === "on" ? "✅ TTS auto-summary enabled." : "❌ TTS auto-summary disabled." }
4695
+ };
4696
+ }
4697
+ if (action === "status") {
4698
+ const enabled = isTtsEnabled(config, prefsPath);
4699
+ const provider = getTtsProvider(config, prefsPath);
4700
+ const hasKey = isTtsProviderConfigured(config, provider, params.cfg);
4701
+ const maxLength = getTtsMaxLength(prefsPath);
4702
+ const summarize = isSummarizationEnabled(prefsPath);
4703
+ const last = getLastTtsAttempt();
4704
+ const lines = [
4705
+ "📊 TTS status",
4706
+ `State: ${enabled ? "✅ enabled" : "❌ disabled"}`,
4707
+ `Provider: ${provider} (${hasKey ? "✅ configured" : "❌ not configured"})`,
4708
+ `Text limit: ${maxLength} chars`,
4709
+ `Auto-summary: ${summarize ? "on" : "off"}`
4710
+ ];
4711
+ if (last) {
4712
+ const timeAgo = Math.round((Date.now() - last.timestamp) / 1e3);
4713
+ lines.push("");
4714
+ lines.push(`Last attempt (${timeAgo}s ago): ${last.success ? "✅" : "❌"}`);
4715
+ lines.push(`Text: ${last.textLength} chars${last.summarized ? " (summarized)" : ""}`);
4716
+ if (last.success) {
4717
+ lines.push(`Provider: ${last.provider ?? "unknown"}`);
4718
+ lines.push(`Latency: ${last.latencyMs ?? 0}ms`);
4719
+ } else if (last.error) lines.push(`Error: ${last.error}`);
4720
+ }
4721
+ return {
4722
+ shouldContinue: false,
4723
+ reply: { text: lines.join("\n") }
4724
+ };
4725
+ }
4726
+ return {
4727
+ shouldContinue: false,
4728
+ reply: ttsUsage()
4729
+ };
4730
+ };
4731
+ //#endregion
4732
+ //#region src/auto-reply/reply/commands-core.ts
4733
+ let HANDLERS = null;
4734
+ async function emitResetCommandHooks(params) {
4735
+ const hookEvent = createInternalHookEvent("command", params.action, params.sessionKey ?? "", {
4736
+ sessionEntry: params.sessionEntry,
4737
+ previousSessionEntry: params.previousSessionEntry,
4738
+ commandSource: params.command.surface,
4739
+ senderId: params.command.senderId,
4740
+ workspaceDir: params.workspaceDir,
4741
+ cfg: params.cfg
4742
+ });
4743
+ await triggerInternalHook(hookEvent);
4744
+ params.command.resetHookTriggered = true;
4745
+ if (hookEvent.messages.length > 0) {
4746
+ const channel = params.ctx.OriginatingChannel || params.command.channel;
4747
+ const to = params.ctx.OriginatingTo || params.command.from || params.command.to;
4748
+ if (channel && to) await routeReply({
4749
+ payload: { text: hookEvent.messages.join("\n\n") },
4750
+ channel,
4751
+ to,
4752
+ sessionKey: params.sessionKey,
4753
+ accountId: params.ctx.AccountId,
4754
+ threadId: params.ctx.MessageThreadId,
4755
+ cfg: params.cfg
4756
+ });
4757
+ }
4758
+ const hookRunner = getGlobalHookRunner();
4759
+ if (hookRunner?.hasHooks("before_reset")) {
4760
+ const prevEntry = params.previousSessionEntry;
4761
+ const sessionFile = prevEntry?.sessionFile;
4762
+ (async () => {
4763
+ try {
4764
+ const messages = [];
4765
+ if (sessionFile) {
4766
+ const content = await fs$1.readFile(sessionFile, "utf-8");
4767
+ for (const line of content.split("\n")) {
4768
+ if (!line.trim()) continue;
4769
+ try {
4770
+ const entry = JSON.parse(line);
4771
+ if (entry.type === "message" && entry.message) messages.push(entry.message);
4772
+ } catch {}
4773
+ }
4774
+ } else logVerbose("before_reset: no session file available, firing hook with empty messages");
4775
+ await hookRunner.runBeforeReset({
4776
+ sessionFile,
4777
+ messages,
4778
+ reason: params.action
4779
+ }, {
4780
+ agentId: resolveAgentIdFromSessionKey(params.sessionKey),
4781
+ sessionKey: params.sessionKey,
4782
+ sessionId: prevEntry?.sessionId,
4783
+ workspaceDir: params.workspaceDir
4784
+ });
4785
+ } catch (err) {
4786
+ logVerbose(`before_reset hook failed: ${String(err)}`);
4787
+ }
4788
+ })();
4789
+ }
4790
+ }
4791
+ function applyAcpResetTailContext(ctx, resetTail) {
4792
+ const mutableCtx = ctx;
4793
+ mutableCtx.Body = resetTail;
4794
+ mutableCtx.RawBody = resetTail;
4795
+ mutableCtx.CommandBody = resetTail;
4796
+ mutableCtx.BodyForCommands = resetTail;
4797
+ mutableCtx.BodyForAgent = resetTail;
4798
+ mutableCtx.BodyStripped = resetTail;
4799
+ mutableCtx.AcpDispatchTailAfterReset = true;
4800
+ }
4801
+ function resolveSessionEntryForHookSessionKey(sessionStore, sessionKey) {
4802
+ if (!sessionStore) return;
4803
+ const directEntry = sessionStore[sessionKey];
4804
+ if (directEntry) return directEntry;
4805
+ const normalizedTarget = sessionKey.trim().toLowerCase();
4806
+ if (!normalizedTarget) return;
4807
+ for (const [candidateKey, candidateEntry] of Object.entries(sessionStore)) if (candidateKey.trim().toLowerCase() === normalizedTarget) return candidateEntry;
4808
+ }
4809
+ async function handleCommands(params) {
4810
+ if (HANDLERS === null) HANDLERS = [
4811
+ handlePluginCommand,
4812
+ handleBtwCommand,
4813
+ handleBashCommand,
4814
+ handleActivationCommand,
4815
+ handleSendPolicyCommand,
4816
+ handleFastCommand,
4817
+ handleUsageCommand,
4818
+ handleSessionCommand,
4819
+ handleRestartCommand,
4820
+ handleTtsCommands,
4821
+ handleHelpCommand,
4822
+ handleCommandsListCommand,
4823
+ handleStatusCommand,
4824
+ handleAllowlistCommand,
4825
+ handleApproveCommand,
4826
+ handleContextCommand,
4827
+ handleExportSessionCommand,
4828
+ handleWhoamiCommand,
4829
+ handleSubagentsCommand,
4830
+ handleAcpCommand,
4831
+ handleMcpCommand,
4832
+ handlePluginsCommand,
4833
+ handleConfigCommand,
4834
+ handleDebugCommand,
4835
+ handleModelsCommand,
4836
+ handleStopCommand,
4837
+ handleCompactCommand,
4838
+ handleAbortTrigger
4839
+ ];
4840
+ const resetMatch = params.command.commandBodyNormalized.match(/^\/(new|reset)(?:\s|$)/);
4841
+ const resetRequested = Boolean(resetMatch);
4842
+ if (resetRequested && !params.command.isAuthorizedSender) {
4843
+ logVerbose(`Ignoring /reset from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
4844
+ return { shouldContinue: false };
4845
+ }
4846
+ if (resetRequested && params.command.isAuthorizedSender) {
4847
+ const commandAction = resetMatch?.[1] === "reset" ? "reset" : "new";
4848
+ const resetTail = resetMatch != null ? params.command.commandBodyNormalized.slice(resetMatch[0].length).trimStart() : "";
4849
+ const boundAcpSessionKey = resolveBoundAcpThreadSessionKey(params);
4850
+ const boundAcpKey = boundAcpSessionKey && isAcpSessionKey(boundAcpSessionKey) ? boundAcpSessionKey.trim() : void 0;
4851
+ if (boundAcpKey) {
4852
+ const resetResult = await resetConfiguredBindingTargetInPlace({
4853
+ cfg: params.cfg,
4854
+ sessionKey: boundAcpKey,
4855
+ reason: commandAction
4856
+ });
4857
+ if (!resetResult.ok && !resetResult.skipped) logVerbose(`acp reset-in-place failed for ${boundAcpKey}: ${resetResult.error ?? "unknown error"}`);
4858
+ if (resetResult.ok) {
4859
+ const hookSessionEntry = boundAcpKey === params.sessionKey ? params.sessionEntry : resolveSessionEntryForHookSessionKey(params.sessionStore, boundAcpKey);
4860
+ const hookPreviousSessionEntry = boundAcpKey === params.sessionKey ? params.previousSessionEntry : resolveSessionEntryForHookSessionKey(params.sessionStore, boundAcpKey);
4861
+ await emitResetCommandHooks({
4862
+ action: commandAction,
4863
+ ctx: params.ctx,
4864
+ cfg: params.cfg,
4865
+ command: params.command,
4866
+ sessionKey: boundAcpKey,
4867
+ sessionEntry: hookSessionEntry,
4868
+ previousSessionEntry: hookPreviousSessionEntry,
4869
+ workspaceDir: params.workspaceDir
4870
+ });
4871
+ if (resetTail) {
4872
+ applyAcpResetTailContext(params.ctx, resetTail);
4873
+ if (params.rootCtx && params.rootCtx !== params.ctx) applyAcpResetTailContext(params.rootCtx, resetTail);
4874
+ return { shouldContinue: false };
4875
+ }
4876
+ return {
4877
+ shouldContinue: false,
4878
+ reply: { text: "✅ ACP session reset in place." }
4879
+ };
4880
+ }
4881
+ if (resetResult.skipped) return {
4882
+ shouldContinue: false,
4883
+ reply: { text: "⚠️ ACP session reset unavailable for this bound conversation. Rebind with /acp bind or /acp spawn." }
4884
+ };
4885
+ return {
4886
+ shouldContinue: false,
4887
+ reply: { text: "⚠️ ACP session reset failed. Check /acp status and try again." }
4888
+ };
4889
+ }
4890
+ await emitResetCommandHooks({
4891
+ action: commandAction,
4892
+ ctx: params.ctx,
4893
+ cfg: params.cfg,
4894
+ command: params.command,
4895
+ sessionKey: params.sessionKey,
4896
+ sessionEntry: params.sessionEntry,
4897
+ previousSessionEntry: params.previousSessionEntry,
4898
+ workspaceDir: params.workspaceDir
4899
+ });
4900
+ }
4901
+ const allowTextCommands = shouldHandleTextCommands({
4902
+ cfg: params.cfg,
4903
+ surface: params.command.surface,
4904
+ commandSource: params.ctx.CommandSource
4905
+ });
4906
+ for (const handler of HANDLERS) {
4907
+ const result = await handler(params, allowTextCommands);
4908
+ if (result) return result;
4909
+ }
4910
+ if (resolveSendPolicy({
4911
+ cfg: params.cfg,
4912
+ entry: params.sessionEntry,
4913
+ sessionKey: params.sessionKey,
4914
+ channel: params.sessionEntry?.channel ?? params.command.channel,
4915
+ chatType: params.sessionEntry?.chatType
4916
+ }) === "deny") {
4917
+ logVerbose(`Send blocked by policy for session ${params.sessionKey ?? "unknown"}`);
4918
+ return { shouldContinue: false };
4919
+ }
4920
+ return { shouldContinue: true };
4921
+ }
4922
+ //#endregion
4923
+ export { handleCommands as n, emitResetCommandHooks as t };