@openclaw/discord 2026.3.13 → 2026.5.1-beta.1

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 (498) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +132 -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/doctor-contract-api.ts +1 -0
  11. package/index.test.ts +13 -0
  12. package/index.ts +18 -13
  13. package/openclaw.plugin.json +3282 -1
  14. package/package.json +67 -2
  15. package/runtime-api.actions.ts +15 -0
  16. package/runtime-api.lookup.ts +22 -0
  17. package/runtime-api.monitor.ts +50 -0
  18. package/runtime-api.send.ts +79 -0
  19. package/runtime-api.threads.ts +30 -0
  20. package/runtime-api.ts +180 -0
  21. package/runtime-setter-api.ts +3 -0
  22. package/secret-contract-api.ts +4 -0
  23. package/security-audit-contract-api.ts +1 -0
  24. package/security-contract-api.ts +4 -0
  25. package/session-key-api.ts +1 -0
  26. package/setup-entry.ts +9 -0
  27. package/setup-plugin-api.ts +3 -0
  28. package/src/account-inspect.test.ts +126 -0
  29. package/src/account-inspect.ts +132 -0
  30. package/src/accounts.test.ts +247 -0
  31. package/src/accounts.ts +196 -0
  32. package/src/actions/handle-action.guild-admin.ts +411 -0
  33. package/src/actions/handle-action.test.ts +185 -0
  34. package/src/actions/handle-action.ts +332 -0
  35. package/src/actions/runtime.guild.ts +446 -0
  36. package/src/actions/runtime.messaging.messages.ts +205 -0
  37. package/src/actions/runtime.messaging.reactions.ts +67 -0
  38. package/src/actions/runtime.messaging.runtime.ts +69 -0
  39. package/src/actions/runtime.messaging.send.ts +244 -0
  40. package/src/actions/runtime.messaging.shared.ts +92 -0
  41. package/src/actions/runtime.messaging.ts +37 -0
  42. package/src/actions/runtime.moderation-shared.ts +48 -0
  43. package/src/actions/runtime.moderation.authz.test.ts +151 -0
  44. package/src/actions/runtime.moderation.ts +116 -0
  45. package/src/actions/runtime.presence.test.ts +160 -0
  46. package/src/actions/runtime.presence.ts +117 -0
  47. package/src/actions/runtime.shared.ts +83 -0
  48. package/src/actions/runtime.test.ts +1056 -0
  49. package/src/actions/runtime.ts +81 -0
  50. package/src/api-barrel.test.ts +80 -0
  51. package/src/api.test.ts +130 -0
  52. package/src/api.ts +169 -0
  53. package/src/approval-handler.runtime.test.ts +41 -0
  54. package/src/approval-handler.runtime.ts +632 -0
  55. package/src/approval-native.test.ts +330 -0
  56. package/src/approval-native.ts +219 -0
  57. package/src/approval-runtime.ts +14 -0
  58. package/src/approval-shared.ts +53 -0
  59. package/src/audit-core.ts +141 -0
  60. package/src/audit.test.ts +145 -0
  61. package/src/audit.ts +32 -0
  62. package/src/channel-actions.contract.test.ts +45 -0
  63. package/src/channel-actions.runtime.ts +1 -0
  64. package/src/channel-actions.test.ts +236 -0
  65. package/src/channel-actions.ts +198 -0
  66. package/src/channel-api.ts +28 -0
  67. package/src/channel.conversation.ts +159 -0
  68. package/src/channel.loaders.ts +47 -0
  69. package/src/channel.runtime.ts +1 -0
  70. package/src/channel.setup.ts +12 -0
  71. package/src/channel.test.ts +539 -12
  72. package/src/channel.ts +596 -430
  73. package/src/chunk.test.ts +157 -0
  74. package/src/chunk.ts +321 -0
  75. package/src/client.proxy.test.ts +176 -0
  76. package/src/client.test.ts +76 -0
  77. package/src/client.ts +139 -0
  78. package/src/component-custom-id.ts +72 -0
  79. package/src/components-registry.ts +356 -0
  80. package/src/components.builders.ts +409 -0
  81. package/src/components.modal.ts +124 -0
  82. package/src/components.parse.ts +407 -0
  83. package/src/components.test.ts +312 -0
  84. package/src/components.ts +54 -0
  85. package/src/components.types.ts +187 -0
  86. package/src/config-schema.test.ts +325 -0
  87. package/src/config-schema.ts +6 -0
  88. package/src/config-ui-hints.ts +249 -0
  89. package/src/conversation-identity.ts +58 -0
  90. package/src/delivery-retry.ts +56 -0
  91. package/src/directory-cache.ts +116 -0
  92. package/src/directory-config.ts +58 -0
  93. package/src/directory-contract.test.ts +129 -0
  94. package/src/directory-live.test.ts +126 -0
  95. package/src/directory-live.ts +135 -0
  96. package/src/doctor-contract.ts +477 -0
  97. package/src/doctor-shared.ts +5 -0
  98. package/src/doctor.test.ts +405 -0
  99. package/src/doctor.ts +340 -0
  100. package/src/draft-chunking.test.ts +64 -0
  101. package/src/draft-chunking.ts +43 -0
  102. package/src/draft-stream.test.ts +159 -0
  103. package/src/draft-stream.ts +154 -0
  104. package/src/error-body.ts +38 -0
  105. package/src/exec-approvals.test.ts +88 -0
  106. package/src/exec-approvals.ts +110 -0
  107. package/src/gateway-logging.test.ts +98 -0
  108. package/src/gateway-logging.ts +67 -0
  109. package/src/group-policy.ts +113 -0
  110. package/src/guilds.ts +29 -0
  111. package/src/inbound-context.contract.test.ts +11 -0
  112. package/src/interactive-dispatch.ts +104 -0
  113. package/src/internal/api.commands.ts +51 -0
  114. package/src/internal/api.guild.ts +164 -0
  115. package/src/internal/api.interactions.ts +53 -0
  116. package/src/internal/api.messages.ts +113 -0
  117. package/src/internal/api.reactions.ts +38 -0
  118. package/src/internal/api.test.ts +262 -0
  119. package/src/internal/api.ts +61 -0
  120. package/src/internal/api.users.ts +19 -0
  121. package/src/internal/api.webhooks.ts +13 -0
  122. package/src/internal/client.test.ts +297 -0
  123. package/src/internal/client.ts +246 -0
  124. package/src/internal/command-deploy.ts +202 -0
  125. package/src/internal/commands.ts +188 -0
  126. package/src/internal/components.base.ts +65 -0
  127. package/src/internal/components.message.ts +279 -0
  128. package/src/internal/components.modal.ts +95 -0
  129. package/src/internal/components.ts +31 -0
  130. package/src/internal/discord.ts +11 -0
  131. package/src/internal/embeds.ts +35 -0
  132. package/src/internal/entity-cache.ts +98 -0
  133. package/src/internal/event-queue.ts +162 -0
  134. package/src/internal/gateway-close-codes.ts +25 -0
  135. package/src/internal/gateway-dispatch.ts +96 -0
  136. package/src/internal/gateway-identify-limiter.ts +26 -0
  137. package/src/internal/gateway-lifecycle.ts +61 -0
  138. package/src/internal/gateway-rate-limit.ts +104 -0
  139. package/src/internal/gateway.test.ts +475 -0
  140. package/src/internal/gateway.ts +437 -0
  141. package/src/internal/interaction-dispatch.test.ts +148 -0
  142. package/src/internal/interaction-dispatch.ts +130 -0
  143. package/src/internal/interaction-options.ts +98 -0
  144. package/src/internal/interaction-response.ts +53 -0
  145. package/src/internal/interactions.test.ts +253 -0
  146. package/src/internal/interactions.ts +337 -0
  147. package/src/internal/listeners.ts +85 -0
  148. package/src/internal/live-smoke.live.test.ts +26 -0
  149. package/src/internal/modal-fields.ts +95 -0
  150. package/src/internal/payload.ts +69 -0
  151. package/src/internal/rest-body.ts +115 -0
  152. package/src/internal/rest-errors.ts +88 -0
  153. package/src/internal/rest-routes.ts +50 -0
  154. package/src/internal/rest-scheduler.ts +412 -0
  155. package/src/internal/rest.test.ts +437 -0
  156. package/src/internal/rest.ts +213 -0
  157. package/src/internal/schemas.ts +36 -0
  158. package/src/internal/structures.ts +278 -0
  159. package/src/internal/test-builders.test-support.ts +163 -0
  160. package/src/internal/voice.ts +49 -0
  161. package/src/media-detection.ts +28 -0
  162. package/src/mentions.test.ts +111 -0
  163. package/src/mentions.ts +147 -0
  164. package/src/monitor/access-groups.ts +55 -0
  165. package/src/monitor/ack-reactions.ts +70 -0
  166. package/src/monitor/acp-bind-here.integration.test.ts +211 -0
  167. package/src/monitor/agent-components-auth.ts +7 -0
  168. package/src/monitor/agent-components-context.ts +144 -0
  169. package/src/monitor/agent-components-data.ts +224 -0
  170. package/src/monitor/agent-components-dm-auth.ts +221 -0
  171. package/src/monitor/agent-components-guild-auth.ts +322 -0
  172. package/src/monitor/agent-components-helpers.runtime.ts +5 -0
  173. package/src/monitor/agent-components-helpers.ts +34 -0
  174. package/src/monitor/agent-components-reply.ts +10 -0
  175. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  176. package/src/monitor/agent-components.dispatch.ts +366 -0
  177. package/src/monitor/agent-components.handlers.ts +303 -0
  178. package/src/monitor/agent-components.modal.ts +160 -0
  179. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  180. package/src/monitor/agent-components.runtime.ts +14 -0
  181. package/src/monitor/agent-components.system-controls.ts +211 -0
  182. package/src/monitor/agent-components.ts +70 -0
  183. package/src/monitor/agent-components.types.ts +57 -0
  184. package/src/monitor/agent-components.wildcard-controls.ts +168 -0
  185. package/src/monitor/agent-components.wildcard.test.ts +71 -0
  186. package/src/monitor/allow-list.ts +623 -0
  187. package/src/monitor/auto-presence.test.ts +156 -0
  188. package/src/monitor/auto-presence.ts +356 -0
  189. package/src/monitor/channel-access.ts +70 -0
  190. package/src/monitor/commands.test.ts +24 -0
  191. package/src/monitor/commands.ts +9 -0
  192. package/src/monitor/dm-command-auth.test.ts +197 -0
  193. package/src/monitor/dm-command-auth.ts +158 -0
  194. package/src/monitor/dm-command-decision.test.ts +113 -0
  195. package/src/monitor/dm-command-decision.ts +49 -0
  196. package/src/monitor/exec-approvals.test.ts +226 -0
  197. package/src/monitor/exec-approvals.ts +158 -0
  198. package/src/monitor/format.ts +45 -0
  199. package/src/monitor/gateway-handle.ts +34 -0
  200. package/src/monitor/gateway-metadata.test.ts +29 -0
  201. package/src/monitor/gateway-metadata.ts +298 -0
  202. package/src/monitor/gateway-plugin.test.ts +297 -0
  203. package/src/monitor/gateway-plugin.ts +294 -0
  204. package/src/monitor/gateway-registry.ts +37 -0
  205. package/src/monitor/gateway-supervisor.test.ts +150 -0
  206. package/src/monitor/gateway-supervisor.ts +206 -0
  207. package/src/monitor/inbound-context.test-helpers.ts +37 -0
  208. package/src/monitor/inbound-context.test.ts +106 -0
  209. package/src/monitor/inbound-context.ts +103 -0
  210. package/src/monitor/inbound-dedupe.ts +79 -0
  211. package/src/monitor/inbound-job.test.ts +203 -0
  212. package/src/monitor/inbound-job.ts +118 -0
  213. package/src/monitor/listeners.queue.ts +91 -0
  214. package/src/monitor/listeners.reactions.ts +610 -0
  215. package/src/monitor/listeners.test.ts +200 -0
  216. package/src/monitor/listeners.ts +150 -0
  217. package/src/monitor/message-channel-info.ts +96 -0
  218. package/src/monitor/message-forwarded.ts +107 -0
  219. package/src/monitor/message-handler.batch-gate.test.ts +22 -0
  220. package/src/monitor/message-handler.batch-gate.ts +19 -0
  221. package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
  222. package/src/monitor/message-handler.context.ts +393 -0
  223. package/src/monitor/message-handler.dm-preflight.ts +123 -0
  224. package/src/monitor/message-handler.draft-preview.ts +246 -0
  225. package/src/monitor/message-handler.hydration.test.ts +80 -0
  226. package/src/monitor/message-handler.hydration.ts +198 -0
  227. package/src/monitor/message-handler.inbound-context.test.ts +59 -0
  228. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  229. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  230. package/src/monitor/message-handler.preflight-channel-context.ts +55 -0
  231. package/src/monitor/message-handler.preflight-context.ts +54 -0
  232. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  233. package/src/monitor/message-handler.preflight-history.ts +23 -0
  234. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  235. package/src/monitor/message-handler.preflight-pluralkit.ts +27 -0
  236. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  237. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  238. package/src/monitor/message-handler.preflight.acp-bindings.test.ts +369 -0
  239. package/src/monitor/message-handler.preflight.test-helpers.ts +111 -0
  240. package/src/monitor/message-handler.preflight.test.ts +1544 -0
  241. package/src/monitor/message-handler.preflight.ts +680 -0
  242. package/src/monitor/message-handler.preflight.types.ts +109 -0
  243. package/src/monitor/message-handler.process.test.ts +1301 -0
  244. package/src/monitor/message-handler.process.ts +684 -0
  245. package/src/monitor/message-handler.queue.test.ts +496 -0
  246. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  247. package/src/monitor/message-handler.test-harness.ts +99 -0
  248. package/src/monitor/message-handler.test-helpers.ts +75 -0
  249. package/src/monitor/message-handler.ts +274 -0
  250. package/src/monitor/message-media.ts +507 -0
  251. package/src/monitor/message-run-queue.ts +101 -0
  252. package/src/monitor/message-text.ts +171 -0
  253. package/src/monitor/message-utils.test.ts +1151 -0
  254. package/src/monitor/message-utils.ts +32 -0
  255. package/src/monitor/model-picker-preferences.test.ts +67 -0
  256. package/src/monitor/model-picker-preferences.ts +184 -0
  257. package/src/monitor/model-picker.state.ts +364 -0
  258. package/src/monitor/model-picker.test-utils.ts +26 -0
  259. package/src/monitor/model-picker.test.ts +794 -0
  260. package/src/monitor/model-picker.ts +38 -0
  261. package/src/monitor/model-picker.view.ts +695 -0
  262. package/src/monitor/monitor.agent-components.test.ts +375 -0
  263. package/src/monitor/monitor.test.ts +849 -0
  264. package/src/monitor/monitor.threading-utils.test.ts +598 -0
  265. package/src/monitor/native-command-agent-reply.ts +123 -0
  266. package/src/monitor/native-command-arg-ui.ts +233 -0
  267. package/src/monitor/native-command-auth.ts +308 -0
  268. package/src/monitor/native-command-bypass.ts +13 -0
  269. package/src/monitor/native-command-context.test.ts +98 -0
  270. package/src/monitor/native-command-context.ts +103 -0
  271. package/src/monitor/native-command-dispatch.ts +35 -0
  272. package/src/monitor/native-command-model-picker-apply.ts +177 -0
  273. package/src/monitor/native-command-model-picker-interaction.ts +461 -0
  274. package/src/monitor/native-command-model-picker-ui.ts +368 -0
  275. package/src/monitor/native-command-reply.test.ts +68 -0
  276. package/src/monitor/native-command-reply.ts +183 -0
  277. package/src/monitor/native-command-route.ts +91 -0
  278. package/src/monitor/native-command-status.ts +76 -0
  279. package/src/monitor/native-command-ui.ts +26 -0
  280. package/src/monitor/native-command-ui.types.ts +20 -0
  281. package/src/monitor/native-command.args.ts +45 -0
  282. package/src/monitor/native-command.command-arg.test.ts +99 -0
  283. package/src/monitor/native-command.commands-allowfrom.test.ts +490 -0
  284. package/src/monitor/native-command.model-picker.test.ts +767 -0
  285. package/src/monitor/native-command.options.test.ts +369 -0
  286. package/src/monitor/native-command.options.ts +153 -0
  287. package/src/monitor/native-command.plugin-dispatch.test.ts +879 -0
  288. package/src/monitor/native-command.runtime.ts +50 -0
  289. package/src/monitor/native-command.status-direct.test.ts +272 -0
  290. package/src/monitor/native-command.test-helpers.ts +64 -0
  291. package/src/monitor/native-command.think-autocomplete.test.ts +416 -0
  292. package/src/monitor/native-command.ts +699 -0
  293. package/src/monitor/native-command.types.ts +9 -0
  294. package/src/monitor/native-interaction-channel-context.ts +50 -0
  295. package/src/monitor/preflight-audio.runtime.ts +9 -0
  296. package/src/monitor/preflight-audio.test.ts +157 -0
  297. package/src/monitor/preflight-audio.ts +130 -0
  298. package/src/monitor/presence-cache.ts +61 -0
  299. package/src/monitor/presence.test.ts +44 -0
  300. package/src/monitor/presence.ts +50 -0
  301. package/src/monitor/provider-session.runtime.ts +12 -0
  302. package/src/monitor/provider.acp.ts +89 -0
  303. package/src/monitor/provider.allowlist.test.ts +149 -0
  304. package/src/monitor/provider.allowlist.ts +394 -0
  305. package/src/monitor/provider.cleanup.ts +41 -0
  306. package/src/monitor/provider.commands.ts +129 -0
  307. package/src/monitor/provider.config-log.ts +45 -0
  308. package/src/monitor/provider.deploy-errors.ts +362 -0
  309. package/src/monitor/provider.deploy.ts +221 -0
  310. package/src/monitor/provider.interactions.ts +160 -0
  311. package/src/monitor/provider.lifecycle.test.ts +658 -0
  312. package/src/monitor/provider.lifecycle.ts +545 -0
  313. package/src/monitor/provider.proxy.test.ts +745 -0
  314. package/src/monitor/provider.rest-proxy.test.ts +121 -0
  315. package/src/monitor/provider.runtime.ts +1 -0
  316. package/src/monitor/provider.skill-dedupe.test.ts +42 -0
  317. package/src/monitor/provider.startup-log.ts +32 -0
  318. package/src/monitor/provider.startup.test.ts +426 -0
  319. package/src/monitor/provider.startup.ts +323 -0
  320. package/src/monitor/provider.test.ts +1111 -0
  321. package/src/monitor/provider.ts +713 -0
  322. package/src/monitor/reply-context.ts +64 -0
  323. package/src/monitor/reply-delivery.test.ts +244 -0
  324. package/src/monitor/reply-delivery.ts +203 -0
  325. package/src/monitor/rest-fetch.ts +43 -0
  326. package/src/monitor/route-resolution.test.ts +204 -0
  327. package/src/monitor/route-resolution.ts +140 -0
  328. package/src/monitor/sender-identity.ts +81 -0
  329. package/src/monitor/startup-status.test.ts +30 -0
  330. package/src/monitor/startup-status.ts +10 -0
  331. package/src/monitor/status.ts +22 -0
  332. package/src/monitor/system-events.ts +55 -0
  333. package/src/monitor/thread-bindings.config.ts +35 -0
  334. package/src/monitor/thread-bindings.discord-api.test.ts +229 -0
  335. package/src/monitor/thread-bindings.discord-api.ts +318 -0
  336. package/src/monitor/thread-bindings.lifecycle.test.ts +1871 -0
  337. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  338. package/src/monitor/thread-bindings.manager.ts +553 -0
  339. package/src/monitor/thread-bindings.messages.ts +6 -0
  340. package/src/monitor/thread-bindings.persona.test.ts +34 -0
  341. package/src/monitor/thread-bindings.persona.ts +25 -0
  342. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  343. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  344. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  345. package/src/monitor/thread-bindings.shared-state.test.ts +36 -0
  346. package/src/monitor/thread-bindings.state.ts +540 -0
  347. package/src/monitor/thread-bindings.ts +48 -0
  348. package/src/monitor/thread-bindings.types.ts +83 -0
  349. package/src/monitor/thread-channel-context.ts +112 -0
  350. package/src/monitor/thread-session-close.test.ts +180 -0
  351. package/src/monitor/thread-session-close.ts +63 -0
  352. package/src/monitor/thread-title.generate.test.ts +197 -0
  353. package/src/monitor/thread-title.test.ts +31 -0
  354. package/src/monitor/thread-title.ts +181 -0
  355. package/src/monitor/threading.auto-thread.test.ts +327 -0
  356. package/src/monitor/threading.auto-thread.ts +287 -0
  357. package/src/monitor/threading.cache.ts +45 -0
  358. package/src/monitor/threading.parent-info.test.ts +156 -0
  359. package/src/monitor/threading.starter.test.ts +260 -0
  360. package/src/monitor/threading.starter.ts +287 -0
  361. package/src/monitor/threading.ts +20 -0
  362. package/src/monitor/threading.types.ts +102 -0
  363. package/src/monitor/timeouts.ts +84 -0
  364. package/src/monitor/typing.test.ts +42 -0
  365. package/src/monitor/typing.ts +17 -0
  366. package/src/monitor.gateway.test.ts +187 -0
  367. package/src/monitor.gateway.ts +75 -0
  368. package/src/monitor.test.ts +1397 -0
  369. package/src/monitor.ts +28 -0
  370. package/src/normalize.test.ts +56 -0
  371. package/src/normalize.ts +86 -0
  372. package/src/outbound-adapter.interactive-order.test.ts +64 -0
  373. package/src/outbound-adapter.test-harness.ts +207 -0
  374. package/src/outbound-adapter.test.ts +696 -0
  375. package/src/outbound-adapter.ts +291 -0
  376. package/src/outbound-approval.ts +29 -0
  377. package/src/outbound-components.ts +81 -0
  378. package/src/outbound-payload.contract.test.ts +38 -0
  379. package/src/outbound-payload.ts +134 -0
  380. package/src/outbound-send-context.ts +92 -0
  381. package/src/outbound-session-route.test.ts +34 -0
  382. package/src/outbound-session-route.ts +72 -0
  383. package/src/pluralkit.test.ts +67 -0
  384. package/src/pluralkit.ts +58 -0
  385. package/src/preview-streaming.ts +32 -0
  386. package/src/probe.intents.test.ts +94 -0
  387. package/src/probe.parse-token.test.ts +43 -0
  388. package/src/probe.runtime.ts +1 -0
  389. package/src/probe.ts +237 -0
  390. package/src/proxy-fetch.ts +92 -0
  391. package/src/proxy-request-client.test.ts +78 -0
  392. package/src/proxy-request-client.ts +54 -0
  393. package/src/recipient-resolution.ts +39 -0
  394. package/src/resolve-allowlist-common.test.ts +36 -0
  395. package/src/resolve-allowlist-common.ts +39 -0
  396. package/src/resolve-channels.test.ts +340 -0
  397. package/src/resolve-channels.ts +369 -0
  398. package/src/resolve-users.test.ts +222 -0
  399. package/src/resolve-users.ts +184 -0
  400. package/src/retry.test.ts +83 -0
  401. package/src/retry.ts +98 -0
  402. package/src/runtime-api.ts +64 -0
  403. package/src/runtime.ts +22 -5
  404. package/src/secret-config-contract.ts +140 -0
  405. package/src/security-audit.runtime.ts +1 -0
  406. package/src/security-audit.test.ts +246 -0
  407. package/src/security-audit.ts +208 -0
  408. package/src/security-contract.ts +47 -0
  409. package/src/security-doctor.test.ts +25 -0
  410. package/src/security-doctor.ts +20 -0
  411. package/src/security.ts +60 -0
  412. package/src/send-target-parsing.ts +14 -0
  413. package/src/send.channels.ts +139 -0
  414. package/src/send.components.test.ts +275 -0
  415. package/src/send.components.ts +383 -0
  416. package/src/send.creates-thread.test.ts +643 -0
  417. package/src/send.emojis-stickers.ts +57 -0
  418. package/src/send.guild.ts +170 -0
  419. package/src/send.message-request.ts +97 -0
  420. package/src/send.messages.test.ts +53 -0
  421. package/src/send.messages.ts +225 -0
  422. package/src/send.outbound.ts +414 -0
  423. package/src/send.permissions.authz.test.ts +188 -0
  424. package/src/send.permissions.ts +283 -0
  425. package/src/send.reactions.ts +155 -0
  426. package/src/send.sends-basic-channel-messages.test.ts +919 -0
  427. package/src/send.shared.ts +445 -0
  428. package/src/send.test-harness.ts +56 -0
  429. package/src/send.ts +82 -0
  430. package/src/send.types.ts +188 -0
  431. package/src/send.typing.test.ts +41 -0
  432. package/src/send.typing.ts +9 -0
  433. package/src/send.voice.ts +134 -0
  434. package/src/send.webhook-activity.test.ts +105 -0
  435. package/src/send.webhook.proxy.test.ts +191 -0
  436. package/src/send.webhook.ts +133 -0
  437. package/src/session-contract.ts +3 -0
  438. package/src/session-key-normalization.test.ts +44 -0
  439. package/src/session-key-normalization.ts +47 -0
  440. package/src/setup-account-state.test.ts +91 -0
  441. package/src/setup-account-state.ts +144 -0
  442. package/src/setup-adapter.ts +12 -0
  443. package/src/setup-core.ts +180 -0
  444. package/src/setup-runtime-helpers.ts +10 -0
  445. package/src/setup-surface.test.ts +96 -0
  446. package/src/setup-surface.ts +129 -0
  447. package/src/shared-interactive.test.ts +153 -0
  448. package/src/shared-interactive.ts +124 -0
  449. package/src/shared.test.ts +159 -0
  450. package/src/shared.ts +190 -0
  451. package/src/status-issues.test.ts +70 -0
  452. package/src/status-issues.ts +169 -0
  453. package/src/subagent-hooks.test.ts +40 -44
  454. package/src/subagent-hooks.ts +185 -122
  455. package/src/target-parsing.ts +53 -0
  456. package/src/target-resolver.ts +129 -0
  457. package/src/targets.test.ts +367 -0
  458. package/src/targets.ts +12 -0
  459. package/src/test-http-helpers.ts +10 -0
  460. package/src/test-support/component-runtime.ts +190 -0
  461. package/src/test-support/config.ts +7 -0
  462. package/src/test-support/configured-binding-runtime.ts +29 -0
  463. package/src/test-support/partial-channel.ts +26 -0
  464. package/src/test-support/provider.test-support.ts +545 -0
  465. package/src/token.test.ts +107 -0
  466. package/src/token.ts +60 -0
  467. package/src/ui-colors.ts +27 -0
  468. package/src/ui.ts +20 -0
  469. package/src/voice/access.test.ts +217 -0
  470. package/src/voice/access.ts +124 -0
  471. package/src/voice/audio.ts +173 -0
  472. package/src/voice/capture-state.test.ts +48 -0
  473. package/src/voice/capture-state.ts +120 -0
  474. package/src/voice/command.test.ts +164 -0
  475. package/src/voice/command.ts +283 -0
  476. package/src/voice/config.ts +8 -0
  477. package/src/voice/manager.e2e.test.ts +928 -0
  478. package/src/voice/manager.ready-listener.test.ts +37 -0
  479. package/src/voice/manager.runtime.ts +11 -0
  480. package/src/voice/manager.ts +691 -0
  481. package/src/voice/prompt.test.ts +16 -0
  482. package/src/voice/prompt.ts +17 -0
  483. package/src/voice/receive-recovery.test.ts +79 -0
  484. package/src/voice/receive-recovery.ts +159 -0
  485. package/src/voice/sanitize.test.ts +34 -0
  486. package/src/voice/sanitize.ts +32 -0
  487. package/src/voice/sdk-runtime.ts +14 -0
  488. package/src/voice/segment.ts +156 -0
  489. package/src/voice/session.ts +50 -0
  490. package/src/voice/speaker-context.ts +127 -0
  491. package/src/voice/tts.ts +125 -0
  492. package/src/voice-message.test.ts +234 -0
  493. package/src/voice-message.ts +444 -0
  494. package/subagent-hooks-api.ts +27 -0
  495. package/test-api.ts +4 -0
  496. package/thread-binding-api.ts +1 -0
  497. package/timeouts.ts +6 -0
  498. package/tsconfig.json +16 -0
