@openclaw/discord 2026.7.2-beta.7 → 2026.8.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/{account-inspect-SXiCBCgP.js → account-inspect-D5xmUpnj.js} +49 -43
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/accounts-DNl-oCEw.js +371 -0
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{active-turn-thread-route-MlKWp8RD.js → active-turn-thread-route-fmHl1HNd.js} +9 -11
  6. package/dist/{activities-api-DTKsuDxf.js → activities-api-KCBAmWxD.js} +133 -175
  7. package/dist/activities-api.js +1 -1
  8. package/dist/{allow-list-DzKrtfah.js → allow-list-BDMimASD.js} +2 -3
  9. package/dist/{api-DnrK9gML.js → api-DNVbJyEy.js} +7 -2
  10. package/dist/api.js +18 -18
  11. package/dist/{approval-handler.runtime-HymvFTYn.js → approval-handler.runtime-B12RCYr8.js} +6 -6
  12. package/dist/{approval-message-safety-DEyKVsAw.js → approval-message-safety-XGFPbDoI.js} +89 -3
  13. package/dist/{audit-CjsrabP8.js → audit-Yc7eZDd6.js} +5 -5
  14. package/dist/{channel-actions-uXFTJX3o.js → channel-actions-Dr2QI8Bf.js} +11 -7
  15. package/dist/{channel-actions.runtime-CIYU90sl.js → channel-actions.runtime-CODTvo7c.js} +99 -97
  16. package/dist/{channel-vKa-76xY.js → channel-cXYzGc4L.js} +102 -104
  17. package/dist/channel-config-api.js +1 -1
  18. package/dist/channel-plugin-api.js +1 -1
  19. package/dist/{channel.setup-CmcwZ_qd.js → channel.setup-CSiwnMgs.js} +16 -54
  20. package/dist/{outbound-session-route-H-HoyH5U.js → components-ezGKo_Yh.js} +69 -142
  21. package/dist/{config-schema-WHRQcY19.js → config-schema-DC5kDtQ5.js} +42 -11
  22. package/dist/conversation-binding-route-D6rCQ5S0.js +43 -0
  23. package/dist/{directory-config-D_LojtCe.js → directory-config-XyCfoqLg.js} +2 -2
  24. package/dist/directory-contract-api.js +1 -1
  25. package/dist/{directory-live-Bw5Ephzv.js → directory-live-Df0NbFJB.js} +7 -4
  26. package/dist/{doctor-Bc4S1qyd.js → doctor-DYY31GrO.js} +34 -13
  27. package/dist/{doctor-contract-CCFMIDk9.js → doctor-contract-DsWvKIXF.js} +2 -3
  28. package/dist/doctor-contract-api.js +147 -2
  29. package/dist/{handle-action.guild-admin-D6VRRW-C.js → handle-action.guild-admin-6Tvvinsa.js} +4 -7
  30. package/dist/{inbound-event-delivery-CEPlt2uz.js → inbound-event-delivery-De2qxTrP.js} +4 -25
  31. package/dist/index.js +5 -4
  32. package/dist/{message-handler-CeiSulIw.js → message-handler-B61q5MOF.js} +118 -33
  33. package/dist/{message-handler.preflight-DibgQFf2.js → message-handler.preflight-Bzg_Hawz.js} +75 -61
  34. package/dist/{message-handler.process-Dnc_oz9y.js → message-handler.process--4_712Ec.js} +236 -296
  35. package/dist/{message-utils-BgTwT_q7.js → message-utils-BXLLnFl6.js} +34 -35
  36. package/dist/{model-picker-preference-primitives-D25pnCOu.js → model-picker-preference-primitives-BHT1LkR_.js} +3 -3
  37. package/dist/{outbound-adapter-DtE-i2OJ.js → outbound-adapter-DxHTOqiN.js} +157 -68
  38. package/dist/{outbound-components-C7GVyfPh.js → outbound-components-B2PL0ooH.js} +3 -3
  39. package/dist/owner-access-Bg41VzAf.js +107 -0
  40. package/dist/{pluralkit-CD4B11JB.js → pluralkit-dUl4v1X3.js} +1 -1
  41. package/dist/{preflight-audio-BjnQZ5yS.js → preflight-audio-DrnqFA8U.js} +22 -28
  42. package/dist/{probe-BeWKhjqX.js → probe-BTdtVRwU.js} +37 -13
  43. package/dist/probe.runtime-Dq5-PRKT.js +2 -0
  44. package/dist/{provider-DfQJX3z5.js → provider-DlK_ynqt.js} +1131 -2021
  45. package/dist/{provider-session.runtime-Bo88k0pV.js → provider-session.runtime-CvvphHvs.js} +3 -3
  46. package/dist/provider.runtime-CzKGRiAF.js +2 -0
  47. package/dist/realtime-session.runtime-ysbMG8v7.js +1351 -0
  48. package/dist/{resolve-allowlist-common-DHERApxi.js → resolve-allowlist-common-DIVXbD1P.js} +3 -3
  49. package/dist/{resolve-channels-BjepAj8b.js → resolve-channels-CGeUoIqb.js} +4 -4
  50. package/dist/{resolve-users-Bc28htgt.js → resolve-users-BtKxLUZv.js} +3 -3
  51. package/dist/{chunk-DX4jpFQP.js → retry-DNsVTeTo.js} +308 -131
  52. package/dist/{runtime-BmW_j_hl.js → runtime-CQovMsH3.js} +12 -15
  53. package/dist/{runtime-_aRC6V2s.js → runtime-D71_VFLr.js} +49 -58
  54. package/dist/runtime-api.actions.js +2 -2
  55. package/dist/runtime-api.js +23 -23
  56. package/dist/runtime-api.lookup.js +5 -5
  57. package/dist/runtime-api.monitor-CzeTYF32.js +6 -0
  58. package/dist/runtime-api.monitor.js +6 -5
  59. package/dist/runtime-api.send.js +6 -6
  60. package/dist/runtime-api.threads.js +5 -6
  61. package/dist/sdk-runtime-37OU6_Yh.js +369 -0
  62. package/dist/{secret-config-contract-B1akrlyY.js → secret-config-contract-B3i6WxV5.js} +53 -25
  63. package/dist/secret-contract-api.js +1 -1
  64. package/dist/security-audit-contract-api.js +1 -1
  65. package/dist/{security-audit.runtime-CPN0xFYz.js → security-audit.runtime-BVKF9VtY.js} +1 -1
  66. package/dist/{send-CdkZ6zeW.js → send-rQIffSYu.js} +180 -91
  67. package/dist/{send.components-5uqwkjgE.js → send.components-ChK1wS7w.js} +32 -46
  68. package/dist/{send.outbound-D-80Ej-t.js → send.outbound-HIkgji_7.js} +57 -34
  69. package/dist/{send.reactions-CtlmGd_o.js → send.reactions-gmJ6yFPo.js} +14 -21
  70. package/dist/{send.receipt-CuwRrpFz.js → send.receipt-Cnhoautb.js} +29 -1
  71. package/dist/{send.shared-jpvAG_u6.js → send.shared-B3fpaLWJ.js} +112 -181
  72. package/dist/{sender-identity-mG_zsdox.js → sender-identity-BJtfyise.js} +1 -1
  73. package/dist/setup-entry.js +0 -5
  74. package/dist/setup-plugin-api.js +1 -1
  75. package/dist/{shared-CXF1tup1.js → shared-CaAaoksy.js} +27 -23
  76. package/dist/subagent-hooks-CNT2ZJTJ.js +49 -0
  77. package/dist/subagent-hooks-api.js +2 -6
  78. package/dist/subagent-progress-FPLqBY1s.js +110 -0
  79. package/dist/{system-events-DdUqf91B.js → system-events-Nuwoq_au.js} +2 -2
  80. package/dist/{target-resolver-C3s_2m0t.js → target-resolver-DIXShHaZ.js} +3 -3
  81. package/dist/targets-B2pf49zc.js +3 -0
  82. package/dist/{thread-bindings-C-M-ly7P.js → thread-bindings-VlymUnbz.js} +29 -28
  83. package/dist/{thread-bindings.manager-DYvSlrva.js → thread-bindings.manager-CngsgErq.js} +258 -29
  84. package/dist/{thread-bindings.session-updates-DAIlp7Px.js → thread-bindings.session-updates-CJb-BpPL.js} +1 -1
  85. package/dist/{thread-bindings.state-Cgi5uRn-.js → thread-bindings.state-D8OMdk4O.js} +3 -16
  86. package/dist/threading-DU6pgeGm.js +456 -0
  87. package/dist/transcripts-source-DeIMNbRh.js +265 -0
  88. package/dist/transcripts-source-api.js +7 -2
  89. package/dist/{typing--Mzo2kM7.js → typing-oLiS5Z13.js} +1 -1
  90. package/dist/voice-runtime-CjNFaynA.js +2549 -0
  91. package/openclaw.plugin.json +215 -25
  92. package/package.json +15 -11
  93. package/skills/discord/SKILL.md +22 -115
  94. package/dist/accounts-DJTf1LtA.js +0 -219
  95. package/dist/channel-api-CAJ0wMoV.js +0 -21
  96. package/dist/legacy-state-migrations-api.js +0 -138
  97. package/dist/manager.runtime-Bjav3pfC.js +0 -3655
  98. package/dist/preflight-audio.runtime-CoCXMM8r.js +0 -7
  99. package/dist/probe.runtime-DqFGFMbZ.js +0 -2
  100. package/dist/provider.runtime-Cy7XZmyh.js +0 -2
  101. package/dist/runtime-api.monitor-CCRubd3-.js +0 -5
  102. package/dist/session-binding-contract-api.js +0 -2
  103. package/dist/subagent-hooks-Dxy7Fmnq.js +0 -120
  104. package/dist/subagent-progress-DI3sYLLo.js +0 -664
  105. package/dist/targets-Dv_RN7vT.js +0 -3
  106. package/dist/thread-bindings.discord-api-BoDNqamb.js +0 -246
  107. package/dist/transcripts-source-DIKGsTGT.js +0 -123
  108. package/node_modules/p-map/index.d.ts +0 -155
  109. package/node_modules/p-map/index.js +0 -285
  110. package/node_modules/p-map/license +0 -9
  111. package/node_modules/p-map/package.json +0 -57
  112. package/node_modules/p-map/readme.md +0 -190
  113. package/dist/{audit-core-xwjIczO0.js → audit-core-BCX8UeFH.js} +1 -1
  114. package/dist/{security-audit-jGnJF__m.js → security-audit-BfJhAXZp.js} +1 -1
