@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,224 @@
1
+ import { logError } from "autobot/plugin-sdk/logging-core";
2
+ import {
3
+ parseDiscordComponentCustomId,
4
+ parseDiscordModalCustomId,
5
+ } from "../component-custom-id.js";
6
+ import type { DiscordComponentEntry, DiscordModalEntry } from "../components.js";
7
+ import type { ComponentData, ModalInteraction } from "../internal/discord.js";
8
+ import type { AgentComponentInteraction } from "./agent-components.types.js";
9
+ import { formatDiscordUserTag } from "./format.js";
10
+
11
+ function readParsedComponentId(data: ComponentData): unknown {
12
+ if (!data || typeof data !== "object") {
13
+ return undefined;
14
+ }
15
+ return "cid" in data
16
+ ? (data as Record<string, unknown>).cid
17
+ : (data as Record<string, unknown>).componentId;
18
+ }
19
+
20
+ function normalizeComponentId(value: unknown): string | undefined {
21
+ if (typeof value === "string") {
22
+ const trimmed = value.trim();
23
+ return trimmed ? trimmed : undefined;
24
+ }
25
+ if (typeof value === "number" && Number.isFinite(value)) {
26
+ return String(value);
27
+ }
28
+ return undefined;
29
+ }
30
+
31
+ function mapOptionLabels(
32
+ options: Array<{ value: string; label: string }> | undefined,
33
+ values: string[],
34
+ ) {
35
+ if (!options || options.length === 0) {
36
+ return values;
37
+ }
38
+ const map = new Map(options.map((option) => [option.value, option.label]));
39
+ return values.map((value) => map.get(value) ?? value);
40
+ }
41
+
42
+ export function parseAgentComponentData(data: ComponentData): { componentId: string } | null {
43
+ const raw = readParsedComponentId(data);
44
+ const decodeSafe = (value: string): string => {
45
+ if (!value.includes("%")) {
46
+ return value;
47
+ }
48
+ if (!/%[0-9A-Fa-f]{2}/.test(value)) {
49
+ return value;
50
+ }
51
+ try {
52
+ return decodeURIComponent(value);
53
+ } catch {
54
+ return value;
55
+ }
56
+ };
57
+ const componentId =
58
+ typeof raw === "string" ? decodeSafe(raw) : typeof raw === "number" ? String(raw) : null;
59
+ if (!componentId) {
60
+ return null;
61
+ }
62
+ return { componentId };
63
+ }
64
+
65
+ export function parseDiscordComponentData(
66
+ data: ComponentData,
67
+ customId?: string,
68
+ ): { componentId: string; modalId?: string } | null {
69
+ if (!data || typeof data !== "object") {
70
+ return null;
71
+ }
72
+ const rawComponentId = readParsedComponentId(data);
73
+ const rawModalId =
74
+ "mid" in data ? (data as { mid?: unknown }).mid : (data as { modalId?: unknown }).modalId;
75
+ let componentId = normalizeComponentId(rawComponentId);
76
+ let modalId = normalizeComponentId(rawModalId);
77
+ if (!componentId && customId) {
78
+ const parsed = parseDiscordComponentCustomId(customId);
79
+ if (parsed) {
80
+ componentId = parsed.componentId;
81
+ modalId = parsed.modalId;
82
+ }
83
+ }
84
+ if (!componentId) {
85
+ return null;
86
+ }
87
+ return { componentId, modalId };
88
+ }
89
+
90
+ export function parseDiscordModalId(data: ComponentData, customId?: string): string | null {
91
+ if (data && typeof data === "object") {
92
+ const rawModalId =
93
+ "mid" in data ? (data as { mid?: unknown }).mid : (data as { modalId?: unknown }).modalId;
94
+ const modalId = normalizeComponentId(rawModalId);
95
+ if (modalId) {
96
+ return modalId;
97
+ }
98
+ }
99
+ if (customId) {
100
+ return parseDiscordModalCustomId(customId);
101
+ }
102
+ return null;
103
+ }
104
+
105
+ export function resolveInteractionCustomId(
106
+ interaction: AgentComponentInteraction,
107
+ ): string | undefined {
108
+ if (!interaction?.rawData || typeof interaction.rawData !== "object") {
109
+ return undefined;
110
+ }
111
+ if (!("data" in interaction.rawData)) {
112
+ return undefined;
113
+ }
114
+ const data = (interaction.rawData as { data?: { custom_id?: unknown } }).data;
115
+ const customId = data?.custom_id;
116
+ if (typeof customId !== "string") {
117
+ return undefined;
118
+ }
119
+ const trimmed = customId.trim();
120
+ return trimmed ? trimmed : undefined;
121
+ }
122
+
123
+ export function mapSelectValues(entry: DiscordComponentEntry, values: string[]): string[] {
124
+ if (entry.selectType === "string") {
125
+ return mapOptionLabels(entry.options, values);
126
+ }
127
+ if (entry.selectType === "user") {
128
+ return values.map((value) => `user:${value}`);
129
+ }
130
+ if (entry.selectType === "role") {
131
+ return values.map((value) => `role:${value}`);
132
+ }
133
+ if (entry.selectType === "mentionable") {
134
+ return values.map((value) => `mentionable:${value}`);
135
+ }
136
+ if (entry.selectType === "channel") {
137
+ return values.map((value) => `channel:${value}`);
138
+ }
139
+ return values;
140
+ }
141
+
142
+ export function resolveModalFieldValues(
143
+ field: DiscordModalEntry["fields"][number],
144
+ interaction: ModalInteraction,
145
+ ): string[] {
146
+ const fields = interaction.fields;
147
+ const optionLabels = field.options?.map((option) => ({
148
+ value: option.value,
149
+ label: option.label,
150
+ }));
151
+ const required = field.required === true;
152
+ try {
153
+ switch (field.type) {
154
+ case "text": {
155
+ const value = required ? fields.getText(field.id, true) : fields.getText(field.id);
156
+ return value ? [value] : [];
157
+ }
158
+ case "select":
159
+ case "checkbox":
160
+ case "radio": {
161
+ const values = required
162
+ ? fields.getStringSelect(field.id, true)
163
+ : (fields.getStringSelect(field.id) ?? []);
164
+ return mapOptionLabels(optionLabels, values);
165
+ }
166
+ case "role-select": {
167
+ try {
168
+ const roles = required
169
+ ? fields.getRoleSelect(field.id, true)
170
+ : (fields.getRoleSelect(field.id) ?? []);
171
+ return roles.map((role) => role.name ?? role.id);
172
+ } catch {
173
+ const values = required
174
+ ? fields.getStringSelect(field.id, true)
175
+ : (fields.getStringSelect(field.id) ?? []);
176
+ return values;
177
+ }
178
+ }
179
+ case "user-select": {
180
+ const users = required
181
+ ? fields.getUserSelect(field.id, true)
182
+ : (fields.getUserSelect(field.id) ?? []);
183
+ return users.map((user) => formatDiscordUserTag(user));
184
+ }
185
+ default:
186
+ return [];
187
+ }
188
+ } catch (err) {
189
+ logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
190
+ return [];
191
+ }
192
+ }
193
+
194
+ export function formatModalSubmissionText(
195
+ entry: DiscordModalEntry,
196
+ interaction: ModalInteraction,
197
+ ): string {
198
+ const lines: string[] = [`Form "${entry.title}" submitted.`];
199
+ for (const field of entry.fields) {
200
+ const values = resolveModalFieldValues(field, interaction);
201
+ if (values.length === 0) {
202
+ continue;
203
+ }
204
+ lines.push(`- ${field.label}: ${values.join(", ")}`);
205
+ }
206
+ if (lines.length === 1) {
207
+ lines.push("- (no values)");
208
+ }
209
+ return lines.join("\n");
210
+ }
211
+
212
+ export function resolveDiscordInteractionId(interaction: AgentComponentInteraction): string {
213
+ const rawId =
214
+ interaction.rawData && typeof interaction.rawData === "object" && "id" in interaction.rawData
215
+ ? (interaction.rawData as { id?: unknown }).id
216
+ : undefined;
217
+ if (typeof rawId === "string" && rawId.trim()) {
218
+ return rawId.trim();
219
+ }
220
+ if (typeof rawId === "number" && Number.isFinite(rawId)) {
221
+ return String(rawId);
222
+ }
223
+ return `discord-interaction:${Date.now()}`;
224
+ }
@@ -0,0 +1,177 @@
1
+ import { createChannelPairingChallengeIssuer } from "autobot/plugin-sdk/channel-pairing";
2
+ import { isDangerousNameMatchingEnabled } from "autobot/plugin-sdk/dangerous-name-runtime";
3
+ import { logVerbose } from "autobot/plugin-sdk/runtime-env";
4
+ import {
5
+ resolveComponentInteractionContext,
6
+ resolveDiscordChannelContext,
7
+ } from "./agent-components-context.js";
8
+ import {
9
+ readChannelIngressStoreAllowFromForDmPolicy,
10
+ upsertChannelPairingRequest,
11
+ } from "./agent-components-helpers.runtime.js";
12
+ import { replySilently } from "./agent-components-reply.js";
13
+ import type {
14
+ AgentComponentContext,
15
+ AgentComponentInteraction,
16
+ DiscordUser,
17
+ } from "./agent-components.types.js";
18
+ import { resolveGroupDmAllow } from "./allow-list.js";
19
+ import { resolveDiscordDmCommandAccess } from "./dm-command-auth.js";
20
+ import { formatDiscordUserTag } from "./format.js";
21
+
22
+ async function ensureDmComponentAuthorized(params: {
23
+ ctx: AgentComponentContext;
24
+ interaction: AgentComponentInteraction;
25
+ user: DiscordUser;
26
+ componentLabel: string;
27
+ replyOpts: { ephemeral?: boolean };
28
+ }) {
29
+ const { ctx, interaction, user, componentLabel, replyOpts } = params;
30
+ const dmPolicy = ctx.dmPolicy ?? "pairing";
31
+ if (dmPolicy === "disabled") {
32
+ logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
33
+ await replySilently(interaction, { content: "DM interactions are disabled.", ...replyOpts });
34
+ return false;
35
+ }
36
+ const access = await resolveDiscordDmCommandAccess({
37
+ accountId: ctx.accountId,
38
+ dmPolicy,
39
+ configuredAllowFrom: ctx.allowFrom ?? [],
40
+ sender: {
41
+ id: user.id,
42
+ name: user.username,
43
+ tag: formatDiscordUserTag(user),
44
+ },
45
+ allowNameMatching: isDangerousNameMatchingEnabled(ctx.discordConfig),
46
+ cfg: ctx.cfg,
47
+ token: ctx.token,
48
+ readStoreAllowFrom: async ({ accountId, dmPolicy }) =>
49
+ await readChannelIngressStoreAllowFromForDmPolicy({
50
+ provider: "discord",
51
+ accountId,
52
+ dmPolicy,
53
+ }),
54
+ eventKind: "button",
55
+ });
56
+ if (access.senderAccess.decision === "allow") {
57
+ return true;
58
+ }
59
+ if (access.senderAccess.decision !== "pairing") {
60
+ logVerbose(`agent ${componentLabel}: blocked DM user ${user.id} (not in allowFrom)`);
61
+ await replySilently(interaction, {
62
+ content: `You are not authorized to use this ${componentLabel}.`,
63
+ ...replyOpts,
64
+ });
65
+ return false;
66
+ }
67
+ const pairingResult = await createChannelPairingChallengeIssuer({
68
+ channel: "discord",
69
+ upsertPairingRequest: async ({ id, meta }) => {
70
+ return await upsertChannelPairingRequest({
71
+ channel: "discord",
72
+ id,
73
+ accountId: ctx.accountId,
74
+ meta,
75
+ });
76
+ },
77
+ })({
78
+ senderId: user.id,
79
+ senderIdLine: `Your Discord user id: ${user.id}`,
80
+ meta: {
81
+ tag: formatDiscordUserTag(user),
82
+ name: user.username,
83
+ },
84
+ sendPairingReply: async (text) => {
85
+ await interaction.reply({
86
+ content: text,
87
+ ...replyOpts,
88
+ });
89
+ },
90
+ });
91
+ if (!pairingResult.created) {
92
+ await replySilently(interaction, {
93
+ content: "Pairing already requested. Ask the bot owner to approve your code.",
94
+ ...replyOpts,
95
+ });
96
+ }
97
+ return false;
98
+ }
99
+
100
+ async function ensureGroupDmComponentAuthorized(params: {
101
+ ctx: AgentComponentContext;
102
+ interaction: AgentComponentInteraction;
103
+ channelId: string;
104
+ componentLabel: string;
105
+ replyOpts: { ephemeral?: boolean };
106
+ }) {
107
+ const { ctx, interaction, channelId, componentLabel, replyOpts } = params;
108
+ const groupDmEnabled = ctx.discordConfig?.dm?.groupEnabled ?? false;
109
+ if (!groupDmEnabled) {
110
+ logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (group DMs disabled)`);
111
+ await replySilently(interaction, {
112
+ content: "Group DM interactions are disabled.",
113
+ ...replyOpts,
114
+ });
115
+ return false;
116
+ }
117
+
118
+ const channelCtx = resolveDiscordChannelContext(interaction);
119
+ const allowed = resolveGroupDmAllow({
120
+ channels: ctx.discordConfig?.dm?.groupChannels,
121
+ channelId,
122
+ channelName: channelCtx.channelName,
123
+ channelSlug: channelCtx.channelSlug,
124
+ });
125
+ if (allowed) {
126
+ return true;
127
+ }
128
+
129
+ logVerbose(`agent ${componentLabel}: blocked group dm ${channelId} (not allowlisted)`);
130
+ await replySilently(interaction, {
131
+ content: `You are not authorized to use this ${componentLabel}.`,
132
+ ...replyOpts,
133
+ });
134
+ return false;
135
+ }
136
+
137
+ export async function resolveInteractionContextWithDmAuth(params: {
138
+ ctx: AgentComponentContext;
139
+ interaction: AgentComponentInteraction;
140
+ label: string;
141
+ componentLabel: string;
142
+ defer?: boolean;
143
+ }) {
144
+ const interactionCtx = await resolveComponentInteractionContext({
145
+ interaction: params.interaction,
146
+ label: params.label,
147
+ defer: params.defer,
148
+ });
149
+ if (!interactionCtx) {
150
+ return null;
151
+ }
152
+ if (interactionCtx.isDirectMessage) {
153
+ const authorized = await ensureDmComponentAuthorized({
154
+ ctx: params.ctx,
155
+ interaction: params.interaction,
156
+ user: interactionCtx.user,
157
+ componentLabel: params.componentLabel,
158
+ replyOpts: interactionCtx.replyOpts,
159
+ });
160
+ if (!authorized) {
161
+ return null;
162
+ }
163
+ }
164
+ if (interactionCtx.isGroupDm) {
165
+ const authorized = await ensureGroupDmComponentAuthorized({
166
+ ctx: params.ctx,
167
+ interaction: params.interaction,
168
+ channelId: interactionCtx.channelId,
169
+ componentLabel: params.componentLabel,
170
+ replyOpts: interactionCtx.replyOpts,
171
+ });
172
+ if (!authorized) {
173
+ return null;
174
+ }
175
+ }
176
+ return interactionCtx;
177
+ }