@openclaw/discord 2026.9.1-beta.1 → 2026.9.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 (93) hide show
  1. package/dist/account-inspect-BY-ve3yH.js +45 -0
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-q-9PaaHH.js → activities-api-E-segZn6.js} +30 -17
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-BDMimASD.js → allow-list-C2JuH-R0.js} +10 -6
  8. package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
  9. package/dist/api.js +18 -18
  10. package/dist/{approval-handler.runtime-B7qhK3fR.js → approval-handler.runtime-CW5k3mSa.js} +19 -12
  11. package/dist/{audit-CBEv_ERu.js → audit-B9rydv5a.js} +8 -7
  12. package/dist/{channel-Dx1tMTfx.js → channel-D93LnbTE.js} +29 -23
  13. package/dist/{channel-actions.runtime-CLWWu9nC.js → channel-actions.runtime-DMFv4doE.js} +16 -13
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-DOzXS2Pk.js → channel.setup-DTL7kPOM.js} +18 -18
  17. package/dist/{components-B9V5o361.js → components-DmXYIQ26.js} +111 -149
  18. package/dist/{config-schema-BR13IAx6.js → config-schema-B797-Spt.js} +19 -12
  19. package/dist/{conversation-binding-route-DJYrY2TQ.js → conversation-binding-route-24afmvEC.js} +1 -1
  20. package/dist/{directory-config-BK6eqekJ.js → directory-config-BD4YL7wT.js} +2 -2
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-DSAJSrJk.js → directory-live-BrFVc1Ds.js} +4 -4
  23. package/dist/{doctor-Cm7Y1pJ2.js → doctor-BUB41_lr.js} +5 -5
  24. package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
  25. package/dist/doctor-contract-api.js +3 -2
  26. package/dist/{handle-action.guild-admin-BdwCRHmm.js → handle-action.guild-admin-B0egstYq.js} +2 -2
  27. package/dist/index.js +1 -1
  28. package/dist/ingress-identity-BCzfPPYM.js +60 -0
  29. package/dist/{message-handler-BXpWZyni.js → message-handler-Qdw9c0j4.js} +14 -10
  30. package/dist/{message-handler.preflight-Ba5LAY_X.js → message-handler.preflight-Dxi2yBfR.js} +41 -101
  31. package/dist/{message-handler.process-3HEzmemS.js → message-handler.process-BYDjtxZJ.js} +83 -109
  32. package/dist/{message-text-aiwO5R2F.js → message-text-BRVqYm-t.js} +11 -6
  33. package/dist/{outbound-adapter-BE4jSq2d.js → outbound-adapter-DEhthWTk.js} +52 -67
  34. package/dist/{outbound-components-oLpg8Qzb.js → outbound-components-DehyxvA4.js} +5 -4
  35. package/dist/{outbound-session-route-Cg15ZFJd.js → outbound-session-route-BFGRF9fE.js} +55 -12
  36. package/dist/{owner-access-UlYi9t0M.js → owner-access-yc1sX7Gx.js} +7 -6
  37. package/dist/{pluralkit-Tiyl70dx.js → pluralkit-XmmAHoV6.js} +2 -2
  38. package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
  39. package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
  40. package/dist/{provider-B11xwilq.js → provider-DuDtKbF8.js} +294 -131
  41. package/dist/{provider-session.runtime-B9xe-Qaf.js → provider-session.runtime-BA2BPyZ4.js} +3 -3
  42. package/dist/provider.runtime-Db8YwZBv.js +2 -0
  43. package/dist/{realtime-session.runtime-CU8IQUS-.js → realtime-session.runtime-DgSbX6ay.js} +103 -163
  44. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-BJ5UZNNT.js} +3 -3
  45. package/dist/{resolve-channels-C2sT_n67.js → resolve-channels-CYseD5Uw.js} +4 -4
  46. package/dist/{resolve-users-CzpjLwjy.js → resolve-users-DrmhDrqm.js} +5 -4
  47. package/dist/{retry-Cv4jCU5Z.js → retry-BNCxiyyR.js} +120 -32
  48. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  49. package/dist/{runtime-BHrTlFkf.js → runtime-BbWNtfyq.js} +127 -93
  50. package/dist/{runtime-CY4PRMF-.js → runtime-DB7Fb6AU.js} +2 -2
  51. package/dist/runtime-api.js +19 -19
  52. package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
  53. package/dist/secret-contract-api.js +1 -1
  54. package/dist/{security-audit-BfJhAXZp.js → security-audit-DKfK-iPY.js} +10 -11
  55. package/dist/security-audit-contract-api.js +1 -1
  56. package/dist/{security-audit.runtime-BVKF9VtY.js → security-audit.runtime-sKZyKgpx.js} +1 -1
  57. package/dist/{send-C49MFF9j.js → send-BnTEIeLE.js} +132 -100
  58. package/dist/{send.components-DKKAw5VX.js → send.components-BWVEcjRP.js} +21 -15
  59. package/dist/{send.outbound-zam0TrZx.js → send.outbound-b5xwHTlL.js} +35 -22
  60. package/dist/{send.shared-JjljcV4O.js → send.shared-5vxBTagO.js} +25 -18
  61. package/dist/{sender-identity-BJtfyise.js → sender-identity-Dt0imZyY.js} +1 -1
  62. package/dist/setup-plugin-api.js +1 -1
  63. package/dist/{shared-_5EcP4jW.js → shared-BSJWHEMA.js} +20 -14
  64. package/dist/{subagent-hooks-DQzvOptn.js → subagent-hooks-IzQKX4RQ.js} +2 -2
  65. package/dist/subagent-hooks-api.js +1 -1
  66. package/dist/{system-events-C7yxaHWP.js → system-events-BOiDS8b3.js} +2 -2
  67. package/dist/{target-resolver-vxIh6O3-.js → target-resolver-BVI8xSSC.js} +6 -5
  68. package/dist/targets-DbxVbq8k.js +3 -0
  69. package/dist/{thread-bindings-DW5F9vat.js → thread-bindings-D7mcaXQC.js} +6 -5
  70. package/dist/{thread-bindings.manager-ByOtwjo_.js → thread-bindings.manager-B1oySiVc.js} +37 -28
  71. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-CC7HoQvt.js} +2 -1
  72. package/dist/{threading-agH1T_6s.js → threading-OQnL-0Zx.js} +8 -6
  73. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  74. package/dist/{transcripts-source-BR11iHA4.js → transcripts-source-D8lH7AkN.js} +9 -4
  75. package/dist/transcripts-source-api.js +1 -1
  76. package/dist/{typing-Dc_YMY2e.js → typing-C9q0AQMb.js} +2 -2
  77. package/dist/{voice-runtime-DIeaa8fJ.js → voice-runtime-Dfhjh1tV.js} +433 -93
  78. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  79. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  81. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  82. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  83. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  84. package/node_modules/typebox/build/format/email.mjs +1 -1
  85. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  86. package/node_modules/typebox/package.json +1 -1
  87. package/openclaw.plugin.json +14 -6
  88. package/package.json +6 -5
  89. package/skills/discord/SKILL.md +1 -1
  90. package/dist/account-inspect-BDfKyuvL.js +0 -89
  91. package/dist/provider.runtime-DiYaHvOz.js +0 -2
  92. package/dist/sdk-runtime-4geQHtXc.js +0 -338
  93. package/dist/targets-CtTKvntJ.js +0 -3
