@openclaw/irc 2026.7.2-beta.7 → 2026.7.34
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/{channel-DoavT7vs.js → .setup/channel-SaGThQQW.mjs} +146 -199
- package/dist/.setup/channel-plugin-api-04wlnIps.mjs +3 -0
- package/dist/{channel-runtime-DsN_0hPp.js → .setup/channel-runtime-DBtfWzX8.mjs} +113 -318
- package/dist/{config-schema-BPoye3--.js → .setup/config-schema-BQXbFpTD.mjs} +43 -24
- package/dist/{runtime-xy-FcjJC.js → .setup/runtime-DZfYm3vY.mjs} +1 -1
- package/dist/.setup/secret-contract-DdKIs_mx.mjs +82 -0
- package/dist/.setup/secret-contract-api-CmA70kMR.mjs +3 -0
- package/dist/api.js +2 -2
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/configured-state.js +6 -0
- package/dist/runtime-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/setup-entry.js +3 -2
- package/openclaw.plugin.json +62 -72
- package/package.json +13 -91
- package/dist/doctor-contract-api.js +0 -16
- package/dist/secret-contract-D_DC3YWj.js +0 -42
|
@@ -1,46 +1,62 @@
|
|
|
1
|
-
import { t as IrcChannelConfigSchema } from "./config-schema-
|
|
2
|
-
import { t as getIrcRuntime } from "./runtime-
|
|
3
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
1
|
+
import { t as IrcChannelConfigSchema } from "./config-schema-BQXbFpTD.mjs";
|
|
2
|
+
import { t as getIrcRuntime } from "./runtime-DZfYm3vY.mjs";
|
|
3
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DdKIs_mx.mjs";
|
|
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
|
-
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, parseOptionalDelimitedEntries } from "openclaw/plugin-sdk/channel-core";
|
|
8
|
-
import {
|
|
7
|
+
import { buildChannelOutboundSessionRoute, createChatChannelPlugin, parseOptionalDelimitedEntries, tryReadSecretFileSync } from "openclaw/plugin-sdk/channel-core";
|
|
8
|
+
import { composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
9
9
|
import { createChannelDirectoryAdapter, createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-runtime";
|
|
10
10
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
11
11
|
import { buildBaseChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
12
|
-
import { resolveAccountWithDefaultFallback } from "openclaw/plugin-sdk/account-core";
|
|
13
12
|
import { DEFAULT_ACCOUNT_ID, DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
13
|
+
import { resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
14
14
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
15
|
-
import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
|
|
16
|
-
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
17
15
|
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
18
16
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringifiedOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
|
-
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter,
|
|
17
|
+
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
20
18
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
21
19
|
import { chunkTextForOutbound, convertMarkdownTables, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
20
|
+
import { runStoppablePassiveMonitor } from "openclaw/plugin-sdk/extension-shared";
|
|
22
21
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
23
22
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
24
23
|
import net from "node:net";
|
|
25
24
|
import tls from "node:tls";
|
|
26
25
|
import { withTimeout } from "openclaw/plugin-sdk/security-runtime";
|
|
27
26
|
import { randomUUID } from "node:crypto";
|
|
28
|
-
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
29
27
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
|
|
30
28
|
import { applyAccountNameToChannelSection, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicySetter, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
31
29
|
//#region extensions/irc/src/accounts.ts
|
|
30
|
+
const TRUTHY_ENV = /* @__PURE__ */ new Set([
|
|
31
|
+
"true",
|
|
32
|
+
"1",
|
|
33
|
+
"yes",
|
|
34
|
+
"on"
|
|
35
|
+
]);
|
|
36
|
+
function parseTruthy(value) {
|
|
37
|
+
if (!value) return false;
|
|
38
|
+
return TRUTHY_ENV.has(normalizeLowercaseStringOrEmpty(value));
|
|
39
|
+
}
|
|
32
40
|
function parseIntEnv(value) {
|
|
33
41
|
if (!value?.trim()) return;
|
|
34
42
|
const parsed = parseStrictPositiveInteger(value);
|
|
35
43
|
if (parsed === void 0 || parsed > 65535) return;
|
|
36
44
|
return parsed;
|
|
37
45
|
}
|
|
38
|
-
const { listAccountIds: listIrcAccountIds, resolveDefaultAccountId: resolveDefaultIrcAccountId
|
|
46
|
+
const { listAccountIds: listIrcAccountIds, resolveDefaultAccountId: resolveDefaultIrcAccountId } = createAccountListHelpers("irc", {
|
|
39
47
|
normalizeAccountId,
|
|
40
|
-
omitKeys: ["defaultAccount"],
|
|
41
|
-
nestedObjectKeys: ["nickserv"],
|
|
42
48
|
hasImplicitDefaultAccount: (cfg) => Boolean((cfg.channels?.irc?.host?.trim() || process.env.IRC_HOST?.trim()) && (cfg.channels?.irc?.nick?.trim() || process.env.IRC_NICK?.trim()))
|
|
43
49
|
});
|
|
50
|
+
function mergeIrcAccountConfig(cfg, accountId) {
|
|
51
|
+
return resolveMergedAccountConfig({
|
|
52
|
+
channelConfig: cfg.channels?.irc,
|
|
53
|
+
accounts: cfg.channels?.irc?.accounts,
|
|
54
|
+
accountId,
|
|
55
|
+
omitKeys: ["defaultAccount"],
|
|
56
|
+
normalizeAccountId,
|
|
57
|
+
nestedObjectKeys: ["nickserv"]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
44
60
|
function resolvePassword(accountId, merged) {
|
|
45
61
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
46
62
|
const envPassword = process.env.IRC_PASSWORD?.trim();
|
|
@@ -50,25 +66,11 @@ function resolvePassword(accountId, merged) {
|
|
|
50
66
|
};
|
|
51
67
|
}
|
|
52
68
|
if (merged.passwordFile?.trim()) {
|
|
53
|
-
|
|
54
|
-
const filePassword = tryReadSecretFileSync(merged.passwordFile, "IRC password file", {
|
|
55
|
-
rejectSymlink: true,
|
|
56
|
-
credentialDiagnostic: {
|
|
57
|
-
configPath: `channels.irc.accounts.${accountId}.passwordFile`,
|
|
58
|
-
report: (value) => {
|
|
59
|
-
diagnostic = value;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
69
|
+
const filePassword = tryReadSecretFileSync(merged.passwordFile, "IRC password file", { rejectSymlink: true });
|
|
63
70
|
if (filePassword) return {
|
|
64
71
|
password: filePassword,
|
|
65
72
|
source: "passwordFile"
|
|
66
73
|
};
|
|
67
|
-
return {
|
|
68
|
-
password: "",
|
|
69
|
-
source: "passwordFile",
|
|
70
|
-
diagnostic
|
|
71
|
-
};
|
|
72
74
|
}
|
|
73
75
|
const configPassword = normalizeResolvedSecretInputString({
|
|
74
76
|
value: merged.password,
|
|
@@ -92,34 +94,23 @@ function resolveNickServConfig(accountId, nickserv) {
|
|
|
92
94
|
value: base.password,
|
|
93
95
|
path: `channels.irc.accounts.${accountId}.nickserv.password`
|
|
94
96
|
}) || envPassword || "";
|
|
95
|
-
|
|
96
|
-
if (!resolvedPassword && passwordFile) resolvedPassword = tryReadSecretFileSync(passwordFile, "IRC NickServ password file", {
|
|
97
|
-
rejectSymlink: true,
|
|
98
|
-
credentialDiagnostic: {
|
|
99
|
-
configPath: `channels.irc.accounts.${accountId}.nickserv.passwordFile`,
|
|
100
|
-
report: (value) => {
|
|
101
|
-
diagnostic = value;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}) ?? "";
|
|
97
|
+
if (!resolvedPassword && passwordFile) resolvedPassword = tryReadSecretFileSync(passwordFile, "IRC NickServ password file", { rejectSymlink: true }) ?? "";
|
|
105
98
|
return {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
registerEmail: base.registerEmail?.trim() || envRegisterEmail || void 0
|
|
112
|
-
},
|
|
113
|
-
diagnostic
|
|
99
|
+
...base,
|
|
100
|
+
service: normalizeOptionalString(base.service),
|
|
101
|
+
passwordFile: passwordFile || void 0,
|
|
102
|
+
password: resolvedPassword || void 0,
|
|
103
|
+
registerEmail: base.registerEmail?.trim() || envRegisterEmail || void 0
|
|
114
104
|
};
|
|
115
105
|
}
|
|
116
106
|
function resolveIrcAccount(params) {
|
|
107
|
+
const hasExplicitAccountId = Boolean(params.accountId?.trim());
|
|
117
108
|
const baseEnabled = params.cfg.channels?.irc?.enabled !== false;
|
|
118
109
|
const resolve = (accountId) => {
|
|
119
110
|
const merged = mergeIrcAccountConfig(params.cfg, accountId);
|
|
120
111
|
const accountEnabled = merged.enabled !== false;
|
|
121
112
|
const enabled = baseEnabled && accountEnabled;
|
|
122
|
-
const tls = typeof merged.tls === "boolean" ? merged.tls : accountId === DEFAULT_ACCOUNT_ID && process.env.IRC_TLS ?
|
|
113
|
+
const tls = typeof merged.tls === "boolean" ? merged.tls : accountId === DEFAULT_ACCOUNT_ID && process.env.IRC_TLS ? parseTruthy(process.env.IRC_TLS) : true;
|
|
123
114
|
const envPort = accountId === DEFAULT_ACCOUNT_ID ? parseIntEnv(process.env.IRC_PORT) : void 0;
|
|
124
115
|
const port = merged.port ?? envPort ?? (tls ? 6697 : 6667);
|
|
125
116
|
const envChannels = accountId === DEFAULT_ACCOUNT_ID ? parseOptionalDelimitedEntries(process.env.IRC_CHANNELS) : void 0;
|
|
@@ -128,8 +119,7 @@ function resolveIrcAccount(params) {
|
|
|
128
119
|
const username = (merged.username?.trim() || (accountId === DEFAULT_ACCOUNT_ID ? process.env.IRC_USERNAME?.trim() : "") || nick || "openclaw").trim();
|
|
129
120
|
const realname = (merged.realname?.trim() || (accountId === DEFAULT_ACCOUNT_ID ? process.env.IRC_REALNAME?.trim() : "") || "OpenClaw").trim();
|
|
130
121
|
const passwordResolution = resolvePassword(accountId, merged);
|
|
131
|
-
const
|
|
132
|
-
const diagnostics = [passwordResolution.diagnostic, nickservResolution.diagnostic].filter((diagnostic) => Boolean(diagnostic));
|
|
122
|
+
const nickserv = resolveNickServConfig(accountId, merged.nickserv);
|
|
133
123
|
const config = {
|
|
134
124
|
...merged,
|
|
135
125
|
channels: merged.channels ?? envChannels,
|
|
@@ -139,7 +129,7 @@ function resolveIrcAccount(params) {
|
|
|
139
129
|
nick,
|
|
140
130
|
username,
|
|
141
131
|
realname,
|
|
142
|
-
nickserv
|
|
132
|
+
nickserv
|
|
143
133
|
};
|
|
144
134
|
return {
|
|
145
135
|
accountId,
|
|
@@ -154,18 +144,17 @@ function resolveIrcAccount(params) {
|
|
|
154
144
|
realname,
|
|
155
145
|
password: passwordResolution.password,
|
|
156
146
|
passwordSource: passwordResolution.source,
|
|
157
|
-
tokenStatus: diagnostics.length > 0 ? "configured_unavailable" : passwordResolution.password || nickservResolution.config.password ? "available" : "missing",
|
|
158
|
-
...diagnostics.length > 0 ? { credentialDiagnostics: diagnostics } : {},
|
|
159
147
|
config
|
|
160
148
|
};
|
|
161
149
|
};
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
const primary = resolve(normalizeAccountId(params.accountId));
|
|
151
|
+
if (hasExplicitAccountId) return primary;
|
|
152
|
+
if (primary.configured) return primary;
|
|
153
|
+
const fallbackId = resolveDefaultIrcAccountId(params.cfg);
|
|
154
|
+
if (fallbackId === primary.accountId) return primary;
|
|
155
|
+
const fallback = resolve(fallbackId);
|
|
156
|
+
if (!fallback.configured) return primary;
|
|
157
|
+
return fallback;
|
|
169
158
|
}
|
|
170
159
|
function listEnabledIrcAccounts(cfg) {
|
|
171
160
|
return listIrcAccountIds(cfg).map((accountId) => resolveIrcAccount({
|
|
@@ -173,17 +162,42 @@ function listEnabledIrcAccounts(cfg) {
|
|
|
173
162
|
accountId
|
|
174
163
|
})).filter((account) => account.enabled);
|
|
175
164
|
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region extensions/irc/src/doctor.ts
|
|
167
|
+
function asObjectRecord(value) {
|
|
168
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
169
|
+
}
|
|
170
|
+
function isIrcMutableAllowEntry(raw) {
|
|
171
|
+
const text = normalizeLowercaseStringOrEmpty(raw);
|
|
172
|
+
if (!text || text === "*") return false;
|
|
173
|
+
return !text.replace(/^irc:/, "").replace(/^user:/, "").trim().includes("@");
|
|
174
|
+
}
|
|
176
175
|
const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
|
|
177
176
|
channel: "irc",
|
|
178
|
-
detector:
|
|
179
|
-
collectLists: (scope) =>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
detector: isIrcMutableAllowEntry,
|
|
178
|
+
collectLists: (scope) => {
|
|
179
|
+
const lists = [{
|
|
180
|
+
pathLabel: `${scope.prefix}.allowFrom`,
|
|
181
|
+
list: scope.account.allowFrom
|
|
182
|
+
}, {
|
|
183
|
+
pathLabel: `${scope.prefix}.groupAllowFrom`,
|
|
184
|
+
list: scope.account.groupAllowFrom
|
|
185
|
+
}];
|
|
186
|
+
const groups = asObjectRecord(scope.account.groups);
|
|
187
|
+
if (groups) for (const [groupKey, groupRaw] of Object.entries(groups)) {
|
|
188
|
+
const group = asObjectRecord(groupRaw);
|
|
189
|
+
if (!group) continue;
|
|
190
|
+
lists.push({
|
|
191
|
+
pathLabel: `${scope.prefix}.groups.${groupKey}.allowFrom`,
|
|
192
|
+
list: group.allowFrom
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return lists;
|
|
196
|
+
}
|
|
183
197
|
});
|
|
184
198
|
//#endregion
|
|
185
199
|
//#region extensions/irc/src/gateway.ts
|
|
186
|
-
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
200
|
+
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-DBtfWzX8.mjs"));
|
|
187
201
|
async function startIrcGatewayAccount(ctx) {
|
|
188
202
|
const account = ctx.account;
|
|
189
203
|
const statusSink = createAccountStatusSink({
|
|
@@ -193,7 +207,7 @@ async function startIrcGatewayAccount(ctx) {
|
|
|
193
207
|
if (!account.configured) throw new Error(`IRC is not configured for account "${account.accountId}" (need host and nick in channels.irc).`);
|
|
194
208
|
ctx.log?.info?.(`[${account.accountId}] starting IRC provider (${account.host}:${account.port}${account.tls ? " tls" : ""})`);
|
|
195
209
|
const { monitorIrcProvider } = await loadIrcChannelRuntime$1();
|
|
196
|
-
await
|
|
210
|
+
await runStoppablePassiveMonitor({
|
|
197
211
|
abortSignal: ctx.abortSignal,
|
|
198
212
|
start: async () => await monitorIrcProvider({
|
|
199
213
|
accountId: account.accountId,
|
|
@@ -201,10 +215,7 @@ async function startIrcGatewayAccount(ctx) {
|
|
|
201
215
|
runtime: ctx.runtime,
|
|
202
216
|
abortSignal: ctx.abortSignal,
|
|
203
217
|
statusSink
|
|
204
|
-
})
|
|
205
|
-
stop: async (monitor) => {
|
|
206
|
-
await monitor.stop();
|
|
207
|
-
}
|
|
218
|
+
})
|
|
208
219
|
});
|
|
209
220
|
}
|
|
210
221
|
//#endregion
|
|
@@ -538,7 +549,7 @@ async function connectIrcClient(options) {
|
|
|
538
549
|
if (line.command === "PRIVMSG") {
|
|
539
550
|
const targetParam = line.params[0];
|
|
540
551
|
const target = targetParam ? targetParam.trim() : "";
|
|
541
|
-
const text = line.trailing
|
|
552
|
+
const text = line.trailing != null ? line.trailing : "";
|
|
542
553
|
const prefix = parseIrcPrefix(line.prefix);
|
|
543
554
|
const senderNick = prefix.nick ? prefix.nick.trim() : "";
|
|
544
555
|
if (!target || !senderNick || !text.trim()) continue;
|
|
@@ -546,7 +557,6 @@ async function connectIrcClient(options) {
|
|
|
546
557
|
senderNick,
|
|
547
558
|
senderUser: prefix.user ? prefix.user.trim() : void 0,
|
|
548
559
|
senderHost: prefix.host ? prefix.host.trim() : void 0,
|
|
549
|
-
connectedNick: currentNick,
|
|
550
560
|
target,
|
|
551
561
|
text,
|
|
552
562
|
rawLine
|
|
@@ -777,59 +787,51 @@ const ircMessageAdapter = defineChannelMessageAdapter({
|
|
|
777
787
|
});
|
|
778
788
|
//#endregion
|
|
779
789
|
//#region extensions/irc/src/outbound-base.ts
|
|
780
|
-
function sanitizeIrcAssistantText(text) {
|
|
781
|
-
return sanitizeForPlainText(sanitizeAssistantVisibleText(text));
|
|
782
|
-
}
|
|
783
790
|
const ircOutboundBaseAdapter = {
|
|
784
791
|
deliveryMode: "direct",
|
|
785
792
|
chunker: chunkTextForOutbound,
|
|
786
793
|
chunkerMode: "markdown",
|
|
787
794
|
textChunkLimit: 350,
|
|
788
|
-
sanitizeText: ({ text }) =>
|
|
795
|
+
sanitizeText: ({ text }) => sanitizeForPlainText(sanitizeAssistantVisibleText(text))
|
|
789
796
|
};
|
|
790
797
|
//#endregion
|
|
791
798
|
//#region extensions/irc/src/policy.ts
|
|
792
|
-
function
|
|
793
|
-
const
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
799
|
+
function resolveIrcGroupMatch(params) {
|
|
800
|
+
const groups = params.groups ?? {};
|
|
801
|
+
const hasConfiguredGroups = Object.keys(groups).length > 0;
|
|
802
|
+
const direct = groups[params.target];
|
|
803
|
+
if (direct) return {
|
|
804
|
+
allowed: true,
|
|
805
|
+
groupConfig: direct,
|
|
806
|
+
wildcardConfig: groups["*"],
|
|
807
|
+
hasConfiguredGroups
|
|
801
808
|
};
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
809
|
+
const targetLower = normalizeLowercaseStringOrEmpty(params.target);
|
|
810
|
+
const directKey = Object.keys(groups).find((key) => normalizeLowercaseStringOrEmpty(key) === targetLower);
|
|
811
|
+
if (directKey) {
|
|
812
|
+
const matched = groups[directKey];
|
|
813
|
+
if (matched) return {
|
|
814
|
+
allowed: true,
|
|
815
|
+
groupConfig: matched,
|
|
816
|
+
wildcardConfig: groups["*"],
|
|
817
|
+
hasConfiguredGroups
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
const wildcard = groups["*"];
|
|
821
|
+
if (wildcard) return {
|
|
822
|
+
allowed: true,
|
|
823
|
+
wildcardConfig: wildcard,
|
|
824
|
+
hasConfiguredGroups
|
|
806
825
|
};
|
|
807
|
-
}
|
|
808
|
-
function resolveIrcGroupMatch(params) {
|
|
809
|
-
const { path } = resolveIrcGroupScope(params);
|
|
810
|
-
const key = path[0];
|
|
811
|
-
const groupConfig = key ? params.groups?.[key] : void 0;
|
|
812
|
-
const wildcardConfig = params.groups?.["*"];
|
|
813
826
|
return {
|
|
814
|
-
allowed:
|
|
815
|
-
|
|
816
|
-
wildcardConfig,
|
|
817
|
-
hasConfiguredGroups: Object.keys(params.groups ?? {}).length > 0
|
|
827
|
+
allowed: false,
|
|
828
|
+
hasConfiguredGroups
|
|
818
829
|
};
|
|
819
830
|
}
|
|
820
|
-
function
|
|
821
|
-
|
|
822
|
-
return
|
|
823
|
-
|
|
824
|
-
path
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
function resolveIrcGroupToolPolicy(params) {
|
|
828
|
-
const { tree, path } = resolveIrcGroupScope(params);
|
|
829
|
-
return resolveScopeToolsPolicy({
|
|
830
|
-
tree,
|
|
831
|
-
path
|
|
832
|
-
});
|
|
831
|
+
function resolveIrcRequireMention(params) {
|
|
832
|
+
if (params.groupConfig?.requireMention !== void 0) return params.groupConfig.requireMention;
|
|
833
|
+
if (params.wildcardConfig?.requireMention !== void 0) return params.wildcardConfig.requireMention;
|
|
834
|
+
return true;
|
|
833
835
|
}
|
|
834
836
|
//#endregion
|
|
835
837
|
//#region extensions/irc/src/probe.ts
|
|
@@ -927,7 +929,6 @@ function setIrcGroupAccess(cfg, accountId, policy, entries, normalizeGroupEntry)
|
|
|
927
929
|
});
|
|
928
930
|
}
|
|
929
931
|
const ircSetupAdapter = {
|
|
930
|
-
singleAccountKeysToMove: ["password"],
|
|
931
932
|
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
932
933
|
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
933
934
|
cfg,
|
|
@@ -964,75 +965,6 @@ const ircSetupAdapter = {
|
|
|
964
965
|
});
|
|
965
966
|
}
|
|
966
967
|
};
|
|
967
|
-
const ircSetupContract = defineChannelSetupContract({
|
|
968
|
-
fields: {
|
|
969
|
-
host: {
|
|
970
|
-
kind: "string",
|
|
971
|
-
cli: {
|
|
972
|
-
flags: "--host <host>",
|
|
973
|
-
description: "IRC server host"
|
|
974
|
-
}
|
|
975
|
-
},
|
|
976
|
-
port: {
|
|
977
|
-
kind: "string",
|
|
978
|
-
cli: {
|
|
979
|
-
flags: "--port <port>",
|
|
980
|
-
description: "IRC server port"
|
|
981
|
-
}
|
|
982
|
-
},
|
|
983
|
-
tls: {
|
|
984
|
-
kind: "boolean",
|
|
985
|
-
cli: {
|
|
986
|
-
flags: "--tls",
|
|
987
|
-
description: "Use TLS for IRC"
|
|
988
|
-
}
|
|
989
|
-
},
|
|
990
|
-
nick: {
|
|
991
|
-
kind: "string",
|
|
992
|
-
cli: {
|
|
993
|
-
flags: "--nick <nick>",
|
|
994
|
-
description: "IRC nickname"
|
|
995
|
-
}
|
|
996
|
-
},
|
|
997
|
-
username: {
|
|
998
|
-
kind: "string",
|
|
999
|
-
cli: {
|
|
1000
|
-
flags: "--username <name>",
|
|
1001
|
-
description: "IRC username"
|
|
1002
|
-
}
|
|
1003
|
-
},
|
|
1004
|
-
realname: {
|
|
1005
|
-
kind: "string",
|
|
1006
|
-
cli: {
|
|
1007
|
-
flags: "--realname <name>",
|
|
1008
|
-
description: "IRC real name"
|
|
1009
|
-
}
|
|
1010
|
-
},
|
|
1011
|
-
channels: {
|
|
1012
|
-
kind: "string-list",
|
|
1013
|
-
cli: {
|
|
1014
|
-
flags: "--channels <names>",
|
|
1015
|
-
description: "IRC channels"
|
|
1016
|
-
}
|
|
1017
|
-
},
|
|
1018
|
-
password: {
|
|
1019
|
-
kind: "string",
|
|
1020
|
-
sensitive: true,
|
|
1021
|
-
cli: {
|
|
1022
|
-
flags: "--password <password>",
|
|
1023
|
-
description: "IRC server password"
|
|
1024
|
-
}
|
|
1025
|
-
},
|
|
1026
|
-
useEnv: {
|
|
1027
|
-
kind: "boolean",
|
|
1028
|
-
cli: {
|
|
1029
|
-
flags: "--use-env",
|
|
1030
|
-
description: "Use IRC environment configuration"
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
},
|
|
1034
|
-
legacyAdapter: ircSetupAdapter
|
|
1035
|
-
});
|
|
1036
968
|
//#endregion
|
|
1037
969
|
//#region extensions/irc/src/setup-surface.ts
|
|
1038
970
|
const t = createSetupTranslator();
|
|
@@ -1226,7 +1158,8 @@ const ircSetupWizard = {
|
|
|
1226
1158
|
return String(defaultPort);
|
|
1227
1159
|
},
|
|
1228
1160
|
validate: ({ value }) => {
|
|
1229
|
-
const
|
|
1161
|
+
const raw = normalizeStringifiedOptionalString(value) ?? "";
|
|
1162
|
+
const parsed = parseStrictPositiveInteger(raw);
|
|
1230
1163
|
return parsed !== void 0 && parsed <= 65535 ? void 0 : "Use a port between 1 and 65535";
|
|
1231
1164
|
},
|
|
1232
1165
|
normalizeValue: ({ value }) => String(parsePort(value, 6697)),
|
|
@@ -1398,7 +1331,7 @@ const meta = {
|
|
|
1398
1331
|
systemImage: "number",
|
|
1399
1332
|
markdownCapable: true
|
|
1400
1333
|
};
|
|
1401
|
-
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
1334
|
+
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-DBtfWzX8.mjs"));
|
|
1402
1335
|
function normalizePairingTarget(raw) {
|
|
1403
1336
|
const normalized = normalizeIrcAllowEntry(raw);
|
|
1404
1337
|
if (!normalized) return "";
|
|
@@ -1454,7 +1387,7 @@ const resolveIrcDmPolicy = createScopedDmSecurityResolver({
|
|
|
1454
1387
|
policyPathSuffix: "dmPolicy",
|
|
1455
1388
|
normalizeEntry: (raw) => normalizeIrcAllowEntry(raw)
|
|
1456
1389
|
});
|
|
1457
|
-
const
|
|
1390
|
+
const collectIrcGroupPolicyWarnings = createAllowlistProviderOpenWarningCollector({
|
|
1458
1391
|
providerConfigPresent: (cfg) => cfg.channels?.irc !== void 0,
|
|
1459
1392
|
resolveGroupPolicy: (account) => account.config.groupPolicy,
|
|
1460
1393
|
buildOpenWarning: {
|
|
@@ -1462,7 +1395,8 @@ const collectIrcSecurityWarnings = composeAccountWarningCollectors(createAllowli
|
|
|
1462
1395
|
openBehavior: "allows all channels and senders (mention-gated)",
|
|
1463
1396
|
remediation: "Prefer channels.irc.groupPolicy=\"allowlist\" with channels.irc.groups"
|
|
1464
1397
|
}
|
|
1465
|
-
})
|
|
1398
|
+
});
|
|
1399
|
+
const collectIrcSecurityWarnings = composeAccountWarningCollectors(collectIrcGroupPolicyWarnings, (account) => !account.config.tls && "- IRC TLS is disabled (channels.irc.tls=false); traffic and credentials are plaintext.", (account) => account.config.nickserv?.register && "- IRC NickServ registration is enabled (channels.irc.nickserv.register=true); this sends \"REGISTER\" on every connect. Disable after first successful registration.", (account) => account.config.nickserv?.register && !account.config.nickserv.password?.trim() && "- IRC NickServ registration is enabled but no NickServ password is resolved; set channels.irc.nickserv.password, channels.irc.nickserv.passwordFile, or IRC_NICKSERV_PASSWORD.");
|
|
1466
1400
|
const ircPlugin = createChatChannelPlugin({
|
|
1467
1401
|
base: {
|
|
1468
1402
|
id: "irc",
|
|
@@ -1471,7 +1405,6 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1471
1405
|
quickstartAllowFrom: true
|
|
1472
1406
|
},
|
|
1473
1407
|
setup: ircSetupAdapter,
|
|
1474
|
-
setupContract: ircSetupContract,
|
|
1475
1408
|
setupWizard: ircSetupWizard,
|
|
1476
1409
|
capabilities: {
|
|
1477
1410
|
chatTypes: ["direct", "group"],
|
|
@@ -1492,8 +1425,7 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1492
1425
|
port: account.port,
|
|
1493
1426
|
tls: account.tls,
|
|
1494
1427
|
nick: account.nick,
|
|
1495
|
-
passwordSource: account.passwordSource
|
|
1496
|
-
tokenStatus: account.tokenStatus
|
|
1428
|
+
passwordSource: account.passwordSource
|
|
1497
1429
|
}
|
|
1498
1430
|
})
|
|
1499
1431
|
},
|
|
@@ -1512,10 +1444,14 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1512
1444
|
accountId
|
|
1513
1445
|
});
|
|
1514
1446
|
if (!groupId) return true;
|
|
1515
|
-
|
|
1447
|
+
const match = resolveIrcGroupMatch({
|
|
1516
1448
|
groups: account.config.groups,
|
|
1517
1449
|
target: groupId
|
|
1518
1450
|
});
|
|
1451
|
+
return resolveIrcRequireMention({
|
|
1452
|
+
groupConfig: match.groupConfig,
|
|
1453
|
+
wildcardConfig: match.wildcardConfig
|
|
1454
|
+
});
|
|
1519
1455
|
},
|
|
1520
1456
|
resolveToolPolicy: ({ cfg, accountId, groupId }) => {
|
|
1521
1457
|
const account = resolveIrcAccount({
|
|
@@ -1523,10 +1459,11 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1523
1459
|
accountId
|
|
1524
1460
|
});
|
|
1525
1461
|
if (!groupId) return;
|
|
1526
|
-
|
|
1462
|
+
const match = resolveIrcGroupMatch({
|
|
1527
1463
|
groups: account.config.groups,
|
|
1528
1464
|
target: groupId
|
|
1529
1465
|
});
|
|
1466
|
+
return match.groupConfig?.tools ?? match.wildcardConfig?.tools;
|
|
1530
1467
|
}
|
|
1531
1468
|
},
|
|
1532
1469
|
messaging: {
|
|
@@ -1600,8 +1537,7 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1600
1537
|
port: account.port,
|
|
1601
1538
|
tls: account.tls,
|
|
1602
1539
|
nick: account.nick,
|
|
1603
|
-
passwordSource: account.passwordSource
|
|
1604
|
-
tokenStatus: account.tokenStatus
|
|
1540
|
+
passwordSource: account.passwordSource
|
|
1605
1541
|
}
|
|
1606
1542
|
})
|
|
1607
1543
|
}),
|
|
@@ -1629,13 +1565,24 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1629
1565
|
base: ircOutboundBaseAdapter,
|
|
1630
1566
|
attachedResults: {
|
|
1631
1567
|
channel: "irc",
|
|
1632
|
-
sendText: ({
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1568
|
+
sendText: async ({ cfg, to, text, accountId, replyToId }) => {
|
|
1569
|
+
const { sendMessageIrc } = await loadIrcChannelRuntime();
|
|
1570
|
+
return await sendMessageIrc(to, text, {
|
|
1571
|
+
cfg,
|
|
1572
|
+
accountId: accountId ?? void 0,
|
|
1573
|
+
replyTo: replyToId ?? void 0
|
|
1574
|
+
});
|
|
1575
|
+
},
|
|
1576
|
+
sendMedia: async ({ cfg, to, text, mediaUrl, accountId, replyToId }) => {
|
|
1577
|
+
const { sendMessageIrc } = await loadIrcChannelRuntime();
|
|
1578
|
+
return await sendMessageIrc(to, mediaUrl ? `${text}\n\nAttachment: ${mediaUrl}` : text, {
|
|
1579
|
+
cfg,
|
|
1580
|
+
accountId: accountId ?? void 0,
|
|
1581
|
+
replyTo: replyToId ?? void 0
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1637
1584
|
}
|
|
1638
1585
|
}
|
|
1639
1586
|
});
|
|
1640
1587
|
//#endregion
|
|
1641
|
-
export {
|
|
1588
|
+
export { resolveIrcRequireMention as a, isChannelTarget as c, connectIrcClient as d, makeIrcMessageId as f, resolveIrcAccount as g, resolveDefaultIrcAccountId as h, resolveIrcGroupMatch as i, normalizeIrcAllowEntry as l, listIrcAccountIds as m, ircSetupWizard as n, sendMessageIrc as o, listEnabledIrcAccounts as p, ircSetupAdapter as r, buildIrcAllowlistCandidates as s, ircPlugin as t, buildIrcConnectOptions as u };
|