@openclaw/irc 2026.7.2-beta.3 → 2026.7.2-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +1 -1
- package/dist/{channel-BC0q2_Tg.js → channel-BZclM5wY.js} +99 -45
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-runtime-DBNGrI_Y.js → channel-runtime-CRzAwKGK.js} +264 -68
- package/openclaw.plugin.json +0 -14
- package/package.json +91 -12
- package/npm-shrinkwrap.json +0 -24
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as resolveIrcAccount, g as resolveDefaultIrcAccountId, h as listIrcAccountIds, m as listEnabledIrcAccounts, n as ircSetupWizard, r as ircSetupAdapter, t as ircPlugin } from "./channel-BZclM5wY.js";
|
|
2
2
|
import { n as setIrcRuntime } from "./runtime-xy-FcjJC.js";
|
|
3
3
|
export { ircPlugin, ircSetupAdapter, ircSetupWizard, listEnabledIrcAccounts, listIrcAccountIds, resolveDefaultIrcAccountId, resolveIrcAccount, setIrcRuntime };
|
|
@@ -9,22 +9,22 @@ import { buildMutableAllowEntryDetector, collectStandardAllowlistLists, composeA
|
|
|
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";
|
|
12
13
|
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
15
|
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
16
16
|
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
17
17
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringifiedOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
18
|
-
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
18
|
+
import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, runPassiveAccountLifecycle, sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
|
|
19
19
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
20
20
|
import { chunkTextForOutbound, convertMarkdownTables, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
21
|
-
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";
|
|
27
|
+
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
28
28
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
|
|
29
29
|
import { applyAccountNameToChannelSection, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicySetter, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
30
30
|
//#region extensions/irc/src/accounts.ts
|
|
@@ -44,20 +44,12 @@ function parseIntEnv(value) {
|
|
|
44
44
|
if (parsed === void 0 || parsed > 65535) return;
|
|
45
45
|
return parsed;
|
|
46
46
|
}
|
|
47
|
-
const { listAccountIds: listIrcAccountIds, resolveDefaultAccountId: resolveDefaultIrcAccountId } = createAccountListHelpers("irc", {
|
|
47
|
+
const { listAccountIds: listIrcAccountIds, resolveDefaultAccountId: resolveDefaultIrcAccountId, resolveAccountConfig: mergeIrcAccountConfig } = createAccountListHelpers("irc", {
|
|
48
48
|
normalizeAccountId,
|
|
49
|
+
omitKeys: ["defaultAccount"],
|
|
50
|
+
nestedObjectKeys: ["nickserv"],
|
|
49
51
|
hasImplicitDefaultAccount: (cfg) => Boolean((cfg.channels?.irc?.host?.trim() || process.env.IRC_HOST?.trim()) && (cfg.channels?.irc?.nick?.trim() || process.env.IRC_NICK?.trim()))
|
|
50
52
|
});
|
|
51
|
-
function mergeIrcAccountConfig(cfg, accountId) {
|
|
52
|
-
return resolveMergedAccountConfig({
|
|
53
|
-
channelConfig: cfg.channels?.irc,
|
|
54
|
-
accounts: cfg.channels?.irc?.accounts,
|
|
55
|
-
accountId,
|
|
56
|
-
omitKeys: ["defaultAccount"],
|
|
57
|
-
normalizeAccountId,
|
|
58
|
-
nestedObjectKeys: ["nickserv"]
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
53
|
function resolvePassword(accountId, merged) {
|
|
62
54
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
63
55
|
const envPassword = process.env.IRC_PASSWORD?.trim();
|
|
@@ -131,7 +123,6 @@ function resolveNickServConfig(accountId, nickserv) {
|
|
|
131
123
|
};
|
|
132
124
|
}
|
|
133
125
|
function resolveIrcAccount(params) {
|
|
134
|
-
const hasExplicitAccountId = Boolean(params.accountId?.trim());
|
|
135
126
|
const baseEnabled = params.cfg.channels?.irc?.enabled !== false;
|
|
136
127
|
const resolve = (accountId) => {
|
|
137
128
|
const merged = mergeIrcAccountConfig(params.cfg, accountId);
|
|
@@ -177,14 +168,13 @@ function resolveIrcAccount(params) {
|
|
|
177
168
|
config
|
|
178
169
|
};
|
|
179
170
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return fallback;
|
|
171
|
+
return resolveAccountWithDefaultFallback({
|
|
172
|
+
accountId: params.accountId,
|
|
173
|
+
normalizeAccountId,
|
|
174
|
+
resolvePrimary: resolve,
|
|
175
|
+
hasCredential: (account) => account.configured,
|
|
176
|
+
resolveDefaultAccountId: () => resolveDefaultIrcAccountId(params.cfg)
|
|
177
|
+
});
|
|
188
178
|
}
|
|
189
179
|
function listEnabledIrcAccounts(cfg) {
|
|
190
180
|
return listIrcAccountIds(cfg).map((accountId) => resolveIrcAccount({
|
|
@@ -202,7 +192,7 @@ const collectIrcMutableAllowlistWarnings = createDangerousNameMatchingMutableAll
|
|
|
202
192
|
});
|
|
203
193
|
//#endregion
|
|
204
194
|
//#region extensions/irc/src/gateway.ts
|
|
205
|
-
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
195
|
+
const loadIrcChannelRuntime$1 = createLazyRuntimeModule(() => import("./channel-runtime-CRzAwKGK.js"));
|
|
206
196
|
async function startIrcGatewayAccount(ctx) {
|
|
207
197
|
const account = ctx.account;
|
|
208
198
|
const statusSink = createAccountStatusSink({
|
|
@@ -212,7 +202,7 @@ async function startIrcGatewayAccount(ctx) {
|
|
|
212
202
|
if (!account.configured) throw new Error(`IRC is not configured for account "${account.accountId}" (need host and nick in channels.irc).`);
|
|
213
203
|
ctx.log?.info?.(`[${account.accountId}] starting IRC provider (${account.host}:${account.port}${account.tls ? " tls" : ""})`);
|
|
214
204
|
const { monitorIrcProvider } = await loadIrcChannelRuntime$1();
|
|
215
|
-
await
|
|
205
|
+
await runPassiveAccountLifecycle({
|
|
216
206
|
abortSignal: ctx.abortSignal,
|
|
217
207
|
start: async () => await monitorIrcProvider({
|
|
218
208
|
accountId: account.accountId,
|
|
@@ -220,7 +210,10 @@ async function startIrcGatewayAccount(ctx) {
|
|
|
220
210
|
runtime: ctx.runtime,
|
|
221
211
|
abortSignal: ctx.abortSignal,
|
|
222
212
|
statusSink
|
|
223
|
-
})
|
|
213
|
+
}),
|
|
214
|
+
stop: async (monitor) => {
|
|
215
|
+
await monitor.stop();
|
|
216
|
+
}
|
|
224
217
|
});
|
|
225
218
|
}
|
|
226
219
|
//#endregion
|
|
@@ -554,7 +547,7 @@ async function connectIrcClient(options) {
|
|
|
554
547
|
if (line.command === "PRIVMSG") {
|
|
555
548
|
const targetParam = line.params[0];
|
|
556
549
|
const target = targetParam ? targetParam.trim() : "";
|
|
557
|
-
const text = line.trailing
|
|
550
|
+
const text = line.trailing ?? line.params[1] ?? "";
|
|
558
551
|
const prefix = parseIrcPrefix(line.prefix);
|
|
559
552
|
const senderNick = prefix.nick ? prefix.nick.trim() : "";
|
|
560
553
|
if (!target || !senderNick || !text.trim()) continue;
|
|
@@ -562,6 +555,7 @@ async function connectIrcClient(options) {
|
|
|
562
555
|
senderNick,
|
|
563
556
|
senderUser: prefix.user ? prefix.user.trim() : void 0,
|
|
564
557
|
senderHost: prefix.host ? prefix.host.trim() : void 0,
|
|
558
|
+
connectedNick: currentNick,
|
|
565
559
|
target,
|
|
566
560
|
text,
|
|
567
561
|
rawLine
|
|
@@ -939,6 +933,7 @@ function setIrcGroupAccess(cfg, accountId, policy, entries, normalizeGroupEntry)
|
|
|
939
933
|
});
|
|
940
934
|
}
|
|
941
935
|
const ircSetupAdapter = {
|
|
936
|
+
singleAccountKeysToMove: ["password"],
|
|
942
937
|
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
943
938
|
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
944
939
|
cfg,
|
|
@@ -975,6 +970,75 @@ const ircSetupAdapter = {
|
|
|
975
970
|
});
|
|
976
971
|
}
|
|
977
972
|
};
|
|
973
|
+
const ircSetupContract = defineChannelSetupContract({
|
|
974
|
+
fields: {
|
|
975
|
+
host: {
|
|
976
|
+
kind: "string",
|
|
977
|
+
cli: {
|
|
978
|
+
flags: "--host <host>",
|
|
979
|
+
description: "IRC server host"
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
port: {
|
|
983
|
+
kind: "string",
|
|
984
|
+
cli: {
|
|
985
|
+
flags: "--port <port>",
|
|
986
|
+
description: "IRC server port"
|
|
987
|
+
}
|
|
988
|
+
},
|
|
989
|
+
tls: {
|
|
990
|
+
kind: "boolean",
|
|
991
|
+
cli: {
|
|
992
|
+
flags: "--tls",
|
|
993
|
+
description: "Use TLS for IRC"
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
nick: {
|
|
997
|
+
kind: "string",
|
|
998
|
+
cli: {
|
|
999
|
+
flags: "--nick <nick>",
|
|
1000
|
+
description: "IRC nickname"
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
username: {
|
|
1004
|
+
kind: "string",
|
|
1005
|
+
cli: {
|
|
1006
|
+
flags: "--username <name>",
|
|
1007
|
+
description: "IRC username"
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
realname: {
|
|
1011
|
+
kind: "string",
|
|
1012
|
+
cli: {
|
|
1013
|
+
flags: "--realname <name>",
|
|
1014
|
+
description: "IRC real name"
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
channels: {
|
|
1018
|
+
kind: "string-list",
|
|
1019
|
+
cli: {
|
|
1020
|
+
flags: "--channels <names>",
|
|
1021
|
+
description: "IRC channels"
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
password: {
|
|
1025
|
+
kind: "string",
|
|
1026
|
+
sensitive: true,
|
|
1027
|
+
cli: {
|
|
1028
|
+
flags: "--password <password>",
|
|
1029
|
+
description: "IRC server password"
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
useEnv: {
|
|
1033
|
+
kind: "boolean",
|
|
1034
|
+
cli: {
|
|
1035
|
+
flags: "--use-env",
|
|
1036
|
+
description: "Use IRC environment configuration"
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
legacyAdapter: ircSetupAdapter
|
|
1041
|
+
});
|
|
978
1042
|
//#endregion
|
|
979
1043
|
//#region extensions/irc/src/setup-surface.ts
|
|
980
1044
|
const t = createSetupTranslator();
|
|
@@ -1340,7 +1404,7 @@ const meta = {
|
|
|
1340
1404
|
systemImage: "number",
|
|
1341
1405
|
markdownCapable: true
|
|
1342
1406
|
};
|
|
1343
|
-
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-
|
|
1407
|
+
const loadIrcChannelRuntime = createLazyRuntimeModule(() => import("./channel-runtime-CRzAwKGK.js"));
|
|
1344
1408
|
function normalizePairingTarget(raw) {
|
|
1345
1409
|
const normalized = normalizeIrcAllowEntry(raw);
|
|
1346
1410
|
if (!normalized) return "";
|
|
@@ -1413,6 +1477,7 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1413
1477
|
quickstartAllowFrom: true
|
|
1414
1478
|
},
|
|
1415
1479
|
setup: ircSetupAdapter,
|
|
1480
|
+
setupContract: ircSetupContract,
|
|
1416
1481
|
setupWizard: ircSetupWizard,
|
|
1417
1482
|
capabilities: {
|
|
1418
1483
|
chatTypes: ["direct", "group"],
|
|
@@ -1570,24 +1635,13 @@ const ircPlugin = createChatChannelPlugin({
|
|
|
1570
1635
|
base: ircOutboundBaseAdapter,
|
|
1571
1636
|
attachedResults: {
|
|
1572
1637
|
channel: "irc",
|
|
1573
|
-
sendText:
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
replyTo: replyToId ?? void 0
|
|
1579
|
-
});
|
|
1580
|
-
},
|
|
1581
|
-
sendMedia: async ({ cfg, to, text, mediaUrl, accountId, replyToId }) => {
|
|
1582
|
-
const { sendMessageIrc } = await loadIrcChannelRuntime();
|
|
1583
|
-
return await sendMessageIrc(to, mediaUrl ? `${text}\n\nAttachment: ${mediaUrl}` : text, {
|
|
1584
|
-
cfg,
|
|
1585
|
-
accountId: accountId ?? void 0,
|
|
1586
|
-
replyTo: replyToId ?? void 0
|
|
1587
|
-
});
|
|
1588
|
-
}
|
|
1638
|
+
sendText: ({ onDeliveryResult: _onDeliveryResult, ...ctx }) => ircMessageAdapter.send.text(ctx),
|
|
1639
|
+
sendMedia: ({ onDeliveryResult: _onDeliveryResult, mediaUrl, ...ctx }) => ircMessageAdapter.send.media({
|
|
1640
|
+
...ctx,
|
|
1641
|
+
mediaUrl: mediaUrl ?? ""
|
|
1642
|
+
})
|
|
1589
1643
|
}
|
|
1590
1644
|
}
|
|
1591
1645
|
});
|
|
1592
1646
|
//#endregion
|
|
1593
|
-
export { resolveIrcGroupRequireMention as a, isChannelTarget as c, connectIrcClient as d,
|
|
1647
|
+
export { resolveIrcAccount as _, resolveIrcGroupRequireMention as a, isChannelTarget as c, connectIrcClient as d, parseIrcLine as f, resolveDefaultIrcAccountId as g, listIrcAccountIds as h, resolveIrcGroupMatch as i, normalizeIrcAllowEntry as l, listEnabledIrcAccounts as m, ircSetupWizard as n, sendMessageIrc as o, parseIrcPrefix as p, ircSetupAdapter as r, buildIrcAllowlistCandidates as s, ircPlugin as t, buildIrcConnectOptions as u };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ircPlugin } from "./channel-
|
|
1
|
+
import { t as ircPlugin } from "./channel-BZclM5wY.js";
|
|
2
2
|
export { ircPlugin };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { a as resolveIrcGroupRequireMention, c as isChannelTarget, d as connectIrcClient, f as
|
|
1
|
+
import { _ as resolveIrcAccount, a as resolveIrcGroupRequireMention, c as isChannelTarget, d as connectIrcClient, f as parseIrcLine, i as resolveIrcGroupMatch, l as normalizeIrcAllowEntry, o as sendMessageIrc, p as parseIrcPrefix, s as buildIrcAllowlistCandidates, u as buildIrcConnectOptions } from "./channel-BZclM5wY.js";
|
|
2
2
|
import { t as getIrcRuntime } from "./runtime-xy-FcjJC.js";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
-
import { resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
4
|
+
import { bindIngressLifecycleToReplyOptions, createChannelIngressMonitor, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
5
6
|
import { resolveLoggerBackedRuntime } from "openclaw/plugin-sdk/extension-shared";
|
|
6
7
|
import { buildChannelInboundEventContext, logInboundDrop, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
7
8
|
import { channelIngressRoutes, createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
@@ -120,7 +121,7 @@ async function deliverIrcReply(params) {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
async function handleIrcInbound(params) {
|
|
123
|
-
const { message, account, config, runtime, connectedNick, statusSink } = params;
|
|
124
|
+
const { message, account, config, runtime, connectedNick, statusSink, turnAdoptionLifecycle } = params;
|
|
124
125
|
const core = getIrcRuntime();
|
|
125
126
|
const pairing = createChannelPairingController({
|
|
126
127
|
core,
|
|
@@ -128,7 +129,11 @@ async function handleIrcInbound(params) {
|
|
|
128
129
|
accountId: account.accountId
|
|
129
130
|
});
|
|
130
131
|
const rawBody = message.text?.trim() ?? "";
|
|
131
|
-
if (!rawBody) return;
|
|
132
|
+
if (!rawBody) return { kind: "completed" };
|
|
133
|
+
if (turnAdoptionLifecycle?.abortSignal.aborted) return {
|
|
134
|
+
kind: "failed-retryable",
|
|
135
|
+
error: turnAdoptionLifecycle.abortSignal.reason
|
|
136
|
+
};
|
|
132
137
|
statusSink?.({ lastInboundAt: message.timestamp });
|
|
133
138
|
const senderDisplay = message.senderHost ? `${message.senderNick}!${message.senderUser ?? "?"}@${message.senderHost}` : message.senderNick;
|
|
134
139
|
const allowNameMatching = isDangerousNameMatchingEnabled(account.config);
|
|
@@ -228,11 +233,11 @@ async function handleIrcInbound(params) {
|
|
|
228
233
|
}
|
|
229
234
|
});
|
|
230
235
|
runtime.log?.(`irc: drop DM sender ${senderDisplay} (dmPolicy=${dmPolicy})`);
|
|
231
|
-
return;
|
|
236
|
+
return { kind: "completed" };
|
|
232
237
|
}
|
|
233
238
|
if (access.ingress.admission === "skip") {
|
|
234
239
|
runtime.log?.(`irc: drop channel ${message.target} (missing-mention)`);
|
|
235
|
-
return;
|
|
240
|
+
return { kind: "completed" };
|
|
236
241
|
}
|
|
237
242
|
if (access.ingress.admission !== "dispatch") {
|
|
238
243
|
if (message.isGroup && access.ingress.decisiveGateId === "command" && access.commandAccess.shouldBlockControlCommand) {
|
|
@@ -242,14 +247,18 @@ async function handleIrcInbound(params) {
|
|
|
242
247
|
reason: "control command (unauthorized)",
|
|
243
248
|
target: senderDisplay
|
|
244
249
|
});
|
|
245
|
-
return;
|
|
250
|
+
return { kind: "completed" };
|
|
246
251
|
}
|
|
247
252
|
if (message.isGroup) if (access.routeAccess.reason === "channel_not_allowlisted") runtime.log?.(`irc: drop channel ${message.target} (not allowlisted)`);
|
|
248
253
|
else if (access.routeAccess.reason === "channel_disabled") runtime.log?.(`irc: drop channel ${message.target} (disabled)`);
|
|
249
254
|
else runtime.log?.(`irc: drop group sender ${senderDisplay} (policy=${groupPolicy})`);
|
|
250
255
|
else runtime.log?.(`irc: drop DM sender ${senderDisplay} (dmPolicy=${dmPolicy})`);
|
|
251
|
-
return;
|
|
256
|
+
return { kind: "completed" };
|
|
252
257
|
}
|
|
258
|
+
if (turnAdoptionLifecycle?.abortSignal.aborted) return {
|
|
259
|
+
kind: "failed-retryable",
|
|
260
|
+
error: turnAdoptionLifecycle.abortSignal.reason
|
|
261
|
+
};
|
|
253
262
|
const channelTarget = message.target.startsWith("#") || message.target.startsWith("&") ? message.target : `#${message.target}`;
|
|
254
263
|
const peerId = message.isGroup ? channelTarget : message.senderNick;
|
|
255
264
|
const { route, buildEnvelope } = resolveChannelInboundRouteEnvelope({
|
|
@@ -313,6 +322,22 @@ async function handleIrcInbound(params) {
|
|
|
313
322
|
GroupSystemPrompt: message.isGroup ? groupSystemPrompt : void 0
|
|
314
323
|
}
|
|
315
324
|
});
|
|
325
|
+
const ingressState = { handoff: "none" };
|
|
326
|
+
const trackedIngressLifecycle = turnAdoptionLifecycle ? {
|
|
327
|
+
...turnAdoptionLifecycle,
|
|
328
|
+
onAdopted: async () => {
|
|
329
|
+
ingressState.handoff = "adopted";
|
|
330
|
+
await turnAdoptionLifecycle.onAdopted();
|
|
331
|
+
},
|
|
332
|
+
onDeferred: () => {
|
|
333
|
+
ingressState.handoff = "deferred";
|
|
334
|
+
turnAdoptionLifecycle.onDeferred();
|
|
335
|
+
},
|
|
336
|
+
onAbandoned: async () => {
|
|
337
|
+
ingressState.handoff = "abandoned";
|
|
338
|
+
await turnAdoptionLifecycle.onAbandoned();
|
|
339
|
+
}
|
|
340
|
+
} : void 0;
|
|
316
341
|
await core.channel.inbound.dispatch({
|
|
317
342
|
cfg: config,
|
|
318
343
|
channel: CHANNEL_ID,
|
|
@@ -339,6 +364,7 @@ async function handleIrcInbound(params) {
|
|
|
339
364
|
},
|
|
340
365
|
replyPipeline: {},
|
|
341
366
|
replyOptions: {
|
|
367
|
+
...trackedIngressLifecycle ? bindIngressLifecycleToReplyOptions(trackedIngressLifecycle) : {},
|
|
342
368
|
skillFilter: groupMatch.groupConfig?.skills,
|
|
343
369
|
disableBlockStreaming: typeof blockStreamingEnabled === "boolean" ? !blockStreamingEnabled : void 0
|
|
344
370
|
},
|
|
@@ -346,23 +372,162 @@ async function handleIrcInbound(params) {
|
|
|
346
372
|
runtime.error?.(`irc: failed updating session meta: ${String(err)}`);
|
|
347
373
|
} }
|
|
348
374
|
});
|
|
375
|
+
if (turnAdoptionLifecycle?.abortSignal.aborted && ingressState.handoff === "none") return {
|
|
376
|
+
kind: "failed-retryable",
|
|
377
|
+
error: turnAdoptionLifecycle.abortSignal.reason
|
|
378
|
+
};
|
|
379
|
+
if (turnAdoptionLifecycle && ingressState.handoff === "none") {
|
|
380
|
+
await turnAdoptionLifecycle.onAdopted();
|
|
381
|
+
ingressState.handoff = "adopted";
|
|
382
|
+
}
|
|
383
|
+
return ingressState.handoff === "deferred" || ingressState.handoff === "abandoned" ? { kind: "deferred" } : { kind: "completed" };
|
|
349
384
|
}
|
|
350
385
|
//#endregion
|
|
351
|
-
//#region extensions/irc/src/
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
386
|
+
//#region extensions/irc/src/irc-ingress.ts
|
|
387
|
+
const IRC_INGRESS_PAYLOAD_VERSION = 1;
|
|
388
|
+
const IRC_INGRESS_POLL_INTERVAL_MS = 1e3;
|
|
389
|
+
const IRC_INGRESS_PRUNE_INTERVAL_MS = 3600 * 1e3;
|
|
390
|
+
const IRC_INGRESS_TOMBSTONE_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
391
|
+
const IRC_INGRESS_TOMBSTONE_MAX_ENTRIES = 1e3;
|
|
392
|
+
var IrcIngressPayloadError = class extends Error {
|
|
393
|
+
constructor(message) {
|
|
394
|
+
super(message);
|
|
395
|
+
this.name = "IrcIngressPayloadError";
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
function inspectRawPrivmsg(rawLine) {
|
|
399
|
+
const line = parseIrcLine(rawLine);
|
|
400
|
+
if (!line || line.command !== "PRIVMSG") throw new IrcIngressPayloadError("IRC ingress row is not a PRIVMSG line.");
|
|
401
|
+
const rawTarget = line.params[0]?.trim() ?? "";
|
|
402
|
+
const text = line.trailing ?? line.params[1] ?? "";
|
|
403
|
+
const prefix = parseIrcPrefix(line.prefix);
|
|
404
|
+
const senderNick = prefix.nick?.trim() ?? "";
|
|
405
|
+
if (!rawTarget || !senderNick || !text.trim()) throw new IrcIngressPayloadError("IRC PRIVMSG line is missing target, sender, or text.");
|
|
406
|
+
const isGroup = isChannelTarget(rawTarget);
|
|
407
|
+
const target = isGroup ? rawTarget : senderNick;
|
|
408
|
+
const lanePeer = normalizeLowercaseStringOrEmpty(target);
|
|
409
|
+
return {
|
|
410
|
+
laneKey: `${isGroup ? "channel" : "direct"}:${lanePeer}`,
|
|
411
|
+
message: {
|
|
412
|
+
target,
|
|
413
|
+
rawTarget,
|
|
414
|
+
senderNick,
|
|
415
|
+
senderUser: prefix.user?.trim() || void 0,
|
|
416
|
+
senderHost: prefix.host?.trim() || void 0,
|
|
417
|
+
text,
|
|
418
|
+
isGroup
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function decodeIrcIngressPayload(payload, claimedId) {
|
|
423
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload) || typeof payload.eventId !== "string" || !Number.isSafeInteger(payload.receivedAt) || (payload.receivedAt ?? 0) <= 0 || typeof payload.connectionEpoch !== "string" || !payload.connectionEpoch?.trim() || typeof payload.connectedNick !== "string" || !payload.connectedNick?.trim() || typeof payload.rawLine !== "string") throw new IrcIngressPayloadError(`IRC ingress row ${claimedId} has invalid metadata.`);
|
|
424
|
+
const validPayload = payload;
|
|
425
|
+
return {
|
|
426
|
+
version: validPayload.version,
|
|
427
|
+
body: {
|
|
428
|
+
eventId: validPayload.eventId,
|
|
429
|
+
receivedAt: validPayload.receivedAt,
|
|
430
|
+
connectionEpoch: validPayload.connectionEpoch,
|
|
431
|
+
connectedNick: validPayload.connectedNick,
|
|
432
|
+
rawLine: validPayload.rawLine
|
|
433
|
+
}
|
|
359
434
|
};
|
|
435
|
+
}
|
|
436
|
+
function inspectIrcIngress(raw, phase) {
|
|
437
|
+
try {
|
|
438
|
+
return {
|
|
439
|
+
eventId: raw.eventId,
|
|
440
|
+
laneKey: inspectRawPrivmsg(raw.rawLine).laneKey
|
|
441
|
+
};
|
|
442
|
+
} catch (error) {
|
|
443
|
+
if (phase === "admission" && error instanceof IrcIngressPayloadError) return {
|
|
444
|
+
eventId: raw.eventId,
|
|
445
|
+
laneKey: `invalid:${raw.eventId}`
|
|
446
|
+
};
|
|
447
|
+
throw error;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function resolveIrcIngressNonRetryableFailure(error) {
|
|
451
|
+
return error instanceof IrcIngressPayloadError ? {
|
|
452
|
+
reason: "invalid-event",
|
|
453
|
+
message: error.message
|
|
454
|
+
} : null;
|
|
455
|
+
}
|
|
456
|
+
function createIrcIngressMonitor(options) {
|
|
457
|
+
const monitor = createChannelIngressMonitor({
|
|
458
|
+
queue: options.queue ?? (() => getIrcRuntime().state.openChannelIngressQueue({ accountId: options.accountId })),
|
|
459
|
+
inspect: (raw, context) => inspectIrcIngress(raw, context.phase),
|
|
460
|
+
payload: {
|
|
461
|
+
version: IRC_INGRESS_PAYLOAD_VERSION,
|
|
462
|
+
serialize: (raw) => raw,
|
|
463
|
+
deserialize: (body) => body,
|
|
464
|
+
encode: ({ body }) => ({
|
|
465
|
+
version: IRC_INGRESS_PAYLOAD_VERSION,
|
|
466
|
+
...body
|
|
467
|
+
}),
|
|
468
|
+
decode: (payload, { claim }) => decodeIrcIngressPayload(payload, claim.id),
|
|
469
|
+
createClaimError: (_kind, claim) => new IrcIngressPayloadError(`IRC ingress row ${claim.id} has invalid metadata.`)
|
|
470
|
+
},
|
|
471
|
+
deliver: (raw, lifecycle, claim) => {
|
|
472
|
+
const message = {
|
|
473
|
+
...inspectRawPrivmsg(raw.rawLine).message,
|
|
474
|
+
messageId: claim.id,
|
|
475
|
+
timestamp: raw.receivedAt
|
|
476
|
+
};
|
|
477
|
+
return options.dispatch(message, lifecycle, {
|
|
478
|
+
connectedNick: raw.connectedNick.trim(),
|
|
479
|
+
connectionEpoch: raw.connectionEpoch.trim()
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
pollIntervalMs: options.pollIntervalMs ?? IRC_INGRESS_POLL_INTERVAL_MS,
|
|
483
|
+
retention: {
|
|
484
|
+
pruneIntervalMs: IRC_INGRESS_PRUNE_INTERVAL_MS,
|
|
485
|
+
completedTtlMs: IRC_INGRESS_TOMBSTONE_TTL_MS,
|
|
486
|
+
completedMaxEntries: IRC_INGRESS_TOMBSTONE_MAX_ENTRIES,
|
|
487
|
+
failedTtlMs: IRC_INGRESS_TOMBSTONE_TTL_MS,
|
|
488
|
+
failedMaxEntries: IRC_INGRESS_TOMBSTONE_MAX_ENTRIES
|
|
489
|
+
},
|
|
490
|
+
drain: {
|
|
491
|
+
resolveNonRetryableFailure: resolveIrcIngressNonRetryableFailure,
|
|
492
|
+
...options.adoptionStallTimeoutMs === void 0 ? {} : { adoptionStallTimeoutMs: options.adoptionStallTimeoutMs },
|
|
493
|
+
onLog: (message) => options.runtime.log?.(`irc ${message}`)
|
|
494
|
+
},
|
|
495
|
+
createStoppedError: () => /* @__PURE__ */ new Error("IRC ingress is stopped."),
|
|
496
|
+
onError: (error) => options.runtime.error?.(`irc ingress drain failed: ${String(error)}`)
|
|
497
|
+
});
|
|
360
498
|
return {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
499
|
+
openConnection: (connectionEpoch = randomUUID()) => {
|
|
500
|
+
const epoch = connectionEpoch.trim();
|
|
501
|
+
if (!epoch) throw new Error("IRC ingress connection epoch is required.");
|
|
502
|
+
let sequence = 0;
|
|
503
|
+
return {
|
|
504
|
+
connectionEpoch: epoch,
|
|
505
|
+
accept: (rawLine, connectedNick) => {
|
|
506
|
+
if (monitor.isStopped()) return Promise.reject(/* @__PURE__ */ new Error("IRC ingress is stopped."));
|
|
507
|
+
sequence += 1;
|
|
508
|
+
const eventId = `local:${epoch}:${String(sequence).padStart(12, "0")}`;
|
|
509
|
+
const receivedAt = Date.now();
|
|
510
|
+
const normalizedNick = connectedNick.trim();
|
|
511
|
+
if (!normalizedNick) return Promise.reject(/* @__PURE__ */ new Error("IRC ingress connected nickname is required."));
|
|
512
|
+
return monitor.admit({
|
|
513
|
+
eventId,
|
|
514
|
+
rawLine,
|
|
515
|
+
receivedAt,
|
|
516
|
+
connectionEpoch: epoch,
|
|
517
|
+
connectedNick: normalizedNick
|
|
518
|
+
}, { receivedAt }).then(() => void 0);
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
},
|
|
522
|
+
start: monitor.start,
|
|
523
|
+
pause: monitor.pause,
|
|
524
|
+
stop: monitor.stop,
|
|
525
|
+
waitForIdle: monitor.waitForIdle
|
|
364
526
|
};
|
|
365
527
|
}
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region extensions/irc/src/monitor.ts
|
|
530
|
+
const IRC_MONITOR_RECONNECT_DELAY_MS = 1e3;
|
|
366
531
|
async function monitorIrcProvider(opts) {
|
|
367
532
|
const core = getIrcRuntime();
|
|
368
533
|
const cfg = opts.config ?? core.config.current();
|
|
@@ -377,6 +542,8 @@ async function monitorIrcProvider(opts) {
|
|
|
377
542
|
accountId: account.accountId
|
|
378
543
|
});
|
|
379
544
|
let client = null;
|
|
545
|
+
let activeConnectionEpoch = null;
|
|
546
|
+
let ingressPause = Promise.resolve();
|
|
380
547
|
let reconnectTimer = null;
|
|
381
548
|
let stopped = false;
|
|
382
549
|
const monitorAbort = new AbortController();
|
|
@@ -389,6 +556,48 @@ async function monitorIrcProvider(opts) {
|
|
|
389
556
|
removeAbortListener = () => opts.abortSignal?.removeEventListener("abort", forwardAbort);
|
|
390
557
|
}
|
|
391
558
|
}
|
|
559
|
+
const ingress = createIrcIngressMonitor({
|
|
560
|
+
accountId: account.accountId,
|
|
561
|
+
runtime,
|
|
562
|
+
...opts.ingressQueue ? { queue: opts.ingressQueue } : {},
|
|
563
|
+
dispatch: async (message, turnAdoptionLifecycle, context) => {
|
|
564
|
+
const activeClient = client;
|
|
565
|
+
if (!activeClient || stopped || monitorAbort.signal.aborted) return {
|
|
566
|
+
kind: "failed-retryable",
|
|
567
|
+
error: /* @__PURE__ */ new Error("IRC transport disconnected before ingress dispatch.")
|
|
568
|
+
};
|
|
569
|
+
if (normalizeLowercaseStringOrEmpty(message.senderNick) === normalizeLowercaseStringOrEmpty(context.connectedNick)) return { kind: "completed" };
|
|
570
|
+
if (!message.isGroup && context.connectionEpoch !== activeConnectionEpoch) {
|
|
571
|
+
logger.warn?.(`[${account.accountId}] dropping replayed IRC DM after the connection changed`);
|
|
572
|
+
return { kind: "completed" };
|
|
573
|
+
}
|
|
574
|
+
if (opts.onMessage) {
|
|
575
|
+
await opts.onMessage(message, activeClient);
|
|
576
|
+
return { kind: "completed" };
|
|
577
|
+
}
|
|
578
|
+
return await handleIrcInbound({
|
|
579
|
+
message,
|
|
580
|
+
account,
|
|
581
|
+
config: cfg,
|
|
582
|
+
runtime,
|
|
583
|
+
connectedNick: context.connectedNick,
|
|
584
|
+
turnAdoptionLifecycle,
|
|
585
|
+
sendReply: async (target, text) => {
|
|
586
|
+
const replyClient = client;
|
|
587
|
+
if (!replyClient || !replyClient.isReady() || stopped || monitorAbort.signal.aborted) throw new Error("IRC transport disconnected before reply send.");
|
|
588
|
+
if (!message.isGroup && context.connectionEpoch !== activeConnectionEpoch) throw new Error("IRC connection changed before private reply send.");
|
|
589
|
+
replyClient.sendPrivmsg(target, text);
|
|
590
|
+
opts.statusSink?.({ lastOutboundAt: Date.now() });
|
|
591
|
+
core.channel.activity.record({
|
|
592
|
+
channel: "irc",
|
|
593
|
+
accountId: account.accountId,
|
|
594
|
+
direction: "outbound"
|
|
595
|
+
});
|
|
596
|
+
},
|
|
597
|
+
statusSink: opts.statusSink
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
});
|
|
392
601
|
function scheduleReconnect() {
|
|
393
602
|
if (stopped || monitorAbort.signal.aborted || reconnectTimer) return;
|
|
394
603
|
reconnectTimer = setTimeout(() => {
|
|
@@ -403,6 +612,7 @@ async function monitorIrcProvider(opts) {
|
|
|
403
612
|
}
|
|
404
613
|
async function connect() {
|
|
405
614
|
if (stopped || monitorAbort.signal.aborted) return;
|
|
615
|
+
const ingressConnection = ingress.openConnection();
|
|
406
616
|
const nextClient = await connectIrcClient(buildIrcConnectOptions(account, {
|
|
407
617
|
channels: account.config.channels,
|
|
408
618
|
abortSignal: monitorAbort.signal,
|
|
@@ -417,54 +627,20 @@ async function monitorIrcProvider(opts) {
|
|
|
417
627
|
},
|
|
418
628
|
onDisconnect: () => {
|
|
419
629
|
if (stopped || monitorAbort.signal.aborted) return;
|
|
630
|
+
ingressPause = ingress.pause();
|
|
631
|
+
if (activeConnectionEpoch === ingressConnection.connectionEpoch) activeConnectionEpoch = null;
|
|
420
632
|
client = null;
|
|
421
633
|
logger.warn?.(`[${account.accountId}] IRC connection closed; reconnecting in ${IRC_MONITOR_RECONNECT_DELAY_MS}ms`);
|
|
422
634
|
scheduleReconnect();
|
|
423
635
|
},
|
|
424
636
|
onPrivmsg: async (event) => {
|
|
425
|
-
|
|
426
|
-
if (normalizeLowercaseStringOrEmpty(event.senderNick) === normalizeLowercaseStringOrEmpty(
|
|
427
|
-
const inboundTarget = resolveIrcInboundTarget({
|
|
428
|
-
target: event.target,
|
|
429
|
-
senderNick: event.senderNick
|
|
430
|
-
});
|
|
431
|
-
const message = {
|
|
432
|
-
messageId: makeIrcMessageId(),
|
|
433
|
-
target: inboundTarget.target,
|
|
434
|
-
rawTarget: inboundTarget.rawTarget,
|
|
435
|
-
senderNick: event.senderNick,
|
|
436
|
-
senderUser: event.senderUser,
|
|
437
|
-
senderHost: event.senderHost,
|
|
438
|
-
text: event.text,
|
|
439
|
-
timestamp: Date.now(),
|
|
440
|
-
isGroup: inboundTarget.isGroup
|
|
441
|
-
};
|
|
637
|
+
await ingressConnection.accept(event.rawLine, event.connectedNick);
|
|
638
|
+
if (normalizeLowercaseStringOrEmpty(event.senderNick) === normalizeLowercaseStringOrEmpty(event.connectedNick)) return;
|
|
442
639
|
core.channel.activity.record({
|
|
443
640
|
channel: "irc",
|
|
444
641
|
accountId: account.accountId,
|
|
445
642
|
direction: "inbound",
|
|
446
|
-
at:
|
|
447
|
-
});
|
|
448
|
-
if (opts.onMessage) {
|
|
449
|
-
await opts.onMessage(message, client);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
await handleIrcInbound({
|
|
453
|
-
message,
|
|
454
|
-
account,
|
|
455
|
-
config: cfg,
|
|
456
|
-
runtime,
|
|
457
|
-
connectedNick: client.nick,
|
|
458
|
-
sendReply: async (target, text) => {
|
|
459
|
-
client?.sendPrivmsg(target, text);
|
|
460
|
-
opts.statusSink?.({ lastOutboundAt: Date.now() });
|
|
461
|
-
core.channel.activity.record({
|
|
462
|
-
channel: "irc",
|
|
463
|
-
accountId: account.accountId,
|
|
464
|
-
direction: "outbound"
|
|
465
|
-
});
|
|
466
|
-
},
|
|
467
|
-
statusSink: opts.statusSink
|
|
643
|
+
at: Date.now()
|
|
468
644
|
});
|
|
469
645
|
}
|
|
470
646
|
}));
|
|
@@ -473,20 +649,40 @@ async function monitorIrcProvider(opts) {
|
|
|
473
649
|
return;
|
|
474
650
|
}
|
|
475
651
|
client = nextClient;
|
|
652
|
+
activeConnectionEpoch = ingressConnection.connectionEpoch;
|
|
653
|
+
await ingressPause;
|
|
654
|
+
if (client !== nextClient || !nextClient.isReady()) {
|
|
655
|
+
if (activeConnectionEpoch === ingressConnection.connectionEpoch) activeConnectionEpoch = null;
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
ingress.start();
|
|
476
659
|
logger.info(`[${account.accountId}] connected to ${account.host}:${account.port}${account.tls ? " (tls)" : ""} as ${nextClient.nick}`);
|
|
477
660
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
661
|
+
try {
|
|
662
|
+
await connect();
|
|
663
|
+
} catch (error) {
|
|
481
664
|
removeAbortListener?.();
|
|
482
665
|
removeAbortListener = null;
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
666
|
+
await ingress.stop();
|
|
667
|
+
throw error;
|
|
668
|
+
}
|
|
669
|
+
let stopTask;
|
|
670
|
+
return { stop: () => {
|
|
671
|
+
stopTask ??= (async () => {
|
|
672
|
+
stopped = true;
|
|
673
|
+
removeAbortListener?.();
|
|
674
|
+
removeAbortListener = null;
|
|
675
|
+
if (!monitorAbort.signal.aborted) monitorAbort.abort();
|
|
676
|
+
if (reconnectTimer) {
|
|
677
|
+
clearTimeout(reconnectTimer);
|
|
678
|
+
reconnectTimer = null;
|
|
679
|
+
}
|
|
680
|
+
client?.quit("shutdown");
|
|
681
|
+
client = null;
|
|
682
|
+
activeConnectionEpoch = null;
|
|
683
|
+
await ingress.stop();
|
|
684
|
+
})();
|
|
685
|
+
return stopTask;
|
|
490
686
|
} };
|
|
491
687
|
}
|
|
492
688
|
//#endregion
|
package/openclaw.plugin.json
CHANGED
|
@@ -6,20 +6,6 @@
|
|
|
6
6
|
"channels": [
|
|
7
7
|
"irc"
|
|
8
8
|
],
|
|
9
|
-
"channelEnvVars": {
|
|
10
|
-
"irc": [
|
|
11
|
-
"IRC_HOST",
|
|
12
|
-
"IRC_PORT",
|
|
13
|
-
"IRC_TLS",
|
|
14
|
-
"IRC_NICK",
|
|
15
|
-
"IRC_USERNAME",
|
|
16
|
-
"IRC_REALNAME",
|
|
17
|
-
"IRC_PASSWORD",
|
|
18
|
-
"IRC_CHANNELS",
|
|
19
|
-
"IRC_NICKSERV_PASSWORD",
|
|
20
|
-
"IRC_NICKSERV_REGISTER_EMAIL"
|
|
21
|
-
]
|
|
22
|
-
},
|
|
23
9
|
"configSchema": {
|
|
24
10
|
"type": "object",
|
|
25
11
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/irc",
|
|
3
|
-
"version": "2026.7.2-beta.
|
|
3
|
+
"version": "2026.7.2-beta.5",
|
|
4
4
|
"description": "OpenClaw IRC channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"openclaw": {
|
|
@@ -15,8 +15,19 @@
|
|
|
15
15
|
"allowInvalidConfigRecovery": true
|
|
16
16
|
},
|
|
17
17
|
"setupEntry": "./dist/setup-entry.js",
|
|
18
|
+
"setupFeatures": {
|
|
19
|
+
"configPromotion": true
|
|
20
|
+
},
|
|
18
21
|
"channel": {
|
|
19
22
|
"id": "irc",
|
|
23
|
+
"configuredState": {
|
|
24
|
+
"env": {
|
|
25
|
+
"allOf": [
|
|
26
|
+
"IRC_HOST",
|
|
27
|
+
"IRC_NICK"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
20
31
|
"label": "IRC",
|
|
21
32
|
"selectionLabel": "IRC (Server + Nick)",
|
|
22
33
|
"detailLabel": "IRC",
|
|
@@ -27,20 +38,89 @@
|
|
|
27
38
|
"internet-relay-chat"
|
|
28
39
|
],
|
|
29
40
|
"systemImage": "network",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
"setup": {
|
|
42
|
+
"fields": [
|
|
43
|
+
{
|
|
44
|
+
"key": "host",
|
|
45
|
+
"kind": "string",
|
|
46
|
+
"cli": {
|
|
47
|
+
"flags": "--host <host>",
|
|
48
|
+
"description": "IRC server host"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"key": "port",
|
|
53
|
+
"kind": "string",
|
|
54
|
+
"cli": {
|
|
55
|
+
"flags": "--port <port>",
|
|
56
|
+
"description": "IRC server port"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"key": "tls",
|
|
61
|
+
"kind": "boolean",
|
|
62
|
+
"cli": {
|
|
63
|
+
"flags": "--tls",
|
|
64
|
+
"description": "Use TLS for IRC"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"key": "nick",
|
|
69
|
+
"kind": "string",
|
|
70
|
+
"cli": {
|
|
71
|
+
"flags": "--nick <nick>",
|
|
72
|
+
"description": "IRC nickname"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"key": "username",
|
|
77
|
+
"kind": "string",
|
|
78
|
+
"cli": {
|
|
79
|
+
"flags": "--username <name>",
|
|
80
|
+
"description": "IRC username"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"key": "realname",
|
|
85
|
+
"kind": "string",
|
|
86
|
+
"cli": {
|
|
87
|
+
"flags": "--realname <name>",
|
|
88
|
+
"description": "IRC real name"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"key": "channels",
|
|
93
|
+
"kind": "string-list",
|
|
94
|
+
"cli": {
|
|
95
|
+
"flags": "--channels <names>",
|
|
96
|
+
"description": "IRC channels"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"key": "password",
|
|
101
|
+
"kind": "string",
|
|
102
|
+
"sensitive": true,
|
|
103
|
+
"cli": {
|
|
104
|
+
"flags": "--password <password>",
|
|
105
|
+
"description": "IRC server password"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"key": "useEnv",
|
|
110
|
+
"kind": "boolean",
|
|
111
|
+
"cli": {
|
|
112
|
+
"flags": "--use-env",
|
|
113
|
+
"description": "Use IRC environment configuration"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
]
|
|
37
117
|
}
|
|
38
118
|
},
|
|
39
119
|
"compat": {
|
|
40
|
-
"pluginApi": ">=2026.7.2-beta.
|
|
120
|
+
"pluginApi": ">=2026.7.2-beta.5"
|
|
41
121
|
},
|
|
42
122
|
"build": {
|
|
43
|
-
"openclawVersion": "2026.7.2-beta.
|
|
123
|
+
"openclawVersion": "2026.7.2-beta.5",
|
|
44
124
|
"bundledDist": false
|
|
45
125
|
},
|
|
46
126
|
"release": {
|
|
@@ -62,11 +142,10 @@
|
|
|
62
142
|
"files": [
|
|
63
143
|
"dist/**",
|
|
64
144
|
"openclaw.plugin.json",
|
|
65
|
-
"npm-shrinkwrap.json",
|
|
66
145
|
"README.md"
|
|
67
146
|
],
|
|
68
147
|
"peerDependencies": {
|
|
69
|
-
"openclaw": ">=2026.7.2-beta.
|
|
148
|
+
"openclaw": ">=2026.7.2-beta.5"
|
|
70
149
|
},
|
|
71
150
|
"peerDependenciesMeta": {
|
|
72
151
|
"openclaw": {
|
package/npm-shrinkwrap.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@openclaw/irc",
|
|
3
|
-
"version": "2026.7.2-beta.3",
|
|
4
|
-
"lockfileVersion": 3,
|
|
5
|
-
"requires": true,
|
|
6
|
-
"packages": {
|
|
7
|
-
"": {
|
|
8
|
-
"name": "@openclaw/irc",
|
|
9
|
-
"version": "2026.7.2-beta.3",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"zod": "4.4.3"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"node_modules/zod": {
|
|
15
|
-
"version": "4.4.3",
|
|
16
|
-
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
|
17
|
-
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"funding": {
|
|
20
|
-
"url": "https://github.com/sponsors/colinhacks"
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|