@openclaw/irc 2026.7.2-beta.7 → 2026.7.33

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.
@@ -1,46 +1,62 @@
1
- import { t as IrcChannelConfigSchema } from "./config-schema-BPoye3--.js";
2
- import { t as getIrcRuntime } from "./runtime-xy-FcjJC.js";
3
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-D_DC3YWj.js";
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 { buildMutableAllowEntryDetector, collectStandardAllowlistLists, composeAccountWarningCollectors, createAllowlistProviderOpenWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, resolveScopeKeyCaseInsensitive, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
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, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
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, resolveAccountConfig: mergeIrcAccountConfig } = createAccountListHelpers("irc", {
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
- let diagnostic;
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
- let diagnostic;
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
- config: {
107
- ...base,
108
- service: normalizeOptionalString(base.service),
109
- passwordFile: passwordFile || void 0,
110
- password: resolvedPassword || void 0,
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 ? isTruthyEnvValue(process.env.IRC_TLS) : true;
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 nickservResolution = resolveNickServConfig(accountId, merged.nickserv);
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: nickservResolution.config
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
- return resolveAccountWithDefaultFallback({
163
- accountId: params.accountId,
164
- normalizeAccountId,
165
- resolvePrimary: resolve,
166
- hasCredential: (account) => account.configured,
167
- resolveDefaultAccountId: () => resolveDefaultIrcAccountId(params.cfg)
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: buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:irc|user):)*[^@]*@/i }),
179
- collectLists: (scope) => collectStandardAllowlistLists(scope, {
180
- includeGroups: true,
181
- groupField: "allowFrom"
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-DsN_0hPp.js"));
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 runPassiveAccountLifecycle({
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 ?? line.params[1] ?? "";
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 }) => sanitizeIrcAssistantText(text)
795
+ sanitizeText: ({ text }) => sanitizeForPlainText(sanitizeAssistantVisibleText(text))
789
796
  };
790
797
  //#endregion
791
798
  //#region extensions/irc/src/policy.ts
792
- function resolveIrcGroupScope(params) {
793
- const { "*": wildcard, ...groups } = params.groups ?? {};
794
- const project = (entry) => ({
795
- requireMention: entry.requireMention,
796
- tools: entry.tools
797
- });
798
- const tree = {
799
- defaults: wildcard ? project(wildcard) : void 0,
800
- scopes: Object.fromEntries(Object.entries(groups).map(([key, entry]) => [key, project(entry)]))
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 key = resolveScopeKeyCaseInsensitive(tree, params.target);
803
- return {
804
- tree,
805
- path: key ? [key] : []
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: Boolean(groupConfig ?? wildcardConfig),
815
- groupConfig,
816
- wildcardConfig,
817
- hasConfiguredGroups: Object.keys(params.groups ?? {}).length > 0
827
+ allowed: false,
828
+ hasConfiguredGroups
818
829
  };
819
830
  }
820
- function resolveIrcGroupRequireMention(params) {
821
- const { tree, path } = resolveIrcGroupScope(params);
822
- return resolveScopeRequireMention({
823
- tree,
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 parsed = parseStrictPositiveInteger(normalizeStringifiedOptionalString(value) ?? "");
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-DsN_0hPp.js"));
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 collectIrcSecurityWarnings = composeAccountWarningCollectors(createAllowlistProviderOpenWarningCollector({
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
- }), (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.");
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
- return resolveIrcGroupRequireMention({
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
- return resolveIrcGroupToolPolicy({
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: ({ onDeliveryResult: _onDeliveryResult, ...ctx }) => ircMessageAdapter.send.text(ctx),
1633
- sendMedia: ({ onDeliveryResult: _onDeliveryResult, mediaUrl, ...ctx }) => ircMessageAdapter.send.media({
1634
- ...ctx,
1635
- mediaUrl: mediaUrl ?? ""
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 { resolveDefaultIrcAccountId as _, resolveIrcGroupRequireMention as a, buildIrcAllowlistCandidates as c, buildIrcConnectOptions as d, connectIrcClient as f, listIrcAccountIds as g, listEnabledIrcAccounts as h, resolveIrcGroupMatch as i, isChannelTarget as l, parseIrcPrefix as m, ircSetupWizard as n, sanitizeIrcAssistantText as o, parseIrcLine as p, ircSetupAdapter as r, sendMessageIrc as s, ircPlugin as t, normalizeIrcAllowEntry as u, resolveIrcAccount as v };
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 };
@@ -0,0 +1,3 @@
1
+ import { t as ircPlugin } from "./channel-SaGThQQW.mjs";
2
+ import "../channel-plugin-api.js";
3
+ export { ircPlugin };