@openclaw/irc 2026.10.10-beta.5 → 2026.11.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.setup/{channel-Bi4lj8N2.mjs → channel-DRdPa321.mjs} +266 -326
- package/dist/.setup/channel-plugin-api-DFjxQCOi.mjs +2 -0
- package/dist/.setup/channel-runtime-D2sqTm8e.mjs +579 -0
- package/dist/.setup/{config-schema-Cy9tItsu.mjs → config-schema-CQuAQW7O.mjs} +1 -4
- package/dist/.setup/{runtime-C_V9tmpk.mjs → runtime-CsdAoZex.mjs} +1 -2
- package/dist/.setup/{secret-contract-C5i-29Hz.mjs → secret-contract-0Ccz8X9F.mjs} +1 -2
- package/dist/.setup/{secret-contract-api-4IT9_EK6.mjs → secret-contract-api-BabNUhhB.mjs} +1 -1
- package/dist/.source-module-urls/4751df78f545ae971ceb22b6e4bff6086f63313240899a1d9884b970424a305e.json +1 -1
- package/dist/api.js +2 -2
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/doctor-contract-api.js +6 -12
- package/dist/index.js +1 -2
- package/dist/runtime-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/setup-entry.js +3 -4
- package/node_modules/zod/package.json +1 -1
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/zod/v4/core/versions.js +1 -1
- package/package.json +5 -5
- package/dist/.setup/channel-plugin-api-1I8kWfv8.mjs +0 -2
- package/dist/.setup/channel-runtime-B4OMtNnX.mjs +0 -652
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { t as IrcChannelConfigSchema } from "./config-schema-
|
|
2
|
-
import { n as
|
|
3
|
-
import { n as
|
|
1
|
+
import { t as IrcChannelConfigSchema } from "./config-schema-CQuAQW7O.mjs";
|
|
2
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-0Ccz8X9F.mjs";
|
|
3
|
+
import { n as getOptionalIrcRuntime } from "./runtime-CsdAoZex.mjs";
|
|
4
4
|
import { createAccountListHelpers, describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
5
5
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
6
6
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
7
7
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
8
8
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, parseOptionalDelimitedEntries } from "openclaw/plugin-sdk/channel-core";
|
|
9
9
|
import { defineStableChannelIngressIdentity, identityEntryAuthenticationClassifier } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
10
|
+
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, createReplyToFanout, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
10
11
|
import { buildMutableAllowEntryDetector, collectStandardAllowlistLists, createAllowlistProviderOpenWarningCollector, createConditionalWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, resolveScopeKeyCaseInsensitive, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
|
|
12
|
+
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
11
13
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
12
14
|
import { createChannelDirectoryAdapter, createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-runtime";
|
|
13
15
|
import { buildProbeChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
@@ -17,24 +19,22 @@ import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
|
|
|
17
19
|
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
18
20
|
import { resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
19
21
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringifiedOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
20
|
-
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, createReplyToFanout, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
21
22
|
import { containsAsciiControlCharacter as hasIrcControlChars } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
22
|
-
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
23
23
|
import { chunkTextForOutbound, convertMarkdownTables, sanitizeAssistantVisibleText, stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
|
|
24
|
-
import { randomUUID } from "node:crypto";
|
|
25
|
-
import { createChannelPartialDeliveryError, isChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
26
|
-
import { captureEffectAuthority } from "openclaw/plugin-sdk/fetch-runtime";
|
|
27
|
-
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
28
|
-
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
29
24
|
import net from "node:net";
|
|
30
25
|
import tls from "node:tls";
|
|
26
|
+
import { createChannelPartialDeliveryError, isChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
31
27
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
28
|
+
import { captureEffectAuthority } from "openclaw/plugin-sdk/fetch-runtime";
|
|
32
29
|
import { withTimeout } from "openclaw/plugin-sdk/security-runtime";
|
|
33
30
|
import { assertSecretOwnerAvailable } from "openclaw/plugin-sdk/channel-secret-owner-runtime";
|
|
31
|
+
import { randomUUID } from "node:crypto";
|
|
32
|
+
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
33
|
+
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
34
34
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
35
35
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
|
|
36
36
|
import { applyAccountNameToChannelSection, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicySetter, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
37
|
-
|
|
37
|
+
// extensions/irc/src/accounts.ts
|
|
38
38
|
const { listAccountIds: listIrcAccountIds, resolveDefaultAccountId: resolveDefaultIrcAccountId, resolveAccountConfig: mergeIrcAccountConfig } = createAccountListHelpers("irc", {
|
|
39
39
|
normalizeAccountId,
|
|
40
40
|
omitKeys: ["defaultAccount"],
|
|
@@ -186,44 +186,7 @@ function listEnabledIrcAccounts(cfg) {
|
|
|
186
186
|
accountId
|
|
187
187
|
})).filter((account) => account.enabled);
|
|
188
188
|
}
|
|
189
|
-
|
|
190
|
-
//#region extensions/irc/src/doctor.ts
|
|
191
|
-
const isIrcMutableAllowEntry = buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:irc|user):)*[^@]*@/i });
|
|
192
|
-
const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
|
|
193
|
-
channel: "irc",
|
|
194
|
-
detector: isIrcMutableAllowEntry,
|
|
195
|
-
collectLists: (scope) => collectStandardAllowlistLists(scope, {
|
|
196
|
-
includeGroups: true,
|
|
197
|
-
groupField: "allowFrom"
|
|
198
|
-
})
|
|
199
|
-
});
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region extensions/irc/src/gateway.ts
|
|
202
|
-
async function startIrcGatewayAccount(ctx) {
|
|
203
|
-
const account = ctx.account;
|
|
204
|
-
const statusSink = createAccountStatusSink({
|
|
205
|
-
accountId: ctx.accountId,
|
|
206
|
-
setStatus: ctx.setStatus
|
|
207
|
-
});
|
|
208
|
-
if (!account.configured) throw new Error(`IRC is not configured for account "${account.accountId}" (need host and nick in channels.irc).`);
|
|
209
|
-
ctx.log?.info?.(`[${account.accountId}] starting IRC provider (${account.host}:${account.port}${account.tls ? " tls" : ""})`);
|
|
210
|
-
const { monitorIrcProvider } = await import("./channel-runtime-B4OMtNnX.mjs");
|
|
211
|
-
await runPassiveAccountLifecycle({
|
|
212
|
-
abortSignal: ctx.abortSignal,
|
|
213
|
-
start: async () => await monitorIrcProvider({
|
|
214
|
-
accountId: account.accountId,
|
|
215
|
-
config: ctx.cfg,
|
|
216
|
-
runtime: ctx.runtime,
|
|
217
|
-
abortSignal: ctx.abortSignal,
|
|
218
|
-
statusSink
|
|
219
|
-
}),
|
|
220
|
-
stop: async (monitor) => {
|
|
221
|
-
await monitor.stop();
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
//#endregion
|
|
226
|
-
//#region extensions/irc/src/control-chars.ts
|
|
189
|
+
// extensions/irc/src/control-chars.ts
|
|
227
190
|
function isIrcControlChar(charCode) {
|
|
228
191
|
return charCode <= 31 || charCode === 127;
|
|
229
192
|
}
|
|
@@ -232,8 +195,7 @@ function stripIrcControlChars(value) {
|
|
|
232
195
|
for (const char of value) if (!isIrcControlChar(char.charCodeAt(0))) out += char;
|
|
233
196
|
return out;
|
|
234
197
|
}
|
|
235
|
-
|
|
236
|
-
//#region extensions/irc/src/normalize.ts
|
|
198
|
+
// extensions/irc/src/normalize.ts
|
|
237
199
|
const IRC_TARGET_PATTERN$1 = /^[^\s:]+$/u;
|
|
238
200
|
function isChannelTarget(target) {
|
|
239
201
|
return target.startsWith("#") || target.startsWith("&");
|
|
@@ -283,17 +245,6 @@ function normalizeIrcAllowEntry(raw) {
|
|
|
283
245
|
if (value.startsWith("user:")) value = value.slice(5);
|
|
284
246
|
return value.trim();
|
|
285
247
|
}
|
|
286
|
-
function buildIrcAllowlistCandidates(message, params) {
|
|
287
|
-
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
288
|
-
const user = normalizeOptionalLowercaseString(message.senderUser);
|
|
289
|
-
const host = normalizeOptionalLowercaseString(message.senderHost);
|
|
290
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
291
|
-
if (nick && params?.allowNameMatching === true) candidates.add(nick);
|
|
292
|
-
if (nick && user) candidates.add(`${nick}!${user}`);
|
|
293
|
-
if (nick && host) candidates.add(`${nick}@${host}`);
|
|
294
|
-
if (nick && user && host) candidates.add(`${nick}!${user}@${host}`);
|
|
295
|
-
return [...candidates];
|
|
296
|
-
}
|
|
297
248
|
const ircIngressIdentity = defineStableChannelIngressIdentity({
|
|
298
249
|
key: "irc-id",
|
|
299
250
|
authentication: "asserted",
|
|
@@ -358,20 +309,25 @@ function normalizeIrcNickEntry(value) {
|
|
|
358
309
|
return normalized;
|
|
359
310
|
}
|
|
360
311
|
function createIrcIngressSubject(message) {
|
|
361
|
-
const candidates = buildIrcAllowlistCandidates(message, { allowNameMatching: true });
|
|
362
|
-
const stableCandidates = candidates.filter((candidate) => hasVerifiedHost(candidate));
|
|
363
312
|
const nick = normalizeLowercaseStringOrEmpty(message.senderNick);
|
|
313
|
+
const user = normalizeOptionalLowercaseString(message.senderUser);
|
|
314
|
+
const host = normalizeOptionalLowercaseString(message.senderHost);
|
|
315
|
+
const candidates = [
|
|
316
|
+
nick,
|
|
317
|
+
nick && user ? `${nick}!${user}` : "",
|
|
318
|
+
nick && host ? `${nick}@${host}` : "",
|
|
319
|
+
nick && user && host ? `${nick}!${user}@${host}` : ""
|
|
320
|
+
];
|
|
364
321
|
return {
|
|
365
|
-
stableId:
|
|
322
|
+
stableId: candidates.findLast(hasVerifiedHost) ?? nick,
|
|
366
323
|
aliases: {
|
|
367
324
|
"irc-id-nick-user": candidates.find((candidate) => isHostlessNickUser(candidate)),
|
|
368
|
-
"irc-id-nick-host":
|
|
325
|
+
"irc-id-nick-host": candidates.find((candidate) => hasVerifiedHost(candidate) && !candidate.includes("!")),
|
|
369
326
|
"irc-nick": nick
|
|
370
327
|
}
|
|
371
328
|
};
|
|
372
329
|
}
|
|
373
|
-
|
|
374
|
-
//#region extensions/irc/src/outbound-base.ts
|
|
330
|
+
// extensions/irc/src/outbound-base.ts
|
|
375
331
|
function sanitizeIrcAssistantText(text) {
|
|
376
332
|
return sanitizeForPlainText(sanitizeAssistantVisibleText(text));
|
|
377
333
|
}
|
|
@@ -382,8 +338,50 @@ const ircOutboundBaseAdapter = {
|
|
|
382
338
|
textChunkLimit: 350,
|
|
383
339
|
sanitizeText: ({ text }) => sanitizeIrcAssistantText(text)
|
|
384
340
|
};
|
|
385
|
-
|
|
386
|
-
|
|
341
|
+
// extensions/irc/src/policy.ts
|
|
342
|
+
function resolveIrcGroupScope(params) {
|
|
343
|
+
const { "*": wildcard, ...groups } = params.groups ?? {};
|
|
344
|
+
const project = (entry) => ({
|
|
345
|
+
requireMention: entry.requireMention,
|
|
346
|
+
tools: entry.tools
|
|
347
|
+
});
|
|
348
|
+
const tree = {
|
|
349
|
+
defaults: wildcard ? project(wildcard) : void 0,
|
|
350
|
+
scopes: Object.fromEntries(Object.entries(groups).map(([key, entry]) => [key, project(entry)]))
|
|
351
|
+
};
|
|
352
|
+
const key = resolveScopeKeyCaseInsensitive(tree, params.target);
|
|
353
|
+
return {
|
|
354
|
+
tree,
|
|
355
|
+
path: key ? [key] : []
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function resolveIrcGroupMatch(params) {
|
|
359
|
+
const { path } = resolveIrcGroupScope(params);
|
|
360
|
+
const key = path[0];
|
|
361
|
+
const groupConfig = key ? params.groups?.[key] : void 0;
|
|
362
|
+
const wildcardConfig = params.groups?.["*"];
|
|
363
|
+
return {
|
|
364
|
+
allowed: Boolean(groupConfig ?? wildcardConfig),
|
|
365
|
+
groupConfig,
|
|
366
|
+
wildcardConfig,
|
|
367
|
+
hasConfiguredGroups: Object.keys(params.groups ?? {}).length > 0
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function resolveIrcGroupRequireMention(params) {
|
|
371
|
+
const { tree, path } = resolveIrcGroupScope(params);
|
|
372
|
+
return resolveScopeRequireMention({
|
|
373
|
+
tree,
|
|
374
|
+
path
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
function resolveIrcGroupToolPolicy(params) {
|
|
378
|
+
const { tree, path } = resolveIrcGroupScope(params);
|
|
379
|
+
return resolveScopeToolsPolicy({
|
|
380
|
+
tree,
|
|
381
|
+
path
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
// packages/normalization-core/src/utf16-slice.ts
|
|
387
385
|
function isHighSurrogate(codeUnit) {
|
|
388
386
|
return codeUnit >= 55296 && codeUnit <= 56319;
|
|
389
387
|
}
|
|
@@ -396,8 +394,7 @@ function avoidTrailingHighSurrogateBreak(text, start, end) {
|
|
|
396
394
|
const adjusted = end - 1;
|
|
397
395
|
return adjusted > start ? adjusted : end + 1;
|
|
398
396
|
}
|
|
399
|
-
|
|
400
|
-
//#region packages/normalization-core/src/grapheme.ts
|
|
397
|
+
// packages/normalization-core/src/grapheme.ts
|
|
401
398
|
let graphemeSegmenter;
|
|
402
399
|
function getGraphemeSegmenter() {
|
|
403
400
|
graphemeSegmenter ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
@@ -421,8 +418,7 @@ function findGraphemeChunkEnd(text, start, maxEnd, preferredEnd = maxEnd, allowP
|
|
|
421
418
|
if (end <= start && preferred < hardEnd) end = hardEnd === text.length ? hardEnd : segments.containing(hardEnd)?.index ?? hardEnd;
|
|
422
419
|
return end > start ? end : allowPartial ? avoidTrailingHighSurrogateBreak(text, start, hardEnd) : start;
|
|
423
420
|
}
|
|
424
|
-
|
|
425
|
-
//#region extensions/irc/src/protocol.ts
|
|
421
|
+
// extensions/irc/src/protocol.ts
|
|
426
422
|
const IRC_TARGET_PATTERN = /^[^\s:]+$/u;
|
|
427
423
|
function parseIrcLine(line) {
|
|
428
424
|
const raw = line.replace(/[\r\n]+/g, "").trim();
|
|
@@ -457,7 +453,6 @@ function parseIrcLine(line) {
|
|
|
457
453
|
cursor = cursor.slice(spaceIdx + 1);
|
|
458
454
|
}
|
|
459
455
|
return {
|
|
460
|
-
raw,
|
|
461
456
|
prefix,
|
|
462
457
|
command: command.toUpperCase(),
|
|
463
458
|
params,
|
|
@@ -484,8 +479,7 @@ function parseIrcPrefix(prefix) {
|
|
|
484
479
|
user
|
|
485
480
|
};
|
|
486
481
|
}
|
|
487
|
-
|
|
488
|
-
return { nick: prefix };
|
|
482
|
+
return prefix.includes(".") ? {} : { nick: prefix };
|
|
489
483
|
}
|
|
490
484
|
function sanitizeIrcOutboundText(text) {
|
|
491
485
|
return stripIrcControlChars(text.replace(/\r?\n/g, " ")).trim();
|
|
@@ -495,8 +489,7 @@ function sanitizeIrcTarget(raw) {
|
|
|
495
489
|
if (raw !== raw.trim() || hasIrcControlChars(raw) || !IRC_TARGET_PATTERN.test(raw)) throw new Error(`Invalid IRC target: ${raw}`);
|
|
496
490
|
return raw;
|
|
497
491
|
}
|
|
498
|
-
|
|
499
|
-
//#region extensions/irc/src/client.ts
|
|
492
|
+
// extensions/irc/src/client.ts
|
|
500
493
|
const IRC_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
501
494
|
"432",
|
|
502
495
|
"464",
|
|
@@ -700,7 +693,6 @@ async function connectIrcClient(options) {
|
|
|
700
693
|
buffer = buffer.slice(idx + 1);
|
|
701
694
|
idx = buffer.indexOf("\n");
|
|
702
695
|
if (!rawLine) continue;
|
|
703
|
-
options.onLine?.(rawLine);
|
|
704
696
|
const line = parseIrcLine(rawLine);
|
|
705
697
|
if (!line) continue;
|
|
706
698
|
if (line.command === "PING") {
|
|
@@ -811,15 +803,13 @@ async function connectIrcClient(options) {
|
|
|
811
803
|
return currentNick;
|
|
812
804
|
},
|
|
813
805
|
isReady: () => ready && !closed,
|
|
814
|
-
sendRaw,
|
|
815
806
|
join,
|
|
816
807
|
sendPrivmsg,
|
|
817
808
|
quit,
|
|
818
809
|
close
|
|
819
810
|
};
|
|
820
811
|
}
|
|
821
|
-
|
|
822
|
-
//#region extensions/irc/src/connect-options.ts
|
|
812
|
+
// extensions/irc/src/connect-options.ts
|
|
823
813
|
function buildIrcConnectOptions(account, overrides = {}) {
|
|
824
814
|
assertSecretOwnerAvailable("account", `irc:${account.accountId}`);
|
|
825
815
|
if (account.tokenStatus === "configured_unavailable") throw new Error(`IRC credentials for account "${account.accountId}" are configured but unavailable.`);
|
|
@@ -831,18 +821,45 @@ function buildIrcConnectOptions(account, overrides = {}) {
|
|
|
831
821
|
username: account.username,
|
|
832
822
|
realname: account.realname,
|
|
833
823
|
password: account.password,
|
|
834
|
-
nickserv:
|
|
835
|
-
enabled: account.config.nickserv?.enabled,
|
|
836
|
-
service: account.config.nickserv?.service,
|
|
837
|
-
password: account.config.nickserv?.password,
|
|
838
|
-
register: account.config.nickserv?.register,
|
|
839
|
-
registerEmail: account.config.nickserv?.registerEmail
|
|
840
|
-
},
|
|
824
|
+
nickserv: account.config.nickserv,
|
|
841
825
|
...overrides
|
|
842
826
|
};
|
|
843
827
|
}
|
|
844
|
-
|
|
845
|
-
|
|
828
|
+
// extensions/irc/src/probe.ts
|
|
829
|
+
async function probeIrc(cfg, opts) {
|
|
830
|
+
const account = resolveIrcAccount({
|
|
831
|
+
cfg,
|
|
832
|
+
accountId: opts?.accountId
|
|
833
|
+
});
|
|
834
|
+
const base = {
|
|
835
|
+
ok: false,
|
|
836
|
+
host: account.host,
|
|
837
|
+
port: account.port,
|
|
838
|
+
tls: account.tls,
|
|
839
|
+
nick: account.nick
|
|
840
|
+
};
|
|
841
|
+
if (!account.configured) return {
|
|
842
|
+
...base,
|
|
843
|
+
error: "missing host or nick"
|
|
844
|
+
};
|
|
845
|
+
const started = Date.now();
|
|
846
|
+
try {
|
|
847
|
+
const client = await connectIrcClient(buildIrcConnectOptions(account, { connectTimeoutMs: opts?.timeoutMs ?? 8e3 }));
|
|
848
|
+
const elapsed = Date.now() - started;
|
|
849
|
+
client.quit("probe");
|
|
850
|
+
return {
|
|
851
|
+
...base,
|
|
852
|
+
ok: true,
|
|
853
|
+
latencyMs: elapsed
|
|
854
|
+
};
|
|
855
|
+
} catch (err) {
|
|
856
|
+
return {
|
|
857
|
+
...base,
|
|
858
|
+
error: err instanceof Error ? err.message : typeof err === "string" ? err : JSON.stringify(err)
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
// extensions/irc/src/send.ts
|
|
846
863
|
async function sendIrcMessages(to, text, opts, planMessages = (preparedText) => [{
|
|
847
864
|
text: preparedText,
|
|
848
865
|
replyTo: opts.replyTo
|
|
@@ -866,15 +883,14 @@ async function sendIrcMessages(to, text, opts, planMessages = (preparedText) =>
|
|
|
866
883
|
if (!prepared.trim()) throw new Error("Message must be non-empty for IRC sends");
|
|
867
884
|
const messages = planMessages(prepared);
|
|
868
885
|
opts.abortSignal?.throwIfAborted();
|
|
869
|
-
|
|
870
|
-
const client = opts.client?.isReady() ? opts.client : transient = await connectIrcClient(buildIrcConnectOptions(account, {
|
|
886
|
+
const client = await connectIrcClient(buildIrcConnectOptions(account, {
|
|
871
887
|
connectTimeoutMs: 12e3,
|
|
872
888
|
abortSignal: opts.abortSignal
|
|
873
889
|
}));
|
|
874
890
|
const results = [];
|
|
875
891
|
try {
|
|
876
892
|
opts.abortSignal?.throwIfAborted();
|
|
877
|
-
if (
|
|
893
|
+
if (target.startsWith("#") || target.startsWith("&")) await effect.initiate(() => {
|
|
878
894
|
opts.abortSignal?.throwIfAborted();
|
|
879
895
|
if (!client.isReady()) throw new Error("IRC connection closed before join");
|
|
880
896
|
client.join(target);
|
|
@@ -931,7 +947,7 @@ async function sendIrcMessages(to, text, opts, planMessages = (preparedText) =>
|
|
|
931
947
|
visibleReplySent: true
|
|
932
948
|
});
|
|
933
949
|
} finally {
|
|
934
|
-
|
|
950
|
+
client.quit("sent");
|
|
935
951
|
}
|
|
936
952
|
}
|
|
937
953
|
async function sendMessageIrc(to, text, opts) {
|
|
@@ -939,141 +955,7 @@ async function sendMessageIrc(to, text, opts) {
|
|
|
939
955
|
if (!result) throw new Error("Message must be non-empty for IRC sends");
|
|
940
956
|
return result;
|
|
941
957
|
}
|
|
942
|
-
|
|
943
|
-
//#region extensions/irc/src/message-adapter.ts
|
|
944
|
-
function toIrcMessageResult({ target, ...result }) {
|
|
945
|
-
return {
|
|
946
|
-
...result,
|
|
947
|
-
target: {
|
|
948
|
-
kind: "conversation",
|
|
949
|
-
id: target
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
}
|
|
953
|
-
async function sendIrcMessage(ctx, text = ctx.text) {
|
|
954
|
-
return toIrcMessageResult(await sendMessageIrc(ctx.to, text, {
|
|
955
|
-
cfg: ctx.cfg,
|
|
956
|
-
accountId: ctx.accountId ?? void 0,
|
|
957
|
-
replyTo: ctx.replyToId ?? void 0,
|
|
958
|
-
abortSignal: ctx.signal,
|
|
959
|
-
onPlatformSendDispatch: ctx.onPlatformSendDispatch
|
|
960
|
-
}));
|
|
961
|
-
}
|
|
962
|
-
const sendFormattedIrcText = async (ctx) => {
|
|
963
|
-
const { chunkTextWithMode, resolveChunkMode, resolveTextChunkLimit } = await import("openclaw/plugin-sdk/reply-chunking");
|
|
964
|
-
const accountId = ctx.accountId ?? void 0;
|
|
965
|
-
const textLimit = ctx.formatting?.textLimit ?? resolveTextChunkLimit(ctx.cfg, "irc", accountId, { fallbackLimit: ircOutboundBaseAdapter.textChunkLimit });
|
|
966
|
-
const chunkMode = ctx.formatting?.chunkMode ?? resolveChunkMode(ctx.cfg, "irc", accountId);
|
|
967
|
-
const nextReplyToId = createReplyToFanout(ctx);
|
|
968
|
-
return (await sendIrcMessages(ctx.to, ctx.text, {
|
|
969
|
-
cfg: ctx.cfg,
|
|
970
|
-
accountId,
|
|
971
|
-
abortSignal: ctx.abortSignal,
|
|
972
|
-
onPlatformSendDispatch: ctx.onPlatformSendDispatch
|
|
973
|
-
}, (preparedText) => chunkTextWithMode(preparedText, textLimit, chunkMode).map((text) => ({
|
|
974
|
-
text,
|
|
975
|
-
replyTo: nextReplyToId()
|
|
976
|
-
})), async (result) => {
|
|
977
|
-
await ctx.onDeliveryResult?.(attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
978
|
-
})).map((result) => attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
979
|
-
};
|
|
980
|
-
const ircMessageAdapter = defineChannelMessageAdapter({
|
|
981
|
-
id: "irc",
|
|
982
|
-
durableFinal: { capabilities: {
|
|
983
|
-
text: true,
|
|
984
|
-
media: true,
|
|
985
|
-
replyTo: true
|
|
986
|
-
} },
|
|
987
|
-
send: {
|
|
988
|
-
text: sendIrcMessage,
|
|
989
|
-
media: (ctx) => sendIrcMessage(ctx, ctx.mediaUrl ? `${ctx.text}\n\nAttachment: ${ctx.mediaUrl}` : ctx.text)
|
|
990
|
-
}
|
|
991
|
-
});
|
|
992
|
-
//#endregion
|
|
993
|
-
//#region extensions/irc/src/policy.ts
|
|
994
|
-
function resolveIrcGroupScope(params) {
|
|
995
|
-
const { "*": wildcard, ...groups } = params.groups ?? {};
|
|
996
|
-
const project = (entry) => ({
|
|
997
|
-
requireMention: entry.requireMention,
|
|
998
|
-
tools: entry.tools
|
|
999
|
-
});
|
|
1000
|
-
const tree = {
|
|
1001
|
-
defaults: wildcard ? project(wildcard) : void 0,
|
|
1002
|
-
scopes: Object.fromEntries(Object.entries(groups).map(([key, entry]) => [key, project(entry)]))
|
|
1003
|
-
};
|
|
1004
|
-
const key = resolveScopeKeyCaseInsensitive(tree, params.target);
|
|
1005
|
-
return {
|
|
1006
|
-
tree,
|
|
1007
|
-
path: key ? [key] : []
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
function resolveIrcGroupMatch(params) {
|
|
1011
|
-
const { path } = resolveIrcGroupScope(params);
|
|
1012
|
-
const key = path[0];
|
|
1013
|
-
const groupConfig = key ? params.groups?.[key] : void 0;
|
|
1014
|
-
const wildcardConfig = params.groups?.["*"];
|
|
1015
|
-
return {
|
|
1016
|
-
allowed: Boolean(groupConfig ?? wildcardConfig),
|
|
1017
|
-
groupConfig,
|
|
1018
|
-
wildcardConfig,
|
|
1019
|
-
hasConfiguredGroups: Object.keys(params.groups ?? {}).length > 0
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
function resolveIrcGroupRequireMention(params) {
|
|
1023
|
-
const { tree, path } = resolveIrcGroupScope(params);
|
|
1024
|
-
return resolveScopeRequireMention({
|
|
1025
|
-
tree,
|
|
1026
|
-
path
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
function resolveIrcGroupToolPolicy(params) {
|
|
1030
|
-
const { tree, path } = resolveIrcGroupScope(params);
|
|
1031
|
-
return resolveScopeToolsPolicy({
|
|
1032
|
-
tree,
|
|
1033
|
-
path
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
//#endregion
|
|
1037
|
-
//#region extensions/irc/src/probe.ts
|
|
1038
|
-
function formatError(err) {
|
|
1039
|
-
if (err instanceof Error) return err.message;
|
|
1040
|
-
return typeof err === "string" ? err : JSON.stringify(err);
|
|
1041
|
-
}
|
|
1042
|
-
async function probeIrc(cfg, opts) {
|
|
1043
|
-
const account = resolveIrcAccount({
|
|
1044
|
-
cfg,
|
|
1045
|
-
accountId: opts?.accountId
|
|
1046
|
-
});
|
|
1047
|
-
const base = {
|
|
1048
|
-
ok: false,
|
|
1049
|
-
host: account.host,
|
|
1050
|
-
port: account.port,
|
|
1051
|
-
tls: account.tls,
|
|
1052
|
-
nick: account.nick
|
|
1053
|
-
};
|
|
1054
|
-
if (!account.configured) return {
|
|
1055
|
-
...base,
|
|
1056
|
-
error: "missing host or nick"
|
|
1057
|
-
};
|
|
1058
|
-
const started = Date.now();
|
|
1059
|
-
try {
|
|
1060
|
-
const client = await connectIrcClient(buildIrcConnectOptions(account, { connectTimeoutMs: opts?.timeoutMs ?? 8e3 }));
|
|
1061
|
-
const elapsed = Date.now() - started;
|
|
1062
|
-
client.quit("probe");
|
|
1063
|
-
return {
|
|
1064
|
-
...base,
|
|
1065
|
-
ok: true,
|
|
1066
|
-
latencyMs: elapsed
|
|
1067
|
-
};
|
|
1068
|
-
} catch (err) {
|
|
1069
|
-
return {
|
|
1070
|
-
...base,
|
|
1071
|
-
error: formatError(err)
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
//#endregion
|
|
1076
|
-
//#region extensions/irc/src/setup-core.ts
|
|
958
|
+
// extensions/irc/src/setup-core.ts
|
|
1077
959
|
const channel$1 = "irc";
|
|
1078
960
|
const setIrcDmPolicy = createTopLevelChannelDmPolicySetter({ channel: channel$1 });
|
|
1079
961
|
const setIrcAllowFrom = createTopLevelChannelAllowFromSetter({ channel: channel$1 });
|
|
@@ -1222,8 +1104,7 @@ const ircSetupContract = defineChannelSetupContract({
|
|
|
1222
1104
|
},
|
|
1223
1105
|
legacyAdapter: ircSetupAdapter
|
|
1224
1106
|
});
|
|
1225
|
-
|
|
1226
|
-
//#region extensions/irc/src/setup-surface.ts
|
|
1107
|
+
// extensions/irc/src/setup-surface.ts
|
|
1227
1108
|
const t = createSetupTranslator();
|
|
1228
1109
|
const channel = "irc";
|
|
1229
1110
|
const USE_ENV_FLAG = "__ircUseEnv";
|
|
@@ -1253,67 +1134,16 @@ function normalizeGroupEntry(raw) {
|
|
|
1253
1134
|
return `#${normalized.replace(/^#+/, "")}`;
|
|
1254
1135
|
}
|
|
1255
1136
|
function parseAutoJoinChannels(value) {
|
|
1256
|
-
return splitSetupEntries(value).map(normalizeGroupEntry).filter((entry) => Boolean(entry && entry !== "*"))
|
|
1137
|
+
return splitSetupEntries(value).map(normalizeGroupEntry).filter((entry) => Boolean(entry && entry !== "*"));
|
|
1257
1138
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
noteTitle: t("wizard.irc.allowlistTitle"),
|
|
1261
|
-
noteLines: [
|
|
1139
|
+
function ircAllowlistHelpLines() {
|
|
1140
|
+
return [
|
|
1262
1141
|
t("wizard.irc.allowlistIntro"),
|
|
1263
1142
|
t("wizard.irc.examples"),
|
|
1264
1143
|
"- alice",
|
|
1265
1144
|
"- alice!ident@example.org",
|
|
1266
1145
|
t("wizard.irc.multipleEntries")
|
|
1267
|
-
]
|
|
1268
|
-
message: t("wizard.irc.allowFromPrompt"),
|
|
1269
|
-
placeholder: "alice, bob!ident@example.org",
|
|
1270
|
-
parseEntries: (raw) => ({ entries: normalizeStringEntries(splitSetupEntries(raw).map(normalizeIrcAllowEntry)) }),
|
|
1271
|
-
getExistingAllowFrom: ({ cfg }) => cfg.channels?.irc?.allowFrom ?? [],
|
|
1272
|
-
applyAllowFrom: ({ cfg, allowFrom }) => setIrcAllowFrom(cfg, allowFrom)
|
|
1273
|
-
});
|
|
1274
|
-
async function promptIrcNickServConfig(params) {
|
|
1275
|
-
const existing = resolveIrcAccount({
|
|
1276
|
-
cfg: params.cfg,
|
|
1277
|
-
accountId: params.accountId
|
|
1278
|
-
}).config.nickserv;
|
|
1279
|
-
const hasExisting = Boolean(existing?.password || existing?.passwordFile);
|
|
1280
|
-
if (!await params.prompter.confirm({
|
|
1281
|
-
message: hasExisting ? t("wizard.irc.nickServUpdatePrompt") : t("wizard.irc.nickServConfigurePrompt"),
|
|
1282
|
-
initialValue: hasExisting
|
|
1283
|
-
})) return params.cfg;
|
|
1284
|
-
const service = (await params.prompter.text({
|
|
1285
|
-
message: t("wizard.irc.nickServServicePrompt"),
|
|
1286
|
-
initialValue: existing?.service || "NickServ",
|
|
1287
|
-
validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : "Required"
|
|
1288
|
-
})).trim();
|
|
1289
|
-
const useEnvPassword = params.accountId === DEFAULT_ACCOUNT_ID$1 && Boolean(process.env.IRC_NICKSERV_PASSWORD?.trim()) && !(existing?.password || existing?.passwordFile) ? await params.prompter.confirm({
|
|
1290
|
-
message: t("wizard.irc.nickServPasswordEnvPrompt"),
|
|
1291
|
-
initialValue: true
|
|
1292
|
-
}) : false;
|
|
1293
|
-
const password = useEnvPassword ? void 0 : (await params.prompter.text({
|
|
1294
|
-
message: t("wizard.irc.nickServPasswordPrompt"),
|
|
1295
|
-
validate: () => void 0
|
|
1296
|
-
})).trim();
|
|
1297
|
-
if (!password && !useEnvPassword) return setIrcNickServ(params.cfg, params.accountId, {
|
|
1298
|
-
enabled: false,
|
|
1299
|
-
service
|
|
1300
|
-
});
|
|
1301
|
-
const register = await params.prompter.confirm({
|
|
1302
|
-
message: t("wizard.irc.nickServRegisterPrompt"),
|
|
1303
|
-
initialValue: existing?.register ?? false
|
|
1304
|
-
});
|
|
1305
|
-
const registerEmail = register ? (await params.prompter.text({
|
|
1306
|
-
message: t("wizard.irc.nickServRegisterEmailPrompt"),
|
|
1307
|
-
initialValue: existing?.registerEmail || (params.accountId === DEFAULT_ACCOUNT_ID$1 ? process.env.IRC_NICKSERV_REGISTER_EMAIL : void 0),
|
|
1308
|
-
validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : "Required"
|
|
1309
|
-
})).trim() : void 0;
|
|
1310
|
-
return setIrcNickServ(params.cfg, params.accountId, {
|
|
1311
|
-
enabled: true,
|
|
1312
|
-
service,
|
|
1313
|
-
...password ? { password } : {},
|
|
1314
|
-
register,
|
|
1315
|
-
...registerEmail ? { registerEmail } : {}
|
|
1316
|
-
});
|
|
1146
|
+
];
|
|
1317
1147
|
}
|
|
1318
1148
|
const ircDmPolicy = {
|
|
1319
1149
|
label: "IRC",
|
|
@@ -1322,7 +1152,16 @@ const ircDmPolicy = {
|
|
|
1322
1152
|
allowFromKey: "channels.irc.allowFrom",
|
|
1323
1153
|
getCurrent: (cfg) => cfg.channels?.irc?.dmPolicy ?? "pairing",
|
|
1324
1154
|
setPolicy: (cfg, policy) => setIrcDmPolicy(cfg, policy),
|
|
1325
|
-
promptAllowFrom:
|
|
1155
|
+
promptAllowFrom: createPromptParsedAllowFromForAccount({
|
|
1156
|
+
defaultAccountId: resolveDefaultIrcAccountId,
|
|
1157
|
+
noteTitle: t("wizard.irc.allowlistTitle"),
|
|
1158
|
+
noteLines: ircAllowlistHelpLines(),
|
|
1159
|
+
message: t("wizard.irc.allowFromPrompt"),
|
|
1160
|
+
placeholder: "alice, bob!ident@example.org",
|
|
1161
|
+
parseEntries: (raw) => ({ entries: normalizeStringEntries(splitSetupEntries(raw).map(normalizeIrcAllowEntry)) }),
|
|
1162
|
+
getExistingAllowFrom: ({ cfg }) => cfg.channels?.irc?.allowFrom ?? [],
|
|
1163
|
+
applyAllowFrom: ({ cfg, allowFrom }) => setIrcAllowFrom(cfg, allowFrom)
|
|
1164
|
+
})
|
|
1326
1165
|
};
|
|
1327
1166
|
const ircSetupWizard = {
|
|
1328
1167
|
channel,
|
|
@@ -1487,13 +1326,7 @@ const ircSetupWizard = {
|
|
|
1487
1326
|
},
|
|
1488
1327
|
allowFrom: createAllowFromSection({
|
|
1489
1328
|
helpTitle: t("wizard.irc.allowlistTitle"),
|
|
1490
|
-
helpLines:
|
|
1491
|
-
t("wizard.irc.allowlistIntro"),
|
|
1492
|
-
t("wizard.irc.examples"),
|
|
1493
|
-
"- alice",
|
|
1494
|
-
"- alice!ident@example.org",
|
|
1495
|
-
t("wizard.irc.multipleEntries")
|
|
1496
|
-
],
|
|
1329
|
+
helpLines: ircAllowlistHelpLines(),
|
|
1497
1330
|
message: t("wizard.irc.allowFromPrompt"),
|
|
1498
1331
|
placeholder: "alice, bob!ident@example.org",
|
|
1499
1332
|
invalidWithoutCredentialNote: t("wizard.irc.allowFromInvalid"),
|
|
@@ -1523,11 +1356,51 @@ const ircSetupWizard = {
|
|
|
1523
1356
|
}
|
|
1524
1357
|
}
|
|
1525
1358
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1359
|
+
const nickServConfig = next;
|
|
1360
|
+
next = await (async () => {
|
|
1361
|
+
const existing = resolveIrcAccount({
|
|
1362
|
+
cfg: nickServConfig,
|
|
1363
|
+
accountId
|
|
1364
|
+
}).config.nickserv;
|
|
1365
|
+
const hasExisting = Boolean(existing?.password || existing?.passwordFile);
|
|
1366
|
+
if (!await prompter.confirm({
|
|
1367
|
+
message: hasExisting ? t("wizard.irc.nickServUpdatePrompt") : t("wizard.irc.nickServConfigurePrompt"),
|
|
1368
|
+
initialValue: hasExisting
|
|
1369
|
+
})) return nickServConfig;
|
|
1370
|
+
const service = (await prompter.text({
|
|
1371
|
+
message: t("wizard.irc.nickServServicePrompt"),
|
|
1372
|
+
initialValue: existing?.service || "NickServ",
|
|
1373
|
+
validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : "Required"
|
|
1374
|
+
})).trim();
|
|
1375
|
+
const useEnvPassword = accountId === DEFAULT_ACCOUNT_ID$1 && Boolean(process.env.IRC_NICKSERV_PASSWORD?.trim()) && !(existing?.password || existing?.passwordFile) ? await prompter.confirm({
|
|
1376
|
+
message: t("wizard.irc.nickServPasswordEnvPrompt"),
|
|
1377
|
+
initialValue: true
|
|
1378
|
+
}) : false;
|
|
1379
|
+
const password = useEnvPassword ? void 0 : (await prompter.text({
|
|
1380
|
+
message: t("wizard.irc.nickServPasswordPrompt"),
|
|
1381
|
+
validate: () => void 0
|
|
1382
|
+
})).trim();
|
|
1383
|
+
if (!password && !useEnvPassword) return setIrcNickServ(nickServConfig, accountId, {
|
|
1384
|
+
enabled: false,
|
|
1385
|
+
service
|
|
1386
|
+
});
|
|
1387
|
+
const register = await prompter.confirm({
|
|
1388
|
+
message: t("wizard.irc.nickServRegisterPrompt"),
|
|
1389
|
+
initialValue: existing?.register ?? false
|
|
1390
|
+
});
|
|
1391
|
+
const registerEmail = register ? (await prompter.text({
|
|
1392
|
+
message: t("wizard.irc.nickServRegisterEmailPrompt"),
|
|
1393
|
+
initialValue: existing?.registerEmail || (accountId === DEFAULT_ACCOUNT_ID$1 ? process.env.IRC_NICKSERV_REGISTER_EMAIL : void 0),
|
|
1394
|
+
validate: (value) => normalizeStringifiedOptionalString(value) ? void 0 : "Required"
|
|
1395
|
+
})).trim() : void 0;
|
|
1396
|
+
return setIrcNickServ(nickServConfig, accountId, {
|
|
1397
|
+
enabled: true,
|
|
1398
|
+
service,
|
|
1399
|
+
...password ? { password } : {},
|
|
1400
|
+
register,
|
|
1401
|
+
...registerEmail ? { registerEmail } : {}
|
|
1402
|
+
});
|
|
1403
|
+
})();
|
|
1531
1404
|
return { cfg: next };
|
|
1532
1405
|
},
|
|
1533
1406
|
completionNote: {
|
|
@@ -1541,8 +1414,74 @@ const ircSetupWizard = {
|
|
|
1541
1414
|
dmPolicy: ircDmPolicy,
|
|
1542
1415
|
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
|
|
1543
1416
|
};
|
|
1544
|
-
|
|
1545
|
-
|
|
1417
|
+
// extensions/irc/src/channel.ts
|
|
1418
|
+
function ircAccountDetails(account) {
|
|
1419
|
+
return {
|
|
1420
|
+
host: account.host,
|
|
1421
|
+
port: account.port,
|
|
1422
|
+
tls: account.tls,
|
|
1423
|
+
nick: account.nick,
|
|
1424
|
+
passwordSource: account.passwordSource,
|
|
1425
|
+
tokenStatus: account.tokenStatus
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function toIrcMessageResult({ target, ...result }) {
|
|
1429
|
+
return {
|
|
1430
|
+
...result,
|
|
1431
|
+
target: {
|
|
1432
|
+
kind: "conversation",
|
|
1433
|
+
id: target
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
async function sendIrcMessage(ctx, text = ctx.text) {
|
|
1438
|
+
return toIrcMessageResult(await sendMessageIrc(ctx.to, text, {
|
|
1439
|
+
cfg: ctx.cfg,
|
|
1440
|
+
accountId: ctx.accountId ?? void 0,
|
|
1441
|
+
replyTo: ctx.replyToId ?? void 0,
|
|
1442
|
+
abortSignal: ctx.signal,
|
|
1443
|
+
onPlatformSendDispatch: ctx.onPlatformSendDispatch
|
|
1444
|
+
}));
|
|
1445
|
+
}
|
|
1446
|
+
const sendFormattedIrcText = async (ctx) => {
|
|
1447
|
+
const { chunkTextWithMode, resolveChunkMode, resolveTextChunkLimit } = await import("openclaw/plugin-sdk/reply-chunking");
|
|
1448
|
+
const accountId = ctx.accountId ?? void 0;
|
|
1449
|
+
const textLimit = ctx.formatting?.textLimit ?? resolveTextChunkLimit(ctx.cfg, "irc", accountId, { fallbackLimit: ircOutboundBaseAdapter.textChunkLimit });
|
|
1450
|
+
const chunkMode = ctx.formatting?.chunkMode ?? resolveChunkMode(ctx.cfg, "irc", accountId);
|
|
1451
|
+
const nextReplyToId = createReplyToFanout(ctx);
|
|
1452
|
+
return (await sendIrcMessages(ctx.to, ctx.text, {
|
|
1453
|
+
cfg: ctx.cfg,
|
|
1454
|
+
accountId,
|
|
1455
|
+
abortSignal: ctx.abortSignal,
|
|
1456
|
+
onPlatformSendDispatch: ctx.onPlatformSendDispatch
|
|
1457
|
+
}, (preparedText) => chunkTextWithMode(preparedText, textLimit, chunkMode).map((text) => ({
|
|
1458
|
+
text,
|
|
1459
|
+
replyTo: nextReplyToId()
|
|
1460
|
+
})), async (result) => {
|
|
1461
|
+
await ctx.onDeliveryResult?.(attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
1462
|
+
})).map((result) => attachChannelToResult("irc", toIrcMessageResult(result)));
|
|
1463
|
+
};
|
|
1464
|
+
const ircMessageAdapter = defineChannelMessageAdapter({
|
|
1465
|
+
id: "irc",
|
|
1466
|
+
durableFinal: { capabilities: {
|
|
1467
|
+
text: true,
|
|
1468
|
+
media: true,
|
|
1469
|
+
replyTo: true
|
|
1470
|
+
} },
|
|
1471
|
+
send: {
|
|
1472
|
+
text: sendIrcMessage,
|
|
1473
|
+
media: (ctx) => sendIrcMessage(ctx, ctx.mediaUrl ? `${ctx.text}\n\nAttachment: ${ctx.mediaUrl}` : ctx.text)
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
const isIrcMutableAllowEntry = buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:irc|user):)*[^@]*@/i });
|
|
1477
|
+
const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
|
|
1478
|
+
channel: "irc",
|
|
1479
|
+
detector: isIrcMutableAllowEntry,
|
|
1480
|
+
collectLists: (scope) => collectStandardAllowlistLists(scope, {
|
|
1481
|
+
includeGroups: true,
|
|
1482
|
+
groupField: "allowFrom"
|
|
1483
|
+
})
|
|
1484
|
+
});
|
|
1546
1485
|
const meta = {
|
|
1547
1486
|
id: "irc",
|
|
1548
1487
|
label: "IRC",
|
|
@@ -1658,14 +1597,7 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1658
1597
|
describeAccount: (account) => describeAccountSnapshot({
|
|
1659
1598
|
account,
|
|
1660
1599
|
configured: account.configured,
|
|
1661
|
-
extra:
|
|
1662
|
-
host: account.host,
|
|
1663
|
-
port: account.port,
|
|
1664
|
-
tls: account.tls,
|
|
1665
|
-
nick: account.nick,
|
|
1666
|
-
passwordSource: account.passwordSource,
|
|
1667
|
-
tokenStatus: account.tokenStatus
|
|
1668
|
-
}
|
|
1600
|
+
extra: ircAccountDetails(account)
|
|
1669
1601
|
})
|
|
1670
1602
|
},
|
|
1671
1603
|
secrets: {
|
|
@@ -1768,20 +1700,29 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1768
1700
|
name: account.name,
|
|
1769
1701
|
enabled: account.enabled,
|
|
1770
1702
|
configured: account.configured,
|
|
1771
|
-
extra:
|
|
1772
|
-
host: account.host,
|
|
1773
|
-
port: account.port,
|
|
1774
|
-
tls: account.tls,
|
|
1775
|
-
nick: account.nick,
|
|
1776
|
-
passwordSource: account.passwordSource,
|
|
1777
|
-
tokenStatus: account.tokenStatus
|
|
1778
|
-
}
|
|
1703
|
+
extra: ircAccountDetails(account)
|
|
1779
1704
|
})
|
|
1780
1705
|
}),
|
|
1781
|
-
gateway: { startAccount: async (ctx) =>
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1706
|
+
gateway: { startAccount: async (ctx) => {
|
|
1707
|
+
const account = ctx.account;
|
|
1708
|
+
const statusSink = createAccountStatusSink(ctx);
|
|
1709
|
+
if (!account.configured) throw new Error(`IRC is not configured for account "${account.accountId}" (need host and nick in channels.irc).`);
|
|
1710
|
+
ctx.log?.info?.(`[${account.accountId}] starting IRC provider (${account.host}:${account.port}${account.tls ? " tls" : ""})`);
|
|
1711
|
+
const { monitorIrcProvider } = await import("./channel-runtime-D2sqTm8e.mjs");
|
|
1712
|
+
await runPassiveAccountLifecycle({
|
|
1713
|
+
abortSignal: ctx.abortSignal,
|
|
1714
|
+
start: async () => await monitorIrcProvider({
|
|
1715
|
+
accountId: account.accountId,
|
|
1716
|
+
config: ctx.cfg,
|
|
1717
|
+
runtime: ctx.runtime,
|
|
1718
|
+
abortSignal: ctx.abortSignal,
|
|
1719
|
+
statusSink
|
|
1720
|
+
}),
|
|
1721
|
+
stop: async (monitor) => {
|
|
1722
|
+
await monitor.stop();
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
} }
|
|
1785
1726
|
},
|
|
1786
1727
|
pairing: { text: {
|
|
1787
1728
|
idLabel: "ircUser",
|
|
@@ -1790,7 +1731,7 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1790
1731
|
notify: async ({ cfg, id, message, accountId }) => {
|
|
1791
1732
|
const target = normalizePairingTarget(id);
|
|
1792
1733
|
if (!target) throw new Error(`invalid IRC pairing id: ${id}`);
|
|
1793
|
-
const { sendMessageIrc } = await import("./channel-runtime-
|
|
1734
|
+
const { sendMessageIrc } = await import("./channel-runtime-D2sqTm8e.mjs");
|
|
1794
1735
|
await sendMessageIrc(target, message, {
|
|
1795
1736
|
cfg,
|
|
1796
1737
|
accountId
|
|
@@ -1816,5 +1757,4 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1816
1757
|
}
|
|
1817
1758
|
}
|
|
1818
1759
|
});
|
|
1819
|
-
|
|
1820
|
-
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 };
|
|
1760
|
+
export { listIrcAccountIds as _, buildIrcConnectOptions as a, parseIrcPrefix as c, sanitizeIrcAssistantText as d, createIrcIngressSubject as f, listEnabledIrcAccounts as g, normalizeIrcAllowEntry as h, sendMessageIrc as i, resolveIrcGroupMatch as l, isChannelTarget as m, ircSetupWizard as n, connectIrcClient as o, ircIngressIdentity as p, ircSetupAdapter as r, parseIrcLine as s, ircPlugin as t, resolveIrcGroupRequireMention as u, resolveDefaultIrcAccountId as v, resolveIrcAccount as y };
|