@@ -2,7 +2,7 @@ import { normalizeLegacyDmAliases } from "openclaw/plugin-sdk/channel-config-hel
2
2
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { buildSecretInputSchema, registerSensitiveConfigSchema } from "openclaw/plugin-sdk/secret-input";
4
4
  import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
5
- import { ChannelBotLoopProtectionSchema, ChannelDangerouslyAllowNameMatchingSchema, ChannelPreviewStreamingConfigSchema, ChannelStreamingProgressSchema, ProviderCommandsSchema, TtsConfigSchema, buildChannelAllowBotsSchema, buildChannelConfigSchema, buildChannelExecApprovalsSchema, buildChannelReactionShape, buildCommonChannelAccountShape, buildGroupEntrySchema, requireAllowlistAllowFrom, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
5
+ import { ChannelBotLoopProtectionSchema, ChannelDangerouslyAllowNameMatchingSchema, ChannelPreviewStreamingConfigSchema, ChannelStreamingProgressSchema, ProviderCommandsSchema, TtsConfigSchema, buildChannelAccountSchemaParts, buildChannelAllowBotsSchema, buildChannelConfigSchema, buildChannelExecApprovalsSchema, buildChannelReactionShape, buildGroupEntrySchema, requireAllowlistAllowFrom, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
6
6
  import { asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor-migrations";
7
7
  import { z } from "zod";
8
8
  //#region extensions/discord/src/config-ui-hints.ts
@@ -35,6 +35,10 @@ const discordChannelConfigUiHints = {
35
35
  },
36
36
  progress: { includeCommentary: true }
37
37
  }),
38
+ joinIntro: {
39
+ label: "Discord Guild Join Introduction",
40
+ help: "Post one brief, room-specific introduction when the bot joins an allowed Discord guild (default: true). Account settings override the channel-wide setting."
41
+ },
38
42
  proxy: {
39
43
  label: "Discord Proxy URL",
40
44
  help: "Proxy URL for Discord gateway + API requests (app-id lookup and allowlist resolution). Set per account via channels.discord.accounts.<id>.proxy."
@@ -53,11 +57,11 @@ const discordChannelConfigUiHints = {
53
57
  },
54
58
  "threadBindings.enabled": {
55
59
  label: "Discord Thread Binding Enabled",
56
- help: "Enable Discord thread binding features (/focus, bound-thread routing/delivery, and thread-bound subagent sessions). Overrides session.threadBindings.enabled when set."
60
+ help: "Enable Discord thread-bound session spawning, routing, and delivery. Overrides session.threadBindings.enabled when set."
57
61
  },
58
62
  "threadBindings.idleHours": {
59
63
  label: "Discord Thread Binding Idle Timeout (hours)",
60
- help: "Inactivity window in hours for Discord thread-bound sessions (/focus and spawned thread sessions). Set 0 to disable idle auto-unfocus (default: 24). Overrides session.threadBindings.idleHours when set."
64
+ help: "Inactivity window in hours for Discord thread-bound sessions. Set 0 to disable idle expiry (default: 24). Overrides session.threadBindings.idleHours when set."
61
65
  },
62
66
  "threadBindings.maxAgeHours": {
63
67
  label: "Discord Thread Binding Max Age (hours)",
@@ -461,13 +465,14 @@ const DiscordVoiceSchema = z.object({
461
465
  captureSilenceGraceMs: z.number().int().positive().max(3e4).optional(),
462
466
  tts: TtsConfigSchema.optional()
463
467
  }).strict().optional();
468
+ const { accountShape, rootPolicyShape } = buildChannelAccountSchemaParts({
469
+ omit: ["groupAllowFrom"],
470
+ allowFrom: DiscordIdListSchema.optional(),
471
+ streaming: DiscordPreviewStreamingConfigSchema.optional()
472
+ });
464
473
  const DiscordAccountSchemaBase = z.object({
465
- ...buildCommonChannelAccountShape({
466
- omit: ["groupAllowFrom"],
467
- groupPolicyDefault: true,
468
- allowFrom: DiscordIdListSchema.optional(),
469
- streaming: DiscordPreviewStreamingConfigSchema.optional()
470
- }),
474
+ ...accountShape,
475
+ joinIntro: z.boolean().optional(),
471
476
  commands: ProviderCommandsSchema,
472
477
  token: registerSensitiveConfigSchema(SecretInputSchema.optional()),
473
478
  applicationId: DiscordIdSchema.optional(),
@@ -509,7 +514,7 @@ const DiscordAccountSchemaBase = z.object({
509
514
  execApprovals: buildChannelExecApprovalsSchema(DiscordIdSchema, { cleanupAfterResolve: z.boolean().optional() }),
510
515
  agentComponents: z.object({
511
516
  enabled: z.boolean().optional(),
512
- ttlMs: z.number().int().positive().max(1440 * 60 * 1e3).optional()
517
+ ttlMs: z.number().int().positive().max(864e5).optional()
513
518
  }).strict().optional(),
514
519
  slashCommand: z.object({ ephemeral: z.boolean().optional() }).strict().optional(),
515
520
  threadBindings: z.object({
@@ -608,7 +613,8 @@ function normalizeShippedDiscordDmAliases(value) {
608
613
  } : rest;
609
614
  }
610
615
  const DiscordAccountSchema = z.preprocess(normalizeShippedDiscordDmAliases, DiscordAccountSchemaBase);
611
- const DiscordConfigSchemaBase = DiscordAccountSchemaBase.extend({
616
+ const DiscordConfigSchemaBase = DiscordAccountSchemaBase.safeExtend({
617
+ ...rootPolicyShape,
612
618
  accounts: z.record(z.string(), DiscordAccountSchema.optional()).optional(),
613
619
  defaultAccount: z.string().optional()
614
620
  }).superRefine((value, ctx) => {
@@ -657,6 +663,7 @@ const DiscordConfigSchemaBase = DiscordAccountSchemaBase.extend({
657
663
  });
658
664
  }
659
665
  });
660
- const DiscordChannelConfigSchema = buildChannelConfigSchema(z.preprocess(normalizeShippedDiscordDmAliases, DiscordConfigSchemaBase), { uiHints: discordChannelConfigUiHints });
666
+ const DiscordConfigSchema = z.preprocess(normalizeShippedDiscordDmAliases, DiscordConfigSchemaBase);
667
+ const DiscordChannelConfigSchema = buildChannelConfigSchema(DiscordConfigSchema, { uiHints: discordChannelConfigUiHints });
661
668
  //#endregion
662
669
  export { DiscordChannelConfigSchema as t };
@@ -1,4 +1,4 @@
1
- import { l as shouldIgnoreStaleDiscordRouteBinding } from "./outbound-session-route-Cg15ZFJd.js";
1
+ import { l as shouldIgnoreStaleDiscordRouteBinding } from "./outbound-session-route-BFGRF9fE.js";
2
2
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
3
3
  import { resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-binding-runtime";
4
4
  //#region extensions/discord/src/monitor/conversation-binding-route.ts
@@ -1,5 +1,5 @@
1
- import { on as __exportAll } from "./retry-Cv4jCU5Z.js";
2
- import { l as resolveDiscordAccountAllowFrom, o as mergeDiscordAccountConfig, s as resolveDefaultDiscordAccountId } from "./accounts-CfQ-vSyf.js";
1
+ import { sn as __exportAll } from "./retry-BNCxiyyR.js";
2
+ import { l as resolveDiscordAccountAllowFrom, o as mergeDiscordAccountConfig, s as resolveDefaultDiscordAccountId } from "./accounts-CwJQoLjM.js";
3
3
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
4
4
  import { createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-config-runtime";
5
5
  //#region extensions/discord/src/directory-config.ts
@@ -1,4 +1,4 @@
1
- import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BK6eqekJ.js";
1
+ import { n as listDiscordDirectoryGroupsFromConfig, r as listDiscordDirectoryPeersFromConfig } from "./directory-config-BD4YL7wT.js";
2
2
  //#region extensions/discord/directory-contract-api.ts
3
3
  const discordDirectoryContractPlugin = {
4
4
  id: "discord",
@@ -1,7 +1,7 @@
1
- import { on as __exportAll } from "./retry-Cv4jCU5Z.js";
2
- import { c as resolveDiscordAccount, m as normalizeDiscordToken } from "./accounts-CfQ-vSyf.js";
3
- import { r as fetchDiscord, t as DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS } from "./api-DNVbJyEy.js";
4
- import { a as normalizeDiscordSlug } from "./allow-list-BDMimASD.js";
1
+ import { sn as __exportAll } from "./retry-BNCxiyyR.js";
2
+ import { c as resolveDiscordAccount, m as normalizeDiscordToken } from "./accounts-CwJQoLjM.js";
3
+ import { r as fetchDiscord, t as DISCORD_DIRECTORY_LOOKUP_TIMEOUT_MS } from "./api-BfmEP6wp.js";
4
+ import { a as normalizeDiscordSlug } from "./allow-list-C2JuH-R0.js";
5
5
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  //#region extensions/discord/src/directory-cache-state.ts
@@ -1,8 +1,8 @@
1
- import { s as resolveDefaultDiscordAccountId } from "./accounts-CfQ-vSyf.js";
2
- import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-BR11iHA4.js";
3
- import { t as inspectDiscordAccount } from "./account-inspect-BDfKyuvL.js";
4
- import { r as DISCORD_LEGACY_CONFIG_RULES } from "./shared-_5EcP4jW.js";
5
- import { n as normalizeCompatibilityConfig } from "./doctor-contract-DsWvKIXF.js";
1
+ import { s as resolveDefaultDiscordAccountId } from "./accounts-CwJQoLjM.js";
2
+ import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-D8lH7AkN.js";
3
+ import { t as inspectDiscordAccount } from "./account-inspect-BY-ve3yH.js";
4
+ import { r as DISCORD_LEGACY_CONFIG_RULES } from "./shared-BSJWHEMA.js";
5
+ import { n as normalizeCompatibilityConfig } from "./doctor-contract-Co5vRCZ6.js";
6
6
  import { t as isDiscordMutableAllowEntry } from "./security-doctor-nGgPm65L.js";
7
7
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
8
8
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -65,7 +65,8 @@ function hasLegacyDiscordGuildChannelAgentId(value) {
65
65
  });
66
66
  }
67
67
  function hasUnsupportedRealtimeWakeNamesInVoice(value) {
68
- const wakeNames = asObjectRecord(asObjectRecord(value)?.realtime)?.wakeNames;
68
+ const voice = asObjectRecord(value);
69
+ const wakeNames = asObjectRecord(voice?.realtime)?.wakeNames;
69
70
  return Array.isArray(wakeNames) ? wakeNames.length === 0 || wakeNames.some((wakeName) => typeof wakeName === "string" && !isSupportedRealtimeVoiceActivationName(wakeName)) : false;
70
71
  }
71
72
  function hasUnsupportedDiscordRealtimeWakeNames(value) {
@@ -274,7 +275,8 @@ const legacyConfigRules = [
274
275
  ],
275
276
  message: "channels.discord.accounts.<id>.voice.tts.<provider> keys (openai/elevenlabs/microsoft/edge) are legacy; use channels.discord.accounts.<id>.voice.tts.providers.<provider>. Run \"openclaw doctor --fix\".",
276
277
  match: (value) => hasLegacyAccountStreamingAliases(value, (accountValue) => {
277
- return hasLegacyTtsProviderKeys(asObjectRecord(asObjectRecord(accountValue)?.voice)?.tts);
278
+ const account = asObjectRecord(accountValue);
279
+ return hasLegacyTtsProviderKeys(asObjectRecord(account?.voice)?.tts);
278
280
  })
279
281
  },
280
282
  {
@@ -324,11 +326,12 @@ const legacyConfigRules = [
324
326
  function normalizeCompatibilityConfig({ cfg }) {
325
327
  const changes = [];
326
328
  const bindingsToAdd = [];
329
+ const aliases = streamingAliasMigration.normalizeChannelConfig({
330
+ cfg,
331
+ changes
332
+ });
327
333
  const tuningKnobs = stripRetiredChannelKeys({
328
- cfg: streamingAliasMigration.normalizeChannelConfig({
329
- cfg,
330
- changes
331
- }).config,
334
+ cfg: aliases.config,
332
335
  channelId: "discord",
333
336
  keys: RETIRED_TUNING_KEYS,
334
337
  scope: "root-and-accounts"
@@ -1,6 +1,6 @@
1
1
  import { n as DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE, t as DISCORD_COMMAND_DEPLOY_HASH_MAX_ENTRIES } from "./command-deploy-store-DFkBTViB.js";
2
2
  import { a as THREAD_BINDINGS_MAX_ENTRIES, d as normalizePersistedBinding, k as toBindingRecordKey, o as THREAD_BINDINGS_NAMESPACE } from "./thread-bindings.state-D8OMdk4O.js";
3
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DsWvKIXF.js";
3
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Co5vRCZ6.js";
4
4
  import { i as sanitizeRecentModels, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.js";
5
5
  import { MAX_DATE_TIMESTAMP_MS, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
6
6
  import path from "node:path";
@@ -37,7 +37,8 @@ function normalizeLegacyPreferenceKey(key) {
37
37
  }
38
38
  function legacyUpdatedAtForIndex(updatedAt, index, total) {
39
39
  const baseMs = preferenceTimestampMs(updatedAt);
40
- return timestampMsToIsoString(Math.min(baseMs + Math.max(0, total), MAX_DATE_TIMESTAMP_MS) - Math.max(0, index)) ?? timestampMsToIsoString(baseMs) ?? timestampMsToIsoString(Math.max(0, total - index)) ?? "1970-01-01T00:00:00.000Z";
40
+ const shiftedMs = Math.min(baseMs + Math.max(0, total), MAX_DATE_TIMESTAMP_MS) - Math.max(0, index);
41
+ return timestampMsToIsoString(shiftedMs) ?? timestampMsToIsoString(baseMs) ?? timestampMsToIsoString(Math.max(0, total - index)) ?? "1970-01-01T00:00:00.000Z";
41
42
  }
42
43
  function readFiniteNumberField(entry, key) {
43
44
  const value = entry[key];
@@ -1,6 +1,6 @@
1
- import { c as readDiscordChannelMoveParams, n as isDiscordModerationAction, o as readDiscordChannelCreateParams, r as readDiscordModerationCommand, s as readDiscordChannelEditParams, t as handleDiscordAction } from "./runtime-BHrTlFkf.js";
1
+ import { c as readDiscordChannelMoveParams, n as isDiscordModerationAction, o as readDiscordChannelCreateParams, r as readDiscordModerationCommand, s as readDiscordChannelEditParams, t as handleDiscordAction } from "./runtime-BbWNtfyq.js";
2
2
  import "./action-runtime-api.js";
3
- import { m as isTrustedRequesterGuildAdminAction } from "./outbound-session-route-Cg15ZFJd.js";
3
+ import { m as isTrustedRequesterGuildAdminAction } from "./outbound-session-route-BFGRF9fE.js";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
6
6
  import { readNonNegativeIntegerParam, readPositiveIntegerParam, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as registerDiscordActivities } from "./activities-api-q-9PaaHH.js";
1
+ import { t as registerDiscordActivities } from "./activities-api-E-segZn6.js";
2
2
  import { registerDiscordSubagentHooks } from "./subagent-hooks-api.js";
3
3
  import { registerDiscordTranscriptSourceProvider } from "./transcripts-source-api.js";
4
4
  import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
@@ -0,0 +1,60 @@
1
+ import { r as normalizeDiscordAllowList } from "./allow-list-C2JuH-R0.js";
2
+ import { defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
3
+ //#region extensions/discord/src/monitor/ingress-identity.ts
4
+ const DISCORD_ALLOW_LIST_PREFIXES = [
5
+ "discord:",
6
+ "user:",
7
+ "pk:"
8
+ ];
9
+ const DISCORD_USER_ID_KIND = "stable-id";
10
+ const DISCORD_USER_NAME_KIND = "username";
11
+ function normalizeDiscordIdEntry(entry) {
12
+ const text = entry.trim();
13
+ if (!text) return null;
14
+ const maybeId = text.replace(/^<@!?/, "").replace(/>$/, "");
15
+ if (/^\d+$/.test(maybeId)) return maybeId;
16
+ const prefix = DISCORD_ALLOW_LIST_PREFIXES.find((entryPrefix) => text.startsWith(entryPrefix));
17
+ if (prefix) return text.slice(prefix.length).trim() || null;
18
+ return null;
19
+ }
20
+ function normalizeDiscordNameEntry(entry) {
21
+ const text = entry.trim();
22
+ if (!text || text === "*" || normalizeDiscordIdEntry(text) || /#\d{4}$/.test(text)) return null;
23
+ const nameSlug = normalizeDiscordAllowList([text], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
24
+ return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
25
+ }
26
+ function normalizeDiscordTagEntry(entry) {
27
+ const text = entry.trim();
28
+ return /#\d{4}$/.test(text) ? normalizeDiscordNameSubject(text) : null;
29
+ }
30
+ function normalizeDiscordNameSubject(value) {
31
+ const nameSlug = normalizeDiscordAllowList([value], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
32
+ return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
33
+ }
34
+ const discordIngressIdentity = defineStableChannelIngressIdentity({
35
+ resolveParticipant: (subject) => {
36
+ const kind = subject.aliases?.participantKind;
37
+ const id = subject.stableId;
38
+ return typeof id === "string" && id && (kind === "user" || kind === "bot" || kind === "pluralkit-member") ? {
39
+ domain: kind === "pluralkit-member" ? "pluralkit" : "discord",
40
+ idKind: kind,
41
+ id
42
+ } : void 0;
43
+ },
44
+ key: "discordUserId",
45
+ kind: DISCORD_USER_ID_KIND,
46
+ authentication: "verified",
47
+ normalizeEntry: normalizeDiscordIdEntry,
48
+ normalizeSubject: (value) => value.trim() || null,
49
+ sensitivity: "pii",
50
+ aliases: [["discordUserName", normalizeDiscordNameEntry], ["discordUserTag", normalizeDiscordTagEntry]].map(([key, normalizeEntry]) => ({
51
+ key,
52
+ kind: DISCORD_USER_NAME_KIND,
53
+ normalizeEntry,
54
+ normalizeSubject: normalizeDiscordNameSubject,
55
+ authentication: "mutable",
56
+ sensitivity: "pii"
57
+ }))
58
+ });
59
+ //#endregion
60
+ export { discordIngressIdentity as t };
@@ -1,7 +1,7 @@
1
1
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
2
- import { c as resolveDiscordChannelInfoSafe, d as resolveDiscordChannelParentSafe, l as resolveDiscordChannelNameSafe, s as resolveDiscordChannelIdSafe } from "./thread-bindings.manager-ByOtwjo_.js";
3
- import { _ as mapGatewayDispatchData } from "./provider-B11xwilq.js";
4
- import { d as resolveDiscordCdnPolicy, i as resolveDiscordMessageText, l as hasDiscordMessageStickers, p as resolveDiscordMessageChannelId } from "./message-text-aiwO5R2F.js";
2
+ import { c as resolveDiscordChannelInfoSafe, d as resolveDiscordChannelParentSafe, l as resolveDiscordChannelNameSafe, s as resolveDiscordChannelIdSafe } from "./thread-bindings.manager-B1oySiVc.js";
3
+ import { v as mapGatewayDispatchData } from "./provider-DuDtKbF8.js";
4
+ import { f as resolveDiscordReferencedReplyMessageId, h as resolveDiscordMessageChannelId, i as resolveDiscordMessageText, l as hasDiscordMessageStickers, p as resolveDiscordCdnPolicy } from "./message-text-BRVqYm-t.js";
5
5
  import { logDebug } from "openclaw/plugin-sdk/logging-core";
6
6
  import { GatewayDispatchEvents } from "discord-api-types/v10";
7
7
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
@@ -58,8 +58,9 @@ function isDiscordAuthenticationFailure(error) {
58
58
  return false;
59
59
  }
60
60
  function createDiscordIngressMonitor(params) {
61
+ const queue = params.queue ?? getDiscordRuntime().state.openChannelIngressQueue({ accountId: params.accountId });
61
62
  const monitor = createChannelIngressMonitor({
62
- queue: params.queue ?? getDiscordRuntime().state.openChannelIngressQueue({ accountId: params.accountId }),
63
+ queue,
63
64
  inspect: inspectDiscordMessage,
64
65
  payload: {
65
66
  version: DISCORD_INGRESS_PAYLOAD_VERSION,
@@ -170,9 +171,9 @@ function normalizeDiscordThreadChannel(threadChannel) {
170
171
  }
171
172
  //#endregion
172
173
  //#region extensions/discord/src/monitor/message-avatar.ts
173
- const DISCORD_AVATAR_MAX_BYTES = 256 * 1024;
174
+ const DISCORD_AVATAR_MAX_BYTES = 262144;
174
175
  const DISCORD_AVATAR_CACHE_MAX_ENTRIES = 128;
175
- const DISCORD_GUILD_ICON_TTL_MS = 5 * 6e4;
176
+ const DISCORD_GUILD_ICON_TTL_MS = 3e5;
176
177
  function setBoundedEntry(map, key, value) {
177
178
  map.delete(key);
178
179
  map.set(key, value);
@@ -248,7 +249,7 @@ function applyImplicitReplyBatchGate(ctx, replyToMode, isBatched) {
248
249
  }
249
250
  //#endregion
250
251
  //#region extensions/discord/src/monitor/message-run-queue.ts
251
- const loadMessageProcessRuntime = createLazyRuntimeModule(() => import("./message-handler.process-3HEzmemS.js"));
252
+ const loadMessageProcessRuntime = createLazyRuntimeModule(() => import("./message-handler.process-BYDjtxZJ.js"));
252
253
  async function processDiscordQueuedMessage(params) {
253
254
  const abortSignal = params.job.runtime.abortSignal && params.lifecycleSignal ? AbortSignal.any([params.job.runtime.abortSignal, params.lifecycleSignal]) : params.job.runtime.abortSignal ?? params.lifecycleSignal;
254
255
  try {
@@ -335,7 +336,7 @@ function createDiscordMessageRunQueue(params) {
335
336
  }
336
337
  //#endregion
337
338
  //#region extensions/discord/src/monitor/message-dispatcher.ts
338
- const loadMessagePreflightRuntime = createLazyRuntimeModule(() => import("./message-handler.preflight-Ba5LAY_X.js"));
339
+ const loadMessagePreflightRuntime = createLazyRuntimeModule(() => import("./message-handler.preflight-Dxi2yBfR.js"));
339
340
  function isNonEmptyString(value) {
340
341
  return typeof value === "string" && value.length > 0;
341
342
  }
@@ -365,7 +366,9 @@ function createDiscordMessageDispatcher(params) {
365
366
  message,
366
367
  eventChannelId: entry.data.channel_id
367
368
  });
368
- return channelId ? `discord:${params.accountId}:${channelId}:${authorId}` : null;
369
+ if (!channelId) return null;
370
+ const replyTargetId = resolveDiscordReferencedReplyMessageId(message);
371
+ return `discord:${params.accountId}:${channelId}:${authorId}:reply:${replyTargetId ?? "none"}`;
369
372
  };
370
373
  const { debouncer } = createChannelInboundDebouncer({
371
374
  cfg: params.cfg,
@@ -374,8 +377,9 @@ function createDiscordMessageDispatcher(params) {
374
377
  shouldDebounce: (entry) => {
375
378
  const message = entry.data.message;
376
379
  if (!message) return false;
380
+ const baseText = resolveDiscordMessageText(message, { includeForwarded: false });
377
381
  return shouldDebounceTextInbound({
378
- text: resolveDiscordMessageText(message, { includeForwarded: false }),
382
+ text: baseText,
379
383
  cfg: params.cfg,
380
384
  hasMedia: message.attachments && message.attachments.length > 0 || hasDiscordMessageStickers(message)
381
385
  });
@@ -1,14 +1,14 @@
1
- import { W as Message, jt as getChannelMessage, y as discord_exports } from "./retry-Cv4jCU5Z.js";
2
- import { s as resolveDefaultDiscordAccountId } from "./accounts-CfQ-vSyf.js";
3
- import { C as resolveTimestampMs, S as resolveDiscordSystemLocation, _ as resolveDiscordShouldRequireMention, a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, f as resolveDiscordGuildEntry, i as normalizeDiscordDisplaySlug, n as isDiscordGroupAllowedByPolicy, p as resolveDiscordMemberAccessState, v as resolveGroupDmAllow, x as formatDiscordUserTag } from "./allow-list-BDMimASD.js";
1
+ import { G as Message, Mt as getChannelMessage, b as discord_exports } from "./retry-BNCxiyyR.js";
2
+ import { s as resolveDefaultDiscordAccountId } from "./accounts-CwJQoLjM.js";
3
+ import { C as resolveTimestampMs, S as resolveDiscordSystemLocation, _ as resolveDiscordShouldRequireMention, a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, f as resolveDiscordGuildEntry, i as normalizeDiscordDisplaySlug, p as resolveDiscordMemberAccessState, x as formatDiscordUserTag } from "./allow-list-C2JuH-R0.js";
4
4
  import { t as isDiscordThreadChannelType } from "./channel-type-CVLZyGYS.js";
5
- import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-B9cy6RvQ.js";
6
- import { a as buildDiscordRoutePeer, c as resolveDiscordEffectiveRoute, f as resolveDiscordRuntimeBindingConversationId, s as resolveDiscordConversationRoute, u as resolveDiscordConversationIdentity } from "./outbound-session-route-Cg15ZFJd.js";
7
- import { t as resolveDiscordConversationBindingRoute } from "./conversation-binding-route-DJYrY2TQ.js";
8
- import { c as resolveDiscordChannelInfoSafe, l as resolveDiscordChannelNameSafe } from "./thread-bindings.manager-ByOtwjo_.js";
9
- import { b as resolveDiscordDmCommandAccess, g as handleDiscordDmCommandDecision, x as resolveDiscordTextCommandAccess } from "./provider-B11xwilq.js";
10
- import { f as resolveDiscordChannelInfo, i as resolveDiscordMessageText, o as resolveForwardedMediaList, p as resolveDiscordMessageChannelId, r as resolveDiscordMessageHistoryText, s as resolveMediaList, u as resolveDiscordMessageStickers } from "./message-text-aiwO5R2F.js";
11
- import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-BJtfyise.js";
5
+ import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-D86uWLt_.js";
6
+ import { a as buildDiscordRoutePeer, c as resolveDiscordEffectiveRoute, f as resolveDiscordRuntimeBindingConversationId, s as resolveDiscordConversationRoute, u as resolveDiscordConversationIdentity } from "./outbound-session-route-BFGRF9fE.js";
7
+ import { t as resolveDiscordConversationBindingRoute } from "./conversation-binding-route-24afmvEC.js";
8
+ import { c as resolveDiscordChannelInfoSafe, l as resolveDiscordChannelNameSafe } from "./thread-bindings.manager-B1oySiVc.js";
9
+ import { S as resolveDiscordTextCommandAccess, _ as handleDiscordDmCommandDecision, n as resolveDiscordPreflightChannelAccess, x as resolveDiscordDmCommandAccess } from "./provider-DuDtKbF8.js";
10
+ import { d as resolveDiscordReferencedReplyMessage, h as resolveDiscordMessageChannelId, i as resolveDiscordMessageText, m as resolveDiscordChannelInfo, o as resolveForwardedMediaList, r as resolveDiscordMessageHistoryText, s as resolveMediaList, u as resolveDiscordMessageStickers } from "./message-text-BRVqYm-t.js";
11
+ import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-Dt0imZyY.js";
12
12
  import { t as createDiscordHistorySenderProvenance } from "./message-handler.history-CJOsN9w5.js";
13
13
  import { logDebug } from "openclaw/plugin-sdk/logging-core";
14
14
  import { MessageReferenceType, MessageType } from "discord-api-types/v10";
@@ -29,7 +29,7 @@ import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
29
29
  import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
30
30
  //#region extensions/discord/src/monitor/message-handler.dm-preflight.ts
31
31
  const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/conversation-binding-runtime"));
32
- const loadDiscordSendRuntime = createLazyRuntimeModule(() => import("./send-C49MFF9j.js").then((n) => n.t));
32
+ const loadDiscordSendRuntime = createLazyRuntimeModule(() => import("./send-BnTEIeLE.js").then((n) => n.t));
33
33
  function resolveDiscordDmPairingSenderId(sender) {
34
34
  return sender.isPluralKit ? `pk:${sender.id}` : sender.id;
35
35
  }
@@ -54,7 +54,9 @@ async function resolveDiscordDmPreflightAccess(params) {
54
54
  sender: {
55
55
  id: params.sender.id,
56
56
  name: params.sender.name,
57
- tag: params.sender.tag
57
+ tag: params.sender.tag,
58
+ isPluralKit: params.sender.isPluralKit,
59
+ authorKind: params.author.bot ? "bot" : "user"
58
60
  },
59
61
  allowNameMatching: params.allowNameMatching,
60
62
  cfg: params.preflight.cfg,
@@ -268,72 +270,6 @@ async function hydrateDiscordMessageIfNeeded(params) {
268
270
  };
269
271
  }
270
272
  //#endregion
271
- //#region extensions/discord/src/monitor/message-handler.preflight-channel-access.ts
272
- function resolveDiscordPreflightChannelAccess(params) {
273
- if (params.isGuildMessage && params.channelConfig?.enabled === false) {
274
- logDebug(`[discord-preflight] drop: channel disabled`);
275
- logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
276
- return {
277
- allowed: false,
278
- channelAllowlistConfigured: false,
279
- channelAllowed: false
280
- };
281
- }
282
- const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
283
- channels: params.groupDmChannels,
284
- channelId: params.messageChannelId,
285
- channelName: params.displayChannelName,
286
- channelSlug: params.displayChannelSlug
287
- });
288
- if (params.isGroupDm && !groupDmAllowed) return {
289
- allowed: false,
290
- channelAllowlistConfigured: false,
291
- channelAllowed: false
292
- };
293
- const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
294
- const channelAllowed = params.channelConfig?.allowed !== false;
295
- if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
296
- groupPolicy: params.groupPolicy,
297
- guildAllowlisted: Boolean(params.guildInfo),
298
- channelAllowlistConfigured,
299
- channelAllowed
300
- })) {
301
- if (params.groupPolicy === "disabled") {
302
- logDebug(`[discord-preflight] drop: groupPolicy disabled`);
303
- logVerbose(`discord: drop guild message (groupPolicy: disabled, ${params.channelMatchMeta})`);
304
- } else if (!channelAllowlistConfigured) {
305
- logDebug(`[discord-preflight] drop: groupPolicy allowlist, no channel allowlist configured`);
306
- logVerbose(`discord: drop guild message (groupPolicy: allowlist, no channel allowlist, ${params.channelMatchMeta})`);
307
- } else {
308
- logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
309
- logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
310
- }
311
- return {
312
- allowed: false,
313
- channelAllowlistConfigured,
314
- channelAllowed
315
- };
316
- }
317
- if (params.isGuildMessage && params.channelConfig?.allowed === false) {
318
- logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
319
- logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
320
- return {
321
- allowed: false,
322
- channelAllowlistConfigured,
323
- channelAllowed
324
- };
325
- }
326
- if (params.isGuildMessage) {
327
- logDebug(`[discord-preflight] pass: channel allowed`);
328
- logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
329
- }
330
- return {
331
- allowed: true,
332
- channelAllowlistConfigured,
333
- channelAllowed
334
- };
335
- }
336
- //#endregion
337
273
  //#region extensions/discord/src/monitor/message-handler.preflight-channel-context.ts
338
274
  function resolveDiscordPreflightChannelContext(params) {
339
275
  const threadName = params.threadChannel?.name;
@@ -479,7 +415,8 @@ function buildDiscordPreflightHistoryEntry(params) {
479
415
  //#region extensions/discord/src/monitor/message-handler.preflight-logging.ts
480
416
  function logDiscordPreflightChannelConfig(params) {
481
417
  if (!shouldLogVerbose()) return;
482
- logDebug(`[discord-preflight] channelConfig=${params.channelConfig ? `allowed=${params.channelConfig.allowed} enabled=${params.channelConfig.enabled ?? "unset"} requireMention=${params.channelConfig.requireMention ?? "unset"} ignoreOtherMentions=${params.channelConfig.ignoreOtherMentions ?? "unset"} matchKey=${params.channelConfig.matchKey ?? "none"} matchSource=${params.channelConfig.matchSource ?? "none"} users=${params.channelConfig.users?.length ?? 0} roles=${params.channelConfig.roles?.length ?? 0} skills=${params.channelConfig.skills?.length ?? 0}` : "none"} channelMatchMeta=${params.channelMatchMeta} channelId=${params.channelId}`);
418
+ const channelConfigSummary = params.channelConfig ? `allowed=${params.channelConfig.allowed} enabled=${params.channelConfig.enabled ?? "unset"} requireMention=${params.channelConfig.requireMention ?? "unset"} ignoreOtherMentions=${params.channelConfig.ignoreOtherMentions ?? "unset"} matchKey=${params.channelConfig.matchKey ?? "none"} matchSource=${params.channelConfig.matchSource ?? "none"} users=${params.channelConfig.users?.length ?? 0} roles=${params.channelConfig.roles?.length ?? 0} skills=${params.channelConfig.skills?.length ?? 0}` : "none";
419
+ logDebug(`[discord-preflight] channelConfig=${channelConfigSummary} channelMatchMeta=${params.channelMatchMeta} channelId=${params.channelId}`);
483
420
  }
484
421
  function logDiscordPreflightInboundSummary(params) {
485
422
  if (!shouldLogVerbose()) return;
@@ -487,13 +424,10 @@ function logDiscordPreflightInboundSummary(params) {
487
424
  }
488
425
  //#endregion
489
426
  //#region extensions/discord/src/monitor/message-handler.preflight-runtime.ts
490
- const loadPluralKitRuntime = createLazyRuntimeModule(() => import("./pluralkit-Tiyl70dx.js").then((n) => n.n));
427
+ const loadPluralKitRuntime = createLazyRuntimeModule(() => import("./pluralkit-XmmAHoV6.js").then((n) => n.n));
491
428
  const loadPreflightAudioRuntime = createLazyRuntimeModule(() => import("./preflight-audio-DrnqFA8U.js"));
492
- const loadSystemEventsRuntime = createLazyRuntimeModule(() => import("./system-events-C7yxaHWP.js"));
493
- const loadDiscordThreadingRuntime = createLazyRuntimeModule(() => import("./threading-agH1T_6s.js").then((n) => n.t));
494
- function isPreflightAborted(abortSignal) {
495
- return Boolean(abortSignal?.aborted);
496
- }
429
+ const loadSystemEventsRuntime = createLazyRuntimeModule(() => import("./system-events-BOiDS8b3.js"));
430
+ const loadDiscordThreadingRuntime = createLazyRuntimeModule(() => import("./threading-OQnL-0Zx.js").then((n) => n.t));
497
431
  //#endregion
498
432
  //#region extensions/discord/src/monitor/message-handler.preflight-pluralkit.ts
499
433
  async function resolveDiscordPreflightPluralKitInfo(params) {
@@ -505,7 +439,7 @@ async function resolveDiscordPreflightPluralKitInfo(params) {
505
439
  config: params.config,
506
440
  signal: params.abortSignal
507
441
  });
508
- return isPreflightAborted(params.abortSignal) ? null : info;
442
+ return params.abortSignal?.aborted ? null : info;
509
443
  } catch (err) {
510
444
  logVerbose(`discord: pluralkit lookup failed for ${params.message.id}: ${String(err)}`);
511
445
  return null;
@@ -527,7 +461,7 @@ async function resolveDiscordPreflightThreadContext(params) {
527
461
  threadChannel: earlyThreadChannel,
528
462
  channelInfo: params.channelInfo
529
463
  });
530
- if (isPreflightAborted(params.abortSignal)) return null;
464
+ if (params.abortSignal?.aborted) return null;
531
465
  return {
532
466
  earlyThreadChannel,
533
467
  earlyThreadParentId: parentInfo.id,
@@ -590,7 +524,7 @@ async function resolveDiscordPreflightRoute(params) {
590
524
  //#endregion
591
525
  //#region extensions/discord/src/monitor/message-handler.preflight.ts
592
526
  const DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
593
- const DISCORD_HISTORY_MEDIA_MAX_BYTES = 10 * 1024 * 1024;
527
+ const DISCORD_HISTORY_MEDIA_MAX_BYTES = 10485760;
594
528
  const DISCORD_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
595
529
  const DISCORD_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
596
530
  function resolveDiscordPreflightConversationKind(params) {
@@ -654,7 +588,7 @@ async function recordDiscordPendingHistoryEntry(params) {
654
588
  limit: params.preflight.historyLimit,
655
589
  mediaLimit: DISCORD_HISTORY_MEDIA_MAX_ATTACHMENTS,
656
590
  messageId: params.message.id,
657
- shouldRecord: () => !isPreflightAborted(params.preflight.abortSignal),
591
+ shouldRecord: () => !params.preflight.abortSignal?.aborted,
658
592
  media: async () => toHistoryMediaEntries(await resolveDiscordHistoryMediaForPendingRecord({
659
593
  preflight: params.preflight,
660
594
  message: params.message
@@ -662,7 +596,7 @@ async function recordDiscordPendingHistoryEntry(params) {
662
596
  });
663
597
  }
664
598
  async function preflightDiscordMessage(params) {
665
- if (isPreflightAborted(params.abortSignal)) return null;
599
+ if (params.abortSignal?.aborted) return null;
666
600
  const logger = getChildLogger({ module: "discord-auto-reply" });
667
601
  let message = params.data.message;
668
602
  const author = params.data.author;
@@ -684,7 +618,7 @@ async function preflightDiscordMessage(params) {
684
618
  messageChannelId
685
619
  });
686
620
  message = hydration.message;
687
- if (isPreflightAborted(params.abortSignal)) return null;
621
+ if (params.abortSignal?.aborted) return null;
688
622
  const pluralkitConfig = params.discordConfig?.pluralkit;
689
623
  const webhookId = resolveDiscordWebhookId(message);
690
624
  if (isRecentOutboundMessageIdentity({
@@ -699,7 +633,7 @@ async function preflightDiscordMessage(params) {
699
633
  }
700
634
  const isGuildMessage = Boolean(params.data.guild_id);
701
635
  const channelInfo = await resolveDiscordChannelInfo(params.client, messageChannelId);
702
- if (isPreflightAborted(params.abortSignal)) return null;
636
+ if (params.abortSignal?.aborted) return null;
703
637
  const { isDirectMessage, isGroupDm } = resolveDiscordPreflightConversationKind({
704
638
  isGuildMessage,
705
639
  channelType: channelInfo?.type
@@ -735,7 +669,7 @@ async function preflightDiscordMessage(params) {
735
669
  config: pluralkitConfig,
736
670
  abortSignal: params.abortSignal
737
671
  });
738
- if (isPreflightAborted(params.abortSignal)) return null;
672
+ if (params.abortSignal?.aborted) return null;
739
673
  const sender = resolveDiscordSenderIdentity({
740
674
  author,
741
675
  member: params.data.member,
@@ -776,7 +710,7 @@ async function preflightDiscordMessage(params) {
776
710
  allowNameMatching,
777
711
  conversationId: messageChannelId
778
712
  });
779
- if (isPreflightAborted(params.abortSignal)) return null;
713
+ if (params.abortSignal?.aborted) return null;
780
714
  if (!access) return null;
781
715
  commandAuthorized = access.commandAuthorized;
782
716
  channelIngress = access.channelIngress;
@@ -927,7 +861,7 @@ async function preflightDiscordMessage(params) {
927
861
  cfg: params.cfg,
928
862
  abortSignal: params.abortSignal
929
863
  });
930
- if (isPreflightAborted(params.abortSignal)) return null;
864
+ if (params.abortSignal?.aborted) return null;
931
865
  const mentionText = hasTypedText ? baseText : "";
932
866
  const { implicitMentionKinds, wasMentioned } = resolveDiscordMentionState({
933
867
  authorIsBot: Boolean(author.bot),
@@ -965,7 +899,9 @@ async function preflightDiscordMessage(params) {
965
899
  sender: {
966
900
  id: sender.id,
967
901
  name: sender.name,
968
- tag: sender.tag
902
+ tag: sender.tag,
903
+ isPluralKit: sender.isPluralKit,
904
+ authorKind: author.bot ? "bot" : "user"
969
905
  },
970
906
  memberAccessConfigured: hasAccessRestrictions,
971
907
  memberAllowed,
@@ -1044,9 +980,13 @@ async function preflightDiscordMessage(params) {
1044
980
  }
1045
981
  }
1046
982
  const ignoreOtherMentions = channelConfig?.ignoreOtherMentions ?? guildInfo?.ignoreOtherMentions ?? false;
1047
- if (isGuildMessage && ignoreOtherMentions && hasUserOrRoleMention && !wasMentioned && !mentionDecision.implicitMention) {
1048
- logDebug(`[discord-preflight] drop: other-mention`);
1049
- logVerbose(`discord: drop guild message (another user/role mentioned, ignoreOtherMentions=true, botId=${botId})`);
983
+ const referencedReply = resolveDiscordReferencedReplyMessage(message);
984
+ const referencedWebhookId = referencedReply ? resolveDiscordWebhookId(referencedReply) : null;
985
+ const referencedAuthor = referencedReply?.author;
986
+ const replyTargetsOtherBot = Boolean(botId) && Boolean(referencedAuthor?.bot) && referencedAuthor?.id !== botId && !referencedWebhookId;
987
+ if (isGuildMessage && ignoreOtherMentions && (hasUserOrRoleMention || replyTargetsOtherBot) && !wasMentioned && !mentionDecision.implicitMention) {
988
+ logDebug(`[discord-preflight] drop: addressed-to-other`);
989
+ logVerbose(`discord: drop guild message (addressed to another identity, ignoreOtherMentions=true, botId=${botId})`);
1050
990
  await recordDiscordPendingHistoryEntry({
1051
991
  preflight: params,
1052
992
  historyKey: messageChannelId,
@@ -1116,9 +1056,9 @@ async function preflightDiscordMessage(params) {
1116
1056
  abortSignal: params.abortSignal
1117
1057
  };
1118
1058
  const preparedMedia = await resolveMediaList(message, params.mediaMaxBytes, mediaResolveOptions);
1119
- if (isPreflightAborted(params.abortSignal)) return null;
1059
+ if (params.abortSignal?.aborted) return null;
1120
1060
  const forwardedMedia = await resolveForwardedMediaList(message, params.mediaMaxBytes, mediaResolveOptions);
1121
- if (isPreflightAborted(params.abortSignal)) return null;
1061
+ if (params.abortSignal?.aborted) return null;
1122
1062
  preparedMedia.push(...forwardedMedia);
1123
1063
  logDebug(`[discord-preflight] success: route=${effectiveRoute.agentId} sessionKey=${effectiveRoute.sessionKey}`);
1124
1064
  return buildDiscordMessagePreflightContext({