@gakr-gakr/discord 0.1.0

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 (353) 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/autobot.plugin.json +15 -0
  5. package/channel-config-api.ts +1 -0
  6. package/channel-plugin-api.ts +3 -0
  7. package/config-api.ts +4 -0
  8. package/configured-state.ts +6 -0
  9. package/contract-api.ts +21 -0
  10. package/directory-contract-api.ts +4 -0
  11. package/doctor-contract-api.ts +1 -0
  12. package/index.ts +24 -0
  13. package/package.json +79 -0
  14. package/runtime-api.actions.ts +15 -0
  15. package/runtime-api.lookup.ts +22 -0
  16. package/runtime-api.monitor.ts +50 -0
  17. package/runtime-api.send.ts +79 -0
  18. package/runtime-api.threads.ts +31 -0
  19. package/runtime-api.ts +181 -0
  20. package/runtime-setter-api.ts +3 -0
  21. package/secret-contract-api.ts +4 -0
  22. package/security-audit-contract-api.ts +1 -0
  23. package/security-contract-api.ts +4 -0
  24. package/session-key-api.ts +1 -0
  25. package/setup-entry.ts +9 -0
  26. package/setup-plugin-api.ts +3 -0
  27. package/src/account-inspect.ts +131 -0
  28. package/src/accounts.ts +205 -0
  29. package/src/actions/handle-action.guild-admin.ts +421 -0
  30. package/src/actions/handle-action.ts +402 -0
  31. package/src/actions/runtime.guild.ts +446 -0
  32. package/src/actions/runtime.messaging.messages.ts +226 -0
  33. package/src/actions/runtime.messaging.reactions.ts +67 -0
  34. package/src/actions/runtime.messaging.runtime.ts +73 -0
  35. package/src/actions/runtime.messaging.send.ts +336 -0
  36. package/src/actions/runtime.messaging.shared.ts +97 -0
  37. package/src/actions/runtime.messaging.ts +37 -0
  38. package/src/actions/runtime.moderation-shared.ts +48 -0
  39. package/src/actions/runtime.moderation.ts +116 -0
  40. package/src/actions/runtime.presence.ts +117 -0
  41. package/src/actions/runtime.shared.ts +86 -0
  42. package/src/actions/runtime.ts +87 -0
  43. package/src/api.ts +219 -0
  44. package/src/approval-handler.runtime.ts +636 -0
  45. package/src/approval-native.ts +219 -0
  46. package/src/approval-runtime.ts +14 -0
  47. package/src/approval-shared.ts +56 -0
  48. package/src/audit-core.ts +178 -0
  49. package/src/audit.ts +32 -0
  50. package/src/channel-actions.runtime.ts +1 -0
  51. package/src/channel-actions.ts +254 -0
  52. package/src/channel-api.ts +29 -0
  53. package/src/channel.conversation.ts +159 -0
  54. package/src/channel.loaders.ts +50 -0
  55. package/src/channel.runtime.ts +1 -0
  56. package/src/channel.setup.ts +12 -0
  57. package/src/channel.ts +728 -0
  58. package/src/chunk.ts +321 -0
  59. package/src/client.ts +143 -0
  60. package/src/component-custom-id.ts +72 -0
  61. package/src/components-registry.ts +356 -0
  62. package/src/components.builders.ts +410 -0
  63. package/src/components.modal.ts +124 -0
  64. package/src/components.parse.ts +407 -0
  65. package/src/components.ts +54 -0
  66. package/src/components.types.ts +187 -0
  67. package/src/config-schema.ts +6 -0
  68. package/src/config-ui-hints.ts +354 -0
  69. package/src/conversation-identity.ts +58 -0
  70. package/src/delivery-retry.ts +56 -0
  71. package/src/directory-cache.ts +116 -0
  72. package/src/directory-config.ts +58 -0
  73. package/src/directory-live.ts +135 -0
  74. package/src/doctor-contract.ts +477 -0
  75. package/src/doctor-shared.ts +5 -0
  76. package/src/doctor.ts +340 -0
  77. package/src/draft-chunking.ts +43 -0
  78. package/src/draft-stream.ts +162 -0
  79. package/src/error-body.ts +38 -0
  80. package/src/exec-approvals.ts +110 -0
  81. package/src/gateway-logging.ts +67 -0
  82. package/src/group-policy.ts +113 -0
  83. package/src/guilds.ts +29 -0
  84. package/src/inbound-event-delivery.ts +135 -0
  85. package/src/interactive-dispatch.ts +104 -0
  86. package/src/internal/api.commands.ts +51 -0
  87. package/src/internal/api.guild.ts +164 -0
  88. package/src/internal/api.interactions.ts +53 -0
  89. package/src/internal/api.messages.ts +113 -0
  90. package/src/internal/api.reactions.ts +38 -0
  91. package/src/internal/api.ts +61 -0
  92. package/src/internal/api.users.ts +19 -0
  93. package/src/internal/api.webhooks.ts +13 -0
  94. package/src/internal/client.ts +310 -0
  95. package/src/internal/command-deploy.ts +352 -0
  96. package/src/internal/commands.ts +188 -0
  97. package/src/internal/components.base.ts +65 -0
  98. package/src/internal/components.message.ts +279 -0
  99. package/src/internal/components.modal.ts +95 -0
  100. package/src/internal/components.ts +31 -0
  101. package/src/internal/discord.ts +11 -0
  102. package/src/internal/embeds.ts +35 -0
  103. package/src/internal/entity-cache.ts +98 -0
  104. package/src/internal/event-queue.ts +185 -0
  105. package/src/internal/gateway-close-codes.ts +25 -0
  106. package/src/internal/gateway-dispatch.ts +96 -0
  107. package/src/internal/gateway-identify-limiter.ts +26 -0
  108. package/src/internal/gateway-lifecycle.ts +75 -0
  109. package/src/internal/gateway-rate-limit.ts +104 -0
  110. package/src/internal/gateway.ts +479 -0
  111. package/src/internal/interaction-dispatch.ts +162 -0
  112. package/src/internal/interaction-options.ts +98 -0
  113. package/src/internal/interaction-response.ts +53 -0
  114. package/src/internal/interactions.ts +378 -0
  115. package/src/internal/listeners.ts +91 -0
  116. package/src/internal/modal-fields.ts +95 -0
  117. package/src/internal/payload.ts +69 -0
  118. package/src/internal/rest-body.ts +115 -0
  119. package/src/internal/rest-errors.ts +88 -0
  120. package/src/internal/rest-routes.ts +50 -0
  121. package/src/internal/rest-scheduler.ts +557 -0
  122. package/src/internal/rest.ts +322 -0
  123. package/src/internal/schemas.ts +36 -0
  124. package/src/internal/structures.ts +280 -0
  125. package/src/internal/test-builders.test-support.ts +167 -0
  126. package/src/internal/voice.ts +49 -0
  127. package/src/media-detection.ts +28 -0
  128. package/src/mentions.ts +147 -0
  129. package/src/monitor/ack-reactions.ts +70 -0
  130. package/src/monitor/agent-components-auth.ts +7 -0
  131. package/src/monitor/agent-components-context.ts +154 -0
  132. package/src/monitor/agent-components-data.ts +224 -0
  133. package/src/monitor/agent-components-dm-auth.ts +177 -0
  134. package/src/monitor/agent-components-guild-auth.ts +322 -0
  135. package/src/monitor/agent-components-helpers.runtime.ts +3 -0
  136. package/src/monitor/agent-components-helpers.ts +34 -0
  137. package/src/monitor/agent-components-reply.ts +10 -0
  138. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  139. package/src/monitor/agent-components.dispatch.ts +359 -0
  140. package/src/monitor/agent-components.handlers.ts +303 -0
  141. package/src/monitor/agent-components.modal.ts +160 -0
  142. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  143. package/src/monitor/agent-components.runtime.ts +14 -0
  144. package/src/monitor/agent-components.system-controls.ts +215 -0
  145. package/src/monitor/agent-components.ts +70 -0
  146. package/src/monitor/agent-components.types.ts +58 -0
  147. package/src/monitor/agent-components.wildcard-controls.ts +171 -0
  148. package/src/monitor/allow-list.ts +631 -0
  149. package/src/monitor/auto-presence.ts +356 -0
  150. package/src/monitor/channel-access.ts +102 -0
  151. package/src/monitor/commands.ts +9 -0
  152. package/src/monitor/dm-command-auth.ts +259 -0
  153. package/src/monitor/dm-command-decision.ts +49 -0
  154. package/src/monitor/exec-approvals.ts +161 -0
  155. package/src/monitor/format.ts +45 -0
  156. package/src/monitor/gateway-handle.ts +34 -0
  157. package/src/monitor/gateway-metadata.ts +298 -0
  158. package/src/monitor/gateway-plugin.ts +302 -0
  159. package/src/monitor/gateway-registry.ts +37 -0
  160. package/src/monitor/gateway-supervisor.ts +206 -0
  161. package/src/monitor/inbound-context.ts +95 -0
  162. package/src/monitor/inbound-dedupe.ts +79 -0
  163. package/src/monitor/inbound-job.ts +118 -0
  164. package/src/monitor/listeners.queue.ts +91 -0
  165. package/src/monitor/listeners.reactions.ts +594 -0
  166. package/src/monitor/listeners.ts +150 -0
  167. package/src/monitor/message-channel-info.ts +96 -0
  168. package/src/monitor/message-forwarded.ts +114 -0
  169. package/src/monitor/message-handler.batch-gate.ts +19 -0
  170. package/src/monitor/message-handler.context.ts +492 -0
  171. package/src/monitor/message-handler.dm-preflight.ts +119 -0
  172. package/src/monitor/message-handler.draft-preview.ts +436 -0
  173. package/src/monitor/message-handler.hydration.ts +198 -0
  174. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  175. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  176. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  177. package/src/monitor/message-handler.preflight-context.ts +54 -0
  178. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  179. package/src/monitor/message-handler.preflight-history.ts +23 -0
  180. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  181. package/src/monitor/message-handler.preflight-pluralkit.ts +28 -0
  182. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  183. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  184. package/src/monitor/message-handler.preflight.ts +822 -0
  185. package/src/monitor/message-handler.preflight.types.ts +115 -0
  186. package/src/monitor/message-handler.process.ts +1033 -0
  187. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  188. package/src/monitor/message-handler.ts +309 -0
  189. package/src/monitor/message-media.ts +536 -0
  190. package/src/monitor/message-run-queue.ts +101 -0
  191. package/src/monitor/message-text.ts +171 -0
  192. package/src/monitor/message-utils.ts +34 -0
  193. package/src/monitor/model-picker-preferences.ts +184 -0
  194. package/src/monitor/model-picker.state.ts +364 -0
  195. package/src/monitor/model-picker.test-utils.ts +26 -0
  196. package/src/monitor/model-picker.ts +38 -0
  197. package/src/monitor/model-picker.view.ts +722 -0
  198. package/src/monitor/native-command-agent-reply.ts +125 -0
  199. package/src/monitor/native-command-arg-ui.ts +233 -0
  200. package/src/monitor/native-command-auth.ts +309 -0
  201. package/src/monitor/native-command-bypass.ts +13 -0
  202. package/src/monitor/native-command-context.ts +109 -0
  203. package/src/monitor/native-command-dispatch.ts +35 -0
  204. package/src/monitor/native-command-model-picker-apply.ts +209 -0
  205. package/src/monitor/native-command-model-picker-interaction.ts +516 -0
  206. package/src/monitor/native-command-model-picker-ui.ts +357 -0
  207. package/src/monitor/native-command-reply.ts +185 -0
  208. package/src/monitor/native-command-route.ts +91 -0
  209. package/src/monitor/native-command-status.ts +76 -0
  210. package/src/monitor/native-command-ui.ts +26 -0
  211. package/src/monitor/native-command-ui.types.ts +20 -0
  212. package/src/monitor/native-command.args.ts +45 -0
  213. package/src/monitor/native-command.options.ts +153 -0
  214. package/src/monitor/native-command.runtime.ts +51 -0
  215. package/src/monitor/native-command.ts +747 -0
  216. package/src/monitor/native-command.types.ts +9 -0
  217. package/src/monitor/native-interaction-channel-context.ts +50 -0
  218. package/src/monitor/preflight-audio.runtime.ts +9 -0
  219. package/src/monitor/preflight-audio.ts +130 -0
  220. package/src/monitor/presence-cache.ts +61 -0
  221. package/src/monitor/presence.ts +50 -0
  222. package/src/monitor/provider-session.runtime.ts +12 -0
  223. package/src/monitor/provider.acp.ts +89 -0
  224. package/src/monitor/provider.allowlist.ts +398 -0
  225. package/src/monitor/provider.cleanup.ts +41 -0
  226. package/src/monitor/provider.commands.ts +129 -0
  227. package/src/monitor/provider.config-log.ts +45 -0
  228. package/src/monitor/provider.deploy-errors.ts +362 -0
  229. package/src/monitor/provider.deploy.ts +221 -0
  230. package/src/monitor/provider.interactions.ts +160 -0
  231. package/src/monitor/provider.lifecycle.ts +562 -0
  232. package/src/monitor/provider.runtime.ts +1 -0
  233. package/src/monitor/provider.startup-log.ts +32 -0
  234. package/src/monitor/provider.startup.ts +323 -0
  235. package/src/monitor/provider.ts +688 -0
  236. package/src/monitor/reply-context.ts +64 -0
  237. package/src/monitor/reply-delivery.ts +216 -0
  238. package/src/monitor/reply-safety.ts +96 -0
  239. package/src/monitor/rest-fetch.ts +97 -0
  240. package/src/monitor/route-resolution.ts +140 -0
  241. package/src/monitor/sender-identity.ts +81 -0
  242. package/src/monitor/startup-status.ts +10 -0
  243. package/src/monitor/status.ts +22 -0
  244. package/src/monitor/system-events.ts +55 -0
  245. package/src/monitor/thread-bindings.config.ts +35 -0
  246. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  247. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  248. package/src/monitor/thread-bindings.manager.ts +554 -0
  249. package/src/monitor/thread-bindings.messages.ts +6 -0
  250. package/src/monitor/thread-bindings.persona.ts +25 -0
  251. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  252. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  253. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  254. package/src/monitor/thread-bindings.state.ts +540 -0
  255. package/src/monitor/thread-bindings.ts +48 -0
  256. package/src/monitor/thread-bindings.types.ts +83 -0
  257. package/src/monitor/thread-channel-context.ts +112 -0
  258. package/src/monitor/thread-session-close.ts +63 -0
  259. package/src/monitor/thread-title.ts +181 -0
  260. package/src/monitor/threading.auto-thread.ts +287 -0
  261. package/src/monitor/threading.cache.ts +45 -0
  262. package/src/monitor/threading.starter.ts +288 -0
  263. package/src/monitor/threading.ts +20 -0
  264. package/src/monitor/threading.types.ts +102 -0
  265. package/src/monitor/timeouts.ts +84 -0
  266. package/src/monitor/typing.ts +17 -0
  267. package/src/monitor.gateway.ts +75 -0
  268. package/src/monitor.ts +28 -0
  269. package/src/network-config.ts +79 -0
  270. package/src/normalize.ts +86 -0
  271. package/src/outbound-adapter.ts +327 -0
  272. package/src/outbound-approval.ts +29 -0
  273. package/src/outbound-components.ts +86 -0
  274. package/src/outbound-payload.ts +208 -0
  275. package/src/outbound-send-context.ts +92 -0
  276. package/src/outbound-session-route.ts +72 -0
  277. package/src/pluralkit.ts +58 -0
  278. package/src/preview-streaming.ts +18 -0
  279. package/src/probe.runtime.ts +1 -0
  280. package/src/probe.ts +237 -0
  281. package/src/proxy-fetch.ts +92 -0
  282. package/src/proxy-request-client.ts +21 -0
  283. package/src/recipient-resolution.ts +39 -0
  284. package/src/resolve-allowlist-common.ts +39 -0
  285. package/src/resolve-channels.ts +369 -0
  286. package/src/resolve-users.ts +184 -0
  287. package/src/retry.ts +98 -0
  288. package/src/runtime-api.ts +64 -0
  289. package/src/runtime-config.ts +16 -0
  290. package/src/runtime.ts +23 -0
  291. package/src/secret-config-contract.ts +140 -0
  292. package/src/security-audit.runtime.ts +1 -0
  293. package/src/security-audit.ts +208 -0
  294. package/src/security-contract.ts +47 -0
  295. package/src/security-doctor.ts +20 -0
  296. package/src/security.ts +60 -0
  297. package/src/send-target-parsing.ts +14 -0
  298. package/src/send.channels.ts +139 -0
  299. package/src/send.components.ts +391 -0
  300. package/src/send.emojis-stickers.ts +57 -0
  301. package/src/send.guild.ts +170 -0
  302. package/src/send.message-request.ts +112 -0
  303. package/src/send.messages.ts +229 -0
  304. package/src/send.outbound.ts +459 -0
  305. package/src/send.permissions.ts +283 -0
  306. package/src/send.reactions.ts +155 -0
  307. package/src/send.receipt.ts +69 -0
  308. package/src/send.shared.ts +469 -0
  309. package/src/send.ts +82 -0
  310. package/src/send.types.ts +191 -0
  311. package/src/send.typing.ts +9 -0
  312. package/src/send.voice.ts +140 -0
  313. package/src/send.webhook.ts +137 -0
  314. package/src/session-contract.ts +3 -0
  315. package/src/session-key-normalization.ts +47 -0
  316. package/src/setup-account-state.ts +144 -0
  317. package/src/setup-adapter.ts +14 -0
  318. package/src/setup-core.ts +215 -0
  319. package/src/setup-runtime-helpers.ts +10 -0
  320. package/src/setup-surface.ts +132 -0
  321. package/src/shared-interactive.ts +167 -0
  322. package/src/shared.ts +197 -0
  323. package/src/status-issues.ts +201 -0
  324. package/src/subagent-hooks.ts +232 -0
  325. package/src/target-parsing.ts +70 -0
  326. package/src/target-resolver.ts +129 -0
  327. package/src/targets.ts +12 -0
  328. package/src/token.ts +107 -0
  329. package/src/ui-colors.ts +27 -0
  330. package/src/ui.ts +20 -0
  331. package/src/voice/access.ts +126 -0
  332. package/src/voice/audio.ts +249 -0
  333. package/src/voice/capture-state.ts +120 -0
  334. package/src/voice/command.ts +284 -0
  335. package/src/voice/config.ts +8 -0
  336. package/src/voice/ingress.ts +164 -0
  337. package/src/voice/manager.runtime.ts +14 -0
  338. package/src/voice/manager.ts +1155 -0
  339. package/src/voice/prompt.ts +22 -0
  340. package/src/voice/realtime.ts +1370 -0
  341. package/src/voice/receive-recovery.ts +159 -0
  342. package/src/voice/sanitize.ts +29 -0
  343. package/src/voice/sdk-runtime.ts +14 -0
  344. package/src/voice/segment.ts +160 -0
  345. package/src/voice/session.ts +81 -0
  346. package/src/voice/speaker-context.ts +127 -0
  347. package/src/voice/tts.ts +151 -0
  348. package/src/voice-message.ts +474 -0
  349. package/subagent-hooks-api.ts +27 -0
  350. package/test-api.ts +4 -0
  351. package/thread-binding-api.ts +1 -0
  352. package/timeouts.ts +6 -0
  353. package/tsconfig.json +16 -0
