@kodelyth/discord 2026.5.39 → 2026.5.42

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 (639) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +130 -0
  4. package/channel-config-api.ts +1 -0
  5. package/channel-plugin-api.ts +3 -0
  6. package/config-api.ts +4 -0
  7. package/configured-state.ts +6 -0
  8. package/contract-api.ts +21 -0
  9. package/directory-contract-api.ts +4 -0
  10. package/dist/account-inspect-Dqw-enky.js +81 -0
  11. package/dist/account-inspect-api.js +10 -0
  12. package/dist/accounts-B7OBFePq.js +224 -0
  13. package/dist/action-runtime-api.js +2 -0
  14. package/dist/agent-components.runtime-DVY_1VB4.js +4 -0
  15. package/dist/allow-list-B0s7evD7.js +354 -0
  16. package/dist/api-CXAcv9nZ.js +130 -0
  17. package/dist/api.js +23 -0
  18. package/dist/approval-handler.runtime-B9xUAF3n.js +426 -0
  19. package/dist/audit-DoiK49WO.js +24 -0
  20. package/dist/audit-core-BGrq3G7r.js +105 -0
  21. package/dist/channel-U_aeoFwW.js +795 -0
  22. package/dist/channel-actions-BxEBnEuv.js +173 -0
  23. package/dist/channel-actions.runtime-CPtpH-yl.js +263 -0
  24. package/dist/channel-api-BfjklLby.js +21 -0
  25. package/dist/channel-config-api.js +2 -0
  26. package/dist/channel-plugin-api.js +2 -0
  27. package/dist/channel.setup-BUSC0apv.js +337 -0
  28. package/dist/components-luonoe13.js +909 -0
  29. package/dist/config-api-DSYGqaLQ.js +2 -0
  30. package/dist/config-schema-DIqJBGwC.js +357 -0
  31. package/dist/configured-state.js +6 -0
  32. package/dist/contract-api.js +8 -0
  33. package/dist/conversation-identity-DXAm0_Mk.js +270 -0
  34. package/dist/directory-config-CYbuMmPS.js +49 -0
  35. package/dist/directory-contract-api.js +2 -0
  36. package/dist/directory-live-DX4dLRpJ.js +159 -0
  37. package/dist/doctor-bbKSvGVD.js +244 -0
  38. package/dist/doctor-contract-Btjt6NJD.js +383 -0
  39. package/dist/doctor-contract-api.js +2 -0
  40. package/dist/gateway-registry-BKSpa4GB.js +74 -0
  41. package/dist/handle-action.guild-admin-B5BArS2n.js +286 -0
  42. package/dist/inbound-context-WAOqhGlT.js +48 -0
  43. package/dist/inbound-event-delivery-C-1Ji3WP.js +65 -0
  44. package/dist/index.js +26 -0
  45. package/dist/manager.runtime-DXHynKE4.js +2356 -0
  46. package/dist/message-handler-mXzc3tA_.js +381 -0
  47. package/dist/message-handler.preflight-BPD1a347.js +1113 -0
  48. package/dist/message-handler.process-GUa3aV8z.js +1438 -0
  49. package/dist/message-utils-dUbem16p.js +549 -0
  50. package/dist/outbound-adapter-C18OAc1y.js +536 -0
  51. package/dist/pluralkit-D1Q2x0w5.js +22 -0
  52. package/dist/preflight-audio-CZtpWcIm.js +72 -0
  53. package/dist/preflight-audio.runtime-Brx_0_xW.js +7 -0
  54. package/dist/preview-streaming-D_slNIiO.js +8 -0
  55. package/dist/probe-D--Ca4JF.js +139 -0
  56. package/dist/probe.runtime-DQBchZzv.js +2 -0
  57. package/dist/provider-B2-31CIT.js +9565 -0
  58. package/dist/provider-session.runtime-BwzzSsrH.js +6 -0
  59. package/dist/provider.runtime-CP3oHLls.js +2 -0
  60. package/dist/resolve-allowlist-common-CqxPLcJO.js +34 -0
  61. package/dist/resolve-channels-0LX4pUbB.js +265 -0
  62. package/dist/resolve-users-CztOv0Qs.js +120 -0
  63. package/dist/runtime-DUaw66V_.js +1073 -0
  64. package/dist/runtime-api.actions.js +3 -0
  65. package/dist/runtime-api.js +30 -0
  66. package/dist/runtime-api.lookup.js +7 -0
  67. package/dist/runtime-api.monitor-CvVKvEXW.js +5 -0
  68. package/dist/runtime-api.monitor.js +8 -0
  69. package/dist/runtime-api.send.js +6 -0
  70. package/dist/runtime-api.threads.js +6 -0
  71. package/dist/runtime-fC6f4UF2.js +8 -0
  72. package/dist/runtime-setter-api.js +2 -0
  73. package/dist/secret-config-contract-B6WW5V88.js +115 -0
  74. package/dist/secret-contract-api.js +2 -0
  75. package/dist/security-audit-CnyIQKz6.js +120 -0
  76. package/dist/security-audit-contract-api.js +2 -0
  77. package/dist/security-audit.runtime-CQSkjNLu.js +2 -0
  78. package/dist/security-contract-DLvYOgLM.js +26 -0
  79. package/dist/security-contract-api.js +2 -0
  80. package/dist/security-doctor-DepqtNCI.js +18 -0
  81. package/dist/send-DCtPCHGk.js +881 -0
  82. package/dist/send.components-Bcgxvm52.js +474 -0
  83. package/dist/send.outbound-S9t0UuHc.js +330 -0
  84. package/dist/send.receipt-CDn3GBWC.js +3119 -0
  85. package/dist/send.shared-D4iBnAmn.js +669 -0
  86. package/dist/sender-identity-CxCe3_1a.js +43 -0
  87. package/dist/session-contract-Dwhw3RTY.js +6 -0
  88. package/dist/session-key-api.js +2 -0
  89. package/dist/session-key-normalization-CP8dPUid.js +23 -0
  90. package/dist/setup-entry.js +11 -0
  91. package/dist/setup-plugin-api.js +2 -0
  92. package/dist/shared-AIlvuZXt.js +171 -0
  93. package/dist/subagent-hooks-8bK-mgiU.js +120 -0
  94. package/dist/subagent-hooks-api.js +22 -0
  95. package/dist/system-events-Ba1TklaL.js +34 -0
  96. package/dist/target-resolver-BrtFQtoK.js +82 -0
  97. package/dist/targets-DWLLZE2l.js +3 -0
  98. package/dist/test-api.js +45 -0
  99. package/dist/thread-binding-api.js +4 -0
  100. package/dist/thread-bindings-9aKRmZv0.js +255 -0
  101. package/dist/thread-bindings.discord-api-ssGH5wc2.js +244 -0
  102. package/dist/thread-bindings.manager-0YBHGemk.js +534 -0
  103. package/dist/thread-bindings.session-updates-DJZGIwaU.js +54 -0
  104. package/dist/thread-bindings.state-eTFl-PqJ.js +318 -0
  105. package/dist/timeouts-CEwuGaWT.js +52 -0
  106. package/dist/timeouts.js +2 -0
  107. package/dist/typing-BmJKRpCS.js +14 -0
  108. package/doctor-contract-api.ts +1 -0
  109. package/index.test.ts +13 -0
  110. package/index.ts +24 -0
  111. package/klaw.plugin.json +2 -3822
  112. package/package.json +4 -4
  113. package/runtime-api.actions.ts +15 -0
  114. package/runtime-api.lookup.ts +22 -0
  115. package/runtime-api.monitor.ts +50 -0
  116. package/runtime-api.send.ts +79 -0
  117. package/runtime-api.threads.ts +31 -0
  118. package/runtime-api.ts +181 -0
  119. package/runtime-setter-api.ts +3 -0
  120. package/secret-contract-api.ts +4 -0
  121. package/security-audit-contract-api.ts +1 -0
  122. package/security-contract-api.ts +4 -0
  123. package/session-key-api.ts +1 -0
  124. package/setup-entry.ts +9 -0
  125. package/setup-plugin-api.ts +3 -0
  126. package/src/account-inspect.test.ts +126 -0
  127. package/src/account-inspect.ts +128 -0
  128. package/src/accounts.test.ts +381 -0
  129. package/src/accounts.ts +205 -0
  130. package/src/actions/handle-action.guild-admin.ts +421 -0
  131. package/src/actions/handle-action.test.ts +480 -0
  132. package/src/actions/handle-action.ts +402 -0
  133. package/src/actions/runtime.guild.ts +446 -0
  134. package/src/actions/runtime.messaging.messages.ts +226 -0
  135. package/src/actions/runtime.messaging.reactions.ts +67 -0
  136. package/src/actions/runtime.messaging.runtime.ts +73 -0
  137. package/src/actions/runtime.messaging.send.ts +336 -0
  138. package/src/actions/runtime.messaging.shared.ts +97 -0
  139. package/src/actions/runtime.messaging.ts +37 -0
  140. package/src/actions/runtime.moderation-shared.ts +48 -0
  141. package/src/actions/runtime.moderation.authz.test.ts +151 -0
  142. package/src/actions/runtime.moderation.ts +116 -0
  143. package/src/actions/runtime.presence.test.ts +165 -0
  144. package/src/actions/runtime.presence.ts +117 -0
  145. package/src/actions/runtime.shared.ts +86 -0
  146. package/src/actions/runtime.test.ts +1337 -0
  147. package/src/actions/runtime.ts +87 -0
  148. package/src/api-barrel.test.ts +78 -0
  149. package/src/api.test.ts +152 -0
  150. package/src/api.ts +215 -0
  151. package/src/approval-handler.runtime.test.ts +41 -0
  152. package/src/approval-handler.runtime.ts +633 -0
  153. package/src/approval-native.test.ts +330 -0
  154. package/src/approval-native.ts +219 -0
  155. package/src/approval-runtime.ts +14 -0
  156. package/src/approval-shared.ts +50 -0
  157. package/src/audit-core.ts +178 -0
  158. package/src/audit.test.ts +204 -0
  159. package/src/audit.ts +32 -0
  160. package/src/channel-actions.contract.test.ts +45 -0
  161. package/src/channel-actions.runtime.ts +1 -0
  162. package/src/channel-actions.test.ts +504 -0
  163. package/src/channel-actions.ts +254 -0
  164. package/src/channel-api.ts +29 -0
  165. package/src/channel.conversation.ts +159 -0
  166. package/src/channel.loaders.ts +50 -0
  167. package/src/channel.message-adapter.test.ts +230 -0
  168. package/src/channel.runtime.ts +1 -0
  169. package/src/channel.setup.ts +12 -0
  170. package/src/channel.test.ts +828 -0
  171. package/src/channel.ts +728 -0
  172. package/src/chunk.test.ts +170 -0
  173. package/src/chunk.ts +321 -0
  174. package/src/client.proxy.test.ts +177 -0
  175. package/src/client.test.ts +83 -0
  176. package/src/client.ts +143 -0
  177. package/src/component-custom-id.ts +72 -0
  178. package/src/components-registry.ts +356 -0
  179. package/src/components.builders.ts +409 -0
  180. package/src/components.modal.ts +124 -0
  181. package/src/components.parse.ts +407 -0
  182. package/src/components.test.ts +345 -0
  183. package/src/components.ts +54 -0
  184. package/src/components.types.ts +187 -0
  185. package/src/config-schema.test.ts +439 -0
  186. package/src/config-schema.ts +6 -0
  187. package/src/config-ui-hints.ts +354 -0
  188. package/src/conversation-identity.ts +58 -0
  189. package/src/delivery-retry.ts +52 -0
  190. package/src/directory-cache.ts +116 -0
  191. package/src/directory-config.ts +58 -0
  192. package/src/directory-contract.test.ts +129 -0
  193. package/src/directory-live.test.ts +141 -0
  194. package/src/directory-live.ts +135 -0
  195. package/src/doctor-contract.ts +477 -0
  196. package/src/doctor-shared.ts +5 -0
  197. package/src/doctor.test.ts +393 -0
  198. package/src/doctor.ts +340 -0
  199. package/src/draft-chunking.test.ts +64 -0
  200. package/src/draft-chunking.ts +43 -0
  201. package/src/draft-stream.test.ts +193 -0
  202. package/src/draft-stream.ts +162 -0
  203. package/src/durable-delivery.test.ts +103 -0
  204. package/src/error-body.ts +38 -0
  205. package/src/exec-approvals.test.ts +88 -0
  206. package/src/exec-approvals.ts +110 -0
  207. package/src/gateway-logging.test.ts +98 -0
  208. package/src/gateway-logging.ts +67 -0
  209. package/src/group-policy.ts +113 -0
  210. package/src/guilds.ts +29 -0
  211. package/src/inbound-context.contract.test.ts +11 -0
  212. package/src/inbound-event-delivery.ts +135 -0
  213. package/src/interactive-dispatch.ts +104 -0
  214. package/src/internal/api.commands.ts +51 -0
  215. package/src/internal/api.guild.ts +164 -0
  216. package/src/internal/api.interactions.ts +53 -0
  217. package/src/internal/api.messages.ts +113 -0
  218. package/src/internal/api.reactions.ts +38 -0
  219. package/src/internal/api.test.ts +260 -0
  220. package/src/internal/api.ts +61 -0
  221. package/src/internal/api.users.ts +19 -0
  222. package/src/internal/api.webhooks.ts +13 -0
  223. package/src/internal/client.test.ts +472 -0
  224. package/src/internal/client.ts +310 -0
  225. package/src/internal/command-deploy.test.ts +197 -0
  226. package/src/internal/command-deploy.ts +352 -0
  227. package/src/internal/commands.ts +188 -0
  228. package/src/internal/components.base.ts +65 -0
  229. package/src/internal/components.message.ts +279 -0
  230. package/src/internal/components.modal.ts +95 -0
  231. package/src/internal/components.ts +31 -0
  232. package/src/internal/discord.ts +11 -0
  233. package/src/internal/embeds.ts +35 -0
  234. package/src/internal/entity-cache.ts +98 -0
  235. package/src/internal/event-queue.ts +185 -0
  236. package/src/internal/gateway-close-codes.ts +25 -0
  237. package/src/internal/gateway-dispatch.ts +96 -0
  238. package/src/internal/gateway-identify-limiter.ts +26 -0
  239. package/src/internal/gateway-lifecycle.test.ts +114 -0
  240. package/src/internal/gateway-lifecycle.ts +75 -0
  241. package/src/internal/gateway-rate-limit.ts +104 -0
  242. package/src/internal/gateway.test.ts +676 -0
  243. package/src/internal/gateway.ts +479 -0
  244. package/src/internal/interaction-dispatch.test.ts +148 -0
  245. package/src/internal/interaction-dispatch.ts +162 -0
  246. package/src/internal/interaction-options.ts +98 -0
  247. package/src/internal/interaction-response.ts +53 -0
  248. package/src/internal/interactions.test.ts +329 -0
  249. package/src/internal/interactions.ts +378 -0
  250. package/src/internal/listeners.ts +91 -0
  251. package/src/internal/live-smoke.live.test.ts +26 -0
  252. package/src/internal/modal-fields.ts +95 -0
  253. package/src/internal/payload.ts +69 -0
  254. package/src/internal/rest-body.ts +115 -0
  255. package/src/internal/rest-errors.ts +88 -0
  256. package/src/internal/rest-routes.ts +50 -0
  257. package/src/internal/rest-scheduler.ts +557 -0
  258. package/src/internal/rest.test.ts +681 -0
  259. package/src/internal/rest.ts +322 -0
  260. package/src/internal/schemas.ts +36 -0
  261. package/src/internal/structures.test.ts +43 -0
  262. package/src/internal/structures.ts +280 -0
  263. package/src/internal/test-builders.test-support.ts +167 -0
  264. package/src/internal/voice.ts +49 -0
  265. package/src/media-detection.ts +28 -0
  266. package/src/mentions.test.ts +111 -0
  267. package/src/mentions.ts +147 -0
  268. package/src/monitor/ack-reactions.ts +70 -0
  269. package/src/monitor/acp-bind-here.integration.test.ts +219 -0
  270. package/src/monitor/agent-components-auth.ts +7 -0
  271. package/src/monitor/agent-components-context.ts +154 -0
  272. package/src/monitor/agent-components-data.ts +224 -0
  273. package/src/monitor/agent-components-dm-auth.ts +177 -0
  274. package/src/monitor/agent-components-guild-auth.ts +322 -0
  275. package/src/monitor/agent-components-helpers.runtime.ts +3 -0
  276. package/src/monitor/agent-components-helpers.ts +34 -0
  277. package/src/monitor/agent-components-reply.ts +10 -0
  278. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  279. package/src/monitor/agent-components.dispatch.ts +359 -0
  280. package/src/monitor/agent-components.handlers.ts +303 -0
  281. package/src/monitor/agent-components.modal.ts +160 -0
  282. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  283. package/src/monitor/agent-components.runtime.ts +14 -0
  284. package/src/monitor/agent-components.system-controls.ts +215 -0
  285. package/src/monitor/agent-components.ts +70 -0
  286. package/src/monitor/agent-components.types.ts +58 -0
  287. package/src/monitor/agent-components.wildcard-controls.ts +171 -0
  288. package/src/monitor/agent-components.wildcard.test.ts +71 -0
  289. package/src/monitor/allow-list.test.ts +14 -0
  290. package/src/monitor/allow-list.ts +631 -0
  291. package/src/monitor/auto-presence.test.ts +184 -0
  292. package/src/monitor/auto-presence.ts +356 -0
  293. package/src/monitor/channel-access.test.ts +113 -0
  294. package/src/monitor/channel-access.ts +102 -0
  295. package/src/monitor/commands.test.ts +24 -0
  296. package/src/monitor/commands.ts +9 -0
  297. package/src/monitor/dm-command-auth.test.ts +274 -0
  298. package/src/monitor/dm-command-auth.ts +259 -0
  299. package/src/monitor/dm-command-decision.test.ts +108 -0
  300. package/src/monitor/dm-command-decision.ts +49 -0
  301. package/src/monitor/exec-approvals.test.ts +225 -0
  302. package/src/monitor/exec-approvals.ts +158 -0
  303. package/src/monitor/format.ts +45 -0
  304. package/src/monitor/gateway-handle.ts +33 -0
  305. package/src/monitor/gateway-metadata.test.ts +29 -0
  306. package/src/monitor/gateway-metadata.ts +298 -0
  307. package/src/monitor/gateway-plugin.test.ts +320 -0
  308. package/src/monitor/gateway-plugin.ts +302 -0
  309. package/src/monitor/gateway-registry.ts +37 -0
  310. package/src/monitor/gateway-supervisor.test.ts +157 -0
  311. package/src/monitor/gateway-supervisor.ts +206 -0
  312. package/src/monitor/inbound-context.test-helpers.ts +37 -0
  313. package/src/monitor/inbound-context.test.ts +112 -0
  314. package/src/monitor/inbound-context.ts +95 -0
  315. package/src/monitor/inbound-dedupe.ts +79 -0
  316. package/src/monitor/inbound-job.test.ts +216 -0
  317. package/src/monitor/inbound-job.ts +118 -0
  318. package/src/monitor/listeners.queue.ts +91 -0
  319. package/src/monitor/listeners.reactions.ts +594 -0
  320. package/src/monitor/listeners.test.ts +209 -0
  321. package/src/monitor/listeners.ts +150 -0
  322. package/src/monitor/message-channel-info.ts +96 -0
  323. package/src/monitor/message-forwarded.ts +114 -0
  324. package/src/monitor/message-handler.batch-gate.test.ts +22 -0
  325. package/src/monitor/message-handler.batch-gate.ts +19 -0
  326. package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
  327. package/src/monitor/message-handler.context.ts +492 -0
  328. package/src/monitor/message-handler.dm-preflight.ts +119 -0
  329. package/src/monitor/message-handler.draft-preview.ts +426 -0
  330. package/src/monitor/message-handler.hydration.test.ts +80 -0
  331. package/src/monitor/message-handler.hydration.ts +198 -0
  332. package/src/monitor/message-handler.inbound-context.test.ts +61 -0
  333. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  334. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  335. package/src/monitor/message-handler.preflight-channel-context.test.ts +18 -0
  336. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  337. package/src/monitor/message-handler.preflight-context.ts +54 -0
  338. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  339. package/src/monitor/message-handler.preflight-history.ts +23 -0
  340. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  341. package/src/monitor/message-handler.preflight-pluralkit.ts +26 -0
  342. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  343. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  344. package/src/monitor/message-handler.preflight.acp-bindings.test.ts +371 -0
  345. package/src/monitor/message-handler.preflight.test-helpers.ts +114 -0
  346. package/src/monitor/message-handler.preflight.test.ts +2255 -0
  347. package/src/monitor/message-handler.preflight.ts +822 -0
  348. package/src/monitor/message-handler.preflight.types.ts +115 -0
  349. package/src/monitor/message-handler.process.test.ts +2520 -0
  350. package/src/monitor/message-handler.process.ts +1027 -0
  351. package/src/monitor/message-handler.queue.test.ts +680 -0
  352. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  353. package/src/monitor/message-handler.test-harness.ts +99 -0
  354. package/src/monitor/message-handler.test-helpers.ts +75 -0
  355. package/src/monitor/message-handler.ts +309 -0
  356. package/src/monitor/message-media.ts +536 -0
  357. package/src/monitor/message-run-queue.ts +101 -0
  358. package/src/monitor/message-text.ts +171 -0
  359. package/src/monitor/message-utils.test.ts +1234 -0
  360. package/src/monitor/message-utils.ts +34 -0
  361. package/src/monitor/model-picker-preferences.test.ts +67 -0
  362. package/src/monitor/model-picker-preferences.ts +184 -0
  363. package/src/monitor/model-picker.state.ts +364 -0
  364. package/src/monitor/model-picker.test-utils.ts +26 -0
  365. package/src/monitor/model-picker.test.ts +869 -0
  366. package/src/monitor/model-picker.ts +38 -0
  367. package/src/monitor/model-picker.view.ts +722 -0
  368. package/src/monitor/monitor.agent-components.test.ts +410 -0
  369. package/src/monitor/monitor.test.ts +919 -0
  370. package/src/monitor/monitor.threading-utils.test.ts +614 -0
  371. package/src/monitor/native-command-agent-reply.ts +125 -0
  372. package/src/monitor/native-command-arg-ui.ts +233 -0
  373. package/src/monitor/native-command-auth.ts +309 -0
  374. package/src/monitor/native-command-bypass.ts +13 -0
  375. package/src/monitor/native-command-context.test.ts +105 -0
  376. package/src/monitor/native-command-context.ts +109 -0
  377. package/src/monitor/native-command-dispatch.ts +35 -0
  378. package/src/monitor/native-command-model-picker-apply.ts +209 -0
  379. package/src/monitor/native-command-model-picker-interaction.ts +516 -0
  380. package/src/monitor/native-command-model-picker-ui.ts +357 -0
  381. package/src/monitor/native-command-reply.test.ts +68 -0
  382. package/src/monitor/native-command-reply.ts +185 -0
  383. package/src/monitor/native-command-route.ts +91 -0
  384. package/src/monitor/native-command-status.ts +76 -0
  385. package/src/monitor/native-command-ui.ts +26 -0
  386. package/src/monitor/native-command-ui.types.ts +20 -0
  387. package/src/monitor/native-command.args.ts +45 -0
  388. package/src/monitor/native-command.command-arg.test.ts +108 -0
  389. package/src/monitor/native-command.commands-allowfrom.test.ts +504 -0
  390. package/src/monitor/native-command.model-picker.test.ts +930 -0
  391. package/src/monitor/native-command.options.test.ts +379 -0
  392. package/src/monitor/native-command.options.ts +153 -0
  393. package/src/monitor/native-command.plugin-dispatch.test.ts +1212 -0
  394. package/src/monitor/native-command.runtime.ts +51 -0
  395. package/src/monitor/native-command.status-direct.test.ts +278 -0
  396. package/src/monitor/native-command.test-helpers.ts +64 -0
  397. package/src/monitor/native-command.think-autocomplete.test.ts +411 -0
  398. package/src/monitor/native-command.ts +747 -0
  399. package/src/monitor/native-command.types.ts +9 -0
  400. package/src/monitor/native-interaction-channel-context.ts +50 -0
  401. package/src/monitor/preflight-audio.runtime.ts +9 -0
  402. package/src/monitor/preflight-audio.test.ts +157 -0
  403. package/src/monitor/preflight-audio.ts +130 -0
  404. package/src/monitor/presence-cache.ts +61 -0
  405. package/src/monitor/presence.test.ts +61 -0
  406. package/src/monitor/presence.ts +50 -0
  407. package/src/monitor/provider-session.runtime.ts +12 -0
  408. package/src/monitor/provider.acp.ts +89 -0
  409. package/src/monitor/provider.allowlist.test.ts +217 -0
  410. package/src/monitor/provider.allowlist.ts +398 -0
  411. package/src/monitor/provider.cleanup.ts +41 -0
  412. package/src/monitor/provider.commands.ts +129 -0
  413. package/src/monitor/provider.config-log.ts +45 -0
  414. package/src/monitor/provider.deploy-errors.ts +362 -0
  415. package/src/monitor/provider.deploy.ts +221 -0
  416. package/src/monitor/provider.interactions.ts +160 -0
  417. package/src/monitor/provider.lifecycle.test.ts +734 -0
  418. package/src/monitor/provider.lifecycle.ts +562 -0
  419. package/src/monitor/provider.proxy.test.ts +804 -0
  420. package/src/monitor/provider.rest-proxy.test.ts +389 -0
  421. package/src/monitor/provider.runtime.ts +1 -0
  422. package/src/monitor/provider.skill-dedupe.test.ts +42 -0
  423. package/src/monitor/provider.startup-log.ts +32 -0
  424. package/src/monitor/provider.startup.test.ts +440 -0
  425. package/src/monitor/provider.startup.ts +323 -0
  426. package/src/monitor/provider.test.ts +1173 -0
  427. package/src/monitor/provider.ts +688 -0
  428. package/src/monitor/reply-context.ts +64 -0
  429. package/src/monitor/reply-delivery.test.ts +474 -0
  430. package/src/monitor/reply-delivery.ts +212 -0
  431. package/src/monitor/reply-safety.ts +96 -0
  432. package/src/monitor/rest-fetch.ts +94 -0
  433. package/src/monitor/route-resolution.test.ts +209 -0
  434. package/src/monitor/route-resolution.ts +140 -0
  435. package/src/monitor/sender-identity.ts +81 -0
  436. package/src/monitor/startup-status.test.ts +30 -0
  437. package/src/monitor/startup-status.ts +10 -0
  438. package/src/monitor/status.ts +22 -0
  439. package/src/monitor/system-events.ts +55 -0
  440. package/src/monitor/thread-bindings.config.ts +35 -0
  441. package/src/monitor/thread-bindings.discord-api.test.ts +250 -0
  442. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  443. package/src/monitor/thread-bindings.lifecycle.test.ts +1994 -0
  444. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  445. package/src/monitor/thread-bindings.manager.ts +551 -0
  446. package/src/monitor/thread-bindings.messages.ts +6 -0
  447. package/src/monitor/thread-bindings.persona.test.ts +34 -0
  448. package/src/monitor/thread-bindings.persona.ts +25 -0
  449. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  450. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  451. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  452. package/src/monitor/thread-bindings.shared-state.test.ts +39 -0
  453. package/src/monitor/thread-bindings.state.ts +540 -0
  454. package/src/monitor/thread-bindings.ts +48 -0
  455. package/src/monitor/thread-bindings.types.ts +83 -0
  456. package/src/monitor/thread-channel-context.ts +112 -0
  457. package/src/monitor/thread-session-close.test.ts +180 -0
  458. package/src/monitor/thread-session-close.ts +63 -0
  459. package/src/monitor/thread-title.generate.test.ts +209 -0
  460. package/src/monitor/thread-title.test.ts +31 -0
  461. package/src/monitor/thread-title.ts +181 -0
  462. package/src/monitor/threading.auto-thread.test.ts +330 -0
  463. package/src/monitor/threading.auto-thread.ts +287 -0
  464. package/src/monitor/threading.cache.ts +45 -0
  465. package/src/monitor/threading.parent-info.test.ts +156 -0
  466. package/src/monitor/threading.starter.test.ts +279 -0
  467. package/src/monitor/threading.starter.ts +288 -0
  468. package/src/monitor/threading.ts +20 -0
  469. package/src/monitor/threading.types.ts +102 -0
  470. package/src/monitor/timeouts.ts +84 -0
  471. package/src/monitor/typing.test.ts +42 -0
  472. package/src/monitor/typing.ts +17 -0
  473. package/src/monitor.gateway.test.ts +187 -0
  474. package/src/monitor.gateway.ts +75 -0
  475. package/src/monitor.test.ts +1416 -0
  476. package/src/monitor.ts +28 -0
  477. package/src/network-config.test.ts +92 -0
  478. package/src/network-config.ts +79 -0
  479. package/src/normalize.test.ts +56 -0
  480. package/src/normalize.ts +86 -0
  481. package/src/outbound-adapter.interactive-order.test.ts +82 -0
  482. package/src/outbound-adapter.test-harness.ts +207 -0
  483. package/src/outbound-adapter.test.ts +804 -0
  484. package/src/outbound-adapter.ts +326 -0
  485. package/src/outbound-approval.ts +29 -0
  486. package/src/outbound-components.ts +86 -0
  487. package/src/outbound-payload.contract.test.ts +49 -0
  488. package/src/outbound-payload.ts +208 -0
  489. package/src/outbound-send-context.ts +89 -0
  490. package/src/outbound-session-route.test.ts +42 -0
  491. package/src/outbound-session-route.ts +72 -0
  492. package/src/pluralkit.test.ts +67 -0
  493. package/src/pluralkit.ts +58 -0
  494. package/src/preview-streaming.ts +18 -0
  495. package/src/probe.intents.test.ts +94 -0
  496. package/src/probe.parse-token.test.ts +43 -0
  497. package/src/probe.runtime.ts +1 -0
  498. package/src/probe.ts +237 -0
  499. package/src/proxy-fetch.ts +92 -0
  500. package/src/proxy-request-client.test.ts +100 -0
  501. package/src/proxy-request-client.ts +21 -0
  502. package/src/recipient-resolution.ts +39 -0
  503. package/src/resolve-allowlist-common.test.ts +40 -0
  504. package/src/resolve-allowlist-common.ts +39 -0
  505. package/src/resolve-channels.test.ts +341 -0
  506. package/src/resolve-channels.ts +369 -0
  507. package/src/resolve-users.test.ts +243 -0
  508. package/src/resolve-users.ts +184 -0
  509. package/src/retry.test.ts +83 -0
  510. package/src/retry.ts +98 -0
  511. package/src/runtime-api.ts +61 -0
  512. package/src/runtime-config.ts +16 -0
  513. package/src/runtime.ts +23 -0
  514. package/src/secret-config-contract.ts +140 -0
  515. package/src/security-audit.runtime.ts +1 -0
  516. package/src/security-audit.test.ts +245 -0
  517. package/src/security-audit.ts +208 -0
  518. package/src/security-contract.ts +47 -0
  519. package/src/security-doctor.test.ts +25 -0
  520. package/src/security-doctor.ts +20 -0
  521. package/src/security.ts +60 -0
  522. package/src/send-target-parsing.ts +14 -0
  523. package/src/send.channels.ts +139 -0
  524. package/src/send.components.test.ts +330 -0
  525. package/src/send.components.ts +391 -0
  526. package/src/send.creates-thread.test.ts +681 -0
  527. package/src/send.emojis-stickers.ts +57 -0
  528. package/src/send.guild.ts +170 -0
  529. package/src/send.message-request.ts +112 -0
  530. package/src/send.messages.test.ts +59 -0
  531. package/src/send.messages.ts +229 -0
  532. package/src/send.outbound.ts +459 -0
  533. package/src/send.permissions.authz.test.ts +190 -0
  534. package/src/send.permissions.ts +283 -0
  535. package/src/send.reactions.ts +155 -0
  536. package/src/send.receipt.ts +69 -0
  537. package/src/send.sends-basic-channel-messages.test.ts +1068 -0
  538. package/src/send.shared.ts +469 -0
  539. package/src/send.test-harness.ts +56 -0
  540. package/src/send.ts +82 -0
  541. package/src/send.types.ts +191 -0
  542. package/src/send.typing.test.ts +41 -0
  543. package/src/send.typing.ts +9 -0
  544. package/src/send.voice.ts +136 -0
  545. package/src/send.webhook-activity.test.ts +152 -0
  546. package/src/send.webhook.proxy.test.ts +210 -0
  547. package/src/send.webhook.ts +137 -0
  548. package/src/session-contract.ts +3 -0
  549. package/src/session-key-normalization.test.ts +44 -0
  550. package/src/session-key-normalization.ts +47 -0
  551. package/src/setup-account-state.test.ts +113 -0
  552. package/src/setup-account-state.ts +141 -0
  553. package/src/setup-adapter.ts +14 -0
  554. package/src/setup-core.ts +215 -0
  555. package/src/setup-runtime-helpers.ts +10 -0
  556. package/src/setup-surface.test.ts +137 -0
  557. package/src/setup-surface.ts +132 -0
  558. package/src/shared-interactive.test.ts +153 -0
  559. package/src/shared-interactive.ts +161 -0
  560. package/src/shared.test.ts +186 -0
  561. package/src/shared.ts +197 -0
  562. package/src/status-issues.test.ts +97 -0
  563. package/src/status-issues.ts +198 -0
  564. package/src/subagent-hooks.test.ts +465 -0
  565. package/src/subagent-hooks.ts +232 -0
  566. package/src/target-parsing.ts +70 -0
  567. package/src/target-resolver.ts +129 -0
  568. package/src/targets.test.ts +393 -0
  569. package/src/targets.ts +12 -0
  570. package/src/test-http-helpers.ts +10 -0
  571. package/src/test-support/component-runtime.ts +194 -0
  572. package/src/test-support/config.ts +7 -0
  573. package/src/test-support/configured-binding-runtime.ts +29 -0
  574. package/src/test-support/partial-channel.ts +26 -0
  575. package/src/test-support/provider.test-support.ts +547 -0
  576. package/src/token.test.ts +174 -0
  577. package/src/token.ts +107 -0
  578. package/src/ui-colors.ts +27 -0
  579. package/src/ui.ts +20 -0
  580. package/src/voice/access.test.ts +288 -0
  581. package/src/voice/access.ts +126 -0
  582. package/src/voice/audio.test.ts +47 -0
  583. package/src/voice/audio.ts +249 -0
  584. package/src/voice/capture-state.test.ts +48 -0
  585. package/src/voice/capture-state.ts +120 -0
  586. package/src/voice/command.test.ts +170 -0
  587. package/src/voice/command.ts +284 -0
  588. package/src/voice/config.ts +8 -0
  589. package/src/voice/ingress.ts +164 -0
  590. package/src/voice/manager.e2e.test.ts +3286 -0
  591. package/src/voice/manager.ready-listener.test.ts +54 -0
  592. package/src/voice/manager.runtime.ts +14 -0
  593. package/src/voice/manager.ts +1155 -0
  594. package/src/voice/prompt.test.ts +30 -0
  595. package/src/voice/prompt.ts +22 -0
  596. package/src/voice/realtime.ts +1370 -0
  597. package/src/voice/receive-recovery.test.ts +81 -0
  598. package/src/voice/receive-recovery.ts +159 -0
  599. package/src/voice/sanitize.test.ts +34 -0
  600. package/src/voice/sanitize.ts +29 -0
  601. package/src/voice/sdk-runtime.ts +14 -0
  602. package/src/voice/segment.ts +160 -0
  603. package/src/voice/session.ts +81 -0
  604. package/src/voice/speaker-context.ts +127 -0
  605. package/src/voice/tts.ts +151 -0
  606. package/src/voice-message.test.ts +376 -0
  607. package/src/voice-message.ts +474 -0
  608. package/subagent-hooks-api.ts +27 -0
  609. package/test-api.ts +4 -0
  610. package/thread-binding-api.ts +1 -0
  611. package/timeouts.ts +6 -0
  612. package/tsconfig.json +16 -0
  613. package/account-inspect-api.js +0 -7
  614. package/action-runtime-api.js +0 -7
  615. package/api.js +0 -7
  616. package/channel-config-api.js +0 -7
  617. package/channel-plugin-api.js +0 -7
  618. package/configured-state.js +0 -7
  619. package/contract-api.js +0 -7
  620. package/directory-contract-api.js +0 -7
  621. package/doctor-contract-api.js +0 -7
  622. package/index.js +0 -7
  623. package/runtime-api.actions.js +0 -7
  624. package/runtime-api.js +0 -7
  625. package/runtime-api.lookup.js +0 -7
  626. package/runtime-api.monitor.js +0 -7
  627. package/runtime-api.send.js +0 -7
  628. package/runtime-api.threads.js +0 -7
  629. package/runtime-setter-api.js +0 -7
  630. package/secret-contract-api.js +0 -7
  631. package/security-audit-contract-api.js +0 -7
  632. package/security-contract-api.js +0 -7
  633. package/session-key-api.js +0 -7
  634. package/setup-entry.js +0 -7
  635. package/setup-plugin-api.js +0 -7
  636. package/subagent-hooks-api.js +0 -7
  637. package/test-api.js +0 -7
  638. package/thread-binding-api.js +0 -7
  639. package/timeouts.js +0 -7
