@openclaw/discord 2026.9.5 → 2026.9.7

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 (517) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
  3. package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
  4. package/dist/.setup/{activities-api-DBwRt5ES.mjs → activities-api-tvbsU2e3.mjs} +38 -66
  5. package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
  6. package/dist/.setup/{approval-handler.runtime-Du3n5ypX.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
  7. package/dist/.setup/{approval-message-updates-BN7JtScm.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
  8. package/dist/.setup/{audit-C8uaKoa9.mjs → audit-CLg9I71N.mjs} +5 -5
  9. package/dist/.setup/{channel-ChKdlBgH.mjs → channel-DxlUVU9t.mjs} +125 -228
  10. package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
  11. package/dist/.setup/{channel.setup-BlC3-Kzz.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
  12. package/dist/.setup/{components-MqMWUWnE.mjs → components-Cq1PvIpN.mjs} +42 -71
  13. package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
  14. package/dist/.setup/{conversation-binding-route-_rz33QHO.mjs → conversation-binding-route-Caz_XuFH.mjs} +14 -6
  15. package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
  16. package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
  17. package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
  18. package/dist/.setup/{doctor-DxcdkXzz.mjs → doctor-BCl1H5tl.mjs} +21 -36
  19. package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
  20. package/dist/.setup/{channel-actions.runtime-CJmiFfps.mjs → handle-action-CUvQWnE7.mjs} +74 -105
  21. package/dist/.setup/{handle-action.guild-admin-DAFyh_yV.mjs → handle-action.guild-admin-Df-8gVle.mjs} +63 -121
  22. package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
  23. package/dist/.setup/{message-handler-DnUrDpaU.mjs → message-handler-B-Jk4oDk.mjs} +18 -93
  24. package/dist/.setup/message-handler.preflight-pluralkit-CWLUBVcx.mjs +141 -0
  25. package/dist/.setup/{message-handler.preflight-CtqaF_fb.mjs → message-handler.preflight-v-__NSDq.mjs} +73 -287
  26. package/dist/.setup/{message-handler.process-Dz1xvuQU.mjs → message-handler.process-BNFFuChn.mjs} +423 -374
  27. package/dist/.setup/{outbound-adapter-C8v79z9Z.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
  28. package/dist/.setup/{outbound-session-route-CqWbuMOm.mjs → outbound-session-route-zVGxxceg.mjs} +142 -109
  29. package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
  30. package/dist/.setup/{preflight-audio-DrnqFA8U.mjs → preflight-audio-DHGIHEpv.mjs} +2 -1
  31. package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
  32. package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
  33. package/dist/.setup/{provider-72zIvN-i.mjs → provider-B_G5hASF.mjs} +1112 -1668
  34. package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
  35. package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
  36. package/dist/.setup/{realtime-session.runtime-DTccTgTM.mjs → realtime-session.runtime-oUd9DOcz.mjs} +372 -345
  37. package/dist/.setup/receive-recovery-CHPOsnLc.mjs +514 -0
  38. package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
  39. package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
  40. package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
  41. package/dist/.setup/{retry-DBfcEgmO.mjs → retry-pz_cSha2.mjs} +81 -16
  42. package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
  43. package/dist/.setup/{runtime-SchNfUsQ.mjs → runtime-FN000lxA.mjs} +83 -166
  44. package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
  45. package/dist/.setup/{runtime-BVoa7hhx.mjs → runtime-sUksZ--Q.mjs} +2 -5
  46. package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
  47. package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
  48. package/dist/.setup/{send-CKDczUNL.mjs → send-CrfEI6Bs.mjs} +73 -114
  49. package/dist/.setup/{send.components-DWQjXhPV.mjs → send.components-DxQAMfES.mjs} +62 -107
  50. package/dist/.setup/{send.outbound-D0hQ7s50.mjs → send.outbound-BISKnb-a.mjs} +79 -154
  51. package/dist/.setup/{send.shared-Zwx6BxQ5.mjs → send.shared-DGFkbkQR.mjs} +10 -25
  52. package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
  53. package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
  54. package/dist/.setup/{shared-CaA3Vv4n.mjs → shared-B3wZ4hN-.mjs} +25 -32
  55. package/dist/.setup/{subagent-hooks-Bired9q6.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
  56. package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
  57. package/dist/.setup/{target-resolver-B6MrxbYv.mjs → target-resolver-BuLapkhy.mjs} +9 -12
  58. package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
  59. package/dist/.setup/{thread-bindings-CK5272V3.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
  60. package/dist/.setup/thread-bindings.manager-DN-NissX.mjs +819 -0
  61. package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
  62. package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
  63. package/dist/.setup/{transcripts-source-CuWYgayu.mjs → transcripts-source-p8EV179h.mjs} +133 -238
  64. package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
  65. package/dist/.setup/{voice-runtime-DHVQ2mFz.mjs → voice-runtime-B46rcwrG.mjs} +633 -1085
  66. package/dist/account-inspect-api.js +1 -1
  67. package/dist/action-runtime-api.js +1 -1
  68. package/dist/activities-api.js +1 -1
  69. package/dist/api.js +18 -18
  70. package/dist/channel-config-api.js +1 -1
  71. package/dist/channel-plugin-api.js +1 -1
  72. package/dist/directory-contract-api.js +1 -1
  73. package/dist/doctor-contract-api.js +4 -4
  74. package/dist/index.js +1 -1
  75. package/dist/runtime-api.js +20 -20
  76. package/dist/secret-contract-api.js +1 -1
  77. package/dist/security-audit-contract-api.js +1 -1
  78. package/dist/setup-entry.js +1 -1
  79. package/dist/setup-plugin-api.js +1 -1
  80. package/dist/src/voice/audio-worker.runtime.js +1056 -0
  81. package/dist/subagent-hooks-api.js +3 -4
  82. package/dist/transcripts-source-api.js +1 -1
  83. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +8 -4
  84. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +8 -4
  85. package/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +1 -1
  86. package/node_modules/@napi-rs/wasm-runtime/dist/fs.js +770 -695
  87. package/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +3 -2
  88. package/node_modules/@napi-rs/wasm-runtime/package.json +1 -1
  89. package/node_modules/@tybys/wasm-util/LICENSE +21 -0
  90. package/node_modules/@tybys/wasm-util/package.json +1 -1
  91. package/node_modules/@types/node/README.md +2 -2
  92. package/node_modules/@types/node/child_process.d.ts +1 -1
  93. package/node_modules/@types/node/crypto.d.ts +20 -8
  94. package/node_modules/@types/node/ffi.d.ts +14 -0
  95. package/node_modules/@types/node/http2.d.ts +3 -2
  96. package/node_modules/@types/node/net.d.ts +16 -4
  97. package/node_modules/@types/node/package.json +2 -17
  98. package/node_modules/@types/node/process.d.ts +1 -0
  99. package/node_modules/@types/node/quic.d.ts +39 -1
  100. package/node_modules/@types/node/stream/iter.d.ts +9 -12
  101. package/node_modules/@types/node/test/reporters.d.ts +1 -0
  102. package/node_modules/@types/node/test.d.ts +72 -0
  103. package/node_modules/@types/node/tls.d.ts +14 -10
  104. package/node_modules/@types/node/vm.d.ts +2 -1
  105. package/node_modules/@types/node/web-globals/streams.d.ts +4 -0
  106. package/node_modules/@types/node/worker_threads.d.ts +4 -1
  107. package/node_modules/typebox/build/compile/code.mjs +1 -2
  108. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  109. package/node_modules/typebox/build/format/iri.mjs +16 -9
  110. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  111. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  112. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  113. package/node_modules/typebox/build/guard/index.mjs +6 -0
  114. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  115. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  116. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  117. package/node_modules/typebox/build/schema/build.mjs +2 -3
  118. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  119. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  120. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  121. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  122. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  123. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  124. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  125. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  126. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  127. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  128. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  129. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  130. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  131. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  132. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  133. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  134. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  135. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  136. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  137. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  138. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  139. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  140. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  141. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  142. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  143. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  144. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  145. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  146. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  147. package/node_modules/typebox/package.json +1 -1
  148. package/node_modules/typebox/readme.md +3 -1
  149. package/node_modules/zod/README.md +2 -2
  150. package/node_modules/zod/compile.cjs +19 -0
  151. package/node_modules/zod/index.cjs +19 -0
  152. package/node_modules/zod/locales/index.cjs +19 -0
  153. package/node_modules/zod/mini/index.cjs +19 -0
  154. package/node_modules/zod/package.json +8 -7
  155. package/node_modules/zod/src/v3/helpers/errorUtil.ts +1 -1
  156. package/node_modules/zod/src/v4/classic/external.ts +2 -0
  157. package/node_modules/zod/src/v4/classic/from-json-schema.ts +248 -25
  158. package/node_modules/zod/src/v4/classic/schemas.ts +243 -168
  159. package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +60 -9
  160. package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +6 -0
  161. package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
  162. package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +265 -0
  163. package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
  164. package/node_modules/zod/src/v4/classic/tests/enum.test.ts +9 -0
  165. package/node_modules/zod/src/v4/classic/tests/error.test.ts +130 -1
  166. package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  167. package/node_modules/zod/src/v4/classic/tests/iban.test.ts +81 -0
  168. package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +40 -2
  169. package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +27 -7
  170. package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +88 -56
  171. package/node_modules/zod/src/v4/classic/tests/number.test.ts +39 -0
  172. package/node_modules/zod/src/v4/classic/tests/object.test.ts +56 -0
  173. package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  174. package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +70 -0
  175. package/node_modules/zod/src/v4/classic/tests/properties.test.ts +141 -0
  176. package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +46 -1
  177. package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +19 -0
  178. package/node_modules/zod/src/v4/classic/tests/string.test.ts +95 -1
  179. package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +33 -1
  180. package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +234 -38
  181. package/node_modules/zod/src/v4/classic/tests/validate.test.ts +569 -0
  182. package/node_modules/zod/src/v4/core/api.ts +44 -28
  183. package/node_modules/zod/src/v4/core/checks.ts +62 -102
  184. package/node_modules/zod/src/v4/core/compile.ts +218 -93
  185. package/node_modules/zod/src/v4/core/core.ts +1 -3
  186. package/node_modules/zod/src/v4/core/doc.ts +6 -2
  187. package/node_modules/zod/src/v4/core/errors.ts +3 -6
  188. package/node_modules/zod/src/v4/core/json-schema-generator.ts +2 -2
  189. package/node_modules/zod/src/v4/core/json-schema-processors.ts +185 -81
  190. package/node_modules/zod/src/v4/core/memoizer.ts +75 -28
  191. package/node_modules/zod/src/v4/core/parse.ts +37 -16
  192. package/node_modules/zod/src/v4/core/regexes.ts +14 -4
  193. package/node_modules/zod/src/v4/core/schemas.ts +296 -132
  194. package/node_modules/zod/src/v4/core/tests/cached.test.ts +54 -0
  195. package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +35 -0
  196. package/node_modules/zod/src/v4/core/tests/compile-generative.test.ts +445 -0
  197. package/node_modules/zod/src/v4/core/tests/compile.test.ts +399 -2
  198. package/node_modules/zod/src/v4/core/tests/email-regex.test.ts +140 -0
  199. package/node_modules/zod/src/v4/core/tests/locales/tg.test.ts +85 -0
  200. package/node_modules/zod/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  201. package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +118 -16
  202. package/node_modules/zod/src/v4/core/to-json-schema.ts +9 -7
  203. package/node_modules/zod/src/v4/core/util.ts +218 -147
  204. package/node_modules/zod/src/v4/core/versions.ts +2 -2
  205. package/node_modules/zod/src/v4/locales/ar.ts +2 -0
  206. package/node_modules/zod/src/v4/locales/az.ts +2 -0
  207. package/node_modules/zod/src/v4/locales/be.ts +2 -0
  208. package/node_modules/zod/src/v4/locales/bg.ts +2 -0
  209. package/node_modules/zod/src/v4/locales/bn.ts +2 -0
  210. package/node_modules/zod/src/v4/locales/ca.ts +2 -0
  211. package/node_modules/zod/src/v4/locales/ckb.ts +2 -0
  212. package/node_modules/zod/src/v4/locales/cs.ts +2 -0
  213. package/node_modules/zod/src/v4/locales/da.ts +2 -0
  214. package/node_modules/zod/src/v4/locales/de.ts +2 -0
  215. package/node_modules/zod/src/v4/locales/el.ts +2 -0
  216. package/node_modules/zod/src/v4/locales/en.ts +2 -0
  217. package/node_modules/zod/src/v4/locales/eo.ts +2 -0
  218. package/node_modules/zod/src/v4/locales/es.ts +2 -0
  219. package/node_modules/zod/src/v4/locales/fa.ts +2 -0
  220. package/node_modules/zod/src/v4/locales/fi.ts +2 -0
  221. package/node_modules/zod/src/v4/locales/fr-CA.ts +2 -0
  222. package/node_modules/zod/src/v4/locales/fr.ts +2 -0
  223. package/node_modules/zod/src/v4/locales/gu.ts +2 -0
  224. package/node_modules/zod/src/v4/locales/he.ts +2 -0
  225. package/node_modules/zod/src/v4/locales/hi.ts +2 -0
  226. package/node_modules/zod/src/v4/locales/hr.ts +2 -0
  227. package/node_modules/zod/src/v4/locales/hu.ts +2 -0
  228. package/node_modules/zod/src/v4/locales/hy.ts +2 -0
  229. package/node_modules/zod/src/v4/locales/id.ts +2 -0
  230. package/node_modules/zod/src/v4/locales/index.ts +1 -0
  231. package/node_modules/zod/src/v4/locales/is.ts +2 -0
  232. package/node_modules/zod/src/v4/locales/it.ts +2 -0
  233. package/node_modules/zod/src/v4/locales/ja.ts +2 -0
  234. package/node_modules/zod/src/v4/locales/ka.ts +2 -0
  235. package/node_modules/zod/src/v4/locales/km.ts +2 -0
  236. package/node_modules/zod/src/v4/locales/kn.ts +2 -0
  237. package/node_modules/zod/src/v4/locales/ko.ts +2 -0
  238. package/node_modules/zod/src/v4/locales/lt.ts +2 -0
  239. package/node_modules/zod/src/v4/locales/mk.ts +2 -0
  240. package/node_modules/zod/src/v4/locales/ms.ts +2 -0
  241. package/node_modules/zod/src/v4/locales/ne.ts +2 -0
  242. package/node_modules/zod/src/v4/locales/nl.ts +2 -0
  243. package/node_modules/zod/src/v4/locales/nn.ts +2 -0
  244. package/node_modules/zod/src/v4/locales/no.ts +2 -0
  245. package/node_modules/zod/src/v4/locales/ota.ts +2 -0
  246. package/node_modules/zod/src/v4/locales/pl.ts +2 -0
  247. package/node_modules/zod/src/v4/locales/ps.ts +2 -0
  248. package/node_modules/zod/src/v4/locales/pt-BR.ts +2 -0
  249. package/node_modules/zod/src/v4/locales/pt.ts +2 -0
  250. package/node_modules/zod/src/v4/locales/ro.ts +2 -0
  251. package/node_modules/zod/src/v4/locales/ru.ts +2 -0
  252. package/node_modules/zod/src/v4/locales/sk.ts +2 -0
  253. package/node_modules/zod/src/v4/locales/sl.ts +2 -0
  254. package/node_modules/zod/src/v4/locales/sv.ts +2 -0
  255. package/node_modules/zod/src/v4/locales/ta.ts +2 -0
  256. package/node_modules/zod/src/v4/locales/tg.ts +135 -0
  257. package/node_modules/zod/src/v4/locales/th.ts +2 -0
  258. package/node_modules/zod/src/v4/locales/tk.ts +2 -0
  259. package/node_modules/zod/src/v4/locales/tr.ts +2 -0
  260. package/node_modules/zod/src/v4/locales/uk.ts +2 -0
  261. package/node_modules/zod/src/v4/locales/ur.ts +2 -0
  262. package/node_modules/zod/src/v4/locales/uz.ts +2 -0
  263. package/node_modules/zod/src/v4/locales/vi.ts +2 -0
  264. package/node_modules/zod/src/v4/locales/yo.ts +2 -0
  265. package/node_modules/zod/src/v4/locales/zh-CN.ts +2 -0
  266. package/node_modules/zod/src/v4/locales/zh-TW.ts +2 -0
  267. package/node_modules/zod/src/v4/mini/external.ts +2 -0
  268. package/node_modules/zod/src/v4/mini/schemas.ts +32 -7
  269. package/node_modules/zod/src/v4/mini/tests/checks.test.ts +1 -1
  270. package/node_modules/zod/src/v4/mini/tests/computed.test.ts +11 -17
  271. package/node_modules/zod/src/v4/mini/tests/index.test.ts +86 -0
  272. package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +16 -0
  273. package/node_modules/zod/src/v4/mini/tests/string.test.ts +23 -0
  274. package/node_modules/zod/v3/ZodError.cjs +19 -0
  275. package/node_modules/zod/v3/errors.cjs +19 -0
  276. package/node_modules/zod/v3/external.cjs +19 -0
  277. package/node_modules/zod/v3/helpers/enumUtil.cjs +19 -0
  278. package/node_modules/zod/v3/helpers/errorUtil.cjs +20 -1
  279. package/node_modules/zod/v3/helpers/errorUtil.js +1 -1
  280. package/node_modules/zod/v3/helpers/parseUtil.cjs +19 -0
  281. package/node_modules/zod/v3/helpers/partialUtil.cjs +19 -0
  282. package/node_modules/zod/v3/helpers/typeAliases.cjs +19 -0
  283. package/node_modules/zod/v3/helpers/util.cjs +19 -0
  284. package/node_modules/zod/v3/index.cjs +19 -0
  285. package/node_modules/zod/v3/standard-schema.cjs +19 -0
  286. package/node_modules/zod/v3/types.cjs +19 -0
  287. package/node_modules/zod/v4/classic/checks.cjs +19 -0
  288. package/node_modules/zod/v4/classic/coerce.cjs +19 -0
  289. package/node_modules/zod/v4/classic/compat.cjs +19 -0
  290. package/node_modules/zod/v4/classic/deep-partial.cjs +19 -0
  291. package/node_modules/zod/v4/classic/errors.cjs +19 -0
  292. package/node_modules/zod/v4/classic/external.cjs +22 -1
  293. package/node_modules/zod/v4/classic/external.d.cts +1 -1
  294. package/node_modules/zod/v4/classic/external.d.ts +1 -1
  295. package/node_modules/zod/v4/classic/external.js +1 -1
  296. package/node_modules/zod/v4/classic/from-json-schema.cjs +264 -24
  297. package/node_modules/zod/v4/classic/from-json-schema.js +245 -24
  298. package/node_modules/zod/v4/classic/in-out.cjs +19 -0
  299. package/node_modules/zod/v4/classic/index.cjs +19 -0
  300. package/node_modules/zod/v4/classic/iso.cjs +19 -0
  301. package/node_modules/zod/v4/classic/parse.cjs +19 -0
  302. package/node_modules/zod/v4/classic/schemas.cjs +100 -35
  303. package/node_modules/zod/v4/classic/schemas.d.cts +15 -1
  304. package/node_modules/zod/v4/classic/schemas.d.ts +15 -1
  305. package/node_modules/zod/v4/classic/schemas.js +77 -33
  306. package/node_modules/zod/v4/core/api.cjs +45 -22
  307. package/node_modules/zod/v4/core/api.d.cts +12 -6
  308. package/node_modules/zod/v4/core/api.d.ts +12 -6
  309. package/node_modules/zod/v4/core/api.js +25 -22
  310. package/node_modules/zod/v4/core/checks.cjs +51 -97
  311. package/node_modules/zod/v4/core/checks.d.cts +17 -1
  312. package/node_modules/zod/v4/core/checks.d.ts +17 -1
  313. package/node_modules/zod/v4/core/checks.js +31 -96
  314. package/node_modules/zod/v4/core/compile.cjs +173 -78
  315. package/node_modules/zod/v4/core/compile.d.cts +18 -4
  316. package/node_modules/zod/v4/core/compile.d.ts +18 -4
  317. package/node_modules/zod/v4/core/compile.js +154 -79
  318. package/node_modules/zod/v4/core/core.cjs +20 -1
  319. package/node_modules/zod/v4/core/core.js +1 -1
  320. package/node_modules/zod/v4/core/doc.cjs +26 -2
  321. package/node_modules/zod/v4/core/doc.js +7 -2
  322. package/node_modules/zod/v4/core/errors.cjs +21 -5
  323. package/node_modules/zod/v4/core/errors.js +2 -5
  324. package/node_modules/zod/v4/core/index.cjs +19 -0
  325. package/node_modules/zod/v4/core/json-schema-generator.cjs +20 -1
  326. package/node_modules/zod/v4/core/json-schema-generator.js +2 -2
  327. package/node_modules/zod/v4/core/json-schema-processors.cjs +188 -72
  328. package/node_modules/zod/v4/core/json-schema-processors.d.cts +16 -0
  329. package/node_modules/zod/v4/core/json-schema-processors.d.ts +16 -0
  330. package/node_modules/zod/v4/core/json-schema-processors.js +170 -74
  331. package/node_modules/zod/v4/core/json-schema.cjs +19 -0
  332. package/node_modules/zod/v4/core/memoizer.cjs +111 -23
  333. package/node_modules/zod/v4/core/memoizer.js +69 -23
  334. package/node_modules/zod/v4/core/parse.cjs +56 -16
  335. package/node_modules/zod/v4/core/parse.js +37 -16
  336. package/node_modules/zod/v4/core/regexes.cjs +31 -6
  337. package/node_modules/zod/v4/core/regexes.d.cts +3 -0
  338. package/node_modules/zod/v4/core/regexes.d.ts +3 -0
  339. package/node_modules/zod/v4/core/regexes.js +10 -4
  340. package/node_modules/zod/v4/core/registries.cjs +19 -0
  341. package/node_modules/zod/v4/core/schemas.cjs +302 -114
  342. package/node_modules/zod/v4/core/schemas.d.cts +28 -8
  343. package/node_modules/zod/v4/core/schemas.d.ts +28 -8
  344. package/node_modules/zod/v4/core/schemas.js +279 -113
  345. package/node_modules/zod/v4/core/standard-schema.cjs +19 -0
  346. package/node_modules/zod/v4/core/to-json-schema.cjs +28 -7
  347. package/node_modules/zod/v4/core/to-json-schema.d.cts +4 -3
  348. package/node_modules/zod/v4/core/to-json-schema.d.ts +4 -3
  349. package/node_modules/zod/v4/core/to-json-schema.js +7 -6
  350. package/node_modules/zod/v4/core/util.cjs +177 -143
  351. package/node_modules/zod/v4/core/util.d.cts +25 -4
  352. package/node_modules/zod/v4/core/util.d.ts +25 -4
  353. package/node_modules/zod/v4/core/util.js +156 -143
  354. package/node_modules/zod/v4/core/versions.cjs +21 -2
  355. package/node_modules/zod/v4/core/versions.d.cts +1 -1
  356. package/node_modules/zod/v4/core/versions.d.ts +1 -1
  357. package/node_modules/zod/v4/core/versions.js +2 -2
  358. package/node_modules/zod/v4/core/visit.cjs +19 -0
  359. package/node_modules/zod/v4/index.cjs +19 -0
  360. package/node_modules/zod/v4/locales/ar.cjs +2 -0
  361. package/node_modules/zod/v4/locales/ar.js +2 -0
  362. package/node_modules/zod/v4/locales/az.cjs +2 -0
  363. package/node_modules/zod/v4/locales/az.js +2 -0
  364. package/node_modules/zod/v4/locales/be.cjs +2 -0
  365. package/node_modules/zod/v4/locales/be.js +2 -0
  366. package/node_modules/zod/v4/locales/bg.cjs +2 -0
  367. package/node_modules/zod/v4/locales/bg.js +2 -0
  368. package/node_modules/zod/v4/locales/bn.cjs +2 -0
  369. package/node_modules/zod/v4/locales/bn.js +2 -0
  370. package/node_modules/zod/v4/locales/ca.cjs +2 -0
  371. package/node_modules/zod/v4/locales/ca.js +2 -0
  372. package/node_modules/zod/v4/locales/ckb.cjs +2 -0
  373. package/node_modules/zod/v4/locales/ckb.js +2 -0
  374. package/node_modules/zod/v4/locales/cs.cjs +2 -0
  375. package/node_modules/zod/v4/locales/cs.js +2 -0
  376. package/node_modules/zod/v4/locales/da.cjs +2 -0
  377. package/node_modules/zod/v4/locales/da.js +2 -0
  378. package/node_modules/zod/v4/locales/de.cjs +2 -0
  379. package/node_modules/zod/v4/locales/de.js +2 -0
  380. package/node_modules/zod/v4/locales/el.cjs +2 -0
  381. package/node_modules/zod/v4/locales/el.js +2 -0
  382. package/node_modules/zod/v4/locales/en.cjs +2 -0
  383. package/node_modules/zod/v4/locales/en.js +2 -0
  384. package/node_modules/zod/v4/locales/eo.cjs +2 -0
  385. package/node_modules/zod/v4/locales/eo.js +2 -0
  386. package/node_modules/zod/v4/locales/es.cjs +2 -0
  387. package/node_modules/zod/v4/locales/es.js +2 -0
  388. package/node_modules/zod/v4/locales/fa.cjs +2 -0
  389. package/node_modules/zod/v4/locales/fa.js +2 -0
  390. package/node_modules/zod/v4/locales/fi.cjs +2 -0
  391. package/node_modules/zod/v4/locales/fi.js +2 -0
  392. package/node_modules/zod/v4/locales/fr-CA.cjs +2 -0
  393. package/node_modules/zod/v4/locales/fr-CA.js +2 -0
  394. package/node_modules/zod/v4/locales/fr.cjs +2 -0
  395. package/node_modules/zod/v4/locales/fr.js +2 -0
  396. package/node_modules/zod/v4/locales/gu.cjs +2 -0
  397. package/node_modules/zod/v4/locales/gu.js +2 -0
  398. package/node_modules/zod/v4/locales/he.cjs +2 -0
  399. package/node_modules/zod/v4/locales/he.js +2 -0
  400. package/node_modules/zod/v4/locales/hi.cjs +2 -0
  401. package/node_modules/zod/v4/locales/hi.js +2 -0
  402. package/node_modules/zod/v4/locales/hr.cjs +2 -0
  403. package/node_modules/zod/v4/locales/hr.js +2 -0
  404. package/node_modules/zod/v4/locales/hu.cjs +2 -0
  405. package/node_modules/zod/v4/locales/hu.js +2 -0
  406. package/node_modules/zod/v4/locales/hy.cjs +2 -0
  407. package/node_modules/zod/v4/locales/hy.js +2 -0
  408. package/node_modules/zod/v4/locales/id.cjs +2 -0
  409. package/node_modules/zod/v4/locales/id.js +2 -0
  410. package/node_modules/zod/v4/locales/index.cjs +22 -1
  411. package/node_modules/zod/v4/locales/index.d.cts +1 -0
  412. package/node_modules/zod/v4/locales/index.d.ts +1 -0
  413. package/node_modules/zod/v4/locales/index.js +1 -0
  414. package/node_modules/zod/v4/locales/is.cjs +2 -0
  415. package/node_modules/zod/v4/locales/is.js +2 -0
  416. package/node_modules/zod/v4/locales/it.cjs +2 -0
  417. package/node_modules/zod/v4/locales/it.js +2 -0
  418. package/node_modules/zod/v4/locales/ja.cjs +2 -0
  419. package/node_modules/zod/v4/locales/ja.js +2 -0
  420. package/node_modules/zod/v4/locales/ka.cjs +2 -0
  421. package/node_modules/zod/v4/locales/ka.js +2 -0
  422. package/node_modules/zod/v4/locales/km.cjs +2 -0
  423. package/node_modules/zod/v4/locales/km.js +2 -0
  424. package/node_modules/zod/v4/locales/kn.cjs +2 -0
  425. package/node_modules/zod/v4/locales/kn.js +2 -0
  426. package/node_modules/zod/v4/locales/ko.cjs +2 -0
  427. package/node_modules/zod/v4/locales/ko.js +2 -0
  428. package/node_modules/zod/v4/locales/lt.cjs +2 -0
  429. package/node_modules/zod/v4/locales/lt.js +2 -0
  430. package/node_modules/zod/v4/locales/mk.cjs +2 -0
  431. package/node_modules/zod/v4/locales/mk.js +2 -0
  432. package/node_modules/zod/v4/locales/ms.cjs +2 -0
  433. package/node_modules/zod/v4/locales/ms.js +2 -0
  434. package/node_modules/zod/v4/locales/ne.cjs +2 -0
  435. package/node_modules/zod/v4/locales/ne.js +2 -0
  436. package/node_modules/zod/v4/locales/nl.cjs +2 -0
  437. package/node_modules/zod/v4/locales/nl.js +2 -0
  438. package/node_modules/zod/v4/locales/nn.cjs +2 -0
  439. package/node_modules/zod/v4/locales/nn.js +2 -0
  440. package/node_modules/zod/v4/locales/no.cjs +2 -0
  441. package/node_modules/zod/v4/locales/no.js +2 -0
  442. package/node_modules/zod/v4/locales/ota.cjs +2 -0
  443. package/node_modules/zod/v4/locales/ota.js +2 -0
  444. package/node_modules/zod/v4/locales/pl.cjs +2 -0
  445. package/node_modules/zod/v4/locales/pl.js +2 -0
  446. package/node_modules/zod/v4/locales/ps.cjs +2 -0
  447. package/node_modules/zod/v4/locales/ps.js +2 -0
  448. package/node_modules/zod/v4/locales/pt-BR.cjs +2 -0
  449. package/node_modules/zod/v4/locales/pt-BR.js +2 -0
  450. package/node_modules/zod/v4/locales/pt.cjs +2 -0
  451. package/node_modules/zod/v4/locales/pt.js +2 -0
  452. package/node_modules/zod/v4/locales/ro.cjs +2 -0
  453. package/node_modules/zod/v4/locales/ro.js +2 -0
  454. package/node_modules/zod/v4/locales/ru.cjs +2 -0
  455. package/node_modules/zod/v4/locales/ru.js +2 -0
  456. package/node_modules/zod/v4/locales/sk.cjs +2 -0
  457. package/node_modules/zod/v4/locales/sk.js +2 -0
  458. package/node_modules/zod/v4/locales/sl.cjs +2 -0
  459. package/node_modules/zod/v4/locales/sl.js +2 -0
  460. package/node_modules/zod/v4/locales/sv.cjs +2 -0
  461. package/node_modules/zod/v4/locales/sv.js +2 -0
  462. package/node_modules/zod/v4/locales/ta.cjs +2 -0
  463. package/node_modules/zod/v4/locales/ta.js +2 -0
  464. package/node_modules/zod/v4/locales/tg.cjs +144 -0
  465. package/node_modules/zod/v4/locales/tg.d.cts +5 -0
  466. package/node_modules/zod/v4/locales/tg.d.ts +4 -0
  467. package/node_modules/zod/v4/locales/tg.js +117 -0
  468. package/node_modules/zod/v4/locales/th.cjs +2 -0
  469. package/node_modules/zod/v4/locales/th.js +2 -0
  470. package/node_modules/zod/v4/locales/tk.cjs +2 -0
  471. package/node_modules/zod/v4/locales/tk.js +2 -0
  472. package/node_modules/zod/v4/locales/tr.cjs +2 -0
  473. package/node_modules/zod/v4/locales/tr.js +2 -0
  474. package/node_modules/zod/v4/locales/uk.cjs +2 -0
  475. package/node_modules/zod/v4/locales/uk.js +2 -0
  476. package/node_modules/zod/v4/locales/ur.cjs +2 -0
  477. package/node_modules/zod/v4/locales/ur.js +2 -0
  478. package/node_modules/zod/v4/locales/uz.cjs +2 -0
  479. package/node_modules/zod/v4/locales/uz.js +2 -0
  480. package/node_modules/zod/v4/locales/vi.cjs +2 -0
  481. package/node_modules/zod/v4/locales/vi.js +2 -0
  482. package/node_modules/zod/v4/locales/yo.cjs +2 -0
  483. package/node_modules/zod/v4/locales/yo.js +2 -0
  484. package/node_modules/zod/v4/locales/zh-CN.cjs +2 -0
  485. package/node_modules/zod/v4/locales/zh-CN.js +2 -0
  486. package/node_modules/zod/v4/locales/zh-TW.cjs +2 -0
  487. package/node_modules/zod/v4/locales/zh-TW.js +2 -0
  488. package/node_modules/zod/v4/mini/checks.cjs +19 -0
  489. package/node_modules/zod/v4/mini/coerce.cjs +19 -0
  490. package/node_modules/zod/v4/mini/deep-partial.cjs +19 -0
  491. package/node_modules/zod/v4/mini/external.cjs +22 -1
  492. package/node_modules/zod/v4/mini/external.d.cts +1 -1
  493. package/node_modules/zod/v4/mini/external.d.ts +1 -1
  494. package/node_modules/zod/v4/mini/external.js +1 -1
  495. package/node_modules/zod/v4/mini/in-out.cjs +19 -0
  496. package/node_modules/zod/v4/mini/index.cjs +19 -0
  497. package/node_modules/zod/v4/mini/iso.cjs +19 -0
  498. package/node_modules/zod/v4/mini/parse.cjs +19 -0
  499. package/node_modules/zod/v4/mini/schemas.cjs +44 -8
  500. package/node_modules/zod/v4/mini/schemas.d.cts +6 -1
  501. package/node_modules/zod/v4/mini/schemas.d.ts +6 -1
  502. package/node_modules/zod/v4/mini/schemas.js +21 -6
  503. package/node_modules/zod/v4-mini/index.cjs +19 -0
  504. package/openclaw.plugin.json +21 -1
  505. package/package.json +9 -6
  506. package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
  507. package/dist/.setup/message-handler.history-CJOsN9w5.mjs +0 -28
  508. package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
  509. package/dist/.setup/provider-session.runtime-BW7QrF5C.mjs +0 -6
  510. package/dist/.setup/provider.runtime-DuhmKdDU.mjs +0 -2
  511. package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
  512. package/dist/.setup/setup-plugin-api-CINIEBLa.mjs +0 -3
  513. package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
  514. package/dist/.setup/targets-D1mAB5yO.mjs +0 -3
  515. package/dist/.setup/thread-bindings.manager-eexkKyrG.mjs +0 -678
  516. package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
  517. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,38 +1,39 @@
1
- import { D as Message, E as Guild, G as Row, J as StringSelectMenu, L as Button, O as User, P as Modal, Q as BaseMessageInteractiveComponent, T as CommandWithSubcommands, Y as TextDisplay, a as MessageCreateListener, c as PresenceUpdateListener, d as ThreadDeleteListener, f as ThreadUpdateListener, h as Plugin, i as InteractionCreateListener, k as hasDiscordV2Components, l as ReadyListener, m as Client, n as GuildCreateListener, o as MessageReactionAddListener, q as Separator, r as GuildDeleteListener, s as MessageReactionRemoveListener, t as discord_exports, v as RateLimitError, w as Command, z as Container } from "./discord-BXpHW-cu.mjs";
2
- import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, d as buildDiscordComponentMessage, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-MqMWUWnE.mjs";
3
- import { C as resolveTimestampMs, E as getDiscordEndpointRuntime, T as assertDiscordEndpointGatewayUrl, a as normalizeDiscordDisplaySlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfig, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordAllowList, l as resolveDiscordChannelConfigWithFallback, m as resolveDiscordMemberAllowed, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, s as resolveDiscordAllowListMatch, t as isDiscordThreadChannelType, u as resolveDiscordChannelPolicyCommandAuthorizer, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./channel-type-DKnjV1XW.mjs";
4
- import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-CwJQoLjM.mjs";
5
- import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-DWQjXhPV.mjs";
1
+ import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, d as buildDiscordComponentMessage, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-Cq1PvIpN.mjs";
2
+ import { $ as BaseMessageInteractiveComponent, B as Container, D as Message, E as Guild, J as Separator, K as Row, O as User, P as Modal, R as Button, T as CommandWithSubcommands, X as TextDisplay, Y as StringSelectMenu, a as MessageCreateListener, c as PresenceUpdateListener, d as ThreadDeleteListener, f as ThreadUpdateListener, h as Plugin, i as InteractionCreateListener, k as hasDiscordV2Components, l as ReadyListener, m as Client, n as GuildCreateListener, o as MessageReactionAddListener, r as GuildDeleteListener, s as MessageReactionRemoveListener, t as discord_exports, v as RateLimitError, w as Command } from "./discord-0xJYfdDD.mjs";
3
+ import { D as getDiscordEndpointRuntime, E as assertDiscordEndpointGatewayUrl, S as formatDiscordUserTag, _ as resolveDiscordOwnerAllowFrom, a as normalizeDiscordDisplaySlug, b as shouldEmitDiscordReactionNotification, c as resolveDiscordChannelConfig, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAccess, i as normalizeDiscordAllowList, l as resolveDiscordChannelConfigWithFallback, m as resolveDiscordMemberAllowed, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, s as resolveDiscordAllowListMatch, t as isDiscordThreadChannelType, u as resolveDiscordChannelPolicyCommandAuthorizer, w as resolveTimestampMs, x as formatDiscordReactionEmoji, y as resolveGroupDmAllow } from "./channel-type-DRCrEMss.mjs";
4
+ import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-ChaMcixG.mjs";
5
+ import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-DxQAMfES.mjs";
6
6
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.mjs";
7
- import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-CBK9zcq5.mjs";
8
- import { o as chunkDiscordTextWithMode } from "./retry-DBfcEgmO.mjs";
9
- import { B as validateDiscordProxyUrl, G as unregisterGateway, P as createDiscordRestClient, R as DISCORD_REST_TIMEOUT_MS, V as withValidatedDiscordProxy, W as registerGateway, b as canViewDiscordGuildChannel, w as hasAnyChannelPermissionDiscord } from "./send.shared-Zwx6BxQ5.mjs";
10
- import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-D0hQ7s50.mjs";
11
- import { n as getDiscordActivitiesRuntime } from "./runtime-BVoa7hhx.mjs";
7
+ import { a as isDiscordRateLimitResponseBody, s as summarizeDiscordResponseBody } from "./api-DVbJwZVt.mjs";
8
+ import { o as chunkDiscordTextWithMode } from "./retry-pz_cSha2.mjs";
9
+ import { B as withValidatedDiscordProxy, C as hasAnyChannelPermissionDiscord, L as DISCORD_REST_TIMEOUT_MS, N as createDiscordRestClient, U as registerGateway, W as unregisterGateway, y as canViewDiscordGuildChannel, z as validateDiscordProxyUrl } from "./send.shared-DGFkbkQR.mjs";
10
+ import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-BISKnb-a.mjs";
11
+ import { n as getDiscordActivitiesRuntime } from "./runtime-sUksZ--Q.mjs";
12
12
  import { t as resolveDiscordCommandOwnerAllowFrom } from "./command-owners-D78sAoOz.mjs";
13
13
  import { n as resolveDiscordChannelInfoSafe, o as resolveDiscordChannelTopicSafe, r as resolveDiscordChannelNameSafe } from "./channel-access-C12aDZ0p.mjs";
14
- import { D as resolveDiscordMessageStickers, c as resolveDiscordVoiceAccess, d as resolveFetchedDiscordThreadLikeChannelContext, o as resolveDiscordVoiceEnabled, r as setDiscordTranscriptsVoiceManager, s as authorizeDiscordVoiceIngress, u as resolveDiscordThreadLikeChannelContext } from "./transcripts-source-CuWYgayu.mjs";
15
- import { i as setPresence, t as clearPresences } from "./presence-cache-dYSHPWMx.mjs";
16
- import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-CKDczUNL.mjs";
14
+ import { D as resolveDiscordReferencedReplyMessage, O as resolveDiscordReferencedReplyMessageId, a as resolveDiscordVoiceEnabled, i as setDiscordTranscriptsVoiceManager, l as resolveDiscordThreadLikeChannelContext, o as authorizeDiscordVoiceIngress, s as resolveDiscordVoiceAccess, u as resolveFetchedDiscordThreadLikeChannelContext } from "./transcripts-source-p8EV179h.mjs";
15
+ import { i as setPresence, t as clearPresences } from "./presence-cache-Di3H3DIU.mjs";
16
+ import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-CrfEI6Bs.mjs";
17
17
  import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-D86uWLt_.mjs";
18
- import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./outbound-session-route-CqWbuMOm.mjs";
19
- import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-eKQ-PLdy.mjs";
20
- import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BbvsLQOZ.mjs";
21
- import { t as resolveDiscordUserAllowlist } from "./resolve-users-ByFlR7LQ.mjs";
22
- import { i as getThreadBindingManager, o as isThreadArchived, u as formatThreadBindingDurationLabel } from "./thread-bindings.manager-eexkKyrG.mjs";
23
- import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-CupW4we4.mjs";
18
+ import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS, u as buildDiscordRoutePeer } from "./outbound-session-route-zVGxxceg.mjs";
19
+ import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-8Pv20CHc.mjs";
20
+ import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BFPNRmVv.mjs";
21
+ import { t as resolveDiscordUserAllowlist } from "./resolve-users-0-aBuCy3.mjs";
22
+ import { a as isThreadArchived, n as getThreadBindingManager } from "./thread-bindings.manager-DN-NissX.mjs";
23
+ import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-LYrIHlBF.mjs";
24
24
  import { i as sanitizeRecentModels, n as normalizeModelRef, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.mjs";
25
- import { t as resolveDiscordSenderIdentity } from "./sender-identity-0Ymgvmaj.mjs";
26
- import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-BN7JtScm.mjs";
25
+ import { t as resolveDiscordSenderIdentity } from "./sender-identity-B9X5Vb9R.mjs";
26
+ import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-BKFqavHZ.mjs";
27
27
  import { createRequire } from "node:module";
28
28
  import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
29
29
  import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes, PermissionFlagsBits } from "discord-api-types/v10";
30
30
  import { Type } from "typebox";
31
31
  import { Check, Errors } from "typebox/value";
32
32
  import { createHash, randomUUID } from "node:crypto";
33
- import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
34
33
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
34
+ import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolvePromptHistoryLimit, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
35
35
  import { inspect } from "node:util";
36
+ import * as fetchRuntimeSdk from "openclaw/plugin-sdk/fetch-runtime";
36
37
  import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
37
38
  import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
38
39
  import { fetchWithSsrFGuard, formatErrorMessage, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -53,29 +54,28 @@ import { buildOutboundSessionContext, listMessageReceiptPlatformIds, resolveChan
53
54
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
54
55
  import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
55
56
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
56
- import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
57
+ import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorization, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
57
58
  import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
58
59
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
59
- import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-dispatch-runtime";
60
- import { createChannelPartialDeliveryError, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
60
+ import { buildChannelInboundEventContext, createChannelPartialDeliveryError, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
61
61
  import path from "node:path";
62
- import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAllowlist$1 } from "openclaw/plugin-sdk/security-runtime";
62
+ import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
63
63
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
64
64
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
65
- import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
66
- import * as conversationRuntime from "openclaw/plugin-sdk/conversation-binding-runtime";
65
+ import { buildPairingReply, formatThreadBindingDurationLabel, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
66
+ import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute } from "openclaw/plugin-sdk/conversation-binding-runtime";
67
67
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
68
- import { createChannelIngressResolver, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
69
- import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
68
+ import { readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
70
69
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
71
70
  import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
72
71
  import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
73
- import { enqueueRoutedSystemEvent, enqueueRoutedSystemEvent as enqueueRoutedSystemEvent$1 } from "openclaw/plugin-sdk/system-event-runtime";
74
- import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
75
- import { captureHttpExchange, captureWsEvent, resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
72
+ import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
73
+ import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
74
+ import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
75
+ import * as proxyCaptureSdk from "openclaw/plugin-sdk/proxy-capture";
76
+ import { resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
76
77
  import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
77
78
  import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
78
- import { Agent } from "undici";
79
79
  import * as dns from "node:dns";
80
80
  import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, mergeNativeCommandSpecs, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
81
81
  import { PLUGIN_COMMAND_DISPATCH } from "openclaw/plugin-sdk/plugin-command-runtime";
@@ -83,7 +83,7 @@ import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-
83
83
  import * as modelsProviderRuntime from "openclaw/plugin-sdk/models-provider-runtime";
84
84
  import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
85
85
  import { EventEmitter } from "node:events";
86
- import { Agent as Agent$1 } from "node:https";
86
+ import { Agent } from "node:https";
87
87
  import { channelReadyPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
88
88
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
89
89
  import { stripPlainTextToolCallBlocks } from "openclaw/plugin-sdk/tool-payload";
@@ -382,7 +382,7 @@ function createDiscordDynamicAccessGroupResolver(params) {
382
382
  };
383
383
  }
384
384
  function createDiscordIngressResolver(params) {
385
- return createChannelIngressResolver({
385
+ return getDiscordRuntime().channel.inbound.ingress.createResolver({
386
386
  channelId: DISCORD_CHANNEL_ID,
387
387
  accountId: params.accountId,
388
388
  identity: discordIngressIdentity,
@@ -529,22 +529,10 @@ async function runDiscordReactionHandler(initialParams) {
529
529
  listener: params.listener,
530
530
  event: params.event,
531
531
  run: async () => handleDiscordReactionEvent({
532
+ ...params.handlerParams,
532
533
  data: params.data,
533
534
  client: params.client,
534
- action: params.action,
535
- cfg: params.handlerParams.cfg,
536
- isPolicyCurrent: params.handlerParams.isPolicyCurrent,
537
- accountId: params.handlerParams.accountId,
538
- botUserId: params.handlerParams.botUserId,
539
- dmEnabled: params.handlerParams.dmEnabled,
540
- groupDmEnabled: params.handlerParams.groupDmEnabled,
541
- groupDmChannels: params.handlerParams.groupDmChannels,
542
- dmPolicy: params.handlerParams.dmPolicy,
543
- allowFrom: params.handlerParams.allowFrom,
544
- groupPolicy: params.handlerParams.groupPolicy,
545
- allowNameMatching: params.handlerParams.allowNameMatching,
546
- guildEntries: params.handlerParams.guildEntries,
547
- logger: params.handlerParams.logger
535
+ action: params.action
548
536
  })
549
537
  });
550
538
  }
@@ -626,51 +614,6 @@ async function authorizeDiscordReactionIngress(params) {
626
614
  };
627
615
  return { allowed: true };
628
616
  }
629
- async function handleDiscordThreadReactionNotification(params) {
630
- if (params.reactionMode === "off") return;
631
- if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
632
- const { access, channelConfig } = await params.resolveThreadChannelAccess();
633
- if (!access.allowed || !params.shouldNotifyReaction({
634
- mode: params.reactionMode,
635
- channelConfig
636
- })) return;
637
- const { baseText } = params.resolveReactionBase();
638
- params.emitReaction(baseText, params.parentId);
639
- return;
640
- }
641
- const message = await params.message.fetch().catch(() => null);
642
- const { access, channelConfig } = await params.resolveThreadChannelAccess();
643
- const messageAuthorId = message?.author?.id ?? void 0;
644
- if (!access.allowed || !params.shouldNotifyReaction({
645
- mode: params.reactionMode,
646
- messageAuthorId,
647
- channelConfig
648
- })) return;
649
- params.emitReactionWithAuthor(message);
650
- }
651
- async function handleDiscordChannelReactionNotification(params) {
652
- if (params.isGuildMessage) {
653
- if (!(await params.authorizeReactionIngressForChannel(params.channelConfig)).allowed) return;
654
- }
655
- if (params.reactionMode === "off") return;
656
- if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
657
- if (!params.shouldNotifyReaction({
658
- mode: params.reactionMode,
659
- channelConfig: params.channelConfig
660
- })) return;
661
- const { baseText } = params.resolveReactionBase();
662
- params.emitReaction(baseText, params.parentId);
663
- return;
664
- }
665
- const message = await params.message.fetch().catch(() => null);
666
- const messageAuthorId = message?.author?.id ?? void 0;
667
- if (!params.shouldNotifyReaction({
668
- mode: params.reactionMode,
669
- messageAuthorId,
670
- channelConfig: params.channelConfig
671
- })) return;
672
- params.emitReactionWithAuthor(message);
673
- }
674
617
  function hasDiscordGuildChannelOverrides(guildInfo) {
675
618
  return Boolean(guildInfo?.channels && Object.keys(guildInfo.channels).length > 0);
676
619
  }
@@ -758,57 +701,10 @@ async function handleDiscordReactionEvent(params) {
758
701
  const parentId = isThreadChannel ? channelContext.threadParentId : channelContext.parentId;
759
702
  const parentName = isThreadChannel ? channelContext.threadParentName : void 0;
760
703
  const parentSlug = isThreadChannel ? channelContext.threadParentSlug : "";
761
- let reactionBase = null;
762
- const resolveReactionBase = () => {
763
- if (reactionBase) return reactionBase;
764
- const emojiLabel = formatDiscordReactionEmoji(data.emoji);
765
- const actorLabel = formatDiscordUserTag(user) || user.id;
766
- const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
767
- const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
768
- reactionBase = {
769
- baseText: `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`,
770
- contextKey: `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`
771
- };
772
- return reactionBase;
773
- };
774
- const emitReaction = (text, parentPeerId) => {
775
- const { contextKey } = resolveReactionBase();
776
- const route = resolveAgentRoute({
777
- cfg: params.cfg,
778
- channel: "discord",
779
- accountId: params.accountId,
780
- guildId: data.guild_id ?? void 0,
781
- memberRoleIds,
782
- peer: {
783
- kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
784
- id: isDirectMessage ? user.id : data.channel_id
785
- },
786
- parentPeer: parentPeerId ? {
787
- kind: "channel",
788
- id: parentPeerId
789
- } : void 0
790
- });
791
- enqueueRoutedSystemEvent(text, route, { contextKey });
792
- };
793
- const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
794
- mode: options.mode,
795
- botId: botUserId,
796
- messageAuthorId: options.messageAuthorId,
797
- userId: user.id,
798
- userName: user.username,
799
- userTag: formatDiscordUserTag(user),
800
- channelConfig: options.channelConfig,
801
- guildInfo,
802
- memberRoleIds,
803
- allowNameMatching: params.allowNameMatching
804
- });
805
- const emitReactionWithAuthor = (message) => {
806
- const { baseText } = resolveReactionBase();
807
- const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
808
- const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
809
- emitReaction(text, parentId);
810
- };
811
- const resolveThreadChannelConfig = () => resolveDiscordChannelConfigWithFallback({
704
+ if (isThreadChannel && reactionMode === "off") return;
705
+ let message = null;
706
+ if (isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
707
+ const channelConfig = resolveDiscordChannelConfigWithFallback({
812
708
  guildInfo,
813
709
  channelId: data.channel_id,
814
710
  channelName,
@@ -816,54 +712,51 @@ async function handleDiscordReactionEvent(params) {
816
712
  parentId,
817
713
  parentName,
818
714
  parentSlug,
819
- scope: "thread"
820
- });
821
- const authorizeReactionIngressForChannel = async (channelConfig) => await authorizeDiscordReactionIngress({
822
- ...reactionIngressBase,
823
- channelConfig
715
+ scope: isThreadChannel ? "thread" : "channel"
824
716
  });
825
- const resolveThreadChannelAccess = async () => {
826
- const channelConfig = resolveThreadChannelConfig();
827
- return {
828
- access: await authorizeReactionIngressForChannel(channelConfig),
717
+ if (isGuildMessage || isThreadChannel) {
718
+ if (!(await authorizeDiscordReactionIngress({
719
+ ...reactionIngressBase,
829
720
  channelConfig
830
- };
831
- };
832
- if (isThreadChannel) {
833
- await handleDiscordThreadReactionNotification({
834
- reactionMode,
835
- message: data.message,
836
- parentId,
837
- resolveThreadChannelAccess,
838
- shouldNotifyReaction,
839
- resolveReactionBase,
840
- emitReaction,
841
- emitReactionWithAuthor
842
- });
843
- return;
721
+ })).allowed) return;
844
722
  }
845
- const channelConfig = resolveDiscordChannelConfigWithFallback({
846
- guildInfo,
847
- channelId: data.channel_id,
848
- channelName,
849
- channelSlug,
850
- parentId,
851
- parentName,
852
- parentSlug,
853
- scope: "channel"
854
- });
855
- await handleDiscordChannelReactionNotification({
856
- isGuildMessage,
857
- reactionMode,
858
- message: data.message,
723
+ if (!isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
724
+ if (!shouldEmitDiscordReactionNotification({
725
+ mode: reactionMode,
726
+ botId: botUserId,
727
+ messageAuthorId: message?.author?.id,
728
+ userId: user.id,
729
+ userName: user.username,
730
+ userTag: formatDiscordUserTag(user),
859
731
  channelConfig,
860
- parentId,
861
- authorizeReactionIngressForChannel,
862
- shouldNotifyReaction,
863
- resolveReactionBase,
864
- emitReaction,
865
- emitReactionWithAuthor
732
+ guildInfo,
733
+ memberRoleIds,
734
+ allowNameMatching: params.allowNameMatching
735
+ })) return;
736
+ const emojiLabel = formatDiscordReactionEmoji(data.emoji);
737
+ const actorLabel = formatDiscordUserTag(user) || user.id;
738
+ const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
739
+ const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
740
+ const baseText = `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`;
741
+ const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
742
+ const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
743
+ const contextKey = `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`;
744
+ const route = resolveAgentRoute({
745
+ cfg: params.cfg,
746
+ channel: "discord",
747
+ accountId: params.accountId,
748
+ guildId: data.guild_id ?? void 0,
749
+ memberRoleIds,
750
+ peer: {
751
+ kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
752
+ id: isDirectMessage ? user.id : data.channel_id
753
+ },
754
+ parentPeer: parentId ? {
755
+ kind: "channel",
756
+ id: parentId
757
+ } : void 0
866
758
  });
759
+ enqueueRoutedSystemEvent(text, route, { contextKey });
867
760
  } catch (err) {
868
761
  params.logger.error(danger(`discord reaction handler failed: ${String(err)}`));
869
762
  }
@@ -899,7 +792,7 @@ var DiscordInteractionListener = class extends InteractionCreateListener {
899
792
  }
900
793
  async handle(data, client) {
901
794
  this.onEvent?.();
902
- Promise.resolve().then(() => client.handleInteraction(data, {})).catch((err) => {
795
+ Promise.resolve().then(() => client.handleInteraction(data)).catch((err) => {
903
796
  (this.logger ?? discordEventQueueLog).error(danger(`discord interaction handler failed: ${String(err)}`));
904
797
  });
905
798
  }
@@ -1254,7 +1147,7 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
1254
1147
  event: this.type,
1255
1148
  run: async () => {
1256
1149
  const threadId = data.id;
1257
- getThreadBindingManager(this.accountId)?.unbindThread({
1150
+ await getThreadBindingManager(this.accountId)?.unbindThread({
1258
1151
  threadId,
1259
1152
  reason: "thread-delete",
1260
1153
  sendFarewell: false
@@ -1276,14 +1169,12 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
1276
1169
  };
1277
1170
  //#endregion
1278
1171
  //#region extensions/discord/src/internal/gateway-dispatch.ts
1279
- function dispatchVoiceGatewayEvent(client, type, data) {
1280
- const guildId = readGuildId(data);
1172
+ function dispatchVoiceGatewayEvent(client, payload) {
1173
+ const guildId = readGuildId(payload.d);
1281
1174
  if (!guildId) return;
1282
1175
  const adapter = (client.getPlugin("voice")?.adapters)?.get(guildId);
1283
- const voiceServerUpdate = GatewayDispatchEvents.VoiceServerUpdate;
1284
- const voiceStateUpdate = GatewayDispatchEvents.VoiceStateUpdate;
1285
- if (type === voiceServerUpdate) adapter?.onVoiceServerUpdate?.(data);
1286
- if (type === voiceStateUpdate) adapter?.onVoiceStateUpdate?.(data);
1176
+ if (payload.t === GatewayDispatchEvents.VoiceServerUpdate) adapter?.onVoiceServerUpdate?.(payload.d);
1177
+ if (payload.t === GatewayDispatchEvents.VoiceStateUpdate) adapter?.onVoiceStateUpdate?.(payload.d);
1287
1178
  }
1288
1179
  function mapGatewayDispatchData(client, type, data) {
1289
1180
  const messageCreate = GatewayDispatchEvents.MessageCreate;
@@ -1514,10 +1405,8 @@ async function resolveAllowFromByUserAllowlist(params) {
1514
1405
  function collectGuildUserEntries(guildEntries) {
1515
1406
  const userEntries = /* @__PURE__ */ new Set();
1516
1407
  for (const guild of Object.values(guildEntries)) {
1517
- if (!guild || typeof guild !== "object") continue;
1518
1408
  addAllowlistUserEntriesFromConfigEntry(userEntries, guild);
1519
- const channels = guild.channels ?? {};
1520
- for (const channel of Object.values(channels)) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
1409
+ for (const channel of Object.values(guild.channels ?? {})) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
1521
1410
  }
1522
1411
  return userEntries;
1523
1412
  }
@@ -1534,15 +1423,13 @@ async function resolveGuildEntriesByUserAllowlist(params) {
1534
1423
  formatResolved: formatDiscordUserResolved,
1535
1424
  formatUnresolved: formatDiscordUserUnresolved
1536
1425
  });
1537
- const nextGuilds = { ...params.guildEntries };
1538
- for (const [guildKey, guildConfig] of Object.entries(params.guildEntries)) {
1539
- if (!guildConfig || typeof guildConfig !== "object") continue;
1426
+ const nextGuilds = patchAllowlistUsersInConfigEntries({
1427
+ entries: params.guildEntries,
1428
+ resolvedMap,
1429
+ strategy: "canonicalize"
1430
+ });
1431
+ for (const [guildKey, guildConfig] of Object.entries(nextGuilds)) {
1540
1432
  const nextGuild = { ...guildConfig };
1541
- const users = guildConfig.users;
1542
- if (Array.isArray(users) && users.length > 0) nextGuild.users = canonicalizeAllowlistWithResolvedIds({
1543
- existing: users,
1544
- resolvedMap
1545
- });
1546
1433
  const channels = guildConfig.channels ?? {};
1547
1434
  if (channels && typeof channels === "object") nextGuild.channels = patchAllowlistUsersInConfigEntries({
1548
1435
  entries: channels,
@@ -1602,7 +1489,7 @@ function isDiscordTransportHostname(hostname) {
1602
1489
  return DISCORD_DNS_HOSTS.some((target) => normalized === target || normalized.endsWith(`.${target}`));
1603
1490
  }
1604
1491
  function reorderLookupAddresses(addresses) {
1605
- if (!Array.isArray(addresses) || addresses.length < 2) return addresses;
1492
+ if (addresses.length < 2) return addresses;
1606
1493
  const ipv4 = addresses.filter((entry) => entry.family === 4);
1607
1494
  const ipv6 = addresses.filter((entry) => entry.family === 6);
1608
1495
  if (ipv4.length === 0) return ipv6;
@@ -1655,13 +1542,9 @@ function createDiscordEndpointDnsLookup(endpointHostname) {
1655
1542
  }
1656
1543
  //#endregion
1657
1544
  //#region extensions/discord/src/monitor/rest-fetch.ts
1545
+ const captureSdk$2 = proxyCaptureSdk;
1546
+ const fetchSdk = fetchRuntimeSdk;
1658
1547
  const discordDnsLookup$1 = createDiscordDnsLookup();
1659
- function createDirectDiscordRestDispatcher() {
1660
- return new Agent({
1661
- allowH2: false,
1662
- connect: { lookup: discordDnsLookup$1 }
1663
- });
1664
- }
1665
1548
  function createEnvProxyDiscordRestDispatcher(runtime) {
1666
1549
  const envProxyOptions = resolveEnvHttpProxyAgentOptions();
1667
1550
  if (!envProxyOptions) return;
@@ -1680,7 +1563,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
1680
1563
  ...init,
1681
1564
  dispatcher
1682
1565
  }).then((response) => {
1683
- captureHttpExchange({
1566
+ captureSdk$2.captureHttpExchangeAsync?.({
1684
1567
  url: resolveRequestUrl(input),
1685
1568
  method: init?.method ?? "GET",
1686
1569
  requestHeaders: init?.headers,
@@ -1688,7 +1571,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
1688
1571
  response,
1689
1572
  flowId: randomUUID(),
1690
1573
  meta: { subsystem: "discord-rest" }
1691
- });
1574
+ }).catch(() => {});
1692
1575
  return response;
1693
1576
  })));
1694
1577
  }
@@ -1700,7 +1583,12 @@ function resolveDiscordRestFetch(proxyUrl, runtime) {
1700
1583
  runtime.log?.("discord: rest proxy enabled");
1701
1584
  return fetcher;
1702
1585
  }
1703
- return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ?? createDirectDiscordRestDispatcher());
1586
+ return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ?? fetchSdk.createHttp1Agent?.({ connect: { lookup: discordDnsLookup$1 } }) ?? createHttp1EnvHttpProxyAgent({
1587
+ httpProxy: "",
1588
+ httpsProxy: "",
1589
+ noProxy: "*",
1590
+ connect: { lookup: discordDnsLookup$1 }
1591
+ }));
1704
1592
  }
1705
1593
  //#endregion
1706
1594
  //#region extensions/discord/src/monitor/live-policy.ts
@@ -1848,6 +1736,13 @@ async function readDiscordInteractionPolicy(readPolicy) {
1848
1736
  //#endregion
1849
1737
  //#region extensions/discord/src/monitor/native-command-reply.ts
1850
1738
  const DISCORD_EMPTY_VISIBLE_REPLY_WARNING = "⚠️ Command produced no visible reply.";
1739
+ function resolveDiscordInteractionReplyOptions(params) {
1740
+ return {
1741
+ textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
1742
+ maxLinesPerMessage: resolveDiscordMaxLinesPerMessage(params),
1743
+ chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
1744
+ };
1745
+ }
1851
1746
  function isDiscordUnknownInteraction(error) {
1852
1747
  if (!error || typeof error !== "object") return false;
1853
1748
  const err = error;
@@ -1937,55 +1832,33 @@ async function deliverDiscordInteractionReply(params) {
1937
1832
  if (!payloadDelivered) throw expiry;
1938
1833
  throw createChannelPartialDeliveryError(expiry, { visibleReplySent: true });
1939
1834
  };
1940
- if (reply.hasMedia) {
1941
- const media = await Promise.all(reply.mediaUrls.map(async (url) => {
1942
- const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
1943
- return {
1944
- name: loaded.fileName ?? "upload",
1945
- data: loaded.buffer,
1946
- contentType: loaded.contentType
1947
- };
1948
- }));
1949
- const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
1950
- maxChars: textLimit,
1951
- maxLines: maxLinesPerMessage,
1952
- chunkMode
1953
- }));
1954
- await sendMessage(chunks[0] ?? "", media, firstMessageComponents, firstMessageEmbeds);
1955
- for (const chunk of chunks.slice(1)) {
1956
- if (!chunk.trim()) continue;
1957
- await sendMessage(chunk);
1958
- }
1959
- return payloadDelivered;
1960
- }
1961
- if (!reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
1835
+ const files = reply.hasMedia ? await Promise.all(reply.mediaUrls.map(async (url) => {
1836
+ const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
1837
+ return {
1838
+ name: loaded.fileName ?? "upload",
1839
+ data: loaded.buffer,
1840
+ contentType: loaded.contentType
1841
+ };
1842
+ })) : void 0;
1843
+ if (!files && !reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
1962
1844
  const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
1963
1845
  maxChars: textLimit,
1964
1846
  maxLines: maxLinesPerMessage,
1965
1847
  chunkMode
1966
1848
  }));
1967
1849
  if (chunks.length === 0) chunks.push("");
1968
- for (const chunk of chunks) {
1969
- if (!chunk.trim() && !firstMessageComponents && !firstMessageEmbeds) continue;
1970
- await sendMessage(chunk, void 0, firstMessageComponents, firstMessageEmbeds);
1850
+ for (const [index, chunk] of chunks.entries()) {
1851
+ const chunkFiles = index === 0 ? files : void 0;
1852
+ if (!chunk.trim() && !chunkFiles && !firstMessageComponents && !firstMessageEmbeds) continue;
1853
+ await sendMessage(chunk, chunkFiles, firstMessageComponents, firstMessageEmbeds);
1971
1854
  }
1972
1855
  return payloadDelivered;
1973
1856
  }
1974
1857
  //#endregion
1975
1858
  //#region extensions/discord/src/monitor/native-command-route.ts
1976
- async function resolveDiscordNativeInteractionRouteState(params) {
1977
- const route = resolveDiscordBoundConversationRoute({
1978
- cfg: params.cfg,
1979
- accountId: params.accountId,
1980
- guildId: params.guildId,
1981
- memberRoleIds: params.memberRoleIds,
1982
- isDirectMessage: params.isDirectMessage,
1983
- isGroupDm: params.isGroupDm,
1984
- directUserId: params.directUserId,
1985
- conversationId: params.conversationId,
1986
- parentConversationId: params.parentConversationId
1987
- });
1988
- const configuredRoute = params.threadBinding == null ? conversationRuntime.resolveConfiguredBindingRoute({
1859
+ function resolveDiscordNativeInteractionRouteState(params) {
1860
+ const route = resolveDiscordBoundConversationRoute(params);
1861
+ const configuredRoute = params.threadBinding == null ? resolveConfiguredBindingRoute({
1989
1862
  cfg: params.cfg,
1990
1863
  route,
1991
1864
  conversation: {
@@ -2008,17 +1881,14 @@ async function resolveDiscordNativeInteractionRouteState(params) {
2008
1881
  }),
2009
1882
  boundSessionKey,
2010
1883
  configuredRoute,
2011
- configuredBinding,
2012
- bindingReadiness: params.enforceConfiguredBindingReadiness && configuredBinding ? await conversationRuntime.ensureConfiguredBindingRouteReady({
2013
- cfg: params.cfg,
2014
- bindingResolution: configuredBinding
2015
- }) : null
1884
+ configuredBinding
2016
1885
  };
2017
1886
  }
2018
1887
  //#endregion
2019
1888
  //#region extensions/discord/src/monitor/native-command.runtime.ts
2020
1889
  const nativeCommandRuntime = {
2021
1890
  dispatchChannelInboundTurn,
1891
+ ensureConfiguredBindingRouteReady,
2022
1892
  resolveDirectStatusReplyForSession,
2023
1893
  resolveDiscordNativeInteractionRouteState,
2024
1894
  getSessionEntry
@@ -2055,15 +1925,9 @@ async function dispatchDiscordNativeAgentReply(params) {
2055
1925
  sessionKey: params.ctxPayload.CommandTargetSessionKey ?? params.effectiveRoute.sessionKey
2056
1926
  },
2057
1927
  mediaLocalRoots: params.mediaLocalRoots,
2058
- textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
2059
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
2060
- cfg: params.cfg,
2061
- discordConfig: params.discordConfig,
2062
- accountId: params.accountId
2063
- }),
1928
+ ...resolveDiscordInteractionReplyOptions(params),
2064
1929
  preferFollowUp: params.preferFollowUp || didReply,
2065
- responseEphemeral: params.responseEphemeral,
2066
- chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
1930
+ responseEphemeral: params.responseEphemeral
2067
1931
  });
2068
1932
  didReply ||= payloadDelivered;
2069
1933
  return payloadDelivered ? { visibleReplySent: true } : {
@@ -2109,11 +1973,7 @@ async function dispatchDiscordNativeAgentReply(params) {
2109
1973
  content: DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
2110
1974
  ephemeral: true
2111
1975
  };
2112
- if (params.preferFollowUp) {
2113
- await params.interaction.followUp(payload);
2114
- return;
2115
- }
2116
- await params.interaction.reply(payload);
1976
+ await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
2117
1977
  });
2118
1978
  return dispatchResult;
2119
1979
  }
@@ -2125,9 +1985,6 @@ function resolveDiscordSlashCommandConfig(raw) {
2125
1985
  //#endregion
2126
1986
  //#region extensions/discord/src/monitor/native-command-arg-ui.ts
2127
1987
  const DISCORD_COMMAND_ARG_CUSTOM_ID_KEY = "cmdarg";
2128
- function createCommandArgsWithValue(params) {
2129
- return { values: { [params.argName]: params.value } };
2130
- }
2131
1988
  function buildDiscordCommandArgCustomId(params) {
2132
1989
  return [
2133
1990
  `${DISCORD_COMMAND_ARG_CUSTOM_ID_KEY}:command=${encodeCustomIdComponent(params.command)}`,
@@ -2172,45 +2029,33 @@ async function handleDiscordCommandArgInteraction(params) {
2172
2029
  return;
2173
2030
  }
2174
2031
  if (await clearWithMessage(`⏳ Applying ${parsed.value}...`) === null) return;
2175
- const commandArgs = createCommandArgsWithValue({
2176
- argName: parsed.arg,
2177
- value: parsed.value
2178
- });
2032
+ const commandArgs = { values: { [parsed.arg]: parsed.value } };
2179
2033
  const commandArgsWithRaw = {
2180
2034
  ...commandArgs,
2181
2035
  raw: serializeCommandArgs(commandDefinition, commandArgs)
2182
2036
  };
2183
2037
  const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
2184
2038
  await params.dispatchCommandInteraction({
2185
- readPolicy: ctx.readPolicy,
2039
+ ...ctx,
2186
2040
  interaction,
2187
2041
  prompt,
2188
2042
  command: commandDefinition,
2189
2043
  commandArgs: commandArgsWithRaw,
2190
- cfg: ctx.cfg,
2191
- discordConfig: ctx.discordConfig,
2192
- accountId: ctx.accountId,
2193
- sessionPrefix: ctx.sessionPrefix,
2194
2044
  preferFollowUp: true,
2195
- threadBindings: ctx.threadBindings,
2196
2045
  responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
2197
- dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
2198
2046
  pluginCommandDispatch: { kind: "non-plugin" }
2199
2047
  });
2200
2048
  }
2201
- async function runDiscordCommandArgButton(params) {
2202
- await handleDiscordCommandArgInteraction(params);
2203
- }
2204
2049
  var DiscordCommandArgButton = class extends Button {
2205
2050
  constructor(params) {
2206
2051
  super();
2207
- this.style = ButtonStyle.Secondary;
2052
+ this.params = params;
2208
2053
  this.label = params.label;
2209
2054
  this.customId = params.customId;
2210
- this.params = params;
2055
+ this.style = params.style ?? ButtonStyle.Secondary;
2211
2056
  }
2212
2057
  async run(interaction, data) {
2213
- await runDiscordCommandArgButton({
2058
+ await handleDiscordCommandArgInteraction({
2214
2059
  ...this.params,
2215
2060
  interaction,
2216
2061
  data
@@ -2244,23 +2089,205 @@ function buildDiscordCommandArgMenu(params) {
2244
2089
  components: rows
2245
2090
  };
2246
2091
  }
2247
- var DiscordCommandArgFallbackButton = class extends Button {
2248
- constructor(params) {
2249
- super();
2250
- this.params = params;
2251
- this.label = "cmdarg";
2252
- this.customId = "cmdarg:seed=1";
2253
- }
2254
- async run(interaction, data) {
2255
- await runDiscordCommandArgButton({
2256
- ...this.params,
2257
- interaction,
2258
- data
2259
- });
2260
- }
2261
- };
2262
2092
  function createDiscordCommandArgFallbackButton$1(params) {
2263
- return new DiscordCommandArgFallbackButton(params);
2093
+ return new DiscordCommandArgButton({
2094
+ ...params,
2095
+ label: "cmdarg",
2096
+ customId: "cmdarg:seed=1",
2097
+ style: ButtonStyle.Primary
2098
+ });
2099
+ }
2100
+ //#endregion
2101
+ //#region extensions/discord/src/monitor/inbound-context.ts
2102
+ function createDiscordSupplementalContextAccessChecker(params) {
2103
+ const userAllowList = params.channelConfig?.users ?? params.guildInfo?.users ?? [];
2104
+ const roleAllowList = params.channelConfig?.roles ?? params.guildInfo?.roles ?? [];
2105
+ const allowFrom = [...userAllowList, ...roleAllowList];
2106
+ return (sender) => {
2107
+ return resolveInboundSupplementalSenderAllowed({
2108
+ isGroup: params.isGuild,
2109
+ groupPolicy: allowFrom.length === 0 ? "open" : "allowlist",
2110
+ allowFrom,
2111
+ isSenderAllowed: () => resolveDiscordMemberAllowed({
2112
+ userAllowList,
2113
+ roleAllowList,
2114
+ memberRoleIds: [...sender.memberRoleIds ?? []],
2115
+ userId: sender.id ?? "",
2116
+ userName: sender.name,
2117
+ userTag: sender.tag,
2118
+ allowNameMatching: params.allowNameMatching
2119
+ })
2120
+ });
2121
+ };
2122
+ }
2123
+ function buildDiscordGroupSystemPrompt(channelConfig) {
2124
+ return channelConfig?.systemPrompt?.trim() || void 0;
2125
+ }
2126
+ function buildDiscordChannelStructuredContext(params) {
2127
+ if (!params.isGuild || typeof params.channelTopic !== "string" || !params.channelTopic.trim()) return;
2128
+ return [{
2129
+ label: "Discord channel metadata",
2130
+ source: "discord",
2131
+ type: "channel_metadata",
2132
+ payload: { topic: params.channelTopic.trim() }
2133
+ }];
2134
+ }
2135
+ function buildDiscordInboundAccessContext(params) {
2136
+ return {
2137
+ groupSystemPrompt: params.isGuild ? buildDiscordGroupSystemPrompt(params.channelConfig) : void 0,
2138
+ channelStructuredContext: buildDiscordChannelStructuredContext({
2139
+ isGuild: params.isGuild,
2140
+ channelTopic: params.channelTopic
2141
+ }),
2142
+ ownerAllowFrom: resolveDiscordOwnerAllowFrom({
2143
+ channelConfig: params.channelConfig,
2144
+ guildInfo: params.guildInfo,
2145
+ sender: params.sender,
2146
+ allowNameMatching: params.allowNameMatching
2147
+ })
2148
+ };
2149
+ }
2150
+ //#endregion
2151
+ //#region extensions/discord/src/monitor/native-command-context.ts
2152
+ async function buildDiscordNativeCommandContext(params) {
2153
+ const conversationLabel = params.isDirectMessage ? params.user.globalName ?? params.user.username : params.channelId;
2154
+ const { groupSystemPrompt, ownerAllowFrom, channelStructuredContext } = buildDiscordInboundAccessContext({
2155
+ channelConfig: params.channelConfig,
2156
+ guildInfo: params.guildInfo,
2157
+ sender: params.sender,
2158
+ allowNameMatching: params.allowNameMatching,
2159
+ isGuild: params.isGuild,
2160
+ channelTopic: params.channelTopic
2161
+ });
2162
+ const conversation = {
2163
+ kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
2164
+ id: params.channelId,
2165
+ parentId: params.isThreadChannel ? params.threadParentId : void 0,
2166
+ threadId: params.isThreadChannel ? params.channelId : void 0
2167
+ };
2168
+ const allowFrom = params.commandAuthorized ? [`user:${params.user.id}`] : [];
2169
+ const channelIngress = await getDiscordRuntime().channel.inbound.ingress.createResolver({
2170
+ channelId: "discord",
2171
+ accountId: params.accountId,
2172
+ identity: discordIngressIdentity,
2173
+ useDefaultPairingStore: false
2174
+ }).command({
2175
+ subject: {
2176
+ stableId: params.user.id,
2177
+ aliases: { participantKind: "user" }
2178
+ },
2179
+ conversation,
2180
+ contextBinding: {
2181
+ agentId: params.agentId,
2182
+ sessionKey: params.sessionKey,
2183
+ nativeChannelId: params.channelId,
2184
+ messageId: params.interactionId,
2185
+ inboundEventKind: "user_request"
2186
+ },
2187
+ event: {
2188
+ kind: "native-command",
2189
+ mayPair: false
2190
+ },
2191
+ dmPolicy: "allowlist",
2192
+ groupPolicy: "allowlist",
2193
+ allowFrom,
2194
+ groupAllowFrom: allowFrom,
2195
+ command: { modeWhenAccessGroupsOff: "configured" }
2196
+ });
2197
+ return await (params.buildContext ?? buildChannelInboundEventContext)({
2198
+ channel: "discord",
2199
+ channelIngress,
2200
+ accountId: params.accountId,
2201
+ messageId: params.interactionId,
2202
+ timestamp: params.timestampMs ?? Date.now(),
2203
+ from: params.isDirectMessage ? `discord:${params.user.id}` : params.isGroupDm ? `discord:group:${params.channelId}` : `discord:channel:${params.channelId}`,
2204
+ sender: {
2205
+ id: params.user.id,
2206
+ name: params.user.globalName ?? params.user.username,
2207
+ username: params.user.username,
2208
+ tag: params.sender.tag,
2209
+ roles: params.memberRoleIds
2210
+ },
2211
+ conversation: {
2212
+ ...conversation,
2213
+ nativeChannelId: params.channelId,
2214
+ routePeer: buildDiscordRoutePeer({
2215
+ isDirectMessage: params.isDirectMessage,
2216
+ isGroupDm: params.isGroupDm,
2217
+ directUserId: params.user.id,
2218
+ conversationId: params.channelId
2219
+ }),
2220
+ label: conversationLabel,
2221
+ spaceId: params.isGuild ? params.guildInfo?.id ?? params.guildInfo?.slug ?? params.guildId : void 0
2222
+ },
2223
+ route: {
2224
+ agentId: params.agentId,
2225
+ accountId: params.accountId,
2226
+ routeSessionKey: params.commandTargetSessionKey,
2227
+ dispatchSessionKey: params.sessionKey
2228
+ },
2229
+ reply: {
2230
+ to: `slash:${params.user.id}`,
2231
+ originatingTo: resolveDiscordConversationIdentity({
2232
+ isDirectMessage: params.isDirectMessage,
2233
+ userId: params.user.id,
2234
+ channelId: params.channelId
2235
+ }) ?? (params.isDirectMessage ? `user:${params.user.id}` : `channel:${params.channelId}`)
2236
+ },
2237
+ message: { rawBody: params.prompt },
2238
+ access: {
2239
+ mentions: {
2240
+ canDetectMention: true,
2241
+ wasMentioned: true
2242
+ },
2243
+ commands: { authorized: params.commandAuthorized }
2244
+ },
2245
+ commandTurn: {
2246
+ kind: "native",
2247
+ source: "native",
2248
+ authorized: params.commandAuthorized,
2249
+ body: params.prompt
2250
+ },
2251
+ supplemental: { groupSystemPrompt },
2252
+ extra: {
2253
+ CommandArgs: params.commandArgs,
2254
+ CommandTargetSessionKey: params.commandTargetSessionKey,
2255
+ CommandSource: "native",
2256
+ GroupSubject: params.isGuild ? params.guildName : void 0,
2257
+ ChannelStructuredContext: channelStructuredContext,
2258
+ OwnerAllowFrom: ownerAllowFrom
2259
+ }
2260
+ });
2261
+ }
2262
+ async function buildDiscordNativeInteractionContext(params) {
2263
+ const { interaction, route, boundSessionKey, sessionPrefix, channelContext, ...context } = params;
2264
+ const targets = resolveNativeCommandSessionTargets({
2265
+ agentId: route.agentId,
2266
+ sessionPrefix,
2267
+ userId: context.user.id,
2268
+ targetSessionKey: route.sessionKey,
2269
+ boundSessionKey
2270
+ });
2271
+ return {
2272
+ ctxPayload: await buildDiscordNativeCommandContext({
2273
+ ...context,
2274
+ ...targets,
2275
+ agentId: route.agentId,
2276
+ accountId: route.accountId,
2277
+ interactionId: interaction.rawData.id,
2278
+ channelId: channelContext.rawChannelId || "unknown",
2279
+ threadParentId: channelContext.threadParentId,
2280
+ memberRoleIds: Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles : [],
2281
+ guildId: interaction.guild?.id,
2282
+ guildName: interaction.guild?.name,
2283
+ channelTopic: resolveDiscordChannelTopicSafe(interaction.channel),
2284
+ isGuild: Boolean(interaction.guild),
2285
+ isDirectMessage: channelContext.isDirectMessage,
2286
+ isGroupDm: channelContext.isGroupDm,
2287
+ isThreadChannel: channelContext.isThreadChannel
2288
+ }),
2289
+ ...targets
2290
+ };
2264
2291
  }
2265
2292
  //#endregion
2266
2293
  //#region extensions/discord/src/monitor/native-interaction-channel-context.ts
@@ -2286,6 +2313,60 @@ async function resolveDiscordNativeInteractionChannelContext(params) {
2286
2313
  }
2287
2314
  //#endregion
2288
2315
  //#region extensions/discord/src/monitor/native-command-auth.ts
2316
+ function resolveDiscordNativePolicyReader(params) {
2317
+ return params.readPolicy ?? createDiscordLivePolicyReader({
2318
+ ...params,
2319
+ readConfig: () => getRuntimeConfigSnapshot() ?? params.cfg,
2320
+ resolvedAllowlist: {
2321
+ guildEntries: params.discordConfig?.guilds,
2322
+ allowFrom: params.discordConfig?.allowFrom ?? resolveDiscordAccountAllowFrom(params)
2323
+ }
2324
+ });
2325
+ }
2326
+ function createDiscordNativeCommandAuthority(params) {
2327
+ const assertAdmittedOwner = resolveCommandAuthorization(params).assertOwnerCurrent;
2328
+ const readAuthorization = () => {
2329
+ const cfg = getRuntimeConfigSnapshot() ?? params.cfg;
2330
+ const owners = resolveDiscordCommandOwnerAllowFrom(cfg);
2331
+ const senderIsOwner = params.isPolicyCurrent?.() !== false && (resolveDiscordOwnerAccess({
2332
+ allowFrom: owners,
2333
+ sender: params.sender,
2334
+ allowNameMatching: params.allowNameMatching
2335
+ }).ownerAllowed || resolveCommandAuthorization({
2336
+ ...params,
2337
+ cfg
2338
+ }).senderIsOwner);
2339
+ const commands = resolveDiscordNativeCommandAllowlistAccess({
2340
+ cfg,
2341
+ sender: params.sender,
2342
+ guildId: params.guildId
2343
+ });
2344
+ return {
2345
+ senderIsOwner,
2346
+ allowed: (!commands.configured || commands.allowed) && (!owners || owners.includes("*") || senderIsOwner || commands.allowed || params.commandName === "status" || params.pluginCommand)
2347
+ };
2348
+ };
2349
+ const assertActive = () => {
2350
+ assertAdmittedOwner?.();
2351
+ if (params.isPolicyCurrent?.() === false || !readAuthorization().allowed) throw new Error("Discord command authority changed; send a new request.");
2352
+ };
2353
+ return {
2354
+ assertActive,
2355
+ assertOwnerCurrent: () => {
2356
+ assertActive();
2357
+ if (!readAuthorization().senderIsOwner) throw new Error("Discord owner authority changed; send a new request.");
2358
+ },
2359
+ senderIsOwner: () => readAuthorization().senderIsOwner,
2360
+ isAllowed: () => {
2361
+ try {
2362
+ assertActive();
2363
+ return true;
2364
+ } catch {
2365
+ return false;
2366
+ }
2367
+ }
2368
+ };
2369
+ }
2289
2370
  function resolveDiscordNativeCommandAllowlistAccess(params) {
2290
2371
  const commandsAllowFrom = params.cfg.commands?.allowFrom;
2291
2372
  if (!commandsAllowFrom || typeof commandsAllowFrom !== "object") return {
@@ -2327,10 +2408,7 @@ function resolveDiscordNativeCommandChannelAccessContext(params) {
2327
2408
  const guild = params.guild ?? null;
2328
2409
  const commandsAllowFromAccess = resolveDiscordNativeCommandAllowlistAccess({
2329
2410
  cfg: params.cfg,
2330
- accountId: params.accountId,
2331
2411
  sender: params.sender,
2332
- chatType: params.isDirectMessage ? "direct" : params.isThreadChannel ? "thread" : guild ? "channel" : "group",
2333
- conversationId: params.rawChannelId || void 0,
2334
2412
  guildId: guild?.id
2335
2413
  });
2336
2414
  const guildInfo = resolveDiscordGuildEntry({
@@ -2372,10 +2450,6 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
2372
2450
  sender: params.sender,
2373
2451
  allowNameMatching: params.allowNameMatching
2374
2452
  });
2375
- const commandAllowlistAuthorizer = {
2376
- configured: params.commandsAllowFromAccess.configured,
2377
- allowed: params.commandsAllowFromAccess.allowed
2378
- };
2379
2453
  const ownerAuthorizer = {
2380
2454
  configured: params.ownerAllowListConfigured,
2381
2455
  allowed: params.ownerAllowed
@@ -2393,9 +2467,9 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
2393
2467
  ownerAuthorizer,
2394
2468
  memberAuthorizer
2395
2469
  ];
2396
- const authorizers = params.commandsAllowFromAccess.configured ? [commandAllowlistAuthorizer] : fallbackAuthorizers;
2470
+ const authorizers = params.commandsAllowFromAccess.configured ? [params.commandsAllowFromAccess] : fallbackAuthorizers;
2397
2471
  return resolveCommandAuthorizedFromAuthorizers({
2398
- useAccessGroups: params.useAccessGroups,
2472
+ useAccessGroups: true,
2399
2473
  authorizers,
2400
2474
  modeWhenAccessGroupsOff: "configured"
2401
2475
  });
@@ -2425,43 +2499,31 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2425
2499
  author: user,
2426
2500
  pluralkitInfo: null
2427
2501
  });
2428
- const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId, threadParentName, threadParentSlug } = await resolveDiscordNativeInteractionChannelContext({
2502
+ const channelContext = await resolveDiscordNativeInteractionChannelContext({
2429
2503
  channel: interaction.channel,
2430
2504
  client: interaction.client,
2431
2505
  hasGuild: Boolean(interaction.guild),
2432
2506
  channelIdFallback: interaction.rawData.channel_id ?? ""
2433
2507
  });
2508
+ const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
2434
2509
  if (params.isPolicyCurrent?.() === false) return false;
2435
2510
  const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
2436
2511
  const allowNameMatching = isDangerousNameMatchingEnabled(discordConfig);
2437
- const useAccessGroups = true;
2438
2512
  const configuredDmAllowFrom = resolveDiscordAccountAllowFrom({
2439
2513
  cfg,
2440
2514
  accountId
2441
2515
  }) ?? [];
2442
2516
  const { ownerAllowList, ownerAllowed: ownerOk } = resolveDiscordOwnerAccess({
2443
2517
  allowFrom: configuredDmAllowFrom,
2444
- sender: {
2445
- id: sender.id,
2446
- name: sender.name,
2447
- tag: sender.tag
2448
- },
2518
+ sender,
2449
2519
  allowNameMatching
2450
2520
  });
2451
2521
  const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
2452
2522
  cfg,
2453
2523
  discordConfig,
2454
- accountId,
2455
2524
  sender,
2456
- isDirectMessage,
2457
- isThreadChannel,
2458
- guild: interaction.guild ?? null,
2459
- rawChannelId,
2460
- channelName,
2461
- channelSlug,
2462
- threadParentId,
2463
- threadParentName,
2464
- threadParentSlug
2525
+ ...channelContext,
2526
+ guild: interaction.guild ?? null
2465
2527
  });
2466
2528
  if (channelConfig?.enabled === false) return false;
2467
2529
  if (interaction.guild && channelConfig?.allowed === false) return false;
@@ -2488,11 +2550,7 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2488
2550
  accountId,
2489
2551
  dmPolicy,
2490
2552
  configuredAllowFrom: configuredDmAllowFrom,
2491
- sender: {
2492
- id: sender.id,
2493
- name: sender.name,
2494
- tag: sender.tag
2495
- },
2553
+ sender,
2496
2554
  allowNameMatching,
2497
2555
  cfg,
2498
2556
  rest: interaction.client.rest
@@ -2507,162 +2565,73 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
2507
2565
  channelName,
2508
2566
  channelSlug
2509
2567
  }).allowed) return false;
2510
- if (params.skipCommandOwnerAllowFrom !== true) {
2511
- const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(cfg);
2512
- const { ownerAllowed: commandOwnerOk } = resolveDiscordOwnerAccess({
2513
- allowFrom: commandOwnerAllowFrom,
2514
- sender: {
2515
- id: sender.id,
2516
- name: sender.name,
2517
- tag: sender.tag
2518
- },
2519
- allowNameMatching
2520
- });
2521
- const commandOwnerAllowAll = commandOwnerAllowFrom?.includes("*") === true;
2522
- if (commandOwnerAllowFrom && !(commandOwnerOk || commandOwnerAllowAll) && !commandsAllowFromAccess.allowed) return false;
2568
+ if (!isDirectMessage) {
2569
+ if (!await resolveDiscordGuildNativeCommandAuthorized({
2570
+ cfg,
2571
+ discordConfig,
2572
+ commandsAllowFromAccess,
2573
+ guildInfo,
2574
+ channelConfig,
2575
+ memberRoleIds,
2576
+ sender,
2577
+ allowNameMatching,
2578
+ ownerAllowListConfigured: ownerAllowList != null,
2579
+ ownerAllowed: ownerOk
2580
+ })) return false;
2523
2581
  }
2524
- if (!isDirectMessage) return await resolveDiscordGuildNativeCommandAuthorized({
2525
- cfg,
2526
- accountId,
2527
- discordConfig,
2528
- useAccessGroups,
2529
- commandsAllowFromAccess,
2530
- guildInfo,
2531
- channelConfig,
2532
- memberRoleIds,
2582
+ const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(cfg);
2583
+ if (params.skipCommandOwnerAllowFrom !== true && commandOwnerAllowFrom && !commandOwnerAllowFrom.includes("*") && !commandsAllowFromAccess.allowed && !resolveDiscordOwnerAccess({
2584
+ allowFrom: commandOwnerAllowFrom,
2533
2585
  sender,
2534
- allowNameMatching,
2535
- ownerAllowListConfigured: ownerAllowList != null,
2536
- ownerAllowed: ownerOk
2537
- }) && params.isPolicyCurrent?.() !== false;
2586
+ allowNameMatching
2587
+ }).ownerAllowed) {
2588
+ const routeState = resolveDiscordNativeInteractionRouteState({
2589
+ cfg,
2590
+ accountId,
2591
+ guildId: interaction.guild?.id,
2592
+ memberRoleIds,
2593
+ isDirectMessage,
2594
+ isGroupDm,
2595
+ directUserId: user.id,
2596
+ conversationId: rawChannelId,
2597
+ parentConversationId: threadParentId,
2598
+ threadBinding: isThreadChannel ? params.threadBindings?.getByThreadId(rawChannelId) : void 0
2599
+ });
2600
+ const { ctxPayload } = await buildDiscordNativeInteractionContext({
2601
+ buildContext: params.buildContext,
2602
+ interaction,
2603
+ channelContext,
2604
+ route: routeState.effectiveRoute,
2605
+ boundSessionKey: routeState.boundSessionKey,
2606
+ sessionPrefix: params.sessionPrefix ?? "discord:slash",
2607
+ channelConfig,
2608
+ guildInfo,
2609
+ allowNameMatching,
2610
+ commandAuthorized: true,
2611
+ user,
2612
+ sender,
2613
+ prompt: "",
2614
+ commandArgs: {}
2615
+ });
2616
+ if (!resolveCommandAuthorization({
2617
+ ctx: ctxPayload,
2618
+ cfg,
2619
+ commandAuthorized: true
2620
+ }).senderIsOwner) return false;
2621
+ }
2538
2622
  return params.isPolicyCurrent?.() !== false;
2539
2623
  }
2540
2624
  //#endregion
2541
2625
  //#region extensions/discord/src/monitor/native-command-bypass.ts
2542
2626
  function shouldBypassConfiguredAcpEnsure(commandName) {
2543
- return commandName.trim().toLowerCase() === "acp";
2627
+ const command = commandName.trim().toLowerCase();
2628
+ return command === "acp" || command === "status";
2544
2629
  }
2545
2630
  function shouldBypassConfiguredAcpGuildGuards(commandName) {
2546
2631
  const command = commandName.trim().toLowerCase();
2547
2632
  return command === "new" || command === "reset";
2548
2633
  }
2549
2634
  //#endregion
2550
- //#region extensions/discord/src/monitor/inbound-context.ts
2551
- function createDiscordSupplementalContextAccessChecker(params) {
2552
- const userAllowList = params.channelConfig?.users ?? params.guildInfo?.users ?? [];
2553
- const roleAllowList = params.channelConfig?.roles ?? params.guildInfo?.roles ?? [];
2554
- const allowFrom = [...userAllowList, ...roleAllowList];
2555
- return (sender) => {
2556
- return resolveInboundSupplementalSenderAllowed({
2557
- isGroup: params.isGuild,
2558
- groupPolicy: allowFrom.length === 0 ? "open" : "allowlist",
2559
- allowFrom,
2560
- isSenderAllowed: () => resolveDiscordMemberAllowed({
2561
- userAllowList,
2562
- roleAllowList,
2563
- memberRoleIds: [...sender.memberRoleIds ?? []],
2564
- userId: sender.id ?? "",
2565
- userName: sender.name,
2566
- userTag: sender.tag,
2567
- allowNameMatching: params.allowNameMatching
2568
- })
2569
- });
2570
- };
2571
- }
2572
- function buildDiscordGroupSystemPrompt(channelConfig) {
2573
- return channelConfig?.systemPrompt?.trim() || void 0;
2574
- }
2575
- function buildDiscordChannelStructuredContext(params) {
2576
- if (!params.isGuild) return;
2577
- const entries = [];
2578
- if (typeof params.channelTopic === "string" && params.channelTopic.trim().length > 0) entries.push({
2579
- label: "Discord channel metadata",
2580
- source: "discord",
2581
- type: "channel_metadata",
2582
- payload: { topic: params.channelTopic.trim() }
2583
- });
2584
- return entries.length > 0 ? entries : void 0;
2585
- }
2586
- function buildDiscordInboundAccessContext(params) {
2587
- return {
2588
- groupSystemPrompt: params.isGuild ? buildDiscordGroupSystemPrompt(params.channelConfig) : void 0,
2589
- channelStructuredContext: buildDiscordChannelStructuredContext({
2590
- isGuild: params.isGuild,
2591
- channelTopic: params.channelTopic
2592
- }),
2593
- ownerAllowFrom: resolveDiscordOwnerAllowFrom({
2594
- channelConfig: params.channelConfig,
2595
- guildInfo: params.guildInfo,
2596
- sender: params.sender,
2597
- allowNameMatching: params.allowNameMatching
2598
- })
2599
- };
2600
- }
2601
- //#endregion
2602
- //#region extensions/discord/src/monitor/native-command-context.ts
2603
- function buildDiscordNativeCommandContext(params) {
2604
- const conversationLabel = params.isDirectMessage ? params.user.globalName ?? params.user.username : params.channelId;
2605
- const { groupSystemPrompt, ownerAllowFrom, channelStructuredContext } = buildDiscordInboundAccessContext({
2606
- channelConfig: params.channelConfig,
2607
- guildInfo: params.guildInfo,
2608
- sender: params.sender,
2609
- allowNameMatching: params.allowNameMatching,
2610
- isGuild: params.isGuild,
2611
- channelTopic: params.channelTopic
2612
- });
2613
- return finalizeInboundContext({
2614
- Body: params.prompt,
2615
- BodyForAgent: params.prompt,
2616
- RawBody: params.prompt,
2617
- CommandBody: params.prompt,
2618
- CommandArgs: params.commandArgs,
2619
- From: params.isDirectMessage ? `discord:${params.user.id}` : params.isGroupDm ? `discord:group:${params.channelId}` : `discord:channel:${params.channelId}`,
2620
- To: `slash:${params.user.id}`,
2621
- SessionKey: params.sessionKey,
2622
- CommandTargetSessionKey: params.commandTargetSessionKey,
2623
- AccountId: params.accountId ?? void 0,
2624
- ChatType: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
2625
- ...buildDiscordConversationRouteContext({
2626
- isDirectMessage: params.isDirectMessage,
2627
- isGroupDm: params.isGroupDm,
2628
- directUserId: params.user.id,
2629
- conversationId: params.channelId,
2630
- isThread: params.isThreadChannel,
2631
- parentConversationId: params.threadParentId
2632
- }),
2633
- ConversationLabel: conversationLabel,
2634
- GroupSubject: params.isGuild ? params.guildName : void 0,
2635
- GroupSpace: params.isGuild ? params.guildInfo?.id ?? params.guildInfo?.slug ?? params.guildId : void 0,
2636
- MemberRoleIds: params.memberRoleIds,
2637
- GroupSystemPrompt: groupSystemPrompt,
2638
- ChannelStructuredContext: channelStructuredContext,
2639
- OwnerAllowFrom: ownerAllowFrom,
2640
- SenderName: params.user.globalName ?? params.user.username,
2641
- SenderId: params.user.id,
2642
- SenderUsername: params.user.username,
2643
- SenderTag: params.sender.tag,
2644
- Provider: "discord",
2645
- Surface: "discord",
2646
- WasMentioned: true,
2647
- MessageSid: params.interactionId,
2648
- Timestamp: params.timestampMs ?? Date.now(),
2649
- CommandAuthorized: params.commandAuthorized,
2650
- CommandTurn: {
2651
- kind: "native",
2652
- source: "native",
2653
- authorized: params.commandAuthorized,
2654
- body: params.prompt
2655
- },
2656
- CommandSource: "native",
2657
- OriginatingChannel: "discord",
2658
- OriginatingTo: resolveDiscordConversationIdentity({
2659
- isDirectMessage: params.isDirectMessage,
2660
- userId: params.user.id,
2661
- channelId: params.channelId
2662
- }) ?? (params.isDirectMessage ? `user:${params.user.id}` : `channel:${params.channelId}`)
2663
- });
2664
- }
2665
- //#endregion
2666
2635
  //#region extensions/discord/src/monitor/model-picker-preferences.ts
2667
2636
  const DEFAULT_RECENT_LIMIT = 5;
2668
2637
  const PREFERENCE_MAX_ENTRIES = 2e3;
@@ -2675,14 +2644,11 @@ function openPreferenceStore(env) {
2675
2644
  ...env ? { env } : {}
2676
2645
  });
2677
2646
  }
2678
- function normalizeId(value) {
2679
- return normalizeOptionalString(value) ?? "";
2680
- }
2681
2647
  function buildDiscordModelPickerPreferenceKey(scope) {
2682
- const userId = normalizeId(scope.userId);
2648
+ const userId = normalizeOptionalString(scope.userId);
2683
2649
  if (!userId) return null;
2684
2650
  const accountId = normalizeAccountId(scope.accountId);
2685
- const guildId = normalizeId(scope.guildId);
2651
+ const guildId = normalizeOptionalString(scope.guildId);
2686
2652
  if (guildId) return `discord:${accountId}:guild:${guildId}:user:${userId}`;
2687
2653
  return `discord:${accountId}:dm:user:${userId}`;
2688
2654
  }
@@ -2702,6 +2668,12 @@ function sanitizeStoredPreferenceEntry(value) {
2702
2668
  function timestampOrder(value) {
2703
2669
  return value !== void 0 && value >= 0 ? value : 0;
2704
2670
  }
2671
+ function scopedPreferenceEntries(entries, scopeKey) {
2672
+ return entries.map((entry) => ({
2673
+ key: entry.key,
2674
+ value: sanitizeStoredPreferenceEntry(entry.value)
2675
+ })).filter((entry) => entry.value?.scopeKey === scopeKey);
2676
+ }
2705
2677
  function comparePreferenceEntries(left, right) {
2706
2678
  return preferenceTimestampMs(right.value.updatedAt) - preferenceTimestampMs(left.value.updatedAt) || timestampOrder(right.value.updatedOrder) - timestampOrder(left.value.updatedOrder) || left.key.localeCompare(right.key);
2707
2679
  }
@@ -2720,10 +2692,7 @@ async function readDiscordModelPickerRecentModels(params) {
2720
2692
  if (!key) return [];
2721
2693
  const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
2722
2694
  try {
2723
- const recent = (await openPreferenceStore(params.env).entries()).map((entry) => ({
2724
- key: entry.key,
2725
- value: sanitizeStoredPreferenceEntry(entry.value)
2726
- })).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
2695
+ const recent = scopedPreferenceEntries(await openPreferenceStore(params.env).entries(), key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
2727
2696
  if (!params.allowedModelRefs || params.allowedModelRefs.size === 0) return sanitizeRecentModels(recent, limit);
2728
2697
  return sanitizeRecentModels(recent.filter((modelRef) => params.allowedModelRefs?.has(modelRef)), limit);
2729
2698
  } catch {
@@ -2736,17 +2705,14 @@ async function recordDiscordModelPickerRecentModel(params) {
2736
2705
  if (!key || !normalizedModelRef) return;
2737
2706
  try {
2738
2707
  const store = openPreferenceStore(params.env);
2739
- const timestamp = nextPreferenceTimestamp((await store.entries()).map((entry) => sanitizeStoredPreferenceEntry(entry.value)).filter((entry) => entry?.scopeKey === key));
2708
+ const timestamp = nextPreferenceTimestamp(scopedPreferenceEntries(await store.entries(), key).map((entry) => entry.value));
2740
2709
  await store.register(buildPreferenceModelKey(key, normalizedModelRef), {
2741
2710
  scopeKey: key,
2742
2711
  modelRef: normalizedModelRef,
2743
2712
  ...timestamp
2744
2713
  });
2745
2714
  const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
2746
- const scopedEntries = (await store.entries()).map((entry) => ({
2747
- key: entry.key,
2748
- value: sanitizeStoredPreferenceEntry(entry.value)
2749
- })).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries);
2715
+ const scopedEntries = scopedPreferenceEntries(await store.entries(), key).toSorted(comparePreferenceEntries);
2750
2716
  await Promise.all(scopedEntries.slice(limit).map((entry) => store.delete(entry.key)));
2751
2717
  } catch {}
2752
2718
  }
@@ -2789,11 +2755,6 @@ const PICKER_VIEWS = [
2789
2755
  "models",
2790
2756
  "recents"
2791
2757
  ];
2792
- /**
2793
- * Alpha buckets engage only when the sorted item list exceeds the single-page
2794
- * select cap. Below this threshold the user gets the existing flat list +
2795
- * prev/next behavior unchanged.
2796
- */
2797
2758
  const DISCORD_MODEL_PICKER_BUCKET_THRESHOLD = DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
2798
2759
  /** Target items per alpha bucket. Discord caps selects at 25 options. */
2799
2760
  const DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE = 20;
@@ -2815,9 +2776,7 @@ function isValidPickerView(value) {
2815
2776
  return PICKER_VIEWS.includes(value);
2816
2777
  }
2817
2778
  function normalizeModelPickerPage(value) {
2818
- const numeric = typeof value === "number" ? value : NaN;
2819
- if (!Number.isFinite(numeric)) return 1;
2820
- return Math.max(1, Math.floor(numeric));
2779
+ return normalizeOptionalModelPickerIndex(value) ?? 1;
2821
2780
  }
2822
2781
  function parseRawPage(value) {
2823
2782
  if (typeof value === "number") return normalizeModelPickerPage(value);
@@ -2948,17 +2907,6 @@ function parseDiscordModelPickerData(data) {
2948
2907
  ...modelBucketRaw ? { modelBucket: modelBucketRaw } : {}
2949
2908
  };
2950
2909
  }
2951
- /**
2952
- * Split a sorted item list into letter-range buckets when its length exceeds
2953
- * {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}. Items below the threshold
2954
- * return a single "All" bucket so callers can render the same code path.
2955
- *
2956
- * The boundary extender keeps items sharing the same starting letter inside
2957
- * the same bucket — selecting "A–G" never strands a stray "g" item in the
2958
- * next bucket. If every item shares a first letter (e.g. all `qwen3-*`),
2959
- * the function falls back to count-based numeric chunks so the user still
2960
- * gets a finite-cardinality picker.
2961
- */
2962
2910
  function computeAlphaBuckets(sortedItems) {
2963
2911
  if (sortedItems.length === 0) return [];
2964
2912
  if (sortedItems.length <= DISCORD_MODEL_PICKER_BUCKET_THRESHOLD) return [{
@@ -2993,16 +2941,8 @@ function computeAlphaBuckets(sortedItems) {
2993
2941
  }
2994
2942
  return buckets;
2995
2943
  }
2996
- /**
2997
- * Pick the per-bucket target size such that the resulting bucket count never
2998
- * exceeds {@link DISCORD_COMPONENT_MAX_SELECT_OPTIONS} (Discord's hard select
2999
- * cap). Stays at the default {@link DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE}
3000
- * for typical inputs and grows linearly for very large lists.
3001
- */
3002
2944
  function computeBucketTargetSize(totalItems) {
3003
- const minTarget = DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE;
3004
- const capByBucketCount = Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS);
3005
- return Math.max(minTarget, capByBucketCount);
2945
+ return Math.max(DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE, Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS));
3006
2946
  }
3007
2947
  function chunkBucketsByCount(sortedItems) {
3008
2948
  const buckets = [];
@@ -3018,37 +2958,15 @@ function chunkBucketsByCount(sortedItems) {
3018
2958
  }
3019
2959
  return buckets;
3020
2960
  }
3021
- /**
3022
- * Resolve a bucket from a list given a (possibly user-supplied) bucket id.
3023
- * Falls back to the first bucket when the id does not match — mirrors the
3024
- * "bad customId → reset to defaults" semantics already used for other
3025
- * state fields.
3026
- */
3027
2961
  function resolveBucket(buckets, id) {
3028
- if (buckets.length === 0) return null;
3029
- if (!id) return expectDefined(buckets.at(0), "non-empty model picker buckets");
3030
- return buckets.find((bucket) => bucket.id === id) ?? expectDefined(buckets.at(0), "non-empty model picker buckets");
2962
+ return buckets.find((bucket) => bucket.id === id) ?? buckets[0] ?? null;
3031
2963
  }
3032
- /**
3033
- * Derive the alpha-bucket id that contains a given provider id. Returns
3034
- * `undefined` when bucketing is inactive (all providers fit in one bucket)
3035
- * or the provider is unknown. Used by the interaction handler to recompute
3036
- * `providerBucket` at re-render time without forcing every customId to
3037
- * carry the bucket field — the bucket is a pure function of the provider
3038
- * list + provider id.
3039
- */
3040
2964
  function findProviderBucketId(data, provider) {
3041
2965
  return findProviderBucketLocation(data, provider)?.bucket;
3042
2966
  }
3043
2967
  function findProviderBucketLocation(data, provider) {
3044
2968
  return findModelPickerBucketLocation([...data.providers].toSorted(), normalizeProviderId(provider));
3045
2969
  }
3046
- /**
3047
- * Derive the alpha-bucket id that contains a given model id within the
3048
- * named provider. Same rationale as {@link findProviderBucketId} — saves
3049
- * customId budget by recomputing the bucket from the durable state
3050
- * (provider + model) rather than carrying it as a parameter.
3051
- */
3052
2970
  function findModelBucketId(data, provider, model) {
3053
2971
  const modelSet = data.byProvider.get(normalizeProviderId(provider));
3054
2972
  return modelSet ? findModelPickerBucketLocation([...modelSet].toSorted(compareBucketItems), model)?.bucket : void 0;
@@ -3156,14 +3074,6 @@ function createModelSelect(params) {
3156
3074
  }
3157
3075
  return new DiscordModelPickerSelect();
3158
3076
  }
3159
- /**
3160
- * Build the alpha-bucket select row that appears above the provider/model
3161
- * surface when the list exceeds {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}.
3162
- *
3163
- * Selecting a bucket emits action=bucket. The chosen bucket travels in the
3164
- * select value, while the custom_id carries only the stable context needed to
3165
- * rebuild the picker under Discord's 100-character custom_id limit.
3166
- */
3167
3077
  function buildBucketSelectRow(params) {
3168
3078
  if (params.buckets.length <= 1) return null;
3169
3079
  const options = params.buckets.map((bucket) => ({
@@ -3197,11 +3107,6 @@ function resolveExplicitRuntimeState(params) {
3197
3107
  const runtime = params.pendingRuntime?.trim() || params.currentRuntime?.trim();
3198
3108
  return runtime && runtime !== "auto" && runtime !== "default" ? runtime : void 0;
3199
3109
  }
3200
- function resolveSelectedRuntime(params) {
3201
- const choices = getRuntimeChoices(params);
3202
- const explicit = resolveExplicitRuntimeState(params);
3203
- return explicit ? choices?.find((choice) => choice.id === explicit)?.id : choices?.[0]?.id;
3204
- }
3205
3110
  function getActiveBucketId(bucket) {
3206
3111
  return bucket && bucket.id !== "all" ? bucket.id : void 0;
3207
3112
  }
@@ -3237,18 +3142,18 @@ function buildRenderedShell(params) {
3237
3142
  return { components: [new Container(containerComponents)] };
3238
3143
  }
3239
3144
  function buildProviderSelectRow(params) {
3240
- if (params.page.items.length === 0) return null;
3241
3145
  const options = params.page.items.map((provider) => ({
3242
3146
  label: provider.id,
3243
3147
  value: provider.id,
3244
3148
  default: provider.id === params.currentProvider,
3245
- description: `${provider.count} ${provider.count === 1 ? "model" : "models"}`
3149
+ ...params.showModelCounts ? { description: `${provider.count} ${provider.count === 1 ? "model" : "models"}` } : {}
3246
3150
  }));
3247
3151
  return new Row([createModelSelect({
3248
3152
  customId: buildDiscordModelPickerCustomId({
3249
3153
  command: params.command,
3250
3154
  action: "provider",
3251
3155
  view: "models",
3156
+ provider: params.provider,
3252
3157
  page: params.page.page,
3253
3158
  providerPage: params.page.page,
3254
3159
  providerBucket: params.providerBucket,
@@ -3292,40 +3197,27 @@ function buildModelRows(params) {
3292
3197
  page: params.providerPage,
3293
3198
  bucket: params.providerBucket
3294
3199
  });
3295
- const providerOptions = providerPage.items.map((provider) => ({
3296
- label: provider.id,
3297
- value: provider.id,
3298
- default: provider.id === params.modelPage.provider
3299
- }));
3300
3200
  const activeProviderBucket = getActiveBucketId(providerPage.bucket);
3301
3201
  const activeModelBucket = getActiveBucketId(params.modelPage.bucket);
3302
- if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(new Row([createModelSelect({
3303
- customId: buildDiscordModelPickerCustomId({
3304
- command: params.command,
3305
- action: "provider",
3306
- view: "models",
3307
- provider: params.modelPage.provider,
3308
- page: providerPage.page,
3309
- providerPage: providerPage.page,
3310
- providerBucket: activeProviderBucket,
3311
- userId: params.userId
3312
- }),
3313
- options: providerOptions,
3314
- placeholder: "Select provider"
3315
- })]));
3202
+ if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(buildProviderSelectRow({
3203
+ command: params.command,
3204
+ userId: params.userId,
3205
+ page: providerPage,
3206
+ provider: params.modelPage.provider,
3207
+ currentProvider: params.modelPage.provider,
3208
+ providerBucket: activeProviderBucket
3209
+ }));
3316
3210
  const runtimeChoices = getRuntimeChoices({
3317
3211
  data: params.data,
3318
3212
  provider: params.modelPage.provider,
3319
3213
  modelRef: params.pendingModel ?? params.currentModel
3320
3214
  });
3321
3215
  const currentRuntime = parsedCurrentModel?.provider === params.modelPage.provider ? params.currentRuntime : void 0;
3322
- const selectedRuntime = resolveSelectedRuntime({
3323
- data: params.data,
3324
- provider: params.modelPage.provider,
3325
- modelRef: params.pendingModel ?? params.currentModel,
3216
+ const explicitRuntime = resolveExplicitRuntimeState({
3326
3217
  currentRuntime,
3327
3218
  pendingRuntime: params.pendingRuntime
3328
3219
  });
3220
+ const selectedRuntime = explicitRuntime ? runtimeChoices?.find((choice) => choice.id === explicitRuntime)?.id : runtimeChoices?.[0]?.id;
3329
3221
  const compactRuntime = resolveCompactRuntimeState({
3330
3222
  currentRuntime,
3331
3223
  pendingRuntime: params.pendingRuntime
@@ -3387,7 +3279,7 @@ function buildModelRows(params) {
3387
3279
  providerPage: providerPage.page,
3388
3280
  modelIndex: params.pendingModelIndex,
3389
3281
  modelToken: pendingModelToken,
3390
- modelBucket: params.modelPage.bucket && params.modelPage.bucket.id !== "all" ? params.modelPage.bucket.id : void 0
3282
+ modelBucket: activeModelBucket
3391
3283
  });
3392
3284
  if (modelNavRow) rows.push(modelNavRow);
3393
3285
  const resolvedDefault = params.data.resolvedDefault;
@@ -3454,7 +3346,9 @@ function buildModelRows(params) {
3454
3346
  }));
3455
3347
  return {
3456
3348
  rows,
3457
- buttonRow: new Row(buttonRowItems)
3349
+ buttonRow: new Row(buttonRowItems),
3350
+ runtimeChoices,
3351
+ selectedRuntime
3458
3352
  };
3459
3353
  }
3460
3354
  function renderDiscordModelPickerProvidersView(params) {
@@ -3473,15 +3367,15 @@ function renderDiscordModelPickerProvidersView(params) {
3473
3367
  currentBucketId: page.bucket?.id
3474
3368
  });
3475
3369
  if (bucketRow) rows.push(bucketRow);
3476
- const activeProviderBucket = page.bucket && page.bucket.id !== "all" ? page.bucket.id : void 0;
3477
- const providerRow = buildProviderSelectRow({
3370
+ const activeProviderBucket = getActiveBucketId(page.bucket);
3371
+ if (page.items.length > 0) rows.push(buildProviderSelectRow({
3478
3372
  command: params.command,
3479
3373
  userId: params.userId,
3480
3374
  page,
3481
3375
  currentProvider: parsedCurrent?.provider,
3482
- providerBucket: activeProviderBucket
3483
- });
3484
- if (providerRow) rows.push(providerRow);
3376
+ providerBucket: activeProviderBucket,
3377
+ showModelCounts: true
3378
+ }));
3485
3379
  const navRow = buildPaginationRow({
3486
3380
  command: params.command,
3487
3381
  userId: params.userId,
@@ -3531,19 +3425,10 @@ function renderDiscordModelPickerModelsView(params) {
3531
3425
  footer: "Choose a different provider."
3532
3426
  });
3533
3427
  }
3534
- const { rows: modelRows, buttonRow } = buildModelRows({
3535
- command: params.command,
3536
- userId: params.userId,
3537
- data: params.data,
3428
+ const { rows: modelRows, buttonRow, runtimeChoices: choices, selectedRuntime } = buildModelRows({
3429
+ ...params,
3538
3430
  providerPage,
3539
- modelPage,
3540
- currentModel: params.currentModel,
3541
- currentRuntime: params.currentRuntime,
3542
- pendingModel: params.pendingModel,
3543
- pendingModelIndex: params.pendingModelIndex,
3544
- pendingRuntime: params.pendingRuntime,
3545
- quickModels: params.quickModels,
3546
- providerBucket: params.providerBucket
3431
+ modelPage
3547
3432
  });
3548
3433
  const pendingRuntime = params.pendingRuntime?.trim();
3549
3434
  const rows = [];
@@ -3555,24 +3440,11 @@ function renderDiscordModelPickerModelsView(params) {
3555
3440
  currentBucketId: modelPage.bucket?.id,
3556
3441
  provider: modelPage.provider,
3557
3442
  runtimeToken: pendingRuntime ? createDiscordModelPickerRuntimeToken(pendingRuntime) : void 0,
3558
- providerPage,
3559
- providerBucket: params.providerBucket
3443
+ providerPage
3560
3444
  });
3561
3445
  if (bucketRow) rows.push(bucketRow);
3562
3446
  rows.push(...modelRows);
3563
3447
  const defaultModel = `${params.data.resolvedDefault.provider}/${params.data.resolvedDefault.model}`;
3564
- const choices = getRuntimeChoices({
3565
- data: params.data,
3566
- provider: modelPage.provider,
3567
- modelRef: params.pendingModel ?? params.currentModel
3568
- });
3569
- const selectedRuntime = resolveSelectedRuntime({
3570
- data: params.data,
3571
- provider: modelPage.provider,
3572
- modelRef: params.pendingModel ?? params.currentModel,
3573
- currentRuntime: parseCurrentModelRef(params.currentModel)?.provider === modelPage.provider ? params.currentRuntime : void 0,
3574
- pendingRuntime: params.pendingRuntime
3575
- });
3576
3448
  const selectedRuntimeLabel = choices?.find((choice) => choice.id === selectedRuntime)?.label;
3577
3449
  const pendingLine = !params.pendingModel ? "Select a model, then press Submit." : !supportsDiscordModelPickerRuntimeChoices() ? `Selected: ${params.pendingModel} (press Submit)` : choices === void 0 ? "Could not confirm how to run this model. Open /models to try again." : choices.length === 0 ? "This model cannot run with your current connections. Choose another model." : selectedRuntimeLabel ? `Selected: ${params.pendingModel} · ${selectedRuntimeLabel} (press Submit)` : "Choose how to run this model, then press Submit.";
3578
3450
  const detailLines = [formatCurrentModelLine(params.currentModel), `Default: ${defaultModel}`];
@@ -3662,6 +3534,7 @@ async function applyDiscordModelPickerSelection(params) {
3662
3534
  preferFollowUp: true,
3663
3535
  threadBindings: params.threadBindings,
3664
3536
  suppressReplies: true,
3537
+ buildContext: params.buildContext,
3665
3538
  dispatchReplyFromConfig: params.dispatchReplyFromConfig,
3666
3539
  pluginCommandDispatch: { kind: "non-plugin" }
3667
3540
  }), 12e3);
@@ -3710,21 +3583,11 @@ async function applyDiscordModelPickerSelection(params) {
3710
3583
  }
3711
3584
  //#endregion
3712
3585
  //#region extensions/discord/src/monitor/native-command-model-picker-ui.ts
3713
- function resolveDiscordModelPickerCommandContext(command) {
3714
- const normalized = normalizeLowercaseStringOrEmpty(command.nativeName ?? command.key);
3715
- if (normalized === "model" || normalized === "models") return normalized;
3716
- return null;
3717
- }
3718
- function resolveCommandArgStringValue(args, key) {
3719
- const value = args?.values?.[key];
3720
- if (typeof value !== "string") return "";
3721
- return value.trim();
3722
- }
3723
3586
  function shouldOpenDiscordModelPickerFromCommand(params) {
3724
- const context = resolveDiscordModelPickerCommandContext(params.command);
3725
- if (!context) return null;
3587
+ const context = normalizeLowercaseStringOrEmpty(params.command.nativeName ?? params.command.key);
3588
+ if (context !== "model" && context !== "models") return null;
3726
3589
  const serializedArgs = normalizeOptionalString(serializeCommandArgs(params.command, params.commandArgs)) ?? "";
3727
- if (context === "model") return !resolveCommandArgStringValue(params.commandArgs, "model") && !serializedArgs ? context : null;
3590
+ if (context === "model") return !normalizeOptionalString(params.commandArgs?.values?.model) && !serializedArgs ? context : null;
3728
3591
  return serializedArgs ? null : context;
3729
3592
  }
3730
3593
  function buildDiscordModelPickerAllowedModelRefs(data) {
@@ -3746,7 +3609,7 @@ function resolveDiscordModelPickerPreferenceScope(params) {
3746
3609
  function buildDiscordModelPickerNoticePayload(message) {
3747
3610
  return { components: [new Container([new TextDisplay(message)])] };
3748
3611
  }
3749
- async function resolveDiscordModelPickerRouteState(params) {
3612
+ async function resolveDiscordModelPickerRoute(params) {
3750
3613
  const { interaction, cfg, accountId } = params;
3751
3614
  const { isDirectMessage, isGroupDm, isThreadChannel, rawChannelId, threadParentId } = await resolveDiscordNativeInteractionChannelContext({
3752
3615
  channel: interaction.channel,
@@ -3756,7 +3619,7 @@ async function resolveDiscordModelPickerRouteState(params) {
3756
3619
  });
3757
3620
  const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
3758
3621
  const threadBinding = isThreadChannel ? params.threadBindings.getByThreadId(rawChannelId) : void 0;
3759
- return await resolveDiscordNativeInteractionRouteState({
3622
+ return resolveDiscordNativeInteractionRouteState({
3760
3623
  cfg,
3761
3624
  accountId,
3762
3625
  guildId: interaction.guild?.id ?? void 0,
@@ -3766,24 +3629,12 @@ async function resolveDiscordModelPickerRouteState(params) {
3766
3629
  directUserId: interaction.user?.id ?? rawChannelId,
3767
3630
  conversationId: rawChannelId,
3768
3631
  parentConversationId: threadParentId,
3769
- threadBinding,
3770
- enforceConfiguredBindingReadiness: params.enforceConfiguredBindingReadiness
3771
- });
3772
- }
3773
- async function resolveDiscordModelPickerRoute(params) {
3774
- return (await resolveDiscordModelPickerRouteState(params)).effectiveRoute;
3632
+ threadBinding
3633
+ }).effectiveRoute;
3775
3634
  }
3776
3635
  async function resolveDiscordNativeChoiceContext(params) {
3777
3636
  try {
3778
- const resolved = await resolveDiscordModelPickerRouteState({
3779
- interaction: params.interaction,
3780
- cfg: params.cfg,
3781
- accountId: params.accountId,
3782
- threadBindings: params.threadBindings,
3783
- enforceConfiguredBindingReadiness: true
3784
- });
3785
- if (resolved.bindingReadiness && !resolved.bindingReadiness.ok) return null;
3786
- const route = resolved.effectiveRoute;
3637
+ const route = params.route ?? await resolveDiscordModelPickerRoute(params);
3787
3638
  const fallback = resolveDefaultModelForAgent({
3788
3639
  cfg: params.cfg,
3789
3640
  agentId: route.agentId
@@ -3898,8 +3749,6 @@ async function replyWithDiscordModelPickerProviders(params) {
3898
3749
  provider: initialProvider,
3899
3750
  model: parsedCurrentRef.model
3900
3751
  }) : { page: 1 };
3901
- const initialPage = initialResolved.page;
3902
- const initialModelBucket = initialResolved.bucket;
3903
3752
  const initialProviderLocation = findProviderBucketLocation(data, initialProvider);
3904
3753
  const payload = {
3905
3754
  ...renderDiscordModelPickerModelsView({
@@ -3907,10 +3756,10 @@ async function replyWithDiscordModelPickerProviders(params) {
3907
3756
  userId: params.userId,
3908
3757
  data,
3909
3758
  provider: initialProvider,
3910
- page: initialPage,
3759
+ page: initialResolved.page,
3911
3760
  providerPage: initialProviderLocation?.page ?? 1,
3912
3761
  providerBucket: initialProviderLocation?.bucket,
3913
- modelBucket: initialModelBucket,
3762
+ modelBucket: initialResolved.bucket,
3914
3763
  currentModel,
3915
3764
  currentRuntime,
3916
3765
  quickModels
@@ -3918,11 +3767,7 @@ async function replyWithDiscordModelPickerProviders(params) {
3918
3767
  ephemeral: true
3919
3768
  };
3920
3769
  await params.safeInteractionCall("model picker reply", async () => {
3921
- if (params.preferFollowUp) {
3922
- await params.interaction.followUp(payload);
3923
- return;
3924
- }
3925
- await params.interaction.reply(payload);
3770
+ await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
3926
3771
  });
3927
3772
  }
3928
3773
  function splitDiscordModelRef(modelRef) {
@@ -3940,11 +3785,7 @@ function splitDiscordModelRef(modelRef) {
3940
3785
  //#endregion
3941
3786
  //#region extensions/discord/src/monitor/native-command-model-picker-interaction.ts
3942
3787
  function resolveModelPickerSelectionValue(interaction) {
3943
- const rawValues = interaction.values;
3944
- if (!Array.isArray(rawValues) || rawValues.length === 0) return null;
3945
- const first = rawValues[0];
3946
- if (typeof first !== "string") return null;
3947
- return first.trim() || null;
3788
+ return normalizeOptionalString(interaction.values?.[0]) ?? null;
3948
3789
  }
3949
3790
  function resolveRuntimeToken(choices, token) {
3950
3791
  if (!token) return;
@@ -4011,15 +3852,11 @@ function resolveDiscordModelPickerModelRefByToken(data, modelToken) {
4011
3852
  return matchingRefs.length === 1 ? matchingRefs[0] ?? null : null;
4012
3853
  }
4013
3854
  function resolveDiscordModelPickerModelIndex(params) {
4014
- const models = listDiscordModelPickerProviderModels(params.data, params.provider);
4015
- if (!models.length) return null;
4016
- const index = models.indexOf(params.model);
4017
- if (index < 0) return null;
4018
- return index + 1;
3855
+ const index = listDiscordModelPickerProviderModels(params.data, params.provider).indexOf(params.model);
3856
+ return index < 0 ? null : index + 1;
4019
3857
  }
4020
3858
  function resolveDiscordModelPickerModelSelection(params) {
4021
3859
  const models = listDiscordModelPickerProviderModels(params.data, params.provider);
4022
- if (!models.length) return null;
4023
3860
  if (params.modelToken) {
4024
3861
  const matchingModels = models.filter((model) => createDiscordModelPickerModelToken(params.provider, model) === params.modelToken);
4025
3862
  return matchingModels.length === 1 ? matchingModels[0] ?? null : null;
@@ -4038,10 +3875,8 @@ async function handleDiscordModelPickerInteraction(params) {
4038
3875
  await params.safeInteractionCall("model picker ack", () => interaction.acknowledge());
4039
3876
  return;
4040
3877
  }
4041
- let deferredUpdate = interaction.acknowledged;
4042
- if (!deferredUpdate) {
3878
+ if (!interaction.acknowledged) {
4043
3879
  if (await params.safeInteractionCall("model picker defer", () => interaction.acknowledge()) === null) return;
4044
- deferredUpdate = true;
4045
3880
  }
4046
3881
  const cfg = getRuntimeConfigSnapshot() ?? ctx.cfg;
4047
3882
  const requireModelToken = cfg !== ctx.cfg;
@@ -4079,7 +3914,7 @@ async function handleDiscordModelPickerInteraction(params) {
4079
3914
  allowedModelRefs,
4080
3915
  limit: 5
4081
3916
  });
4082
- const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => deferredUpdate ? interaction.editReply(payload) : interaction.update(payload));
3917
+ const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => interaction.editReply(payload));
4083
3918
  const showNotice = async (message) => await updatePicker(buildDiscordModelPickerNoticePayload(message));
4084
3919
  const updateModelsView = async (provider, state = {}) => {
4085
3920
  const rendered = renderDiscordModelPickerModelsView({
@@ -4146,15 +3981,16 @@ async function handleDiscordModelPickerInteraction(params) {
4146
3981
  }));
4147
3982
  return;
4148
3983
  }
4149
- if (parsed.action === "bucket" && parsed.view === "models") {
3984
+ if (parsed.view === "models" && (parsed.action === "bucket" || parsed.action === "back")) {
4150
3985
  const provider = resolveModelPickerProvider({
4151
3986
  parsedProvider,
4152
3987
  currentModelRef,
4153
3988
  data: pickerData
4154
3989
  });
3990
+ const selectingBucket = parsed.action === "bucket";
4155
3991
  await updateModelsView(provider, {
4156
- page: 1,
4157
- modelBucket: resolveSelectedBucket(interaction),
3992
+ page: selectingBucket ? 1 : parsed.page,
3993
+ modelBucket: selectingBucket ? resolveSelectedBucket(interaction) : parsed.modelBucket,
4158
3994
  pendingRuntime: resolvePendingRuntime({
4159
3995
  data: pickerData,
4160
3996
  provider,
@@ -4197,22 +4033,6 @@ async function handleDiscordModelPickerInteraction(params) {
4197
4033
  });
4198
4034
  return;
4199
4035
  }
4200
- if (parsed.action === "back" && parsed.view === "models") {
4201
- const provider = resolveModelPickerProvider({
4202
- parsedProvider,
4203
- currentModelRef,
4204
- data: pickerData
4205
- });
4206
- await updateModelsView(provider, {
4207
- modelBucket: parsed.modelBucket,
4208
- pendingRuntime: resolvePendingRuntime({
4209
- data: pickerData,
4210
- provider,
4211
- parsed
4212
- })
4213
- });
4214
- return;
4215
- }
4216
4036
  if (parsed.action === "provider") {
4217
4037
  const selectedProvider = resolveModelPickerSelectionValue(interaction) ?? parsed.provider;
4218
4038
  if (!selectedProvider || !pickerData.byProvider.has(selectedProvider)) {
@@ -4284,9 +4104,8 @@ async function handleDiscordModelPickerInteraction(params) {
4284
4104
  provider,
4285
4105
  model: selectedModel
4286
4106
  }) : void 0;
4287
- const currentModelOnly = splitDiscordModelRef(currentModelRef ?? "");
4288
4107
  await updateModelsView(provider, {
4289
- modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModelOnly && currentModelOnly.provider === provider ? findModelBucketId(pickerData, provider, currentModelOnly.model) : void 0),
4108
+ modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModel && currentModel.provider === provider ? findModelBucketId(pickerData, provider, currentModel.model) : void 0),
4290
4109
  ...pendingModel ? { pendingModel } : {},
4291
4110
  pendingModelIndex: pendingModelIndex ?? void 0,
4292
4111
  pendingRuntime: selectedRuntime
@@ -4364,16 +4183,11 @@ async function handleDiscordModelPickerInteraction(params) {
4364
4183
  return;
4365
4184
  }
4366
4185
  const applyResult = await applyDiscordModelPickerSelection({
4186
+ ...ctx,
4367
4187
  interaction,
4368
4188
  selectionCommand,
4369
4189
  dispatchCommandInteraction: params.dispatchCommandInteraction,
4370
4190
  cfg,
4371
- discordConfig: ctx.discordConfig,
4372
- readPolicy: ctx.readPolicy,
4373
- accountId: ctx.accountId,
4374
- sessionPrefix: ctx.sessionPrefix,
4375
- threadBindings: ctx.threadBindings,
4376
- dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
4377
4191
  route,
4378
4192
  resolvedModelRef,
4379
4193
  selectedRuntime,
@@ -4397,44 +4211,37 @@ async function handleDiscordModelPickerInteraction(params) {
4397
4211
  }
4398
4212
  if (parsed.action === "cancel") await showNotice(`ℹ️ Model kept as ${currentModelRef ?? "default"}.`);
4399
4213
  }
4400
- async function runDiscordModelPickerFallback(params) {
4401
- await handleDiscordModelPickerInteraction(params);
4402
- }
4403
- var DiscordModelPickerFallbackButton = class extends Button {
4404
- constructor(params) {
4405
- super();
4406
- this.params = params;
4407
- this.label = "modelpick";
4408
- this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
4409
- }
4410
- async run(interaction, data) {
4411
- await runDiscordModelPickerFallback({
4412
- ...this.params,
4413
- interaction,
4414
- data
4415
- });
4416
- }
4417
- };
4418
- var DiscordModelPickerFallbackSelect = class extends StringSelectMenu {
4419
- constructor(params) {
4420
- super();
4421
- this.params = params;
4422
- this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
4423
- this.options = [];
4424
- }
4425
- async run(interaction, data) {
4426
- await runDiscordModelPickerFallback({
4427
- ...this.params,
4428
- interaction,
4429
- data
4430
- });
4431
- }
4432
- };
4433
4214
  function createDiscordModelPickerFallbackButton$1(params) {
4434
- return new DiscordModelPickerFallbackButton(params);
4215
+ return new class extends Button {
4216
+ constructor(..._args) {
4217
+ super(..._args);
4218
+ this.label = "modelpick";
4219
+ this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
4220
+ }
4221
+ async run(interaction, data) {
4222
+ await handleDiscordModelPickerInteraction({
4223
+ ...params,
4224
+ interaction,
4225
+ data
4226
+ });
4227
+ }
4228
+ }();
4435
4229
  }
4436
4230
  function createDiscordModelPickerFallbackSelect$1(params) {
4437
- return new DiscordModelPickerFallbackSelect(params);
4231
+ return new class extends StringSelectMenu {
4232
+ constructor(..._args2) {
4233
+ super(..._args2);
4234
+ this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
4235
+ this.options = [];
4236
+ }
4237
+ async run(interaction, data) {
4238
+ await handleDiscordModelPickerInteraction({
4239
+ ...params,
4240
+ interaction,
4241
+ data
4242
+ });
4243
+ }
4244
+ }();
4438
4245
  }
4439
4246
  //#endregion
4440
4247
  //#region extensions/discord/src/monitor/native-command-status.ts
@@ -4455,15 +4262,9 @@ async function maybeDeliverDiscordDirectStatus(params) {
4455
4262
  interaction: params.interaction,
4456
4263
  payload: statusReply,
4457
4264
  mediaLocalRoots: params.mediaLocalRoots,
4458
- textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
4459
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
4460
- cfg: params.cfg,
4461
- discordConfig: params.discordConfig,
4462
- accountId: params.accountId
4463
- }),
4265
+ ...resolveDiscordInteractionReplyOptions(params),
4464
4266
  preferFollowUp: params.preferFollowUp,
4465
- responseEphemeral: params.responseEphemeral,
4466
- chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
4267
+ responseEphemeral: params.responseEphemeral
4467
4268
  });
4468
4269
  return {
4469
4270
  accepted: true,
@@ -4483,9 +4284,9 @@ function readDiscordCommandArgs(interaction, definitions) {
4483
4284
  const values = {};
4484
4285
  for (const definition of definitions) {
4485
4286
  let value;
4486
- if (definition.type === "number") value = interaction.options.getNumber(definition.name) ?? null;
4487
- else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name) ?? null;
4488
- else value = interaction.options.getString(definition.name) ?? null;
4287
+ if (definition.type === "number") value = interaction.options.getNumber(definition.name);
4288
+ else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name);
4289
+ else value = interaction.options.getString(definition.name);
4489
4290
  if (value != null) values[definition.name] = value;
4490
4291
  }
4491
4292
  return Object.keys(values).length > 0 ? { values } : void 0;
@@ -4520,26 +4321,21 @@ function truncateDiscordCommandDescriptionLocalizations(params) {
4520
4321
  label: `${params.label} locale:${locale}`
4521
4322
  })]));
4522
4323
  }
4523
- function resolveDiscordCommandLogLabel(command) {
4524
- if (typeof command.nativeName === "string" && command.nativeName.trim().length > 0) return command.nativeName;
4525
- return command.key;
4526
- }
4527
4324
  function buildDiscordCommandOptions(params) {
4528
4325
  const { command, cfg, resolveConfig, authorizeChoiceContext, resolveChoiceContext } = params;
4529
- const commandLabel = resolveDiscordCommandLogLabel(command);
4326
+ const commandLabel = command.nativeName?.trim() ? command.nativeName : command.key;
4530
4327
  const args = command.args;
4531
4328
  if (!args || args.length === 0) return;
4532
4329
  return args.map((arg) => {
4533
- const required = arg.required ?? false;
4534
- if (arg.type === "number" || arg.type === "boolean") return {
4330
+ const base = {
4535
4331
  name: arg.name,
4536
4332
  description: truncateDiscordCommandDescription({
4537
4333
  value: arg.description,
4538
4334
  label: `command:${commandLabel} arg:${arg.name}`
4539
4335
  }),
4540
- type: arg.type === "number" ? ApplicationCommandOptionType.Number : ApplicationCommandOptionType.Boolean,
4541
- required
4336
+ required: arg.required ?? false
4542
4337
  };
4338
+ if (arg.type === "number" || arg.type === "boolean") return Object.assign(base, { type: arg.type === "number" ? ApplicationCommandOptionType.Number : ApplicationCommandOptionType.Boolean });
4543
4339
  const resolvedChoices = resolveCommandArgChoices({
4544
4340
  command,
4545
4341
  arg,
@@ -4580,35 +4376,19 @@ function buildDiscordCommandOptions(params) {
4580
4376
  name: choice.label,
4581
4377
  value: choice.value
4582
4378
  })) : void 0;
4583
- return {
4584
- name: arg.name,
4585
- description: truncateDiscordCommandDescription({
4586
- value: arg.description,
4587
- label: `command:${commandLabel} arg:${arg.name}`
4588
- }),
4379
+ return Object.assign(base, {
4589
4380
  type: ApplicationCommandOptionType.String,
4590
- required,
4591
4381
  choices,
4592
4382
  autocomplete
4593
- };
4383
+ });
4594
4384
  });
4595
4385
  }
4596
4386
  //#endregion
4597
4387
  //#region extensions/discord/src/monitor/native-command.ts
4598
4388
  const log = createSubsystemLogger("discord/native-command");
4599
4389
  const NON_PLUGIN_COMMAND_DISPATCH = Object.freeze({ kind: "non-plugin" });
4600
- function resolveDiscordNativePolicyReader(params) {
4601
- return params.readPolicy ?? createDiscordLivePolicyReader({
4602
- ...params,
4603
- readConfig: () => getRuntimeConfigSnapshot() ?? params.cfg,
4604
- resolvedAllowlist: {
4605
- guildEntries: params.discordConfig?.guilds,
4606
- allowFrom: params.discordConfig?.allowFrom ?? resolveDiscordAccountAllowFrom(params)
4607
- }
4608
- });
4609
- }
4610
4390
  function createDiscordNativeCommand(params) {
4611
- const { command, cfg, discordConfig, accountId, sessionPrefix, ephemeralDefault, threadBindings, dispatchReplyFromConfig } = params;
4391
+ const { command, cfg, discordConfig, accountId, sessionPrefix, ephemeralDefault, threadBindings, buildContext, dispatchReplyFromConfig } = params;
4612
4392
  const fallbackCommandDefinition = createNativeCommandDefinition(command);
4613
4393
  const pluginCommandCandidate = "prepareDispatch" in command ? command : void 0;
4614
4394
  const commandDefinition = pluginCommandCandidate ? fallbackCommandDefinition : findCommandByNativeName$1(command.name, "discord", { includeBundledChannelFallback: false }) ?? fallbackCommandDefinition;
@@ -4627,6 +4407,9 @@ function createDiscordNativeCommand(params) {
4627
4407
  ...policy,
4628
4408
  isPolicyCurrent: policy.isCurrent,
4629
4409
  accountId,
4410
+ sessionPrefix,
4411
+ threadBindings,
4412
+ buildContext,
4630
4413
  skipCommandOwnerAllowFrom: pluginCommandCandidate !== void 0
4631
4414
  });
4632
4415
  },
@@ -4681,6 +4464,7 @@ function createDiscordNativeCommand(params) {
4681
4464
  preferFollowUp: true,
4682
4465
  threadBindings,
4683
4466
  responseEphemeral: ephemeralDefault,
4467
+ buildContext,
4684
4468
  dispatchReplyFromConfig,
4685
4469
  pluginCommandDispatch: preparedPluginCommand ?? NON_PLUGIN_COMMAND_DISPATCH
4686
4470
  });
@@ -4688,7 +4472,7 @@ function createDiscordNativeCommand(params) {
4688
4472
  }();
4689
4473
  }
4690
4474
  async function dispatchDiscordCommandInteraction(params) {
4691
- const { interaction, prompt, command, commandArgs, cfg: inputConfig, discordConfig: inputDiscordConfig, accountId, sessionPrefix, preferFollowUp, threadBindings, responseEphemeral, suppressReplies, dispatchReplyFromConfig } = params;
4475
+ const { interaction, prompt, command, commandArgs, cfg: inputConfig, discordConfig: inputDiscordConfig, accountId, sessionPrefix, preferFollowUp, threadBindings, responseEphemeral, suppressReplies, buildContext, dispatchReplyFromConfig } = params;
4692
4476
  const policy = await params.readPolicy?.();
4693
4477
  const cfg = policy?.cfg ?? getRuntimeConfigSnapshot() ?? inputConfig;
4694
4478
  const discordConfig = policy?.discordConfig ?? inputDiscordConfig;
@@ -4700,14 +4484,9 @@ async function dispatchDiscordCommandInteraction(params) {
4700
4484
  ...ephemeral !== void 0 ? { ephemeral } : {}
4701
4485
  };
4702
4486
  await safeDiscordInteractionCall("interaction reply", async () => {
4703
- if (preferFollowUp) {
4704
- await interaction.followUp(payload);
4705
- return;
4706
- }
4707
- await interaction.reply(payload);
4487
+ await interaction[preferFollowUp ? "followUp" : "reply"](payload);
4708
4488
  });
4709
4489
  };
4710
- const useAccessGroups = true;
4711
4490
  const user = interaction.user;
4712
4491
  if (!user) return { accepted: false };
4713
4492
  const sender = resolveDiscordSenderIdentity({
@@ -4715,12 +4494,13 @@ async function dispatchDiscordCommandInteraction(params) {
4715
4494
  pluralkitInfo: null
4716
4495
  });
4717
4496
  const channel = interaction.channel;
4718
- const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId, threadParentName, threadParentSlug } = await resolveDiscordNativeInteractionChannelContext({
4497
+ const channelContext = await resolveDiscordNativeInteractionChannelContext({
4719
4498
  channel,
4720
4499
  client: interaction.client,
4721
4500
  hasGuild: Boolean(interaction.guild),
4722
4501
  channelIdFallback: interaction.rawData.channel_id ?? ""
4723
4502
  });
4503
+ const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
4724
4504
  if (policy?.isCurrent() === false) {
4725
4505
  await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
4726
4506
  return { accepted: false };
@@ -4731,47 +4511,20 @@ async function dispatchDiscordCommandInteraction(params) {
4731
4511
  cfg,
4732
4512
  accountId
4733
4513
  }) ?? [];
4734
- const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(cfg);
4735
- const { ownerAllowList: discordOwnerAllowList, ownerAllowed: discordOwnerOk } = resolveDiscordOwnerAccess({
4514
+ const { ownerAllowList, ownerAllowed } = resolveDiscordOwnerAccess({
4736
4515
  allowFrom: configuredDmAllowFrom,
4737
- sender: {
4738
- id: sender.id,
4739
- name: sender.name,
4740
- tag: sender.tag
4741
- },
4742
- allowNameMatching
4743
- });
4744
- const { ownerAllowed: commandOwnerOk } = resolveDiscordOwnerAccess({
4745
- allowFrom: commandOwnerAllowFrom,
4746
- sender: {
4747
- id: sender.id,
4748
- name: sender.name,
4749
- tag: sender.tag
4750
- },
4516
+ sender,
4751
4517
  allowNameMatching
4752
4518
  });
4753
- const commandOwnerAllowAll = commandOwnerAllowFrom?.includes("*") === true;
4754
- const senderIsCommandOwner = commandOwnerOk;
4755
- const commandOwnerAccessAllowed = senderIsCommandOwner || commandOwnerAllowAll;
4756
- const ownerAllowListConfigured = discordOwnerAllowList != null;
4757
- const ownerOk = discordOwnerOk;
4758
4519
  const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
4759
4520
  cfg,
4760
4521
  discordConfig,
4761
- accountId,
4762
4522
  sender,
4763
- isDirectMessage,
4764
- isThreadChannel,
4765
- guild: interaction.guild ?? null,
4766
- rawChannelId,
4767
- channelName,
4768
- channelSlug,
4769
- threadParentId,
4770
- threadParentName,
4771
- threadParentSlug
4523
+ ...channelContext,
4524
+ guild: interaction.guild ?? null
4772
4525
  });
4773
- let nativeRouteStatePromise;
4774
- const getNativeRouteState = () => nativeRouteStatePromise ??= nativeCommandRuntime.resolveDiscordNativeInteractionRouteState({
4526
+ let nativeRouteState;
4527
+ const getNativeRouteState = () => nativeRouteState ??= nativeCommandRuntime.resolveDiscordNativeInteractionRouteState({
4775
4528
  cfg,
4776
4529
  accountId,
4777
4530
  guildId: interaction.guild?.id ?? void 0,
@@ -4781,19 +4534,18 @@ async function dispatchDiscordCommandInteraction(params) {
4781
4534
  directUserId: user.id,
4782
4535
  conversationId: rawChannelId || "unknown",
4783
4536
  parentConversationId: threadParentId,
4784
- threadBinding: isThreadChannel ? threadBindings.getByThreadId(rawChannelId) : void 0,
4785
- enforceConfiguredBindingReadiness: !shouldBypassConfiguredAcpEnsure(commandName)
4537
+ threadBinding: isThreadChannel ? threadBindings.getByThreadId(rawChannelId) : void 0
4786
4538
  });
4787
- const canBypassConfiguredAcpGuildGuards = async () => {
4539
+ const canBypassConfiguredAcpGuildGuards = () => {
4788
4540
  if (!interaction.guild || !shouldBypassConfiguredAcpGuildGuards(commandName)) return false;
4789
- const routeState = await getNativeRouteState();
4790
- return routeState.effectiveRoute.matchedBy === "binding.channel" || routeState.boundSessionKey != null || routeState.configuredBinding != null || routeState.configuredRoute != null;
4541
+ const routeState = getNativeRouteState();
4542
+ return routeState.effectiveRoute.matchedBy === "binding.channel" || routeState.boundSessionKey != null || routeState.configuredBinding != null;
4791
4543
  };
4792
- if (channelConfig?.enabled === false && !await canBypassConfiguredAcpGuildGuards()) {
4544
+ if (channelConfig?.enabled === false && !canBypassConfiguredAcpGuildGuards()) {
4793
4545
  await respond("This channel is disabled.");
4794
4546
  return { accepted: false };
4795
4547
  }
4796
- if (interaction.guild && channelConfig?.allowed === false && !await canBypassConfiguredAcpGuildGuards()) {
4548
+ if (interaction.guild && channelConfig?.allowed === false && !canBypassConfiguredAcpGuildGuards()) {
4797
4549
  await respond("This channel is not allowed.");
4798
4550
  return { accepted: false };
4799
4551
  }
@@ -4807,7 +4559,7 @@ async function dispatchDiscordCommandInteraction(params) {
4807
4559
  groupPolicy,
4808
4560
  guildInfo,
4809
4561
  channelConfig
4810
- }).allowed && !await canBypassConfiguredAcpGuildGuards()) {
4562
+ }).allowed && !canBypassConfiguredAcpGuildGuards()) {
4811
4563
  await respond("This channel is not allowed.");
4812
4564
  return { accepted: false };
4813
4565
  }
@@ -4831,11 +4583,7 @@ async function dispatchDiscordCommandInteraction(params) {
4831
4583
  accountId,
4832
4584
  dmPolicy,
4833
4585
  configuredAllowFrom: configuredDmAllowFrom,
4834
- sender: {
4835
- id: sender.id,
4836
- name: sender.name,
4837
- tag: sender.tag
4838
- },
4586
+ sender,
4839
4587
  allowNameMatching,
4840
4588
  cfg,
4841
4589
  rest: interaction.client.rest
@@ -4883,19 +4631,17 @@ async function dispatchDiscordCommandInteraction(params) {
4883
4631
  if (!isDirectMessage) {
4884
4632
  commandAuthorized = await resolveDiscordGuildNativeCommandAuthorized({
4885
4633
  cfg,
4886
- accountId,
4887
4634
  discordConfig,
4888
- useAccessGroups,
4889
4635
  commandsAllowFromAccess,
4890
4636
  guildInfo,
4891
4637
  channelConfig,
4892
4638
  memberRoleIds,
4893
4639
  sender,
4894
4640
  allowNameMatching,
4895
- ownerAllowListConfigured,
4896
- ownerAllowed: ownerOk
4641
+ ownerAllowListConfigured: ownerAllowList != null,
4642
+ ownerAllowed
4897
4643
  });
4898
- if (!commandAuthorized && !await canBypassConfiguredAcpGuildGuards()) {
4644
+ if (!commandAuthorized && !canBypassConfiguredAcpGuildGuards()) {
4899
4645
  await respond("You are not authorized to use this command.", { ephemeral: true });
4900
4646
  return { accepted: false };
4901
4647
  }
@@ -4904,18 +4650,63 @@ async function dispatchDiscordCommandInteraction(params) {
4904
4650
  await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
4905
4651
  return { accepted: false };
4906
4652
  }
4907
- if (commandOwnerAllowFrom && !commandOwnerAccessAllowed && !commandsAllowFromAccess.allowed && commandName !== "status" && params.pluginCommandDispatch.kind !== "plugin") {
4653
+ const routeState = getNativeRouteState();
4654
+ const effectiveRoute = routeState.effectiveRoute;
4655
+ const { ctxPayload, sessionKey, commandTargetSessionKey } = await buildDiscordNativeInteractionContext({
4656
+ buildContext,
4657
+ interaction,
4658
+ channelContext,
4659
+ route: effectiveRoute,
4660
+ boundSessionKey: routeState.boundSessionKey,
4661
+ sessionPrefix,
4662
+ prompt,
4663
+ commandArgs: commandArgs ?? {},
4664
+ channelConfig,
4665
+ guildInfo,
4666
+ allowNameMatching,
4667
+ commandAuthorized,
4668
+ user,
4669
+ sender
4670
+ });
4671
+ const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, effectiveRoute.agentId);
4672
+ if (policy?.isCurrent() === false) {
4673
+ await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
4674
+ return { accepted: false };
4675
+ }
4676
+ const authority = createDiscordNativeCommandAuthority({
4677
+ cfg,
4678
+ ctx: ctxPayload,
4679
+ commandAuthorized,
4680
+ sender,
4681
+ allowNameMatching,
4682
+ isPolicyCurrent: policy?.isCurrent,
4683
+ accountId,
4684
+ guildId: interaction.guild?.id,
4685
+ commandName,
4686
+ pluginCommand: params.pluginCommandDispatch.kind === "plugin"
4687
+ });
4688
+ if (!authority.isAllowed()) {
4689
+ await respond("You are not authorized to use this command.", { ephemeral: true });
4690
+ return { accepted: false };
4691
+ }
4692
+ const bindingReadiness = routeState.configuredBinding && !shouldBypassConfiguredAcpEnsure(commandName) ? await nativeCommandRuntime.ensureConfiguredBindingRouteReady({
4693
+ cfg,
4694
+ bindingResolution: routeState.configuredBinding,
4695
+ assertActive: authority.assertActive
4696
+ }) : null;
4697
+ if (!authority.isAllowed()) {
4908
4698
  await respond("You are not authorized to use this command.", { ephemeral: true });
4909
4699
  return { accepted: false };
4910
4700
  }
4911
4701
  const isGuild = Boolean(interaction.guild);
4912
4702
  const channelId = rawChannelId || "unknown";
4913
4703
  const menuNeedsModelContext = !(commandArgs?.raw && !commandArgs.values) && command.args?.some((arg) => typeof arg.choices === "function" && commandArgs?.values?.[arg.name] == null);
4914
- const menuModelContext = menuNeedsModelContext ? await resolveDiscordNativeChoiceContext({
4704
+ const menuModelContext = menuNeedsModelContext && bindingReadiness?.ok !== false ? await resolveDiscordNativeChoiceContext({
4915
4705
  interaction,
4916
4706
  cfg,
4917
4707
  accountId,
4918
- threadBindings
4708
+ threadBindings,
4709
+ route: effectiveRoute
4919
4710
  }) : null;
4920
4711
  const menuModelCatalog = command.key === "think" && menuNeedsModelContext ? await loadPreparedModelCatalog({
4921
4712
  config: cfg,
@@ -4925,17 +4716,20 @@ async function dispatchDiscordCommandInteraction(params) {
4925
4716
  } : {},
4926
4717
  readOnly: true
4927
4718
  }) : void 0;
4928
- const menuRouteState = command.key === "verbose" ? await getNativeRouteState() : void 0;
4929
- const menu = menuRouteState?.bindingReadiness?.ok === false ? null : resolveCommandArgMenu({
4719
+ const menu = command.key === "verbose" && bindingReadiness?.ok === false ? null : resolveCommandArgMenu({
4930
4720
  command,
4931
4721
  args: commandArgs,
4932
4722
  cfg,
4933
- session: menuRouteState?.effectiveRoute,
4723
+ session: command.key === "verbose" ? effectiveRoute : void 0,
4934
4724
  provider: menuModelContext?.provider,
4935
4725
  model: menuModelContext?.model,
4936
4726
  agentRuntime: menuModelContext?.agentRuntime,
4937
4727
  catalog: menuModelCatalog
4938
4728
  });
4729
+ if (policy?.isCurrent() === false) {
4730
+ await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
4731
+ return { accepted: false };
4732
+ }
4939
4733
  if (menu) {
4940
4734
  const menuPayload = buildDiscordCommandArgMenu({
4941
4735
  command,
@@ -4947,20 +4741,13 @@ async function dispatchDiscordCommandInteraction(params) {
4947
4741
  accountId,
4948
4742
  sessionPrefix,
4949
4743
  threadBindings,
4744
+ buildContext,
4950
4745
  dispatchReplyFromConfig
4951
4746
  },
4952
4747
  safeInteractionCall: safeDiscordInteractionCall,
4953
4748
  dispatchCommandInteraction: dispatchDiscordCommandInteraction
4954
4749
  });
4955
- if (preferFollowUp) {
4956
- await safeDiscordInteractionCall("interaction follow-up", () => interaction.followUp({
4957
- content: menuPayload.content,
4958
- components: menuPayload.components,
4959
- ephemeral: true
4960
- }));
4961
- return { accepted: true };
4962
- }
4963
- await safeDiscordInteractionCall("interaction reply", () => interaction.reply({
4750
+ await safeDiscordInteractionCall(preferFollowUp ? "interaction follow-up" : "interaction reply", () => interaction[preferFollowUp ? "followUp" : "reply"]({
4964
4751
  content: menuPayload.content,
4965
4752
  components: menuPayload.components,
4966
4753
  ephemeral: true
@@ -4974,19 +4761,20 @@ async function dispatchDiscordCommandInteraction(params) {
4974
4761
  }
4975
4762
  const messageThreadId = !isDirectMessage && isThreadChannel ? channelId : void 0;
4976
4763
  const pluginThreadParentId = !isDirectMessage && isThreadChannel ? threadParentId : void 0;
4977
- const routeState = await getNativeRouteState();
4978
- const { effectiveRoute } = routeState;
4979
4764
  const pluginCommandAgentId = (isThreadChannel ? threadBindings.getByThreadId(rawChannelId)?.agentId : void 0) || routeState.configuredBinding?.statefulTarget.agentId || effectiveRoute.agentId;
4980
4765
  const targetSessionEntry = nativeCommandRuntime.getSessionEntry({
4981
4766
  agentId: pluginCommandAgentId,
4982
4767
  sessionKey: effectiveRoute.sessionKey
4983
4768
  });
4769
+ authority.assertActive();
4770
+ const senderIsOwner = authority.senderIsOwner();
4984
4771
  const pluginReply = await params.pluginCommandDispatch.execute({
4985
4772
  senderId: sender.id,
4986
4773
  channel: "discord",
4987
4774
  channelId,
4988
4775
  isAuthorizedSender: commandAuthorized,
4989
- senderIsOwner: senderIsCommandOwner,
4776
+ senderIsOwner,
4777
+ ...senderIsOwner ? { assertOwnerCurrent: authority.assertOwnerCurrent } : {},
4990
4778
  agentId: pluginCommandAgentId,
4991
4779
  sessionKey: effectiveRoute.sessionKey,
4992
4780
  authProfileId: targetSessionEntry?.authProfileOverride,
@@ -5015,15 +4803,13 @@ async function dispatchDiscordCommandInteraction(params) {
5015
4803
  await deliverDiscordInteractionReply({
5016
4804
  interaction,
5017
4805
  payload: pluginReply,
5018
- textLimit: resolveTextChunkLimit(cfg, "discord", accountId, { fallbackLimit: 2e3 }),
5019
- maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
4806
+ ...resolveDiscordInteractionReplyOptions({
5020
4807
  cfg,
5021
4808
  discordConfig,
5022
4809
  accountId
5023
4810
  }),
5024
4811
  preferFollowUp,
5025
- responseEphemeral,
5026
- chunkMode: resolveChunkMode(cfg, "discord", accountId)
4812
+ responseEphemeral
5027
4813
  });
5028
4814
  return {
5029
4815
  accepted: true,
@@ -5047,58 +4833,14 @@ async function dispatchDiscordCommandInteraction(params) {
5047
4833
  });
5048
4834
  return { accepted: true };
5049
4835
  }
5050
- const interactionId = interaction.rawData.id;
5051
- const routeState = await getNativeRouteState();
5052
- if (routeState.bindingReadiness && !routeState.bindingReadiness.ok) {
4836
+ if (bindingReadiness && !bindingReadiness.ok) {
5053
4837
  const configuredBinding = routeState.configuredBinding;
5054
4838
  if (configuredBinding) {
5055
- logVerbose(`discord native command: configured ACP binding unavailable for channel ${configuredBinding.record.conversation.conversationId}: ${routeState.bindingReadiness.error}`);
4839
+ logVerbose(`discord native command: configured ACP binding unavailable for channel ${configuredBinding.record.conversation.conversationId}: ${bindingReadiness.error}`);
5056
4840
  await respond("Configured ACP binding is unavailable right now. Please try again.");
5057
4841
  return { accepted: false };
5058
4842
  }
5059
4843
  }
5060
- const boundSessionKey = routeState.boundSessionKey;
5061
- const effectiveRoute = routeState.effectiveRoute;
5062
- const { sessionKey, commandTargetSessionKey } = resolveNativeCommandSessionTargets({
5063
- agentId: effectiveRoute.agentId,
5064
- sessionPrefix,
5065
- userId: user.id,
5066
- targetSessionKey: effectiveRoute.sessionKey,
5067
- boundSessionKey
5068
- });
5069
- const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, effectiveRoute.agentId);
5070
- const ctxPayload = buildDiscordNativeCommandContext({
5071
- prompt,
5072
- commandArgs: commandArgs ?? {},
5073
- sessionKey,
5074
- commandTargetSessionKey,
5075
- accountId: effectiveRoute.accountId,
5076
- interactionId,
5077
- channelId,
5078
- threadParentId,
5079
- memberRoleIds,
5080
- guildId: interaction.guild?.id,
5081
- guildName: interaction.guild?.name,
5082
- channelTopic: resolveDiscordChannelTopicSafe(channel),
5083
- channelConfig,
5084
- guildInfo,
5085
- allowNameMatching,
5086
- commandAuthorized,
5087
- isDirectMessage,
5088
- isGroupDm,
5089
- isGuild,
5090
- isThreadChannel,
5091
- user: {
5092
- id: user.id,
5093
- username: user.username,
5094
- globalName: user.globalName
5095
- },
5096
- sender: {
5097
- id: sender.id,
5098
- name: sender.name,
5099
- tag: sender.tag
5100
- }
5101
- });
5102
4844
  const directStatusResult = await maybeDeliverDiscordDirectStatus({
5103
4845
  commandName,
5104
4846
  suppressReplies,
@@ -5110,7 +4852,7 @@ async function dispatchDiscordCommandInteraction(params) {
5110
4852
  commandTargetSessionKey,
5111
4853
  channel: "discord",
5112
4854
  senderId: sender.id,
5113
- senderIsOwner: senderIsCommandOwner,
4855
+ senderIsOwner: authority.senderIsOwner(),
5114
4856
  isAuthorizedSender: commandAuthorized,
5115
4857
  isGroup: isGuild || isGroupDm,
5116
4858
  defaultGroupActivation: () => !isGuild ? "always" : channelConfig?.requireMention === false ? "always" : "mention",
@@ -5325,7 +5067,7 @@ var GatewaySendLimiter = class {
5325
5067
  shouldEmitOverflowWarning = true;
5326
5068
  }
5327
5069
  }
5328
- this.outboundQueue.push({ payload: serialized });
5070
+ this.outboundQueue.push(serialized);
5329
5071
  if (shouldEmitOverflowWarning) this.emitOverflowWarning({
5330
5072
  droppedEvents: this.droppedEvents,
5331
5073
  maxQueuedEvents: GATEWAY_SEND_QUEUE_LIMIT,
@@ -5382,9 +5124,9 @@ var GatewaySendLimiter = class {
5382
5124
  flush() {
5383
5125
  while (this.outboundQueue.length > 0 && this.canSend(Date.now())) {
5384
5126
  const queued = this.outboundQueue.shift();
5385
- if (!queued) continue;
5127
+ if (queued === void 0) continue;
5386
5128
  try {
5387
- this.sendSerialized(queued.payload);
5129
+ this.sendSerialized(queued);
5388
5130
  } catch (error) {
5389
5131
  this.emitError(error instanceof Error ? error : new Error(String(error), { cause: error }));
5390
5132
  this.clear();
@@ -5519,9 +5261,6 @@ var GatewayPlugin = class extends Plugin {
5519
5261
  };
5520
5262
  this.gatewayInfo = gatewayInfo;
5521
5263
  }
5522
- get ping() {
5523
- return null;
5524
- }
5525
5264
  listVoiceChannelStates(guildId, channelId) {
5526
5265
  return this.voiceStateCache.listVoiceChannelStates(guildId, channelId);
5527
5266
  }
@@ -5555,8 +5294,8 @@ var GatewayPlugin = class extends Plugin {
5555
5294
  this.connect(false);
5556
5295
  }
5557
5296
  connect(resume = false) {
5558
- this.stopReconnectTimer();
5559
- this.stopHeartbeat();
5297
+ this.reconnectTimer.stop();
5298
+ this.heartbeatTimers.stop();
5560
5299
  if (this.isConnecting) return;
5561
5300
  this.shouldReconnect = true;
5562
5301
  this.lastHeartbeatAck = true;
@@ -5569,8 +5308,8 @@ var GatewayPlugin = class extends Plugin {
5569
5308
  }
5570
5309
  disconnect() {
5571
5310
  this.shouldReconnect = false;
5572
- this.stopReconnectTimer();
5573
- this.stopHeartbeat();
5311
+ this.reconnectTimer.stop();
5312
+ this.heartbeatTimers.stop();
5574
5313
  this.outboundLimiter.clear();
5575
5314
  this.ws?.close(1e3, "Client disconnect");
5576
5315
  this.ws = null;
@@ -5603,7 +5342,7 @@ var GatewayPlugin = class extends Plugin {
5603
5342
  socket.on("close", (code) => {
5604
5343
  if (socket !== this.ws) return;
5605
5344
  const closeCode = code;
5606
- this.stopHeartbeat();
5345
+ this.heartbeatTimers.stop();
5607
5346
  this.outboundLimiter.clear();
5608
5347
  this.isConnecting = false;
5609
5348
  this.isConnected = false;
@@ -5688,12 +5427,6 @@ var GatewayPlugin = class extends Plugin {
5688
5427
  }
5689
5428
  });
5690
5429
  }
5691
- stopHeartbeat() {
5692
- this.heartbeatTimers.stop();
5693
- }
5694
- stopReconnectTimer() {
5695
- this.reconnectTimer.stop();
5696
- }
5697
5430
  sendHeartbeat() {
5698
5431
  if (!this.ws || this.ws.readyState !== READY_STATE_OPEN) return;
5699
5432
  this.lastHeartbeatAck = false;
@@ -5759,7 +5492,7 @@ var GatewayPlugin = class extends Plugin {
5759
5492
  this.isConnected = true;
5760
5493
  }
5761
5494
  this.voiceStateCache.apply(payload);
5762
- dispatchVoiceGatewayEvent(this.client, payload.t, payload.d);
5495
+ dispatchVoiceGatewayEvent(this.client, payload);
5763
5496
  const data = payload.t === GatewayDispatchEvents.MessageCreate ? payload.d : mapGatewayDispatchData(this.client, payload.t, payload.d);
5764
5497
  await this.client.dispatchGatewayEvent(payload.t, data);
5765
5498
  if (payload.t === GatewayDispatchEvents.InteractionCreate && this.options.autoInteractions) await this.client.handleInteraction(payload.d);
@@ -5779,8 +5512,8 @@ var GatewayPlugin = class extends Plugin {
5779
5512
  }
5780
5513
  scheduleReconnect(options) {
5781
5514
  if (!this.shouldReconnect) return;
5782
- this.stopHeartbeat();
5783
- this.stopReconnectTimer();
5515
+ this.heartbeatTimers.stop();
5516
+ this.reconnectTimer.stop();
5784
5517
  this.ws?.close();
5785
5518
  this.ws = null;
5786
5519
  this.isConnecting = false;
@@ -5818,43 +5551,24 @@ var GatewayPlugin = class extends Plugin {
5818
5551
  d: data
5819
5552
  }, true);
5820
5553
  }
5821
- requestGuildMembers(data) {
5822
- if (!this.hasIntent(GatewayIntentBits.GuildMembers)) throw new Error("GUILD_MEMBERS intent is required for requestGuildMembers");
5823
- if (data.presences && !this.hasIntent(GatewayIntentBits.GuildPresences)) throw new Error("GUILD_PRESENCES intent is required when requesting presences");
5824
- if (!data.query && data.query !== "" && !data.user_ids) throw new Error("Either query or user_ids is required for requestGuildMembers");
5825
- this.send({
5826
- op: GatewayOpcodes.RequestGuildMembers,
5827
- d: data
5828
- });
5829
- }
5830
5554
  getRateLimitStatus() {
5831
5555
  return this.outboundLimiter.getStatus();
5832
5556
  }
5833
- hasIntent(intent) {
5834
- return Boolean((this.options.intents ?? 0) & intent);
5835
- }
5836
5557
  };
5837
5558
  //#endregion
5838
5559
  //#region extensions/discord/src/monitor/presence.ts
5839
- const DEFAULT_CUSTOM_ACTIVITY_TYPE$1 = 4;
5840
- const CUSTOM_STATUS_NAME$1 = "Custom Status";
5560
+ const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
5561
+ const CUSTOM_STATUS_NAME = "Custom Status";
5841
5562
  function resolveDiscordPresenceUpdate(config) {
5842
5563
  const activityText = normalizeOptionalString(config.activity) ?? "";
5843
5564
  const status = normalizeOptionalString(config.status) ?? "";
5844
5565
  const activityType = config.activityType;
5845
5566
  const activityUrl = normalizeOptionalString(config.activityUrl) ?? "";
5846
- const hasActivity = Boolean(activityText);
5847
- if (!hasActivity && !Boolean(status)) return {
5848
- since: null,
5849
- activities: [],
5850
- status: "online",
5851
- afk: false
5852
- };
5853
5567
  const activities = [];
5854
- if (hasActivity) {
5855
- const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE$1;
5856
- const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE$1 ? {
5857
- name: CUSTOM_STATUS_NAME$1,
5568
+ if (activityText) {
5569
+ const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE;
5570
+ const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE ? {
5571
+ name: CUSTOM_STATUS_NAME,
5858
5572
  type: resolvedType,
5859
5573
  state: activityText
5860
5574
  } : {
@@ -5873,8 +5587,6 @@ function resolveDiscordPresenceUpdate(config) {
5873
5587
  }
5874
5588
  //#endregion
5875
5589
  //#region extensions/discord/src/monitor/auto-presence.ts
5876
- const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
5877
- const CUSTOM_STATUS_NAME = "Custom Status";
5878
5590
  const DEFAULT_INTERVAL_MS = 3e4;
5879
5591
  const DEFAULT_MIN_UPDATE_INTERVAL_MS = 15e3;
5880
5592
  const MIN_INTERVAL_MS = 5e3;
@@ -5894,13 +5606,6 @@ function resolveAutoPresenceConfig(config) {
5894
5606
  minUpdateIntervalMs
5895
5607
  };
5896
5608
  }
5897
- function buildCustomStatusActivity(text) {
5898
- return {
5899
- name: CUSTOM_STATUS_NAME,
5900
- type: DEFAULT_CUSTOM_ACTIVITY_TYPE,
5901
- state: text
5902
- };
5903
- }
5904
5609
  function isExhaustedUnavailableReason(reason) {
5905
5610
  if (!reason) return false;
5906
5611
  return reason === "rate_limit" || reason === "overloaded" || reason === "billing" || reason === "auth" || reason === "auth_permanent";
@@ -5916,15 +5621,6 @@ function resolveAuthAvailability(params) {
5916
5621
  now: params.now
5917
5622
  })) ? "exhausted" : "degraded";
5918
5623
  }
5919
- function resolvePresenceActivities(params) {
5920
- if (params.state === "healthy") return params.basePresence?.activities ?? [];
5921
- return [buildCustomStatusActivity(params.state === "degraded" ? "runtime degraded" : "token exhausted")];
5922
- }
5923
- function resolvePresenceStatus(state) {
5924
- if (state === "healthy") return "online";
5925
- if (state === "exhausted") return "dnd";
5926
- return "idle";
5927
- }
5928
5624
  function resolveDiscordAutoPresenceUpdate(params) {
5929
5625
  if (!resolveAutoPresenceConfig(params.discordConfig.autoPresence).enabled) return null;
5930
5626
  const now = params.now ?? Date.now();
@@ -5934,15 +5630,15 @@ function resolveDiscordAutoPresenceUpdate(params) {
5934
5630
  now
5935
5631
  });
5936
5632
  const state = params.gatewayConnected ? availability : "degraded";
5937
- return {
5633
+ return state === "healthy" ? {
5938
5634
  since: null,
5939
- activities: resolvePresenceActivities({
5940
- state,
5941
- basePresence
5942
- }),
5943
- status: resolvePresenceStatus(state),
5635
+ activities: basePresence.activities,
5636
+ status: "online",
5944
5637
  afk: false
5945
- };
5638
+ } : resolveDiscordPresenceUpdate({
5639
+ activity: state === "degraded" ? "runtime degraded" : "token exhausted",
5640
+ status: state === "degraded" ? "idle" : "dnd"
5641
+ });
5946
5642
  }
5947
5643
  function stablePresenceSignature(payload) {
5948
5644
  return JSON.stringify({
@@ -6015,6 +5711,7 @@ function createDiscordAutoPresenceController(params) {
6015
5711
  const DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT = "openclaw:discord-gateway-transport-activity";
6016
5712
  //#endregion
6017
5713
  //#region extensions/discord/src/monitor/gateway-metadata.ts
5714
+ const captureSdk$1 = proxyCaptureSdk;
6018
5715
  const DISCORD_GATEWAY_BOT_URL = "https://discord.com/api/v10/gateway/bot";
6019
5716
  const DISCORD_API_HOST = "discord.com";
6020
5717
  const DEFAULT_DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/";
@@ -6034,11 +5731,6 @@ const discordGatewayBotInfoSchema = Type.Object({
6034
5731
  })
6035
5732
  });
6036
5733
  const gatewayMetadataFallbackLogLastAt = /* @__PURE__ */ new WeakMap();
6037
- function resolveFetchInputUrl(input) {
6038
- if (typeof input === "string") return input;
6039
- if (input instanceof URL) return input.toString();
6040
- return input.url;
6041
- }
6042
5734
  async function materializeGuardedResponse(response) {
6043
5735
  const body = new Uint8Array(await readResponseWithLimit(response, DISCORD_GATEWAY_METADATA_MAX_BYTES, { onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`Discord gateway metadata response body too large: ${size} bytes (limit: ${maxBytes} bytes)`) }));
6044
5736
  return new Response(body, {
@@ -6102,6 +5794,7 @@ function parseDiscordGatewayInfoBody(body) {
6102
5794
  }
6103
5795
  async function fetchDiscordGatewayInfo(params) {
6104
5796
  let response;
5797
+ let body;
6105
5798
  try {
6106
5799
  response = await params.fetchImpl(params.gatewayBotUrl ?? DISCORD_GATEWAY_BOT_URL, {
6107
5800
  ...params.fetchInit,
@@ -6110,15 +5803,6 @@ async function fetchDiscordGatewayInfo(params) {
6110
5803
  Authorization: `Bot ${params.token}`
6111
5804
  }
6112
5805
  });
6113
- } catch (error) {
6114
- throw createGatewayMetadataError({
6115
- detail: formatErrorMessage$1(error),
6116
- transient: true,
6117
- cause: error
6118
- });
6119
- }
6120
- let body;
6121
- try {
6122
5806
  body = await response.text();
6123
5807
  } catch (error) {
6124
5808
  throw createGatewayMetadataError({
@@ -6183,7 +5867,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6183
5867
  const requestInit = init;
6184
5868
  const signal = requestInit?.signal ?? void 0;
6185
5869
  const guarded = await fetchWithSsrFGuard({
6186
- url: resolveFetchInputUrl(input),
5870
+ url: input,
6187
5871
  init: requestInit,
6188
5872
  ...signal ? { signal } : {},
6189
5873
  policy: { allowedHostnames: [DISCORD_API_HOST] },
@@ -6204,7 +5888,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6204
5888
  } finally {
6205
5889
  await guarded.release();
6206
5890
  }
6207
- if (options?.capture) captureHttpExchange({
5891
+ if (options?.capture) captureSdk$1.captureHttpExchangeAsync?.({
6208
5892
  url: input,
6209
5893
  method: init?.method ?? "GET",
6210
5894
  requestHeaders: init?.headers,
@@ -6212,23 +5896,17 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
6212
5896
  response,
6213
5897
  flowId: options.capture.flowId,
6214
5898
  meta: options.capture.meta
6215
- });
5899
+ }).catch(() => {});
6216
5900
  return response;
6217
5901
  }
6218
5902
  //#endregion
6219
5903
  //#region extensions/discord/src/monitor/gateway-plugin.ts
5904
+ const captureSdk = proxyCaptureSdk;
6220
5905
  const DISCORD_GATEWAY_POLICY_VIOLATION_CLOSE_CODE = 1008;
6221
5906
  const DISCORD_GATEWAY_WS_RECEIVER_LIMIT_CODE = "WS_ERR_TOO_MANY_BUFFERED_PARTS";
6222
5907
  const DISCORD_GATEWAY_CLOSE_REASON_LOG_MAX_CHARS = 240;
6223
5908
  const discordDnsLookup = createDiscordDnsLookup();
6224
5909
  const registrationPromises = /* @__PURE__ */ new WeakMap();
6225
- function assignGatewayClient(plugin, client) {
6226
- plugin.client = client;
6227
- }
6228
- function hasGatewaySocketStarted(plugin) {
6229
- const state = plugin;
6230
- return state.ws != null || state.isConnecting === true;
6231
- }
6232
5910
  function readStringProperty(value, key) {
6233
5911
  const property = value[key];
6234
5912
  return typeof property === "string" && property ? property : void 0;
@@ -6304,7 +5982,7 @@ function createGatewayPlugin(params) {
6304
5982
  return registration;
6305
5983
  }
6306
5984
  async registerClientInternal(client) {
6307
- assignGatewayClient(this, client);
5985
+ this.client = client;
6308
5986
  if (!this.gatewayInfo || this.gatewayInfoUsedFallback) {
6309
5987
  const resolved = await fetchDiscordGatewayInfoWithTimeout({
6310
5988
  token: client.options.token,
@@ -6329,7 +6007,7 @@ function createGatewayPlugin(params) {
6329
6007
  await params.testing.registerClient(this, client);
6330
6008
  return;
6331
6009
  }
6332
- if (hasGatewaySocketStarted(this)) return;
6010
+ if (this.ws != null || this.isConnecting) return;
6333
6011
  return super.registerClient(client);
6334
6012
  }
6335
6013
  createWebSocket(url) {
@@ -6345,35 +6023,34 @@ function createGatewayPlugin(params) {
6345
6023
  if (this.ws !== socket) return;
6346
6024
  this.emitter.emit(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, { at: Date.now() });
6347
6025
  };
6348
- captureWsEvent({
6349
- url,
6026
+ const captureEvent = (event) => {
6027
+ captureSdk.captureWsEventAsync?.({
6028
+ url,
6029
+ ...event(),
6030
+ flowId: wsFlowId,
6031
+ meta: { subsystem: "discord-gateway" }
6032
+ }).catch(() => {});
6033
+ };
6034
+ captureEvent(() => ({
6350
6035
  direction: "local",
6351
- kind: "ws-open",
6352
- flowId: wsFlowId,
6353
- meta: { subsystem: "discord-gateway" }
6354
- });
6036
+ kind: "ws-open"
6037
+ }));
6355
6038
  socket.on?.("message", (data) => {
6356
6039
  emitTransportActivity();
6357
- captureWsEvent({
6358
- url,
6040
+ captureEvent(() => ({
6359
6041
  direction: "inbound",
6360
6042
  kind: "ws-frame",
6361
- flowId: wsFlowId,
6362
- payload: Buffer.isBuffer(data) ? data : Buffer.from(String(data)),
6363
- meta: { subsystem: "discord-gateway" }
6364
- });
6043
+ payload: Buffer.isBuffer(data) ? data : Buffer.from(String(data))
6044
+ }));
6365
6045
  });
6366
6046
  socket.on?.("close", (code, reason) => {
6367
6047
  const closeReason = Buffer.isBuffer(reason) ? reason : Buffer.from(String(reason ?? ""));
6368
- captureWsEvent({
6369
- url,
6048
+ captureEvent(() => ({
6370
6049
  direction: "local",
6371
6050
  kind: "ws-close",
6372
- flowId: wsFlowId,
6373
6051
  closeCode: code,
6374
- payload: closeReason,
6375
- meta: { subsystem: "discord-gateway" }
6376
- });
6052
+ payload: closeReason
6053
+ }));
6377
6054
  if (shouldLogDiscordGatewayTransportClose({
6378
6055
  code,
6379
6056
  reason: closeReason,
@@ -6387,14 +6064,11 @@ function createGatewayPlugin(params) {
6387
6064
  });
6388
6065
  socket.on?.("error", (error) => {
6389
6066
  lastTransportError = describeDiscordGatewayTransportError(error);
6390
- captureWsEvent({
6391
- url,
6067
+ captureEvent(() => ({
6392
6068
  direction: "local",
6393
6069
  kind: "error",
6394
- flowId: wsFlowId,
6395
- errorText: error.message,
6396
- meta: { subsystem: "discord-gateway" }
6397
- });
6070
+ errorText: error.message
6071
+ }));
6398
6072
  params.runtime?.log?.(warn(formatDiscordGatewayTransportErrorLog({
6399
6073
  flowId: wsFlowId,
6400
6074
  error: lastTransportError
@@ -6445,7 +6119,7 @@ function createDiscordGatewayPlugin(params) {
6445
6119
  } : void 0;
6446
6120
  const endpointGatewayUrl = endpoint ? new URL(endpoint.gatewayOrigin) : void 0;
6447
6121
  let fetchImpl = createDiscordGatewayMetadataFetch(debugProxySettings.enabled, endpoint ? { endpoint } : void 0);
6448
- let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent$1({ lookup: endpointGatewayUrl ? createDiscordEndpointDnsLookup(endpointGatewayUrl.hostname) : discordDnsLookup });
6122
+ let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent({ lookup: endpointGatewayUrl ? createDiscordEndpointDnsLookup(endpointGatewayUrl.hostname) : discordDnsLookup });
6449
6123
  if (proxy && !endpoint) try {
6450
6124
  validateDiscordProxyUrl(proxy);
6451
6125
  wsAgent = params.testing?.createProxyAgent?.(proxy) ?? createNodeProxyAgent({
@@ -6524,29 +6198,16 @@ function formatDiscordGatewayErrorMessage(err) {
6524
6198
  }
6525
6199
  function classifyDiscordGatewayEvent(params) {
6526
6200
  const message = formatDiscordGatewayErrorMessage(params.err);
6527
- if (params.isDisallowedIntentsError(params.err)) return {
6528
- type: "disallowed-intents",
6529
- err: params.err,
6530
- message,
6531
- shouldStopLifecycle: true
6532
- };
6533
- if (message.includes("Max reconnect attempts")) return {
6534
- type: "reconnect-exhausted",
6535
- err: params.err,
6536
- message,
6537
- shouldStopLifecycle: true
6538
- };
6539
- if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) return {
6540
- type: "fatal",
6541
- err: params.err,
6542
- message,
6543
- shouldStopLifecycle: true
6544
- };
6201
+ let type;
6202
+ if (params.isDisallowedIntentsError(params.err)) type = "disallowed-intents";
6203
+ else if (message.includes("Max reconnect attempts")) type = "reconnect-exhausted";
6204
+ else if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) type = "fatal";
6205
+ else type = "other";
6545
6206
  return {
6546
- type: "other",
6207
+ type,
6547
6208
  err: params.err,
6548
6209
  message,
6549
- shouldStopLifecycle: false
6210
+ shouldStopLifecycle: type !== "other"
6550
6211
  };
6551
6212
  }
6552
6213
  function createDiscordGatewaySupervisor(params) {
@@ -6562,7 +6223,7 @@ function createDiscordGatewaySupervisor(params) {
6562
6223
  let lifecycleHandler;
6563
6224
  let phase = "buffering";
6564
6225
  const seenLateEventKeys = /* @__PURE__ */ new Set();
6565
- const logLateEvent = (state) => (event) => {
6226
+ const logLateEvent = (state, event) => {
6566
6227
  const key = `${state}:${event.type}:${event.message}`;
6567
6228
  if (seenLateEventKeys.has(key)) return;
6568
6229
  seenLateEventKeys.add(key);
@@ -6575,13 +6236,13 @@ function createDiscordGatewaySupervisor(params) {
6575
6236
  });
6576
6237
  switch (phase) {
6577
6238
  case "disposed":
6578
- logLateEvent("disposed")(event);
6239
+ logLateEvent("disposed", event);
6579
6240
  return;
6580
6241
  case "active":
6581
6242
  lifecycleHandler?.(event);
6582
6243
  return;
6583
6244
  case "teardown":
6584
- logLateEvent("teardown")(event);
6245
+ logLateEvent("teardown", event);
6585
6246
  return;
6586
6247
  case "buffering": pending.push(event);
6587
6248
  }
@@ -6733,12 +6394,6 @@ function normalizeGatewayReadyTimeoutMs(value) {
6733
6394
  if (numeric === void 0) return;
6734
6395
  return Math.min(numeric, MAX_DISCORD_GATEWAY_READY_TIMEOUT_MS);
6735
6396
  }
6736
- function resolveDiscordGatewayReadyTimeoutMs(params) {
6737
- return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
6738
- }
6739
- function resolveDiscordGatewayRuntimeReadyTimeoutMs(params) {
6740
- return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
6741
- }
6742
6397
  async function restartGatewayAfterReadyTimeout(params) {
6743
6398
  if (!params.gateway || params.abortSignal?.aborted) return;
6744
6399
  const socket = params.gateway.ws;
@@ -6767,44 +6422,32 @@ async function restartGatewayAfterReadyTimeout(params) {
6767
6422
  socket.removeListener("close", onClose);
6768
6423
  socket.removeListener("error", ignoreSocketError);
6769
6424
  };
6770
- const finishResolve = () => {
6425
+ const finish = (error) => {
6771
6426
  if (settled) return;
6772
6427
  settled = true;
6773
6428
  cleanup();
6774
- resolve();
6775
- };
6776
- const finishReject = (error) => {
6777
- if (params.abortSignal?.aborted) {
6778
- finishResolve();
6779
- return;
6780
- }
6781
- if (settled) return;
6782
- settled = true;
6783
- cleanup();
6784
- reject(error);
6785
- };
6786
- const onClose = () => {
6787
- finishResolve();
6429
+ if (error && !params.abortSignal?.aborted) reject(error);
6430
+ else resolve();
6788
6431
  };
6432
+ const onClose = () => finish();
6433
+ const failClose = () => finish(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6789
6434
  socket.on("error", ignoreSocketError);
6790
6435
  socket.on("close", onClose);
6791
6436
  params.gateway?.disconnect();
6792
6437
  drainTimeout = setTimeout(() => {
6793
6438
  if (settled) return;
6794
6439
  if (typeof socket.terminate !== "function") {
6795
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6440
+ failClose();
6796
6441
  return;
6797
6442
  }
6798
6443
  params.runtime.error?.(danger(`discord: startup restart waiting on a stale gateway socket for ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms; forcing terminate before reconnect`));
6799
6444
  try {
6800
6445
  socket.terminate();
6801
6446
  } catch {
6802
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6447
+ failClose();
6803
6448
  return;
6804
6449
  }
6805
- terminateCloseTimeout = setTimeout(() => {
6806
- finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
6807
- }, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
6450
+ terminateCloseTimeout = setTimeout(failClose, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
6808
6451
  terminateCloseTimeout.unref?.();
6809
6452
  }, DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS);
6810
6453
  drainTimeout.unref?.();
@@ -6845,9 +6488,6 @@ function createGatewayStatusObserver(params) {
6845
6488
  }
6846
6489
  queuedForceStopError = err;
6847
6490
  };
6848
- const pushConnectedStatus = (at) => {
6849
- params.pushStatus(createDiscordReadyStatusPatch(at));
6850
- };
6851
6491
  const startReadyWatch = () => {
6852
6492
  clearReadyWatch();
6853
6493
  const pollConnected = () => {
@@ -6857,7 +6497,7 @@ function createGatewayStatusObserver(params) {
6857
6497
  }
6858
6498
  if (!params.gateway?.isConnected) return;
6859
6499
  clearReadyWatch();
6860
- pushConnectedStatus(Date.now());
6500
+ params.pushStatus(createDiscordReadyStatusPatch(Date.now()));
6861
6501
  };
6862
6502
  pollConnected();
6863
6503
  if (!readyTimeoutId) {
@@ -7007,8 +6647,8 @@ async function runDiscordGatewayLifecycle(params) {
7007
6647
  const pushStatus = (patch) => {
7008
6648
  params.statusSink?.(patch);
7009
6649
  };
7010
- const gatewayReadyTimeoutMs = resolveDiscordGatewayReadyTimeoutMs({ env: process.env });
7011
- const gatewayRuntimeReadyTimeoutMs = resolveDiscordGatewayRuntimeReadyTimeoutMs({ env: process.env });
6650
+ const gatewayReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
6651
+ const gatewayRuntimeReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
7012
6652
  const statusObserver = createGatewayStatusObserver({
7013
6653
  gateway,
7014
6654
  abortSignal: params.abortSignal,
@@ -7072,23 +6712,26 @@ async function runDiscordGatewayLifecycle(params) {
7072
6712
  } catch (err) {
7073
6713
  if (!sawDisallowedIntents && !params.isDisallowedIntentsError(err)) throw err;
7074
6714
  } finally {
7075
- lifecycleStopping = true;
7076
- params.gatewaySupervisor.detachLifecycle();
7077
- unregisterGateway(params.accountId);
7078
- stopGatewayLogging();
7079
- statusObserver.dispose();
7080
- gatewayEmitter?.removeListener("debug", statusObserver.onGatewayDebug);
7081
- gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
7082
- if (params.voiceManager) {
7083
- await params.voiceManager.destroy();
7084
- setDiscordTranscriptsVoiceManager({
7085
- accountId: params.accountId,
7086
- manager: null,
7087
- expectedManager: params.voiceManager
7088
- });
7089
- params.voiceManagerRef.current = null;
6715
+ try {
6716
+ lifecycleStopping = true;
6717
+ params.gatewaySupervisor.detachLifecycle();
6718
+ unregisterGateway(params.accountId);
6719
+ stopGatewayLogging();
6720
+ statusObserver.dispose();
6721
+ gatewayEmitter?.removeListener("debug", statusObserver.onGatewayDebug);
6722
+ gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
6723
+ if (params.voiceManager) {
6724
+ await params.voiceManager.destroy();
6725
+ setDiscordTranscriptsVoiceManager({
6726
+ accountId: params.accountId,
6727
+ manager: null,
6728
+ expectedManager: params.voiceManager
6729
+ });
6730
+ params.voiceManagerRef.current = null;
6731
+ }
6732
+ } finally {
6733
+ await params.threadBindings.stop();
7090
6734
  }
7091
- params.threadBindings.stop();
7092
6735
  }
7093
6736
  }
7094
6737
  //#endregion
@@ -7096,7 +6739,7 @@ async function runDiscordGatewayLifecycle(params) {
7096
6739
  let discordVoiceRuntimePromise;
7097
6740
  let discordProviderSessionRuntimePromise;
7098
6741
  async function loadDiscordVoiceRuntime() {
7099
- const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-DHVQ2mFz.mjs").then((n) => n.t);
6742
+ const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-B46rcwrG.mjs").then((n) => n.t);
7100
6743
  discordVoiceRuntimePromise = promise;
7101
6744
  try {
7102
6745
  return await promise;
@@ -7106,7 +6749,7 @@ async function loadDiscordVoiceRuntime() {
7106
6749
  }
7107
6750
  }
7108
6751
  async function loadDiscordProviderSessionRuntime() {
7109
- const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BW7QrF5C.mjs");
6752
+ const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BYlTBFD2.mjs");
7110
6753
  discordProviderSessionRuntimePromise = promise;
7111
6754
  try {
7112
6755
  return await promise;
@@ -7210,22 +6853,49 @@ async function probeDiscordAcpBindingHealth(params) {
7210
6853
  //#endregion
7211
6854
  //#region extensions/discord/src/monitor/provider.cleanup.ts
7212
6855
  async function cleanupDiscordProviderStartup(params) {
7213
- const listenersStopped = params.stopMonitorListeners?.();
7214
6856
  try {
7215
- await params.deactivateMessageHandler?.();
6857
+ const listenersStopped = params.stopMonitorListeners?.();
6858
+ try {
6859
+ await params.deactivateMessageHandler?.();
6860
+ } finally {
6861
+ await listenersStopped;
6862
+ }
6863
+ params.autoPresenceController?.stop();
6864
+ params.setStatus?.({ connected: false });
6865
+ if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
6866
+ if (!params.lifecycleStarted) try {
6867
+ params.lifecycleGateway?.disconnect();
6868
+ } catch (err) {
6869
+ params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
6870
+ }
6871
+ params.gatewaySupervisor?.dispose();
7216
6872
  } finally {
7217
- await listenersStopped;
7218
- }
7219
- params.autoPresenceController?.stop();
7220
- params.setStatus?.({ connected: false });
7221
- if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
7222
- if (!params.lifecycleStarted) try {
7223
- params.lifecycleGateway?.disconnect();
7224
- } catch (err) {
7225
- params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
6873
+ if (!params.lifecycleStarted) await params.threadBindings.stop();
7226
6874
  }
7227
- params.gatewaySupervisor?.dispose();
7228
- if (!params.lifecycleStarted) params.threadBindings.stop();
6875
+ }
6876
+ //#endregion
6877
+ //#region extensions/discord/src/voice/session.ts
6878
+ const MIN_SEGMENT_SECONDS = .35;
6879
+ const CAPTURE_FINALIZE_GRACE_MS = 2e3;
6880
+ const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
6881
+ const VOICE_RECONNECT_GRACE_MS = 15e3;
6882
+ function resolveVoiceTimeoutMs(value, fallbackMs) {
6883
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
6884
+ return Math.floor(value);
6885
+ }
6886
+ function resolveDiscordVoiceMode(voice) {
6887
+ const mode = voice?.mode;
6888
+ if (mode === "stt-tts" || mode === "bidi") return mode;
6889
+ return "agent-proxy";
6890
+ }
6891
+ function isDiscordRealtimeVoiceMode(mode) {
6892
+ return mode === "agent-proxy" || mode === "bidi";
6893
+ }
6894
+ function logVoiceVerbose(message) {
6895
+ logVerbose(`discord voice: ${message}`);
6896
+ }
6897
+ function isVoiceChannel(type) {
6898
+ return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
7229
6899
  }
7230
6900
  //#endregion
7231
6901
  //#region extensions/discord/src/voice/command.ts
@@ -7302,37 +6972,6 @@ async function authorizeVoiceCommand(interaction, params, options) {
7302
6972
  guildId: interaction.guild.id
7303
6973
  };
7304
6974
  }
7305
- async function resolveVoiceCommandRuntimeContext(interaction, params) {
7306
- const guildId = interaction.guild?.id;
7307
- if (!guildId) {
7308
- await interaction.reply({
7309
- content: "Unable to resolve guild for this command.",
7310
- ephemeral: true
7311
- });
7312
- return null;
7313
- }
7314
- const manager = params.getManager();
7315
- if (!manager) {
7316
- await interaction.reply({
7317
- content: "Voice manager is not available yet.",
7318
- ephemeral: true
7319
- });
7320
- return null;
7321
- }
7322
- return {
7323
- guildId,
7324
- manager
7325
- };
7326
- }
7327
- async function ensureVoiceCommandAccess(params) {
7328
- const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
7329
- if (access.ok) return true;
7330
- await params.interaction.reply({
7331
- content: access.message ?? "Not authorized.",
7332
- ephemeral: true
7333
- });
7334
- return false;
7335
- }
7336
6975
  function createDiscordVoiceCommand(startupParams) {
7337
6976
  const params = {
7338
6977
  ...startupParams,
@@ -7348,7 +6987,6 @@ function createDiscordVoiceCommand(startupParams) {
7348
6987
  }
7349
6988
  })
7350
6989
  };
7351
- const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
7352
6990
  class JoinCommand extends Command {
7353
6991
  constructor(..._args) {
7354
6992
  super(..._args);
@@ -7384,7 +7022,7 @@ function createDiscordVoiceCommand(startupParams) {
7384
7022
  });
7385
7023
  return;
7386
7024
  }
7387
- if (!isVoiceChannelType(channel.type)) {
7025
+ if (!isVoiceChannel(channel.type)) {
7388
7026
  await interaction.reply({
7389
7027
  content: "That is not a voice channel.",
7390
7028
  ephemeral: true
@@ -7417,48 +7055,49 @@ function createDiscordVoiceCommand(startupParams) {
7417
7055
  });
7418
7056
  }
7419
7057
  }
7420
- class LeaveCommand extends Command {
7421
- constructor(..._args2) {
7422
- super(..._args2);
7423
- this.name = "leave";
7424
- this.description = "Leave the current voice channel";
7425
- this.defer = true;
7426
- this.ephemeral = params.ephemeralDefault;
7427
- }
7428
- async run(interaction) {
7429
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
7430
- if (!runtimeContext) return;
7431
- const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
7432
- if (!await ensureVoiceCommandAccess({
7433
- interaction,
7434
- context: params,
7435
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
7436
- })) return;
7437
- const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
7438
- await interaction.reply({
7439
- content: result.message,
7440
- ephemeral: true
7441
- });
7442
- }
7443
- }
7444
- class StatusCommand extends Command {
7445
- constructor(..._args3) {
7446
- super(..._args3);
7447
- this.name = "status";
7448
- this.description = "Show active voice sessions";
7058
+ class SessionCommand extends Command {
7059
+ constructor(name) {
7060
+ super();
7061
+ this.name = name;
7449
7062
  this.defer = true;
7450
7063
  this.ephemeral = params.ephemeralDefault;
7064
+ this.description = name === "leave" ? "Leave the current voice channel" : "Show active voice sessions";
7451
7065
  }
7452
7066
  async run(interaction) {
7453
- const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
7454
- if (!runtimeContext) return;
7455
- const sessions = runtimeContext.manager.status().filter((entry) => entry.guildId === runtimeContext.guildId);
7067
+ const guildId = interaction.guild?.id;
7068
+ if (!guildId) {
7069
+ await interaction.reply({
7070
+ content: "Unable to resolve guild for this command.",
7071
+ ephemeral: true
7072
+ });
7073
+ return;
7074
+ }
7075
+ const manager = params.getManager();
7076
+ if (!manager) {
7077
+ await interaction.reply({
7078
+ content: "Voice manager is not available yet.",
7079
+ ephemeral: true
7080
+ });
7081
+ return;
7082
+ }
7083
+ const sessions = manager.status().filter((entry) => entry.guildId === guildId);
7456
7084
  const sessionChannelId = sessions[0]?.channelId;
7457
- if (!await ensureVoiceCommandAccess({
7458
- interaction,
7459
- context: params,
7460
- channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
7461
- })) return;
7085
+ const access = await authorizeVoiceCommand(interaction, params, { channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0 });
7086
+ if (!access.ok) {
7087
+ await interaction.reply({
7088
+ content: access.message ?? "Not authorized.",
7089
+ ephemeral: true
7090
+ });
7091
+ return;
7092
+ }
7093
+ if (this.name === "leave") {
7094
+ const result = await manager.leave({ guildId });
7095
+ await interaction.reply({
7096
+ content: result.message,
7097
+ ephemeral: true
7098
+ });
7099
+ return;
7100
+ }
7462
7101
  if (sessions.length === 0) {
7463
7102
  await interaction.reply({
7464
7103
  content: "No active voice sessions.",
@@ -7474,21 +7113,18 @@ function createDiscordVoiceCommand(startupParams) {
7474
7113
  }
7475
7114
  }
7476
7115
  return new class extends CommandWithSubcommands {
7477
- constructor(..._args4) {
7478
- super(..._args4);
7116
+ constructor(..._args2) {
7117
+ super(..._args2);
7479
7118
  this.name = DISCORD_VOICE_COMMAND_SPEC.name;
7480
7119
  this.description = DISCORD_VOICE_COMMAND_SPEC.description;
7481
7120
  this.subcommands = [
7482
7121
  new JoinCommand(),
7483
- new LeaveCommand(),
7484
- new StatusCommand()
7122
+ new SessionCommand("leave"),
7123
+ new SessionCommand("status")
7485
7124
  ];
7486
7125
  }
7487
7126
  }();
7488
7127
  }
7489
- function isVoiceChannelType(type) {
7490
- return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
7491
- }
7492
7128
  //#endregion
7493
7129
  //#region extensions/discord/src/monitor/provider.commands.ts
7494
7130
  const loadPluginCommandRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/plugin-command-runtime"));
@@ -7570,7 +7206,6 @@ function attachDiscordDeployRestContext(err, context) {
7570
7206
  if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) deployErr.deployTimeoutMs = context.timeoutMs;
7571
7207
  }
7572
7208
  function stringifyDiscordDeployField(value) {
7573
- if (typeof value === "string") return JSON.stringify(value);
7574
7209
  try {
7575
7210
  return JSON.stringify(value);
7576
7211
  } catch {
@@ -7588,8 +7223,7 @@ function readDiscordDeployRejectedFields(value) {
7588
7223
  function resolveDiscordRejectedDeployEntriesSource(rawBody) {
7589
7224
  if (!rawBody || typeof rawBody !== "object") return null;
7590
7225
  const payload = rawBody;
7591
- const source = (payload.errors && typeof payload.errors === "object" ? payload.errors : void 0) ?? rawBody;
7592
- return source && typeof source === "object" ? source : null;
7226
+ return (payload.errors && typeof payload.errors === "object" ? payload.errors : void 0) ?? rawBody;
7593
7227
  }
7594
7228
  function readDiscordDeployObjectField(value, field) {
7595
7229
  return value && typeof value === "object" && field in value ? value[field] : void 0;
@@ -7604,9 +7238,7 @@ function formatDiscordDeployRestOperation(err) {
7604
7238
  const method = typeof err.deployRestMethod === "string" && err.deployRestMethod.trim().length > 0 ? err.deployRestMethod.toUpperCase() : void 0;
7605
7239
  const path = typeof err.deployRestPath === "string" && err.deployRestPath.trim().length > 0 ? err.deployRestPath : void 0;
7606
7240
  if (method && path) return `${method} ${path}`;
7607
- if (method) return method;
7608
- if (path) return path;
7609
- return "request";
7241
+ return method ?? path ?? "request";
7610
7242
  }
7611
7243
  function formatDiscordDeployErrorMessage(err) {
7612
7244
  if (!isAbortLikeError(err)) return formatErrorMessage(err);
@@ -7642,19 +7274,19 @@ function formatDiscordDeployRateLimitDetails(err) {
7642
7274
  const rateLimit = resolveDiscordDeployRateLimitDetails(err);
7643
7275
  if (!rateLimit) return "";
7644
7276
  const details = [];
7645
- if (typeof rateLimit.status === "number") details.push(`status=${rateLimit.status}`);
7646
- if (typeof rateLimit.retryAfterMs === "number") details.push(`retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7277
+ if (rateLimit.status !== void 0) details.push(`status=${rateLimit.status}`);
7278
+ if (rateLimit.retryAfterMs !== void 0) details.push(`retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7647
7279
  if (rateLimit.scope) details.push(`scope=${rateLimit.scope}`);
7648
- if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") details.push(`code=${rateLimit.discordCode}`);
7280
+ if (rateLimit.discordCode !== void 0) details.push(`code=${rateLimit.discordCode}`);
7649
7281
  return details.length > 0 ? ` (${details.join(", ")})` : "";
7650
7282
  }
7651
7283
  function formatDiscordDeployRateLimitWarning(err, accountId) {
7652
7284
  const rateLimit = resolveDiscordDeployRateLimitDetails(err);
7653
7285
  if (!rateLimit) return;
7654
7286
  const parts = [`[${accountId}] slash command deploy rate limited`];
7655
- if (typeof rateLimit.retryAfterMs === "number") parts.push(`retry after ${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7287
+ if (rateLimit.retryAfterMs !== void 0) parts.push(`retry after ${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
7656
7288
  if (rateLimit.scope) parts.push(`scope=${rateLimit.scope}`);
7657
- if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") parts.push(`code=${rateLimit.discordCode}`);
7289
+ if (rateLimit.discordCode !== void 0) parts.push(`code=${rateLimit.discordCode}`);
7658
7290
  return `${parts.join("; ")}. Existing slash commands stay active. Message send/receive is unaffected.`;
7659
7291
  }
7660
7292
  function formatDiscordRejectedDeployEntries(params) {
@@ -7683,10 +7315,7 @@ function formatDiscordDeployErrorDetails(err) {
7683
7315
  if (!err || typeof err !== "object") return "";
7684
7316
  const rateLimitDetails = formatDiscordDeployRateLimitDetails(err);
7685
7317
  if (rateLimitDetails) return rateLimitDetails;
7686
- const status = err.status;
7687
- const discordCode = err.discordCode;
7688
- const rawBody = err.rawBody;
7689
- const requestBody = err.deployRequestBody;
7318
+ const { status, discordCode, rawBody, deployRequestBody: requestBody } = err;
7690
7319
  const details = [];
7691
7320
  if (typeof status === "number") details.push(`status=${status}`);
7692
7321
  if (typeof discordCode === "number" || typeof discordCode === "string") details.push(`code=${discordCode}`);
@@ -7727,7 +7356,7 @@ function formatDiscordStartupGatewayState(gateway) {
7727
7356
  const reconnectAttempts = gateway.reconnectAttempts;
7728
7357
  return `gatewayConnected=${gateway.isConnected ? "true" : "false"} reconnectAttempts=${typeof reconnectAttempts === "number" ? reconnectAttempts : "na"}`;
7729
7358
  }
7730
- function logDiscordStartupPhase$1(params) {
7359
+ function logDiscordStartupPhase(params) {
7731
7360
  if (!(params.isVerbose ?? isVerbose)()) return;
7732
7361
  const elapsedMs = Math.max(0, Date.now() - params.startAt);
7733
7362
  const suffix = [params.details, formatDiscordStartupGatewayState(params.gateway)].filter((value) => Boolean(value)).join(" ");
@@ -7835,7 +7464,7 @@ async function deployDiscordCommands(params) {
7835
7464
  }
7836
7465
  function runDiscordCommandDeployInBackground(params) {
7837
7466
  if (!params.enabled) return;
7838
- logDiscordStartupPhase$1({
7467
+ logDiscordStartupPhase({
7839
7468
  runtime: params.runtime,
7840
7469
  accountId: params.accountId,
7841
7470
  phase: "deploy-commands:scheduled",
@@ -7844,7 +7473,7 @@ function runDiscordCommandDeployInBackground(params) {
7844
7473
  isVerbose: params.isVerbose
7845
7474
  });
7846
7475
  deployDiscordCommands(params).then(() => {
7847
- logDiscordStartupPhase$1({
7476
+ logDiscordStartupPhase({
7848
7477
  runtime: params.runtime,
7849
7478
  accountId: params.accountId,
7850
7479
  phase: "deploy-commands:done",
@@ -7921,7 +7550,7 @@ var DiscordActivityButton = class extends Button {
7921
7550
  };
7922
7551
  function createDiscordActivityButton(ctx, applicationId, deps = {}) {
7923
7552
  const runtime = getDiscordActivitiesRuntime();
7924
- if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
7553
+ if (!runtime) return null;
7925
7554
  if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
7926
7555
  if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
7927
7556
  return new DiscordActivityButton(ctx, {
@@ -8036,6 +7665,104 @@ async function resolveComponentInteractionContext(params) {
8036
7665
  };
8037
7666
  }
8038
7667
  //#endregion
7668
+ //#region extensions/discord/src/monitor/agent-components-data.ts
7669
+ function readParsedComponentId(data) {
7670
+ if (!data || typeof data !== "object") return;
7671
+ return "cid" in data ? data.cid : data.componentId;
7672
+ }
7673
+ function normalizeComponentId(value) {
7674
+ if (typeof value === "string") return normalizeOptionalString(value);
7675
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
7676
+ }
7677
+ function mapOptionLabels(options, values) {
7678
+ if (!options || options.length === 0) return values;
7679
+ const map = new Map(options.map((option) => [option.value, option.label]));
7680
+ return values.map((value) => map.get(value) ?? value);
7681
+ }
7682
+ function parseAgentComponentData(data) {
7683
+ const raw = readParsedComponentId(data);
7684
+ const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
7685
+ if (!componentId) return null;
7686
+ return { componentId };
7687
+ }
7688
+ function parseDiscordComponentData(data, customId) {
7689
+ if (!data || typeof data !== "object") return null;
7690
+ const rawComponentId = readParsedComponentId(data);
7691
+ const rawModalId = "mid" in data ? data.mid : data.modalId;
7692
+ let componentId = normalizeComponentId(rawComponentId);
7693
+ let modalId = normalizeComponentId(rawModalId);
7694
+ if (!componentId && customId) {
7695
+ const parsed = parseDiscordComponentCustomId(customId);
7696
+ if (parsed) {
7697
+ componentId = parsed.componentId;
7698
+ modalId = parsed.modalId;
7699
+ }
7700
+ }
7701
+ if (!componentId) return null;
7702
+ return {
7703
+ componentId,
7704
+ modalId
7705
+ };
7706
+ }
7707
+ function parseDiscordModalId(data, customId) {
7708
+ if (data && typeof data === "object") {
7709
+ const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
7710
+ if (modalId) return modalId;
7711
+ }
7712
+ if (customId) return parseDiscordModalCustomId(customId);
7713
+ return null;
7714
+ }
7715
+ function resolveInteractionCustomId(interaction) {
7716
+ if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
7717
+ if (!("data" in interaction.rawData)) return;
7718
+ return normalizeOptionalString(interaction.rawData.data?.custom_id);
7719
+ }
7720
+ function mapSelectValues(entry, values) {
7721
+ switch (entry.selectType) {
7722
+ case "string": return mapOptionLabels(entry.options, values);
7723
+ case "user":
7724
+ case "role":
7725
+ case "mentionable":
7726
+ case "channel": return values.map((value) => `${entry.selectType}:${value}`);
7727
+ default: return values;
7728
+ }
7729
+ }
7730
+ function resolveModalFieldValues(field, interaction) {
7731
+ const fields = interaction.fields;
7732
+ const required = field.required === true;
7733
+ try {
7734
+ switch (field.type) {
7735
+ case "text": {
7736
+ const value = fields.getText(field.id, required);
7737
+ return value ? [value] : [];
7738
+ }
7739
+ case "select":
7740
+ case "checkbox":
7741
+ case "radio": return mapOptionLabels(field.options, fields.getStringSelect(field.id, required));
7742
+ case "role-select": try {
7743
+ return fields.getRoleSelect(field.id, required).map((role) => role.name ?? role.id);
7744
+ } catch {
7745
+ return fields.getStringSelect(field.id, required);
7746
+ }
7747
+ case "user-select": return fields.getUserSelect(field.id, required).map((user) => formatDiscordUserTag(user));
7748
+ default: return [];
7749
+ }
7750
+ } catch (err) {
7751
+ logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
7752
+ return [];
7753
+ }
7754
+ }
7755
+ function formatModalSubmissionText(entry, interaction) {
7756
+ const lines = [`Form "${entry.title}" submitted.`];
7757
+ for (const field of entry.fields) {
7758
+ const values = resolveModalFieldValues(field, interaction);
7759
+ if (values.length === 0) continue;
7760
+ lines.push(`- ${field.label}: ${values.join(", ")}`);
7761
+ }
7762
+ if (lines.length === 1) lines.push("- (no values)");
7763
+ return lines.join("\n");
7764
+ }
7765
+ //#endregion
8039
7766
  //#region extensions/discord/src/monitor/agent-components-live-policy.ts
8040
7767
  async function resolveAgentComponentPolicyContext(params) {
8041
7768
  if (!params.ctx.readPolicy) return params.ctx;
@@ -8108,7 +7835,7 @@ async function ensureDmComponentAuthorized(params) {
8108
7835
  channel: "discord",
8109
7836
  accountId: ctx.accountId,
8110
7837
  upsertPairingRequest: async ({ id, meta }) => {
8111
- return await upsertChannelPairingRequest$1({
7838
+ return await upsertChannelPairingRequest({
8112
7839
  channel: "discord",
8113
7840
  id,
8114
7841
  accountId: ctx.accountId,
@@ -8258,7 +7985,7 @@ async function ensureGuildComponentMemberAllowed(params) {
8258
7985
  return false;
8259
7986
  }
8260
7987
  async function ensureComponentUserAllowed(params) {
8261
- const allowList = normalizeDiscordAllowList(params.entry.allowedUsers, [
7988
+ const allowList = normalizeDiscordAllowList(params.allowedUsers, [
8262
7989
  "discord:",
8263
7990
  "user:",
8264
7991
  "pk:"
@@ -8369,6 +8096,13 @@ async function resolveAuthorizedComponentInteraction(params) {
8369
8096
  });
8370
8097
  return null;
8371
8098
  }
8099
+ if (params.allowedUsers !== void 0 && !await ensureComponentUserAllowed({
8100
+ ...params,
8101
+ allowedUsers: params.allowedUsers,
8102
+ user,
8103
+ replyOpts,
8104
+ allowNameMatching
8105
+ })) return null;
8372
8106
  return {
8373
8107
  ctx,
8374
8108
  interactionCtx,
@@ -8388,159 +8122,50 @@ async function resolveComponentCommandAuthorized(params) {
8388
8122
  allowFrom: ctx.allowFrom,
8389
8123
  sender: {
8390
8124
  id: interactionCtx.user.id,
8391
- name: interactionCtx.user.username,
8392
- tag: formatDiscordUserTag(interactionCtx.user)
8393
- },
8394
- allowNameMatching: params.allowNameMatching
8395
- });
8396
- const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8397
- channelConfig,
8398
- guildInfo,
8399
- memberRoleIds: interactionCtx.memberRoleIds,
8400
- sender: {
8401
- id: interactionCtx.user.id,
8402
- name: interactionCtx.user.username,
8403
- tag: formatDiscordUserTag(interactionCtx.user)
8404
- },
8405
- allowNameMatching: params.allowNameMatching
8406
- });
8407
- return resolveCommandAuthorizedFromAuthorizers({
8408
- useAccessGroups: true,
8409
- authorizers: [{
8410
- configured: ownerAllowList != null,
8411
- allowed: ownerOk
8412
- }, {
8413
- configured: hasAccessRestrictions,
8414
- allowed: memberAllowed
8415
- }],
8416
- modeWhenAccessGroupsOff: "configured"
8417
- });
8418
- }
8419
- //#endregion
8420
- //#region extensions/discord/src/monitor/agent-components-data.ts
8421
- function readParsedComponentId(data) {
8422
- if (!data || typeof data !== "object") return;
8423
- return "cid" in data ? data.cid : data.componentId;
8424
- }
8425
- function normalizeComponentId(value) {
8426
- if (typeof value === "string") {
8427
- const trimmed = value.trim();
8428
- return trimmed ? trimmed : void 0;
8429
- }
8430
- if (typeof value === "number" && Number.isFinite(value)) return String(value);
8431
- }
8432
- function mapOptionLabels(options, values) {
8433
- if (!options || options.length === 0) return values;
8434
- const map = new Map(options.map((option) => [option.value, option.label]));
8435
- return values.map((value) => map.get(value) ?? value);
8436
- }
8437
- function parseAgentComponentData(data) {
8438
- const raw = readParsedComponentId(data);
8439
- const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
8440
- if (!componentId) return null;
8441
- return { componentId };
8442
- }
8443
- function parseDiscordComponentData(data, customId) {
8444
- if (!data || typeof data !== "object") return null;
8445
- const rawComponentId = readParsedComponentId(data);
8446
- const rawModalId = "mid" in data ? data.mid : data.modalId;
8447
- let componentId = normalizeComponentId(rawComponentId);
8448
- let modalId = normalizeComponentId(rawModalId);
8449
- if (!componentId && customId) {
8450
- const parsed = parseDiscordComponentCustomId(customId);
8451
- if (parsed) {
8452
- componentId = parsed.componentId;
8453
- modalId = parsed.modalId;
8454
- }
8455
- }
8456
- if (!componentId) return null;
8457
- return {
8458
- componentId,
8459
- modalId
8460
- };
8461
- }
8462
- function parseDiscordModalId(data, customId) {
8463
- if (data && typeof data === "object") {
8464
- const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
8465
- if (modalId) return modalId;
8466
- }
8467
- if (customId) return parseDiscordModalCustomId(customId);
8468
- return null;
8469
- }
8470
- function resolveInteractionCustomId(interaction) {
8471
- if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
8472
- if (!("data" in interaction.rawData)) return;
8473
- const customId = interaction.rawData.data?.custom_id;
8474
- if (typeof customId !== "string") return;
8475
- const trimmed = customId.trim();
8476
- return trimmed ? trimmed : void 0;
8477
- }
8478
- function mapSelectValues(entry, values) {
8479
- if (entry.selectType === "string") return mapOptionLabels(entry.options, values);
8480
- if (entry.selectType === "user") return values.map((value) => `user:${value}`);
8481
- if (entry.selectType === "role") return values.map((value) => `role:${value}`);
8482
- if (entry.selectType === "mentionable") return values.map((value) => `mentionable:${value}`);
8483
- if (entry.selectType === "channel") return values.map((value) => `channel:${value}`);
8484
- return values;
8485
- }
8486
- function resolveModalFieldValues(field, interaction) {
8487
- const fields = interaction.fields;
8488
- const optionLabels = field.options?.map((option) => ({
8489
- value: option.value,
8490
- label: option.label
8491
- }));
8492
- const required = field.required === true;
8493
- try {
8494
- switch (field.type) {
8495
- case "text": {
8496
- const value = required ? fields.getText(field.id, true) : fields.getText(field.id);
8497
- return value ? [value] : [];
8498
- }
8499
- case "select":
8500
- case "checkbox":
8501
- case "radio": return mapOptionLabels(optionLabels, required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? []);
8502
- case "role-select": try {
8503
- return (required ? fields.getRoleSelect(field.id, true) : fields.getRoleSelect(field.id) ?? []).map((role) => role.name ?? role.id);
8504
- } catch {
8505
- return required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? [];
8506
- }
8507
- case "user-select": return (required ? fields.getUserSelect(field.id, true) : fields.getUserSelect(field.id) ?? []).map((user) => formatDiscordUserTag(user));
8508
- default: return [];
8509
- }
8510
- } catch (err) {
8511
- logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
8512
- return [];
8513
- }
8514
- }
8515
- function formatModalSubmissionText(entry, interaction) {
8516
- const lines = [`Form "${entry.title}" submitted.`];
8517
- for (const field of entry.fields) {
8518
- const values = resolveModalFieldValues(field, interaction);
8519
- if (values.length === 0) continue;
8520
- lines.push(`- ${field.label}: ${values.join(", ")}`);
8521
- }
8522
- if (lines.length === 1) lines.push("- (no values)");
8523
- return lines.join("\n");
8125
+ name: interactionCtx.user.username,
8126
+ tag: formatDiscordUserTag(interactionCtx.user)
8127
+ },
8128
+ allowNameMatching: params.allowNameMatching
8129
+ });
8130
+ const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
8131
+ channelConfig,
8132
+ guildInfo,
8133
+ memberRoleIds: interactionCtx.memberRoleIds,
8134
+ sender: {
8135
+ id: interactionCtx.user.id,
8136
+ name: interactionCtx.user.username,
8137
+ tag: formatDiscordUserTag(interactionCtx.user)
8138
+ },
8139
+ allowNameMatching: params.allowNameMatching
8140
+ });
8141
+ return resolveCommandAuthorizedFromAuthorizers({
8142
+ useAccessGroups: true,
8143
+ authorizers: [{
8144
+ configured: ownerAllowList != null,
8145
+ allowed: ownerOk
8146
+ }, {
8147
+ configured: hasAccessRestrictions,
8148
+ allowed: memberAllowed
8149
+ }],
8150
+ modeWhenAccessGroupsOff: "configured"
8151
+ });
8524
8152
  }
8525
8153
  //#endregion
8526
- //#region extensions/discord/src/monitor/agent-components-helpers.ts
8527
- const AGENT_BUTTON_KEY = "agent";
8528
- const AGENT_SELECT_KEY = "agentsel";
8529
- //#endregion
8530
8154
  //#region extensions/discord/src/monitor/reply-context.ts
8531
8155
  function resolveReplyContext(message, resolveDiscordMessageText) {
8532
- const referenced = message.referencedMessage;
8533
- if (!referenced?.author) return null;
8156
+ const id = resolveDiscordReferencedReplyMessageId(message);
8157
+ if (!id) return null;
8158
+ const referenced = resolveDiscordReferencedReplyMessage(message);
8159
+ const channelId = message.messageReference?.channel_id ?? message.channelId;
8160
+ if (!referenced?.author || referenced.id !== id) return null;
8534
8161
  const referencedText = resolveDiscordMessageText(referenced, { includeForwarded: true });
8535
- const hasVisibleMedia = referenced.attachments.length > 0 || !referencedText && resolveDiscordMessageStickers(referenced).length > 0;
8536
- if (!referencedText && !hasVisibleMedia) return null;
8537
8162
  const sender = resolveDiscordSenderIdentity({
8538
8163
  author: referenced.author,
8539
8164
  pluralkitInfo: null
8540
8165
  });
8541
8166
  return {
8542
- id: referenced.id,
8543
- channelId: referenced.channelId,
8167
+ id,
8168
+ channelId,
8544
8169
  sender: sender.tag ?? sender.label ?? "unknown",
8545
8170
  senderId: referenced.author.id,
8546
8171
  senderName: referenced.author.username ?? void 0,
@@ -8624,14 +8249,10 @@ function formatDiscordReplySkip(params) {
8624
8249
  const context = [`target=${params.target}`, params.sessionKey ? `session=${params.sessionKey}` : void 0].filter(Boolean).join(" ");
8625
8250
  return `discord ${params.kind} reply skipped (${params.reason}): ${context}`;
8626
8251
  }
8627
- function resolveTargetChannelId(target) {
8628
- if (!target.startsWith("channel:")) return;
8629
- return target.slice(8).trim() || void 0;
8630
- }
8631
8252
  function resolveBoundThreadBinding(params) {
8632
8253
  const sessionKey = params.sessionKey?.trim();
8633
8254
  if (!params.threadBindings || !sessionKey) return;
8634
- const targetChannelId = resolveTargetChannelId(params.target);
8255
+ const targetChannelId = params.target.startsWith("channel:") ? params.target.slice(8).trim() : void 0;
8635
8256
  if (!targetChannelId) return;
8636
8257
  return params.threadBindings.listBySessionKey(sessionKey).find((entry) => entry.threadId === targetChannelId);
8637
8258
  }
@@ -8662,27 +8283,6 @@ function createDiscordDeliveryDeps(params) {
8662
8283
  })
8663
8284
  };
8664
8285
  }
8665
- function resolveDiscordDeliveryOptions(params) {
8666
- const binding = resolveBoundThreadBinding({
8667
- threadBindings: params.threadBindings,
8668
- sessionKey: params.sessionKey,
8669
- target: params.target
8670
- });
8671
- return {
8672
- to: binding ? `channel:${binding.channelId}` : params.target,
8673
- threadId: binding?.threadId,
8674
- agentId: binding?.agentId,
8675
- identity: resolveBindingIdentity(params.cfg, binding),
8676
- mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
8677
- replyToMode: params.replyToMode ?? "all",
8678
- formatting: {
8679
- textLimit: params.textLimit,
8680
- maxLinesPerMessage: params.maxLinesPerMessage,
8681
- tableMode: params.tableMode,
8682
- chunkMode: params.chunkMode
8683
- }
8684
- };
8685
- }
8686
8286
  function formatDiscordReasoningPayload(payload) {
8687
8287
  if (payload.isReasoning !== true) return payload;
8688
8288
  const text = typeof payload.text === "string" ? payload.text.trim() : "";
@@ -8694,8 +8294,8 @@ function formatDiscordReasoningPayload(payload) {
8694
8294
  return nextPayload;
8695
8295
  }
8696
8296
  async function deliverDiscordReply(params) {
8697
- params.runtime;
8698
- const delivery = resolveDiscordDeliveryOptions(params);
8297
+ const binding = resolveBoundThreadBinding(params);
8298
+ const to = binding ? `channel:${binding.channelId}` : params.target;
8699
8299
  const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies, { kind: params.kind }).map(formatDiscordReasoningPayload).map((payload) => params.bindPendingFinalDelivery?.(payload) ?? payload);
8700
8300
  if (payloads.length === 0) return {
8701
8301
  visibleReplySent: false,
@@ -8704,14 +8304,19 @@ async function deliverDiscordReply(params) {
8704
8304
  const send = await sendDurableMessageBatch({
8705
8305
  cfg: params.cfg,
8706
8306
  channel: "discord",
8707
- to: delivery.to,
8307
+ to,
8708
8308
  accountId: params.accountId,
8709
8309
  payloads,
8710
8310
  replyToId: normalizeOptionalString(params.replyToId),
8711
- replyToMode: delivery.replyToMode,
8712
- formatting: delivery.formatting,
8713
- threadId: delivery.threadId,
8714
- identity: delivery.identity,
8311
+ replyToMode: params.replyToMode ?? "all",
8312
+ formatting: {
8313
+ textLimit: params.textLimit,
8314
+ maxLinesPerMessage: params.maxLinesPerMessage,
8315
+ tableMode: params.tableMode,
8316
+ chunkMode: params.chunkMode
8317
+ },
8318
+ threadId: binding?.threadId,
8319
+ identity: resolveBindingIdentity(params.cfg, binding),
8715
8320
  onPlatformSendDispatch: params.onPlatformSendDispatch,
8716
8321
  assertDirectAdapterHandoff: params.assertPlatformSendAuthorized,
8717
8322
  deps: createDiscordDeliveryDeps({
@@ -8720,11 +8325,11 @@ async function deliverDiscordReply(params) {
8720
8325
  rest: params.rest,
8721
8326
  allowedMentions: params.allowedMentions
8722
8327
  }),
8723
- mediaAccess: delivery.mediaAccess,
8328
+ mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
8724
8329
  session: buildOutboundSessionContext({
8725
8330
  cfg: params.cfg,
8726
8331
  sessionKey: params.sessionKey,
8727
- agentId: delivery.agentId,
8332
+ agentId: binding?.agentId,
8728
8333
  requesterAccountId: params.accountId
8729
8334
  })
8730
8335
  });
@@ -8740,7 +8345,7 @@ async function deliverDiscordReply(params) {
8740
8345
  }
8741
8346
  };
8742
8347
  }
8743
- if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${delivery.to}`);
8348
+ if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${to}`);
8744
8349
  const deliveryResult = {
8745
8350
  messageIds: listMessageReceiptPlatformIds(send.receipt),
8746
8351
  receipt: send.receipt,
@@ -8751,8 +8356,8 @@ async function deliverDiscordReply(params) {
8751
8356
  }
8752
8357
  //#endregion
8753
8358
  //#region extensions/discord/src/monitor/agent-components.dispatch.ts
8754
- const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.mjs"));
8755
- const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-BKZL5fGj.mjs").then((n) => n.n));
8359
+ const loadReplyRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/reply-runtime"));
8360
+ const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-BiHCzBRu.mjs").then((n) => n.n));
8756
8361
  function buildDiscordComponentConversationLabel(params) {
8757
8362
  if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
8758
8363
  if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
@@ -8767,16 +8372,8 @@ function resolveDiscordComponentChatType(interactionCtx) {
8767
8372
  if (interactionCtx.isGroupDm) return "group";
8768
8373
  return "channel";
8769
8374
  }
8770
- function resolveDiscordComponentOriginatingTo(interactionCtx) {
8771
- return resolveDiscordConversationIdentity({
8772
- isDirectMessage: interactionCtx.isDirectMessage,
8773
- userId: interactionCtx.userId,
8774
- channelId: interactionCtx.channelId
8775
- });
8776
- }
8777
8375
  async function dispatchDiscordComponentEvent(params) {
8778
8376
  const { ctx, interaction, interactionCtx, channelCtx, guildInfo, eventText } = params;
8779
- const runtime = ctx.runtime ?? createNonExitingRuntime();
8780
8377
  const route = resolveAgentComponentRoute({
8781
8378
  ctx,
8782
8379
  rawGuildId: interactionCtx.rawGuildId,
@@ -8790,7 +8387,6 @@ async function dispatchDiscordComponentEvent(params) {
8790
8387
  const sessionKey = params.routeOverrides?.sessionKey ?? route.sessionKey;
8791
8388
  const agentId = params.routeOverrides?.agentId ?? route.agentId;
8792
8389
  const accountId = params.routeOverrides?.accountId ?? route.accountId;
8793
- const inboundLastRouteSessionKey = sessionKey;
8794
8390
  const fromLabel = buildDiscordComponentConversationLabel({
8795
8391
  interactionCtx,
8796
8392
  interaction,
@@ -8825,7 +8421,7 @@ async function dispatchDiscordComponentEvent(params) {
8825
8421
  isGuild: !interactionCtx.isDirectMessage
8826
8422
  });
8827
8423
  const groupSystemPrompt = buildDiscordGroupSystemPrompt(channelConfig);
8828
- const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist$1({
8424
+ const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
8829
8425
  dmScope: ctx.cfg.session?.dmScope,
8830
8426
  allowFrom: channelConfig?.users ?? guildInfo?.users,
8831
8427
  normalizeEntry: (entry) => {
@@ -8844,12 +8440,17 @@ async function dispatchDiscordComponentEvent(params) {
8844
8440
  guildInfo,
8845
8441
  allowNameMatching
8846
8442
  });
8847
- const storePath = resolveStorePath$1(ctx.cfg.session?.store, { agentId });
8443
+ const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId });
8848
8444
  const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
8849
- const previousTimestamp = readSessionUpdatedAt$1({
8445
+ const previousTimestamp = readSessionUpdatedAt({
8850
8446
  storePath,
8851
8447
  sessionKey
8852
8448
  });
8449
+ const originatingTo = resolveDiscordConversationIdentity({
8450
+ isDirectMessage: interactionCtx.isDirectMessage,
8451
+ userId: interactionCtx.userId,
8452
+ channelId: interactionCtx.channelId
8453
+ });
8853
8454
  const timestamp = Date.now();
8854
8455
  const combinedBody = formatInboundEnvelope({
8855
8456
  channel: "Discord",
@@ -8861,9 +8462,7 @@ async function dispatchDiscordComponentEvent(params) {
8861
8462
  previousTimestamp,
8862
8463
  envelope: envelopeOptions
8863
8464
  });
8864
- const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await (async () => {
8865
- return { ...await loadConversationRuntime$1() };
8866
- })();
8465
+ const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await loadReplyRuntime();
8867
8466
  const ctxPayload = finalizeInboundContext({
8868
8467
  Body: combinedBody,
8869
8468
  BodyForAgent: eventText,
@@ -8905,7 +8504,7 @@ async function dispatchDiscordComponentEvent(params) {
8905
8504
  MessageSid: interaction.rawData.id,
8906
8505
  Timestamp: timestamp,
8907
8506
  OriginatingChannel: "discord",
8908
- OriginatingTo: resolveDiscordComponentOriginatingTo(interactionCtx) ?? `channel:${interactionCtx.channelId}`
8507
+ OriginatingTo: originatingTo ?? `channel:${interactionCtx.channelId}`
8909
8508
  });
8910
8509
  const deliverTarget = `channel:${interactionCtx.channelId}`;
8911
8510
  const typingChannelId = interactionCtx.channelId;
@@ -8951,11 +8550,11 @@ async function dispatchDiscordComponentEvent(params) {
8951
8550
  dispatchReplyFromConfig: ctx.channelRuntime?.reply?.dispatchReplyFromConfig,
8952
8551
  record: {
8953
8552
  updateLastRoute: interactionCtx.isDirectMessage ? {
8954
- sessionKey: inboundLastRouteSessionKey,
8553
+ sessionKey,
8955
8554
  channel: "discord",
8956
- to: resolveDiscordComponentOriginatingTo(interactionCtx) ?? `user:${interactionCtx.userId}`,
8555
+ to: originatingTo ?? `user:${interactionCtx.userId}`,
8957
8556
  accountId,
8958
- mainDmOwnerPin: inboundLastRouteSessionKey === route.mainSessionKey && pinnedMainDmOwner ? {
8557
+ mainDmOwnerPin: sessionKey === route.mainSessionKey && pinnedMainDmOwner ? {
8959
8558
  ownerRecipient: pinnedMainDmOwner,
8960
8559
  senderRecipient: interactionCtx.userId,
8961
8560
  onSkip: ({ ownerRecipient, senderRecipient }) => {
@@ -8977,7 +8576,6 @@ async function dispatchDiscordComponentEvent(params) {
8977
8576
  token,
8978
8577
  accountId,
8979
8578
  rest: interaction.client.rest,
8980
- runtime,
8981
8579
  replyToId,
8982
8580
  replyToMode,
8983
8581
  textLimit,
@@ -9034,7 +8632,7 @@ async function dispatchDiscordPluginInteractiveHandler(params) {
9034
8632
  }
9035
8633
  //#endregion
9036
8634
  //#region extensions/discord/src/monitor/agent-components.plugin-interactive.ts
9037
- const loadConversationRuntime = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.mjs"));
8635
+ const loadConversationRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/conversation-runtime"));
9038
8636
  async function dispatchPluginDiscordInteractiveEvent(params) {
9039
8637
  const normalizedConversationId = params.interactionCtx.rawGuildId || params.channelCtx.channelType === ChannelType.GroupDM ? `channel:${params.interactionCtx.channelId}` : `user:${params.interactionCtx.userId}`;
9040
8638
  let responded = false;
@@ -9089,13 +8687,16 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
9089
8687
  });
9090
8688
  }
9091
8689
  };
8690
+ const acknowledgeSilently = async () => {
8691
+ try {
8692
+ await respond.acknowledge();
8693
+ } catch {}
8694
+ };
9092
8695
  const conversationRuntime = await loadConversationRuntime();
9093
8696
  const pluginBindingApproval = conversationRuntime.parsePluginBindingApprovalCustomId(params.data);
9094
8697
  if (pluginBindingApproval) {
9095
8698
  const { buildPluginBindingResolvedText, resolvePluginConversationBindingApproval } = conversationRuntime;
9096
- try {
9097
- await respond.acknowledge();
9098
- } catch {}
8699
+ await acknowledgeSilently();
9099
8700
  const resolved = await resolvePluginConversationBindingApproval({
9100
8701
  approvalId: pluginBindingApproval.approvalId,
9101
8702
  decision: pluginBindingApproval.decision,
@@ -9140,24 +8741,18 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
9140
8741
  }
9141
8742
  },
9142
8743
  respond,
9143
- onMatched: async () => {
9144
- try {
9145
- await respond.acknowledge();
9146
- } catch {}
9147
- }
8744
+ onMatched: acknowledgeSilently
9148
8745
  });
9149
8746
  if (!dispatched.matched) return "unmatched";
9150
8747
  if (dispatched.handled) {
9151
- if (!responded) try {
9152
- await respond.acknowledge();
9153
- } catch {}
8748
+ if (!responded) await acknowledgeSilently();
9154
8749
  return "handled";
9155
8750
  }
9156
8751
  return "unmatched";
9157
8752
  }
9158
8753
  //#endregion
9159
8754
  //#region extensions/discord/src/monitor/agent-components.handlers.ts
9160
- const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-MqMWUWnE.mjs").then((n) => n.t));
8755
+ const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-Cq1PvIpN.mjs").then((n) => n.t));
9161
8756
  async function handleDiscordComponentEvent(params) {
9162
8757
  const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
9163
8758
  if (!parsed) {
@@ -9180,19 +8775,11 @@ async function handleDiscordComponentEvent(params) {
9180
8775
  label: params.label,
9181
8776
  componentLabel: params.componentLabel,
9182
8777
  unauthorizedReply,
8778
+ allowedUsers: entry.allowedUsers,
9183
8779
  defer: false
9184
8780
  });
9185
8781
  if (!authorized) return;
9186
- const { ctx, interactionCtx, channelCtx, guildInfo, allowNameMatching, commandAuthorized, user, replyOpts } = authorized;
9187
- if (!await ensureComponentUserAllowed({
9188
- entry,
9189
- interaction: params.interaction,
9190
- user,
9191
- replyOpts,
9192
- componentLabel: params.componentLabel,
9193
- unauthorizedReply,
9194
- allowNameMatching
9195
- })) return;
8782
+ const { ctx, interactionCtx, channelCtx, guildInfo, commandAuthorized, replyOpts } = authorized;
9196
8783
  const consumed = await resolveDiscordComponentEntryWithPersistence({
9197
8784
  id: parsed.componentId,
9198
8785
  consume: !entry.reusable
@@ -9228,14 +8815,11 @@ async function handleDiscordComponentEvent(params) {
9228
8815
  label: consumed.label,
9229
8816
  values
9230
8817
  });
9231
- try {
9232
- await params.interaction.reply({
9233
- content: "✓",
9234
- ...replyOpts
9235
- });
9236
- } catch (err) {
9237
- logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
9238
- }
8818
+ await ackComponentInteraction({
8819
+ interaction: params.interaction,
8820
+ replyOpts,
8821
+ label: params.label
8822
+ });
9239
8823
  await dispatchDiscordComponentEvent({
9240
8824
  ctx,
9241
8825
  interaction: params.interaction,
@@ -9272,25 +8856,14 @@ async function handleDiscordModalTrigger(params) {
9272
8856
  await replyUnavailableComponentInteraction(params.interaction, "This form is no longer available.");
9273
8857
  return;
9274
8858
  }
9275
- const unauthorizedReply = "You are not authorized to use this form.";
9276
- const authorized = await resolveAuthorizedComponentInteraction({
8859
+ if (!await resolveAuthorizedComponentInteraction({
9277
8860
  ctx: params.ctx,
9278
8861
  interaction: params.interaction,
9279
8862
  label: params.label,
9280
8863
  componentLabel: "form",
9281
- unauthorizedReply,
8864
+ unauthorizedReply: "You are not authorized to use this form.",
8865
+ allowedUsers: entry.allowedUsers,
9282
8866
  defer: false
9283
- });
9284
- if (!authorized) return;
9285
- const { user, replyOpts, allowNameMatching } = authorized;
9286
- if (!await ensureComponentUserAllowed({
9287
- entry,
9288
- interaction: params.interaction,
9289
- user,
9290
- replyOpts,
9291
- componentLabel: "form",
9292
- unauthorizedReply,
9293
- allowNameMatching
9294
8867
  })) return;
9295
8868
  const consumed = await resolveDiscordComponentEntryWithPersistence({
9296
8869
  id: parsed.componentId,
@@ -9325,11 +8898,11 @@ const discordComponentControlHandlers = {
9325
8898
  var DiscordComponentModal = class extends Modal {
9326
8899
  constructor(ctx) {
9327
8900
  super();
8901
+ this.ctx = ctx;
9328
8902
  this.title = "OpenClaw form";
9329
8903
  this.customId = "__openclaw_discord_component_modal_wildcard__";
9330
8904
  this.components = [];
9331
8905
  this.customIdParser = parseDiscordModalCustomIdForInteraction;
9332
- this.ctx = ctx;
9333
8906
  }
9334
8907
  async run(interaction, data) {
9335
8908
  const modalId = parseDiscordModalId(data, resolveInteractionCustomId(interaction));
@@ -9346,32 +8919,18 @@ var DiscordComponentModal = class extends Modal {
9346
8919
  await replyUnavailableComponentInteraction(interaction, "This form has expired.");
9347
8920
  return;
9348
8921
  }
9349
- const unauthorizedReply = "You are not authorized to use this form.";
9350
8922
  const authorized = await resolveAuthorizedComponentInteraction({
9351
8923
  ctx: this.ctx,
9352
8924
  interaction,
9353
8925
  label: "discord component modal",
9354
8926
  componentLabel: "form",
9355
- unauthorizedReply,
8927
+ unauthorizedReply: "You are not authorized to use this form.",
8928
+ allowedUsers: modalEntry.allowedUsers,
9356
8929
  defer: false
9357
8930
  });
9358
8931
  if (!authorized) return;
9359
8932
  const ctx = authorized.ctx;
9360
- const { interactionCtx, channelCtx, guildInfo, allowNameMatching, commandAuthorized, user, replyOpts } = authorized;
9361
- if (!await ensureComponentUserAllowed({
9362
- entry: {
9363
- id: modalEntry.id,
9364
- kind: "button",
9365
- label: modalEntry.title,
9366
- allowedUsers: modalEntry.allowedUsers
9367
- },
9368
- interaction,
9369
- user,
9370
- replyOpts,
9371
- componentLabel: "form",
9372
- unauthorizedReply,
9373
- allowNameMatching
9374
- })) return;
8933
+ const { interactionCtx, channelCtx, guildInfo, commandAuthorized } = authorized;
9375
8934
  const consumed = await resolveDiscordModalEntryWithPersistence({
9376
8935
  id: modalId,
9377
8936
  consume: !modalEntry.reusable
@@ -9421,6 +8980,8 @@ var DiscordComponentModal = class extends Modal {
9421
8980
  };
9422
8981
  //#endregion
9423
8982
  //#region extensions/discord/src/monitor/agent-components.system-controls.ts
8983
+ const AGENT_BUTTON_KEY = "agent";
8984
+ const AGENT_SELECT_KEY = "agentsel";
9424
8985
  async function runAgentSystemControlInteraction(params) {
9425
8986
  const parsed = parseAgentComponentData(params.data);
9426
8987
  if (!parsed) {
@@ -9468,7 +9029,7 @@ async function runAgentSystemControlInteraction(params) {
9468
9029
  userId
9469
9030
  });
9470
9031
  logDebug(`${params.label}: enqueuing event for channel ${channelId}: ${eventText}`);
9471
- enqueueRoutedSystemEvent$1(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
9032
+ enqueueRoutedSystemEvent(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
9472
9033
  await ackComponentInteraction({
9473
9034
  interaction: params.interaction,
9474
9035
  replyOpts,
@@ -9478,10 +9039,10 @@ async function runAgentSystemControlInteraction(params) {
9478
9039
  var AgentComponentButton = class extends Button {
9479
9040
  constructor(ctx) {
9480
9041
  super();
9042
+ this.ctx = ctx;
9481
9043
  this.label = AGENT_BUTTON_KEY;
9482
9044
  this.customId = `${AGENT_BUTTON_KEY}:seed=1`;
9483
9045
  this.style = ButtonStyle.Primary;
9484
- this.ctx = ctx;
9485
9046
  }
9486
9047
  async run(interaction, data) {
9487
9048
  await runAgentSystemControlInteraction({
@@ -9501,9 +9062,9 @@ var AgentComponentButton = class extends Button {
9501
9062
  var AgentSelectMenu = class extends StringSelectMenu {
9502
9063
  constructor(ctx) {
9503
9064
  super();
9065
+ this.ctx = ctx;
9504
9066
  this.customId = `${AGENT_SELECT_KEY}:seed=1`;
9505
9067
  this.options = [];
9506
- this.ctx = ctx;
9507
9068
  }
9508
9069
  async run(interaction, data) {
9509
9070
  const values = interaction.values ?? [];
@@ -9622,11 +9183,8 @@ var DiscordComponentButton = class extends Button {
9622
9183
  });
9623
9184
  }
9624
9185
  };
9625
- function createSelectControl(spec, ctx, handlers) {
9626
- return new DiscordComponentSelectControl(spec, ctx, handlers);
9627
- }
9628
9186
  function bindSelectControl(spec) {
9629
- return (ctx, handlers) => createSelectControl(spec, ctx, handlers);
9187
+ return (ctx, handlers) => new DiscordComponentSelectControl(spec, ctx, handlers);
9630
9188
  }
9631
9189
  function createDiscordComponentButtonControl(ctx, handlers) {
9632
9190
  return new DiscordComponentButton(ctx, handlers);
@@ -9638,24 +9196,15 @@ const createDiscordComponentMentionableSelectControl = bindSelectControl(SELECT_
9638
9196
  const createDiscordComponentChannelSelectControl = bindSelectControl(SELECT_CONTROLS.channel);
9639
9197
  //#endregion
9640
9198
  //#region extensions/discord/src/monitor/agent-components.ts
9641
- function bindDiscordComponentControl(createControl) {
9642
- return (ctx) => createControl(ctx, discordComponentControlHandlers);
9643
- }
9644
- const createDiscordComponentButton = bindDiscordComponentControl(createDiscordComponentButtonControl);
9645
- const createDiscordComponentStringSelect = bindDiscordComponentControl(createDiscordComponentStringSelectControl);
9646
- const createDiscordComponentUserSelect = bindDiscordComponentControl(createDiscordComponentUserSelectControl);
9647
- const createDiscordComponentRoleSelect = bindDiscordComponentControl(createDiscordComponentRoleSelectControl);
9648
- const createDiscordComponentMentionableSelect = bindDiscordComponentControl(createDiscordComponentMentionableSelectControl);
9649
- const createDiscordComponentChannelSelect = bindDiscordComponentControl(createDiscordComponentChannelSelectControl);
9650
9199
  const createAgentComponentControls = [createAgentComponentButton, createAgentSelectMenu];
9651
9200
  const createDiscordComponentControls = [
9652
- createDiscordComponentButton,
9653
- createDiscordComponentStringSelect,
9654
- createDiscordComponentUserSelect,
9655
- createDiscordComponentRoleSelect,
9656
- createDiscordComponentMentionableSelect,
9657
- createDiscordComponentChannelSelect
9658
- ];
9201
+ createDiscordComponentButtonControl,
9202
+ createDiscordComponentStringSelectControl,
9203
+ createDiscordComponentUserSelectControl,
9204
+ createDiscordComponentRoleSelectControl,
9205
+ createDiscordComponentMentionableSelectControl,
9206
+ createDiscordComponentChannelSelectControl
9207
+ ].map((createControl) => (ctx) => createControl(ctx, discordComponentControlHandlers));
9659
9208
  function createDiscordComponentModal(ctx) {
9660
9209
  return new DiscordComponentModal(ctx);
9661
9210
  }
@@ -9700,23 +9249,19 @@ var ExecApprovalButton = class extends Button {
9700
9249
  async run(interaction, data) {
9701
9250
  const parsed = parseExecApprovalData(data);
9702
9251
  if (!parsed) {
9703
- try {
9704
- await interaction.reply({
9705
- content: "This approval is no longer valid.",
9706
- ephemeral: true
9707
- });
9708
- } catch {}
9252
+ await replySilently(interaction, {
9253
+ content: "This approval is no longer valid.",
9254
+ ephemeral: true
9255
+ });
9709
9256
  return;
9710
9257
  }
9711
9258
  const approvers = this.ctx.getApprovers();
9712
9259
  const userId = interaction.userId;
9713
9260
  if (!approvers.some((id) => id === userId)) {
9714
- try {
9715
- await interaction.reply({
9716
- content: "⛔ You are not authorized to approve requests.",
9717
- ephemeral: true
9718
- });
9719
- } catch {}
9261
+ await replySilently(interaction, {
9262
+ content: "⛔ You are not authorized to approve requests.",
9263
+ ephemeral: true
9264
+ });
9720
9265
  return;
9721
9266
  }
9722
9267
  const decisionLabel = parsed.action === "allow-once" ? "Allowed (once)" : parsed.action === "allow-always" ? "Allowed (always)" : "Denied";
@@ -9854,6 +9399,16 @@ function createDiscordQuestionButton(params) {
9854
9399
  //#region extensions/discord/src/monitor/provider.interactions.ts
9855
9400
  function createDiscordProviderInteractionSurface(params) {
9856
9401
  const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
9402
+ const commandContext = {
9403
+ readPolicy: params.readPolicy,
9404
+ cfg: params.cfg,
9405
+ discordConfig: params.discordConfig,
9406
+ accountId: params.accountId,
9407
+ sessionPrefix: params.sessionPrefix,
9408
+ threadBindings: params.threadBindings,
9409
+ buildContext: params.channelRuntime?.inbound.buildContext,
9410
+ dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9411
+ };
9857
9412
  const commands = params.commandSpecs.map((spec) => {
9858
9413
  if (params.nativeEnabled && params.voiceEnabled && spec.name === DISCORD_VOICE_COMMAND_SPEC.name) return createDiscordVoiceCommand({
9859
9414
  readPolicy: params.readPolicy,
@@ -9866,15 +9421,9 @@ function createDiscordProviderInteractionSurface(params) {
9866
9421
  ephemeralDefault: params.ephemeralDefault
9867
9422
  });
9868
9423
  return createNativeCommand({
9869
- readPolicy: params.readPolicy,
9424
+ ...commandContext,
9870
9425
  command: spec,
9871
- cfg: params.cfg,
9872
- discordConfig: params.discordConfig,
9873
- accountId: params.accountId,
9874
- sessionPrefix: params.sessionPrefix,
9875
- ephemeralDefault: params.ephemeralDefault,
9876
- threadBindings: params.threadBindings,
9877
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9426
+ ephemeralDefault: params.ephemeralDefault
9878
9427
  });
9879
9428
  });
9880
9429
  const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
@@ -9899,61 +9448,29 @@ function createDiscordProviderInteractionSurface(params) {
9899
9448
  },
9900
9449
  abortSignal: params.abortSignal
9901
9450
  });
9902
- const components = [
9903
- createDiscordQuestionButton({
9904
- cfg: params.cfg,
9905
- accountId: params.accountId,
9906
- authContext: {
9907
- readPolicy: params.readPolicy,
9908
- cfg: params.cfg,
9909
- accountId: params.accountId,
9910
- discordConfig: params.discordConfig,
9911
- runtime: params.runtime,
9912
- token: params.token,
9913
- guildEntries: params.guildEntries,
9914
- allowFrom: params.allowFrom,
9915
- dmPolicy: params.dmPolicy
9916
- }
9917
- }),
9918
- createDiscordCommandArgFallbackButton({
9919
- readPolicy: params.readPolicy,
9920
- cfg: params.cfg,
9921
- discordConfig: params.discordConfig,
9922
- accountId: params.accountId,
9923
- sessionPrefix: params.sessionPrefix,
9924
- threadBindings: params.threadBindings,
9925
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9926
- }),
9927
- createDiscordModelPickerFallbackButton({
9928
- readPolicy: params.readPolicy,
9929
- cfg: params.cfg,
9930
- discordConfig: params.discordConfig,
9931
- accountId: params.accountId,
9932
- sessionPrefix: params.sessionPrefix,
9933
- threadBindings: params.threadBindings,
9934
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9935
- }),
9936
- createDiscordModelPickerFallbackSelect({
9937
- readPolicy: params.readPolicy,
9938
- cfg: params.cfg,
9939
- discordConfig: params.discordConfig,
9940
- accountId: params.accountId,
9941
- sessionPrefix: params.sessionPrefix,
9942
- threadBindings: params.threadBindings,
9943
- dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
9944
- })
9945
- ];
9946
- const activityButton = createDiscordActivityButton({
9451
+ const componentContext = {
9947
9452
  readPolicy: params.readPolicy,
9948
9453
  cfg: params.cfg,
9949
- discordConfig: params.discordConfig,
9950
9454
  accountId: params.accountId,
9455
+ discordConfig: params.discordConfig,
9456
+ runtime: params.runtime,
9457
+ token: params.token,
9951
9458
  guildEntries: params.guildEntries,
9952
9459
  allowFrom: params.allowFrom,
9953
- dmPolicy: params.dmPolicy,
9954
- runtime: params.runtime,
9955
- channelRuntime: params.channelRuntime,
9956
- token: params.token
9460
+ dmPolicy: params.dmPolicy
9461
+ };
9462
+ const components = [createDiscordQuestionButton({
9463
+ cfg: params.cfg,
9464
+ accountId: params.accountId,
9465
+ authContext: componentContext
9466
+ }), ...[
9467
+ createDiscordCommandArgFallbackButton,
9468
+ createDiscordModelPickerFallbackButton,
9469
+ createDiscordModelPickerFallbackSelect
9470
+ ].map((create) => create(commandContext))];
9471
+ const activityButton = createDiscordActivityButton({
9472
+ ...componentContext,
9473
+ channelRuntime: params.channelRuntime
9957
9474
  }, params.applicationId);
9958
9475
  if (activityButton) components.push(activityButton);
9959
9476
  const modals = [];
@@ -9963,17 +9480,6 @@ function createDiscordProviderInteractionSurface(params) {
9963
9480
  config: execApprovalsConfig
9964
9481
  })));
9965
9482
  if ((params.discordConfig.agentComponents ?? {}).enabled ?? true) {
9966
- const componentContext = {
9967
- readPolicy: params.readPolicy,
9968
- cfg: params.cfg,
9969
- discordConfig: params.discordConfig,
9970
- accountId: params.accountId,
9971
- guildEntries: params.guildEntries,
9972
- allowFrom: params.allowFrom,
9973
- dmPolicy: params.dmPolicy,
9974
- runtime: params.runtime,
9975
- token: params.token
9976
- };
9977
9483
  components.push(...createAgentComponentControls.map((create) => create(componentContext)));
9978
9484
  components.push(...createDiscordComponentControls.map((create) => create(componentContext)));
9979
9485
  modals.push(createDiscordComponentModal(componentContext));
@@ -10015,7 +9521,7 @@ var VoicePlugin = class extends Plugin {
10015
9521
  }
10016
9522
  },
10017
9523
  destroy: () => {
10018
- this.adapters.delete(guildId);
9524
+ if (this.adapters.get(guildId) === methods) this.adapters.delete(guildId);
10019
9525
  }
10020
9526
  };
10021
9527
  };
@@ -10027,11 +9533,7 @@ function resolveDiscordPreflightChannelAccess(params) {
10027
9533
  if (params.isGuildMessage && params.channelConfig?.enabled === false) {
10028
9534
  logDebug(`[discord-preflight] drop: channel disabled`);
10029
9535
  logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
10030
- return {
10031
- allowed: false,
10032
- channelAllowlistConfigured: false,
10033
- channelAllowed: false
10034
- };
9536
+ return false;
10035
9537
  }
10036
9538
  const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
10037
9539
  channels: params.groupDmChannels,
@@ -10039,11 +9541,7 @@ function resolveDiscordPreflightChannelAccess(params) {
10039
9541
  channelName: params.displayChannelName,
10040
9542
  channelSlug: params.displayChannelSlug
10041
9543
  });
10042
- if (params.isGroupDm && !groupDmAllowed) return {
10043
- allowed: false,
10044
- channelAllowlistConfigured: false,
10045
- channelAllowed: false
10046
- };
9544
+ if (params.isGroupDm && !groupDmAllowed) return false;
10047
9545
  const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
10048
9546
  const channelAllowed = params.channelConfig?.allowed !== false;
10049
9547
  if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
@@ -10062,30 +9560,18 @@ function resolveDiscordPreflightChannelAccess(params) {
10062
9560
  logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
10063
9561
  logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
10064
9562
  }
10065
- return {
10066
- allowed: false,
10067
- channelAllowlistConfigured,
10068
- channelAllowed
10069
- };
9563
+ return false;
10070
9564
  }
10071
9565
  if (params.isGuildMessage && params.channelConfig?.allowed === false) {
10072
9566
  logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
10073
9567
  logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
10074
- return {
10075
- allowed: false,
10076
- channelAllowlistConfigured,
10077
- channelAllowed
10078
- };
9568
+ return false;
10079
9569
  }
10080
9570
  if (params.isGuildMessage) {
10081
9571
  logDebug(`[discord-preflight] pass: channel allowed`);
10082
9572
  logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
10083
9573
  }
10084
- return {
10085
- allowed: true,
10086
- channelAllowlistConfigured,
10087
- channelAllowed
10088
- };
9574
+ return true;
10089
9575
  }
10090
9576
  //#endregion
10091
9577
  //#region extensions/discord/src/monitor/listeners.guild-join.ts
@@ -10142,7 +9628,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
10142
9628
  guildInfo,
10143
9629
  channelConfig,
10144
9630
  channelMatchMeta: `guild=${data.id} channel=${channel.id}`
10145
- }).allowed;
9631
+ });
10146
9632
  if (roomAllowed) {
10147
9633
  targetChannel = channel;
10148
9634
  break;
@@ -10216,11 +9702,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
10216
9702
  //#region extensions/discord/src/monitor/provider.startup.ts
10217
9703
  function registerLatePlugin(client, plugin) {
10218
9704
  plugin.registerClient?.(client);
10219
- plugin.registerRoutes?.(client);
10220
- if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push({
10221
- id: plugin.id,
10222
- plugin
10223
- });
9705
+ if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push(plugin);
10224
9706
  }
10225
9707
  function createDiscordStatusReadyListener(params) {
10226
9708
  return new class DiscordStatusReadyListener extends ReadyListener {
@@ -10232,21 +9714,17 @@ function createDiscordStatusReadyListener(params) {
10232
9714
  }
10233
9715
  const gateway = client.getPlugin("gateway");
10234
9716
  if (!gateway) return;
10235
- const presence = resolveDiscordPresenceUpdate(params.discordConfig);
10236
- if (!presence) return;
10237
- gateway.updatePresence(presence);
9717
+ gateway.updatePresence(resolveDiscordPresenceUpdate(params.discordConfig));
10238
9718
  }
10239
9719
  }();
10240
9720
  }
10241
9721
  async function createDiscordMonitorClient(params) {
10242
9722
  let autoPresenceController = null;
10243
- const clientPlugins = [params.createGatewayPlugin({
9723
+ const constructorPlugins = [params.createGatewayPlugin({
10244
9724
  discordConfig: params.discordConfig,
10245
9725
  runtime: params.runtime
10246
9726
  })];
10247
- if (params.voiceEnabled) clientPlugins.push(new VoicePlugin());
10248
- const voicePlugin = clientPlugins.find((plugin) => plugin.id === "voice");
10249
- const constructorPlugins = voicePlugin ? clientPlugins.filter((plugin) => plugin !== voicePlugin) : clientPlugins;
9727
+ const voicePlugin = params.voiceEnabled ? new VoicePlugin() : void 0;
10250
9728
  const eventQueueOpts = {
10251
9729
  listenerTimeout: 12e4,
10252
9730
  slowListenerThreshold: 3e4
@@ -10256,16 +9734,11 @@ async function createDiscordMonitorClient(params) {
10256
9734
  getAutoPresenceController: () => autoPresenceController
10257
9735
  });
10258
9736
  const client = params.createClient({
10259
- baseUrl: "http://localhost",
10260
- deploySecret: "a",
10261
9737
  clientId: params.applicationId,
10262
- publicKey: "a",
10263
9738
  token: params.token,
10264
- autoDeploy: false,
10265
9739
  commandDeployHashStore: params.commandDeployHashStore,
10266
9740
  requestOptions: {
10267
9741
  timeout: DISCORD_REST_TIMEOUT_MS,
10268
- runtimeProfile: "persistent",
10269
9742
  maxQueueSize: 1e3,
10270
9743
  ...params.restFetch ? { fetch: params.restFetch } : {}
10271
9744
  },
@@ -10319,9 +9792,8 @@ async function fetchDiscordBotIdentity(params) {
10319
9792
  params.logStartupPhase("fetch-bot-identity:error", String(err));
10320
9793
  throw new Error("Failed to resolve Discord bot identity", { cause: err });
10321
9794
  }
10322
- const botUserRecord = botUser;
10323
- const botUserId = normalizeOptionalString(botUserRecord?.id);
10324
- const botUserName = normalizeOptionalString(botUserRecord?.username) ?? normalizeOptionalString(botUserRecord?.globalName);
9795
+ const botUserId = normalizeOptionalString(botUser?.id);
9796
+ const botUserName = normalizeOptionalString(botUser?.username) ?? normalizeOptionalString(botUser?.globalName);
10325
9797
  if (!botUserId) {
10326
9798
  const details = "fetchUser(\"@me\") returned no usable id";
10327
9799
  params.runtime.error?.(danger(`discord: failed to fetch bot identity: ${details}`));
@@ -10405,12 +9877,6 @@ function formatDiscordStartupStatusMessage(params) {
10405
9877
  //#endregion
10406
9878
  //#region extensions/discord/src/monitor/provider.ts
10407
9879
  const DEFAULT_DISCORD_MEDIA_MAX_MB = 100;
10408
- function logDiscordStartupPhase(params) {
10409
- logDiscordStartupPhase$1({
10410
- ...params,
10411
- isVerbose: discordProviderRuntime.isVerbose
10412
- });
10413
- }
10414
9880
  const DISCORD_DISALLOWED_INTENTS_CODE = GatewayCloseCodes$1.DisallowedIntents;
10415
9881
  function isDiscordDisallowedIntentsError(err) {
10416
9882
  if (!err) return false;
@@ -10427,6 +9893,16 @@ async function monitorDiscordProvider(opts = {}) {
10427
9893
  const token = normalizeDiscordToken(opts.token ?? void 0, "channels.discord.token") ?? account.token;
10428
9894
  if (!token) throw new Error(`Discord bot token missing for account "${account.accountId}" (set discord.accounts.${account.accountId}.token or DISCORD_BOT_TOKEN for default).`);
10429
9895
  const runtime = opts.runtime ?? createNonExitingRuntime();
9896
+ let lifecycleGateway;
9897
+ const logStartupPhase = (phase, details) => logDiscordStartupPhase({
9898
+ runtime,
9899
+ accountId: account.accountId,
9900
+ phase,
9901
+ startAt: startupStartedAt,
9902
+ gateway: lifecycleGateway,
9903
+ details,
9904
+ isVerbose: discordProviderRuntime.isVerbose
9905
+ });
10430
9906
  const rawDiscordCfg = account.config;
10431
9907
  const discordRestFetch = resolveDiscordRestFetch(rawDiscordCfg.proxy, runtime);
10432
9908
  const dmConfig = rawDiscordCfg.dm;
@@ -10456,7 +9932,7 @@ async function monitorDiscordProvider(opts = {}) {
10456
9932
  let allowFrom = configuredDmAllowFrom ?? [];
10457
9933
  const mediaMaxBytes = (opts.mediaMaxMb ?? discordCfg.mediaMaxMb ?? DEFAULT_DISCORD_MEDIA_MAX_MB) * 1024 * 1024;
10458
9934
  const textLimit = resolveTextChunkLimit(cfg, "discord", account.accountId, { fallbackLimit: 2e3 });
10459
- const historyLimit = Math.max(0, opts.historyLimit ?? discordCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? 20);
9935
+ const historyLimit = resolvePromptHistoryLimit(opts.historyLimit ?? discordCfg.historyLimit ?? cfg.messages?.groupChat?.historyLimit, 20);
10460
9936
  const replyToMode = opts.replyToMode ?? discordCfg.replyToMode ?? "off";
10461
9937
  const dmEnabled = dmConfig?.enabled ?? true;
10462
9938
  const dmPolicy = resolveDiscordAccountDmPolicy({
@@ -10532,12 +10008,7 @@ async function monitorDiscordProvider(opts = {}) {
10532
10008
  threadBindingIdleTimeoutMs,
10533
10009
  threadBindingMaxAgeMs
10534
10010
  });
10535
- logDiscordStartupPhase({
10536
- runtime,
10537
- accountId: account.accountId,
10538
- phase: "fetch-application-id:start",
10539
- startAt: startupStartedAt
10540
- });
10011
+ logStartupPhase("fetch-application-id:start");
10541
10012
  const parsedApplicationId = (typeof discordCfg.applicationId === "string" && discordCfg.applicationId.trim() ? discordCfg.applicationId.trim() : void 0) ?? parseApplicationIdFromToken(token);
10542
10013
  const applicationIdProbe = parsedApplicationId ? {
10543
10014
  kind: "resolved",
@@ -10563,13 +10034,7 @@ async function monitorDiscordProvider(opts = {}) {
10563
10034
  throw new Error(message, { cause: applicationIdProbe.error });
10564
10035
  }
10565
10036
  const applicationId = applicationIdProbe.applicationId;
10566
- logDiscordStartupPhase({
10567
- runtime,
10568
- accountId: account.accountId,
10569
- phase: "fetch-application-id:done",
10570
- startAt: startupStartedAt,
10571
- details: `applicationId=${applicationId}`
10572
- });
10037
+ logStartupPhase("fetch-application-id:done", `applicationId=${applicationId}`);
10573
10038
  const { commandSpecs } = await resolveDiscordProviderCommandSpecs({
10574
10039
  cfg,
10575
10040
  runtime,
@@ -10592,7 +10057,6 @@ async function monitorDiscordProvider(opts = {}) {
10592
10057
  let deactivateMessageHandler;
10593
10058
  let stopMonitorListeners;
10594
10059
  let autoPresenceController = null;
10595
- let lifecycleGateway;
10596
10060
  let earlyGatewayEmitter = gatewaySupervisor?.emitter;
10597
10061
  let onEarlyGatewayDebug;
10598
10062
  try {
@@ -10672,14 +10136,7 @@ async function monitorDiscordProvider(opts = {}) {
10672
10136
  runtime.log?.(`discord startup [${account.accountId}] gateway-debug ${Math.max(0, Date.now() - startupStartedAt)}ms ${String(msg)}`);
10673
10137
  };
10674
10138
  earlyGatewayEmitter?.on("debug", onEarlyGatewayDebug);
10675
- logDiscordStartupPhase({
10676
- runtime,
10677
- accountId: account.accountId,
10678
- phase: "deploy-commands:schedule",
10679
- startAt: startupStartedAt,
10680
- gateway: lifecycleGateway,
10681
- details: `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`
10682
- });
10139
+ logStartupPhase("deploy-commands:schedule", `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`);
10683
10140
  runDiscordCommandDeployInBackground({
10684
10141
  client,
10685
10142
  runtime,
@@ -10695,14 +10152,7 @@ async function monitorDiscordProvider(opts = {}) {
10695
10152
  client,
10696
10153
  token,
10697
10154
  runtime,
10698
- logStartupPhase: (phase, details) => logDiscordStartupPhase({
10699
- runtime,
10700
- accountId: account.accountId,
10701
- phase,
10702
- startAt: startupStartedAt,
10703
- gateway: lifecycleGateway,
10704
- details
10705
- })
10155
+ logStartupPhase
10706
10156
  });
10707
10157
  let voiceManager = null;
10708
10158
  if (voiceEnabled) {
@@ -10779,13 +10229,7 @@ async function monitorDiscordProvider(opts = {}) {
10779
10229
  messageHandler,
10780
10230
  trackInboundEvent
10781
10231
  });
10782
- logDiscordStartupPhase({
10783
- runtime,
10784
- accountId: account.accountId,
10785
- phase: "client-start",
10786
- startAt: startupStartedAt,
10787
- gateway: lifecycleGateway
10788
- });
10232
+ logStartupPhase("client-start");
10789
10233
  const botIdentity = botUserId && botUserName ? `${botUserId} (${botUserName})` : botUserId ?? botUserName ?? "";
10790
10234
  runtime.log?.(formatDiscordStartupStatusMessage({
10791
10235
  gatewayReady: lifecycleGateway?.isConnected === true,
@@ -10824,4 +10268,4 @@ async function monitorDiscordProvider(opts = {}) {
10824
10268
  }
10825
10269
  }
10826
10270
  //#endregion
10827
- export { resolveDiscordTextCommandAccess as S, handleDiscordDmCommandDecision as _, formatDiscordReplySkip as a, registerDiscordListener as b, buildGuildLabel as c, resolveDiscordGatewayIntents as d, waitForDiscordGatewayPluginRegistration as f, createDiscordSupplementalContextAccessChecker as g, buildDiscordInboundAccessContext as h, formatDiscordReplyDeliveryFailure as i, resolveReplyContext as l, buildDiscordGroupSystemPrompt as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, createDiscordNativeCommand as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, createDiscordGatewayPlugin as u, createDiscordLivePolicyReader as v, resolveDiscordDmCommandAccess as x, mapGatewayDispatchData as y };
10271
+ export { resolveDiscordDmCommandAccess as A, buildDiscordGroupSystemPrompt as C, createDiscordLivePolicyReader as D, handleDiscordDmCommandDecision as E, mapGatewayDispatchData as O, createDiscordNativeCommand as S, createDiscordSupplementalContextAccessChecker as T, resolveDiscordVoiceMode as _, formatDiscordReplySkip as a, resolveDiscordGatewayIntents as b, buildGuildLabel as c, MIN_SEGMENT_SECONDS as d, VOICE_CONNECT_READY_TIMEOUT_MS as f, logVoiceVerbose as g, isVoiceChannel as h, formatDiscordReplyDeliveryFailure as i, resolveDiscordTextCommandAccess as j, registerDiscordListener as k, resolveReplyContext as l, isDiscordRealtimeVoiceMode as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, VOICE_RECONNECT_GRACE_MS as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, CAPTURE_FINALIZE_GRACE_MS as u, resolveVoiceTimeoutMs as v, buildDiscordInboundAccessContext as w, waitForDiscordGatewayPluginRegistration as x, createDiscordGatewayPlugin as y };