@@ -1,219 +0,0 @@
1
- import { createAccountActionGate, createAccountListHelpers } from "openclaw/plugin-sdk/account-helpers";
2
- import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
3
- import { mapAllowFromEntries, normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
4
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1, resolveAccountEntry } from "openclaw/plugin-sdk/routing";
5
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
- import { getRuntimeConfigSnapshot, getRuntimeConfigSourceSnapshot, selectApplicableRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
7
- import { normalizeResolvedSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
8
- //#region extensions/discord/src/runtime-config.ts
9
- function selectDiscordRuntimeConfig(inputConfig) {
10
- return selectApplicableRuntimeConfig({
11
- inputConfig,
12
- runtimeConfig: getRuntimeConfigSnapshot(),
13
- runtimeSourceConfig: getRuntimeConfigSourceSnapshot()
14
- }) ?? inputConfig;
15
- }
16
- //#endregion
17
- //#region extensions/discord/src/token.ts
18
- function stripDiscordBotPrefix(token) {
19
- return token.replace(/^Bot\s+/i, "");
20
- }
21
- function normalizeDiscordToken(raw, path) {
22
- const trimmed = normalizeResolvedSecretInputString({
23
- value: raw,
24
- path
25
- });
26
- if (!trimmed) return;
27
- return stripDiscordBotPrefix(trimmed);
28
- }
29
- function resolveDiscordTokenValue(params) {
30
- const resolved = resolveSecretInputString({
31
- value: params.value,
32
- path: params.path,
33
- defaults: params.cfg.secrets?.defaults,
34
- mode: "inspect"
35
- });
36
- if (resolved.status === "available") return {
37
- status: "available",
38
- value: stripDiscordBotPrefix(resolved.value)
39
- };
40
- if (resolved.status === "configured_unavailable") return { status: "configured_unavailable" };
41
- return { status: "missing" };
42
- }
43
- function resolveDiscordToken(cfg, opts = {}) {
44
- const selectedCfg = selectDiscordRuntimeConfig(cfg);
45
- const accountId = normalizeAccountId$1(opts.accountId);
46
- const discordCfg = selectedCfg?.channels?.discord;
47
- const accountCfg = resolveAccountEntry(discordCfg?.accounts, accountId);
48
- const hasAccountToken = Boolean(accountCfg && Object.hasOwn(accountCfg, "token"));
49
- const accountToken = resolveDiscordTokenValue({
50
- cfg: selectedCfg,
51
- value: accountCfg?.token,
52
- path: `channels.discord.accounts.${accountId}.token`
53
- });
54
- if (accountToken.status === "available" && accountToken.value) return {
55
- token: accountToken.value,
56
- source: "config",
57
- tokenStatus: "available"
58
- };
59
- if (accountToken.status === "configured_unavailable") return {
60
- token: "",
61
- source: "config",
62
- tokenStatus: "configured_unavailable"
63
- };
64
- if (hasAccountToken) return {
65
- token: "",
66
- source: "none",
67
- tokenStatus: "missing"
68
- };
69
- const configToken = resolveDiscordTokenValue({
70
- cfg: selectedCfg,
71
- value: discordCfg?.token,
72
- path: "channels.discord.token"
73
- });
74
- if (configToken.status === "available" && configToken.value) return {
75
- token: configToken.value,
76
- source: "config",
77
- tokenStatus: "available"
78
- };
79
- if (configToken.status === "configured_unavailable") return {
80
- token: "",
81
- source: "config",
82
- tokenStatus: "configured_unavailable"
83
- };
84
- const envToken = accountId === DEFAULT_ACCOUNT_ID$1 ? normalizeDiscordToken(opts.envToken ?? process.env.DISCORD_BOT_TOKEN, "DISCORD_BOT_TOKEN") : void 0;
85
- if (envToken) return {
86
- token: envToken,
87
- source: "env",
88
- tokenStatus: "available"
89
- };
90
- return {
91
- token: "",
92
- source: "none",
93
- tokenStatus: "missing"
94
- };
95
- }
96
- //#endregion
97
- //#region extensions/discord/src/accounts.ts
98
- const { listAccountIds, resolveDefaultAccountId, resolveAccountConfig: resolveMergedDiscordAccountConfig } = createAccountListHelpers("discord", {
99
- implicitDefaultAccount: {
100
- channelKeys: ["token"],
101
- envVars: ["DISCORD_BOT_TOKEN"]
102
- },
103
- nestedObjectKeys: [
104
- "activities",
105
- "agentComponents",
106
- "botLoopProtection"
107
- ]
108
- });
109
- const listDiscordAccountIds = listAccountIds;
110
- const resolveDefaultDiscordAccountId = resolveDefaultAccountId;
111
- function resolveDiscordAccountConfig(cfg, accountId) {
112
- return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
113
- }
114
- function mergeDiscordAccountConfig(cfg, accountId) {
115
- return resolveMergedDiscordAccountConfig(cfg, accountId);
116
- }
117
- function resolveDiscordAccountAllowFrom(params) {
118
- const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
119
- const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
120
- const rootConfig = params.cfg.channels?.discord;
121
- const allowFrom = accountConfig?.allowFrom ?? rootConfig?.allowFrom;
122
- return allowFrom ? mapAllowFromEntries(allowFrom) : void 0;
123
- }
124
- function resolveDiscordAccountDmPolicy(params) {
125
- const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
126
- const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
127
- const rootConfig = params.cfg.channels?.discord;
128
- return normalizeChannelDmPolicy(accountConfig?.dmPolicy ?? rootConfig?.dmPolicy ?? "pairing");
129
- }
130
- function createDiscordActionGate(params) {
131
- const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
132
- return createAccountActionGate({
133
- baseActions: params.cfg.channels?.discord?.actions,
134
- accountActions: resolveDiscordAccountConfig(params.cfg, accountId)?.actions
135
- });
136
- }
137
- function resolveDiscordAccount(params) {
138
- const cfg = selectDiscordRuntimeConfig(params.cfg);
139
- const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(cfg));
140
- const baseEnabled = cfg.channels?.discord?.enabled !== false;
141
- const merged = mergeDiscordAccountConfig(cfg, accountId);
142
- const accountEnabled = merged.enabled !== false;
143
- const enabled = baseEnabled && accountEnabled;
144
- const tokenResolution = resolveDiscordToken(cfg, { accountId });
145
- return {
146
- accountId,
147
- enabled,
148
- name: normalizeOptionalString(merged.name),
149
- token: tokenResolution.token,
150
- tokenSource: tokenResolution.source,
151
- tokenStatus: tokenResolution.tokenStatus,
152
- config: merged
153
- };
154
- }
155
- function resolveDiscordMaxLinesPerMessage(params) {
156
- if (typeof params.discordConfig?.maxLinesPerMessage === "number") return params.discordConfig.maxLinesPerMessage;
157
- return resolveDiscordAccount({
158
- cfg: params.cfg,
159
- accountId: params.accountId
160
- }).config.maxLinesPerMessage;
161
- }
162
- function resolveDiscordAccountTokenOwner(params) {
163
- const token = params.token.trim();
164
- if (!token) return;
165
- let owner;
166
- const accountIds = listDiscordAccountIds(params.cfg);
167
- for (const [index, accountId] of accountIds.entries()) {
168
- const account = resolveDiscordAccount({
169
- cfg: params.cfg,
170
- accountId
171
- });
172
- const accountToken = account.token.trim();
173
- if (!account.enabled || accountToken !== token) continue;
174
- const priority = account.tokenSource === "config" ? 2 : account.tokenSource === "env" ? 1 : 0;
175
- if (!owner || priority > owner.priority) {
176
- owner = {
177
- accountId: account.accountId,
178
- priority,
179
- index
180
- };
181
- continue;
182
- }
183
- if (priority === owner.priority && index < owner.index) owner = {
184
- accountId: account.accountId,
185
- priority,
186
- index
187
- };
188
- }
189
- return owner?.accountId;
190
- }
191
- function resolveDiscordDuplicateTokenOwner(params) {
192
- const owner = resolveDiscordAccountTokenOwner({
193
- cfg: params.cfg,
194
- token: params.account.token
195
- });
196
- return owner && owner !== params.account.accountId ? owner : void 0;
197
- }
198
- function isDiscordAccountEnabledForRuntime(account, cfg) {
199
- return account.enabled && !resolveDiscordDuplicateTokenOwner({
200
- cfg,
201
- account
202
- });
203
- }
204
- function resolveDiscordAccountDisabledReason(account, cfg) {
205
- if (!account.enabled) return "disabled";
206
- const owner = resolveDiscordDuplicateTokenOwner({
207
- cfg,
208
- account
209
- });
210
- return owner ? `duplicate bot token; using account "${owner}"` : "disabled";
211
- }
212
- function listEnabledDiscordAccounts(cfg) {
213
- return listDiscordAccountIds(cfg).map((accountId) => resolveDiscordAccount({
214
- cfg,
215
- accountId
216
- })).filter((account) => isDiscordAccountEnabledForRuntime(account, cfg));
217
- }
218
- //#endregion
219
- export { mergeDiscordAccountConfig as a, resolveDiscordAccountAllowFrom as c, resolveDiscordAccountDmPolicy as d, resolveDiscordMaxLinesPerMessage as f, listEnabledDiscordAccounts as i, resolveDiscordAccountConfig as l, resolveDiscordToken as m, isDiscordAccountEnabledForRuntime as n, resolveDefaultDiscordAccountId as o, normalizeDiscordToken as p, listDiscordAccountIds as r, resolveDiscordAccount as s, createDiscordActionGate as t, resolveDiscordAccountDisabledReason as u };
@@ -1,21 +0,0 @@
1
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/account-id";
2
- import { PAIRING_APPROVED_MESSAGE, buildTokenChannelStatusSummary, projectCredentialSnapshotFields, resolveConfiguredFromCredentialStatuses } from "openclaw/plugin-sdk/channel-status";
3
- //#region extensions/discord/src/channel-api.ts
4
- const DISCORD_CHANNEL_META = {
5
- id: "discord",
6
- label: "Discord",
7
- selectionLabel: "Discord (Bot API)",
8
- detailLabel: "Discord Bot",
9
- docsPath: "/channels/discord",
10
- docsLabel: "discord",
11
- blurb: "very well supported right now.",
12
- systemImage: "bubble.left.and.bubble.right",
13
- markdownCapable: true,
14
- preferSessionLookupForAnnounceTarget: true
15
- };
16
- function getChatChannelMeta(id) {
17
- if (id !== DISCORD_CHANNEL_META.id) throw new Error(`Unsupported Discord channel meta lookup: ${id}`);
18
- return DISCORD_CHANNEL_META;
19
- }
20
- //#endregion
21
- export { projectCredentialSnapshotFields as a, getChatChannelMeta as i, PAIRING_APPROVED_MESSAGE as n, resolveConfiguredFromCredentialStatuses as o, buildTokenChannelStatusSummary as r, DEFAULT_ACCOUNT_ID$1 as t };
@@ -1,138 +0,0 @@
1
- import { n as DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE, t as DISCORD_COMMAND_DEPLOY_HASH_MAX_ENTRIES } from "./command-deploy-store-DFkBTViB.js";
2
- import { A as toBindingRecordKey, a as THREAD_BINDINGS_MAX_ENTRIES, d as normalizePersistedBinding, o as THREAD_BINDINGS_NAMESPACE } from "./thread-bindings.state-Cgi5uRn-.js";
3
- import { i as timestampMs, r as sanitizeRecentModels, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-D25pnCOu.js";
4
- import { MAX_DATE_TIMESTAMP_MS, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
5
- import path from "node:path";
6
- import fs from "node:fs";
7
- //#region extensions/discord/src/monitor/model-picker-preferences-migrations.ts
8
- const PREFERENCE_MAX_ENTRIES = 2e3;
9
- const MAX_PLUGIN_STATE_KEY_BYTES = 512;
10
- const textEncoder = new TextEncoder();
11
- function fileExists(filePath) {
12
- try {
13
- return fs.statSync(filePath).isFile();
14
- } catch {
15
- return false;
16
- }
17
- }
18
- function readLegacyStore(filePath) {
19
- try {
20
- const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
21
- return parsed && typeof parsed === "object" ? parsed : null;
22
- } catch {
23
- return null;
24
- }
25
- }
26
- function readLegacyThreadBindingsStore(filePath) {
27
- const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
28
- if (!parsed || typeof parsed !== "object") throw new Error("legacy Discord thread bindings store must be an object");
29
- return parsed;
30
- }
31
- function normalizeLegacyPreferenceKey(key) {
32
- const trimmed = key.trim();
33
- if (!trimmed || textEncoder.encode(trimmed).length > MAX_PLUGIN_STATE_KEY_BYTES) return;
34
- return trimmed;
35
- }
36
- function legacyUpdatedAtForIndex(updatedAt, index, total) {
37
- const baseMs = timestampMs(updatedAt);
38
- return timestampMsToIsoString(Math.min(baseMs + Math.max(0, total), MAX_DATE_TIMESTAMP_MS) - Math.max(0, index)) ?? timestampMsToIsoString(baseMs) ?? timestampMsToIsoString(Math.max(0, total - index)) ?? "1970-01-01T00:00:00.000Z";
39
- }
40
- function readFiniteNumberField(entry, key) {
41
- const value = entry[key];
42
- return typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : void 0;
43
- }
44
- function upgradeLegacyThreadBindingShape(rawEntry) {
45
- if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) return rawEntry;
46
- const entry = { ...rawEntry };
47
- if (entry.targetSessionKey === void 0 && typeof entry.sessionKey === "string") entry.targetSessionKey = entry.sessionKey;
48
- delete entry.sessionKey;
49
- const expiresAt = readFiniteNumberField(entry, "expiresAt");
50
- delete entry.expiresAt;
51
- if (entry.idleTimeoutMs === void 0 && entry.maxAgeMs === void 0 && expiresAt !== void 0) {
52
- entry.idleTimeoutMs = 0;
53
- if (expiresAt <= 0) entry.maxAgeMs = 0;
54
- else {
55
- const boundAt = readFiniteNumberField(entry, "boundAt") ?? 0;
56
- const lastActivityAt = readFiniteNumberField(entry, "lastActivityAt") ?? 0;
57
- entry.maxAgeMs = Math.max(1, expiresAt - Math.max(0, boundAt > 0 ? boundAt : lastActivityAt));
58
- }
59
- }
60
- return entry;
61
- }
62
- const detectDiscordLegacyStateMigrations = ({ stateDir }) => {
63
- const plans = [];
64
- const commandDeployCacheSourcePath = path.join(stateDir, "discord", "command-deploy-cache.json");
65
- if (fileExists(commandDeployCacheSourcePath)) plans.push({
66
- kind: "plugin-state-import",
67
- label: "Discord command deployment cache",
68
- sourcePath: commandDeployCacheSourcePath,
69
- targetPath: `plugin state:${DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE}`,
70
- pluginId: "discord",
71
- namespace: DISCORD_COMMAND_DEPLOY_HASH_NAMESPACE,
72
- maxEntries: DISCORD_COMMAND_DEPLOY_HASH_MAX_ENTRIES,
73
- scopeKey: "",
74
- cleanupSource: "remove",
75
- cleanupWhenEmpty: true,
76
- readEntries: () => []
77
- });
78
- const modelPickerSourcePath = path.join(stateDir, "discord", "model-picker-preferences.json");
79
- if (fileExists(modelPickerSourcePath)) plans.push({
80
- kind: "plugin-state-import",
81
- label: "Discord model picker preferences",
82
- sourcePath: modelPickerSourcePath,
83
- targetPath: "plugin state:model-picker-preferences",
84
- pluginId: "discord",
85
- namespace: "model-picker-preferences",
86
- maxEntries: PREFERENCE_MAX_ENTRIES,
87
- scopeKey: "",
88
- cleanupSource: "rename",
89
- readEntries: () => {
90
- const store = readLegacyStore(modelPickerSourcePath);
91
- if (!store || !store.entries || typeof store.entries !== "object") return [];
92
- const out = [];
93
- for (const [rawKey, rawEntry] of Object.entries(store.entries)) {
94
- const scopeKey = normalizeLegacyPreferenceKey(rawKey);
95
- if (!scopeKey || !rawEntry || typeof rawEntry !== "object") continue;
96
- const recent = sanitizeRecentModels(rawEntry.recent, 10);
97
- for (const [index, modelRef] of recent.entries()) out.push({
98
- key: buildPreferenceModelKey(scopeKey, modelRef),
99
- value: {
100
- scopeKey,
101
- modelRef,
102
- updatedAt: legacyUpdatedAtForIndex(rawEntry.updatedAt, index, recent.length)
103
- }
104
- });
105
- }
106
- return out;
107
- }
108
- });
109
- const threadBindingsSourcePath = path.join(stateDir, "discord", "thread-bindings.json");
110
- if (fileExists(threadBindingsSourcePath)) plans.push({
111
- kind: "plugin-state-import",
112
- label: "Discord thread bindings",
113
- sourcePath: threadBindingsSourcePath,
114
- targetPath: `plugin state:${THREAD_BINDINGS_NAMESPACE}`,
115
- pluginId: "discord",
116
- namespace: THREAD_BINDINGS_NAMESPACE,
117
- maxEntries: THREAD_BINDINGS_MAX_ENTRIES,
118
- scopeKey: "",
119
- cleanupSource: "rename",
120
- cleanupWhenEmpty: true,
121
- readEntries: () => {
122
- const store = readLegacyThreadBindingsStore(threadBindingsSourcePath);
123
- if (store?.version !== 1 || !store.bindings || typeof store.bindings !== "object") throw new Error("legacy Discord thread bindings store must have version 1 bindings");
124
- const out = [];
125
- for (const [rawKey, rawEntry] of Object.entries(store.bindings)) {
126
- const normalized = normalizePersistedBinding(rawKey, upgradeLegacyThreadBindingShape(rawEntry));
127
- if (normalized) out.push({
128
- key: toBindingRecordKey(normalized),
129
- value: normalized
130
- });
131
- }
132
- return out;
133
- }
134
- });
135
- return plans;
136
- };
137
- //#endregion
138
- export { detectDiscordLegacyStateMigrations };