@openclaw/discord 2026.8.1 → 2026.8.2

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 (89) 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-Dl-TOyOX.js → activities-api-CkKcHUB6.js} +14 -13
  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 +17 -17
  10. package/dist/{approval-handler.runtime-q4Zqo44V.js → approval-handler.runtime-DZM6Kt1Z.js} +8 -7
  11. package/dist/{audit-DgrvFPGt.js → audit-DIbQA4VT.js} +8 -7
  12. package/dist/{channel-BsQUalPw.js → channel-CarzU3bg.js} +24 -22
  13. package/dist/{channel-actions.runtime-UMGGIfSy.js → channel-actions.runtime-B2wMqeVK.js} +13 -11
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-rPs4dsk_.js → channel.setup-z_ewMVa9.js} +18 -18
  17. package/dist/{components-Dk35LTf_.js → components-gvRA0oaI.js} +1 -1
  18. package/dist/{config-schema-CxPqtVI1.js → config-schema-B797-Spt.js} +5 -4
  19. package/dist/{conversation-binding-route-BjvX4e35.js → conversation-binding-route-DPpBRpYI.js} +1 -1
  20. package/dist/{directory-config-B7DY_pNG.js → directory-config-AA8wQx0D.js} +2 -2
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-DuAXKkan.js → directory-live-D_kFz_Fj.js} +4 -4
  23. package/dist/{doctor-zQTtn6hm.js → doctor-QQTOkBfW.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-DZewwLr1.js → handle-action.guild-admin-Cc88ZGon.js} +2 -2
  27. package/dist/index.js +1 -1
  28. package/dist/{ingress-identity-CzZKcPK8.js → ingress-identity-BCzfPPYM.js} +1 -1
  29. package/dist/{message-handler-C5By3yl5.js → message-handler-CAeEpqWo.js} +14 -10
  30. package/dist/{message-handler.preflight-DrszWuHw.js → message-handler.preflight-CoKoE3dY.js} +24 -19
  31. package/dist/{message-handler.process-DyFPDLCt.js → message-handler.process-cdIJ_fDT.js} +56 -74
  32. package/dist/{message-text-Ca8M6TU8.js → message-text-C0K4-fkg.js} +9 -4
  33. package/dist/{outbound-adapter-Dif8p481.js → outbound-adapter-Ch0At5Ra.js} +34 -24
  34. package/dist/{outbound-components-wjv7yyAj.js → outbound-components-Bnt_7x7r.js} +3 -3
  35. package/dist/{outbound-session-route-Bn4uXaoE.js → outbound-session-route-CzzerX2K.js} +10 -7
  36. package/dist/{owner-access-UlYi9t0M.js → owner-access-yc1sX7Gx.js} +7 -6
  37. package/dist/{pluralkit-9EuEN4UD.js → pluralkit-B3cUVI7i.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-LXiOcJrH.js → provider-CjI8BSzS.js} +97 -76
  41. package/dist/{provider-session.runtime-DSNe7r2W.js → provider-session.runtime-DdKRMcE9.js} +3 -3
  42. package/dist/provider.runtime-Bo1WbLLr.js +2 -0
  43. package/dist/{realtime-session.runtime-DOViOIjY.js → realtime-session.runtime-37IC-p5K.js} +5 -5
  44. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-BJ5UZNNT.js} +3 -3
  45. package/dist/{resolve-channels-D2yl_2CN.js → resolve-channels-BexR2eUn.js} +4 -4
  46. package/dist/{resolve-users-BLxfqajZ.js → resolve-users-BtXBCH5W.js} +5 -4
  47. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  48. package/dist/{retry-DqHCW6PV.js → retry-t5RcEsPk.js} +37 -29
  49. package/dist/{runtime-DrxVBTtp.js → runtime-BNlDfLwS.js} +2 -2
  50. package/dist/{runtime-BYamRVPN.js → runtime-DydyfxST.js} +126 -92
  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/{send-UJHiAm4C.js → send-mTKSBdmZ.js} +76 -48
  55. package/dist/{send.components-CrBJpGT_.js → send.components-nsPnc7kK.js} +20 -14
  56. package/dist/{send.outbound-D7JYmfm9.js → send.outbound-CaOs9Zy1.js} +34 -20
  57. package/dist/{send.shared-DZJ1akvQ.js → send.shared-BJHt0Vyf.js} +24 -17
  58. package/dist/{sender-identity-BJtfyise.js → sender-identity-Dt0imZyY.js} +1 -1
  59. package/dist/setup-plugin-api.js +1 -1
  60. package/dist/{shared-Dii2HTn7.js → shared-BNesVA4P.js} +17 -14
  61. package/dist/{subagent-hooks-JyGrtQIl.js → subagent-hooks-IeZVPLGj.js} +2 -2
  62. package/dist/subagent-hooks-api.js +1 -1
  63. package/dist/{system-events-BEmcj4xJ.js → system-events-Be5EJI3b.js} +2 -2
  64. package/dist/{target-resolver-V-IYae6s.js → target-resolver-C0MnwEki.js} +6 -5
  65. package/dist/targets-DQSye1Rv.js +3 -0
  66. package/dist/{thread-bindings-DvYP79fy.js → thread-bindings-wECUSIIG.js} +6 -5
  67. package/dist/{thread-bindings.manager-Clm77DBM.js → thread-bindings.manager-B-3UHCc1.js} +28 -25
  68. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-CC7HoQvt.js} +2 -1
  69. package/dist/{threading-CXuu_7o9.js → threading-te5ADPQI.js} +8 -6
  70. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  71. package/dist/{transcripts-source-BLEMH_yi.js → transcripts-source-DkUhR7YK.js} +3 -3
  72. package/dist/transcripts-source-api.js +1 -1
  73. package/dist/{typing-B9snnwMe.js → typing-DAwJF5VT.js} +2 -2
  74. package/dist/{voice-runtime-DY6_o73o.js → voice-runtime-COyYYTDD.js} +348 -14
  75. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  76. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  77. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  78. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  79. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  81. package/node_modules/typebox/build/format/email.mjs +1 -1
  82. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  83. package/node_modules/typebox/package.json +1 -1
  84. package/openclaw.plugin.json +2 -2
  85. package/package.json +5 -5
  86. package/dist/account-inspect-BDfKyuvL.js +0 -89
  87. package/dist/provider.runtime-DiInaDXO.js +0 -2
  88. package/dist/sdk-runtime-6tfgYDjY.js +0 -338
  89. package/dist/targets-CQp53cGj.js +0 -3