@@ -0,0 +1,1113 @@
1
+ import { A as Message, c as discord_exports, mt as getChannelMessage } from "./send.receipt-CDn3GBWC.js";
2
+ import { o as resolveDefaultDiscordAccountId } from "./accounts-B7OBFePq.js";
3
+ import { S as resolveTimestampMs, _ as resolveGroupDmAllow, a as normalizeDiscordSlug, b as formatDiscordUserTag, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, f as resolveDiscordMemberAccessState, g as resolveDiscordShouldRequireMention, i as normalizeDiscordDisplaySlug, n as isDiscordGroupAllowedByPolicy, x as resolveDiscordSystemLocation } from "./allow-list-B0s7evD7.js";
4
+ import { t as resolveDiscordConversationIdentity } from "./conversation-identity-DXAm0_Mk.js";
5
+ import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-eTFl-PqJ.js";
6
+ import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-ssGH5wc2.js";
7
+ import "./thread-bindings-9aKRmZv0.js";
8
+ import { C as resolveDiscordDmCommandAccess, f as buildDiscordRoutePeer, g as handleDiscordDmCommandDecision, h as shouldIgnoreStaleDiscordRouteBinding, m as resolveDiscordEffectiveRoute, p as resolveDiscordConversationRoute, w as resolveDiscordTextCommandAccess } from "./provider-B2-31CIT.js";
9
+ import { d as resolveDiscordMessageChannelId, l as resolveDiscordMessageStickers, o as resolveMediaList, r as resolveDiscordMessageText, u as resolveDiscordChannelInfo } from "./message-utils-dUbem16p.js";
10
+ import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-CxCe3_1a.js";
11
+ import { normalizeOptionalString } from "klaw/plugin-sdk/string-coerce-runtime";
12
+ import { getChildLogger, logVerbose, shouldLogVerbose } from "klaw/plugin-sdk/runtime-env";
13
+ import { recordChannelActivity } from "klaw/plugin-sdk/channel-activity-runtime";
14
+ import { formatAllowlistMatchMeta } from "klaw/plugin-sdk/allow-from";
15
+ import { isDangerousNameMatchingEnabled } from "klaw/plugin-sdk/dangerous-name-runtime";
16
+ import { enqueueSystemEvent } from "klaw/plugin-sdk/system-event-runtime";
17
+ import { mimeTypeFromFilePath } from "klaw/plugin-sdk/media-mime";
18
+ import { buildMentionRegexes, classifyChannelInboundEvent, implicitMentionKindWhen, logInboundDrop, matchesMentionWithExplicit, resolveInboundMentionDecision, resolveUnmentionedGroupInboundPolicy, toInboundMediaFacts } from "klaw/plugin-sdk/channel-inbound";
19
+ import { logDebug } from "klaw/plugin-sdk/logging-core";
20
+ import { recordDroppedChannelTurnHistory } from "klaw/plugin-sdk/inbound-reply-dispatch";
21
+ import { hasControlCommand } from "klaw/plugin-sdk/command-detection";
22
+ import { isAbortRequestText } from "klaw/plugin-sdk/command-primitives-runtime";
23
+ import { shouldHandleTextCommands } from "klaw/plugin-sdk/command-surface";
24
+ //#region extensions/discord/src/monitor/message-handler.dm-preflight.ts
25
+ let conversationRuntimePromise$1;
26
+ let discordSendRuntimePromise;
27
+ async function loadConversationRuntime$1() {
28
+ conversationRuntimePromise$1 ??= import("klaw/plugin-sdk/conversation-binding-runtime");
29
+ return await conversationRuntimePromise$1;
30
+ }
31
+ async function loadDiscordSendRuntime() {
32
+ discordSendRuntimePromise ??= import("./send-DCtPCHGk.js").then((n) => n.t);
33
+ return await discordSendRuntimePromise;
34
+ }
35
+ async function resolveDiscordDmPreflightAccess(params) {
36
+ if (params.dmPolicy === "disabled") {
37
+ logVerbose("discord: drop dm (dmPolicy: disabled)");
38
+ return null;
39
+ }
40
+ const directBindingConversationId = resolveDiscordConversationIdentity({
41
+ isDirectMessage: true,
42
+ userId: params.author.id
43
+ }) ?? `user:${params.author.id}`;
44
+ const directBindingRecord = (await loadConversationRuntime$1()).getSessionBindingService().resolveByConversation({
45
+ channel: "discord",
46
+ accountId: params.preflight.accountId,
47
+ conversationId: directBindingConversationId
48
+ });
49
+ const dmAccess = await resolveDiscordDmCommandAccess({
50
+ accountId: params.resolvedAccountId,
51
+ dmPolicy: params.dmPolicy,
52
+ configuredAllowFrom: params.preflight.allowFrom ?? [],
53
+ sender: {
54
+ id: params.sender.id,
55
+ name: params.sender.name,
56
+ tag: params.sender.tag
57
+ },
58
+ allowNameMatching: params.allowNameMatching,
59
+ cfg: params.preflight.cfg,
60
+ token: params.preflight.token,
61
+ rest: params.preflight.client.rest
62
+ });
63
+ const commandAuthorized = dmAccess.senderAccess.allowed && dmAccess.commandAccess.authorized || directBindingRecord != null;
64
+ if (dmAccess.senderAccess.decision === "allow") return { commandAuthorized };
65
+ if (directBindingRecord) {
66
+ logVerbose(`discord: allow bound DM conversation ${directBindingConversationId} despite dmPolicy=${params.dmPolicy}`);
67
+ return { commandAuthorized };
68
+ }
69
+ await handleDiscordDmCommandDecision({
70
+ senderAccess: dmAccess.senderAccess,
71
+ accountId: params.resolvedAccountId,
72
+ sender: {
73
+ id: params.author.id,
74
+ tag: formatDiscordUserTag(params.author),
75
+ name: params.author.username ?? void 0
76
+ },
77
+ onPairingCreated: async (code) => {
78
+ logVerbose(`discord pairing request sender=${params.author.id} tag=${formatDiscordUserTag(params.author)} reason=${dmAccess.senderAccess.reasonCode}`);
79
+ try {
80
+ const conversationRuntime = await loadConversationRuntime$1();
81
+ const { sendMessageDiscord } = await loadDiscordSendRuntime();
82
+ await sendMessageDiscord(`user:${params.author.id}`, conversationRuntime.buildPairingReply({
83
+ channel: "discord",
84
+ idLine: `Your Discord user id: ${params.author.id}`,
85
+ code
86
+ }), {
87
+ cfg: params.preflight.cfg,
88
+ token: params.preflight.token,
89
+ rest: params.preflight.client.rest,
90
+ accountId: params.preflight.accountId
91
+ });
92
+ } catch (err) {
93
+ logVerbose(`discord pairing reply failed for ${params.author.id}: ${String(err)}`);
94
+ }
95
+ },
96
+ onUnauthorized: async () => {
97
+ logVerbose(`Blocked unauthorized discord sender ${params.sender.id} (dmPolicy=${params.dmPolicy}, reason=${dmAccess.senderAccess.reasonCode})`);
98
+ }
99
+ });
100
+ return null;
101
+ }
102
+ //#endregion
103
+ //#region extensions/discord/src/monitor/message-handler.hydration.ts
104
+ function mergeFetchedDiscordMessage(base, fetched) {
105
+ const baseRawData = readMessageRawData(base);
106
+ const baseFallback = readMessageFallback(base);
107
+ const rawData = {
108
+ ...baseRawData,
109
+ ...fetched,
110
+ id: fetched.id ?? baseRawData.id ?? baseFallback.id,
111
+ channel_id: fetched.channel_id ?? baseRawData.channel_id ?? baseFallback.channel_id,
112
+ content: fetched.content ?? baseRawData.content ?? baseFallback.content,
113
+ author: fetched.author ?? baseRawData.author ?? baseFallback.author,
114
+ attachments: fetched.attachments ?? baseRawData.attachments ?? baseFallback.attachments,
115
+ embeds: fetched.embeds ?? baseRawData.embeds ?? baseFallback.embeds,
116
+ mentions: fetched.mentions ?? baseRawData.mentions ?? baseFallback.mentions,
117
+ mention_roles: fetched.mention_roles ?? baseRawData.mention_roles ?? baseFallback.mention_roles,
118
+ mention_everyone: fetched.mention_everyone ?? baseRawData.mention_everyone ?? baseFallback.mention_everyone,
119
+ timestamp: fetched.timestamp ?? baseRawData.timestamp ?? baseFallback.timestamp,
120
+ tts: fetched.tts ?? baseRawData.tts ?? false,
121
+ pinned: fetched.pinned ?? baseRawData.pinned ?? false,
122
+ type: fetched.type ?? baseRawData.type ?? 0,
123
+ message_snapshots: fetched.message_snapshots ?? baseRawData.message_snapshots ?? baseFallback.message_snapshots,
124
+ sticker_items: fetched.sticker_items ?? baseRawData.sticker_items ?? baseFallback.sticker_items
125
+ };
126
+ const hydrated = new Message(readMessageClient(base), rawData);
127
+ copyRuntimeMessageFields(base, hydrated);
128
+ return hydrated;
129
+ }
130
+ function readMessageClient(message) {
131
+ return message.client;
132
+ }
133
+ function readMessageRawData(message) {
134
+ try {
135
+ const rawData = message.rawData;
136
+ return rawData && typeof rawData === "object" ? rawData : {};
137
+ } catch {
138
+ return {};
139
+ }
140
+ }
141
+ function readMessageFallback(message) {
142
+ const value = message;
143
+ return {
144
+ id: typeof value.id === "string" ? value.id : "",
145
+ channel_id: readString(value.channel_id) ?? readString(value.channelId) ?? "",
146
+ content: typeof value.content === "string" ? value.content : "",
147
+ author: normalizeApiUser(value.author),
148
+ attachments: Array.isArray(value.attachments) ? value.attachments : [],
149
+ embeds: Array.isArray(value.embeds) ? value.embeds : [],
150
+ mentions: normalizeApiUsers(value.mentionedUsers),
151
+ mention_roles: normalizeStringArray(value.mentionedRoles),
152
+ mention_everyone: value.mentionedEveryone === true,
153
+ timestamp: readString(value.timestamp) ?? "1970-01-01T00:00:00.000Z",
154
+ sticker_items: Array.isArray(value.sticker_items) ? value.sticker_items : Array.isArray(value.stickers) ? value.stickers : void 0,
155
+ message_snapshots: Array.isArray(value.message_snapshots) ? value.message_snapshots : void 0
156
+ };
157
+ }
158
+ function readString(value) {
159
+ return typeof value === "string" ? value : void 0;
160
+ }
161
+ function normalizeStringArray(value) {
162
+ return Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" ? [entry] : []) : [];
163
+ }
164
+ function normalizeApiUsers(value) {
165
+ return Array.isArray(value) ? value.flatMap((entry) => {
166
+ const user = normalizeApiUser(entry);
167
+ return user.id ? [user] : [];
168
+ }) : [];
169
+ }
170
+ function normalizeApiUser(value) {
171
+ if (!value || typeof value !== "object") return {
172
+ id: "",
173
+ username: "",
174
+ discriminator: "0",
175
+ global_name: null,
176
+ avatar: null
177
+ };
178
+ const input = value;
179
+ return {
180
+ id: readString(input.id) ?? "",
181
+ username: readString(input.username) ?? "",
182
+ discriminator: readString(input.discriminator) ?? "0",
183
+ global_name: readString(input.global_name) ?? readString(input.globalName) ?? null,
184
+ avatar: input.avatar === null ? null : readString(input.avatar) ?? null,
185
+ ...typeof input.bot === "boolean" ? { bot: input.bot } : {}
186
+ };
187
+ }
188
+ function copyRuntimeMessageFields(source, target) {
189
+ const channelDescriptor = Object.getOwnPropertyDescriptor(source, "channel");
190
+ if (channelDescriptor) Object.defineProperty(target, "channel", channelDescriptor);
191
+ }
192
+ function shouldHydrateDiscordMessage(params) {
193
+ let currentText = "";
194
+ try {
195
+ currentText = resolveDiscordMessageText(params.message, { includeForwarded: true });
196
+ } catch {
197
+ return true;
198
+ }
199
+ if (!currentText) return true;
200
+ if ((params.message.mentionedUsers?.length ?? 0) > 0 || (params.message.mentionedRoles?.length ?? 0) > 0 || params.message.mentionedEveryone) return false;
201
+ return /<@!?\d+>|<@&\d+>|@everyone|@here/u.test(currentText);
202
+ }
203
+ async function hydrateDiscordMessageIfNeeded(params) {
204
+ params.channelInfo;
205
+ if (!shouldHydrateDiscordMessage({ message: params.message })) return params.message;
206
+ try {
207
+ const fetched = await getChannelMessage(params.client.rest, params.messageChannelId, params.message.id);
208
+ if (!fetched) return params.message;
209
+ logVerbose(`discord: hydrated inbound payload via REST for ${params.message.id}`);
210
+ return mergeFetchedDiscordMessage(params.message, fetched);
211
+ } catch (err) {
212
+ logVerbose(`discord: failed to hydrate message ${params.message.id}: ${String(err)}`);
213
+ return params.message;
214
+ }
215
+ }
216
+ //#endregion
217
+ //#region extensions/discord/src/monitor/message-handler.preflight-channel-access.ts
218
+ function resolveDiscordPreflightChannelAccess(params) {
219
+ if (params.isGuildMessage && params.channelConfig?.enabled === false) {
220
+ logDebug(`[discord-preflight] drop: channel disabled`);
221
+ logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
222
+ return {
223
+ allowed: false,
224
+ channelAllowlistConfigured: false,
225
+ channelAllowed: false
226
+ };
227
+ }
228
+ const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
229
+ channels: params.groupDmChannels,
230
+ channelId: params.messageChannelId,
231
+ channelName: params.displayChannelName,
232
+ channelSlug: params.displayChannelSlug
233
+ });
234
+ if (params.isGroupDm && !groupDmAllowed) return {
235
+ allowed: false,
236
+ channelAllowlistConfigured: false,
237
+ channelAllowed: false
238
+ };
239
+ const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
240
+ const channelAllowed = params.channelConfig?.allowed !== false;
241
+ if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
242
+ groupPolicy: params.groupPolicy,
243
+ guildAllowlisted: Boolean(params.guildInfo),
244
+ channelAllowlistConfigured,
245
+ channelAllowed
246
+ })) {
247
+ if (params.groupPolicy === "disabled") {
248
+ logDebug(`[discord-preflight] drop: groupPolicy disabled`);
249
+ logVerbose(`discord: drop guild message (groupPolicy: disabled, ${params.channelMatchMeta})`);
250
+ } else if (!channelAllowlistConfigured) {
251
+ logDebug(`[discord-preflight] drop: groupPolicy allowlist, no channel allowlist configured`);
252
+ logVerbose(`discord: drop guild message (groupPolicy: allowlist, no channel allowlist, ${params.channelMatchMeta})`);
253
+ } else {
254
+ logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
255
+ logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
256
+ }
257
+ return {
258
+ allowed: false,
259
+ channelAllowlistConfigured,
260
+ channelAllowed
261
+ };
262
+ }
263
+ if (params.isGuildMessage && params.channelConfig?.allowed === false) {
264
+ logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
265
+ logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
266
+ return {
267
+ allowed: false,
268
+ channelAllowlistConfigured,
269
+ channelAllowed
270
+ };
271
+ }
272
+ if (params.isGuildMessage) {
273
+ logDebug(`[discord-preflight] pass: channel allowed`);
274
+ logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
275
+ }
276
+ return {
277
+ allowed: true,
278
+ channelAllowlistConfigured,
279
+ channelAllowed
280
+ };
281
+ }
282
+ //#endregion
283
+ //#region extensions/discord/src/monitor/message-handler.preflight-channel-context.ts
284
+ function resolveDiscordPreflightChannelContext(params) {
285
+ const threadName = params.threadChannel?.name;
286
+ const configChannelName = params.threadParentName ?? params.channelName;
287
+ const configChannelSlug = configChannelName ? normalizeDiscordSlug(configChannelName) : "";
288
+ const displayChannelName = threadName ?? params.channelName;
289
+ const displayChannelSlug = displayChannelName ? normalizeDiscordDisplaySlug(displayChannelName) : "";
290
+ const guildSlug = params.guildInfo?.slug || (params.guildName ? normalizeDiscordSlug(params.guildName) : "");
291
+ const threadChannelSlug = params.channelName ? normalizeDiscordSlug(params.channelName) : "";
292
+ const threadParentSlug = params.threadParentName ? normalizeDiscordSlug(params.threadParentName) : "";
293
+ return {
294
+ threadName,
295
+ configChannelName,
296
+ configChannelSlug,
297
+ displayChannelName,
298
+ displayChannelSlug,
299
+ guildSlug,
300
+ threadChannelSlug,
301
+ threadParentSlug,
302
+ channelConfig: params.isGuildMessage ? resolveDiscordChannelConfigWithFallback({
303
+ guildInfo: params.guildInfo,
304
+ channelId: params.messageChannelId,
305
+ channelName: params.channelName,
306
+ channelSlug: threadChannelSlug,
307
+ parentId: params.threadParentId,
308
+ parentName: params.threadParentName,
309
+ parentSlug: threadParentSlug,
310
+ scope: params.threadChannel ? "thread" : "channel"
311
+ }) : null
312
+ };
313
+ }
314
+ //#endregion
315
+ //#region extensions/discord/src/monitor/message-handler.preflight-context.ts
316
+ function buildDiscordMessagePreflightContext({ preflightParams, ...fields }) {
317
+ return {
318
+ cfg: preflightParams.cfg,
319
+ discordConfig: preflightParams.discordConfig,
320
+ accountId: preflightParams.accountId,
321
+ token: preflightParams.token,
322
+ runtime: preflightParams.runtime,
323
+ botUserId: preflightParams.botUserId,
324
+ abortSignal: preflightParams.abortSignal,
325
+ guildHistories: preflightParams.guildHistories,
326
+ historyLimit: preflightParams.historyLimit,
327
+ mediaMaxBytes: preflightParams.mediaMaxBytes,
328
+ textLimit: preflightParams.textLimit,
329
+ replyToMode: preflightParams.replyToMode,
330
+ ackReactionScope: preflightParams.ackReactionScope,
331
+ groupPolicy: preflightParams.groupPolicy,
332
+ ...fields,
333
+ threadBindings: preflightParams.threadBindings,
334
+ discordRestFetch: preflightParams.discordRestFetch
335
+ };
336
+ }
337
+ //#endregion
338
+ //#region extensions/discord/src/monitor/message-handler.preflight-helpers.ts
339
+ const DISCORD_BOUND_THREAD_SYSTEM_PREFIXES = [
340
+ "⚙️",
341
+ "🤖",
342
+ "🧰"
343
+ ];
344
+ function isBoundThreadBotSystemMessage(params) {
345
+ if (!params.isBoundThreadSession || !params.isBotAuthor) return false;
346
+ const text = params.text?.trim();
347
+ if (!text) return false;
348
+ return DISCORD_BOUND_THREAD_SYSTEM_PREFIXES.some((prefix) => text.startsWith(prefix));
349
+ }
350
+ function isDiscordThreadChannelType(type) {
351
+ return type === discord_exports.ChannelType.PublicThread || type === discord_exports.ChannelType.PrivateThread || type === discord_exports.ChannelType.AnnouncementThread;
352
+ }
353
+ function isDiscordThreadChannelMessage(params) {
354
+ if (!params.isGuildMessage) return false;
355
+ const channel = "channel" in params.message ? params.message.channel : void 0;
356
+ return Boolean(channel && typeof channel === "object" && "isThread" in channel && typeof channel.isThread === "function" && channel.isThread() || isDiscordThreadChannelType(params.channelInfo?.type));
357
+ }
358
+ function resolveInjectedBoundThreadLookupRecord(params) {
359
+ const getByThreadId = params.threadBindings.getByThreadId;
360
+ if (typeof getByThreadId !== "function") return;
361
+ const binding = getByThreadId(params.threadId);
362
+ return binding && typeof binding === "object" ? binding : void 0;
363
+ }
364
+ function resolveDiscordMentionState(params) {
365
+ if (params.isDirectMessage) return {
366
+ implicitMentionKinds: [],
367
+ wasMentioned: false
368
+ };
369
+ const wasMentioned = params.mentionedEveryone && (!params.authorIsBot || params.senderIsPluralKit) || matchesMentionWithExplicit({
370
+ text: params.mentionText,
371
+ mentionRegexes: params.mentionRegexes,
372
+ explicit: {
373
+ hasAnyMention: params.hasAnyMention,
374
+ isExplicitlyMentioned: params.isExplicitlyMentioned,
375
+ canResolveExplicit: Boolean(params.botId)
376
+ },
377
+ transcript: params.transcript
378
+ });
379
+ return {
380
+ implicitMentionKinds: implicitMentionKindWhen("reply_to_bot", Boolean(params.botId) && Boolean(params.referencedAuthorId) && params.referencedAuthorId === params.botId),
381
+ wasMentioned
382
+ };
383
+ }
384
+ function resolvePreflightMentionRequirement(params) {
385
+ if (!params.shouldRequireMention) return false;
386
+ return !params.bypassMentionRequirement;
387
+ }
388
+ function shouldIgnoreBoundThreadWebhookMessage(params) {
389
+ const webhookId = normalizeOptionalString(params.webhookId) ?? "";
390
+ if (!webhookId) return false;
391
+ const boundWebhookId = normalizeOptionalString(params.threadBinding?.webhookId) ?? normalizeOptionalString(params.threadBinding?.metadata?.webhookId) ?? "";
392
+ if (boundWebhookId && webhookId === boundWebhookId) return true;
393
+ const threadId = normalizeOptionalString(params.threadId) ?? "";
394
+ if (!threadId) return false;
395
+ if (params.threadBinding) return true;
396
+ return isRecentlyUnboundThreadWebhookMessage({
397
+ accountId: params.accountId,
398
+ threadId,
399
+ webhookId
400
+ });
401
+ }
402
+ //#endregion
403
+ //#region extensions/discord/src/monitor/message-handler.preflight-history.ts
404
+ function buildDiscordPreflightHistoryEntry(params) {
405
+ const textForHistory = resolveDiscordMessageText(params.message, { includeForwarded: true });
406
+ return params.isGuildMessage && params.historyLimit > 0 && textForHistory ? {
407
+ sender: params.senderLabel,
408
+ body: textForHistory,
409
+ timestamp: resolveTimestampMs(params.message.timestamp),
410
+ messageId: params.message.id
411
+ } : void 0;
412
+ }
413
+ //#endregion
414
+ //#region extensions/discord/src/monitor/message-handler.preflight-logging.ts
415
+ function logDiscordPreflightChannelConfig(params) {
416
+ if (!shouldLogVerbose()) return;
417
+ logDebug(`[discord-preflight] channelConfig=${params.channelConfig ? `allowed=${params.channelConfig.allowed} enabled=${params.channelConfig.enabled ?? "unset"} requireMention=${params.channelConfig.requireMention ?? "unset"} ignoreOtherMentions=${params.channelConfig.ignoreOtherMentions ?? "unset"} matchKey=${params.channelConfig.matchKey ?? "none"} matchSource=${params.channelConfig.matchSource ?? "none"} users=${params.channelConfig.users?.length ?? 0} roles=${params.channelConfig.roles?.length ?? 0} skills=${params.channelConfig.skills?.length ?? 0}` : "none"} channelMatchMeta=${params.channelMatchMeta} channelId=${params.channelId}`);
418
+ }
419
+ function logDiscordPreflightInboundSummary(params) {
420
+ if (!shouldLogVerbose()) return;
421
+ logVerbose(`discord: inbound id=${params.messageId} guild=${params.guildId ?? "dm"} channel=${params.channelId} mention=${params.wasMentioned ? "yes" : "no"} type=${params.isDirectMessage ? "dm" : params.isGroupDm ? "group-dm" : "guild"} content=${params.hasContent ? "yes" : "no"}`);
422
+ }
423
+ //#endregion
424
+ //#region extensions/discord/src/monitor/message-handler.preflight-runtime.ts
425
+ let pluralkitRuntimePromise;
426
+ let preflightAudioRuntimePromise;
427
+ let systemEventsRuntimePromise;
428
+ let discordThreadingRuntimePromise;
429
+ async function loadPluralKitRuntime() {
430
+ pluralkitRuntimePromise ??= import("./pluralkit-D1Q2x0w5.js").then((n) => n.n);
431
+ return await pluralkitRuntimePromise;
432
+ }
433
+ async function loadPreflightAudioRuntime() {
434
+ preflightAudioRuntimePromise ??= import("./preflight-audio-CZtpWcIm.js");
435
+ return await preflightAudioRuntimePromise;
436
+ }
437
+ async function loadSystemEventsRuntime() {
438
+ systemEventsRuntimePromise ??= import("./system-events-Ba1TklaL.js");
439
+ return await systemEventsRuntimePromise;
440
+ }
441
+ async function loadDiscordThreadingRuntime() {
442
+ discordThreadingRuntimePromise ??= import("./provider-B2-31CIT.js").then((n) => n.v);
443
+ return await discordThreadingRuntimePromise;
444
+ }
445
+ function isPreflightAborted(abortSignal) {
446
+ return Boolean(abortSignal?.aborted);
447
+ }
448
+ //#endregion
449
+ //#region extensions/discord/src/monitor/message-handler.preflight-pluralkit.ts
450
+ async function resolveDiscordPreflightPluralKitInfo(params) {
451
+ if (!params.config?.enabled) return null;
452
+ try {
453
+ const { fetchPluralKitMessageInfo } = await loadPluralKitRuntime();
454
+ const info = await fetchPluralKitMessageInfo({
455
+ messageId: params.message.id,
456
+ config: params.config
457
+ });
458
+ return isPreflightAborted(params.abortSignal) ? null : info;
459
+ } catch (err) {
460
+ logVerbose(`discord: pluralkit lookup failed for ${params.message.id}: ${String(err)}`);
461
+ return null;
462
+ }
463
+ }
464
+ //#endregion
465
+ //#region extensions/discord/src/monitor/message-handler.preflight-thread.ts
466
+ async function resolveDiscordPreflightThreadContext(params) {
467
+ const { resolveDiscordThreadChannel, resolveDiscordThreadParentInfo } = await loadDiscordThreadingRuntime();
468
+ const earlyThreadChannel = resolveDiscordThreadChannel({
469
+ isGuildMessage: params.isGuildMessage,
470
+ message: params.message,
471
+ channelInfo: params.channelInfo,
472
+ messageChannelId: params.messageChannelId
473
+ });
474
+ if (!earlyThreadChannel) return { earlyThreadChannel: null };
475
+ const parentInfo = await resolveDiscordThreadParentInfo({
476
+ client: params.client,
477
+ threadChannel: earlyThreadChannel,
478
+ channelInfo: params.channelInfo
479
+ });
480
+ if (isPreflightAborted(params.abortSignal)) return null;
481
+ return {
482
+ earlyThreadChannel,
483
+ earlyThreadParentId: parentInfo.id,
484
+ earlyThreadParentName: parentInfo.name,
485
+ earlyThreadParentType: parentInfo.type
486
+ };
487
+ }
488
+ //#endregion
489
+ //#region extensions/discord/src/monitor/message-handler.routing-preflight.ts
490
+ let conversationRuntimePromise;
491
+ async function loadConversationRuntime() {
492
+ conversationRuntimePromise ??= import("klaw/plugin-sdk/conversation-binding-runtime");
493
+ return await conversationRuntimePromise;
494
+ }
495
+ async function resolveDiscordPreflightRoute(params) {
496
+ const conversationRuntime = await loadConversationRuntime();
497
+ const route = resolveDiscordConversationRoute({
498
+ cfg: params.preflight.cfg,
499
+ accountId: params.preflight.accountId,
500
+ guildId: params.preflight.data.guild_id ?? void 0,
501
+ memberRoleIds: params.memberRoleIds,
502
+ peer: buildDiscordRoutePeer({
503
+ isDirectMessage: params.isDirectMessage,
504
+ isGroupDm: params.isGroupDm,
505
+ directUserId: params.author.id,
506
+ conversationId: params.messageChannelId
507
+ }),
508
+ parentConversationId: params.earlyThreadParentId
509
+ });
510
+ const bindingConversationId = params.isDirectMessage ? resolveDiscordConversationIdentity({
511
+ isDirectMessage: true,
512
+ userId: params.author.id
513
+ }) ?? `user:${params.author.id}` : params.messageChannelId;
514
+ let runtimeRoute = conversationRuntime.resolveRuntimeConversationBindingRoute({
515
+ route,
516
+ conversation: {
517
+ channel: "discord",
518
+ accountId: params.preflight.accountId,
519
+ conversationId: bindingConversationId,
520
+ parentConversationId: params.earlyThreadParentId
521
+ }
522
+ });
523
+ if (shouldIgnoreStaleDiscordRouteBinding({
524
+ bindingRecord: runtimeRoute.bindingRecord,
525
+ route
526
+ })) {
527
+ logVerbose(`discord: ignoring stale route binding for conversation ${bindingConversationId} (${runtimeRoute.bindingRecord?.targetSessionKey} -> ${route.sessionKey})`);
528
+ runtimeRoute = {
529
+ bindingRecord: null,
530
+ route
531
+ };
532
+ }
533
+ let threadBinding = runtimeRoute.bindingRecord ?? void 0;
534
+ const configuredRoute = threadBinding == null ? conversationRuntime.resolveConfiguredBindingRoute({
535
+ cfg: params.preflight.cfg,
536
+ route,
537
+ conversation: {
538
+ channel: "discord",
539
+ accountId: params.preflight.accountId,
540
+ conversationId: params.messageChannelId,
541
+ parentConversationId: params.earlyThreadParentId
542
+ }
543
+ }) : null;
544
+ const configuredBinding = configuredRoute?.bindingResolution ?? null;
545
+ if (!threadBinding && configuredBinding) threadBinding = configuredBinding.record;
546
+ const boundSessionKey = conversationRuntime.isPluginOwnedSessionBindingRecord(threadBinding) ? "" : runtimeRoute.boundSessionKey ?? threadBinding?.targetSessionKey?.trim();
547
+ const effectiveRoute = runtimeRoute.boundSessionKey ? runtimeRoute.route : resolveDiscordEffectiveRoute({
548
+ route,
549
+ boundSessionKey,
550
+ configuredRoute,
551
+ matchedBy: "binding.channel"
552
+ });
553
+ return {
554
+ conversationRuntime,
555
+ threadBinding,
556
+ configuredBinding,
557
+ boundSessionKey,
558
+ effectiveRoute,
559
+ boundAgentId: boundSessionKey ? effectiveRoute.agentId : void 0,
560
+ baseSessionKey: effectiveRoute.sessionKey
561
+ };
562
+ }
563
+ //#endregion
564
+ //#region extensions/discord/src/monitor/message-handler.preflight.ts
565
+ const DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
566
+ const DISCORD_HISTORY_MEDIA_MAX_BYTES = 10 * 1024 * 1024;
567
+ const DISCORD_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
568
+ const DISCORD_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
569
+ function resolveDiscordPreflightConversationKind(params) {
570
+ const isGroupDm = params.channelType === discord_exports.ChannelType.GroupDM;
571
+ return {
572
+ isDirectMessage: params.channelType === discord_exports.ChannelType.DM || !params.isGuildMessage && !isGroupDm && params.channelType == null,
573
+ isGroupDm
574
+ };
575
+ }
576
+ function isDiscordImageAttachmentCandidate(attachment) {
577
+ if ((attachment.content_type?.split(";")[0]?.trim().toLowerCase())?.startsWith("image/")) return true;
578
+ return Boolean(mimeTypeFromFilePath(attachment.filename)?.startsWith("image/") || mimeTypeFromFilePath(attachment.url)?.startsWith("image/"));
579
+ }
580
+ async function resolveDiscordHistoryMediaForPendingRecord(params) {
581
+ const imageAttachments = (params.message.attachments ?? []).filter(isDiscordImageAttachmentCandidate).slice(0, DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS);
582
+ const stickers = resolveDiscordMessageStickers(params.message).slice(0, Math.max(0, DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS - imageAttachments.length));
583
+ if (imageAttachments.length === 0 && stickers.length === 0) return [];
584
+ const rawData = (() => {
585
+ try {
586
+ return params.message.rawData;
587
+ } catch {
588
+ return {};
589
+ }
590
+ })();
591
+ const mediaMessage = Object.assign(Object.create(Object.getPrototypeOf(params.message)), params.message);
592
+ Object.defineProperties(mediaMessage, {
593
+ attachments: { value: imageAttachments },
594
+ rawData: { value: {
595
+ ...rawData,
596
+ attachments: imageAttachments,
597
+ sticker_items: stickers,
598
+ stickers
599
+ } },
600
+ stickers: { value: stickers }
601
+ });
602
+ return toInboundMediaFacts(await resolveMediaList(mediaMessage, Math.min(params.preflight.mediaMaxBytes, DISCORD_HISTORY_MEDIA_MAX_BYTES), {
603
+ fetchImpl: params.preflight.discordRestFetch,
604
+ ssrfPolicy: params.preflight.cfg.browser?.ssrfPolicy,
605
+ readIdleTimeoutMs: DISCORD_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
606
+ totalTimeoutMs: DISCORD_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
607
+ abortSignal: params.preflight.abortSignal
608
+ }), {
609
+ kind: "image",
610
+ messageId: params.message.id
611
+ });
612
+ }
613
+ async function recordDiscordPendingHistoryEntry(params) {
614
+ if (params.preflight.historyLimit <= 0) return;
615
+ await recordDroppedChannelTurnHistory({
616
+ input: {
617
+ id: params.message.id,
618
+ timestamp: params.entry?.timestamp,
619
+ rawText: params.entry?.body ?? "",
620
+ textForAgent: params.entry?.body,
621
+ raw: params.message
622
+ },
623
+ admission: {
624
+ kind: "drop",
625
+ reason: "discord-preflight",
626
+ recordHistory: true
627
+ },
628
+ preflight: {
629
+ message: params.entry ? {
630
+ rawBody: params.entry.body,
631
+ body: params.entry.body,
632
+ bodyForAgent: params.entry.body,
633
+ senderLabel: params.entry.sender,
634
+ envelopeFrom: params.entry.sender
635
+ } : void 0,
636
+ history: {
637
+ key: params.historyKey,
638
+ historyMap: params.preflight.guildHistories,
639
+ limit: params.preflight.historyLimit,
640
+ recordOnDrop: true,
641
+ mediaLimit: DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS,
642
+ shouldRecord: () => !isPreflightAborted(params.preflight.abortSignal)
643
+ },
644
+ media: () => resolveDiscordHistoryMediaForPendingRecord({
645
+ preflight: params.preflight,
646
+ message: params.message
647
+ })
648
+ }
649
+ });
650
+ }
651
+ async function preflightDiscordMessage(params) {
652
+ if (isPreflightAborted(params.abortSignal)) return null;
653
+ const logger = getChildLogger({ module: "discord-auto-reply" });
654
+ let message = params.data.message;
655
+ const author = params.data.author;
656
+ if (!author) return null;
657
+ const messageChannelId = resolveDiscordMessageChannelId({
658
+ message,
659
+ eventChannelId: params.data.channel_id
660
+ });
661
+ if (!messageChannelId) {
662
+ logVerbose(`discord: drop message ${message.id} (missing channel id)`);
663
+ return null;
664
+ }
665
+ const allowBotsSetting = params.discordConfig?.allowBots;
666
+ const allowBotsMode = allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting === true ? "all" : "off";
667
+ if (params.botUserId && author.id === params.botUserId) return null;
668
+ message = await hydrateDiscordMessageIfNeeded({
669
+ client: params.client,
670
+ message,
671
+ messageChannelId
672
+ });
673
+ if (isPreflightAborted(params.abortSignal)) return null;
674
+ const pluralkitConfig = params.discordConfig?.pluralkit;
675
+ const webhookId = resolveDiscordWebhookId(message);
676
+ const isGuildMessage = Boolean(params.data.guild_id);
677
+ const channelInfo = await resolveDiscordChannelInfo(params.client, messageChannelId);
678
+ if (isPreflightAborted(params.abortSignal)) return null;
679
+ const { isDirectMessage, isGroupDm } = resolveDiscordPreflightConversationKind({
680
+ isGuildMessage,
681
+ channelType: channelInfo?.type
682
+ });
683
+ const messageText = resolveDiscordMessageText(message, { includeForwarded: true });
684
+ const injectedBoundThreadBinding = !isDirectMessage && !isGroupDm ? resolveInjectedBoundThreadLookupRecord({
685
+ threadBindings: params.threadBindings,
686
+ threadId: messageChannelId
687
+ }) : void 0;
688
+ if (shouldIgnoreBoundThreadWebhookMessage({
689
+ accountId: params.accountId,
690
+ threadId: messageChannelId,
691
+ webhookId,
692
+ threadBinding: injectedBoundThreadBinding
693
+ })) {
694
+ logVerbose(`discord: drop bound-thread webhook echo message ${message.id}`);
695
+ return null;
696
+ }
697
+ if (isBoundThreadBotSystemMessage({
698
+ isBoundThreadSession: Boolean(injectedBoundThreadBinding) && isDiscordThreadChannelMessage({
699
+ isGuildMessage,
700
+ message,
701
+ channelInfo
702
+ }),
703
+ isBotAuthor: Boolean(author.bot),
704
+ text: messageText
705
+ })) {
706
+ logVerbose(`discord: drop bound-thread bot system message ${message.id}`);
707
+ return null;
708
+ }
709
+ const pluralkitInfo = await resolveDiscordPreflightPluralKitInfo({
710
+ message,
711
+ config: pluralkitConfig,
712
+ abortSignal: params.abortSignal
713
+ });
714
+ if (isPreflightAborted(params.abortSignal)) return null;
715
+ const sender = resolveDiscordSenderIdentity({
716
+ author,
717
+ member: params.data.member,
718
+ pluralkitInfo
719
+ });
720
+ if (author.bot) {
721
+ if (allowBotsMode === "off" && !sender.isPluralKit) {
722
+ logVerbose("discord: drop bot message (allowBots=false)");
723
+ return null;
724
+ }
725
+ }
726
+ const data = message === params.data.message ? params.data : {
727
+ ...params.data,
728
+ message
729
+ };
730
+ logDebug(`[discord-preflight] channelId=${messageChannelId} guild_id=${params.data.guild_id} channelType=${channelInfo?.type} isGuild=${isGuildMessage} isDM=${isDirectMessage} isGroupDm=${isGroupDm}`);
731
+ if (isGroupDm && !params.groupDmEnabled) {
732
+ logVerbose("discord: drop group dm (group dms disabled)");
733
+ return null;
734
+ }
735
+ if (isDirectMessage && !params.dmEnabled) {
736
+ logVerbose("discord: drop dm (dms disabled)");
737
+ return null;
738
+ }
739
+ const dmPolicy = params.dmPolicy;
740
+ const resolvedAccountId = params.accountId ?? resolveDefaultDiscordAccountId(params.cfg);
741
+ const allowNameMatching = isDangerousNameMatchingEnabled(params.discordConfig);
742
+ let commandAuthorized = true;
743
+ if (isDirectMessage) {
744
+ const access = await resolveDiscordDmPreflightAccess({
745
+ preflight: params,
746
+ author,
747
+ sender,
748
+ dmPolicy,
749
+ resolvedAccountId,
750
+ allowNameMatching
751
+ });
752
+ if (isPreflightAborted(params.abortSignal)) return null;
753
+ if (!access) return null;
754
+ commandAuthorized = access.commandAuthorized;
755
+ }
756
+ const botId = params.botUserId;
757
+ const baseText = resolveDiscordMessageText(message, { includeForwarded: false });
758
+ recordChannelActivity({
759
+ channel: "discord",
760
+ accountId: params.accountId,
761
+ direction: "inbound"
762
+ });
763
+ const channelName = channelInfo?.name ?? (isGuildMessage || isGroupDm ? resolveDiscordChannelNameSafe("channel" in message ? message.channel : void 0) : void 0);
764
+ const threadContext = await resolveDiscordPreflightThreadContext({
765
+ client: params.client,
766
+ isGuildMessage,
767
+ message,
768
+ channelInfo,
769
+ messageChannelId,
770
+ abortSignal: params.abortSignal
771
+ });
772
+ if (!threadContext) return null;
773
+ const { earlyThreadChannel, earlyThreadParentId, earlyThreadParentName, earlyThreadParentType } = threadContext;
774
+ const memberRoleIds = Array.isArray(params.data.rawMember?.roles) ? params.data.rawMember.roles : [];
775
+ const { conversationRuntime, threadBinding, configuredBinding, boundSessionKey, effectiveRoute, boundAgentId, baseSessionKey } = await resolveDiscordPreflightRoute({
776
+ preflight: params,
777
+ author,
778
+ isDirectMessage,
779
+ isGroupDm,
780
+ messageChannelId,
781
+ memberRoleIds,
782
+ earlyThreadParentId
783
+ });
784
+ if (shouldIgnoreBoundThreadWebhookMessage({
785
+ accountId: params.accountId,
786
+ threadId: messageChannelId,
787
+ webhookId,
788
+ threadBinding
789
+ })) {
790
+ logVerbose(`discord: drop bound-thread webhook echo message ${message.id}`);
791
+ return null;
792
+ }
793
+ const isBoundThreadSession = Boolean(threadBinding && earlyThreadChannel);
794
+ const bypassMentionRequirement = isBoundThreadSession;
795
+ if (isBoundThreadBotSystemMessage({
796
+ isBoundThreadSession,
797
+ isBotAuthor: Boolean(author.bot),
798
+ text: messageText
799
+ })) {
800
+ logVerbose(`discord: drop bound-thread bot system message ${message.id}`);
801
+ return null;
802
+ }
803
+ const mentionRegexes = buildMentionRegexes(params.cfg, effectiveRoute.agentId);
804
+ const explicitlyMentioned = Boolean(botId && message.mentionedUsers?.some((user) => user.id === botId));
805
+ const hasAnyMention = !isDirectMessage && ((message.mentionedUsers?.length ?? 0) > 0 || (message.mentionedRoles?.length ?? 0) > 0 || message.mentionedEveryone && (!author.bot || sender.isPluralKit));
806
+ const hasUserOrRoleMention = !isDirectMessage && ((message.mentionedUsers?.length ?? 0) > 0 || (message.mentionedRoles?.length ?? 0) > 0);
807
+ if (isGuildMessage && (message.type === discord_exports.MessageType.ChatInputCommand || message.type === discord_exports.MessageType.ContextMenuCommand)) {
808
+ logVerbose("discord: drop channel command message");
809
+ return null;
810
+ }
811
+ const guildInfo = isGuildMessage ? resolveDiscordGuildEntry({
812
+ guild: params.data.guild ?? void 0,
813
+ guildId: params.data.guild_id ?? void 0,
814
+ guildEntries: params.guildEntries
815
+ }) : null;
816
+ logDebug(`[discord-preflight] guild_id=${params.data.guild_id} guild_obj=${!!params.data.guild} guild_obj_id=${params.data.guild?.id} guildInfo=${!!guildInfo} guildEntries=${params.guildEntries ? Object.keys(params.guildEntries).join(",") : "none"}`);
817
+ if (isGuildMessage && params.guildEntries && Object.keys(params.guildEntries).length > 0 && !guildInfo) {
818
+ logDebug(`[discord-preflight] guild blocked: guild_id=${params.data.guild_id} guildEntries keys=${Object.keys(params.guildEntries).join(",")}`);
819
+ logVerbose(`Blocked discord guild ${params.data.guild_id ?? "unknown"} (not in discord.guilds)`);
820
+ return null;
821
+ }
822
+ const threadChannel = earlyThreadChannel;
823
+ const threadParentId = earlyThreadParentId;
824
+ const threadParentName = earlyThreadParentName;
825
+ const threadParentType = earlyThreadParentType;
826
+ const { threadName, configChannelName, configChannelSlug, displayChannelName, displayChannelSlug, guildSlug, channelConfig } = resolveDiscordPreflightChannelContext({
827
+ isGuildMessage,
828
+ messageChannelId,
829
+ channelName,
830
+ guildName: params.data.guild?.name,
831
+ guildInfo,
832
+ threadChannel,
833
+ threadParentId,
834
+ threadParentName
835
+ });
836
+ const channelMatchMeta = formatAllowlistMatchMeta(channelConfig);
837
+ logDiscordPreflightChannelConfig({
838
+ channelConfig,
839
+ channelMatchMeta,
840
+ channelId: messageChannelId
841
+ });
842
+ const channelAccess = resolveDiscordPreflightChannelAccess({
843
+ isGuildMessage,
844
+ isGroupDm,
845
+ groupPolicy: params.groupPolicy,
846
+ groupDmChannels: params.groupDmChannels,
847
+ messageChannelId,
848
+ displayChannelName,
849
+ displayChannelSlug,
850
+ guildInfo,
851
+ channelConfig,
852
+ channelMatchMeta
853
+ });
854
+ if (!channelAccess.allowed) return null;
855
+ const { channelAllowlistConfigured, channelAllowed } = channelAccess;
856
+ const historyEntry = buildDiscordPreflightHistoryEntry({
857
+ isGuildMessage,
858
+ historyLimit: params.historyLimit,
859
+ message,
860
+ senderLabel: sender.label
861
+ });
862
+ const threadOwnerId = threadChannel ? resolveDiscordChannelInfoSafe(threadChannel).ownerId ?? channelInfo?.ownerId : void 0;
863
+ const shouldRequireMentionByConfig = resolveDiscordShouldRequireMention({
864
+ isGuildMessage,
865
+ isThread: Boolean(threadChannel),
866
+ botId,
867
+ threadOwnerId,
868
+ channelConfig,
869
+ guildInfo
870
+ });
871
+ const shouldRequireMention = resolvePreflightMentionRequirement({
872
+ shouldRequireMention: shouldRequireMentionByConfig,
873
+ bypassMentionRequirement
874
+ });
875
+ const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
876
+ channelConfig,
877
+ guildInfo,
878
+ memberRoleIds,
879
+ sender,
880
+ allowNameMatching
881
+ });
882
+ if (isGuildMessage && hasAccessRestrictions && !memberAllowed) {
883
+ logDebug(`[discord-preflight] drop: member not allowed`);
884
+ logVerbose("Blocked discord guild sender (not in users/roles allowlist)");
885
+ return null;
886
+ }
887
+ const { resolveDiscordPreflightAudioMentionContext } = await loadPreflightAudioRuntime();
888
+ const { hasTypedText, transcript: preflightTranscript } = await resolveDiscordPreflightAudioMentionContext({
889
+ message,
890
+ isDirectMessage,
891
+ shouldRequireMention,
892
+ mentionRegexes,
893
+ cfg: params.cfg,
894
+ abortSignal: params.abortSignal
895
+ });
896
+ if (isPreflightAborted(params.abortSignal)) return null;
897
+ const mentionText = hasTypedText ? baseText : "";
898
+ const { implicitMentionKinds, wasMentioned } = resolveDiscordMentionState({
899
+ authorIsBot: Boolean(author.bot),
900
+ botId,
901
+ hasAnyMention,
902
+ isDirectMessage,
903
+ isExplicitlyMentioned: explicitlyMentioned,
904
+ mentionRegexes,
905
+ mentionText,
906
+ mentionedEveryone: message.mentionedEveryone,
907
+ referencedAuthorId: message.referencedMessage?.author?.id,
908
+ senderIsPluralKit: sender.isPluralKit,
909
+ transcript: preflightTranscript
910
+ });
911
+ logDiscordPreflightInboundSummary({
912
+ messageId: message.id,
913
+ guildId: params.data.guild_id ?? void 0,
914
+ channelId: messageChannelId,
915
+ wasMentioned,
916
+ isDirectMessage,
917
+ isGroupDm,
918
+ hasContent: Boolean(messageText)
919
+ });
920
+ const allowTextCommands = shouldHandleTextCommands({
921
+ cfg: params.cfg,
922
+ surface: "discord"
923
+ });
924
+ const hasControlCommandInMessage = hasControlCommand(baseText, params.cfg);
925
+ const hasAbortRequest = isAbortRequestText(baseText);
926
+ if (!isDirectMessage) {
927
+ const commandAccess = await resolveDiscordTextCommandAccess({
928
+ accountId: params.accountId,
929
+ cfg: params.cfg,
930
+ ownerAllowFrom: params.allowFrom,
931
+ sender: {
932
+ id: sender.id,
933
+ name: sender.name,
934
+ tag: sender.tag
935
+ },
936
+ memberAccessConfigured: hasAccessRestrictions,
937
+ memberAllowed,
938
+ allowNameMatching,
939
+ allowTextCommands,
940
+ hasControlCommand: hasControlCommandInMessage
941
+ });
942
+ commandAuthorized = commandAccess.authorized;
943
+ if (commandAccess.shouldBlockControlCommand) {
944
+ logInboundDrop({
945
+ log: logVerbose,
946
+ channel: "discord",
947
+ reason: "control command (unauthorized)",
948
+ target: sender.id
949
+ });
950
+ return null;
951
+ }
952
+ }
953
+ const canDetectMention = Boolean(botId) || mentionRegexes.length > 0;
954
+ const mentionDecision = resolveInboundMentionDecision({
955
+ facts: {
956
+ canDetectMention,
957
+ wasMentioned,
958
+ hasAnyMention,
959
+ implicitMentionKinds
960
+ },
961
+ policy: {
962
+ isGroup: isGuildMessage,
963
+ requireMention: shouldRequireMention,
964
+ allowTextCommands,
965
+ hasControlCommand: hasControlCommandInMessage,
966
+ commandAuthorized
967
+ }
968
+ });
969
+ const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
970
+ const inboundEventKind = classifyChannelInboundEvent({
971
+ conversation: { kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel" },
972
+ unmentionedGroupPolicy: resolveUnmentionedGroupInboundPolicy({
973
+ cfg: params.cfg,
974
+ agentId: effectiveRoute.agentId
975
+ }),
976
+ wasMentioned: effectiveWasMentioned,
977
+ hasControlCommand: hasControlCommandInMessage,
978
+ hasAbortRequest
979
+ });
980
+ logDebug(`[discord-preflight] shouldRequireMention=${shouldRequireMention} baseRequireMention=${shouldRequireMentionByConfig} boundThreadSession=${isBoundThreadSession} mentionDecision.shouldSkip=${mentionDecision.shouldSkip} wasMentioned=${wasMentioned}`);
981
+ if (isGuildMessage && shouldRequireMention) {
982
+ if (mentionDecision.shouldSkip) {
983
+ logDebug(`[discord-preflight] drop: no-mention`);
984
+ logVerbose(`discord: drop guild message (mention required, botId=${botId ?? "<missing>"})`);
985
+ logger.info({
986
+ channelId: messageChannelId,
987
+ reason: "no-mention"
988
+ }, "discord: skipping guild message");
989
+ await recordDiscordPendingHistoryEntry({
990
+ preflight: params,
991
+ historyKey: messageChannelId,
992
+ message,
993
+ entry: historyEntry
994
+ });
995
+ return null;
996
+ }
997
+ }
998
+ if (author.bot && !sender.isPluralKit && allowBotsMode === "mentions") {
999
+ if (!(isDirectMessage || wasMentioned || mentionDecision.implicitMention)) {
1000
+ logDebug(`[discord-preflight] drop: bot message missing mention (allowBots=mentions)`);
1001
+ logVerbose("discord: drop bot message (allowBots=mentions, missing mention)");
1002
+ return null;
1003
+ }
1004
+ }
1005
+ const ignoreOtherMentions = channelConfig?.ignoreOtherMentions ?? guildInfo?.ignoreOtherMentions ?? false;
1006
+ if (isGuildMessage && ignoreOtherMentions && hasUserOrRoleMention && !wasMentioned && !mentionDecision.implicitMention) {
1007
+ logDebug(`[discord-preflight] drop: other-mention`);
1008
+ logVerbose(`discord: drop guild message (another user/role mentioned, ignoreOtherMentions=true, botId=${botId})`);
1009
+ await recordDiscordPendingHistoryEntry({
1010
+ preflight: params,
1011
+ historyKey: messageChannelId,
1012
+ message,
1013
+ entry: historyEntry
1014
+ });
1015
+ return null;
1016
+ }
1017
+ const systemLocation = resolveDiscordSystemLocation({
1018
+ isDirectMessage,
1019
+ isGroupDm,
1020
+ guild: params.data.guild ?? void 0,
1021
+ channelName: channelName ?? messageChannelId
1022
+ });
1023
+ const { resolveDiscordSystemEvent } = await loadSystemEventsRuntime();
1024
+ const systemText = resolveDiscordSystemEvent(message, systemLocation);
1025
+ if (systemText) {
1026
+ logDebug(`[discord-preflight] drop: system event`);
1027
+ enqueueSystemEvent(systemText, {
1028
+ sessionKey: effectiveRoute.sessionKey,
1029
+ contextKey: `discord:system:${messageChannelId}:${message.id}`,
1030
+ forceSenderIsOwnerFalse: true,
1031
+ trusted: false
1032
+ });
1033
+ return null;
1034
+ }
1035
+ if (!messageText) {
1036
+ logDebug(`[discord-preflight] drop: empty content`);
1037
+ logVerbose(`discord: drop message ${message.id} (empty content)`);
1038
+ return null;
1039
+ }
1040
+ if (configuredBinding) {
1041
+ const ensured = await conversationRuntime.ensureConfiguredBindingRouteReady({
1042
+ cfg: params.cfg,
1043
+ bindingResolution: configuredBinding
1044
+ });
1045
+ if (!ensured.ok) {
1046
+ logVerbose(`discord: configured ACP binding unavailable for channel ${configuredBinding.record.conversation.conversationId}: ${ensured.error}`);
1047
+ return null;
1048
+ }
1049
+ }
1050
+ const botLoopProtection = author.bot && !sender.isPluralKit && allowBotsMode !== "off" && params.botUserId && author.id !== params.botUserId ? {
1051
+ scopeId: params.accountId,
1052
+ conversationId: messageChannelId,
1053
+ senderId: author.id,
1054
+ receiverId: params.botUserId,
1055
+ config: params.discordConfig?.botLoopProtection,
1056
+ defaultsConfig: params.cfg.channels?.defaults?.botLoopProtection,
1057
+ defaultEnabled: true,
1058
+ nowMs: resolveTimestampMs(message.timestamp)
1059
+ } : void 0;
1060
+ logDebug(`[discord-preflight] success: route=${effectiveRoute.agentId} sessionKey=${effectiveRoute.sessionKey}`);
1061
+ return buildDiscordMessagePreflightContext({
1062
+ preflightParams: params,
1063
+ data,
1064
+ client: params.client,
1065
+ message,
1066
+ messageChannelId,
1067
+ author,
1068
+ sender,
1069
+ canonicalMessageId: pluralkitInfo?.original?.trim() || void 0,
1070
+ memberRoleIds,
1071
+ channelInfo,
1072
+ channelName,
1073
+ isGuildMessage,
1074
+ isDirectMessage,
1075
+ isGroupDm,
1076
+ commandAuthorized,
1077
+ baseText,
1078
+ messageText,
1079
+ ...preflightTranscript !== void 0 ? { preflightAudioTranscript: preflightTranscript } : {},
1080
+ wasMentioned,
1081
+ route: effectiveRoute,
1082
+ threadBinding,
1083
+ boundSessionKey: boundSessionKey || void 0,
1084
+ boundAgentId,
1085
+ guildInfo,
1086
+ guildSlug,
1087
+ threadChannel,
1088
+ threadParentId,
1089
+ threadParentName,
1090
+ threadParentType,
1091
+ threadName,
1092
+ configChannelName,
1093
+ configChannelSlug,
1094
+ displayChannelName,
1095
+ displayChannelSlug,
1096
+ baseSessionKey,
1097
+ channelConfig,
1098
+ channelAllowlistConfigured,
1099
+ channelAllowed,
1100
+ shouldRequireMention,
1101
+ hasAnyMention,
1102
+ hasControlCommand: hasControlCommandInMessage,
1103
+ allowTextCommands,
1104
+ shouldBypassMention: mentionDecision.shouldBypassMention,
1105
+ effectiveWasMentioned,
1106
+ inboundEventKind,
1107
+ canDetectMention,
1108
+ historyEntry,
1109
+ botLoopProtection
1110
+ });
1111
+ }
1112
+ //#endregion
1113
+ export { preflightDiscordMessage, resolvePreflightMentionRequirement, shouldIgnoreBoundThreadWebhookMessage };