@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.
- package/dist/account-inspect-BY-ve3yH.js +45 -0
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
- package/dist/action-runtime-api.js +1 -1
- package/dist/{activities-api-q-9PaaHH.js → activities-api-E-segZn6.js} +30 -17
- package/dist/activities-api.js +1 -1
- package/dist/{allow-list-BDMimASD.js → allow-list-C2JuH-R0.js} +10 -6
- package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
- package/dist/api.js +18 -18
- package/dist/{approval-handler.runtime-B7qhK3fR.js → approval-handler.runtime-CW5k3mSa.js} +19 -12
- package/dist/{audit-CBEv_ERu.js → audit-B9rydv5a.js} +8 -7
- package/dist/{channel-Dx1tMTfx.js → channel-D93LnbTE.js} +29 -23
- package/dist/{channel-actions.runtime-CLWWu9nC.js → channel-actions.runtime-DMFv4doE.js} +16 -13
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-DOzXS2Pk.js → channel.setup-DTL7kPOM.js} +18 -18
- package/dist/{components-B9V5o361.js → components-DmXYIQ26.js} +111 -149
- package/dist/{config-schema-BR13IAx6.js → config-schema-B797-Spt.js} +19 -12
- package/dist/{conversation-binding-route-DJYrY2TQ.js → conversation-binding-route-24afmvEC.js} +1 -1
- package/dist/{directory-config-BK6eqekJ.js → directory-config-BD4YL7wT.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DSAJSrJk.js → directory-live-BrFVc1Ds.js} +4 -4
- package/dist/{doctor-Cm7Y1pJ2.js → doctor-BUB41_lr.js} +5 -5
- package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
- package/dist/doctor-contract-api.js +3 -2
- package/dist/{handle-action.guild-admin-BdwCRHmm.js → handle-action.guild-admin-B0egstYq.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/ingress-identity-BCzfPPYM.js +60 -0
- package/dist/{message-handler-BXpWZyni.js → message-handler-Qdw9c0j4.js} +14 -10
- package/dist/{message-handler.preflight-Ba5LAY_X.js → message-handler.preflight-Dxi2yBfR.js} +41 -101
- package/dist/{message-handler.process-3HEzmemS.js → message-handler.process-BYDjtxZJ.js} +83 -109
- package/dist/{message-text-aiwO5R2F.js → message-text-BRVqYm-t.js} +11 -6
- package/dist/{outbound-adapter-BE4jSq2d.js → outbound-adapter-DEhthWTk.js} +52 -67
- package/dist/{outbound-components-oLpg8Qzb.js → outbound-components-DehyxvA4.js} +5 -4
- package/dist/{outbound-session-route-Cg15ZFJd.js → outbound-session-route-BFGRF9fE.js} +55 -12
- package/dist/{owner-access-UlYi9t0M.js → owner-access-yc1sX7Gx.js} +7 -6
- package/dist/{pluralkit-Tiyl70dx.js → pluralkit-XmmAHoV6.js} +2 -2
- package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
- package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
- package/dist/{provider-B11xwilq.js → provider-DuDtKbF8.js} +294 -131
- package/dist/{provider-session.runtime-B9xe-Qaf.js → provider-session.runtime-BA2BPyZ4.js} +3 -3
- package/dist/provider.runtime-Db8YwZBv.js +2 -0
- package/dist/{realtime-session.runtime-CU8IQUS-.js → realtime-session.runtime-DgSbX6ay.js} +103 -163
- package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-BJ5UZNNT.js} +3 -3
- package/dist/{resolve-channels-C2sT_n67.js → resolve-channels-CYseD5Uw.js} +4 -4
- package/dist/{resolve-users-CzpjLwjy.js → resolve-users-DrmhDrqm.js} +5 -4
- package/dist/{retry-Cv4jCU5Z.js → retry-BNCxiyyR.js} +120 -32
- package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
- package/dist/{runtime-BHrTlFkf.js → runtime-BbWNtfyq.js} +127 -93
- package/dist/{runtime-CY4PRMF-.js → runtime-DB7Fb6AU.js} +2 -2
- package/dist/runtime-api.js +19 -19
- package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
- package/dist/secret-contract-api.js +1 -1
- package/dist/{security-audit-BfJhAXZp.js → security-audit-DKfK-iPY.js} +10 -11
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/{security-audit.runtime-BVKF9VtY.js → security-audit.runtime-sKZyKgpx.js} +1 -1
- package/dist/{send-C49MFF9j.js → send-BnTEIeLE.js} +132 -100
- package/dist/{send.components-DKKAw5VX.js → send.components-BWVEcjRP.js} +21 -15
- package/dist/{send.outbound-zam0TrZx.js → send.outbound-b5xwHTlL.js} +35 -22
- package/dist/{send.shared-JjljcV4O.js → send.shared-5vxBTagO.js} +25 -18
- package/dist/{sender-identity-BJtfyise.js → sender-identity-Dt0imZyY.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-_5EcP4jW.js → shared-BSJWHEMA.js} +20 -14
- package/dist/{subagent-hooks-DQzvOptn.js → subagent-hooks-IzQKX4RQ.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-C7yxaHWP.js → system-events-BOiDS8b3.js} +2 -2
- package/dist/{target-resolver-vxIh6O3-.js → target-resolver-BVI8xSSC.js} +6 -5
- package/dist/targets-DbxVbq8k.js +3 -0
- package/dist/{thread-bindings-DW5F9vat.js → thread-bindings-D7mcaXQC.js} +6 -5
- package/dist/{thread-bindings.manager-ByOtwjo_.js → thread-bindings.manager-B1oySiVc.js} +37 -28
- package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-CC7HoQvt.js} +2 -1
- package/dist/{threading-agH1T_6s.js → threading-OQnL-0Zx.js} +8 -6
- package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
- package/dist/{transcripts-source-BR11iHA4.js → transcripts-source-D8lH7AkN.js} +9 -4
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing-Dc_YMY2e.js → typing-C9q0AQMb.js} +2 -2
- package/dist/{voice-runtime-DIeaa8fJ.js → voice-runtime-Dfhjh1tV.js} +433 -93
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
- package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
- package/node_modules/typebox/build/format/email.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
- package/node_modules/typebox/package.json +1 -1
- package/openclaw.plugin.json +14 -6
- package/package.json +6 -5
- package/skills/discord/SKILL.md +1 -1
- package/dist/account-inspect-BDfKyuvL.js +0 -89
- package/dist/provider.runtime-DiYaHvOz.js +0 -2
- package/dist/sdk-runtime-4geQHtXc.js +0 -338
- package/dist/targets-CtTKvntJ.js +0 -3
|
@@ -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:
|
|
11
|
+
* Last updated: Sat, 01 Aug 2026 03:43:12 GMT
|
|
12
12
|
* Dependencies: none
|
|
13
13
|
|
|
14
14
|
# Credits
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@types/lodash",
|
|
3
|
-
"version": "4.17.
|
|
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": "
|
|
55
|
-
"typeScriptVersion": "5.
|
|
54
|
+
"typesPublisherContentHash": "5b89763740a3523d5295cc411a286fab1b0799800b598f81ec76d2f90a1ffce3",
|
|
55
|
+
"typeScriptVersion": "5.6"
|
|
56
56
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]
|
|
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
|
|
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;
|
package/openclaw.plugin.json
CHANGED
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"type": "boolean"
|
|
64
64
|
},
|
|
65
65
|
"dmPolicy": {
|
|
66
|
+
"default": "pairing",
|
|
66
67
|
"type": "string",
|
|
67
68
|
"enum": [
|
|
68
69
|
"pairing",
|
|
@@ -359,6 +360,9 @@
|
|
|
359
360
|
}
|
|
360
361
|
]
|
|
361
362
|
},
|
|
363
|
+
"joinIntro": {
|
|
364
|
+
"type": "boolean"
|
|
365
|
+
},
|
|
362
366
|
"commands": {
|
|
363
367
|
"type": "object",
|
|
364
368
|
"properties": {
|
|
@@ -1892,7 +1896,6 @@
|
|
|
1892
1896
|
"type": "string"
|
|
1893
1897
|
},
|
|
1894
1898
|
"groupPolicy": {
|
|
1895
|
-
"default": "allowlist",
|
|
1896
1899
|
"type": "string",
|
|
1897
1900
|
"enum": [
|
|
1898
1901
|
"open",
|
|
@@ -2170,6 +2173,9 @@
|
|
|
2170
2173
|
}
|
|
2171
2174
|
]
|
|
2172
2175
|
},
|
|
2176
|
+
"joinIntro": {
|
|
2177
|
+
"type": "boolean"
|
|
2178
|
+
},
|
|
2173
2179
|
"commands": {
|
|
2174
2180
|
"type": "object",
|
|
2175
2181
|
"properties": {
|
|
@@ -3647,9 +3653,6 @@
|
|
|
3647
3653
|
"additionalProperties": false
|
|
3648
3654
|
}
|
|
3649
3655
|
},
|
|
3650
|
-
"required": [
|
|
3651
|
-
"groupPolicy"
|
|
3652
|
-
],
|
|
3653
3656
|
"additionalProperties": false
|
|
3654
3657
|
}
|
|
3655
3658
|
},
|
|
@@ -3658,6 +3661,7 @@
|
|
|
3658
3661
|
}
|
|
3659
3662
|
},
|
|
3660
3663
|
"required": [
|
|
3664
|
+
"dmPolicy",
|
|
3661
3665
|
"groupPolicy"
|
|
3662
3666
|
],
|
|
3663
3667
|
"additionalProperties": false
|
|
@@ -3769,6 +3773,10 @@
|
|
|
3769
3773
|
"label": "Discord Progress Command Text",
|
|
3770
3774
|
"help": "Command/exec detail in progress draft lines: \"status\" is the safe default; \"raw\" opts into command text."
|
|
3771
3775
|
},
|
|
3776
|
+
"joinIntro": {
|
|
3777
|
+
"label": "Discord Guild Join Introduction",
|
|
3778
|
+
"help": "Post one brief, room-specific introduction when the bot joins an allowed Discord guild (default: true). Account settings override the channel-wide setting."
|
|
3779
|
+
},
|
|
3772
3780
|
"proxy": {
|
|
3773
3781
|
"label": "Discord Proxy URL",
|
|
3774
3782
|
"help": "Proxy URL for Discord gateway + API requests (app-id lookup and allowlist resolution). Set per account via channels.discord.accounts.<id>.proxy."
|
|
@@ -3787,11 +3795,11 @@
|
|
|
3787
3795
|
},
|
|
3788
3796
|
"threadBindings.enabled": {
|
|
3789
3797
|
"label": "Discord Thread Binding Enabled",
|
|
3790
|
-
"help": "Enable Discord thread
|
|
3798
|
+
"help": "Enable Discord thread-bound session spawning, routing, and delivery. Overrides session.threadBindings.enabled when set."
|
|
3791
3799
|
},
|
|
3792
3800
|
"threadBindings.idleHours": {
|
|
3793
3801
|
"label": "Discord Thread Binding Idle Timeout (hours)",
|
|
3794
|
-
"help": "Inactivity window in hours for Discord thread-bound sessions
|
|
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."
|
|
3795
3803
|
},
|
|
3796
3804
|
"threadBindings.maxAgeHours": {
|
|
3797
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.9.1
|
|
3
|
+
"version": "2026.9.1",
|
|
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
|
+
"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.9.1
|
|
22
|
+
"openclaw": ">=2026.9.1"
|
|
23
23
|
},
|
|
24
24
|
"peerDependenciesMeta": {
|
|
25
25
|
"openclaw": {
|
|
@@ -94,10 +94,11 @@
|
|
|
94
94
|
"allowInvalidConfigRecovery": true
|
|
95
95
|
},
|
|
96
96
|
"compat": {
|
|
97
|
-
"pluginApi": ">=2026.9.1
|
|
97
|
+
"pluginApi": ">=2026.9.1"
|
|
98
98
|
},
|
|
99
99
|
"build": {
|
|
100
|
-
"
|
|
100
|
+
"bundledDist": false,
|
|
101
|
+
"openclawVersion": "2026.9.1",
|
|
101
102
|
"staticAssets": [
|
|
102
103
|
{
|
|
103
104
|
"source": "./assets/embedded-app-sdk.mjs",
|
package/skills/discord/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: discord
|
|
3
3
|
description: "Discord messaging workflows through OpenClaw's message tool."
|
|
4
|
-
metadata: { "openclaw": { "emoji": "🎮", "requires": { "config": ["channels.discord
|
|
4
|
+
metadata: { "openclaw": { "emoji": "🎮", "requires": { "config": ["channels.discord"] } } }
|
|
5
5
|
allowed-tools: ["message"]
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { o as mergeDiscordAccountConfig, s as resolveDefaultDiscordAccountId, u as resolveDiscordAccountConfig } from "./accounts-CfQ-vSyf.js";
|
|
2
|
-
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
3
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
-
import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
5
|
-
//#region extensions/discord/src/account-token-inspect.ts
|
|
6
|
-
function inspectDiscordConfiguredToken(value) {
|
|
7
|
-
const normalized = normalizeSecretInputString(value);
|
|
8
|
-
if (normalized) return {
|
|
9
|
-
token: normalized.replace(/^Bot\s+/i, ""),
|
|
10
|
-
tokenSource: "config",
|
|
11
|
-
tokenStatus: "available"
|
|
12
|
-
};
|
|
13
|
-
if (hasConfiguredSecretInput(value)) return {
|
|
14
|
-
token: "",
|
|
15
|
-
tokenSource: "config",
|
|
16
|
-
tokenStatus: "configured_unavailable"
|
|
17
|
-
};
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
function inspectDiscordAccountTokenState(params) {
|
|
21
|
-
const accountToken = inspectDiscordConfiguredToken(params.accountToken);
|
|
22
|
-
if (accountToken) return {
|
|
23
|
-
...params.base,
|
|
24
|
-
...accountToken,
|
|
25
|
-
configured: true,
|
|
26
|
-
config: params.config
|
|
27
|
-
};
|
|
28
|
-
if (params.hasAccountToken) return {
|
|
29
|
-
...params.base,
|
|
30
|
-
token: "",
|
|
31
|
-
tokenSource: "none",
|
|
32
|
-
tokenStatus: "missing",
|
|
33
|
-
configured: false,
|
|
34
|
-
config: params.config
|
|
35
|
-
};
|
|
36
|
-
const channelToken = inspectDiscordConfiguredToken(params.channelToken);
|
|
37
|
-
if (channelToken) return {
|
|
38
|
-
...params.base,
|
|
39
|
-
...channelToken,
|
|
40
|
-
configured: true,
|
|
41
|
-
config: params.config
|
|
42
|
-
};
|
|
43
|
-
const fallback = params.resolveFallbackToken();
|
|
44
|
-
if (fallback.token) return {
|
|
45
|
-
...params.base,
|
|
46
|
-
token: fallback.token,
|
|
47
|
-
tokenSource: fallback.source,
|
|
48
|
-
tokenStatus: "available",
|
|
49
|
-
configured: true,
|
|
50
|
-
config: params.config
|
|
51
|
-
};
|
|
52
|
-
return {
|
|
53
|
-
...params.base,
|
|
54
|
-
token: "",
|
|
55
|
-
tokenSource: "none",
|
|
56
|
-
tokenStatus: "missing",
|
|
57
|
-
configured: false,
|
|
58
|
-
config: params.config
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region extensions/discord/src/account-inspect.ts
|
|
63
|
-
function inspectDiscordAccount(params) {
|
|
64
|
-
const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
|
|
65
|
-
const merged = mergeDiscordAccountConfig(params.cfg, accountId);
|
|
66
|
-
const enabled = params.cfg.channels?.discord?.enabled !== false && merged.enabled !== false;
|
|
67
|
-
const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
|
|
68
|
-
const hasAccountToken = Boolean(accountConfig && Object.hasOwn(accountConfig, "token"));
|
|
69
|
-
return inspectDiscordAccountTokenState({
|
|
70
|
-
base: {
|
|
71
|
-
accountId,
|
|
72
|
-
enabled,
|
|
73
|
-
name: normalizeOptionalString(merged.name)
|
|
74
|
-
},
|
|
75
|
-
config: merged,
|
|
76
|
-
accountToken: accountConfig?.token,
|
|
77
|
-
hasAccountToken,
|
|
78
|
-
channelToken: params.cfg.channels?.discord?.token,
|
|
79
|
-
resolveFallbackToken: () => {
|
|
80
|
-
const envToken = accountId === DEFAULT_ACCOUNT_ID ? normalizeSecretInputString(params.envToken ?? process.env.DISCORD_BOT_TOKEN) : void 0;
|
|
81
|
-
return {
|
|
82
|
-
token: envToken?.replace(/^Bot\s+/i, "") ?? "",
|
|
83
|
-
source: envToken ? "env" : "none"
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
//#endregion
|
|
89
|
-
export { inspectDiscordAccountTokenState as n, inspectDiscordAccount as t };
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import { y as discord_exports } from "./retry-Cv4jCU5Z.js";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
5
|
-
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
6
|
-
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
7
|
-
import { resolveFfmpegBin } from "openclaw/plugin-sdk/media-runtime";
|
|
8
|
-
import { resolvePreferredOpenClawTmpDir, tempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
9
|
-
import { controlRealtimeVoiceAgentRun, resamplePcm, shouldAutoControlRealtimeVoiceAgentText } from "openclaw/plugin-sdk/realtime-voice";
|
|
10
|
-
import { spawn } from "node:child_process";
|
|
11
|
-
import { Transform } from "node:stream";
|
|
12
|
-
import { StringDecoder } from "node:string_decoder";
|
|
13
|
-
import { Application, createDecoder, createEncoder } from "libopus-wasm";
|
|
14
|
-
//#region extensions/discord/src/voice/log-preview.ts
|
|
15
|
-
const DISCORD_VOICE_LOG_PREVIEW_CHARS = 500;
|
|
16
|
-
function formatVoiceLogPreview(text) {
|
|
17
|
-
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
18
|
-
if (oneLine.length <= DISCORD_VOICE_LOG_PREVIEW_CHARS) return oneLine;
|
|
19
|
-
return `${truncateUtf16Safe(oneLine, DISCORD_VOICE_LOG_PREVIEW_CHARS)}...`;
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region extensions/discord/src/voice/agent-control.ts
|
|
23
|
-
async function maybeControlDiscordVoiceAgentRun(params) {
|
|
24
|
-
if (!shouldAutoControlRealtimeVoiceAgentText(params.text)) return { handled: false };
|
|
25
|
-
const result = await controlRealtimeVoiceAgentRun({
|
|
26
|
-
sessionKey: params.entry.route.sessionKey,
|
|
27
|
-
text: params.text
|
|
28
|
-
});
|
|
29
|
-
if (!result.active) return {
|
|
30
|
-
handled: false,
|
|
31
|
-
result
|
|
32
|
-
};
|
|
33
|
-
return {
|
|
34
|
-
handled: true,
|
|
35
|
-
result,
|
|
36
|
-
...result.speak && !result.suppress ? { speakText: result.message } : {}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region extensions/discord/src/voice/prompt.ts
|
|
41
|
-
const DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT = [
|
|
42
|
-
"You are OpenClaw's Discord voice interface in a live voice channel.",
|
|
43
|
-
"Discord voice reply requirements:",
|
|
44
|
-
"- Return only the concise text that should be spoken aloud in the voice channel.",
|
|
45
|
-
"- Treat the transcript as speech-to-text from a live conversation; repair obvious transcription artifacts and ignore repeated partial fragments caused by voice buffering.",
|
|
46
|
-
"- If the transcript is garbled, incomplete, or missing the user's intent, ask one brief clarifying question instead of guessing.",
|
|
47
|
-
"- If the request needs deeper reasoning, current information, or tools, use the available tools before answering.",
|
|
48
|
-
"- Do not call the tts tool; Discord voice will synthesize and play the returned text.",
|
|
49
|
-
"- Do not reply with NO_REPLY unless no spoken response is appropriate.",
|
|
50
|
-
"- Keep the response brief, natural, and conversational. Prefer one to three short sentences.",
|
|
51
|
-
"- Avoid markdown tables, code fences, citations, and visual formatting unless the user explicitly asks for something that cannot be spoken naturally."
|
|
52
|
-
].join("\n");
|
|
53
|
-
function formatVoiceIngressPrompt(transcript, speakerLabel) {
|
|
54
|
-
const cleanedTranscript = transcript.trim();
|
|
55
|
-
const cleanedLabel = speakerLabel?.trim();
|
|
56
|
-
const voiceInput = cleanedLabel ? [`Voice transcript from speaker "${cleanedLabel}":`, cleanedTranscript].join("\n") : cleanedTranscript;
|
|
57
|
-
return [DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT, voiceInput].join("\n\n");
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region extensions/discord/src/voice/audio.ts
|
|
61
|
-
const SAMPLE_RATE = 48e3;
|
|
62
|
-
const CHANNELS = 2;
|
|
63
|
-
const BIT_DEPTH = 16;
|
|
64
|
-
const FFMPEG_ERROR_OUTPUT_BYTES = 8192;
|
|
65
|
-
const DISCORD_OPUS_FRAME_SIZE = 960;
|
|
66
|
-
const DISCORD_OPUS_FRAME_BYTES = DISCORD_OPUS_FRAME_SIZE * CHANNELS * (BIT_DEPTH / 8);
|
|
67
|
-
const FFMPEG_PCM_ARGUMENTS = [
|
|
68
|
-
"-analyzeduration",
|
|
69
|
-
"0",
|
|
70
|
-
"-loglevel",
|
|
71
|
-
"error",
|
|
72
|
-
"-vn",
|
|
73
|
-
"-sn",
|
|
74
|
-
"-dn",
|
|
75
|
-
"-f",
|
|
76
|
-
"s16le",
|
|
77
|
-
"-ar",
|
|
78
|
-
String(SAMPLE_RATE),
|
|
79
|
-
"-ac",
|
|
80
|
-
String(CHANNELS)
|
|
81
|
-
];
|
|
82
|
-
let warnedOpusMissing = false;
|
|
83
|
-
function buildWavBuffer(pcm) {
|
|
84
|
-
const blockAlign = CHANNELS * BIT_DEPTH / 8;
|
|
85
|
-
const byteRate = SAMPLE_RATE * blockAlign;
|
|
86
|
-
const header = Buffer.alloc(44);
|
|
87
|
-
header.write("RIFF", 0);
|
|
88
|
-
header.writeUInt32LE(36 + pcm.length, 4);
|
|
89
|
-
header.write("WAVE", 8);
|
|
90
|
-
header.write("fmt ", 12);
|
|
91
|
-
header.writeUInt32LE(16, 16);
|
|
92
|
-
header.writeUInt16LE(1, 20);
|
|
93
|
-
header.writeUInt16LE(CHANNELS, 22);
|
|
94
|
-
header.writeUInt32LE(SAMPLE_RATE, 24);
|
|
95
|
-
header.writeUInt32LE(byteRate, 28);
|
|
96
|
-
header.writeUInt16LE(blockAlign, 32);
|
|
97
|
-
header.writeUInt16LE(BIT_DEPTH, 34);
|
|
98
|
-
header.write("data", 36);
|
|
99
|
-
header.writeUInt32LE(pcm.length, 40);
|
|
100
|
-
return Buffer.concat([header, pcm]);
|
|
101
|
-
}
|
|
102
|
-
function createDiscordOpusEncodeStream() {
|
|
103
|
-
return new DiscordOpusEncodeStream();
|
|
104
|
-
}
|
|
105
|
-
function createDiscordOpusPlaybackStream(input) {
|
|
106
|
-
const inputSource = typeof input === "string" ? input : "pipe:0";
|
|
107
|
-
const ffmpeg = spawn(resolveFfmpegBin(), [
|
|
108
|
-
"-i",
|
|
109
|
-
inputSource,
|
|
110
|
-
...FFMPEG_PCM_ARGUMENTS,
|
|
111
|
-
"pipe:1"
|
|
112
|
-
], {
|
|
113
|
-
stdio: [
|
|
114
|
-
"pipe",
|
|
115
|
-
"pipe",
|
|
116
|
-
"pipe"
|
|
117
|
-
],
|
|
118
|
-
windowsHide: true
|
|
119
|
-
});
|
|
120
|
-
const opusStream = createDiscordOpusEncodeStream();
|
|
121
|
-
const stderr = Buffer.alloc(FFMPEG_ERROR_OUTPUT_BYTES);
|
|
122
|
-
let stderrBytes = 0;
|
|
123
|
-
let ffmpegClosed = false;
|
|
124
|
-
const killFfmpeg = (signal = "SIGTERM") => {
|
|
125
|
-
if (!ffmpegClosed && !ffmpeg.killed) ffmpeg.kill(signal);
|
|
126
|
-
};
|
|
127
|
-
ffmpeg.stderr.on("data", (chunk) => {
|
|
128
|
-
if (stderrBytes < FFMPEG_ERROR_OUTPUT_BYTES) stderrBytes += chunk.copy(stderr, stderrBytes, 0, FFMPEG_ERROR_OUTPUT_BYTES - stderrBytes);
|
|
129
|
-
});
|
|
130
|
-
ffmpeg.once("error", (err) => {
|
|
131
|
-
opusStream.destroy(err);
|
|
132
|
-
});
|
|
133
|
-
ffmpeg.once("close", (code, signal) => {
|
|
134
|
-
ffmpegClosed = true;
|
|
135
|
-
if (code && code !== 0) {
|
|
136
|
-
const stderrText = new StringDecoder("utf8").write(stderr.subarray(0, stderrBytes)).trim();
|
|
137
|
-
const suffix = stderrText ? `: ${stderrText}` : "";
|
|
138
|
-
opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with code ${code}${suffix}`));
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (signal) opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with signal ${signal}`));
|
|
142
|
-
});
|
|
143
|
-
for (const readable of [ffmpeg.stdout, ffmpeg.stderr]) readable.on("error", (err) => {
|
|
144
|
-
killFfmpeg("SIGKILL");
|
|
145
|
-
opusStream.destroy(err);
|
|
146
|
-
});
|
|
147
|
-
ffmpeg.stdin.on("error", (err) => {
|
|
148
|
-
if (err.code !== "EPIPE") opusStream.destroy(err);
|
|
149
|
-
});
|
|
150
|
-
ffmpeg.stdout.pipe(opusStream);
|
|
151
|
-
opusStream.once("close", () => {
|
|
152
|
-
if (!opusStream.readableEnded) killFfmpeg();
|
|
153
|
-
});
|
|
154
|
-
if (typeof input !== "string") {
|
|
155
|
-
input.on("error", (err) => {
|
|
156
|
-
ffmpeg.stdin.destroy(err);
|
|
157
|
-
opusStream.destroy(err);
|
|
158
|
-
});
|
|
159
|
-
input.pipe(ffmpeg.stdin);
|
|
160
|
-
} else ffmpeg.stdin.end();
|
|
161
|
-
return opusStream;
|
|
162
|
-
}
|
|
163
|
-
var DiscordOpusEncodeStream = class extends Transform {
|
|
164
|
-
#buffer = Buffer.alloc(0);
|
|
165
|
-
#encoder;
|
|
166
|
-
constructor() {
|
|
167
|
-
super({ readableObjectMode: true });
|
|
168
|
-
}
|
|
169
|
-
_construct(done) {
|
|
170
|
-
createEncoder({
|
|
171
|
-
application: Application.Audio,
|
|
172
|
-
channels: CHANNELS,
|
|
173
|
-
sampleRate: SAMPLE_RATE
|
|
174
|
-
}).then((encoder) => {
|
|
175
|
-
this.#encoder = encoder;
|
|
176
|
-
done();
|
|
177
|
-
}, (err) => done(err instanceof Error ? err : new Error(formatErrorMessage(err))));
|
|
178
|
-
}
|
|
179
|
-
_transform(chunk, _encoding, done) {
|
|
180
|
-
try {
|
|
181
|
-
this.#buffer = this.#buffer.length > 0 ? Buffer.concat([this.#buffer, chunk]) : Buffer.from(chunk);
|
|
182
|
-
while (this.#buffer.length >= DISCORD_OPUS_FRAME_BYTES) {
|
|
183
|
-
const frame = this.#buffer.subarray(0, DISCORD_OPUS_FRAME_BYTES);
|
|
184
|
-
this.#buffer = this.#buffer.subarray(DISCORD_OPUS_FRAME_BYTES);
|
|
185
|
-
this.#encodeFrame(frame);
|
|
186
|
-
}
|
|
187
|
-
done();
|
|
188
|
-
} catch (err) {
|
|
189
|
-
done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
_flush(done) {
|
|
193
|
-
try {
|
|
194
|
-
if (this.#buffer.length > 0) {
|
|
195
|
-
const frame = Buffer.alloc(DISCORD_OPUS_FRAME_BYTES);
|
|
196
|
-
this.#buffer.copy(frame);
|
|
197
|
-
this.#buffer = Buffer.alloc(0);
|
|
198
|
-
this.#encodeFrame(frame);
|
|
199
|
-
}
|
|
200
|
-
done();
|
|
201
|
-
} catch (err) {
|
|
202
|
-
done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
_destroy(err, done) {
|
|
206
|
-
this.#encoder?.free();
|
|
207
|
-
this.#buffer = Buffer.alloc(0);
|
|
208
|
-
done(err);
|
|
209
|
-
}
|
|
210
|
-
#encodeFrame(frame) {
|
|
211
|
-
this.push(Buffer.from(this.#encoder.encode(frame, { frameSize: DISCORD_OPUS_FRAME_SIZE })));
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
function pcmInt16ToBuffer(pcm) {
|
|
215
|
-
return Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength);
|
|
216
|
-
}
|
|
217
|
-
async function decodeOpusStream(stream, params) {
|
|
218
|
-
const chunks = [];
|
|
219
|
-
await decodeOpusStreamChunks(stream, {
|
|
220
|
-
...params,
|
|
221
|
-
onChunk: (chunk) => chunks.push(chunk)
|
|
222
|
-
});
|
|
223
|
-
return Buffer.concat(chunks);
|
|
224
|
-
}
|
|
225
|
-
async function decodeOpusStreamChunks(stream, params) {
|
|
226
|
-
let decoder;
|
|
227
|
-
try {
|
|
228
|
-
decoder = await createDecoder({
|
|
229
|
-
channels: CHANNELS,
|
|
230
|
-
sampleRate: SAMPLE_RATE
|
|
231
|
-
});
|
|
232
|
-
} catch (err) {
|
|
233
|
-
if (!warnedOpusMissing) {
|
|
234
|
-
warnedOpusMissing = true;
|
|
235
|
-
params.onWarn(`discord voice: no usable opus decoder available (libopus-wasm: ${formatErrorMessage(err)}); cannot decode voice audio`);
|
|
236
|
-
}
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
params.onVerbose("opus decoder: libopus-wasm");
|
|
240
|
-
try {
|
|
241
|
-
for await (const chunk of stream) {
|
|
242
|
-
if (!chunk || !(chunk instanceof Buffer) || chunk.length === 0) continue;
|
|
243
|
-
const decoded = decoder.decode(chunk, { maxFrameSize: DISCORD_OPUS_FRAME_SIZE });
|
|
244
|
-
if (decoded.length > 0) params.onChunk(pcmInt16ToBuffer(decoded));
|
|
245
|
-
}
|
|
246
|
-
} catch (err) {
|
|
247
|
-
params.onError?.(err);
|
|
248
|
-
if (shouldLogVerbose()) logVerbose(`discord voice: opus decode failed: ${formatErrorMessage(err)}`);
|
|
249
|
-
} finally {
|
|
250
|
-
decoder.free();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
function convertDiscordPcm48kStereoToRealtimePcm24kMono(pcm) {
|
|
254
|
-
const frameCount = Math.floor(pcm.length / 4);
|
|
255
|
-
if (frameCount === 0) return Buffer.alloc(0);
|
|
256
|
-
const mono48k = Buffer.alloc(frameCount * 2);
|
|
257
|
-
for (let frame = 0; frame < frameCount; frame += 1) {
|
|
258
|
-
const offset = frame * 4;
|
|
259
|
-
const left = pcm.readInt16LE(offset);
|
|
260
|
-
const right = pcm.readInt16LE(offset + 2);
|
|
261
|
-
mono48k.writeInt16LE(Math.round((left + right) / 2), frame * 2);
|
|
262
|
-
}
|
|
263
|
-
return resamplePcm(mono48k, SAMPLE_RATE, 24e3);
|
|
264
|
-
}
|
|
265
|
-
function convertRealtimePcm24kMonoToDiscordPcm48kStereo(pcm) {
|
|
266
|
-
const mono48k = resamplePcm(pcm, 24e3, SAMPLE_RATE);
|
|
267
|
-
const sampleCount = Math.floor(mono48k.length / 2);
|
|
268
|
-
if (sampleCount === 0) return Buffer.alloc(0);
|
|
269
|
-
const stereo = Buffer.alloc(sampleCount * 4);
|
|
270
|
-
for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex += 1) {
|
|
271
|
-
const sample = mono48k.readInt16LE(sampleIndex * 2);
|
|
272
|
-
const offset = sampleIndex * 4;
|
|
273
|
-
stereo.writeInt16LE(sample, offset);
|
|
274
|
-
stereo.writeInt16LE(sample, offset + 2);
|
|
275
|
-
}
|
|
276
|
-
return stereo;
|
|
277
|
-
}
|
|
278
|
-
function estimateDurationSeconds(pcm) {
|
|
279
|
-
const bytesPerSample = BIT_DEPTH / 8 * CHANNELS;
|
|
280
|
-
return pcm.length / (bytesPerSample * SAMPLE_RATE);
|
|
281
|
-
}
|
|
282
|
-
async function writeVoiceWavFile(pcm) {
|
|
283
|
-
const workspace = await tempWorkspace({
|
|
284
|
-
rootDir: resolvePreferredOpenClawTmpDir(),
|
|
285
|
-
prefix: "discord-voice-"
|
|
286
|
-
});
|
|
287
|
-
scheduleTempCleanup(workspace.dir);
|
|
288
|
-
const wav = buildWavBuffer(pcm);
|
|
289
|
-
return {
|
|
290
|
-
path: await workspace.write("segment.wav", wav),
|
|
291
|
-
durationSeconds: estimateDurationSeconds(pcm)
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
function scheduleTempCleanup(tempDir, delayMs = 1800 * 1e3) {
|
|
295
|
-
setTimeout(() => {
|
|
296
|
-
fs.rm(tempDir, {
|
|
297
|
-
recursive: true,
|
|
298
|
-
force: true
|
|
299
|
-
}).catch((err) => {
|
|
300
|
-
if (shouldLogVerbose()) logVerbose(`discord voice: temp cleanup failed for ${tempDir}: ${formatErrorMessage(err)}`);
|
|
301
|
-
});
|
|
302
|
-
}, delayMs).unref();
|
|
303
|
-
}
|
|
304
|
-
//#endregion
|
|
305
|
-
//#region extensions/discord/src/voice/session.ts
|
|
306
|
-
const MIN_SEGMENT_SECONDS = .35;
|
|
307
|
-
const CAPTURE_FINALIZE_GRACE_MS = 2e3;
|
|
308
|
-
const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
|
|
309
|
-
const VOICE_RECONNECT_GRACE_MS = 15e3;
|
|
310
|
-
const PLAYBACK_READY_TIMEOUT_MS = 6e4;
|
|
311
|
-
function resolveVoiceTimeoutMs(value, fallbackMs) {
|
|
312
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
|
|
313
|
-
return Math.floor(value);
|
|
314
|
-
}
|
|
315
|
-
function resolveDiscordVoiceMode(voice) {
|
|
316
|
-
const mode = voice?.mode;
|
|
317
|
-
if (mode === "stt-tts" || mode === "bidi") return mode;
|
|
318
|
-
return "agent-proxy";
|
|
319
|
-
}
|
|
320
|
-
function isDiscordRealtimeVoiceMode(mode) {
|
|
321
|
-
return mode === "agent-proxy" || mode === "bidi";
|
|
322
|
-
}
|
|
323
|
-
function logVoiceVerbose(message) {
|
|
324
|
-
logVerbose(`discord voice: ${message}`);
|
|
325
|
-
}
|
|
326
|
-
function isVoiceChannel(type) {
|
|
327
|
-
return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
|
|
328
|
-
}
|
|
329
|
-
//#endregion
|
|
330
|
-
//#region extensions/discord/src/voice/sdk-runtime.ts
|
|
331
|
-
let cachedDiscordVoiceSdk = null;
|
|
332
|
-
function loadDiscordVoiceSdk() {
|
|
333
|
-
if (cachedDiscordVoiceSdk) return cachedDiscordVoiceSdk;
|
|
334
|
-
cachedDiscordVoiceSdk = createRequire(import.meta.url)("@discordjs/voice");
|
|
335
|
-
return cachedDiscordVoiceSdk;
|
|
336
|
-
}
|
|
337
|
-
//#endregion
|
|
338
|
-
export { decodeOpusStreamChunks as _, VOICE_CONNECT_READY_TIMEOUT_MS as a, maybeControlDiscordVoiceAgentRun as b, isVoiceChannel as c, resolveVoiceTimeoutMs as d, convertDiscordPcm48kStereoToRealtimePcm24kMono as f, decodeOpusStream as g, createDiscordOpusPlaybackStream as h, PLAYBACK_READY_TIMEOUT_MS as i, logVoiceVerbose as l, createDiscordOpusEncodeStream as m, CAPTURE_FINALIZE_GRACE_MS as n, VOICE_RECONNECT_GRACE_MS as o, convertRealtimePcm24kMonoToDiscordPcm48kStereo as p, MIN_SEGMENT_SECONDS as r, isDiscordRealtimeVoiceMode as s, loadDiscordVoiceSdk as t, resolveDiscordVoiceMode as u, writeVoiceWavFile as v, formatVoiceLogPreview as x, formatVoiceIngressPrompt as y };
|
package/dist/targets-CtTKvntJ.js
DELETED