@@ -1,6 +1,6 @@
1
- import { on as __exportAll } from "./retry-DqHCW6PV.js";
2
- import { a as listEnabledDiscordAccounts, c as resolveDiscordAccount } from "./accounts-CfQ-vSyf.js";
3
- import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-UlYi9t0M.js";
1
+ import { on as __exportAll } from "./retry-t5RcEsPk.js";
2
+ import { a as listEnabledDiscordAccounts, c as resolveDiscordAccount } from "./accounts-CwJQoLjM.js";
3
+ import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-yc1sX7Gx.js";
4
4
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
5
5
  import { summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -1,4 +1,4 @@
1
- import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-BLEMH_yi.js";
1
+ import { t as discordVoiceTranscriptsSourceProvider } from "./transcripts-source-DkUhR7YK.js";
2
2
  //#region extensions/discord/transcripts-source-api.ts
3
3
  function registerDiscordTranscriptSourceProvider(api) {
4
4
  api.registerTranscriptSourceProvider(discordVoiceTranscriptsSourceProvider);
@@ -1,5 +1,5 @@
1
- import { Rt as sendChannelTyping, on as __exportAll } from "./retry-DqHCW6PV.js";
2
- import { c as raceWithTimeout } from "./timeouts-B9cy6RvQ.js";
1
+ import { Rt as sendChannelTyping, on as __exportAll } from "./retry-t5RcEsPk.js";
2
+ import { c as raceWithTimeout } from "./timeouts-D86uWLt_.js";
3
3
  //#region extensions/discord/src/monitor/typing.ts
4
4
  var typing_exports = /* @__PURE__ */ __exportAll({ sendTyping: () => sendTyping });
5
5
  const DISCORD_TYPING_START_TIMEOUT_MS = 5e3;
@@ -1,24 +1,350 @@
1
- import { D as ReadyListener, L as isUnknownDiscordVoiceStateError, O as ResumedListener, Yt as getGuildVoiceState, _ as parseDiscordTarget, j as VoiceStateUpdateListener, y as discord_exports } from "./retry-DqHCW6PV.js";
1
+ import { D as ReadyListener, L as isUnknownDiscordVoiceStateError, O as ResumedListener, Yt as getGuildVoiceState, _ as parseDiscordTarget, j as VoiceStateUpdateListener, on as __exportAll, y as discord_exports } from "./retry-t5RcEsPk.js";
2
2
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
3
- import { a as normalizeDiscordSlug, h as resolveDiscordOwnerAccess, x as formatDiscordUserTag } from "./allow-list-BDMimASD.js";
4
- import { a as formatMention } from "./send.outbound-D7JYmfm9.js";
5
- import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-UlYi9t0M.js";
6
- import { b as resolveFetchedDiscordThreadLikeChannelContext, m as buildDiscordGroupSystemPrompt } from "./provider-LXiOcJrH.js";
7
- import { _ as decodeOpusStreamChunks, a as VOICE_CONNECT_READY_TIMEOUT_MS, b as maybeControlDiscordVoiceAgentRun, c as isVoiceChannel, d as resolveVoiceTimeoutMs, g as decodeOpusStream, h as createDiscordOpusPlaybackStream, i as PLAYBACK_READY_TIMEOUT_MS, l as logVoiceVerbose, n as CAPTURE_FINALIZE_GRACE_MS, o as VOICE_RECONNECT_GRACE_MS, s as isDiscordRealtimeVoiceMode, t as loadDiscordVoiceSdk, u as resolveDiscordVoiceMode, v as writeVoiceWavFile, x as formatVoiceLogPreview, y as formatVoiceIngressPrompt } from "./sdk-runtime-6tfgYDjY.js";
3
+ import { a as normalizeDiscordSlug, h as resolveDiscordOwnerAccess, x as formatDiscordUserTag } from "./allow-list-C2JuH-R0.js";
4
+ import { a as formatMention } from "./send.outbound-CaOs9Zy1.js";
5
+ import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-yc1sX7Gx.js";
6
+ import { b as resolveFetchedDiscordThreadLikeChannelContext, m as buildDiscordGroupSystemPrompt } from "./provider-CjI8BSzS.js";
7
+ import { createRequire } from "node:module";
8
+ import fs from "node:fs/promises";
8
9
  import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
9
10
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
10
11
  import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
11
12
  import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
12
13
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
- import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
14
+ import { createSubsystemLogger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
14
15
  import { escapeRegExp, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
15
16
  import { stripInlineDirectiveTagsForDisplay } from "openclaw/plugin-sdk/text-chunking";
16
- import { unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
17
+ import { resolveFfmpegBin, unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
18
+ import { resolvePreferredOpenClawTmpDir, tempWorkspace } from "openclaw/plugin-sdk/temp-path";
17
19
  import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
18
20
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
19
- import { Readable } from "node:stream";
20
- import { OpusError } from "libopus-wasm";
21
+ import { controlRealtimeVoiceAgentRun, resamplePcm, shouldAutoControlRealtimeVoiceAgentText } from "openclaw/plugin-sdk/realtime-voice";
22
+ import { spawn } from "node:child_process";
23
+ import { Readable, Transform } from "node:stream";
24
+ import { StringDecoder } from "node:string_decoder";
25
+ import { Application, OpusError, createDecoder, createEncoder } from "libopus-wasm";
21
26
  import { resolveRealtimeBootstrapContextInstructions } from "openclaw/plugin-sdk/realtime-bootstrap-context";
27
+ //#region extensions/discord/src/voice/log-preview.ts
28
+ const DISCORD_VOICE_LOG_PREVIEW_CHARS = 500;
29
+ function formatVoiceLogPreview(text) {
30
+ const oneLine = text.replace(/\s+/g, " ").trim();
31
+ if (oneLine.length <= DISCORD_VOICE_LOG_PREVIEW_CHARS) return oneLine;
32
+ return `${truncateUtf16Safe(oneLine, DISCORD_VOICE_LOG_PREVIEW_CHARS)}...`;
33
+ }
34
+ //#endregion
35
+ //#region extensions/discord/src/voice/agent-control.ts
36
+ async function maybeControlDiscordVoiceAgentRun(params) {
37
+ if (!shouldAutoControlRealtimeVoiceAgentText(params.text)) return { handled: false };
38
+ const result = await controlRealtimeVoiceAgentRun({
39
+ sessionKey: params.entry.route.sessionKey,
40
+ text: params.text
41
+ });
42
+ if (!result.active) return {
43
+ handled: false,
44
+ result
45
+ };
46
+ return {
47
+ handled: true,
48
+ result,
49
+ ...result.speak && !result.suppress ? { speakText: result.message } : {}
50
+ };
51
+ }
52
+ //#endregion
53
+ //#region extensions/discord/src/voice/prompt.ts
54
+ const DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT = [
55
+ "You are OpenClaw's Discord voice interface in a live voice channel.",
56
+ "Discord voice reply requirements:",
57
+ "- Return only the concise text that should be spoken aloud in the voice channel.",
58
+ "- Treat the transcript as speech-to-text from a live conversation; repair obvious transcription artifacts and ignore repeated partial fragments caused by voice buffering.",
59
+ "- If the transcript is garbled, incomplete, or missing the user's intent, ask one brief clarifying question instead of guessing.",
60
+ "- If the request needs deeper reasoning, current information, or tools, use the available tools before answering.",
61
+ "- Do not call the tts tool; Discord voice will synthesize and play the returned text.",
62
+ "- Do not reply with NO_REPLY unless no spoken response is appropriate.",
63
+ "- Keep the response brief, natural, and conversational. Prefer one to three short sentences.",
64
+ "- Avoid markdown tables, code fences, citations, and visual formatting unless the user explicitly asks for something that cannot be spoken naturally."
65
+ ].join("\n");
66
+ function formatVoiceIngressPrompt(transcript, speakerLabel) {
67
+ const cleanedTranscript = transcript.trim();
68
+ const cleanedLabel = speakerLabel?.trim();
69
+ const voiceInput = cleanedLabel ? [`Voice transcript from speaker "${cleanedLabel}":`, cleanedTranscript].join("\n") : cleanedTranscript;
70
+ return [DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT, voiceInput].join("\n\n");
71
+ }
72
+ //#endregion
73
+ //#region extensions/discord/src/voice/audio.ts
74
+ const SAMPLE_RATE = 48e3;
75
+ const CHANNELS = 2;
76
+ const BIT_DEPTH = 16;
77
+ const FFMPEG_ERROR_OUTPUT_BYTES = 8192;
78
+ const DISCORD_OPUS_FRAME_SIZE = 960;
79
+ const DISCORD_OPUS_FRAME_BYTES = DISCORD_OPUS_FRAME_SIZE * CHANNELS * (BIT_DEPTH / 8);
80
+ const FFMPEG_PCM_ARGUMENTS = [
81
+ "-analyzeduration",
82
+ "0",
83
+ "-loglevel",
84
+ "error",
85
+ "-vn",
86
+ "-sn",
87
+ "-dn",
88
+ "-f",
89
+ "s16le",
90
+ "-ar",
91
+ String(SAMPLE_RATE),
92
+ "-ac",
93
+ String(CHANNELS)
94
+ ];
95
+ let warnedOpusMissing = false;
96
+ function buildWavBuffer(pcm) {
97
+ const blockAlign = 4;
98
+ const byteRate = SAMPLE_RATE * blockAlign;
99
+ const header = Buffer.alloc(44);
100
+ header.write("RIFF", 0);
101
+ header.writeUInt32LE(36 + pcm.length, 4);
102
+ header.write("WAVE", 8);
103
+ header.write("fmt ", 12);
104
+ header.writeUInt32LE(16, 16);
105
+ header.writeUInt16LE(1, 20);
106
+ header.writeUInt16LE(CHANNELS, 22);
107
+ header.writeUInt32LE(SAMPLE_RATE, 24);
108
+ header.writeUInt32LE(byteRate, 28);
109
+ header.writeUInt16LE(blockAlign, 32);
110
+ header.writeUInt16LE(BIT_DEPTH, 34);
111
+ header.write("data", 36);
112
+ header.writeUInt32LE(pcm.length, 40);
113
+ return Buffer.concat([header, pcm]);
114
+ }
115
+ function createDiscordOpusEncodeStream() {
116
+ return new DiscordOpusEncodeStream();
117
+ }
118
+ function createDiscordOpusPlaybackStream(input) {
119
+ const inputSource = typeof input === "string" ? input : "pipe:0";
120
+ const ffmpeg = spawn(resolveFfmpegBin(), [
121
+ "-i",
122
+ inputSource,
123
+ ...FFMPEG_PCM_ARGUMENTS,
124
+ "pipe:1"
125
+ ], {
126
+ stdio: [
127
+ "pipe",
128
+ "pipe",
129
+ "pipe"
130
+ ],
131
+ windowsHide: true
132
+ });
133
+ const opusStream = createDiscordOpusEncodeStream();
134
+ const stderr = Buffer.alloc(FFMPEG_ERROR_OUTPUT_BYTES);
135
+ let stderrBytes = 0;
136
+ let ffmpegClosed = false;
137
+ const killFfmpeg = (signal = "SIGTERM") => {
138
+ if (!ffmpegClosed && !ffmpeg.killed) ffmpeg.kill(signal);
139
+ };
140
+ ffmpeg.stderr.on("data", (chunk) => {
141
+ if (stderrBytes < FFMPEG_ERROR_OUTPUT_BYTES) stderrBytes += chunk.copy(stderr, stderrBytes, 0, FFMPEG_ERROR_OUTPUT_BYTES - stderrBytes);
142
+ });
143
+ ffmpeg.once("error", (err) => {
144
+ opusStream.destroy(err);
145
+ });
146
+ ffmpeg.once("close", (code, signal) => {
147
+ ffmpegClosed = true;
148
+ if (code && code !== 0) {
149
+ const stderrText = new StringDecoder("utf8").write(stderr.subarray(0, stderrBytes)).trim();
150
+ const suffix = stderrText ? `: ${stderrText}` : "";
151
+ opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with code ${code}${suffix}`));
152
+ return;
153
+ }
154
+ if (signal) opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with signal ${signal}`));
155
+ });
156
+ for (const readable of [ffmpeg.stdout, ffmpeg.stderr]) readable.on("error", (err) => {
157
+ killFfmpeg("SIGKILL");
158
+ opusStream.destroy(err);
159
+ });
160
+ ffmpeg.stdin.on("error", (err) => {
161
+ if (err.code !== "EPIPE") opusStream.destroy(err);
162
+ });
163
+ ffmpeg.stdout.pipe(opusStream);
164
+ opusStream.once("close", () => {
165
+ if (!opusStream.readableEnded) killFfmpeg();
166
+ });
167
+ if (typeof input !== "string") {
168
+ input.on("error", (err) => {
169
+ ffmpeg.stdin.destroy(err);
170
+ opusStream.destroy(err);
171
+ });
172
+ input.pipe(ffmpeg.stdin);
173
+ } else ffmpeg.stdin.end();
174
+ return opusStream;
175
+ }
176
+ var DiscordOpusEncodeStream = class extends Transform {
177
+ #buffer = Buffer.alloc(0);
178
+ #encoder;
179
+ constructor() {
180
+ super({ readableObjectMode: true });
181
+ }
182
+ _construct(done) {
183
+ createEncoder({
184
+ application: Application.Audio,
185
+ channels: CHANNELS,
186
+ sampleRate: SAMPLE_RATE
187
+ }).then((encoder) => {
188
+ this.#encoder = encoder;
189
+ done();
190
+ }, (err) => done(err instanceof Error ? err : new Error(formatErrorMessage(err))));
191
+ }
192
+ _transform(chunk, _encoding, done) {
193
+ try {
194
+ this.#buffer = this.#buffer.length > 0 ? Buffer.concat([this.#buffer, chunk]) : Buffer.from(chunk);
195
+ while (this.#buffer.length >= DISCORD_OPUS_FRAME_BYTES) {
196
+ const frame = this.#buffer.subarray(0, DISCORD_OPUS_FRAME_BYTES);
197
+ this.#buffer = this.#buffer.subarray(DISCORD_OPUS_FRAME_BYTES);
198
+ this.#encodeFrame(frame);
199
+ }
200
+ done();
201
+ } catch (err) {
202
+ done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
203
+ }
204
+ }
205
+ _flush(done) {
206
+ try {
207
+ if (this.#buffer.length > 0) {
208
+ const frame = Buffer.alloc(DISCORD_OPUS_FRAME_BYTES);
209
+ this.#buffer.copy(frame);
210
+ this.#buffer = Buffer.alloc(0);
211
+ this.#encodeFrame(frame);
212
+ }
213
+ done();
214
+ } catch (err) {
215
+ done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
216
+ }
217
+ }
218
+ _destroy(err, done) {
219
+ this.#encoder?.free();
220
+ this.#buffer = Buffer.alloc(0);
221
+ done(err);
222
+ }
223
+ #encodeFrame(frame) {
224
+ this.push(Buffer.from(this.#encoder.encode(frame, { frameSize: DISCORD_OPUS_FRAME_SIZE })));
225
+ }
226
+ };
227
+ function pcmInt16ToBuffer(pcm) {
228
+ return Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength);
229
+ }
230
+ async function decodeOpusStream(stream, params) {
231
+ const chunks = [];
232
+ await decodeOpusStreamChunks(stream, {
233
+ ...params,
234
+ onChunk: (chunk) => chunks.push(chunk)
235
+ });
236
+ return Buffer.concat(chunks);
237
+ }
238
+ async function decodeOpusStreamChunks(stream, params) {
239
+ let decoder;
240
+ try {
241
+ decoder = await createDecoder({
242
+ channels: CHANNELS,
243
+ sampleRate: SAMPLE_RATE
244
+ });
245
+ } catch (err) {
246
+ if (!warnedOpusMissing) {
247
+ warnedOpusMissing = true;
248
+ params.onWarn(`discord voice: no usable opus decoder available (libopus-wasm: ${formatErrorMessage(err)}); cannot decode voice audio`);
249
+ }
250
+ return;
251
+ }
252
+ params.onVerbose("opus decoder: libopus-wasm");
253
+ try {
254
+ for await (const chunk of stream) {
255
+ if (!chunk || !(chunk instanceof Buffer) || chunk.length === 0) continue;
256
+ const decoded = decoder.decode(chunk, { maxFrameSize: DISCORD_OPUS_FRAME_SIZE });
257
+ if (decoded.length > 0) params.onChunk(pcmInt16ToBuffer(decoded));
258
+ }
259
+ } catch (err) {
260
+ params.onError?.(err);
261
+ if (shouldLogVerbose()) logVerbose(`discord voice: opus decode failed: ${formatErrorMessage(err)}`);
262
+ } finally {
263
+ decoder.free();
264
+ }
265
+ }
266
+ function convertDiscordPcm48kStereoToRealtimePcm24kMono(pcm) {
267
+ const frameCount = Math.floor(pcm.length / 4);
268
+ if (frameCount === 0) return Buffer.alloc(0);
269
+ const mono48k = Buffer.alloc(frameCount * 2);
270
+ for (let frame = 0; frame < frameCount; frame += 1) {
271
+ const offset = frame * 4;
272
+ const left = pcm.readInt16LE(offset);
273
+ const right = pcm.readInt16LE(offset + 2);
274
+ mono48k.writeInt16LE(Math.round((left + right) / 2), frame * 2);
275
+ }
276
+ return resamplePcm(mono48k, SAMPLE_RATE, 24e3);
277
+ }
278
+ function convertRealtimePcm24kMonoToDiscordPcm48kStereo(pcm) {
279
+ const mono48k = resamplePcm(pcm, 24e3, SAMPLE_RATE);
280
+ const sampleCount = Math.floor(mono48k.length / 2);
281
+ if (sampleCount === 0) return Buffer.alloc(0);
282
+ const stereo = Buffer.alloc(sampleCount * 4);
283
+ for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex += 1) {
284
+ const sample = mono48k.readInt16LE(sampleIndex * 2);
285
+ const offset = sampleIndex * 4;
286
+ stereo.writeInt16LE(sample, offset);
287
+ stereo.writeInt16LE(sample, offset + 2);
288
+ }
289
+ return stereo;
290
+ }
291
+ function estimateDurationSeconds(pcm) {
292
+ const bytesPerSample = BIT_DEPTH / 8 * CHANNELS;
293
+ return pcm.length / (bytesPerSample * SAMPLE_RATE);
294
+ }
295
+ async function writeVoiceWavFile(pcm) {
296
+ const workspace = await tempWorkspace({
297
+ rootDir: resolvePreferredOpenClawTmpDir(),
298
+ prefix: "discord-voice-"
299
+ });
300
+ scheduleTempCleanup(workspace.dir);
301
+ const wav = buildWavBuffer(pcm);
302
+ return {
303
+ path: await workspace.write("segment.wav", wav),
304
+ durationSeconds: estimateDurationSeconds(pcm)
305
+ };
306
+ }
307
+ function scheduleTempCleanup(tempDir, delayMs = 18e5) {
308
+ setTimeout(() => {
309
+ fs.rm(tempDir, {
310
+ recursive: true,
311
+ force: true
312
+ }).catch((err) => {
313
+ if (shouldLogVerbose()) logVerbose(`discord voice: temp cleanup failed for ${tempDir}: ${formatErrorMessage(err)}`);
314
+ });
315
+ }, delayMs).unref();
316
+ }
317
+ const CAPTURE_FINALIZE_GRACE_MS = 2e3;
318
+ const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
319
+ const VOICE_RECONNECT_GRACE_MS = 15e3;
320
+ const PLAYBACK_READY_TIMEOUT_MS = 6e4;
321
+ function resolveVoiceTimeoutMs(value, fallbackMs) {
322
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
323
+ return Math.floor(value);
324
+ }
325
+ function resolveDiscordVoiceMode(voice) {
326
+ const mode = voice?.mode;
327
+ if (mode === "stt-tts" || mode === "bidi") return mode;
328
+ return "agent-proxy";
329
+ }
330
+ function isDiscordRealtimeVoiceMode(mode) {
331
+ return mode === "agent-proxy" || mode === "bidi";
332
+ }
333
+ function logVoiceVerbose(message) {
334
+ logVerbose(`discord voice: ${message}`);
335
+ }
336
+ function isVoiceChannel(type) {
337
+ return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
338
+ }
339
+ //#endregion
340
+ //#region extensions/discord/src/voice/sdk-runtime.ts
341
+ let cachedDiscordVoiceSdk = null;
342
+ function loadDiscordVoiceSdk() {
343
+ if (cachedDiscordVoiceSdk) return cachedDiscordVoiceSdk;
344
+ cachedDiscordVoiceSdk = createRequire(import.meta.url)("@discordjs/voice");
345
+ return cachedDiscordVoiceSdk;
346
+ }
347
+ //#endregion
22
348
  //#region extensions/discord/src/voice/ingress.ts
23
349
  const DISCORD_VOICE_MESSAGE_PROVIDER = "discord-voice";
24
350
  const logger$7 = createSubsystemLogger("discord/voice");
@@ -1115,12 +1441,13 @@ function sanitizeVoiceReplyTextForSpeech(text, speakerLabel) {
1115
1441
  //#endregion
1116
1442
  //#region extensions/discord/src/voice/tts.ts
1117
1443
  async function transcribeVoiceAudio(params) {
1118
- return normalizeOptionalString((await getDiscordRuntime().mediaUnderstanding.transcribeAudioFile({
1444
+ const result = await getDiscordRuntime().mediaUnderstanding.transcribeAudioFile({
1119
1445
  filePath: params.filePath,
1120
1446
  cfg: params.cfg,
1121
1447
  agentDir: resolveAgentDir(params.cfg, params.agentId),
1122
1448
  mime: "audio/wav"
1123
- })).text);
1449
+ });
1450
+ return normalizeOptionalString(result.text);
1124
1451
  }
1125
1452
  async function synthesizeVoiceReplyAudio(params) {
1126
1453
  const runtime = getDiscordRuntime();
@@ -2052,7 +2379,7 @@ var DiscordVoiceSessions = class {
2052
2379
  ok: false,
2053
2380
  message: "Discord realtime voice session stopped before startup completed."
2054
2381
  };
2055
- const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-DOViOIjY.js");
2382
+ const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-37IC-p5K.js");
2056
2383
  const realtime = new DiscordRealtimeVoiceSession({
2057
2384
  accountId: this.params.accountId,
2058
2385
  bootstrapContextInstructions,
@@ -2156,6 +2483,13 @@ var DiscordVoiceStateUpdateListener = class extends VoiceStateUpdateListener {
2156
2483
  };
2157
2484
  //#endregion
2158
2485
  //#region extensions/discord/src/voice/voice-runtime.ts
2486
+ var voice_runtime_exports = /* @__PURE__ */ __exportAll({
2487
+ DiscordVoiceGuildCreateListener: () => DiscordVoiceGuildCreateListener,
2488
+ DiscordVoiceManager: () => DiscordVoiceManager,
2489
+ DiscordVoiceReadyListener: () => DiscordVoiceReadyListener,
2490
+ DiscordVoiceResumedListener: () => DiscordVoiceResumedListener,
2491
+ DiscordVoiceStateUpdateListener: () => DiscordVoiceStateUpdateListener
2492
+ });
2159
2493
  const logger = createSubsystemLogger("discord/voice");
2160
2494
  const DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS = [
2161
2495
  "api key missing",
@@ -2556,4 +2890,4 @@ var DiscordVoiceManager = class {
2556
2890
  }
2557
2891
  };
2558
2892
  //#endregion
2559
- export { DiscordVoiceGuildCreateListener, DiscordVoiceManager, DiscordVoiceReadyListener, DiscordVoiceResumedListener, DiscordVoiceStateUpdateListener };
2893
+ export { DiscordVoiceGuildCreateListener, DiscordVoiceManager, DiscordVoiceReadyListener, DiscordVoiceResumedListener, DiscordVoiceStateUpdateListener, convertRealtimePcm24kMonoToDiscordPcm48kStereo as a, maybeControlDiscordVoiceAgentRun as c, convertDiscordPcm48kStereoToRealtimePcm24kMono as i, formatVoiceLogPreview as l, loadDiscordVoiceSdk as n, createDiscordOpusEncodeStream as o, logVoiceVerbose as r, formatVoiceIngressPrompt as s, voice_runtime_exports as t };
@@ -8,7 +8,7 @@ This package contains type definitions for lodash (https://lodash.com).
8
8
  Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash.
9
9
 
10
10
  ### Additional Details
11
- * Last updated: Mon, 23 Feb 2026 05:30:26 GMT
11
+ * Last updated: Sat, 01 Aug 2026 03:43:12 GMT
12
12
  * Dependencies: none
13
13
 
14
14
  # Credits
@@ -0,0 +1,2 @@
1
+ import { conforms } from "./index";
2
+ export = conforms;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@types/lodash",
3
- "version": "4.17.24",
3
+ "version": "4.17.25",
4
4
  "description": "TypeScript definitions for lodash",
5
5
  "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/lodash",
6
6
  "license": "MIT",
@@ -51,6 +51,6 @@
51
51
  "scripts": {},
52
52
  "dependencies": {},
53
53
  "peerDependencies": {},
54
- "typesPublisherContentHash": "6d5f9d074e23fea95ae8ef8f188116218dbc1b67c538bd01d89810cceb550268",
55
- "typeScriptVersion": "5.2"
54
+ "typesPublisherContentHash": "5b89763740a3523d5295cc411a286fab1b0799800b598f81ec76d2f90a1ffce3",
55
+ "typeScriptVersion": "5.6"
56
56
  }
@@ -0,0 +1,2 @@
1
+ import { stubArray } from "./index";
2
+ export = stubArray;
@@ -0,0 +1,2 @@
1
+ import { stubObject } from "./index";
2
+ export = stubObject;
@@ -0,0 +1,2 @@
1
+ import { stubString } from "./index";
2
+ export = stubString;
@@ -1,4 +1,4 @@
1
- const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\.)*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i;
1
+ const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\[\x20-\x7e])*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i;
2
2
  /**
3
3
  * Returns true if the value is an Email
4
4
  * @specification https://datatracker.ietf.org/doc/html/rfc5322
@@ -1,6 +1,9 @@
1
1
  import * as FormatBidi from './format/bidi.mjs';
2
2
  import * as LabelUnicode from './label/unicode.mjs';
3
3
  import * as LabelPuny from './label/puny.mjs';
4
+ // ------------------------------------------------------------------
5
+ // IsLabel
6
+ // ------------------------------------------------------------------
4
7
  function IsValidLabelLength(value) {
5
8
  return value.length > 0 && value.length <= 63;
6
9
  }
@@ -8,9 +11,24 @@ function IsLabel(value) {
8
11
  return IsValidLabelLength(value) && (LabelPuny.IsPunyLabel(value) ||
9
12
  LabelUnicode.IsUnicodeLabel(value));
10
13
  }
14
+ // ------------------------------------------------------------------
15
+ // NormalizeHostname
16
+ //
17
+ // Normalizes a hostname for label validation. Normalizes for NFC
18
+ // such that equivalent codepoint sequences can be uniformly
19
+ // compared. It also removes codepoints that IDNA mapping ignores,
20
+ // and converts full stop variants to ASCII '.' so the hostname can
21
+ // be split into labels.
22
+ // ------------------------------------------------------------------
11
23
  function NormalizeHostname(value) {
12
- return value.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
24
+ return value
25
+ .normalize('NFC')
26
+ .replace(/[\u00ad\u034f\u180b-\u180d\u200b\ufe00-\ufe0f\u{e0100}-\u{e01ef}]/gu, '') // RE_IGNORED_MAPPING
27
+ .replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.'); // RE_FULL_STOP_MAPPING
13
28
  }
29
+ // ------------------------------------------------------------------
30
+ // IsIdnHostname
31
+ // ------------------------------------------------------------------
14
32
  export function IsIdnHostname(value) {
15
33
  if (value.length === 0 || value.includes(' '))
16
34
  return false;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.3.16",
4
+ "version": "1.3.17",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
@@ -3795,11 +3795,11 @@
3795
3795
  },
3796
3796
  "threadBindings.enabled": {
3797
3797
  "label": "Discord Thread Binding Enabled",
3798
- "help": "Enable Discord thread binding features (/focus, bound-thread routing/delivery, and thread-bound subagent sessions). Overrides session.threadBindings.enabled when set."
3798
+ "help": "Enable Discord thread-bound session spawning, routing, and delivery. Overrides session.threadBindings.enabled when set."
3799
3799
  },
3800
3800
  "threadBindings.idleHours": {
3801
3801
  "label": "Discord Thread Binding Idle Timeout (hours)",
3802
- "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."
3802
+ "help": "Inactivity window in hours for Discord thread-bound sessions. Set 0 to disable idle expiry (default: 24). Overrides session.threadBindings.idleHours when set."
3803
3803
  },
3804
3804
  "threadBindings.maxAgeHours": {
3805
3805
  "label": "Discord Thread Binding Max Age (hours)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.8.1",
3
+ "version": "2026.8.2",
4
4
  "description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,13 +13,13 @@
13
13
  "discord-api-types": "0.38.53",
14
14
  "libopus-wasm": "0.2.0",
15
15
  "mdast-util-from-markdown": "2.0.3",
16
- "typebox": "1.3.16",
16
+ "typebox": "1.3.17",
17
17
  "undici": "8.10.0",
18
18
  "ws": "8.21.3",
19
19
  "zod": "4.4.3"
20
20
  },
21
21
  "peerDependencies": {
22
- "openclaw": ">=2026.8.1"
22
+ "openclaw": ">=2026.8.2"
23
23
  },
24
24
  "peerDependenciesMeta": {
25
25
  "openclaw": {
@@ -94,10 +94,10 @@
94
94
  "allowInvalidConfigRecovery": true
95
95
  },
96
96
  "compat": {
97
- "pluginApi": ">=2026.8.1"
97
+ "pluginApi": ">=2026.8.2"
98
98
  },
99
99
  "build": {
100
- "openclawVersion": "2026.8.1",
100
+ "openclawVersion": "2026.8.2",
101
101
  "staticAssets": [
102
102
  {
103
103
  "source": "./assets/embedded-app-sdk.mjs",