@openclaw/discord 2026.9.6 → 2026.9.8
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/assets/icon.png +0 -0
- package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
- package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
- package/dist/.setup/{activities-api-COU4-0nR.mjs → activities-api-tvbsU2e3.mjs} +38 -66
- package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
- package/dist/.setup/{approval-handler.runtime-CbBktBb4.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
- package/dist/.setup/{approval-message-updates-jf9zMaIC.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
- package/dist/.setup/{audit-vKbh-LFR.mjs → audit-CLg9I71N.mjs} +5 -5
- package/dist/.setup/{channel-Dv4e3Jpc.mjs → channel-DxlUVU9t.mjs} +121 -227
- package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
- package/dist/.setup/{channel.setup-0NX6FFwi.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
- package/dist/.setup/{components-yBEb75bB.mjs → components-Cq1PvIpN.mjs} +41 -69
- package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
- package/dist/.setup/{conversation-binding-route-B7qImK_b.mjs → conversation-binding-route-Caz_XuFH.mjs} +10 -5
- package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
- package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
- package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
- package/dist/.setup/{doctor-D1R-uFIu.mjs → doctor-BCl1H5tl.mjs} +21 -36
- package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
- package/dist/.setup/{channel-actions.runtime-leZuw01r.mjs → handle-action-CUvQWnE7.mjs} +67 -104
- package/dist/.setup/{handle-action.guild-admin-DcFa8NwA.mjs → handle-action.guild-admin-Df-8gVle.mjs} +62 -120
- package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
- package/dist/.setup/{message-handler-X6ejmbtY.mjs → message-handler-B-Jk4oDk.mjs} +18 -94
- package/dist/.setup/{message-handler.preflight-pluralkit-8Xji34AF.mjs → message-handler.preflight-pluralkit-CWLUBVcx.mjs} +8 -10
- package/dist/.setup/{message-handler.preflight-DE_POxFc.mjs → message-handler.preflight-v-__NSDq.mjs} +69 -180
- package/dist/.setup/{message-handler.process-CCmIVnxy.mjs → message-handler.process-BNFFuChn.mjs} +65 -86
- package/dist/.setup/{outbound-adapter-ClIgmu4F.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
- package/dist/.setup/{outbound-session-route-VulUE0yV.mjs → outbound-session-route-zVGxxceg.mjs} +140 -108
- package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
- package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
- package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
- package/dist/.setup/{provider-iOf73HW-.mjs → provider-B_G5hASF.mjs} +721 -1416
- package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
- package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
- package/dist/.setup/{realtime-session.runtime-Dz8uVutq.mjs → realtime-session.runtime-oUd9DOcz.mjs} +41 -55
- package/dist/.setup/{receive-recovery-DHst8WRx.mjs → receive-recovery-CHPOsnLc.mjs} +1 -4
- package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
- package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
- package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
- package/dist/.setup/{retry-BEYkDy0P.mjs → retry-pz_cSha2.mjs} +3 -3
- package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
- package/dist/.setup/{runtime-B8lJfyrA.mjs → runtime-FN000lxA.mjs} +60 -162
- package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
- package/dist/.setup/{runtime-DisDbixd.mjs → runtime-sUksZ--Q.mjs} +2 -5
- package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
- package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
- package/dist/.setup/{send-CIBzvXjS.mjs → send-CrfEI6Bs.mjs} +53 -108
- package/dist/.setup/{send.components-ChY21qr-.mjs → send.components-DxQAMfES.mjs} +62 -107
- package/dist/.setup/{send.outbound-QTyuFupn.mjs → send.outbound-BISKnb-a.mjs} +66 -140
- package/dist/.setup/{send.shared-VNvWfX2T.mjs → send.shared-DGFkbkQR.mjs} +10 -25
- package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
- package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
- package/dist/.setup/{shared-DHPDaMSx.mjs → shared-B3wZ4hN-.mjs} +25 -32
- package/dist/.setup/{subagent-hooks-CjW7r8Pe.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
- package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
- package/dist/.setup/{target-resolver-BXpy6VT8.mjs → target-resolver-BuLapkhy.mjs} +9 -12
- package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
- package/dist/.setup/{thread-bindings-CEh2dhqP.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
- package/dist/.setup/{thread-bindings.manager-ve-i6oqt.mjs → thread-bindings.manager-DN-NissX.mjs} +325 -233
- package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
- package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
- package/dist/.setup/{transcripts-source-DVegW0WI.mjs → transcripts-source-p8EV179h.mjs} +76 -235
- package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
- package/dist/.setup/{voice-runtime-elTtjEIG.mjs → voice-runtime-B46rcwrG.mjs} +140 -244
- package/dist/account-inspect-api.js +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/activities-api.js +1 -1
- package/dist/api.js +18 -18
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +4 -4
- package/dist/index.js +1 -1
- package/dist/runtime-api.js +20 -20
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/src/voice/audio-worker.runtime.js +15 -24
- package/dist/subagent-hooks-api.js +3 -4
- package/dist/transcripts-source-api.js +1 -1
- package/node_modules/@types/node/README.md +2 -2
- package/node_modules/@types/node/child_process.d.ts +1 -1
- package/node_modules/@types/node/crypto.d.ts +20 -8
- package/node_modules/@types/node/ffi.d.ts +14 -0
- package/node_modules/@types/node/http2.d.ts +3 -2
- package/node_modules/@types/node/net.d.ts +16 -4
- package/node_modules/@types/node/package.json +2 -17
- package/node_modules/@types/node/process.d.ts +1 -0
- package/node_modules/@types/node/quic.d.ts +39 -1
- package/node_modules/@types/node/stream/iter.d.ts +9 -12
- package/node_modules/@types/node/test/reporters.d.ts +1 -0
- package/node_modules/@types/node/test.d.ts +72 -0
- package/node_modules/@types/node/tls.d.ts +14 -10
- package/node_modules/@types/node/vm.d.ts +2 -1
- package/node_modules/@types/node/worker_threads.d.ts +4 -1
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/openclaw.plugin.json +21 -1
- package/package.json +5 -5
- package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
- package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
- package/dist/.setup/provider-session.runtime-DrGAYnZv.mjs +0 -6
- package/dist/.setup/provider.runtime-BmjW_pIw.mjs +0 -2
- package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
- package/dist/.setup/setup-plugin-api-Dvr41dyx.mjs +0 -3
- package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
- package/dist/.setup/targets-CvemhN3i.mjs +0 -3
- package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
package/dist/.setup/{thread-bindings.manager-ve-i6oqt.mjs → thread-bindings.manager-DN-NissX.mjs}
RENAMED
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
|
|
2
|
+
import { C as withDiscordRequestAuthority, mt as getChannel, nt as createChannelWebhook } from "./discord-0xJYfdDD.mjs";
|
|
3
|
+
import { t as isDiscordThreadChannelType } from "./channel-type-DRCrEMss.mjs";
|
|
4
|
+
import { t as canFallbackDiscordWebhookSend, x as resolveDiscordChannelId } from "./retry-pz_cSha2.mjs";
|
|
5
|
+
import { N as createDiscordRestClient } from "./send.shared-DGFkbkQR.mjs";
|
|
6
|
+
import { t as sendMessageDiscord } from "./send.outbound-BISKnb-a.mjs";
|
|
6
7
|
import { n as resolveDiscordChannelInfoSafe, t as resolveDiscordChannelIdSafe } from "./channel-access-C12aDZ0p.mjs";
|
|
7
|
-
import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-
|
|
8
|
-
import { C as
|
|
8
|
+
import { c as sendWebhookMessageDiscord, u as createThreadDiscord } from "./send-CrfEI6Bs.mjs";
|
|
9
|
+
import { C as resolvePreparedThreadBindingLifecycle, D as resolveThreadBindingMaxAgeMs$1, M as toReusableWebhookKey, S as resolveBindingRecordKey, _ as refreshUnboundThreadWebhookIdentity, c as THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS, d as forgetThreadBindingToken, f as getThreadBindingToken, h as normalizeThreadBindingDurationMs, i as REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, j as toBindingRecordKey, k as shouldDefaultPersist, m as normalizeTargetKind, n as MANAGERS_BY_ACCOUNT_ID, r as PERSIST_BY_ACCOUNT_ID, t as BINDINGS_BY_THREAD_ID, u as ensureBindingsLoadedAsync, v as rememberReusableWebhook, w as resolveThreadBindingIdleTimeoutMs$1, x as resolveBindingIdsForSession, y as rememberThreadBindingToken } from "./thread-bindings.state-g6v9zAym.mjs";
|
|
10
|
+
import { c as drainThreadBindingAccountOperations, d as runThreadBindingAccountOperation, f as runThreadBindingMutation, h as updateBindingRecordSync, l as drainThreadBindingMutations, m as snapshotThreadBindingJson, p as shouldPersistAnyBindingState, s as commitBindingRecord } from "./thread-bindings.session-updates-CshfKghV.mjs";
|
|
9
11
|
import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
10
12
|
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
|
11
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
|
+
import { asOptionalObjectRecord, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
12
14
|
import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
13
15
|
import { createSubsystemLogger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
14
16
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
15
17
|
import { SYSTEM_MARK } from "openclaw/plugin-sdk/text-chunking";
|
|
16
|
-
import {
|
|
18
|
+
import { registerSessionBindingAdapter, resolveThreadBindingConversationIdFromBindingId, resolveThreadBindingFarewellText, resolveThreadBindingThreadName, unregisterSessionBindingAdapter } from "openclaw/plugin-sdk/conversation-runtime";
|
|
17
19
|
import { resolveSessionAgentIdStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
18
20
|
//#region extensions/discord/src/monitor/thread-bindings.persona.ts
|
|
19
21
|
const THREAD_BINDING_PERSONA_MAX_CHARS = 80;
|
|
@@ -26,10 +28,7 @@ function resolveThreadBindingPersona(params) {
|
|
|
26
28
|
return truncateUtf16Safe(`${SYSTEM_MARK} ${base}`, THREAD_BINDING_PERSONA_MAX_CHARS);
|
|
27
29
|
}
|
|
28
30
|
function resolveThreadBindingPersonaFromRecord(record) {
|
|
29
|
-
return resolveThreadBindingPersona(
|
|
30
|
-
label: record.label,
|
|
31
|
-
agentId: record.agentId
|
|
32
|
-
});
|
|
31
|
+
return resolveThreadBindingPersona(record);
|
|
33
32
|
}
|
|
34
33
|
//#endregion
|
|
35
34
|
//#region extensions/discord/src/monitor/thread-bindings.types.ts
|
|
@@ -44,10 +43,7 @@ function buildThreadTarget(threadId) {
|
|
|
44
43
|
function isThreadArchived(raw) {
|
|
45
44
|
if (!raw || typeof raw !== "object") return false;
|
|
46
45
|
const asRecord = raw;
|
|
47
|
-
|
|
48
|
-
if (asRecord.thread_metadata?.archived === true) return true;
|
|
49
|
-
if (asRecord.threadMetadata?.archived === true) return true;
|
|
50
|
-
return false;
|
|
46
|
+
return asRecord.archived === true || asRecord.thread_metadata?.archived === true || asRecord.threadMetadata?.archived === true;
|
|
51
47
|
}
|
|
52
48
|
function normalizeDiscordBindingChannelId(raw) {
|
|
53
49
|
const trimmed = normalizeOptionalString(raw) ?? "";
|
|
@@ -64,18 +60,15 @@ function summarizeDiscordError(err) {
|
|
|
64
60
|
if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint" || typeof err === "symbol") return String(err);
|
|
65
61
|
return "error";
|
|
66
62
|
}
|
|
67
|
-
function extractNumericDiscordErrorValue(value) {
|
|
68
|
-
return parseStrictNonNegativeInteger(value);
|
|
69
|
-
}
|
|
70
63
|
function extractDiscordErrorStatus(err) {
|
|
71
64
|
if (!err || typeof err !== "object") return;
|
|
72
65
|
const candidate = err;
|
|
73
|
-
return
|
|
66
|
+
return parseStrictNonNegativeInteger(candidate.status) ?? parseStrictNonNegativeInteger(candidate.statusCode) ?? parseStrictNonNegativeInteger(candidate.response?.status);
|
|
74
67
|
}
|
|
75
68
|
function extractDiscordErrorCode(err) {
|
|
76
69
|
if (!err || typeof err !== "object") return;
|
|
77
70
|
const candidate = err;
|
|
78
|
-
return
|
|
71
|
+
return parseStrictNonNegativeInteger(candidate.code) ?? parseStrictNonNegativeInteger(candidate.rawError?.code) ?? parseStrictNonNegativeInteger(candidate.body?.code) ?? parseStrictNonNegativeInteger(candidate.response?.body?.code) ?? parseStrictNonNegativeInteger(candidate.response?.data?.code);
|
|
79
72
|
}
|
|
80
73
|
function isDiscordThreadGoneError(err) {
|
|
81
74
|
if (extractDiscordErrorCode(err) === 10003) return true;
|
|
@@ -207,21 +200,6 @@ async function createThreadForBinding(params) {
|
|
|
207
200
|
}
|
|
208
201
|
//#endregion
|
|
209
202
|
//#region extensions/discord/src/monitor/thread-bindings.session-adapter.ts
|
|
210
|
-
function normalizeChildBindingParentChannelId(raw) {
|
|
211
|
-
const trimmed = normalizeOptionalString(raw) ?? "";
|
|
212
|
-
if (!trimmed) return;
|
|
213
|
-
try {
|
|
214
|
-
return resolveDiscordChannelId(trimmed);
|
|
215
|
-
} catch {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
function toSessionBindingTargetKind(raw) {
|
|
220
|
-
return raw === "subagent" ? "subagent" : "session";
|
|
221
|
-
}
|
|
222
|
-
function toThreadBindingTargetKind(raw) {
|
|
223
|
-
return raw === "subagent" ? "subagent" : "acp";
|
|
224
|
-
}
|
|
225
203
|
function toSessionBindingRecord(record, defaults) {
|
|
226
204
|
const bindingId = resolveBindingRecordKey({
|
|
227
205
|
accountId: record.accountId,
|
|
@@ -234,7 +212,7 @@ function toSessionBindingRecord(record, defaults) {
|
|
|
234
212
|
return {
|
|
235
213
|
bindingId,
|
|
236
214
|
targetSessionKey: record.targetSessionKey,
|
|
237
|
-
targetKind:
|
|
215
|
+
targetKind: record.targetKind === "subagent" ? "subagent" : "session",
|
|
238
216
|
conversation: {
|
|
239
217
|
channel: "discord",
|
|
240
218
|
accountId: record.accountId,
|
|
@@ -270,18 +248,19 @@ function createThreadBindingSessionAdapter(params) {
|
|
|
270
248
|
if (!targetSessionKey) return null;
|
|
271
249
|
const conversationId = normalizeOptionalString(input.conversation.conversationId) ?? "";
|
|
272
250
|
const placement = input.placement === "child" ? "child" : "current";
|
|
273
|
-
const metadata = input.metadata ?? {};
|
|
251
|
+
const metadata = asOptionalObjectRecord(snapshotThreadBindingJson(input.metadata ? { ...input.metadata } : void 0)) ?? {};
|
|
252
|
+
const targetKind = input.targetKind === "subagent" ? "subagent" : "acp";
|
|
274
253
|
const label = normalizeOptionalString(metadata.label);
|
|
275
|
-
const threadName =
|
|
276
|
-
const introText =
|
|
277
|
-
const boundBy =
|
|
278
|
-
const agentId =
|
|
254
|
+
const threadName = normalizeOptionalString(metadata.threadName);
|
|
255
|
+
const introText = normalizeOptionalString(metadata.introText);
|
|
256
|
+
const boundBy = normalizeOptionalString(metadata.boundBy);
|
|
257
|
+
const agentId = normalizeOptionalString(metadata.agentId);
|
|
279
258
|
let threadId;
|
|
280
259
|
let channelId;
|
|
281
260
|
let createThread = false;
|
|
282
261
|
if (placement === "child") {
|
|
283
262
|
createThread = true;
|
|
284
|
-
channelId =
|
|
263
|
+
channelId = normalizeDiscordBindingChannelId(input.conversation.parentConversationId) ?? void 0;
|
|
285
264
|
if (!channelId && conversationId) channelId = await resolveChannelIdForBinding({
|
|
286
265
|
cfg: params.resolveCurrentCfg(),
|
|
287
266
|
accountId: params.accountId,
|
|
@@ -294,7 +273,7 @@ function createThreadBindingSessionAdapter(params) {
|
|
|
294
273
|
channelId,
|
|
295
274
|
createThread,
|
|
296
275
|
threadName,
|
|
297
|
-
targetKind
|
|
276
|
+
targetKind,
|
|
298
277
|
targetSessionKey,
|
|
299
278
|
agentId,
|
|
300
279
|
label,
|
|
@@ -312,28 +291,39 @@ function createThreadBindingSessionAdapter(params) {
|
|
|
312
291
|
return binding ? serializeBinding(binding) : null;
|
|
313
292
|
},
|
|
314
293
|
touch: (bindingId, at) => {
|
|
294
|
+
const threadId = resolveThreadBindingConversationIdFromBindingId({
|
|
295
|
+
accountId: params.accountId,
|
|
296
|
+
bindingId
|
|
297
|
+
});
|
|
298
|
+
if (threadId) params.manager.touchThreadSync({
|
|
299
|
+
threadId,
|
|
300
|
+
at,
|
|
301
|
+
persist: true
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
touchAsync: async (bindingId, at) => {
|
|
315
305
|
const threadId = resolveThreadBindingConversationIdFromBindingId({
|
|
316
306
|
accountId: params.accountId,
|
|
317
307
|
bindingId
|
|
318
308
|
});
|
|
319
309
|
if (!threadId) return;
|
|
320
|
-
params.manager.touchThread({
|
|
310
|
+
await params.manager.touchThread({
|
|
321
311
|
threadId,
|
|
322
312
|
at,
|
|
323
313
|
persist: true
|
|
324
314
|
});
|
|
325
315
|
},
|
|
326
316
|
unbind: async (input) => {
|
|
327
|
-
if (input.targetSessionKey?.trim()) return params.manager.unbindBySessionKey({
|
|
317
|
+
if (input.targetSessionKey?.trim()) return (await params.manager.unbindBySessionKey({
|
|
328
318
|
targetSessionKey: input.targetSessionKey,
|
|
329
319
|
reason: input.reason
|
|
330
|
-
}).map(serializeBinding);
|
|
320
|
+
})).map(serializeBinding);
|
|
331
321
|
const threadId = resolveThreadBindingConversationIdFromBindingId({
|
|
332
322
|
accountId: params.accountId,
|
|
333
323
|
bindingId: input.bindingId
|
|
334
324
|
});
|
|
335
325
|
if (!threadId) return [];
|
|
336
|
-
const removed = params.manager.unbindThread({
|
|
326
|
+
const removed = await params.manager.unbindThread({
|
|
337
327
|
threadId,
|
|
338
328
|
reason: input.reason
|
|
339
329
|
});
|
|
@@ -358,17 +348,20 @@ function createNoopThreadBindingManager(accountIdRaw) {
|
|
|
358
348
|
registerSessionBindingAdapter(adapter);
|
|
359
349
|
return {
|
|
360
350
|
accountId,
|
|
351
|
+
isStopping: () => false,
|
|
361
352
|
getIdleTimeoutMs: () => DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS,
|
|
362
353
|
getMaxAgeMs: () => 0,
|
|
363
354
|
getByThreadId: () => void 0,
|
|
364
355
|
getBySessionKey: () => void 0,
|
|
365
356
|
listBySessionKey: () => [],
|
|
366
357
|
listBindings: () => [],
|
|
367
|
-
touchThread: () => null,
|
|
358
|
+
touchThread: async () => null,
|
|
359
|
+
touchThreadSync: () => null,
|
|
368
360
|
bindTarget: async () => null,
|
|
369
|
-
unbindThread: () => null,
|
|
370
|
-
unbindBySessionKey: () => [],
|
|
371
|
-
|
|
361
|
+
unbindThread: async () => null,
|
|
362
|
+
unbindBySessionKey: async () => [],
|
|
363
|
+
notifyUnbound: () => {},
|
|
364
|
+
stop: async () => unregisterSessionBindingAdapter({
|
|
372
365
|
channel: "discord",
|
|
373
366
|
accountId,
|
|
374
367
|
adapter
|
|
@@ -379,15 +372,23 @@ function createNoopThreadBindingManager(accountIdRaw) {
|
|
|
379
372
|
//#region extensions/discord/src/monitor/thread-bindings.manager.ts
|
|
380
373
|
var thread_bindings_manager_exports = /* @__PURE__ */ __exportAll({
|
|
381
374
|
createThreadBindingManager: () => createThreadBindingManager,
|
|
382
|
-
createThreadBindingManagerAsync: () => createThreadBindingManagerAsync,
|
|
383
375
|
getThreadBindingManager: () => getThreadBindingManager
|
|
384
376
|
});
|
|
385
377
|
function isDirectConversationBindingId(value) {
|
|
386
378
|
const trimmed = normalizeOptionalString(value);
|
|
387
379
|
return Boolean(trimmed && /^(user:|channel:)/i.test(trimmed));
|
|
388
380
|
}
|
|
389
|
-
function createThreadBindingManager(
|
|
390
|
-
|
|
381
|
+
async function createThreadBindingManager(input) {
|
|
382
|
+
const params = { ...input };
|
|
383
|
+
await ensureBindingsLoadedAsync();
|
|
384
|
+
const manager = await runThreadBindingMutation(async () => createLoadedThreadBindingManager(params));
|
|
385
|
+
if (manager.isStopping()) {
|
|
386
|
+
await manager.stop();
|
|
387
|
+
return await createThreadBindingManager(params);
|
|
388
|
+
}
|
|
389
|
+
return manager;
|
|
390
|
+
}
|
|
391
|
+
function createLoadedThreadBindingManager(params) {
|
|
391
392
|
const accountId = normalizeAccountId(params.accountId);
|
|
392
393
|
const existing = MANAGERS_BY_ACCOUNT_ID.get(accountId);
|
|
393
394
|
if (existing) {
|
|
@@ -408,6 +409,23 @@ function createThreadBindingManager(params) {
|
|
|
408
409
|
const resolveCurrentCfg = () => getRuntimeConfigSnapshot() ?? params.cfg;
|
|
409
410
|
const resolveCurrentToken = () => getThreadBindingToken(accountId) ?? params.token;
|
|
410
411
|
const getCurrentBinding = (threadId) => MANAGERS_BY_ACCOUNT_ID.get(accountId) === manager ? manager.getByThreadId(threadId) : void 0;
|
|
412
|
+
let stopping = false;
|
|
413
|
+
let stopPromise;
|
|
414
|
+
let sweepPromise;
|
|
415
|
+
const assertManagerCurrent = () => {
|
|
416
|
+
if (MANAGERS_BY_ACCOUNT_ID.get(accountId) !== manager) throw new Error("Discord thread binding manager was retired");
|
|
417
|
+
};
|
|
418
|
+
const runOwnedMutation = (operation) => {
|
|
419
|
+
if (stopping) return Promise.reject(/* @__PURE__ */ new Error("Discord thread binding manager is stopping"));
|
|
420
|
+
return runThreadBindingAccountOperation([manager], async () => {
|
|
421
|
+
assertManagerCurrent();
|
|
422
|
+
return await operation();
|
|
423
|
+
});
|
|
424
|
+
};
|
|
425
|
+
const mutate = (operation) => runOwnedMutation(() => runThreadBindingMutation(async () => {
|
|
426
|
+
assertManagerCurrent();
|
|
427
|
+
return await operation();
|
|
428
|
+
}));
|
|
411
429
|
let sweepTimer = null;
|
|
412
430
|
const runSweepOnce = async () => {
|
|
413
431
|
const bindings = manager.listBindings();
|
|
@@ -415,7 +433,7 @@ function createThreadBindingManager(params) {
|
|
|
415
433
|
let rest = null;
|
|
416
434
|
for (const snapshotBinding of bindings) {
|
|
417
435
|
const binding = getCurrentBinding(snapshotBinding.threadId);
|
|
418
|
-
if (!binding) continue;
|
|
436
|
+
if (!binding || stopping) continue;
|
|
419
437
|
const now = Date.now();
|
|
420
438
|
const lifecycle = resolvePreparedThreadBindingLifecycle({
|
|
421
439
|
record: binding,
|
|
@@ -424,8 +442,9 @@ function createThreadBindingManager(params) {
|
|
|
424
442
|
});
|
|
425
443
|
const { expiresAt, reason } = lifecycle;
|
|
426
444
|
if (expiresAt != null && reason && now >= expiresAt) {
|
|
427
|
-
manager.unbindThread({
|
|
445
|
+
await manager.unbindThread({
|
|
428
446
|
threadId: binding.threadId,
|
|
447
|
+
expected: binding,
|
|
429
448
|
reason,
|
|
430
449
|
sendFarewell: true,
|
|
431
450
|
farewellText: resolveThreadBindingFarewellText({
|
|
@@ -454,8 +473,9 @@ function createThreadBindingManager(params) {
|
|
|
454
473
|
logVerbose(`discord thread binding sweep probe returned invalid payload for ${binding.threadId}`);
|
|
455
474
|
continue;
|
|
456
475
|
}
|
|
457
|
-
if (isThreadArchived(channel)) manager.unbindThread({
|
|
476
|
+
if (isThreadArchived(channel)) await manager.unbindThread({
|
|
458
477
|
threadId: binding.threadId,
|
|
478
|
+
expected: binding,
|
|
459
479
|
reason: "thread-archived",
|
|
460
480
|
sendFarewell: true
|
|
461
481
|
});
|
|
@@ -463,8 +483,9 @@ function createThreadBindingManager(params) {
|
|
|
463
483
|
if (getCurrentBinding(binding.threadId) !== binding) continue;
|
|
464
484
|
if (isDiscordThreadGoneError(err)) {
|
|
465
485
|
logVerbose(`discord thread binding sweep removing stale binding ${binding.threadId}: ${summarizeDiscordError(err)}`);
|
|
466
|
-
manager.unbindThread({
|
|
486
|
+
await manager.unbindThread({
|
|
467
487
|
threadId: binding.threadId,
|
|
488
|
+
expected: binding,
|
|
468
489
|
reason: "thread-delete",
|
|
469
490
|
sendFarewell: false
|
|
470
491
|
});
|
|
@@ -474,8 +495,52 @@ function createThreadBindingManager(params) {
|
|
|
474
495
|
}
|
|
475
496
|
}
|
|
476
497
|
};
|
|
498
|
+
const unbindThread = async (unbindParams) => {
|
|
499
|
+
const bindingKey = resolveBindingRecordKey({
|
|
500
|
+
accountId,
|
|
501
|
+
threadId: unbindParams.threadId
|
|
502
|
+
});
|
|
503
|
+
if (!bindingKey) return null;
|
|
504
|
+
const existingLocal = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
505
|
+
if (!existingLocal || existingLocal.accountId !== accountId || unbindParams.expected && existingLocal !== unbindParams.expected) return null;
|
|
506
|
+
await commitBindingRecord({
|
|
507
|
+
bindingKey,
|
|
508
|
+
previous: existingLocal,
|
|
509
|
+
next: null,
|
|
510
|
+
persist: unbindParams.persist ?? persist,
|
|
511
|
+
assertCurrent: assertManagerCurrent
|
|
512
|
+
});
|
|
513
|
+
const removed = existingLocal;
|
|
514
|
+
manager.notifyUnbound(removed, unbindParams);
|
|
515
|
+
return removed;
|
|
516
|
+
};
|
|
477
517
|
const manager = {
|
|
478
518
|
accountId,
|
|
519
|
+
isStopping: () => stopping,
|
|
520
|
+
notifyUnbound: (removed, notification) => {
|
|
521
|
+
refreshUnboundThreadWebhookIdentity(removed);
|
|
522
|
+
if (notification.sendFarewell !== false) {
|
|
523
|
+
const cfg = resolveCurrentCfg();
|
|
524
|
+
const farewell = resolveThreadBindingFarewellText({
|
|
525
|
+
reason: notification.reason,
|
|
526
|
+
farewellText: notification.farewellText,
|
|
527
|
+
idleTimeoutMs: resolveThreadBindingIdleTimeoutMs$1({
|
|
528
|
+
record: removed,
|
|
529
|
+
defaultIdleTimeoutMs: idleTimeoutMs
|
|
530
|
+
}),
|
|
531
|
+
maxAgeMs: resolveThreadBindingMaxAgeMs$1({
|
|
532
|
+
record: removed,
|
|
533
|
+
defaultMaxAgeMs: maxAgeMs
|
|
534
|
+
})
|
|
535
|
+
});
|
|
536
|
+
if (cfg) maybeSendBindingMessage({
|
|
537
|
+
cfg,
|
|
538
|
+
record: removed,
|
|
539
|
+
text: farewell,
|
|
540
|
+
preferWebhook: false
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
},
|
|
479
544
|
getIdleTimeoutMs: () => idleTimeoutMs,
|
|
480
545
|
getMaxAgeMs: () => maxAgeMs,
|
|
481
546
|
getByThreadId: (threadId) => {
|
|
@@ -498,206 +563,237 @@ function createThreadBindingManager(params) {
|
|
|
498
563
|
}).map((bindingKey) => BINDINGS_BY_THREAD_ID.get(bindingKey)).filter((entry) => Boolean(entry));
|
|
499
564
|
},
|
|
500
565
|
listBindings: () => [...BINDINGS_BY_THREAD_ID.values()].filter((entry) => entry.accountId === accountId),
|
|
501
|
-
|
|
566
|
+
touchThreadSync: (input) => {
|
|
567
|
+
assertManagerCurrent();
|
|
568
|
+
if (stopping) throw new Error("Discord thread binding manager is stopping");
|
|
502
569
|
const key = resolveBindingRecordKey({
|
|
503
570
|
accountId,
|
|
504
|
-
threadId:
|
|
571
|
+
threadId: input.threadId
|
|
505
572
|
});
|
|
506
573
|
if (!key) return null;
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
574
|
+
const at = typeof input.at === "number" && Number.isFinite(input.at) ? Math.max(0, Math.floor(input.at)) : Date.now();
|
|
575
|
+
return updateBindingRecordSync({
|
|
576
|
+
bindingKey: key,
|
|
577
|
+
transform: (record) => ({
|
|
578
|
+
...record,
|
|
579
|
+
lastActivityAt: Math.max(record.lastActivityAt || 0, at)
|
|
580
|
+
}),
|
|
581
|
+
persist: (input.persist ?? persist) && shouldPersistAnyBindingState(),
|
|
582
|
+
minIntervalMs: THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS
|
|
583
|
+
});
|
|
584
|
+
},
|
|
585
|
+
touchThread: (input) => {
|
|
586
|
+
const touchParams = {
|
|
587
|
+
...input,
|
|
588
|
+
at: typeof input.at === "number" && Number.isFinite(input.at) ? Math.max(0, Math.floor(input.at)) : Date.now()
|
|
514
589
|
};
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
590
|
+
return mutate(async () => {
|
|
591
|
+
const key = resolveBindingRecordKey({
|
|
592
|
+
accountId,
|
|
593
|
+
threadId: touchParams.threadId
|
|
594
|
+
});
|
|
595
|
+
if (!key) return null;
|
|
596
|
+
const existingResult = BINDINGS_BY_THREAD_ID.get(key);
|
|
597
|
+
if (!existingResult || existingResult.accountId !== accountId) return null;
|
|
598
|
+
const nextRecord = {
|
|
599
|
+
...existingResult,
|
|
600
|
+
lastActivityAt: Math.max(existingResult.lastActivityAt || 0, touchParams.at)
|
|
601
|
+
};
|
|
602
|
+
await commitBindingRecord({
|
|
603
|
+
bindingKey: key,
|
|
604
|
+
previous: existingResult,
|
|
605
|
+
next: nextRecord,
|
|
606
|
+
persist: (touchParams.persist ?? persist) && shouldPersistAnyBindingState(),
|
|
607
|
+
minIntervalMs: THREAD_BINDING_TOUCH_PERSIST_MIN_INTERVAL_MS,
|
|
608
|
+
assertCurrent: assertManagerCurrent
|
|
609
|
+
});
|
|
610
|
+
return nextRecord;
|
|
611
|
+
});
|
|
518
612
|
},
|
|
519
613
|
bindTarget: async (input) => {
|
|
520
614
|
const bindParams = {
|
|
521
615
|
...input,
|
|
522
|
-
metadata: input.metadata ? { ...input.metadata } : void 0
|
|
616
|
+
metadata: asOptionalObjectRecord(snapshotThreadBindingJson(input.metadata ? { ...input.metadata } : void 0))
|
|
523
617
|
};
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
618
|
+
return runOwnedMutation(async () => {
|
|
619
|
+
const assertCurrent = bindParams.assertCurrent;
|
|
620
|
+
assertCurrent?.();
|
|
621
|
+
const cfg = resolveCurrentCfg();
|
|
622
|
+
let threadId = normalizeOptionalStringifiedId(bindParams.threadId);
|
|
623
|
+
let channelId = normalizeOptionalString(bindParams.channelId) ?? "";
|
|
624
|
+
const directConversationBinding = isDirectConversationBindingId(threadId) || isDirectConversationBindingId(channelId);
|
|
625
|
+
let nativeBindingCreated = false;
|
|
626
|
+
const targetSessionKey = normalizeOptionalString(bindParams.targetSessionKey) ?? "";
|
|
627
|
+
if (!targetSessionKey) return null;
|
|
628
|
+
const targetKind = normalizeTargetKind(bindParams.targetKind, targetSessionKey);
|
|
629
|
+
let agentId = normalizeOptionalString(bindParams.agentId);
|
|
630
|
+
if (!threadId && bindParams.createThread) {
|
|
631
|
+
if (!channelId) return null;
|
|
632
|
+
agentId ??= resolveSessionAgentIdStrict({
|
|
633
|
+
config: cfg,
|
|
634
|
+
sessionKey: targetSessionKey
|
|
635
|
+
});
|
|
636
|
+
const threadName = resolveThreadBindingThreadName({
|
|
637
|
+
agentId: bindParams.agentId,
|
|
638
|
+
label: bindParams.label
|
|
639
|
+
});
|
|
640
|
+
threadId = await createThreadForBinding({
|
|
641
|
+
cfg,
|
|
642
|
+
accountId,
|
|
643
|
+
token: resolveCurrentToken(),
|
|
644
|
+
channelId,
|
|
645
|
+
threadName: normalizeOptionalString(bindParams.threadName) ?? threadName,
|
|
646
|
+
...assertCurrent ? { assertCreateAllowed: assertCurrent } : {}
|
|
647
|
+
}) ?? void 0;
|
|
648
|
+
nativeBindingCreated = Boolean(threadId);
|
|
649
|
+
}
|
|
650
|
+
if (!threadId) return null;
|
|
651
|
+
if (!channelId && directConversationBinding) channelId = threadId;
|
|
652
|
+
if (!channelId) channelId = await resolveChannelIdForBinding({
|
|
653
|
+
cfg,
|
|
654
|
+
accountId,
|
|
655
|
+
token: resolveCurrentToken(),
|
|
656
|
+
threadId,
|
|
657
|
+
channelId: bindParams.channelId
|
|
658
|
+
}) ?? "";
|
|
536
659
|
if (!channelId) return null;
|
|
537
|
-
|
|
660
|
+
const existingValue = manager.getByThreadId(threadId);
|
|
661
|
+
const previous = existingValue?.targetSessionKey === targetSessionKey && existingValue.targetKind === targetKind ? existingValue : void 0;
|
|
662
|
+
agentId ??= normalizeOptionalString(previous?.agentId) ?? resolveSessionAgentIdStrict({
|
|
538
663
|
config: cfg,
|
|
539
664
|
sessionKey: targetSessionKey
|
|
540
665
|
});
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
666
|
+
let webhookId = normalizeOptionalString(bindParams.webhookId) ?? normalizeOptionalString(existingValue?.webhookId) ?? "";
|
|
667
|
+
let webhookToken = normalizeOptionalString(bindParams.webhookToken) ?? normalizeOptionalString(existingValue?.webhookToken) ?? "";
|
|
668
|
+
if (!directConversationBinding && (!webhookId || !webhookToken)) {
|
|
669
|
+
const cachedWebhook = findReusableWebhook({
|
|
670
|
+
accountId,
|
|
671
|
+
channelId
|
|
672
|
+
});
|
|
673
|
+
webhookId = cachedWebhook.webhookId ?? "";
|
|
674
|
+
webhookToken = cachedWebhook.webhookToken ?? "";
|
|
675
|
+
}
|
|
676
|
+
if (!directConversationBinding && (!webhookId || !webhookToken)) {
|
|
677
|
+
const createdWebhook = await createWebhookForChannel({
|
|
678
|
+
cfg,
|
|
679
|
+
accountId,
|
|
680
|
+
token: resolveCurrentToken(),
|
|
681
|
+
channelId,
|
|
682
|
+
...assertCurrent ? { assertCreateAllowed: assertCurrent } : {}
|
|
683
|
+
});
|
|
684
|
+
webhookId = createdWebhook.webhookId ?? "";
|
|
685
|
+
webhookToken = createdWebhook.webhookToken ?? "";
|
|
686
|
+
nativeBindingCreated ||= Boolean(webhookId && webhookToken);
|
|
687
|
+
}
|
|
688
|
+
const now = Date.now();
|
|
689
|
+
const record = {
|
|
547
690
|
accountId,
|
|
548
|
-
token: resolveCurrentToken(),
|
|
549
691
|
channelId,
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
692
|
+
threadId,
|
|
693
|
+
targetKind,
|
|
694
|
+
targetSessionKey,
|
|
695
|
+
agentId,
|
|
696
|
+
label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(previous?.label),
|
|
697
|
+
webhookId: webhookId || void 0,
|
|
698
|
+
webhookToken: webhookToken || void 0,
|
|
699
|
+
boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(previous?.boundBy) ?? "system",
|
|
700
|
+
boundAt: now,
|
|
701
|
+
lastActivityAt: now,
|
|
702
|
+
idleTimeoutMs: typeof existingValue?.idleTimeoutMs === "number" ? existingValue.idleTimeoutMs : idleTimeoutMs,
|
|
703
|
+
maxAgeMs: typeof existingValue?.maxAgeMs === "number" ? existingValue.maxAgeMs : maxAgeMs,
|
|
704
|
+
metadata: {
|
|
705
|
+
...previous?.metadata,
|
|
706
|
+
...bindParams.metadata
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
if (!nativeBindingCreated) assertCurrent?.();
|
|
710
|
+
await runThreadBindingMutation(() => commitBindingRecord({
|
|
711
|
+
bindingKey: toBindingRecordKey({
|
|
712
|
+
accountId,
|
|
713
|
+
threadId
|
|
714
|
+
}),
|
|
715
|
+
previous: existingValue,
|
|
716
|
+
next: record,
|
|
717
|
+
persist,
|
|
718
|
+
assertCurrent: () => {
|
|
719
|
+
assertManagerCurrent();
|
|
720
|
+
if (!nativeBindingCreated) assertCurrent?.();
|
|
721
|
+
}
|
|
722
|
+
}));
|
|
723
|
+
const introText = bindParams.introText?.trim();
|
|
724
|
+
if (introText && cfg) maybeSendBindingMessage({
|
|
583
725
|
cfg,
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
726
|
+
record,
|
|
727
|
+
text: introText,
|
|
728
|
+
assertCurrent: () => {
|
|
729
|
+
assertCurrent?.();
|
|
730
|
+
const current = getCurrentBinding(record.threadId);
|
|
731
|
+
if (!current || current.targetSessionKey !== record.targetSessionKey || current.targetKind !== record.targetKind) throw new Error("Discord thread binding changed before its intro");
|
|
732
|
+
}
|
|
588
733
|
});
|
|
589
|
-
|
|
590
|
-
webhookToken = createdWebhook.webhookToken ?? "";
|
|
591
|
-
nativeBindingCreated ||= Boolean(webhookId && webhookToken);
|
|
592
|
-
}
|
|
593
|
-
const now = Date.now();
|
|
594
|
-
const record = {
|
|
595
|
-
accountId,
|
|
596
|
-
channelId,
|
|
597
|
-
threadId,
|
|
598
|
-
targetKind,
|
|
599
|
-
targetSessionKey,
|
|
600
|
-
agentId,
|
|
601
|
-
label: normalizeOptionalString(bindParams.label) ?? normalizeOptionalString(previous?.label),
|
|
602
|
-
webhookId: webhookId || void 0,
|
|
603
|
-
webhookToken: webhookToken || void 0,
|
|
604
|
-
boundBy: normalizeOptionalString(bindParams.boundBy) ?? normalizeOptionalString(previous?.boundBy) ?? "system",
|
|
605
|
-
boundAt: now,
|
|
606
|
-
lastActivityAt: now,
|
|
607
|
-
idleTimeoutMs: typeof existingValue?.idleTimeoutMs === "number" ? existingValue.idleTimeoutMs : idleTimeoutMs,
|
|
608
|
-
maxAgeMs: typeof existingValue?.maxAgeMs === "number" ? existingValue.maxAgeMs : maxAgeMs,
|
|
609
|
-
metadata: {
|
|
610
|
-
...previous?.metadata,
|
|
611
|
-
...bindParams.metadata
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
if (!nativeBindingCreated) assertCurrent?.();
|
|
615
|
-
setBindingRecord(record);
|
|
616
|
-
if (persist) saveBindingsToDisk();
|
|
617
|
-
const introText = bindParams.introText?.trim();
|
|
618
|
-
if (introText && cfg) maybeSendBindingMessage({
|
|
619
|
-
cfg,
|
|
620
|
-
record,
|
|
621
|
-
text: introText,
|
|
622
|
-
...assertCurrent ? { assertCurrent } : {}
|
|
734
|
+
return record;
|
|
623
735
|
});
|
|
624
|
-
return record;
|
|
625
736
|
},
|
|
626
|
-
unbindThread: (
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
threadId: unbindParams.threadId
|
|
630
|
-
});
|
|
631
|
-
if (!bindingKey) return null;
|
|
632
|
-
const existingLocal = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
633
|
-
if (!existingLocal || existingLocal.accountId !== accountId) return null;
|
|
634
|
-
const removed = removeBindingRecord(bindingKey);
|
|
635
|
-
if (!removed) return null;
|
|
636
|
-
refreshUnboundThreadWebhookIdentity(removed);
|
|
637
|
-
if (persist) saveBindingsToDisk();
|
|
638
|
-
if (unbindParams.sendFarewell !== false) {
|
|
639
|
-
const cfg = resolveCurrentCfg();
|
|
640
|
-
const farewell = resolveThreadBindingFarewellText({
|
|
641
|
-
reason: unbindParams.reason,
|
|
642
|
-
farewellText: unbindParams.farewellText,
|
|
643
|
-
idleTimeoutMs: resolveThreadBindingIdleTimeoutMs$1({
|
|
644
|
-
record: removed,
|
|
645
|
-
defaultIdleTimeoutMs: idleTimeoutMs
|
|
646
|
-
}),
|
|
647
|
-
maxAgeMs: resolveThreadBindingMaxAgeMs$1({
|
|
648
|
-
record: removed,
|
|
649
|
-
defaultMaxAgeMs: maxAgeMs
|
|
650
|
-
})
|
|
651
|
-
});
|
|
652
|
-
if (cfg) maybeSendBindingMessage({
|
|
653
|
-
cfg,
|
|
654
|
-
record: removed,
|
|
655
|
-
text: farewell,
|
|
656
|
-
preferWebhook: false
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
return removed;
|
|
737
|
+
unbindThread: (input) => {
|
|
738
|
+
const unbindParams = { ...input };
|
|
739
|
+
return mutate(() => unbindThread(unbindParams));
|
|
660
740
|
},
|
|
661
|
-
unbindBySessionKey: (
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const removed = [];
|
|
669
|
-
for (const bindingKey of ids) {
|
|
670
|
-
const binding = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
671
|
-
if (!binding) continue;
|
|
672
|
-
const entry = manager.unbindThread({
|
|
673
|
-
threadId: binding.threadId,
|
|
674
|
-
reason: unbindParams.reason,
|
|
675
|
-
sendFarewell: unbindParams.sendFarewell,
|
|
676
|
-
farewellText: unbindParams.farewellText
|
|
741
|
+
unbindBySessionKey: (input) => {
|
|
742
|
+
const unbindParams = { ...input };
|
|
743
|
+
return mutate(async () => {
|
|
744
|
+
const ids = resolveBindingIdsForSession({
|
|
745
|
+
targetSessionKey: unbindParams.targetSessionKey,
|
|
746
|
+
accountId,
|
|
747
|
+
targetKind: unbindParams.targetKind
|
|
677
748
|
});
|
|
678
|
-
if (
|
|
679
|
-
|
|
680
|
-
|
|
749
|
+
if (ids.length === 0) return [];
|
|
750
|
+
const removed = [];
|
|
751
|
+
for (const bindingKey of ids) {
|
|
752
|
+
const binding = BINDINGS_BY_THREAD_ID.get(bindingKey);
|
|
753
|
+
if (!binding) continue;
|
|
754
|
+
const entry = await unbindThread({
|
|
755
|
+
threadId: binding.threadId,
|
|
756
|
+
reason: unbindParams.reason,
|
|
757
|
+
sendFarewell: unbindParams.sendFarewell,
|
|
758
|
+
farewellText: unbindParams.farewellText
|
|
759
|
+
});
|
|
760
|
+
if (entry) removed.push(entry);
|
|
761
|
+
}
|
|
762
|
+
return removed;
|
|
763
|
+
});
|
|
681
764
|
},
|
|
682
765
|
stop: () => {
|
|
766
|
+
if (stopPromise) return stopPromise;
|
|
767
|
+
stopping = true;
|
|
683
768
|
if (sweepTimer) {
|
|
684
769
|
clearInterval(sweepTimer);
|
|
685
770
|
sweepTimer = null;
|
|
686
771
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
772
|
+
stopPromise = (async () => {
|
|
773
|
+
await sweepPromise;
|
|
774
|
+
await drainThreadBindingAccountOperations(manager);
|
|
775
|
+
await drainThreadBindingMutations();
|
|
776
|
+
if (MANAGERS_BY_ACCOUNT_ID.get(accountId) === manager) {
|
|
777
|
+
MANAGERS_BY_ACCOUNT_ID.delete(accountId);
|
|
778
|
+
forgetThreadBindingToken(accountId);
|
|
779
|
+
}
|
|
780
|
+
unregisterSessionBindingAdapter({
|
|
781
|
+
channel: "discord",
|
|
782
|
+
accountId,
|
|
783
|
+
adapter: sessionBindingAdapter
|
|
784
|
+
});
|
|
785
|
+
})();
|
|
786
|
+
return stopPromise;
|
|
696
787
|
}
|
|
697
788
|
};
|
|
698
789
|
if (params.enableSweeper !== false) {
|
|
699
790
|
sweepTimer = setInterval(() => {
|
|
700
|
-
|
|
791
|
+
if (stopping || sweepPromise) return;
|
|
792
|
+
sweepPromise = runSweepOnce().catch((error) => {
|
|
793
|
+
logVerbose(`discord thread binding sweep failed: ${String(error)}`);
|
|
794
|
+
}).finally(() => {
|
|
795
|
+
sweepPromise = void 0;
|
|
796
|
+
});
|
|
701
797
|
}, THREAD_BINDINGS_SWEEP_INTERVAL_MS);
|
|
702
798
|
if (!(process.env.VITEST || false)) sweepTimer.unref?.();
|
|
703
799
|
}
|
|
@@ -715,13 +811,9 @@ function createThreadBindingManager(params) {
|
|
|
715
811
|
MANAGERS_BY_ACCOUNT_ID.set(accountId, manager);
|
|
716
812
|
return manager;
|
|
717
813
|
}
|
|
718
|
-
async function createThreadBindingManagerAsync(params) {
|
|
719
|
-
await ensureBindingsLoadedAsync();
|
|
720
|
-
return createThreadBindingManager(params);
|
|
721
|
-
}
|
|
722
814
|
function getThreadBindingManager(accountId) {
|
|
723
815
|
const normalized = normalizeAccountId(accountId);
|
|
724
816
|
return MANAGERS_BY_ACCOUNT_ID.get(normalized) ?? null;
|
|
725
817
|
}
|
|
726
818
|
//#endregion
|
|
727
|
-
export {
|
|
819
|
+
export { isThreadArchived as a, resolveThreadBindingPersonaFromRecord as c, createNoopThreadBindingManager as i, getThreadBindingManager as n, resolveChannelIdForBinding as o, thread_bindings_manager_exports as r, resolveThreadBindingPersona as s, createThreadBindingManager as t };
|