@openclaw/discord 2026.8.1-beta.2 → 2026.8.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-CqzrH14k.js → account-inspect-BDfKyuvL.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-DJTf1LtA.js → accounts-CfQ-vSyf.js} +34 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/{activities-api-DS7vpdtp.js → activities-api-Dl-TOyOX.js} +134 -175
- package/dist/activities-api.js +1 -1
- package/dist/api.js +17 -17
- package/dist/{approval-handler.runtime-B6yEV79q.js → approval-handler.runtime-q4Zqo44V.js} +29 -106
- package/dist/{audit-Db-rlntl.js → audit-DgrvFPGt.js} +5 -5
- package/dist/{channel-CnnbJSt5.js → channel-BsQUalPw.js} +72 -50
- package/dist/{channel-actions.runtime-CLKrx6tr.js → channel-actions.runtime-UMGGIfSy.js} +31 -45
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-CVLZyGYS.js +7 -0
- package/dist/{channel.setup-BFAO-V1P.js → channel.setup-rPs4dsk_.js} +5 -5
- package/dist/{outbound-session-route-DxLkrgKQ.js → components-Dk35LTf_.js} +34 -76
- package/dist/{config-schema-BgEskFAs.js → config-schema-CxPqtVI1.js} +46 -14
- package/dist/conversation-binding-route-BjvX4e35.js +43 -0
- package/dist/{directory-config-BVX7Cflc.js → directory-config-B7DY_pNG.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DGIGxpIo.js → directory-live-DuAXKkan.js} +3 -3
- package/dist/doctor-contract-api.js +2 -2
- package/dist/{doctor-BzC-TLnB.js → doctor-zQTtn6hm.js} +33 -12
- package/dist/{handle-action.guild-admin-BNVTUISF.js → handle-action.guild-admin-DZewwLr1.js} +9 -5
- package/dist/index.js +3 -4
- package/dist/ingress-identity-CzZKcPK8.js +60 -0
- package/dist/{message-handler-Unk_f10F.js → message-handler-C5By3yl5.js} +82 -6
- package/dist/{message-handler.preflight-C9zecxR9.js → message-handler.preflight-DrszWuHw.js} +44 -118
- package/dist/{message-handler.process-DWQ6UHHu.js → message-handler.process-DyFPDLCt.js} +205 -235
- package/dist/{message-utils-BSCPVgy0.js → message-text-Ca8M6TU8.js} +43 -42
- package/dist/{outbound-adapter-D9nRivT1.js → outbound-adapter-Dif8p481.js} +118 -91
- package/dist/{outbound-components-cTzwBJ60.js → outbound-components-wjv7yyAj.js} +5 -4
- package/dist/outbound-session-route-Bn4uXaoE.js +665 -0
- package/dist/owner-access-UlYi9t0M.js +107 -0
- package/dist/{pluralkit-DdiJ9KMK.js → pluralkit-9EuEN4UD.js} +1 -1
- package/dist/{probe-Bl-k5_Ku.js → probe-n6ZXxK8V.js} +1 -1
- package/dist/{probe.runtime-M9fREKvp.js → probe.runtime-CN4bdPfZ.js} +1 -1
- package/dist/{provider-DvSNb-2v.js → provider-LXiOcJrH.js} +887 -1350
- package/dist/{provider-session.runtime-BUEqD0rA.js → provider-session.runtime-DSNe7r2W.js} +3 -3
- package/dist/provider.runtime-DiInaDXO.js +2 -0
- package/dist/{realtime-session.runtime-C7wen-aF.js → realtime-session.runtime-DOViOIjY.js} +129 -134
- package/dist/{resolve-allowlist-common-D04lpEzb.js → resolve-allowlist-common-BLoYaxEG.js} +2 -2
- package/dist/{resolve-channels-Dm7jEeg6.js → resolve-channels-D2yl_2CN.js} +5 -4
- package/dist/{resolve-users-bktrCUUU.js → resolve-users-BLxfqajZ.js} +2 -2
- package/dist/{retry-CLpJcXXf.js → retry-DqHCW6PV.js} +187 -19
- package/dist/{runtime-DGsSyDTS.js → runtime-BYamRVPN.js} +89 -86
- package/dist/{runtime-DoHjckYm.js → runtime-DrxVBTtp.js} +9 -10
- package/dist/runtime-api.js +19 -25
- package/dist/{sdk-runtime-QpY8PvCh.js → sdk-runtime-6tfgYDjY.js} +57 -89
- package/dist/{secret-config-contract-B1akrlyY.js → secret-config-contract-B3i6WxV5.js} +53 -25
- package/dist/secret-contract-api.js +1 -1
- package/dist/{security-audit-jGnJF__m.js → security-audit-DKfK-iPY.js} +11 -12
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/{security-audit.runtime-CPN0xFYz.js → security-audit.runtime-sKZyKgpx.js} +1 -1
- package/dist/{send-B7Q6Oc1I.js → send-UJHiAm4C.js} +82 -19
- package/dist/{send.components-iJyFXw9L.js → send.components-CrBJpGT_.js} +22 -39
- package/dist/{send.outbound-DS5tHwfR.js → send.outbound-D7JYmfm9.js} +77 -78
- package/dist/{send.shared-BmwFjW6T.js → send.shared-DZJ1akvQ.js} +136 -121
- package/dist/{sender-identity-QtalnCYv.js → sender-identity-BJtfyise.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-BIXIX6uJ.js → shared-Dii2HTn7.js} +41 -14
- package/dist/subagent-hooks-JyGrtQIl.js +49 -0
- package/dist/subagent-hooks-api.js +1 -6
- package/dist/{system-events-CTqDf6_s.js → system-events-BEmcj4xJ.js} +2 -2
- package/dist/{target-resolver-maOKSqO0.js → target-resolver-V-IYae6s.js} +3 -3
- package/dist/targets-CQp53cGj.js +3 -0
- package/dist/{thread-bindings-3L8p82GV.js → thread-bindings-DvYP79fy.js} +28 -26
- package/dist/{thread-bindings.manager-DCIH6WDC.js → thread-bindings.manager-Clm77DBM.js} +11 -14
- package/dist/{thread-bindings.session-updates-bJ2KQFY6.js → thread-bindings.session-updates-CJb-BpPL.js} +1 -1
- package/dist/{thread-bindings.state-aeV8HNgV.js → thread-bindings.state-D8OMdk4O.js} +1 -1
- package/dist/threading-CXuu_7o9.js +478 -0
- package/dist/transcripts-source-BLEMH_yi.js +270 -0
- package/dist/transcripts-source-api.js +7 -2
- package/dist/{typing-CS-nNVoe.js → typing-B9snnwMe.js} +1 -1
- package/dist/{voice-runtime-BEdqNcST.js → voice-runtime-DY6_o73o.js} +250 -150
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/README.md +19 -19
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist/v1.js +7 -3
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist/v7.js +5 -2
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist-node/v1.js +7 -3
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist-node/v7.js +5 -2
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/package.json +4 -3
- package/node_modules/@discordjs/voice/node_modules/@types/node/README.md +1 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@discordjs/voice/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@discordjs/voice/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@discordjs/voice/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@discordjs/voice/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@discordjs/voice/node_modules/@types/node/package.json +2 -2
- package/node_modules/@discordjs/voice/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@discordjs/voice/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@discordjs/voice/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@discordjs/voice/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/v8.d.ts +20 -23
- package/node_modules/discord-api-types/CHANGELOG.md +8 -0
- package/node_modules/discord-api-types/package.json +4 -4
- package/node_modules/discord-api-types/payloads/v10/channel.d.ts +2 -2
- package/node_modules/discord-api-types/payloads/v10/channel.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/gateway.d.ts +4 -0
- package/node_modules/discord-api-types/payloads/v10/gateway.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/gateway.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/message.d.ts +4 -1
- package/node_modules/discord-api-types/payloads/v10/message.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/message.js +1 -0
- package/node_modules/discord-api-types/payloads/v10/message.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/channel.d.ts +2 -2
- package/node_modules/discord-api-types/payloads/v9/channel.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/gateway.d.ts +4 -0
- package/node_modules/discord-api-types/payloads/v9/gateway.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/gateway.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/message.d.ts +4 -1
- package/node_modules/discord-api-types/payloads/v9/message.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/message.js +1 -0
- package/node_modules/discord-api-types/payloads/v9/message.js.map +1 -1
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/node_modules/undici/docs/docs/api/Client.md +21 -8
- package/node_modules/undici/lib/api/readable.js +33 -43
- package/node_modules/undici/lib/core/connect.js +16 -2
- package/node_modules/undici/lib/core/symbols.js +1 -0
- package/node_modules/undici/lib/dispatcher/client-h1.js +3 -3
- package/node_modules/undici/lib/dispatcher/client-h2.js +179 -10
- package/node_modules/undici/lib/dispatcher/client.js +74 -29
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +28 -6
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +15 -1
- package/node_modules/undici/lib/handler/retry-handler.js +7 -2
- package/node_modules/undici/lib/interceptor/cache.js +5 -2
- package/node_modules/undici/lib/interceptor/deduplicate.js +1 -1
- package/node_modules/undici/lib/mock/mock-utils.js +213 -24
- package/node_modules/undici/lib/util/cache.js +2 -4
- package/node_modules/undici/lib/web/websocket/websocket.js +22 -0
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/client.d.ts +40 -0
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +24 -10
- package/package.json +8 -10
- package/skills/discord/SKILL.md +1 -1
- package/dist/approval-message-safety-AcIxvrf3.js +0 -140
- package/dist/audit-core-xwjIczO0.js +0 -105
- package/dist/channel-actions-5s_hjYKd.js +0 -208
- package/dist/channel-api-CAJ0wMoV.js +0 -21
- package/dist/inbound-event-delivery-De2qxTrP.js +0 -39
- package/dist/provider.runtime-C9PnJZbZ.js +0 -2
- package/dist/runtime-api.actions.js +0 -3
- package/dist/runtime-api.lookup.js +0 -7
- package/dist/runtime-api.monitor-CHxrFPnW.js +0 -5
- package/dist/runtime-api.monitor.js +0 -8
- package/dist/runtime-api.send.js +0 -7
- package/dist/runtime-api.threads.js +0 -5
- package/dist/send.reactions-BAn0iiVQ.js +0 -78
- package/dist/send.receipt-IPI1p-SP.js +0 -66
- package/dist/subagent-hooks-CTt5KCJr.js +0 -120
- package/dist/subagent-progress-DhaE_h8a.js +0 -109
- package/dist/targets-yUFTHoAx.js +0 -3
- package/dist/transcripts-source-CfFMexGt.js +0 -123
- package/node_modules/p-map/index.d.ts +0 -155
- package/node_modules/p-map/index.js +0 -285
- package/node_modules/p-map/license +0 -9
- package/node_modules/p-map/package.json +0 -57
- package/node_modules/p-map/readme.md +0 -190
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
- package/dist/{allow-list-DnxIlPP2.js → allow-list-BDMimASD.js} +1 -1
- package/dist/{doctor-contract-DLa-BTiU.js → doctor-contract-DsWvKIXF.js} +1 -1
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import {
|
|
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";
|
|
2
2
|
import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
|
|
3
|
-
import { a as normalizeDiscordSlug, h as resolveDiscordOwnerAccess, x as formatDiscordUserTag } from "./allow-list-
|
|
4
|
-
import { a as formatMention } from "./send.outbound-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
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";
|
|
9
8
|
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
10
9
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
11
10
|
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
11
|
+
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
12
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
12
13
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
13
14
|
import { escapeRegExp, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
14
15
|
import { stripInlineDirectiveTagsForDisplay } from "openclaw/plugin-sdk/text-chunking";
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
16
|
+
import { unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
|
|
17
|
+
import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
17
18
|
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
18
19
|
import { Readable } from "node:stream";
|
|
19
20
|
import { OpusError } from "libopus-wasm";
|
|
@@ -82,12 +83,13 @@ async function runDiscordVoiceAgentTurn(params) {
|
|
|
82
83
|
});
|
|
83
84
|
if (!context) return null;
|
|
84
85
|
const voiceModel = normalizeOptionalString(params.discordConfig.voice?.model);
|
|
85
|
-
const payloads = (await
|
|
86
|
+
const payloads = (await getDiscordRuntime().agent.runCommandFromIngress({
|
|
86
87
|
message: params.message,
|
|
87
88
|
sessionKey: params.entry.route.sessionKey,
|
|
88
89
|
agentId: params.entry.route.agentId,
|
|
89
90
|
messageChannel: "discord",
|
|
90
91
|
messageProvider: DISCORD_VOICE_MESSAGE_PROVIDER,
|
|
92
|
+
accountId: params.accountId,
|
|
91
93
|
extraSystemPrompt: context.extraSystemPrompt,
|
|
92
94
|
senderIsOwner: context.senderIsOwner,
|
|
93
95
|
allowModelOverride: Boolean(voiceModel),
|
|
@@ -193,7 +195,7 @@ function countDiscordVoiceHumanParticipants(params) {
|
|
|
193
195
|
const userId = state.user_id?.trim();
|
|
194
196
|
if (!userId || userId === params.botUserId || knownUserIds.has(userId)) continue;
|
|
195
197
|
knownUserIds.add(userId);
|
|
196
|
-
if (state.member?.user
|
|
198
|
+
if (state.member?.user && state.member.user.bot !== true) count += 1;
|
|
197
199
|
}
|
|
198
200
|
for (const rawUserId of params.additionalUserIds ?? []) {
|
|
199
201
|
const userId = rawUserId.trim();
|
|
@@ -654,7 +656,8 @@ function normalizeVoiceChannelResidencies(entries) {
|
|
|
654
656
|
const channelId = entry.channelId?.trim();
|
|
655
657
|
if (guildId && channelId) normalized.push({
|
|
656
658
|
guildId,
|
|
657
|
-
channelId
|
|
659
|
+
channelId,
|
|
660
|
+
...entry.whenOccupied === true ? { whenOccupied: true } : {}
|
|
658
661
|
});
|
|
659
662
|
}
|
|
660
663
|
return normalized;
|
|
@@ -1017,6 +1020,7 @@ var DiscordVoiceFollowing = class {
|
|
|
1017
1020
|
}
|
|
1018
1021
|
resolveVoiceResidencyTarget(guildId) {
|
|
1019
1022
|
const autoJoinTarget = this.params.autoJoinChannels.toReversed().find((entry) => entry.guildId === guildId);
|
|
1023
|
+
if (autoJoinTarget?.whenOccupied) return null;
|
|
1020
1024
|
if (autoJoinTarget && this.params.isAllowedVoiceChannel(autoJoinTarget)) return autoJoinTarget;
|
|
1021
1025
|
if (this.params.allowedChannels === null) return null;
|
|
1022
1026
|
const guildAllowed = this.params.allowedChannels.filter((entry) => entry.guildId === guildId);
|
|
@@ -1142,6 +1146,7 @@ async function synthesizeVoiceReplyAudio(params) {
|
|
|
1142
1146
|
release: streamResult.release,
|
|
1143
1147
|
speakText
|
|
1144
1148
|
};
|
|
1149
|
+
const streamFailure = streamResult && !streamResult.success ? streamResult.attempts?.findLast((attempt) => attempt.outcome === "failed") : void 0;
|
|
1145
1150
|
const result = await runtime.tts.textToSpeech({
|
|
1146
1151
|
text: speakText,
|
|
1147
1152
|
cfg: prepared.cfg,
|
|
@@ -1156,7 +1161,11 @@ async function synthesizeVoiceReplyAudio(params) {
|
|
|
1156
1161
|
status: "ok",
|
|
1157
1162
|
mode: "file",
|
|
1158
1163
|
audioPath: result.audioPath,
|
|
1159
|
-
speakText
|
|
1164
|
+
speakText,
|
|
1165
|
+
...streamFailure ? { streamFailure: {
|
|
1166
|
+
provider: streamFailure.provider,
|
|
1167
|
+
reasonCode: streamFailure.reasonCode
|
|
1168
|
+
} } : {}
|
|
1160
1169
|
};
|
|
1161
1170
|
}
|
|
1162
1171
|
//#endregion
|
|
@@ -1190,6 +1199,7 @@ async function processDiscordVoiceSegment(params) {
|
|
|
1190
1199
|
logVoiceVerbose(`transcription ok (${transcript.length} chars): guild ${entry.guildId} channel ${entry.channelId}`);
|
|
1191
1200
|
logVoiceVerbose(`transcript from ${ingress.speakerLabel} (${userId}) in guild ${entry.guildId} channel ${entry.channelId}: ${formatVoiceLogPreview(transcript)}`);
|
|
1192
1201
|
if (params.transcripts) {
|
|
1202
|
+
if (entry.sessionLifecycle.status === "stopped" || entry.transcripts !== params.transcripts) return;
|
|
1193
1203
|
await params.transcripts.onUtterance({
|
|
1194
1204
|
sessionId: params.transcripts.sessionId,
|
|
1195
1205
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1219,10 +1229,12 @@ async function processDiscordVoiceSegment(params) {
|
|
|
1219
1229
|
logger$4.info(`discord voice: active-run control handled mode=${control.result.mode} ok=${control.result.ok} active=${control.result.active} reason=${control.result.reason ?? "none"} session=${entry.route.sessionKey}`);
|
|
1220
1230
|
replyText = control.speakText ?? "";
|
|
1221
1231
|
} else {
|
|
1232
|
+
const prompt = formatVoiceIngressPrompt(transcript, ingress.speakerLabel);
|
|
1222
1233
|
const turn = await runDiscordVoiceAgentTurn({
|
|
1223
1234
|
entry,
|
|
1235
|
+
accountId: params.accountId,
|
|
1224
1236
|
userId,
|
|
1225
|
-
message:
|
|
1237
|
+
message: prompt,
|
|
1226
1238
|
cfg: params.cfg,
|
|
1227
1239
|
discordConfig: params.discordConfig,
|
|
1228
1240
|
runtime: params.runtime,
|
|
@@ -1256,26 +1268,38 @@ async function processDiscordVoiceSegment(params) {
|
|
|
1256
1268
|
logger$4.warn(`discord voice: TTS failed: ${voiceReplyAudio.error ?? "unknown error"}`);
|
|
1257
1269
|
return;
|
|
1258
1270
|
}
|
|
1271
|
+
const streamFailure = voiceReplyAudio.mode === "file" ? voiceReplyAudio.streamFailure : void 0;
|
|
1272
|
+
if (streamFailure && !entry.ttsStreamFallbackWarned) {
|
|
1273
|
+
entry.ttsStreamFallbackWarned = true;
|
|
1274
|
+
logger$4.warn(`discord voice: streaming TTS failed provider=${streamFailure.provider} reasonCode=${streamFailure.reasonCode}; using file fallback`);
|
|
1275
|
+
}
|
|
1259
1276
|
logVoiceVerbose(`tts ok (${voiceReplyAudio.speakText.length} chars): guild ${entry.guildId} channel ${entry.channelId}`);
|
|
1277
|
+
const releaseAudio = voiceReplyAudio.mode === "stream" ? voiceReplyAudio.release : () => unlinkIfExists(voiceReplyAudio.audioPath);
|
|
1278
|
+
if (entry.sessionLifecycle.status === "stopped") {
|
|
1279
|
+
await releaseAudio?.();
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1260
1282
|
params.enqueuePlayback(entry, async () => {
|
|
1261
1283
|
const voiceSdk = loadDiscordVoiceSdk();
|
|
1262
|
-
const
|
|
1284
|
+
const playbackLifecycle = new AbortController();
|
|
1285
|
+
let playbackStarted = false;
|
|
1286
|
+
const cancelStoppedPlayback = () => (!playbackStarted || entry.sessionLifecycle.status === "stopped") && playbackLifecycle.abort();
|
|
1263
1287
|
try {
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
}
|
|
1274
|
-
await voiceSdk.entersState(entry.player, voiceSdk.AudioPlayerStatus.Playing, PLAYBACK_READY_TIMEOUT_MS).catch(() => void 0);
|
|
1275
|
-
await voiceSdk.entersState(entry.player, voiceSdk.AudioPlayerStatus.Idle, SPEAKING_READY_TIMEOUT_MS).catch(() => void 0);
|
|
1288
|
+
if (entry.sessionLifecycle.status === "stopped") return;
|
|
1289
|
+
entry.player.on(voiceSdk.AudioPlayerStatus.Idle, cancelStoppedPlayback);
|
|
1290
|
+
const input = voiceReplyAudio.mode === "stream" ? Readable.fromWeb(voiceReplyAudio.audioStream) : voiceReplyAudio.audioPath;
|
|
1291
|
+
logVoiceVerbose(`playback start: guild ${entry.guildId} channel ${entry.channelId} ${voiceReplyAudio.mode}`);
|
|
1292
|
+
const resource = voiceSdk.createAudioResource(createDiscordOpusPlaybackStream(input), { inputType: voiceSdk.StreamType.Opus });
|
|
1293
|
+
entry.player.play(resource);
|
|
1294
|
+
await voiceSdk.entersState(entry.player, voiceSdk.AudioPlayerStatus.Playing, AbortSignal.any([AbortSignal.timeout(PLAYBACK_READY_TIMEOUT_MS), playbackLifecycle.signal]));
|
|
1295
|
+
playbackStarted = true;
|
|
1296
|
+
await voiceSdk.entersState(entry.player, voiceSdk.AudioPlayerStatus.Idle, playbackLifecycle.signal);
|
|
1276
1297
|
logVoiceVerbose(`playback done: guild ${entry.guildId} channel ${entry.channelId}`);
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
if (entry.sessionLifecycle.status !== "stopped") throw error;
|
|
1277
1300
|
} finally {
|
|
1278
|
-
|
|
1301
|
+
entry.player.off(voiceSdk.AudioPlayerStatus.Idle, cancelStoppedPlayback);
|
|
1302
|
+
await releaseAudio?.();
|
|
1279
1303
|
}
|
|
1280
1304
|
});
|
|
1281
1305
|
}
|
|
@@ -1320,6 +1344,7 @@ var DiscordVoiceReceive = class {
|
|
|
1320
1344
|
}
|
|
1321
1345
|
logVoiceVerbose(`capture start: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
|
|
1322
1346
|
const voiceSdk = loadDiscordVoiceSdk();
|
|
1347
|
+
const transcripts = entry.transcripts;
|
|
1323
1348
|
const voiceMode = resolveDiscordVoiceMode(this.params.discordConfig.voice);
|
|
1324
1349
|
const realtime = entry.realtimeLifecycle.status === "active" && isDiscordRealtimeVoiceMode(voiceMode) ? entry.realtimeLifecycle.instance : void 0;
|
|
1325
1350
|
if (entry.player.state.status === voiceSdk.AudioPlayerStatus.Playing && !realtime) {
|
|
@@ -1397,6 +1422,7 @@ var DiscordVoiceReceive = class {
|
|
|
1397
1422
|
logVoiceVerbose(`capture ready (${durationSeconds.toFixed(2)}s): guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
|
|
1398
1423
|
entry.processingQueue = entry.processingQueue.then(async () => {
|
|
1399
1424
|
if (!this.params.isEntryCurrent(entry)) return;
|
|
1425
|
+
if (entry.transcripts !== transcripts) return;
|
|
1400
1426
|
await this.processSegment({
|
|
1401
1427
|
entry,
|
|
1402
1428
|
wavPath,
|
|
@@ -1415,6 +1441,7 @@ var DiscordVoiceReceive = class {
|
|
|
1415
1441
|
async processSegment(params) {
|
|
1416
1442
|
await processDiscordVoiceSegment({
|
|
1417
1443
|
...params,
|
|
1444
|
+
accountId: this.params.accountId,
|
|
1418
1445
|
cfg: this.params.cfg,
|
|
1419
1446
|
discordConfig: this.params.discordConfig,
|
|
1420
1447
|
admissionAllowFrom: this.params.admissionAllowFrom,
|
|
@@ -1515,6 +1542,7 @@ var DiscordVoiceReceive = class {
|
|
|
1515
1542
|
logger$3.info(`discord voice: agent turn start guild=${entry.guildId} channel=${entry.channelId} voiceSession=${entry.voiceSessionKey} supervisorSession=${entry.route.sessionKey} agent=${entry.route.agentId} user=${userId} speaker=${context.speakerLabel} owner=${context.senderIsOwner} model=${this.params.discordConfig.voice?.model ?? "route-default"} message=${formatVoiceLogPreview(message)}`);
|
|
1516
1543
|
const turn = await runDiscordVoiceAgentTurn({
|
|
1517
1544
|
entry,
|
|
1545
|
+
accountId: this.params.accountId,
|
|
1518
1546
|
userId,
|
|
1519
1547
|
message,
|
|
1520
1548
|
cfg: this.params.cfg,
|
|
@@ -1574,16 +1602,31 @@ var DiscordVoiceReceive = class {
|
|
|
1574
1602
|
const result = await this.params.join({
|
|
1575
1603
|
guildId: entry.guildId,
|
|
1576
1604
|
channelId: entry.channelId
|
|
1577
|
-
}, {
|
|
1605
|
+
}, {
|
|
1606
|
+
preserveFollowState,
|
|
1607
|
+
autoJoinWhenOccupied: entry.autoJoinWhenOccupied
|
|
1608
|
+
});
|
|
1578
1609
|
if (!result.ok) logger$3.warn(`discord voice: rejoin after decrypt failures failed: ${result.message}`);
|
|
1579
1610
|
}
|
|
1580
1611
|
};
|
|
1581
1612
|
//#endregion
|
|
1582
1613
|
//#region extensions/discord/src/voice/voice-session.ts
|
|
1583
1614
|
const logger$2 = createSubsystemLogger("discord/voice");
|
|
1615
|
+
const REALTIME_PLAYBACK_MAX_MISSED_FRAMES = 100;
|
|
1584
1616
|
function isVoiceSessionStopped(entry) {
|
|
1585
1617
|
return entry.sessionLifecycle.status === "stopped";
|
|
1586
1618
|
}
|
|
1619
|
+
function retireTranscripts(entry) {
|
|
1620
|
+
const transcripts = entry.transcripts;
|
|
1621
|
+
entry.transcripts = void 0;
|
|
1622
|
+
try {
|
|
1623
|
+
Promise.resolve(transcripts?.onStop?.()).catch((error) => {
|
|
1624
|
+
logger$2.warn(`discord voice: transcripts retirement failed: ${formatErrorMessage(error)}`);
|
|
1625
|
+
});
|
|
1626
|
+
} catch (error) {
|
|
1627
|
+
logger$2.warn(`discord voice: transcripts retirement failed: ${formatErrorMessage(error)}`);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1587
1630
|
function isVoiceConnectionDestroyed(connection, voiceSdk) {
|
|
1588
1631
|
return connection.state.status === voiceSdk.VoiceConnectionStatus.Destroyed;
|
|
1589
1632
|
}
|
|
@@ -1660,10 +1703,20 @@ var DiscordVoiceSessions = class {
|
|
|
1660
1703
|
const { guildId, channelId } = params;
|
|
1661
1704
|
const voiceConfig = this.params.discordConfig.voice;
|
|
1662
1705
|
const voiceMode = resolveDiscordVoiceMode(voiceConfig);
|
|
1706
|
+
const cancelledJoinResult = () => ({
|
|
1707
|
+
ok: false,
|
|
1708
|
+
message: "Discord voice join was cancelled.",
|
|
1709
|
+
guildId,
|
|
1710
|
+
channelId
|
|
1711
|
+
});
|
|
1663
1712
|
const existing = this.params.sessions.get(guildId);
|
|
1664
1713
|
if (existing && existing.channelId === channelId) {
|
|
1714
|
+
existing.autoJoinWhenOccupied = options?.autoJoinWhenOccupied === true;
|
|
1665
1715
|
if (authority) existing.generation = authority.generation;
|
|
1666
|
-
if (options?.transcripts)
|
|
1716
|
+
if (options?.transcripts) {
|
|
1717
|
+
retireTranscripts(existing);
|
|
1718
|
+
existing.transcripts = options.transcripts;
|
|
1719
|
+
}
|
|
1667
1720
|
if (!options?.transcripts && isDiscordRealtimeVoiceMode(voiceMode) && existing.realtimeLifecycle.status !== "active" && existing.realtimeLifecycle.status !== "starting") {
|
|
1668
1721
|
const realtimeResult = await this.attachRealtimeSession(existing, voiceMode, {
|
|
1669
1722
|
requireLiveEntry: true,
|
|
@@ -1688,14 +1741,20 @@ var DiscordVoiceSessions = class {
|
|
|
1688
1741
|
logVoiceVerbose(`join: replacing existing session for guild ${guildId}`);
|
|
1689
1742
|
await this.leave({ guildId }, { preserveFollowState: options?.preserveFollowState });
|
|
1690
1743
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1744
|
+
let channelInfo;
|
|
1745
|
+
try {
|
|
1746
|
+
channelInfo = await this.params.client.fetchChannel(channelId);
|
|
1747
|
+
} catch (err) {
|
|
1748
|
+
if (authority && !authority.isCurrent()) return cancelledJoinResult();
|
|
1749
|
+
return {
|
|
1750
|
+
ok: false,
|
|
1751
|
+
message: `Failed to resolve Discord channel ${channelId}: ${formatErrorMessage(err)}`,
|
|
1752
|
+
guildId,
|
|
1753
|
+
channelId
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
if (authority && !authority.isCurrent()) return cancelledJoinResult();
|
|
1757
|
+
if (!isVoiceChannel(channelInfo.type)) return {
|
|
1699
1758
|
ok: false,
|
|
1700
1759
|
message: `Channel ${channelId} is not a voice channel.`
|
|
1701
1760
|
};
|
|
@@ -1717,10 +1776,7 @@ var DiscordVoiceSessions = class {
|
|
|
1717
1776
|
logVoiceVerbose(`join: DAVE settings encryption=${daveEncryption === false ? "off" : "on"} tolerance=${decryptionFailureTolerance ?? "default"} connectTimeout=${connectReadyTimeoutMs}ms reconnectGrace=${reconnectGraceMs}ms`);
|
|
1718
1777
|
const voiceSdk = loadDiscordVoiceSdk();
|
|
1719
1778
|
const existingEntry = this.params.sessions.get(guildId);
|
|
1720
|
-
if (existingEntry)
|
|
1721
|
-
existingEntry.stop();
|
|
1722
|
-
this.params.sessions.delete(guildId);
|
|
1723
|
-
}
|
|
1779
|
+
if (existingEntry) existingEntry.stop();
|
|
1724
1780
|
const voiceConnectionGroup = resolveVoiceConnectionGroup(this.params.accountId);
|
|
1725
1781
|
const staleConnection = voiceSdk.getVoiceConnection(guildId, voiceConnectionGroup);
|
|
1726
1782
|
if (staleConnection) destroyVoiceConnectionSafely({
|
|
@@ -1774,12 +1830,7 @@ var DiscordVoiceSessions = class {
|
|
|
1774
1830
|
voiceSdk,
|
|
1775
1831
|
reason: `cancelled join guild ${guildId} channel ${channelId}`
|
|
1776
1832
|
});
|
|
1777
|
-
return
|
|
1778
|
-
ok: false,
|
|
1779
|
-
message: "Discord voice join was cancelled.",
|
|
1780
|
-
guildId,
|
|
1781
|
-
channelId
|
|
1782
|
-
};
|
|
1833
|
+
return cancelledJoinResult();
|
|
1783
1834
|
}
|
|
1784
1835
|
if (this.params.destroyed()) {
|
|
1785
1836
|
destroyVoiceConnectionSafely({
|
|
@@ -1820,24 +1871,23 @@ var DiscordVoiceSessions = class {
|
|
|
1820
1871
|
}
|
|
1821
1872
|
const { route, voiceRoute, agentSessionMode, agentSessionTarget } = routeInfo;
|
|
1822
1873
|
logger$2.info(`discord voice: joining guild=${guildId} channel=${channelId} mode=${voiceMode} agent=${route.agentId} voiceSession=${voiceRoute.sessionKey} supervisorSession=${route.sessionKey} agentSessionMode=${agentSessionMode}${agentSessionTarget ? ` agentSessionTarget=${agentSessionTarget}` : ""} voiceModel=${voiceConfig?.model ?? "route-default"} realtimeProvider=${voiceConfig?.realtime?.provider ?? "auto"} realtimeModel=${voiceConfig?.realtime?.model ?? "provider-default"} realtimeVoice=${voiceConfig?.realtime?.speakerVoice ?? voiceConfig?.realtime?.speakerVoiceId ?? "provider-default"}`);
|
|
1823
|
-
const player = voiceSdk.createAudioPlayer();
|
|
1874
|
+
const player = isDiscordRealtimeVoiceMode(voiceMode) ? voiceSdk.createAudioPlayer({ behaviors: { maxMissedFrames: REALTIME_PLAYBACK_MAX_MISSED_FRAMES } }) : voiceSdk.createAudioPlayer();
|
|
1824
1875
|
connection.subscribe(player);
|
|
1825
|
-
const
|
|
1826
|
-
if (this.params.sessions.get(guildId)?.connection === connection) this.params.sessions.delete(guildId);
|
|
1827
|
-
};
|
|
1828
|
-
const stopEntry = (entry, optionsLocal) => {
|
|
1876
|
+
const stopEntry = (optionsLocal) => {
|
|
1829
1877
|
if (entry.sessionLifecycle.status === "stopped") return;
|
|
1830
1878
|
entry.sessionLifecycle = {
|
|
1831
1879
|
status: "stopped",
|
|
1832
1880
|
reason: optionsLocal.reason
|
|
1833
1881
|
};
|
|
1882
|
+
retireTranscripts(entry);
|
|
1883
|
+
if (this.params.sessions.get(guildId) === entry) this.params.sessions.delete(guildId);
|
|
1834
1884
|
this.params.membership.deactivate(entry);
|
|
1835
|
-
|
|
1836
|
-
|
|
1885
|
+
connection.receiver.speaking.off("start", speakingHandler);
|
|
1886
|
+
connection.receiver.speaking.off("end", speakingEndHandler);
|
|
1837
1887
|
stopVoiceCaptureState(entry.capture);
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1888
|
+
connection.off(voiceSdk.VoiceConnectionStatus.Disconnected, disconnectedHandler);
|
|
1889
|
+
connection.off(voiceSdk.VoiceConnectionStatus.Destroyed, destroyedHandler);
|
|
1890
|
+
player.off("error", playerErrorHandler);
|
|
1841
1891
|
const realtimeLifecycle = entry.realtimeLifecycle;
|
|
1842
1892
|
if (realtimeLifecycle.status === "starting" || realtimeLifecycle.status === "active") realtimeLifecycle.instance.close();
|
|
1843
1893
|
entry.realtimeLifecycle = {
|
|
@@ -1845,7 +1895,7 @@ var DiscordVoiceSessions = class {
|
|
|
1845
1895
|
generation: realtimeLifecycle.generation,
|
|
1846
1896
|
reason: optionsLocal.reason
|
|
1847
1897
|
};
|
|
1848
|
-
player.stop();
|
|
1898
|
+
player.stop(true);
|
|
1849
1899
|
if (optionsLocal.destroyConnection) destroyVoiceConnectionSafely({
|
|
1850
1900
|
connection,
|
|
1851
1901
|
voiceSdk,
|
|
@@ -1855,6 +1905,7 @@ var DiscordVoiceSessions = class {
|
|
|
1855
1905
|
};
|
|
1856
1906
|
const entry = {
|
|
1857
1907
|
generation: authority?.generation ?? 0,
|
|
1908
|
+
autoJoinWhenOccupied: options?.autoJoinWhenOccupied === true,
|
|
1858
1909
|
sessionLifecycle: { status: "active" },
|
|
1859
1910
|
guildId,
|
|
1860
1911
|
guildName: channelInfo && "guild" in channelInfo && channelInfo.guild && typeof channelInfo.guild.name === "string" ? channelInfo.guild.name : void 0,
|
|
@@ -1867,6 +1918,7 @@ var DiscordVoiceSessions = class {
|
|
|
1867
1918
|
player,
|
|
1868
1919
|
playbackQueue: Promise.resolve(),
|
|
1869
1920
|
processingQueue: Promise.resolve(),
|
|
1921
|
+
ttsStreamFallbackWarned: false,
|
|
1870
1922
|
capture: createVoiceCaptureState(),
|
|
1871
1923
|
transcripts: options?.transcripts,
|
|
1872
1924
|
receiveRecovery: createVoiceReceiveRecoveryState(),
|
|
@@ -1875,41 +1927,12 @@ var DiscordVoiceSessions = class {
|
|
|
1875
1927
|
generation: 0
|
|
1876
1928
|
},
|
|
1877
1929
|
stop(reason) {
|
|
1878
|
-
|
|
1879
|
-
stopEntry(entry, {
|
|
1930
|
+
stopEntry({
|
|
1880
1931
|
destroyConnection: true,
|
|
1881
1932
|
reason: reason ?? `stop guild ${guildId} channel ${channelId}`
|
|
1882
1933
|
});
|
|
1883
1934
|
}
|
|
1884
1935
|
};
|
|
1885
|
-
if (!options?.transcripts && isDiscordRealtimeVoiceMode(voiceMode)) {
|
|
1886
|
-
const realtimeResult = await this.attachRealtimeSession(entry, voiceMode, { isCurrent: authority?.isCurrent });
|
|
1887
|
-
if (!realtimeResult.ok) {
|
|
1888
|
-
destroyVoiceConnectionSafely({
|
|
1889
|
-
connection,
|
|
1890
|
-
voiceSdk,
|
|
1891
|
-
reason: `realtime setup failed guild ${guildId} channel ${channelId}`
|
|
1892
|
-
});
|
|
1893
|
-
return {
|
|
1894
|
-
ok: false,
|
|
1895
|
-
message: realtimeResult.message,
|
|
1896
|
-
guildId,
|
|
1897
|
-
channelId
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
if (this.params.destroyed() || authority && !authority.isCurrent()) {
|
|
1902
|
-
stopEntry(entry, {
|
|
1903
|
-
destroyConnection: true,
|
|
1904
|
-
reason: `${this.params.destroyed() ? "manager stopped" : "join cancelled"} during setup guild ${guildId} channel ${channelId}`
|
|
1905
|
-
});
|
|
1906
|
-
return {
|
|
1907
|
-
ok: false,
|
|
1908
|
-
message: this.params.destroyed() ? "Discord voice manager is stopped." : "Discord voice join was cancelled.",
|
|
1909
|
-
guildId,
|
|
1910
|
-
channelId
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
1936
|
const speakingHandler = (userId) => {
|
|
1914
1937
|
this.params.receive.handleSpeakingStart(entry, userId).catch((err) => {
|
|
1915
1938
|
logger$2.warn(`discord voice: capture failed: ${formatErrorMessage(err)}`);
|
|
@@ -1926,8 +1949,7 @@ var DiscordVoiceSessions = class {
|
|
|
1926
1949
|
logVoiceVerbose(`disconnected: recovery started guild ${guildId} channel ${channelId}`);
|
|
1927
1950
|
} catch (err) {
|
|
1928
1951
|
logger$2.warn(`discord voice: disconnect recovery failed: guild ${guildId} channel ${channelId} timeout=${reconnectGraceMs}ms error=${formatErrorMessage(err)}; destroying connection`);
|
|
1929
|
-
|
|
1930
|
-
stopEntry(entry, {
|
|
1952
|
+
stopEntry({
|
|
1931
1953
|
destroyConnection: true,
|
|
1932
1954
|
reason: `disconnect recovery failed guild ${guildId} channel ${channelId}`
|
|
1933
1955
|
});
|
|
@@ -1935,8 +1957,7 @@ var DiscordVoiceSessions = class {
|
|
|
1935
1957
|
})();
|
|
1936
1958
|
};
|
|
1937
1959
|
const destroyedHandler = () => {
|
|
1938
|
-
|
|
1939
|
-
stopEntry(entry, {
|
|
1960
|
+
stopEntry({
|
|
1940
1961
|
destroyConnection: false,
|
|
1941
1962
|
reason: `destroyed guild ${guildId} channel ${channelId}`
|
|
1942
1963
|
});
|
|
@@ -1944,12 +1965,33 @@ var DiscordVoiceSessions = class {
|
|
|
1944
1965
|
const playerErrorHandler = (err) => {
|
|
1945
1966
|
logger$2.warn(`discord voice: playback error: ${formatErrorMessage(err)}`);
|
|
1946
1967
|
};
|
|
1947
|
-
this.params.receive.enableDaveReceivePassthrough(entry, "post-join warmup", 30);
|
|
1948
|
-
connection.receiver.speaking.on("start", speakingHandler);
|
|
1949
|
-
connection.receiver.speaking.on("end", speakingEndHandler);
|
|
1950
1968
|
connection.on(voiceSdk.VoiceConnectionStatus.Disconnected, disconnectedHandler);
|
|
1951
1969
|
connection.on(voiceSdk.VoiceConnectionStatus.Destroyed, destroyedHandler);
|
|
1952
1970
|
player.on("error", playerErrorHandler);
|
|
1971
|
+
if (!options?.transcripts && isDiscordRealtimeVoiceMode(voiceMode)) {
|
|
1972
|
+
const realtimeResult = await this.attachRealtimeSession(entry, voiceMode, { isCurrent: authority?.isCurrent });
|
|
1973
|
+
if (!realtimeResult.ok) {
|
|
1974
|
+
entry.stop(`realtime setup failed guild ${guildId} channel ${channelId}`);
|
|
1975
|
+
return {
|
|
1976
|
+
ok: false,
|
|
1977
|
+
message: realtimeResult.message,
|
|
1978
|
+
guildId,
|
|
1979
|
+
channelId
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
if (isVoiceSessionStopped(entry) || this.params.destroyed() || authority && !authority.isCurrent()) {
|
|
1984
|
+
entry.stop(`${this.params.destroyed() ? "manager stopped" : "join cancelled"} during setup guild ${guildId} channel ${channelId}`);
|
|
1985
|
+
return {
|
|
1986
|
+
ok: false,
|
|
1987
|
+
message: this.params.destroyed() ? "Discord voice manager is stopped." : "Discord voice join was cancelled.",
|
|
1988
|
+
guildId,
|
|
1989
|
+
channelId
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
this.params.receive.enableDaveReceivePassthrough(entry, "post-join warmup", 30);
|
|
1993
|
+
connection.receiver.speaking.on("start", speakingHandler);
|
|
1994
|
+
connection.receiver.speaking.on("end", speakingEndHandler);
|
|
1953
1995
|
this.params.sessions.set(guildId, entry);
|
|
1954
1996
|
this.params.membership.activate(entry, this.params.botUserId());
|
|
1955
1997
|
logger$2.info(`discord voice: joined guild=${guildId} channel=${channelId} mode=${voiceMode} agent=${route.agentId} voiceSession=${voiceRoute.sessionKey} supervisorSession=${route.sessionKey} voiceModel=${voiceConfig?.model ?? "route-default"}`);
|
|
@@ -1980,7 +2022,7 @@ var DiscordVoiceSessions = class {
|
|
|
1980
2022
|
channelId: entry.channelId
|
|
1981
2023
|
};
|
|
1982
2024
|
if (entry.realtimeLifecycle.status === "active" || entry.realtimeLifecycle.status === "starting") {
|
|
1983
|
-
entry
|
|
2025
|
+
retireTranscripts(entry);
|
|
1984
2026
|
return {
|
|
1985
2027
|
ok: true,
|
|
1986
2028
|
message: `Stopped transcripts for ${formatMention({ channelId: entry.channelId })}.`,
|
|
@@ -1990,7 +2032,6 @@ var DiscordVoiceSessions = class {
|
|
|
1990
2032
|
}
|
|
1991
2033
|
}
|
|
1992
2034
|
entry.stop();
|
|
1993
|
-
this.params.sessions.delete(guildId);
|
|
1994
2035
|
if (!entry.receiveRecovery.decryptRecoveryInFlight) this.params.receive.deleteRecoveryAttempt(guildId);
|
|
1995
2036
|
if (!options?.preserveFollowState) this.params.onLeaveFollowState(guildId);
|
|
1996
2037
|
logVoiceVerbose(`leave: disconnected from guild ${guildId} channel ${entry.channelId}`);
|
|
@@ -2011,8 +2052,9 @@ var DiscordVoiceSessions = class {
|
|
|
2011
2052
|
ok: false,
|
|
2012
2053
|
message: "Discord realtime voice session stopped before startup completed."
|
|
2013
2054
|
};
|
|
2014
|
-
const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-
|
|
2055
|
+
const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-DOViOIjY.js");
|
|
2015
2056
|
const realtime = new DiscordRealtimeVoiceSession({
|
|
2057
|
+
accountId: this.params.accountId,
|
|
2016
2058
|
bootstrapContextInstructions,
|
|
2017
2059
|
cfg: this.params.cfg,
|
|
2018
2060
|
discordConfig: this.params.discordConfig,
|
|
@@ -2069,8 +2111,8 @@ var DiscordVoiceSessions = class {
|
|
|
2069
2111
|
//#endregion
|
|
2070
2112
|
//#region extensions/discord/src/voice/listeners.ts
|
|
2071
2113
|
const logger$1 = createSubsystemLogger("discord/voice");
|
|
2072
|
-
function startAutoJoin(
|
|
2073
|
-
|
|
2114
|
+
function startAutoJoin(operation, context = "") {
|
|
2115
|
+
operation().catch((err) => logger$1.warn(`discord voice: autoJoin${context} failed: ${formatErrorMessage(err)}`));
|
|
2074
2116
|
}
|
|
2075
2117
|
var DiscordVoiceReadyListener = class extends ReadyListener {
|
|
2076
2118
|
constructor(manager) {
|
|
@@ -2078,7 +2120,7 @@ var DiscordVoiceReadyListener = class extends ReadyListener {
|
|
|
2078
2120
|
this.manager = manager;
|
|
2079
2121
|
}
|
|
2080
2122
|
async handle(_data, _client) {
|
|
2081
|
-
startAutoJoin(this.manager);
|
|
2123
|
+
startAutoJoin(() => this.manager.autoJoin());
|
|
2082
2124
|
}
|
|
2083
2125
|
};
|
|
2084
2126
|
var DiscordVoiceResumedListener = class extends ResumedListener {
|
|
@@ -2087,7 +2129,7 @@ var DiscordVoiceResumedListener = class extends ResumedListener {
|
|
|
2087
2129
|
this.manager = manager;
|
|
2088
2130
|
}
|
|
2089
2131
|
async handle(_data, _client) {
|
|
2090
|
-
startAutoJoin(this.manager);
|
|
2132
|
+
startAutoJoin(() => this.manager.autoJoin());
|
|
2091
2133
|
}
|
|
2092
2134
|
};
|
|
2093
2135
|
var DiscordVoiceGuildCreateListener = class {
|
|
@@ -2096,7 +2138,10 @@ var DiscordVoiceGuildCreateListener = class {
|
|
|
2096
2138
|
this.type = discord_exports.GatewayDispatchEvents.GuildCreate;
|
|
2097
2139
|
}
|
|
2098
2140
|
async handle(data, _client) {
|
|
2099
|
-
if (!data.unavailable)
|
|
2141
|
+
if (!data.unavailable) {
|
|
2142
|
+
this.manager.refreshGuildRoster(data.id);
|
|
2143
|
+
startAutoJoin(() => this.manager.reconcileAutoJoinGuild(data.id), ` occupancy reconciliation guild=${data.id}`);
|
|
2144
|
+
}
|
|
2100
2145
|
}
|
|
2101
2146
|
};
|
|
2102
2147
|
var DiscordVoiceStateUpdateListener = class extends VoiceStateUpdateListener {
|
|
@@ -2137,9 +2182,10 @@ var DiscordVoiceManager = class {
|
|
|
2137
2182
|
this.guildLifecycles = /* @__PURE__ */ new Map();
|
|
2138
2183
|
this.nextGuildGeneration = 0;
|
|
2139
2184
|
this.joinTasks = /* @__PURE__ */ new Map();
|
|
2140
|
-
this.
|
|
2185
|
+
this.autoJoinTasks = /* @__PURE__ */ new Map();
|
|
2141
2186
|
this.fatalAutoJoinFailures = /* @__PURE__ */ new Map();
|
|
2142
2187
|
this.destroyed = false;
|
|
2188
|
+
this.client = params.client;
|
|
2143
2189
|
this.botUserId = params.botUserId;
|
|
2144
2190
|
this.voiceEnabled = resolveDiscordVoiceEnabled(params.discordConfig.voice);
|
|
2145
2191
|
const voiceAccess = resolveDiscordVoiceAccess(params);
|
|
@@ -2153,6 +2199,7 @@ var DiscordVoiceManager = class {
|
|
|
2153
2199
|
});
|
|
2154
2200
|
this.membership = new DiscordVoiceMembershipTracker(params.client, this.speakerContext, params.accountId);
|
|
2155
2201
|
this.receive = new DiscordVoiceReceive({
|
|
2202
|
+
accountId: params.accountId,
|
|
2156
2203
|
admissionAllowFrom: this.admissionAllowFrom,
|
|
2157
2204
|
botUserId: () => this.botUserId,
|
|
2158
2205
|
cfg: params.cfg,
|
|
@@ -2218,51 +2265,24 @@ var DiscordVoiceManager = class {
|
|
|
2218
2265
|
}
|
|
2219
2266
|
async autoJoin() {
|
|
2220
2267
|
if (!this.voiceEnabled || this.destroyed) return;
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
if (selected) logger.warn(`discord voice: autoJoin has multiple entries for guild ${guildId}; using channel ${selected.channelId}`);
|
|
2240
|
-
}
|
|
2241
|
-
for (const entry of entriesByGuild.values()) {
|
|
2242
|
-
const failureKey = formatAutoJoinFailureKey(entry);
|
|
2243
|
-
const fatalFailure = this.fatalAutoJoinFailures.get(failureKey);
|
|
2244
|
-
if (fatalFailure) {
|
|
2245
|
-
if (!fatalFailure.skipLogged) {
|
|
2246
|
-
logger.warn(`discord voice: autoJoin suppressed guild=${entry.guildId} channel=${entry.channelId} after fatal startup failure; retry with /vc join or reload config after fixing credentials: ${fatalFailure.message}`);
|
|
2247
|
-
fatalFailure.skipLogged = true;
|
|
2248
|
-
}
|
|
2249
|
-
continue;
|
|
2250
|
-
}
|
|
2251
|
-
logVoiceVerbose(`autoJoin: joining guild ${entry.guildId} channel ${entry.channelId}`);
|
|
2252
|
-
const result = await this.join(entry);
|
|
2253
|
-
if (!result.ok) {
|
|
2254
|
-
logger.warn(`discord voice: autoJoin skipped guild=${entry.guildId} channel=${entry.channelId}: ${result.message}`);
|
|
2255
|
-
if (isFatalAutoJoinFailure(result.message)) this.fatalAutoJoinFailures.set(failureKey, {
|
|
2256
|
-
message: result.message,
|
|
2257
|
-
skipLogged: false
|
|
2258
|
-
});
|
|
2259
|
-
}
|
|
2260
|
-
}
|
|
2261
|
-
await this.following.startReconciliation();
|
|
2262
|
-
})().finally(() => {
|
|
2263
|
-
this.autoJoinTask = null;
|
|
2264
|
-
});
|
|
2265
|
-
return this.autoJoinTask;
|
|
2268
|
+
const entriesByGuild = /* @__PURE__ */ new Map();
|
|
2269
|
+
const duplicateGuilds = /* @__PURE__ */ new Set();
|
|
2270
|
+
for (const entry of this.autoJoinChannels) {
|
|
2271
|
+
if (entriesByGuild.has(entry.guildId)) duplicateGuilds.add(entry.guildId);
|
|
2272
|
+
entriesByGuild.set(entry.guildId, entry);
|
|
2273
|
+
}
|
|
2274
|
+
logVoiceVerbose(`autoJoin: ${this.autoJoinChannels.length} entries, ${entriesByGuild.size} guilds`);
|
|
2275
|
+
for (const guildId of duplicateGuilds) {
|
|
2276
|
+
const selected = entriesByGuild.get(guildId);
|
|
2277
|
+
if (selected) logger.warn(`discord voice: autoJoin has multiple entries for guild ${guildId}; using channel ${selected.channelId}`);
|
|
2278
|
+
}
|
|
2279
|
+
for (const entry of entriesByGuild.values()) await this.enqueueAutoJoin(entry);
|
|
2280
|
+
await this.following.startReconciliation();
|
|
2281
|
+
}
|
|
2282
|
+
async reconcileAutoJoinGuild(guildId) {
|
|
2283
|
+
const entry = this.resolveAutoJoinTarget(guildId);
|
|
2284
|
+
if (!entry?.whenOccupied || !this.voiceEnabled || this.destroyed) return;
|
|
2285
|
+
await this.enqueueAutoJoin(entry);
|
|
2266
2286
|
}
|
|
2267
2287
|
status() {
|
|
2268
2288
|
return Array.from(this.guildLifecycles.values()).filter((lifecycle) => lifecycle.status === "active").map(({ instance: session }) => ({
|
|
@@ -2279,6 +2299,24 @@ var DiscordVoiceManager = class {
|
|
|
2279
2299
|
channelId: params.channelId.trim()
|
|
2280
2300
|
});
|
|
2281
2301
|
}
|
|
2302
|
+
async resolveAccessTarget(params) {
|
|
2303
|
+
const [guild, channel] = await Promise.all([this.client.fetchGuild(params.guildId).catch(() => null), this.client.fetchChannel(params.channelId).catch(() => null)]);
|
|
2304
|
+
if (!guild || !channel) return;
|
|
2305
|
+
const context = await resolveFetchedDiscordThreadLikeChannelContext({
|
|
2306
|
+
client: this.client,
|
|
2307
|
+
channel,
|
|
2308
|
+
channelIdFallback: params.channelId
|
|
2309
|
+
});
|
|
2310
|
+
return {
|
|
2311
|
+
guild,
|
|
2312
|
+
...context.channelName ? { channelName: context.channelName } : {},
|
|
2313
|
+
channelSlug: context.channelSlug,
|
|
2314
|
+
...context.parentId ? { parentId: context.parentId } : {},
|
|
2315
|
+
...context.threadParentName ? { parentName: context.threadParentName } : {},
|
|
2316
|
+
...context.threadParentSlug ? { parentSlug: context.threadParentSlug } : {},
|
|
2317
|
+
scope: context.isThreadChannel ? "thread" : "channel"
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2282
2320
|
async join(params, options) {
|
|
2283
2321
|
if (this.destroyed) return {
|
|
2284
2322
|
ok: false,
|
|
@@ -2429,6 +2467,7 @@ var DiscordVoiceManager = class {
|
|
|
2429
2467
|
guildId,
|
|
2430
2468
|
channelId
|
|
2431
2469
|
});
|
|
2470
|
+
await this.reconcileAutoJoinGuild(guildId);
|
|
2432
2471
|
return;
|
|
2433
2472
|
}
|
|
2434
2473
|
this.membership.track(this.sessions.get(guildId), data, previousVoiceState);
|
|
@@ -2437,6 +2476,8 @@ var DiscordVoiceManager = class {
|
|
|
2437
2476
|
channelId,
|
|
2438
2477
|
userId
|
|
2439
2478
|
});
|
|
2479
|
+
const autoJoinTarget = this.resolveAutoJoinTarget(guildId);
|
|
2480
|
+
if (autoJoinTarget?.whenOccupied) await this.enqueueAutoJoin(autoJoinTarget);
|
|
2440
2481
|
}
|
|
2441
2482
|
async destroy() {
|
|
2442
2483
|
this.destroyed = true;
|
|
@@ -2454,6 +2495,65 @@ var DiscordVoiceManager = class {
|
|
|
2454
2495
|
const lifecycle = this.guildLifecycles.get(entry.guildId);
|
|
2455
2496
|
return lifecycle?.status === "active" && lifecycle.generation === entry.generation && lifecycle.instance === entry && entry.sessionLifecycle.status === "active";
|
|
2456
2497
|
}
|
|
2498
|
+
resolveAutoJoinTarget(guildId) {
|
|
2499
|
+
return this.autoJoinChannels.toReversed().find((entry) => entry.guildId === guildId.trim());
|
|
2500
|
+
}
|
|
2501
|
+
enqueueAutoJoin(entry) {
|
|
2502
|
+
const task = (this.autoJoinTasks.get(entry.guildId) ?? Promise.resolve()).catch(() => void 0).then(async () => await this.reconcileAutoJoinEntry(entry)).finally(() => {
|
|
2503
|
+
if (this.autoJoinTasks.get(entry.guildId) === task) this.autoJoinTasks.delete(entry.guildId);
|
|
2504
|
+
});
|
|
2505
|
+
this.autoJoinTasks.set(entry.guildId, task);
|
|
2506
|
+
return task;
|
|
2507
|
+
}
|
|
2508
|
+
async reconcileAutoJoinEntry(entry) {
|
|
2509
|
+
if (this.destroyed) return;
|
|
2510
|
+
const failureKey = formatAutoJoinFailureKey(entry);
|
|
2511
|
+
const fatalFailure = this.fatalAutoJoinFailures.get(failureKey);
|
|
2512
|
+
if (fatalFailure) {
|
|
2513
|
+
if (!fatalFailure.skipLogged) {
|
|
2514
|
+
logger.warn(`discord voice: autoJoin suppressed guild=${entry.guildId} channel=${entry.channelId} after fatal startup failure; retry with /vc join or reload config after fixing credentials: ${fatalFailure.message}`);
|
|
2515
|
+
fatalFailure.skipLogged = true;
|
|
2516
|
+
}
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
if (entry.whenOccupied) {
|
|
2520
|
+
const states = listDiscordVoiceParticipantStates({
|
|
2521
|
+
client: this.client,
|
|
2522
|
+
guildId: entry.guildId,
|
|
2523
|
+
channelId: entry.channelId
|
|
2524
|
+
});
|
|
2525
|
+
if (states === null) {
|
|
2526
|
+
logVoiceVerbose(`autoJoin waiting for guild voice snapshot guild=${entry.guildId} channel=${entry.channelId}`);
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
const humanCount = countDiscordVoiceHumanParticipants({
|
|
2530
|
+
states,
|
|
2531
|
+
botUserId: this.botUserId
|
|
2532
|
+
});
|
|
2533
|
+
const existing = this.sessions.get(entry.guildId);
|
|
2534
|
+
if (humanCount === 0) {
|
|
2535
|
+
if (!existing?.autoJoinWhenOccupied || existing.channelId !== entry.channelId) return;
|
|
2536
|
+
logger.info(`discord voice: occupied autoJoin leaving empty channel guild=${entry.guildId} channel=${entry.channelId}`);
|
|
2537
|
+
const result = await this.leave({
|
|
2538
|
+
guildId: entry.guildId,
|
|
2539
|
+
channelId: entry.channelId
|
|
2540
|
+
});
|
|
2541
|
+
if (!result.ok) logger.warn(`discord voice: occupied autoJoin failed to leave guild=${entry.guildId} channel=${entry.channelId}: ${result.message}`);
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
const lifecycle = this.guildLifecycles.get(entry.guildId);
|
|
2545
|
+
if (existing || lifecycle?.status === "starting" || lifecycle?.status === "active") return;
|
|
2546
|
+
logger.info(`discord voice: occupied autoJoin joining guild=${entry.guildId} channel=${entry.channelId} humans=${humanCount}`);
|
|
2547
|
+
} else logVoiceVerbose(`autoJoin: joining guild ${entry.guildId} channel ${entry.channelId}`);
|
|
2548
|
+
const result = await this.join(entry, { autoJoinWhenOccupied: entry.whenOccupied === true });
|
|
2549
|
+
if (!result.ok) {
|
|
2550
|
+
logger.warn(`discord voice: autoJoin skipped guild=${entry.guildId} channel=${entry.channelId}: ${result.message}`);
|
|
2551
|
+
if (isFatalAutoJoinFailure(result.message)) this.fatalAutoJoinFailures.set(failureKey, {
|
|
2552
|
+
message: result.message,
|
|
2553
|
+
skipLogged: false
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2457
2557
|
};
|
|
2458
2558
|
//#endregion
|
|
2459
2559
|
export { DiscordVoiceGuildCreateListener, DiscordVoiceManager, DiscordVoiceReadyListener, DiscordVoiceResumedListener, DiscordVoiceStateUpdateListener };
|