@openclaw/irc 2026.8.1-beta.3 → 2026.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +1 -1
- package/dist/{channel-BO1GdA4V.js → channel-BVYDQ8Fk.js} +261 -112
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-runtime-CSpBc1ef.js → channel-runtime-Ywcn0k9_.js} +7 -76
- package/dist/{config-schema-DdB_h5mL.js → config-schema-DcYE4WjJ.js} +7 -5
- package/dist/doctor-contract-api.js +34 -4
- package/openclaw.plugin.json +40 -12
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { _ as listIrcAccountIds, g as listEnabledIrcAccounts, n as ircSetupWizard, r as ircSetupAdapter, t as ircPlugin, v as resolveDefaultIrcAccountId, y as resolveIrcAccount } from "./channel-BVYDQ8Fk.js";
|
|
2
2
|
import { n as setIrcRuntime } from "./runtime-xy-FcjJC.js";
|
|
3
3
|
export { ircPlugin, ircSetupAdapter, ircSetupWizard, listEnabledIrcAccounts, listIrcAccountIds, resolveDefaultIrcAccountId, resolveIrcAccount, setIrcRuntime };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { t as IrcChannelConfigSchema } from "./config-schema-
|
|
1
|
+
import { t as IrcChannelConfigSchema } from "./config-schema-DcYE4WjJ.js";
|
|
2
2
|
import { t as getIrcRuntime } from "./runtime-xy-FcjJC.js";
|
|
3
3
|
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-D_DC3YWj.js";
|
|
4
4
|
import { createAccountListHelpers, describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
5
5
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
6
6
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
7
7
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, parseOptionalDelimitedEntries } from "openclaw/plugin-sdk/channel-core";
|
|
8
|
+
import { defineStableChannelIngressIdentity, identityEntryAuthenticationClassifier } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
8
9
|
import { buildMutableAllowEntryDetector, collectStandardAllowlistLists, createAllowlistProviderOpenWarningCollector, createConditionalWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, resolveScopeKeyCaseInsensitive, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
|
|
9
10
|
import { createChannelDirectoryAdapter, createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-runtime";
|
|
10
11
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
@@ -16,9 +17,10 @@ import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
|
|
|
16
17
|
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
17
18
|
import { resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
18
19
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringifiedOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
|
-
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
20
|
+
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, createReplyToFanout, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
20
21
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
21
22
|
import { chunkTextForOutbound, convertMarkdownTables, sanitizeAssistantVisibleText, stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
|
|
23
|
+
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
22
24
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
23
25
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
24
26
|
import net from "node:net";
|
|
@@ -187,9 +189,12 @@ function listEnabledIrcAccounts(cfg) {
|
|
|
187
189
|
accountId
|
|
188
190
|
})).filter((account) => account.enabled);
|
|
189
191
|
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region extensions/irc/src/doctor.ts
|
|
194
|
+
const isIrcMutableAllowEntry = buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:irc|user):)*[^@]*@/i });
|
|
190
195
|
const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
|
|
191
196
|
channel: "irc",
|
|
192
|
-
detector:
|
|
197
|
+
detector: isIrcMutableAllowEntry,
|
|
193
198
|
collectLists: (scope) => collectStandardAllowlistLists(scope, {
|
|
194
199
|
includeGroups: true,
|
|
195
200
|
groupField: "allowFrom"
|
|
@@ -197,7 +202,7 @@ const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAll
|
|
|
197
202
|
});
|
|
198
203
|
//#endregion
|
|
199
204
|
//#region extensions/irc/src/gateway.ts
|
|
200
|
-
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
205
|
+
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-Ywcn0k9_.js"));
|
|
201
206
|
async function startIrcGatewayAccount(ctx) {
|
|
202
207
|
const account = ctx.account;
|
|
203
208
|
const statusSink = createAccountStatusSink({
|
|
@@ -236,8 +241,158 @@ function stripIrcControlChars(value) {
|
|
|
236
241
|
return out;
|
|
237
242
|
}
|
|
238
243
|
//#endregion
|
|
239
|
-
//#region extensions/irc/src/
|
|
244
|
+
//#region extensions/irc/src/normalize.ts
|
|
240
245
|
const IRC_TARGET_PATTERN$1 = /^[^\s:]+$/u;
|
|
246
|
+
function isChannelTarget(target) {
|
|
247
|
+
return target.startsWith("#") || target.startsWith("&");
|
|
248
|
+
}
|
|
249
|
+
function normalizeIrcMessagingTarget(raw) {
|
|
250
|
+
const trimmed = raw.trim();
|
|
251
|
+
if (!trimmed) return;
|
|
252
|
+
let target = trimmed;
|
|
253
|
+
if (normalizeLowercaseStringOrEmpty(target).startsWith("irc:")) target = target.slice(4).trim();
|
|
254
|
+
if (normalizeLowercaseStringOrEmpty(target).startsWith("channel:")) {
|
|
255
|
+
target = target.slice(8).trim();
|
|
256
|
+
if (!target.startsWith("#") && !target.startsWith("&")) target = `#${target}`;
|
|
257
|
+
}
|
|
258
|
+
if (normalizeLowercaseStringOrEmpty(target).startsWith("user:")) target = target.slice(5).trim();
|
|
259
|
+
if (!target || !looksLikeIrcTargetId(target)) return;
|
|
260
|
+
return target;
|
|
261
|
+
}
|
|
262
|
+
function resolveIrcOutboundSessionRoute(params) {
|
|
263
|
+
const target = normalizeIrcMessagingTarget(params.target);
|
|
264
|
+
if (!target) return null;
|
|
265
|
+
const chatType = isChannelTarget(target) ? "group" : "direct";
|
|
266
|
+
return buildChannelOutboundSessionRoute({
|
|
267
|
+
cfg: params.cfg,
|
|
268
|
+
agentId: params.agentId,
|
|
269
|
+
channel: "irc",
|
|
270
|
+
accountId: params.accountId,
|
|
271
|
+
recipientSessionExact: chatType === "direct" ? "direct-alias" : false,
|
|
272
|
+
peer: {
|
|
273
|
+
kind: chatType,
|
|
274
|
+
id: target
|
|
275
|
+
},
|
|
276
|
+
chatType,
|
|
277
|
+
from: `irc:${target}`,
|
|
278
|
+
to: target
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function looksLikeIrcTargetId(raw) {
|
|
282
|
+
const trimmed = raw.trim();
|
|
283
|
+
if (!trimmed) return false;
|
|
284
|
+
if (hasIrcControlChars(trimmed)) return false;
|
|
285
|
+
return IRC_TARGET_PATTERN$1.test(trimmed);
|
|
286
|
+
}
|
|
287
|
+
function normalizeIrcAllowEntry(raw) {
|
|
288
|
+
let value = normalizeLowercaseStringOrEmpty(raw);
|
|
289
|
+
if (!value) return "";
|
|
290
|
+
if (value.startsWith("irc:")) value = value.slice(4);
|
|
291
|
+
if (value.startsWith("user:")) value = value.slice(5);
|
|
292
|
+
return value.trim();
|
|
293
|
+
}
|
|
294
|
+
function buildIrcAllowlistCandidates(message, params) {
|
|
295
|
+
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
296
|
+
const user = normalizeOptionalLowercaseString(message.senderUser);
|
|
297
|
+
const host = normalizeOptionalLowercaseString(message.senderHost);
|
|
298
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
299
|
+
if (nick && params?.allowNameMatching === true) candidates.add(nick);
|
|
300
|
+
if (nick && user) candidates.add(`${nick}!${user}`);
|
|
301
|
+
if (nick && host) candidates.add(`${nick}@${host}`);
|
|
302
|
+
if (nick && user && host) candidates.add(`${nick}!${user}@${host}`);
|
|
303
|
+
return [...candidates];
|
|
304
|
+
}
|
|
305
|
+
const ircIngressIdentity = defineStableChannelIngressIdentity({
|
|
306
|
+
key: "irc-id",
|
|
307
|
+
authentication: "asserted",
|
|
308
|
+
normalizeEntry: normalizeIrcStableEntry,
|
|
309
|
+
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
310
|
+
sensitivity: "pii",
|
|
311
|
+
aliases: [
|
|
312
|
+
{
|
|
313
|
+
key: "irc-id-nick-user",
|
|
314
|
+
kind: "stable-id",
|
|
315
|
+
normalizeEntry: normalizeIrcNickUserEntry,
|
|
316
|
+
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
317
|
+
authentication: "mutable",
|
|
318
|
+
sensitivity: "pii"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
key: "irc-id-nick-host",
|
|
322
|
+
kind: "stable-id",
|
|
323
|
+
authentication: "asserted",
|
|
324
|
+
normalizeEntry: normalizeIrcNickHostEntry,
|
|
325
|
+
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
326
|
+
sensitivity: "pii"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
key: "irc-nick",
|
|
330
|
+
kind: "plugin:irc-nick",
|
|
331
|
+
normalizeEntry: normalizeIrcNickEntry,
|
|
332
|
+
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
333
|
+
authentication: "mutable",
|
|
334
|
+
sensitivity: "pii"
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
isWildcardEntry: (entry) => normalizeIrcAllowEntry(entry) === "*",
|
|
338
|
+
resolveEntryId: ({ entryIndex, fieldKey }) => `irc-entry-${entryIndex + 1}:${fieldKey === "irc-nick" ? "nick" : "id"}`
|
|
339
|
+
});
|
|
340
|
+
function isBareNick(value) {
|
|
341
|
+
return !value.includes("!") && !value.includes("@");
|
|
342
|
+
}
|
|
343
|
+
function hasVerifiedHost(value) {
|
|
344
|
+
return value.includes("@");
|
|
345
|
+
}
|
|
346
|
+
function isHostlessNickUser(value) {
|
|
347
|
+
return value.includes("!") && !value.includes("@");
|
|
348
|
+
}
|
|
349
|
+
function normalizeIrcStableEntry(value) {
|
|
350
|
+
const normalized = normalizeIrcAllowEntry(value);
|
|
351
|
+
if (!normalized.includes("!") || !hasVerifiedHost(normalized)) return null;
|
|
352
|
+
return normalized;
|
|
353
|
+
}
|
|
354
|
+
function normalizeIrcNickHostEntry(value) {
|
|
355
|
+
const normalized = normalizeIrcAllowEntry(value);
|
|
356
|
+
return !normalized.includes("!") && hasVerifiedHost(normalized) ? normalized : null;
|
|
357
|
+
}
|
|
358
|
+
function normalizeIrcNickUserEntry(value) {
|
|
359
|
+
const normalized = normalizeIrcAllowEntry(value);
|
|
360
|
+
if (!normalized || normalized === "*" || !isHostlessNickUser(normalized)) return null;
|
|
361
|
+
return normalized;
|
|
362
|
+
}
|
|
363
|
+
function normalizeIrcNickEntry(value) {
|
|
364
|
+
const normalized = normalizeIrcAllowEntry(value);
|
|
365
|
+
if (!normalized || normalized === "*" || !isBareNick(normalized)) return null;
|
|
366
|
+
return normalized;
|
|
367
|
+
}
|
|
368
|
+
function createIrcIngressSubject(message) {
|
|
369
|
+
const candidates = buildIrcAllowlistCandidates(message, { allowNameMatching: true });
|
|
370
|
+
const stableCandidates = candidates.filter((candidate) => hasVerifiedHost(candidate));
|
|
371
|
+
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
372
|
+
return {
|
|
373
|
+
stableId: stableCandidates[stableCandidates.length - 1] ?? nick,
|
|
374
|
+
aliases: {
|
|
375
|
+
"irc-id-nick-user": candidates.find((candidate) => isHostlessNickUser(candidate)),
|
|
376
|
+
"irc-id-nick-host": stableCandidates.find((candidate) => !candidate.includes("!") && candidate.includes("@")),
|
|
377
|
+
"irc-nick": nick
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region extensions/irc/src/outbound-base.ts
|
|
383
|
+
function sanitizeIrcAssistantText(text) {
|
|
384
|
+
return sanitizeForPlainText(sanitizeAssistantVisibleText(text));
|
|
385
|
+
}
|
|
386
|
+
const ircOutboundBaseAdapter = {
|
|
387
|
+
deliveryMode: "direct",
|
|
388
|
+
chunker: chunkTextForOutbound,
|
|
389
|
+
chunkerMode: "markdown",
|
|
390
|
+
textChunkLimit: 350,
|
|
391
|
+
sanitizeText: ({ text }) => sanitizeIrcAssistantText(text)
|
|
392
|
+
};
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region extensions/irc/src/protocol.ts
|
|
395
|
+
const IRC_TARGET_PATTERN = /^[^\s:]+$/u;
|
|
241
396
|
function parseIrcLine(line) {
|
|
242
397
|
const raw = line.replace(/[\r\n]+/g, "").trim();
|
|
243
398
|
if (!raw) return null;
|
|
@@ -316,7 +471,7 @@ function sanitizeIrcTarget(raw) {
|
|
|
316
471
|
if (!decoded) throw new Error("IRC target is required");
|
|
317
472
|
if (decoded !== decoded.trim()) throw new Error(`Invalid IRC target: ${raw}`);
|
|
318
473
|
if (hasIrcControlChars(decoded)) throw new Error(`Invalid IRC target: ${raw}`);
|
|
319
|
-
if (!IRC_TARGET_PATTERN
|
|
474
|
+
if (!IRC_TARGET_PATTERN.test(decoded)) throw new Error(`Invalid IRC target: ${raw}`);
|
|
320
475
|
return decoded;
|
|
321
476
|
}
|
|
322
477
|
function makeIrcMessageId() {
|
|
@@ -648,68 +803,6 @@ function buildIrcConnectOptions(account, overrides = {}) {
|
|
|
648
803
|
};
|
|
649
804
|
}
|
|
650
805
|
//#endregion
|
|
651
|
-
//#region extensions/irc/src/normalize.ts
|
|
652
|
-
const IRC_TARGET_PATTERN = /^[^\s:]+$/u;
|
|
653
|
-
function isChannelTarget(target) {
|
|
654
|
-
return target.startsWith("#") || target.startsWith("&");
|
|
655
|
-
}
|
|
656
|
-
function normalizeIrcMessagingTarget(raw) {
|
|
657
|
-
const trimmed = raw.trim();
|
|
658
|
-
if (!trimmed) return;
|
|
659
|
-
let target = trimmed;
|
|
660
|
-
if (normalizeLowercaseStringOrEmpty(target).startsWith("irc:")) target = target.slice(4).trim();
|
|
661
|
-
if (normalizeLowercaseStringOrEmpty(target).startsWith("channel:")) {
|
|
662
|
-
target = target.slice(8).trim();
|
|
663
|
-
if (!target.startsWith("#") && !target.startsWith("&")) target = `#${target}`;
|
|
664
|
-
}
|
|
665
|
-
if (normalizeLowercaseStringOrEmpty(target).startsWith("user:")) target = target.slice(5).trim();
|
|
666
|
-
if (!target || !looksLikeIrcTargetId(target)) return;
|
|
667
|
-
return target;
|
|
668
|
-
}
|
|
669
|
-
function resolveIrcOutboundSessionRoute(params) {
|
|
670
|
-
const target = normalizeIrcMessagingTarget(params.target);
|
|
671
|
-
if (!target) return null;
|
|
672
|
-
const chatType = isChannelTarget(target) ? "group" : "direct";
|
|
673
|
-
return buildChannelOutboundSessionRoute({
|
|
674
|
-
cfg: params.cfg,
|
|
675
|
-
agentId: params.agentId,
|
|
676
|
-
channel: "irc",
|
|
677
|
-
accountId: params.accountId,
|
|
678
|
-
recipientSessionExact: chatType === "direct" ? "direct-alias" : false,
|
|
679
|
-
peer: {
|
|
680
|
-
kind: chatType,
|
|
681
|
-
id: target
|
|
682
|
-
},
|
|
683
|
-
chatType,
|
|
684
|
-
from: `irc:${target}`,
|
|
685
|
-
to: target
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
function looksLikeIrcTargetId(raw) {
|
|
689
|
-
const trimmed = raw.trim();
|
|
690
|
-
if (!trimmed) return false;
|
|
691
|
-
if (hasIrcControlChars(trimmed)) return false;
|
|
692
|
-
return IRC_TARGET_PATTERN.test(trimmed);
|
|
693
|
-
}
|
|
694
|
-
function normalizeIrcAllowEntry(raw) {
|
|
695
|
-
let value = normalizeLowercaseStringOrEmpty(raw);
|
|
696
|
-
if (!value) return "";
|
|
697
|
-
if (value.startsWith("irc:")) value = value.slice(4);
|
|
698
|
-
if (value.startsWith("user:")) value = value.slice(5);
|
|
699
|
-
return value.trim();
|
|
700
|
-
}
|
|
701
|
-
function buildIrcAllowlistCandidates(message, params) {
|
|
702
|
-
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
703
|
-
const user = normalizeOptionalLowercaseString(message.senderUser);
|
|
704
|
-
const host = normalizeOptionalLowercaseString(message.senderHost);
|
|
705
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
706
|
-
if (nick && params?.allowNameMatching === true) candidates.add(nick);
|
|
707
|
-
if (nick && user) candidates.add(`${nick}!${user}`);
|
|
708
|
-
if (nick && host) candidates.add(`${nick}@${host}`);
|
|
709
|
-
if (nick && user && host) candidates.add(`${nick}!${user}@${host}`);
|
|
710
|
-
return [...candidates];
|
|
711
|
-
}
|
|
712
|
-
//#endregion
|
|
713
806
|
//#region extensions/irc/src/send.ts
|
|
714
807
|
function recordIrcOutboundActivity(accountId) {
|
|
715
808
|
try {
|
|
@@ -729,7 +822,7 @@ function resolveTarget(to, opts) {
|
|
|
729
822
|
if (fromOpt) return fromOpt;
|
|
730
823
|
throw new Error(`Invalid IRC target: ${to}`);
|
|
731
824
|
}
|
|
732
|
-
async function
|
|
825
|
+
async function sendIrcMessages(to, messages, opts, onDeliveryResult) {
|
|
733
826
|
const cfg = requireRuntimeConfig(opts.cfg, "IRC send");
|
|
734
827
|
const account = resolveIrcAccount({
|
|
735
828
|
cfg,
|
|
@@ -742,37 +835,66 @@ async function sendMessageIrc(to, text, opts) {
|
|
|
742
835
|
channel: "irc",
|
|
743
836
|
accountId: account.accountId
|
|
744
837
|
});
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
838
|
+
const preparedMessages = messages.map((message) => {
|
|
839
|
+
const prepared = stripMarkdown(convertMarkdownTables(message.text.trim(), tableMode));
|
|
840
|
+
if (!prepared.trim()) throw new Error("Message must be non-empty for IRC sends");
|
|
841
|
+
return {
|
|
842
|
+
payload: message.replyTo ? `${prepared}\n\n[reply:${message.replyTo}]` : prepared,
|
|
843
|
+
replyTo: message.replyTo
|
|
844
|
+
};
|
|
845
|
+
});
|
|
846
|
+
if (preparedMessages.length === 0) return [];
|
|
847
|
+
opts.abortSignal?.throwIfAborted();
|
|
848
|
+
let transient;
|
|
849
|
+
const client = opts.client?.isReady() ? opts.client : transient = await connectIrcClient(buildIrcConnectOptions(account, {
|
|
850
|
+
connectTimeoutMs: 12e3,
|
|
851
|
+
abortSignal: opts.abortSignal
|
|
852
|
+
}));
|
|
853
|
+
const results = [];
|
|
854
|
+
try {
|
|
855
|
+
opts.abortSignal?.throwIfAborted();
|
|
856
|
+
if (transient && (target.startsWith("#") || target.startsWith("&"))) client.join(target);
|
|
857
|
+
for (const message of preparedMessages) {
|
|
858
|
+
opts.abortSignal?.throwIfAborted();
|
|
859
|
+
if (!client.isReady()) throw new Error("IRC connection closed before send");
|
|
860
|
+
await opts.onPlatformSendDispatch?.();
|
|
861
|
+
opts.abortSignal?.throwIfAborted();
|
|
862
|
+
if (!client.isReady()) throw new Error("IRC connection closed before send");
|
|
863
|
+
client.sendPrivmsg(target, message.payload);
|
|
864
|
+
recordIrcOutboundActivity(account.accountId);
|
|
865
|
+
const messageId = makeIrcMessageId();
|
|
866
|
+
const result = {
|
|
764
867
|
messageId,
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
868
|
+
target,
|
|
869
|
+
receipt: createMessageReceiptFromOutboundResults({
|
|
870
|
+
results: [{
|
|
871
|
+
channel: "irc",
|
|
872
|
+
messageId,
|
|
873
|
+
conversationId: target
|
|
874
|
+
}],
|
|
875
|
+
kind: "text",
|
|
876
|
+
...message.replyTo ? { replyToId: message.replyTo } : {}
|
|
877
|
+
})
|
|
878
|
+
};
|
|
879
|
+
results.push(result);
|
|
880
|
+
await onDeliveryResult?.(result);
|
|
881
|
+
}
|
|
882
|
+
return results;
|
|
883
|
+
} finally {
|
|
884
|
+
transient?.quit("sent");
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
async function sendMessageIrc(to, text, opts) {
|
|
888
|
+
const result = (await sendIrcMessages(to, [{
|
|
889
|
+
text,
|
|
890
|
+
...opts.replyTo ? { replyTo: opts.replyTo } : {}
|
|
891
|
+
}], opts))[0];
|
|
892
|
+
if (!result) throw new Error("Message must be non-empty for IRC sends");
|
|
893
|
+
return result;
|
|
771
894
|
}
|
|
772
895
|
//#endregion
|
|
773
896
|
//#region extensions/irc/src/message-adapter.ts
|
|
774
|
-
|
|
775
|
-
const { target, ...result } = await sendMessageIrc(...args);
|
|
897
|
+
function toIrcMessageResult({ target, ...result }) {
|
|
776
898
|
return {
|
|
777
899
|
...result,
|
|
778
900
|
target: {
|
|
@@ -781,6 +903,40 @@ async function sendIrcMessage(...args) {
|
|
|
781
903
|
}
|
|
782
904
|
};
|
|
783
905
|
}
|
|
906
|
+
async function sendIrcMessage(...args) {
|
|
907
|
+
return toIrcMessageResult(await sendMessageIrc(...args));
|
|
908
|
+
}
|
|
909
|
+
const sendFormattedIrcText = async (ctx) => {
|
|
910
|
+
const { chunkMarkdownTextWithMode, resolveChunkMode, resolveTextChunkLimit } = await import("openclaw/plugin-sdk/reply-chunking");
|
|
911
|
+
const accountId = ctx.accountId ?? void 0;
|
|
912
|
+
const textLimit = ctx.formatting?.textLimit ?? resolveTextChunkLimit(ctx.cfg, "irc", accountId, { fallbackLimit: ircOutboundBaseAdapter.textChunkLimit });
|
|
913
|
+
const chunkMode = ctx.formatting?.chunkMode ?? resolveChunkMode(ctx.cfg, "irc", accountId);
|
|
914
|
+
const chunkText = (text) => ctx.formatting ? ircOutboundBaseAdapter.chunker(text, textLimit, { formatting: ctx.formatting }) : ircOutboundBaseAdapter.chunker(text, textLimit);
|
|
915
|
+
let chunks;
|
|
916
|
+
if (chunkMode === "newline") {
|
|
917
|
+
const blocks = chunkMarkdownTextWithMode(ctx.text, textLimit, chunkMode);
|
|
918
|
+
if (blocks.length === 0 && ctx.text) blocks.push(ctx.text);
|
|
919
|
+
chunks = blocks.flatMap((block) => {
|
|
920
|
+
const blockChunks = chunkText(block);
|
|
921
|
+
return blockChunks.length === 0 && block ? [block] : blockChunks;
|
|
922
|
+
});
|
|
923
|
+
} else chunks = chunkText(ctx.text);
|
|
924
|
+
const nextReplyToId = createReplyToFanout(ctx);
|
|
925
|
+
return (await sendIrcMessages(ctx.to, chunks.map((text) => {
|
|
926
|
+
const replyTo = nextReplyToId();
|
|
927
|
+
return replyTo ? {
|
|
928
|
+
text,
|
|
929
|
+
replyTo
|
|
930
|
+
} : { text };
|
|
931
|
+
}), {
|
|
932
|
+
cfg: ctx.cfg,
|
|
933
|
+
accountId,
|
|
934
|
+
abortSignal: ctx.abortSignal,
|
|
935
|
+
onPlatformSendDispatch: ctx.onPlatformSendDispatch
|
|
936
|
+
}, async (result) => {
|
|
937
|
+
await ctx.onDeliveryResult?.(attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
938
|
+
})).map((result) => attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
939
|
+
};
|
|
784
940
|
const ircMessageAdapter = defineChannelMessageAdapter({
|
|
785
941
|
id: "irc",
|
|
786
942
|
durableFinal: { capabilities: {
|
|
@@ -802,18 +958,6 @@ const ircMessageAdapter = defineChannelMessageAdapter({
|
|
|
802
958
|
}
|
|
803
959
|
});
|
|
804
960
|
//#endregion
|
|
805
|
-
//#region extensions/irc/src/outbound-base.ts
|
|
806
|
-
function sanitizeIrcAssistantText(text) {
|
|
807
|
-
return sanitizeForPlainText(sanitizeAssistantVisibleText(text));
|
|
808
|
-
}
|
|
809
|
-
const ircOutboundBaseAdapter = {
|
|
810
|
-
deliveryMode: "direct",
|
|
811
|
-
chunker: chunkTextForOutbound,
|
|
812
|
-
chunkerMode: "markdown",
|
|
813
|
-
textChunkLimit: 350,
|
|
814
|
-
sanitizeText: ({ text }) => sanitizeIrcAssistantText(text)
|
|
815
|
-
};
|
|
816
|
-
//#endregion
|
|
817
961
|
//#region extensions/irc/src/policy.ts
|
|
818
962
|
function resolveIrcGroupScope(params) {
|
|
819
963
|
const { "*": wildcard, ...groups } = params.groups ?? {};
|
|
@@ -1253,7 +1397,8 @@ const ircSetupWizard = {
|
|
|
1253
1397
|
return String(defaultPort);
|
|
1254
1398
|
},
|
|
1255
1399
|
validate: ({ value }) => {
|
|
1256
|
-
const
|
|
1400
|
+
const raw = normalizeStringifiedOptionalString(value) ?? "";
|
|
1401
|
+
const parsed = parseStrictPositiveInteger(raw);
|
|
1257
1402
|
return parsed !== void 0 && parsed <= 65535 ? void 0 : "Use a port between 1 and 65535";
|
|
1258
1403
|
},
|
|
1259
1404
|
normalizeValue: ({ value }) => String(parsePort(value, 6697)),
|
|
@@ -1425,7 +1570,7 @@ const meta = {
|
|
|
1425
1570
|
systemImage: "number",
|
|
1426
1571
|
markdownCapable: true
|
|
1427
1572
|
};
|
|
1428
|
-
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
1573
|
+
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-Ywcn0k9_.js"));
|
|
1429
1574
|
function normalizePairingTarget(raw) {
|
|
1430
1575
|
const normalized = normalizeIrcAllowEntry(raw);
|
|
1431
1576
|
if (!normalized) return "";
|
|
@@ -1479,6 +1624,7 @@ const resolveIrcDmPolicy = createScopedDmSecurityResolver({
|
|
|
1479
1624
|
resolvePolicy: (account) => account.config.dmPolicy,
|
|
1480
1625
|
resolveAllowFrom: (account) => account.config.allowFrom,
|
|
1481
1626
|
policyPathSuffix: "dmPolicy",
|
|
1627
|
+
classifyEntryAuthentication: identityEntryAuthenticationClassifier(ircIngressIdentity),
|
|
1482
1628
|
normalizeEntry: (raw) => normalizeIrcAllowEntry(raw)
|
|
1483
1629
|
});
|
|
1484
1630
|
const collectIrcGroupPolicyWarnings = createAllowlistProviderOpenWarningCollector({
|
|
@@ -1668,7 +1814,10 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1668
1814
|
collectWarnings: collectIrcSecurityWarnings
|
|
1669
1815
|
},
|
|
1670
1816
|
outbound: {
|
|
1671
|
-
base:
|
|
1817
|
+
base: {
|
|
1818
|
+
...ircOutboundBaseAdapter,
|
|
1819
|
+
sendFormattedText: sendFormattedIrcText
|
|
1820
|
+
},
|
|
1672
1821
|
attachedResults: {
|
|
1673
1822
|
channel: "irc",
|
|
1674
1823
|
sendText: ({ onDeliveryResult: _onDeliveryResult, ...ctx }) => ircMessageAdapter.send.text(ctx),
|
|
@@ -1680,4 +1829,4 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1680
1829
|
}
|
|
1681
1830
|
});
|
|
1682
1831
|
//#endregion
|
|
1683
|
-
export {
|
|
1832
|
+
export { listIrcAccountIds as _, resolveIrcGroupRequireMention as a, connectIrcClient as c, sanitizeIrcAssistantText as d, createIrcIngressSubject as f, listEnabledIrcAccounts as g, normalizeIrcAllowEntry as h, resolveIrcGroupMatch as i, parseIrcLine as l, isChannelTarget as m, ircSetupWizard as n, sendMessageIrc as o, ircIngressIdentity as p, ircSetupAdapter as r, buildIrcConnectOptions as s, ircPlugin as t, parseIrcPrefix as u, resolveDefaultIrcAccountId as v, resolveIrcAccount as y };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as IrcChannelConfigSchema } from "./config-schema-
|
|
1
|
+
import { t as IrcChannelConfigSchema } from "./config-schema-DcYE4WjJ.js";
|
|
2
2
|
export { IrcChannelConfigSchema };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ircPlugin } from "./channel-
|
|
1
|
+
import { t as ircPlugin } from "./channel-BVYDQ8Fk.js";
|
|
2
2
|
export { ircPlugin };
|
|
@@ -1,51 +1,18 @@
|
|
|
1
|
-
import { a as resolveIrcGroupRequireMention, c as
|
|
1
|
+
import { a as resolveIrcGroupRequireMention, c as connectIrcClient, d as sanitizeIrcAssistantText, f as createIrcIngressSubject, h as normalizeIrcAllowEntry, i as resolveIrcGroupMatch, l as parseIrcLine, m as isChannelTarget, o as sendMessageIrc, p as ircIngressIdentity, s as buildIrcConnectOptions, u as parseIrcPrefix, y as resolveIrcAccount } from "./channel-BVYDQ8Fk.js";
|
|
2
2
|
import { t as getIrcRuntime } from "./runtime-xy-FcjJC.js";
|
|
3
|
+
import { channelIngressRoutes, createChannelIngressResolver } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
3
4
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
5
|
import { bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
5
6
|
import { randomUUID } from "node:crypto";
|
|
6
7
|
import { resolveLoggerBackedRuntime } from "openclaw/plugin-sdk/extension-shared";
|
|
7
8
|
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
8
9
|
import { logInboundDrop, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
9
|
-
import { channelIngressRoutes, createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
10
10
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
11
11
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
12
12
|
import { deliverFormattedTextWithAttachments } from "openclaw/plugin-sdk/reply-payload";
|
|
13
13
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
14
14
|
//#region extensions/irc/src/inbound.ts
|
|
15
15
|
const CHANNEL_ID = "irc";
|
|
16
|
-
const ircIngressIdentity = defineStableChannelIngressIdentity({
|
|
17
|
-
key: "irc-id",
|
|
18
|
-
normalizeEntry: normalizeIrcStableEntry,
|
|
19
|
-
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
20
|
-
sensitivity: "pii",
|
|
21
|
-
aliases: [
|
|
22
|
-
{
|
|
23
|
-
key: "irc-id-nick-user",
|
|
24
|
-
kind: "stable-id",
|
|
25
|
-
normalizeEntry: normalizeIrcNickUserEntry,
|
|
26
|
-
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
27
|
-
dangerous: true,
|
|
28
|
-
sensitivity: "pii"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
key: "irc-id-nick-host",
|
|
32
|
-
kind: "stable-id",
|
|
33
|
-
normalizeEntry: () => null,
|
|
34
|
-
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
35
|
-
sensitivity: "pii"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
key: "irc-nick",
|
|
39
|
-
kind: "plugin:irc-nick",
|
|
40
|
-
normalizeEntry: normalizeIrcNickEntry,
|
|
41
|
-
normalizeSubject: normalizeLowercaseStringOrEmpty,
|
|
42
|
-
dangerous: true,
|
|
43
|
-
sensitivity: "pii"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
isWildcardEntry: (entry) => normalizeIrcAllowEntry(entry) === "*",
|
|
47
|
-
resolveEntryId: ({ entryIndex, fieldKey }) => `irc-entry-${entryIndex + 1}:${fieldKey === "irc-nick" ? "nick" : "id"}`
|
|
48
|
-
});
|
|
49
16
|
const escapeIrcRegexLiteral = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
50
17
|
const IRC_NICK_CHARACTER = String.raw`[A-Za-z0-9_\-\[\]\\\x60^{}|~]`;
|
|
51
18
|
const IRC_RFC1459_CASE_EQUIVALENTS = /* @__PURE__ */ new Map([
|
|
@@ -64,46 +31,9 @@ function buildIrcNickMentionPattern(value) {
|
|
|
64
31
|
return equivalent ? `[${escapeIrcRegexLiteral(character)}${escapeIrcRegexLiteral(equivalent)}]` : escapeIrcRegexLiteral(character);
|
|
65
32
|
}).join("");
|
|
66
33
|
}
|
|
67
|
-
function isBareNick(value) {
|
|
68
|
-
return !value.includes("!") && !value.includes("@");
|
|
69
|
-
}
|
|
70
|
-
function hasVerifiedHost(value) {
|
|
71
|
-
return value.includes("@");
|
|
72
|
-
}
|
|
73
|
-
function isHostlessNickUser(value) {
|
|
74
|
-
return value.includes("!") && !value.includes("@");
|
|
75
|
-
}
|
|
76
|
-
function normalizeIrcStableEntry(value) {
|
|
77
|
-
const normalized = normalizeIrcAllowEntry(value);
|
|
78
|
-
if (!normalized || normalized === "*" || !hasVerifiedHost(normalized)) return null;
|
|
79
|
-
return normalized;
|
|
80
|
-
}
|
|
81
|
-
function normalizeIrcNickUserEntry(value) {
|
|
82
|
-
const normalized = normalizeIrcAllowEntry(value);
|
|
83
|
-
if (!normalized || normalized === "*" || !isHostlessNickUser(normalized)) return null;
|
|
84
|
-
return normalized;
|
|
85
|
-
}
|
|
86
|
-
function normalizeIrcNickEntry(value) {
|
|
87
|
-
const normalized = normalizeIrcAllowEntry(value);
|
|
88
|
-
if (!normalized || normalized === "*" || !isBareNick(normalized)) return null;
|
|
89
|
-
return normalized;
|
|
90
|
-
}
|
|
91
34
|
function hasEntries(entries) {
|
|
92
35
|
return normalizeStringEntries(entries).some((entry) => normalizeIrcAllowEntry(entry));
|
|
93
36
|
}
|
|
94
|
-
function createIrcIngressSubject(message) {
|
|
95
|
-
const candidates = buildIrcAllowlistCandidates(message, { allowNameMatching: true });
|
|
96
|
-
const stableCandidates = candidates.filter((candidate) => hasVerifiedHost(candidate));
|
|
97
|
-
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
98
|
-
return {
|
|
99
|
-
stableId: stableCandidates[stableCandidates.length - 1] ?? nick,
|
|
100
|
-
aliases: {
|
|
101
|
-
"irc-id-nick-user": candidates.find((candidate) => isHostlessNickUser(candidate)),
|
|
102
|
-
"irc-id-nick-host": stableCandidates.find((candidate) => !candidate.includes("!") && candidate.includes("@")),
|
|
103
|
-
"irc-nick": nick
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
37
|
function routeDescriptorsForIrcGroup(params) {
|
|
108
38
|
if (!params.isGroup) return [];
|
|
109
39
|
return channelIngressRoutes(params.groupPolicy === "allowlist" && {
|
|
@@ -287,10 +217,11 @@ async function handleIrcInbound(params) {
|
|
|
287
217
|
});
|
|
288
218
|
return { kind: "completed" };
|
|
289
219
|
}
|
|
290
|
-
if (message.isGroup)
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
220
|
+
if (message.isGroup) {
|
|
221
|
+
if (access.routeAccess.reason === "channel_not_allowlisted") runtime.log?.(`irc: drop channel ${message.target} (not allowlisted)`);
|
|
222
|
+
else if (access.routeAccess.reason === "channel_disabled") runtime.log?.(`irc: drop channel ${message.target} (disabled)`);
|
|
223
|
+
else runtime.log?.(`irc: drop group sender ${senderDisplay} (policy=${groupPolicy})`);
|
|
224
|
+
} else runtime.log?.(`irc: drop DM sender ${senderDisplay} (dmPolicy=${dmPolicy})`);
|
|
294
225
|
return { kind: "completed" };
|
|
295
226
|
}
|
|
296
227
|
if (turnAdoptionLifecycle?.abortSignal.aborted) return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
|
|
2
|
-
import { ChannelGroupEntrySchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, ReplyRuntimeConfigSchemaShape, buildChannelConfigSchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
2
|
+
import { ChannelGroupEntrySchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, ReplyRuntimeConfigSchemaShape, ReplyToModeSchema, buildChannelConfigSchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region extensions/irc/src/config-ui-hints.ts
|
|
5
5
|
const ircChannelConfigUiHints = {
|
|
@@ -56,10 +56,11 @@ const IrcNickServSchema = z.object({
|
|
|
56
56
|
message: "channels.irc.nickserv.register=true requires channels.irc.nickserv.registerEmail"
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
-
const
|
|
59
|
+
const IrcAccountSchemaBase = z.object({
|
|
60
60
|
name: z.string().optional(),
|
|
61
61
|
enabled: z.boolean().optional(),
|
|
62
62
|
configWrites: z.boolean().optional(),
|
|
63
|
+
replyToMode: ReplyToModeSchema.optional(),
|
|
63
64
|
dangerouslyAllowNameMatching: z.boolean().optional(),
|
|
64
65
|
host: z.string().optional(),
|
|
65
66
|
port: z.number().int().min(1).max(65535).optional(),
|
|
@@ -76,10 +77,10 @@ const IrcChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannel
|
|
|
76
77
|
groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
|
77
78
|
groups: z.record(z.string(), ChannelGroupEntrySchema.optional()).optional(),
|
|
78
79
|
channels: z.array(z.string()).optional(),
|
|
79
|
-
mentionPatterns: z.array(z.string()).optional(),
|
|
80
80
|
markdown: MarkdownConfigSchema,
|
|
81
81
|
...ReplyRuntimeConfigSchemaShape
|
|
82
|
-
}).strict()
|
|
82
|
+
}).strict();
|
|
83
|
+
const IrcConfigSchema = buildMultiAccountChannelSchema(IrcAccountSchemaBase, {
|
|
83
84
|
optionalAccount: true,
|
|
84
85
|
refine: (value, ctx) => {
|
|
85
86
|
requireOpenAllowFrom({
|
|
@@ -90,6 +91,7 @@ const IrcChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannel
|
|
|
90
91
|
message: "channels.irc.dmPolicy=\"open\" requires channels.irc.allowFrom to include \"*\""
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
|
-
})
|
|
94
|
+
});
|
|
95
|
+
const IrcChannelConfigSchema = buildChannelConfigSchema(IrcConfigSchema, { uiHints: ircChannelConfigUiHints });
|
|
94
96
|
//#endregion
|
|
95
97
|
export { IrcChannelConfigSchema as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
2
|
-
//#region extensions/irc/doctor-
|
|
1
|
+
import { asObjectRecord, defineChannelAliasMigration, stripRetiredChannelKeys } from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
2
|
+
//#region extensions/irc/config-doctor-api.ts
|
|
3
3
|
const streamingAliasMigration = defineChannelAliasMigration({
|
|
4
4
|
channelId: "irc",
|
|
5
5
|
streaming: {
|
|
@@ -8,9 +8,39 @@ const streamingAliasMigration = defineChannelAliasMigration({
|
|
|
8
8
|
},
|
|
9
9
|
accountStreamingReplacesRoot: true
|
|
10
10
|
});
|
|
11
|
-
const
|
|
11
|
+
const RETIRED_IRC_KEYS = /* @__PURE__ */ new Set(["mentionPatterns"]);
|
|
12
|
+
const legacyConfigRules = [
|
|
13
|
+
...streamingAliasMigration.legacyConfigRules,
|
|
14
|
+
{
|
|
15
|
+
path: ["channels", "irc"],
|
|
16
|
+
match: (value) => Object.hasOwn(asObjectRecord(value) ?? {}, "mentionPatterns"),
|
|
17
|
+
message: "channels.irc.mentionPatterns was accepted but never read; configure mention patterns with messages.groupChat.mentionPatterns. Run \"openclaw doctor --fix\"."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
path: [
|
|
21
|
+
"channels",
|
|
22
|
+
"irc",
|
|
23
|
+
"accounts"
|
|
24
|
+
],
|
|
25
|
+
match: (value) => Object.values(asObjectRecord(value) ?? {}).some((account) => Object.hasOwn(asObjectRecord(account) ?? {}, "mentionPatterns")),
|
|
26
|
+
message: "channels.irc.accounts.<id>.mentionPatterns was accepted but never read; configure mention patterns with messages.groupChat.mentionPatterns. Run \"openclaw doctor --fix\"."
|
|
27
|
+
}
|
|
28
|
+
];
|
|
12
29
|
function normalizeCompatibilityConfig({ cfg }) {
|
|
13
|
-
|
|
30
|
+
const aliases = streamingAliasMigration.normalizeChannelConfig({ cfg });
|
|
31
|
+
const changes = [...aliases.changes];
|
|
32
|
+
return {
|
|
33
|
+
config: stripRetiredChannelKeys({
|
|
34
|
+
cfg: aliases.config,
|
|
35
|
+
channelId: "irc",
|
|
36
|
+
keys: RETIRED_IRC_KEYS,
|
|
37
|
+
scope: "root-and-accounts",
|
|
38
|
+
onRemove: (removed) => {
|
|
39
|
+
changes.push(`Removed ${removed.pathPrefix}.${removed.key}; it was never read.`);
|
|
40
|
+
}
|
|
41
|
+
}).config,
|
|
42
|
+
changes
|
|
43
|
+
};
|
|
14
44
|
}
|
|
15
45
|
//#endregion
|
|
16
46
|
export { legacyConfigRules, normalizeCompatibilityConfig };
|
package/openclaw.plugin.json
CHANGED
|
@@ -29,6 +29,26 @@
|
|
|
29
29
|
"configWrites": {
|
|
30
30
|
"type": "boolean"
|
|
31
31
|
},
|
|
32
|
+
"replyToMode": {
|
|
33
|
+
"anyOf": [
|
|
34
|
+
{
|
|
35
|
+
"type": "string",
|
|
36
|
+
"const": "off"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "string",
|
|
40
|
+
"const": "first"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "string",
|
|
44
|
+
"const": "all"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "string",
|
|
48
|
+
"const": "batched"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
32
52
|
"dangerouslyAllowNameMatching": {
|
|
33
53
|
"type": "boolean"
|
|
34
54
|
},
|
|
@@ -227,12 +247,6 @@
|
|
|
227
247
|
"type": "string"
|
|
228
248
|
}
|
|
229
249
|
},
|
|
230
|
-
"mentionPatterns": {
|
|
231
|
-
"type": "array",
|
|
232
|
-
"items": {
|
|
233
|
-
"type": "string"
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
250
|
"markdown": {
|
|
237
251
|
"type": "object",
|
|
238
252
|
"properties": {
|
|
@@ -355,6 +369,26 @@
|
|
|
355
369
|
"configWrites": {
|
|
356
370
|
"type": "boolean"
|
|
357
371
|
},
|
|
372
|
+
"replyToMode": {
|
|
373
|
+
"anyOf": [
|
|
374
|
+
{
|
|
375
|
+
"type": "string",
|
|
376
|
+
"const": "off"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"type": "string",
|
|
380
|
+
"const": "first"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"type": "string",
|
|
384
|
+
"const": "all"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"type": "string",
|
|
388
|
+
"const": "batched"
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
},
|
|
358
392
|
"dangerouslyAllowNameMatching": {
|
|
359
393
|
"type": "boolean"
|
|
360
394
|
},
|
|
@@ -553,12 +587,6 @@
|
|
|
553
587
|
"type": "string"
|
|
554
588
|
}
|
|
555
589
|
},
|
|
556
|
-
"mentionPatterns": {
|
|
557
|
-
"type": "array",
|
|
558
|
-
"items": {
|
|
559
|
-
"type": "string"
|
|
560
|
-
}
|
|
561
|
-
},
|
|
562
590
|
"markdown": {
|
|
563
591
|
"type": "object",
|
|
564
592
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/irc",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.2",
|
|
4
4
|
"description": "OpenClaw IRC channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"openclaw": {
|
|
@@ -121,10 +121,10 @@
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
"compat": {
|
|
124
|
-
"pluginApi": ">=2026.8.
|
|
124
|
+
"pluginApi": ">=2026.8.2"
|
|
125
125
|
},
|
|
126
126
|
"build": {
|
|
127
|
-
"openclawVersion": "2026.8.
|
|
127
|
+
"openclawVersion": "2026.8.2",
|
|
128
128
|
"bundledDist": false
|
|
129
129
|
},
|
|
130
130
|
"release": {
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"README.md"
|
|
150
150
|
],
|
|
151
151
|
"peerDependencies": {
|
|
152
|
-
"openclaw": ">=2026.8.
|
|
152
|
+
"openclaw": ">=2026.8.2"
|
|
153
153
|
},
|
|
154
154
|
"peerDependenciesMeta": {
|
|
155
155
|
"openclaw": {
|