@@ -0,0 +1,10 @@
1
+ export function formatDiscordStartupStatusMessage(params: {
2
+ gatewayReady: boolean;
3
+ botIdentity?: string;
4
+ }): string {
5
+ const identitySuffix = params.botIdentity ? ` as ${params.botIdentity}` : "";
6
+ if (params.gatewayReady) {
7
+ return `logged in to discord${identitySuffix}`;
8
+ }
9
+ return `discord client initialized${identitySuffix}; awaiting gateway readiness`;
10
+ }
@@ -0,0 +1,22 @@
1
+ type DiscordMonitorStatusPatch = {
2
+ connected?: boolean;
3
+ lastEventAt?: number | null;
4
+ lastTransportActivityAt?: number | null;
5
+ lastConnectedAt?: number | null;
6
+ lastDisconnect?:
7
+ | string
8
+ | {
9
+ at: number;
10
+ status?: number;
11
+ error?: string;
12
+ loggedOut?: boolean;
13
+ }
14
+ | null;
15
+ lastInboundAt?: number | null;
16
+ lastError?: string | null;
17
+ busy?: boolean;
18
+ activeRuns?: number;
19
+ lastRunActivityAt?: number | null;
20
+ };
21
+
22
+ export type DiscordMonitorStatusSink = (patch: DiscordMonitorStatusPatch) => void;
@@ -0,0 +1,55 @@
1
+ import { type Message, MessageType } from "../internal/discord.js";
2
+ import { formatDiscordUserTag } from "./format.js";
3
+
4
+ export function resolveDiscordSystemEvent(message: Message, location: string): string | null {
5
+ switch (message.type) {
6
+ case MessageType.ChannelPinnedMessage:
7
+ return buildDiscordSystemEvent(message, location, "pinned a message");
8
+ case MessageType.RecipientAdd:
9
+ return buildDiscordSystemEvent(message, location, "added a recipient");
10
+ case MessageType.RecipientRemove:
11
+ return buildDiscordSystemEvent(message, location, "removed a recipient");
12
+ case MessageType.UserJoin:
13
+ return buildDiscordSystemEvent(message, location, "user joined");
14
+ case MessageType.GuildBoost:
15
+ return buildDiscordSystemEvent(message, location, "boosted the server");
16
+ case MessageType.GuildBoostTier1:
17
+ return buildDiscordSystemEvent(message, location, "boosted the server (Tier 1 reached)");
18
+ case MessageType.GuildBoostTier2:
19
+ return buildDiscordSystemEvent(message, location, "boosted the server (Tier 2 reached)");
20
+ case MessageType.GuildBoostTier3:
21
+ return buildDiscordSystemEvent(message, location, "boosted the server (Tier 3 reached)");
22
+ case MessageType.ThreadCreated:
23
+ return buildDiscordSystemEvent(message, location, "created a thread");
24
+ case MessageType.AutoModerationAction:
25
+ return buildDiscordSystemEvent(message, location, "auto moderation action");
26
+ case MessageType.GuildIncidentAlertModeEnabled:
27
+ return buildDiscordSystemEvent(message, location, "raid protection enabled");
28
+ case MessageType.GuildIncidentAlertModeDisabled:
29
+ return buildDiscordSystemEvent(message, location, "raid protection disabled");
30
+ case MessageType.GuildIncidentReportRaid:
31
+ return buildDiscordSystemEvent(message, location, "raid reported");
32
+ case MessageType.GuildIncidentReportFalseAlarm:
33
+ return buildDiscordSystemEvent(message, location, "raid report marked false alarm");
34
+ case MessageType.StageStart:
35
+ return buildDiscordSystemEvent(message, location, "stage started");
36
+ case MessageType.StageEnd:
37
+ return buildDiscordSystemEvent(message, location, "stage ended");
38
+ case MessageType.StageSpeaker:
39
+ return buildDiscordSystemEvent(message, location, "stage speaker updated");
40
+ case MessageType.StageTopic:
41
+ return buildDiscordSystemEvent(message, location, "stage topic updated");
42
+ case MessageType.PollResult:
43
+ return buildDiscordSystemEvent(message, location, "poll results posted");
44
+ case MessageType.PurchaseNotification:
45
+ return buildDiscordSystemEvent(message, location, "purchase notification");
46
+ default:
47
+ return null;
48
+ }
49
+ }
50
+
51
+ function buildDiscordSystemEvent(message: Message, location: string, action: string) {
52
+ const authorLabel = message.author ? formatDiscordUserTag(message.author) : "";
53
+ const actor = authorLabel ? `${authorLabel} ` : "";
54
+ return `Discord system: ${actor}${action} in ${location}`;
55
+ }
@@ -0,0 +1,35 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import {
3
+ resolveThreadBindingIdleTimeoutMs,
4
+ resolveThreadBindingMaxAgeMs,
5
+ resolveThreadBindingsEnabled,
6
+ } from "autobot/plugin-sdk/conversation-runtime";
7
+ import { normalizeAccountId } from "autobot/plugin-sdk/routing";
8
+
9
+ export { resolveThreadBindingsEnabled };
10
+
11
+ export function resolveDiscordThreadBindingIdleTimeoutMs(params: {
12
+ cfg: AutoBotConfig;
13
+ accountId?: string;
14
+ }): number {
15
+ const accountId = normalizeAccountId(params.accountId);
16
+ const root = params.cfg.channels?.discord?.threadBindings;
17
+ const account = params.cfg.channels?.discord?.accounts?.[accountId]?.threadBindings;
18
+ return resolveThreadBindingIdleTimeoutMs({
19
+ channelIdleHoursRaw: account?.idleHours ?? root?.idleHours,
20
+ sessionIdleHoursRaw: params.cfg.session?.threadBindings?.idleHours,
21
+ });
22
+ }
23
+
24
+ export function resolveDiscordThreadBindingMaxAgeMs(params: {
25
+ cfg: AutoBotConfig;
26
+ accountId?: string;
27
+ }): number {
28
+ const accountId = normalizeAccountId(params.accountId);
29
+ const root = params.cfg.channels?.discord?.threadBindings;
30
+ const account = params.cfg.channels?.discord?.accounts?.[accountId]?.threadBindings;
31
+ return resolveThreadBindingMaxAgeMs({
32
+ channelMaxAgeHoursRaw: account?.maxAgeHours ?? root?.maxAgeHours,
33
+ sessionMaxAgeHoursRaw: params.cfg.session?.threadBindings?.maxAgeHours,
34
+ });
35
+ }
@@ -0,0 +1,310 @@
1
+ import { ChannelType } from "discord-api-types/v10";
2
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
3
+ import { logVerbose } from "autobot/plugin-sdk/runtime-env";
4
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
5
+ import { createDiscordRestClient } from "../client.js";
6
+ import { createChannelWebhook, getChannel } from "../internal/discord.js";
7
+ import { sendMessageDiscord, sendWebhookMessageDiscord } from "../send.js";
8
+ import { createThreadDiscord } from "../send.messages.js";
9
+ import { resolveDiscordChannelId } from "../target-parsing.js";
10
+ import { resolveDiscordChannelIdSafe, resolveDiscordChannelInfoSafe } from "./channel-access.js";
11
+ import { resolveThreadBindingPersonaFromRecord } from "./thread-bindings.persona.js";
12
+ import {
13
+ BINDINGS_BY_THREAD_ID,
14
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL,
15
+ rememberReusableWebhook,
16
+ toReusableWebhookKey,
17
+ } from "./thread-bindings.state.js";
18
+ import {
19
+ DISCORD_UNKNOWN_CHANNEL_ERROR_CODE,
20
+ type ThreadBindingRecord,
21
+ } from "./thread-bindings.types.js";
22
+
23
+ function buildThreadTarget(threadId: string): string {
24
+ return /^(channel:|user:)/i.test(threadId) ? threadId : `channel:${threadId}`;
25
+ }
26
+
27
+ export function isThreadArchived(raw: unknown): boolean {
28
+ if (!raw || typeof raw !== "object") {
29
+ return false;
30
+ }
31
+ const asRecord = raw as {
32
+ archived?: unknown;
33
+ thread_metadata?: { archived?: unknown };
34
+ threadMetadata?: { archived?: unknown };
35
+ };
36
+ if (asRecord.archived === true) {
37
+ return true;
38
+ }
39
+ if (asRecord.thread_metadata?.archived === true) {
40
+ return true;
41
+ }
42
+ if (asRecord.threadMetadata?.archived === true) {
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+
48
+ function isThreadChannelType(type: unknown): boolean {
49
+ return (
50
+ type === ChannelType.PublicThread ||
51
+ type === ChannelType.PrivateThread ||
52
+ type === ChannelType.AnnouncementThread
53
+ );
54
+ }
55
+
56
+ function normalizeDiscordBindingChannelId(raw?: string | null): string | null {
57
+ const trimmed = normalizeOptionalString(raw) ?? "";
58
+ if (!trimmed) {
59
+ return null;
60
+ }
61
+ try {
62
+ return resolveDiscordChannelId(trimmed);
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ export function summarizeDiscordError(err: unknown): string {
69
+ if (err instanceof Error) {
70
+ return err.message;
71
+ }
72
+ if (typeof err === "string") {
73
+ return err;
74
+ }
75
+ if (
76
+ typeof err === "number" ||
77
+ typeof err === "boolean" ||
78
+ typeof err === "bigint" ||
79
+ typeof err === "symbol"
80
+ ) {
81
+ return String(err);
82
+ }
83
+ return "error";
84
+ }
85
+
86
+ function extractNumericDiscordErrorValue(value: unknown): number | undefined {
87
+ if (typeof value === "number" && Number.isFinite(value)) {
88
+ return Math.trunc(value);
89
+ }
90
+ if (typeof value === "string" && /^\d+$/.test(value.trim())) {
91
+ return Number(value);
92
+ }
93
+ return undefined;
94
+ }
95
+
96
+ function extractDiscordErrorStatus(err: unknown): number | undefined {
97
+ if (!err || typeof err !== "object") {
98
+ return undefined;
99
+ }
100
+ const candidate = err as {
101
+ status?: unknown;
102
+ statusCode?: unknown;
103
+ response?: { status?: unknown };
104
+ };
105
+ return (
106
+ extractNumericDiscordErrorValue(candidate.status) ??
107
+ extractNumericDiscordErrorValue(candidate.statusCode) ??
108
+ extractNumericDiscordErrorValue(candidate.response?.status)
109
+ );
110
+ }
111
+
112
+ function extractDiscordErrorCode(err: unknown): number | undefined {
113
+ if (!err || typeof err !== "object") {
114
+ return undefined;
115
+ }
116
+ const candidate = err as {
117
+ code?: unknown;
118
+ rawError?: { code?: unknown };
119
+ body?: { code?: unknown };
120
+ response?: { body?: { code?: unknown }; data?: { code?: unknown } };
121
+ };
122
+ return (
123
+ extractNumericDiscordErrorValue(candidate.code) ??
124
+ extractNumericDiscordErrorValue(candidate.rawError?.code) ??
125
+ extractNumericDiscordErrorValue(candidate.body?.code) ??
126
+ extractNumericDiscordErrorValue(candidate.response?.body?.code) ??
127
+ extractNumericDiscordErrorValue(candidate.response?.data?.code)
128
+ );
129
+ }
130
+
131
+ export function isDiscordThreadGoneError(err: unknown): boolean {
132
+ const code = extractDiscordErrorCode(err);
133
+ if (code === DISCORD_UNKNOWN_CHANNEL_ERROR_CODE) {
134
+ return true;
135
+ }
136
+ const status = extractDiscordErrorStatus(err);
137
+ // 404: deleted/unknown channel. 403: bot no longer has access.
138
+ return status === 404 || status === 403;
139
+ }
140
+
141
+ export async function maybeSendBindingMessage(params: {
142
+ cfg: AutoBotConfig;
143
+ record: ThreadBindingRecord;
144
+ text: string;
145
+ preferWebhook?: boolean;
146
+ }) {
147
+ const text = params.text.trim();
148
+ if (!text) {
149
+ return;
150
+ }
151
+ const record = params.record;
152
+ if (params.preferWebhook !== false && record.webhookId && record.webhookToken) {
153
+ try {
154
+ await sendWebhookMessageDiscord(text, {
155
+ cfg: params.cfg,
156
+ webhookId: record.webhookId,
157
+ webhookToken: record.webhookToken,
158
+ accountId: record.accountId,
159
+ threadId: record.threadId,
160
+ username: resolveThreadBindingPersonaFromRecord(record),
161
+ });
162
+ return;
163
+ } catch (err) {
164
+ logVerbose(`discord thread binding webhook send failed: ${summarizeDiscordError(err)}`);
165
+ }
166
+ }
167
+ try {
168
+ await sendMessageDiscord(buildThreadTarget(record.threadId), text, {
169
+ cfg: params.cfg,
170
+ accountId: record.accountId,
171
+ });
172
+ } catch (err) {
173
+ logVerbose(`discord thread binding fallback send failed: ${summarizeDiscordError(err)}`);
174
+ }
175
+ }
176
+
177
+ export async function createWebhookForChannel(params: {
178
+ cfg: AutoBotConfig;
179
+ accountId: string;
180
+ token?: string;
181
+ channelId: string;
182
+ }): Promise<{ webhookId?: string; webhookToken?: string }> {
183
+ try {
184
+ const rest = createDiscordRestClient({
185
+ cfg: params.cfg,
186
+ accountId: params.accountId,
187
+ token: params.token,
188
+ }).rest;
189
+ const created = await createChannelWebhook(rest, params.channelId, {
190
+ body: {
191
+ name: "AutoBot Agents",
192
+ },
193
+ });
194
+ const webhookId = normalizeOptionalString(created?.id) ?? "";
195
+ const webhookToken = normalizeOptionalString(created?.token) ?? "";
196
+ if (!webhookId || !webhookToken) {
197
+ return {};
198
+ }
199
+ return { webhookId, webhookToken };
200
+ } catch (err) {
201
+ logVerbose(
202
+ `discord thread binding webhook create failed for ${params.channelId}: ${summarizeDiscordError(err)}`,
203
+ );
204
+ return {};
205
+ }
206
+ }
207
+
208
+ export function findReusableWebhook(params: { accountId: string; channelId: string }): {
209
+ webhookId?: string;
210
+ webhookToken?: string;
211
+ } {
212
+ const reusableKey = toReusableWebhookKey({
213
+ accountId: params.accountId,
214
+ channelId: params.channelId,
215
+ });
216
+ const cached = REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.get(reusableKey);
217
+ if (cached) {
218
+ return {
219
+ webhookId: cached.webhookId,
220
+ webhookToken: cached.webhookToken,
221
+ };
222
+ }
223
+ for (const record of BINDINGS_BY_THREAD_ID.values()) {
224
+ if (record.accountId !== params.accountId) {
225
+ continue;
226
+ }
227
+ if (record.channelId !== params.channelId) {
228
+ continue;
229
+ }
230
+ if (!record.webhookId || !record.webhookToken) {
231
+ continue;
232
+ }
233
+ rememberReusableWebhook(record);
234
+ return {
235
+ webhookId: record.webhookId,
236
+ webhookToken: record.webhookToken,
237
+ };
238
+ }
239
+ return {};
240
+ }
241
+
242
+ export async function resolveChannelIdForBinding(params: {
243
+ cfg: AutoBotConfig;
244
+ accountId: string;
245
+ token?: string;
246
+ threadId: string;
247
+ channelId?: string;
248
+ }): Promise<string | null> {
249
+ const explicit = normalizeDiscordBindingChannelId(params.channelId);
250
+ if (explicit) {
251
+ return explicit;
252
+ }
253
+ const lookupThreadId = normalizeDiscordBindingChannelId(params.threadId);
254
+ if (!lookupThreadId) {
255
+ return null;
256
+ }
257
+ try {
258
+ const rest = createDiscordRestClient({
259
+ cfg: params.cfg,
260
+ accountId: params.accountId,
261
+ token: params.token,
262
+ }).rest;
263
+ const channel = await getChannel(rest, lookupThreadId);
264
+ const channelInfo = resolveDiscordChannelInfoSafe(channel);
265
+ const channelId = normalizeOptionalString(resolveDiscordChannelIdSafe(channel)) ?? "";
266
+ const type = channelInfo.type;
267
+ const parentId = normalizeOptionalString(channelInfo.parentId) ?? "";
268
+ // Only thread channels should resolve to their parent channel.
269
+ // Non-thread channels (text/forum/media) must keep their own ID.
270
+ if (parentId && isThreadChannelType(type)) {
271
+ return parentId;
272
+ }
273
+ return channelId || null;
274
+ } catch (err) {
275
+ logVerbose(
276
+ `discord thread binding channel resolve failed for ${lookupThreadId}: ${summarizeDiscordError(err)}`,
277
+ );
278
+ return null;
279
+ }
280
+ }
281
+
282
+ export async function createThreadForBinding(params: {
283
+ cfg: AutoBotConfig;
284
+ accountId: string;
285
+ token?: string;
286
+ channelId: string;
287
+ threadName: string;
288
+ }): Promise<string | null> {
289
+ try {
290
+ const created = await createThreadDiscord(
291
+ params.channelId,
292
+ {
293
+ name: params.threadName,
294
+ autoArchiveMinutes: 60,
295
+ },
296
+ {
297
+ cfg: params.cfg,
298
+ accountId: params.accountId,
299
+ token: params.token,
300
+ },
301
+ );
302
+ const createdId = normalizeOptionalString(created?.id) ?? "";
303
+ return createdId || null;
304
+ } catch (err) {
305
+ logVerbose(
306
+ `discord thread binding auto-thread create failed for ${params.channelId}: ${summarizeDiscordError(err)}`,
307
+ );
308
+ return null;
309
+ }
310
+ }