@@ -0,0 +1,129 @@
1
+ import {
2
+ listNativeCommandSpecsForConfig,
3
+ listSkillCommandsForAgents,
4
+ type NativeCommandSpec,
5
+ } from "openclaw/plugin-sdk/command-auth";
6
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
7
+ import { danger, warn, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
8
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
9
+
10
+ export type GetPluginCommandSpecs =
11
+ typeof import("openclaw/plugin-sdk/plugin-runtime").getPluginCommandSpecs;
12
+
13
+ let pluginRuntimePromise: Promise<typeof import("openclaw/plugin-sdk/plugin-runtime")> | undefined;
14
+
15
+ async function loadPluginRuntime() {
16
+ const promise = pluginRuntimePromise ?? import("openclaw/plugin-sdk/plugin-runtime");
17
+ pluginRuntimePromise = promise;
18
+ try {
19
+ return await promise;
20
+ } catch (error) {
21
+ if (pluginRuntimePromise === promise) {
22
+ pluginRuntimePromise = undefined;
23
+ }
24
+ throw error;
25
+ }
26
+ }
27
+
28
+ async function appendPluginCommandSpecs(params: {
29
+ commandSpecs: NativeCommandSpec[];
30
+ runtime: RuntimeEnv;
31
+ cfg: OpenClawConfig;
32
+ getPluginCommandSpecs?: GetPluginCommandSpecs;
33
+ }): Promise<NativeCommandSpec[]> {
34
+ const merged = [...params.commandSpecs];
35
+ const existingNames = new Set(
36
+ merged.map((spec) => normalizeLowercaseStringOrEmpty(spec.name)).filter(Boolean),
37
+ );
38
+ const getPluginCommandSpecs =
39
+ params.getPluginCommandSpecs ?? (await loadPluginRuntime()).getPluginCommandSpecs;
40
+ for (const pluginCommand of getPluginCommandSpecs("discord", { config: params.cfg })) {
41
+ const normalizedName = normalizeLowercaseStringOrEmpty(pluginCommand.name);
42
+ if (!normalizedName) {
43
+ continue;
44
+ }
45
+ if (existingNames.has(normalizedName)) {
46
+ params.runtime.error?.(
47
+ danger(
48
+ `discord: plugin command "/${normalizedName}" duplicates an existing native command. Skipping.`,
49
+ ),
50
+ );
51
+ continue;
52
+ }
53
+ existingNames.add(normalizedName);
54
+ merged.push({
55
+ name: pluginCommand.name,
56
+ description: pluginCommand.description,
57
+ acceptsArgs: pluginCommand.acceptsArgs,
58
+ });
59
+ }
60
+ return merged;
61
+ }
62
+
63
+ export async function resolveDiscordProviderCommandSpecs(params: {
64
+ cfg: OpenClawConfig;
65
+ runtime: RuntimeEnv;
66
+ nativeEnabled: boolean;
67
+ nativeSkillsEnabled: boolean;
68
+ maxDiscordCommands?: number;
69
+ listSkillCommandsForAgents?: typeof listSkillCommandsForAgents;
70
+ listNativeCommandSpecsForConfig?: typeof listNativeCommandSpecsForConfig;
71
+ getPluginCommandSpecs?: GetPluginCommandSpecs;
72
+ }): Promise<{
73
+ skillCommands: ReturnType<typeof listSkillCommandsForAgents>;
74
+ commandSpecs: NativeCommandSpec[];
75
+ }> {
76
+ const listSkillCommands = params.listSkillCommandsForAgents ?? listSkillCommandsForAgents;
77
+ const listNativeCommandSpecs =
78
+ params.listNativeCommandSpecsForConfig ?? listNativeCommandSpecsForConfig;
79
+ const maxDiscordCommands = params.maxDiscordCommands ?? 100;
80
+ let skillCommands =
81
+ params.nativeEnabled && params.nativeSkillsEnabled
82
+ ? listSkillCommands({ cfg: params.cfg })
83
+ : [];
84
+ let commandSpecs = params.nativeEnabled
85
+ ? listNativeCommandSpecs(params.cfg, {
86
+ skillCommands,
87
+ provider: "discord",
88
+ })
89
+ : [];
90
+ if (params.nativeEnabled) {
91
+ commandSpecs = await appendPluginCommandSpecs({
92
+ commandSpecs,
93
+ runtime: params.runtime,
94
+ cfg: params.cfg,
95
+ getPluginCommandSpecs: params.getPluginCommandSpecs,
96
+ });
97
+ }
98
+ const initialCommandCount = commandSpecs.length;
99
+ if (
100
+ params.nativeEnabled &&
101
+ params.nativeSkillsEnabled &&
102
+ commandSpecs.length > maxDiscordCommands
103
+ ) {
104
+ skillCommands = [];
105
+ commandSpecs = listNativeCommandSpecs(params.cfg, {
106
+ skillCommands: [],
107
+ provider: "discord",
108
+ });
109
+ commandSpecs = await appendPluginCommandSpecs({
110
+ commandSpecs,
111
+ runtime: params.runtime,
112
+ cfg: params.cfg,
113
+ getPluginCommandSpecs: params.getPluginCommandSpecs,
114
+ });
115
+ params.runtime.log?.(
116
+ warn(
117
+ `discord: ${initialCommandCount} commands exceeds limit; removing per-skill commands and keeping /skill.`,
118
+ ),
119
+ );
120
+ }
121
+ if (params.nativeEnabled && commandSpecs.length > maxDiscordCommands) {
122
+ params.runtime.log?.(
123
+ warn(
124
+ `discord: ${commandSpecs.length} commands exceeds limit; some commands may fail to deploy.`,
125
+ ),
126
+ );
127
+ }
128
+ return { skillCommands, commandSpecs };
129
+ }
@@ -0,0 +1,45 @@
1
+ import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
2
+ import { summarizeStringEntries } from "openclaw/plugin-sdk/text-runtime";
3
+ import { formatThreadBindingDurationLabel } from "./thread-bindings.messages.js";
4
+
5
+ function formatThreadBindingDurationForConfigLabel(durationMs: number): string {
6
+ const label = formatThreadBindingDurationLabel(durationMs);
7
+ return label === "disabled" ? "off" : label;
8
+ }
9
+
10
+ export function logDiscordResolvedConfig(params: {
11
+ dmEnabled: boolean;
12
+ dmPolicy: string;
13
+ allowFrom?: string[];
14
+ groupDmEnabled: boolean;
15
+ groupDmChannels?: string[];
16
+ groupPolicy: string;
17
+ guildEntries?: Record<string, unknown>;
18
+ historyLimit: number;
19
+ mediaMaxBytes: number;
20
+ nativeEnabled: boolean;
21
+ nativeSkillsEnabled: boolean;
22
+ useAccessGroups: boolean;
23
+ threadBindingsEnabled: boolean;
24
+ threadBindingIdleTimeoutMs: number;
25
+ threadBindingMaxAgeMs: number;
26
+ }): void {
27
+ const allowFromSummary = summarizeStringEntries({
28
+ entries: params.allowFrom ?? [],
29
+ limit: 4,
30
+ emptyText: "any",
31
+ });
32
+ const groupDmChannelSummary = summarizeStringEntries({
33
+ entries: params.groupDmChannels ?? [],
34
+ limit: 4,
35
+ emptyText: "any",
36
+ });
37
+ const guildSummary = summarizeStringEntries({
38
+ entries: Object.keys(params.guildEntries ?? {}),
39
+ limit: 4,
40
+ emptyText: "any",
41
+ });
42
+ logVerbose(
43
+ `discord: config dm=${params.dmEnabled ? "on" : "off"} dmPolicy=${params.dmPolicy} allowFrom=${allowFromSummary} groupDm=${params.groupDmEnabled ? "on" : "off"} groupDmChannels=${groupDmChannelSummary} groupPolicy=${params.groupPolicy} guilds=${guildSummary} historyLimit=${params.historyLimit} mediaMaxMb=${Math.round(params.mediaMaxBytes / (1024 * 1024))} native=${params.nativeEnabled ? "on" : "off"} nativeSkills=${params.nativeSkillsEnabled ? "on" : "off"} accessGroups=${params.useAccessGroups ? "on" : "off"} threadBindings=${params.threadBindingsEnabled ? "on" : "off"} threadIdleTimeout=${formatThreadBindingDurationForConfigLabel(params.threadBindingIdleTimeoutMs)} threadMaxAge=${formatThreadBindingDurationForConfigLabel(params.threadBindingMaxAgeMs)}`,
44
+ );
45
+ }
@@ -0,0 +1,362 @@
1
+ import { inspect } from "node:util";
2
+ import { formatDurationSeconds } from "openclaw/plugin-sdk/runtime-env";
3
+ import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
4
+ import { RateLimitError } from "../internal/discord.js";
5
+
6
+ const DISCORD_DEPLOY_REJECTED_ENTRY_LIMIT = 3;
7
+
8
+ type DiscordDeployErrorLike = {
9
+ status?: unknown;
10
+ statusCode?: unknown;
11
+ discordCode?: unknown;
12
+ retryAfter?: unknown;
13
+ scope?: unknown;
14
+ rawBody?: unknown;
15
+ deployRequestBody?: unknown;
16
+ deployRestMethod?: unknown;
17
+ deployRestPath?: unknown;
18
+ deployRequestMs?: unknown;
19
+ deployTimeoutMs?: unknown;
20
+ };
21
+
22
+ type DiscordDeployRateLimitDetails = {
23
+ status?: number;
24
+ retryAfterMs?: number;
25
+ scope?: string;
26
+ discordCode?: number | string;
27
+ };
28
+
29
+ export function attachDiscordDeployRequestBody(err: unknown, body: unknown) {
30
+ if (!err || typeof err !== "object" || body === undefined) {
31
+ return;
32
+ }
33
+ const deployErr = err as DiscordDeployErrorLike;
34
+ if (deployErr.deployRequestBody === undefined) {
35
+ deployErr.deployRequestBody = body;
36
+ }
37
+ }
38
+
39
+ export function attachDiscordDeployRestContext(
40
+ err: unknown,
41
+ context: {
42
+ method: string;
43
+ path: string;
44
+ requestMs: number;
45
+ timeoutMs?: number;
46
+ },
47
+ ) {
48
+ if (!err || typeof err !== "object") {
49
+ return;
50
+ }
51
+ const deployErr = err as DiscordDeployErrorLike;
52
+ deployErr.deployRestMethod = context.method;
53
+ deployErr.deployRestPath = context.path;
54
+ deployErr.deployRequestMs = context.requestMs;
55
+ if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) {
56
+ deployErr.deployTimeoutMs = context.timeoutMs;
57
+ }
58
+ }
59
+
60
+ function stringifyDiscordDeployField(value: unknown): string {
61
+ if (typeof value === "string") {
62
+ return JSON.stringify(value);
63
+ }
64
+ try {
65
+ return JSON.stringify(value);
66
+ } catch {
67
+ return inspect(value, { depth: 2, breakLength: 120 });
68
+ }
69
+ }
70
+
71
+ function readDiscordDeployRejectedFields(value: unknown): string[] {
72
+ if (Array.isArray(value)) {
73
+ return value.filter((entry): entry is string => typeof entry === "string").slice(0, 6);
74
+ }
75
+ if (!value || typeof value !== "object") {
76
+ return [];
77
+ }
78
+ return Object.keys(value).slice(0, 6);
79
+ }
80
+
81
+ function resolveDiscordRejectedDeployEntriesSource(
82
+ rawBody: unknown,
83
+ ): Record<string, unknown> | null {
84
+ if (!rawBody || typeof rawBody !== "object") {
85
+ return null;
86
+ }
87
+ const payload = rawBody as { errors?: unknown };
88
+ const errors = payload.errors && typeof payload.errors === "object" ? payload.errors : undefined;
89
+ const source = errors ?? rawBody;
90
+ return source && typeof source === "object" ? (source as Record<string, unknown>) : null;
91
+ }
92
+
93
+ function readDiscordDeployObjectField(value: unknown, field: string): unknown {
94
+ return value && typeof value === "object" && field in value
95
+ ? (value as Record<string, unknown>)[field]
96
+ : undefined;
97
+ }
98
+
99
+ function readFiniteNumber(value: unknown): number | undefined {
100
+ if (typeof value === "number" && Number.isFinite(value)) {
101
+ return value;
102
+ }
103
+ if (typeof value === "string" && value.trim().length > 0) {
104
+ const parsed = Number(value);
105
+ return Number.isFinite(parsed) ? parsed : undefined;
106
+ }
107
+ return undefined;
108
+ }
109
+
110
+ function formatDurationMs(ms: number): string {
111
+ return formatDurationSeconds(ms, { decimals: ms >= 1000 ? 1 : 0 });
112
+ }
113
+
114
+ function isAbortLikeError(err: unknown): boolean {
115
+ if (!err || typeof err !== "object") {
116
+ return false;
117
+ }
118
+ const name = "name" in err && typeof err.name === "string" ? err.name : undefined;
119
+ const message = formatErrorMessage(err);
120
+ return (
121
+ name === "AbortError" ||
122
+ message === "This operation was aborted" ||
123
+ message === "The operation was aborted" ||
124
+ /\boperation was aborted\b/i.test(message)
125
+ );
126
+ }
127
+
128
+ function formatDiscordDeployRestOperation(err: DiscordDeployErrorLike): string {
129
+ const method =
130
+ typeof err.deployRestMethod === "string" && err.deployRestMethod.trim().length > 0
131
+ ? err.deployRestMethod.toUpperCase()
132
+ : undefined;
133
+ const path =
134
+ typeof err.deployRestPath === "string" && err.deployRestPath.trim().length > 0
135
+ ? err.deployRestPath
136
+ : undefined;
137
+ if (method && path) {
138
+ return `${method} ${path}`;
139
+ }
140
+ if (method) {
141
+ return method;
142
+ }
143
+ if (path) {
144
+ return path;
145
+ }
146
+ return "request";
147
+ }
148
+
149
+ export function formatDiscordDeployErrorMessage(err: unknown): string {
150
+ if (!isAbortLikeError(err)) {
151
+ return formatErrorMessage(err);
152
+ }
153
+ const deployErr =
154
+ err && typeof err === "object"
155
+ ? (err as DiscordDeployErrorLike)
156
+ : ({} as DiscordDeployErrorLike);
157
+ const requestMs = readFiniteNumber(deployErr.deployRequestMs);
158
+ const timeoutMs = readFiniteNumber(deployErr.deployTimeoutMs);
159
+ const operation = formatDiscordDeployRestOperation(deployErr);
160
+ const hasRestContext =
161
+ requestMs !== undefined ||
162
+ timeoutMs !== undefined ||
163
+ deployErr.deployRestMethod !== undefined ||
164
+ deployErr.deployRestPath !== undefined;
165
+ if (!hasRestContext) {
166
+ return "Discord REST request was aborted";
167
+ }
168
+ const timing: string[] = [];
169
+ if (timeoutMs !== undefined) {
170
+ timing.push(`timeout=${formatDurationMs(timeoutMs)}`);
171
+ }
172
+ if (requestMs !== undefined) {
173
+ timing.push(`observed=${formatDurationMs(requestMs)}`);
174
+ }
175
+ const timingText = timing.length > 0 ? ` (${timing.join(", ")})` : "";
176
+ if (timeoutMs !== undefined && requestMs !== undefined && requestMs >= timeoutMs) {
177
+ return `Discord REST ${operation} timed out${timingText}`;
178
+ }
179
+ return `Discord REST ${operation} was aborted${timingText}`;
180
+ }
181
+
182
+ export function resolveDiscordDeployRateLimitDetails(
183
+ err: unknown,
184
+ ): DiscordDeployRateLimitDetails | undefined {
185
+ if (!err || typeof err !== "object") {
186
+ return undefined;
187
+ }
188
+ const deployErr = err as DiscordDeployErrorLike;
189
+ const status = readFiniteNumber(deployErr.status) ?? readFiniteNumber(deployErr.statusCode);
190
+ const retryAfterSeconds =
191
+ readFiniteNumber(deployErr.retryAfter) ??
192
+ readFiniteNumber(readDiscordDeployObjectField(deployErr.rawBody, "retry_after"));
193
+ const isRateLimit =
194
+ err instanceof RateLimitError || status === 429 || retryAfterSeconds !== undefined;
195
+ if (!isRateLimit) {
196
+ return undefined;
197
+ }
198
+ const rawGlobal = readDiscordDeployObjectField(deployErr.rawBody, "global");
199
+ const scope =
200
+ typeof deployErr.scope === "string" && deployErr.scope.trim().length > 0
201
+ ? deployErr.scope
202
+ : rawGlobal === true
203
+ ? "global"
204
+ : rawGlobal === false
205
+ ? "route"
206
+ : undefined;
207
+ const discordCode =
208
+ typeof deployErr.discordCode === "number" || typeof deployErr.discordCode === "string"
209
+ ? deployErr.discordCode
210
+ : undefined;
211
+ return {
212
+ status,
213
+ retryAfterMs:
214
+ retryAfterSeconds === undefined ? undefined : Math.max(0, retryAfterSeconds * 1000),
215
+ scope,
216
+ discordCode,
217
+ };
218
+ }
219
+
220
+ export function formatDiscordDeployRateLimitDetails(err: unknown): string {
221
+ const rateLimit = resolveDiscordDeployRateLimitDetails(err);
222
+ if (!rateLimit) {
223
+ return "";
224
+ }
225
+ const details: string[] = [];
226
+ if (typeof rateLimit.status === "number") {
227
+ details.push(`status=${rateLimit.status}`);
228
+ }
229
+ if (typeof rateLimit.retryAfterMs === "number") {
230
+ details.push(
231
+ `retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, {
232
+ decimals: 1,
233
+ })}`,
234
+ );
235
+ }
236
+ if (rateLimit.scope) {
237
+ details.push(`scope=${rateLimit.scope}`);
238
+ }
239
+ if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") {
240
+ details.push(`code=${rateLimit.discordCode}`);
241
+ }
242
+ return details.length > 0 ? ` (${details.join(", ")})` : "";
243
+ }
244
+
245
+ export function formatDiscordDeployRateLimitWarning(
246
+ err: unknown,
247
+ accountId: string,
248
+ ): string | undefined {
249
+ const rateLimit = resolveDiscordDeployRateLimitDetails(err);
250
+ if (!rateLimit) {
251
+ return undefined;
252
+ }
253
+ const parts = [`discord: native slash command deploy rate limited for ${accountId}`];
254
+ if (typeof rateLimit.retryAfterMs === "number") {
255
+ parts.push(
256
+ `retry after ${formatDurationSeconds(rateLimit.retryAfterMs, {
257
+ decimals: 1,
258
+ })}`,
259
+ );
260
+ }
261
+ if (rateLimit.scope) {
262
+ parts.push(`scope=${rateLimit.scope}`);
263
+ }
264
+ if (typeof rateLimit.discordCode === "number" || typeof rateLimit.discordCode === "string") {
265
+ parts.push(`code=${rateLimit.discordCode}`);
266
+ }
267
+ return `${parts.join("; ")}. Existing slash commands stay active. Message send/receive is unaffected.`;
268
+ }
269
+
270
+ function formatDiscordRejectedDeployEntries(params: {
271
+ rawBody: unknown;
272
+ requestBody: unknown;
273
+ }): string[] {
274
+ const requestBody = Array.isArray(params.requestBody) ? params.requestBody : null;
275
+ const rejectedEntriesSource = resolveDiscordRejectedDeployEntriesSource(params.rawBody);
276
+ if (!rejectedEntriesSource || !requestBody || requestBody.length === 0) {
277
+ return [];
278
+ }
279
+ const rawEntries = Object.entries(rejectedEntriesSource).filter(([key]) => /^\d+$/.test(key));
280
+ return rawEntries.slice(0, DISCORD_DEPLOY_REJECTED_ENTRY_LIMIT).flatMap(([key, value]) => {
281
+ const index = Number.parseInt(key, 10);
282
+ if (!Number.isFinite(index) || index < 0 || index >= requestBody.length) {
283
+ return [];
284
+ }
285
+ const command = requestBody[index];
286
+ if (!command || typeof command !== "object") {
287
+ return [`#${index} fields=${readDiscordDeployRejectedFields(value).join("|") || "unknown"}`];
288
+ }
289
+ const payload = command as {
290
+ name?: unknown;
291
+ description?: unknown;
292
+ options?: unknown;
293
+ };
294
+ const parts = [
295
+ `#${index}`,
296
+ `fields=${readDiscordDeployRejectedFields(value).join("|") || "unknown"}`,
297
+ ];
298
+ if (typeof payload.name === "string" && payload.name.trim().length > 0) {
299
+ parts.push(`name=${payload.name}`);
300
+ }
301
+ if (payload.description !== undefined) {
302
+ parts.push(`description=${stringifyDiscordDeployField(payload.description)}`);
303
+ }
304
+ if (Array.isArray(payload.options) && payload.options.length > 0) {
305
+ parts.push(`options=${payload.options.length}`);
306
+ }
307
+ return [parts.join(" ")];
308
+ });
309
+ }
310
+
311
+ export function formatDiscordDeployErrorDetails(err: unknown): string {
312
+ if (!err || typeof err !== "object") {
313
+ return "";
314
+ }
315
+ const rateLimitDetails = formatDiscordDeployRateLimitDetails(err);
316
+ if (rateLimitDetails) {
317
+ return rateLimitDetails;
318
+ }
319
+ const status = (err as DiscordDeployErrorLike).status;
320
+ const discordCode = (err as DiscordDeployErrorLike).discordCode;
321
+ const rawBody = (err as DiscordDeployErrorLike).rawBody;
322
+ const requestBody = (err as DiscordDeployErrorLike).deployRequestBody;
323
+ const details: string[] = [];
324
+ if (typeof status === "number") {
325
+ details.push(`status=${status}`);
326
+ }
327
+ if (typeof discordCode === "number" || typeof discordCode === "string") {
328
+ details.push(`code=${discordCode}`);
329
+ }
330
+ if (rawBody !== undefined) {
331
+ let bodyText = "";
332
+ try {
333
+ bodyText = JSON.stringify(rawBody);
334
+ } catch {
335
+ bodyText =
336
+ typeof rawBody === "string" ? rawBody : inspect(rawBody, { depth: 3, breakLength: 120 });
337
+ }
338
+ if (bodyText) {
339
+ const maxLen = 800;
340
+ const trimmed = bodyText.length > maxLen ? `${bodyText.slice(0, maxLen)}...` : bodyText;
341
+ details.push(`body=${trimmed}`);
342
+ }
343
+ }
344
+ const rejectedEntries = formatDiscordRejectedDeployEntries({ rawBody, requestBody });
345
+ if (rejectedEntries.length > 0) {
346
+ details.push(`rejected=${rejectedEntries.join("; ")}`);
347
+ }
348
+ return details.length > 0 ? ` (${details.join(", ")})` : "";
349
+ }
350
+
351
+ export function isDiscordDeployDailyCreateLimit(err: unknown): boolean {
352
+ if (!err || typeof err !== "object") {
353
+ return false;
354
+ }
355
+ const deployErr = err as DiscordDeployErrorLike;
356
+ const discordCode = readFiniteNumber(deployErr.discordCode);
357
+ const rawCode = readFiniteNumber(readDiscordDeployObjectField(deployErr.rawBody, "code"));
358
+ return (
359
+ (discordCode === 30034 || rawCode === 30034) &&
360
+ /daily application command creates/i.test(formatErrorMessage(err))
361
+ );
362
+ }