@nextclaw/openclaw-compat 0.1.6 → 0.1.8
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/index.d.ts +50 -1
- package/dist/index.js +500 -684
- package/package.json +11 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/plugin-sdk/index.ts
|
|
2
|
+
import { listBuiltinChannelPlugins } from "@nextclaw/core";
|
|
2
3
|
function emptyPluginConfigSchema() {
|
|
3
4
|
return {
|
|
4
5
|
type: "object",
|
|
@@ -44,6 +45,19 @@ function normalizeAccountId(accountId) {
|
|
|
44
45
|
const trimmed = accountId?.trim();
|
|
45
46
|
return trimmed || DEFAULT_ACCOUNT_ID;
|
|
46
47
|
}
|
|
48
|
+
function createNextclawBuiltinChannelPlugin(channelId) {
|
|
49
|
+
const builtin = listBuiltinChannelPlugins().find((entry) => entry.id === channelId);
|
|
50
|
+
if (!builtin) {
|
|
51
|
+
throw new Error(`builtin channel plugin not found: ${channelId}`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
id: channelId,
|
|
55
|
+
nextclaw: {
|
|
56
|
+
isEnabled: builtin.isEnabled,
|
|
57
|
+
createChannel: builtin.create
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
47
61
|
var __nextclawPluginSdkCompat = true;
|
|
48
62
|
|
|
49
63
|
// src/plugins/config-state.ts
|
|
@@ -224,10 +238,10 @@ function resolvePluginChannelMessageToolHints(params) {
|
|
|
224
238
|
}
|
|
225
239
|
}
|
|
226
240
|
function getPluginUiMetadataFromRegistry(registry) {
|
|
227
|
-
return registry.plugins.map((
|
|
228
|
-
id:
|
|
229
|
-
configSchema:
|
|
230
|
-
configUiHints:
|
|
241
|
+
return registry.plugins.map((plugin) => ({
|
|
242
|
+
id: plugin.id,
|
|
243
|
+
configSchema: plugin.configJsonSchema,
|
|
244
|
+
configUiHints: plugin.configUiHints
|
|
231
245
|
}));
|
|
232
246
|
}
|
|
233
247
|
async function startPluginChannelGateways(params) {
|
|
@@ -1057,11 +1071,11 @@ async function installPluginFromPath(params) {
|
|
|
1057
1071
|
|
|
1058
1072
|
// src/plugins/loader.ts
|
|
1059
1073
|
import fs5 from "fs";
|
|
1060
|
-
import
|
|
1074
|
+
import path5 from "path";
|
|
1061
1075
|
import { fileURLToPath } from "url";
|
|
1076
|
+
import { createRequire } from "module";
|
|
1062
1077
|
import createJitiImport from "jiti";
|
|
1063
1078
|
import { getWorkspacePathFromConfig } from "@nextclaw/core";
|
|
1064
|
-
import { expandHome as expandHome2 } from "@nextclaw/core";
|
|
1065
1079
|
|
|
1066
1080
|
// src/plugins/manifest-registry.ts
|
|
1067
1081
|
import fs4 from "fs";
|
|
@@ -1208,6 +1222,43 @@ function loadPluginUiMetadata(params) {
|
|
|
1208
1222
|
return toPluginUiMetadata(registry.plugins);
|
|
1209
1223
|
}
|
|
1210
1224
|
|
|
1225
|
+
// src/plugins/schema-validator.ts
|
|
1226
|
+
import AjvPkg from "ajv";
|
|
1227
|
+
var AjvCtor = AjvPkg;
|
|
1228
|
+
var ajv = new AjvCtor({
|
|
1229
|
+
allErrors: true,
|
|
1230
|
+
strict: false,
|
|
1231
|
+
removeAdditional: false
|
|
1232
|
+
});
|
|
1233
|
+
var schemaCache = /* @__PURE__ */ new Map();
|
|
1234
|
+
function formatAjvErrors(errors) {
|
|
1235
|
+
if (!errors || errors.length === 0) {
|
|
1236
|
+
return ["invalid config"];
|
|
1237
|
+
}
|
|
1238
|
+
return errors.map((error) => {
|
|
1239
|
+
const path7 = error.instancePath?.replace(/^\//, "").replace(/\//g, ".") || "<root>";
|
|
1240
|
+
const message = error.message ?? "invalid";
|
|
1241
|
+
return `${path7}: ${message}`;
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
function validateJsonSchemaValue(params) {
|
|
1245
|
+
let cached = schemaCache.get(params.cacheKey);
|
|
1246
|
+
if (!cached || cached.schema !== params.schema) {
|
|
1247
|
+
const validate = ajv.compile(params.schema);
|
|
1248
|
+
cached = { validate, schema: params.schema };
|
|
1249
|
+
schemaCache.set(params.cacheKey, cached);
|
|
1250
|
+
}
|
|
1251
|
+
const ok = cached.validate(params.value);
|
|
1252
|
+
if (ok) {
|
|
1253
|
+
return { ok: true };
|
|
1254
|
+
}
|
|
1255
|
+
return { ok: false, errors: formatAjvErrors(cached.validate.errors) };
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// src/plugins/registry.ts
|
|
1259
|
+
import path4 from "path";
|
|
1260
|
+
import { expandHome as expandHome2 } from "@nextclaw/core";
|
|
1261
|
+
|
|
1211
1262
|
// src/plugins/runtime.ts
|
|
1212
1263
|
import { getPackageVersion } from "@nextclaw/core";
|
|
1213
1264
|
import { MemoryGetTool, MemorySearchTool } from "@nextclaw/core";
|
|
@@ -1260,165 +1311,339 @@ function createPluginRuntime(params) {
|
|
|
1260
1311
|
};
|
|
1261
1312
|
}
|
|
1262
1313
|
|
|
1263
|
-
// src/plugins/
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1314
|
+
// src/plugins/registry.ts
|
|
1315
|
+
function buildPluginLogger(base, pluginId) {
|
|
1316
|
+
const withPrefix = (message) => `[plugins:${pluginId}] ${message}`;
|
|
1317
|
+
return {
|
|
1318
|
+
info: (message) => base.info(withPrefix(message)),
|
|
1319
|
+
warn: (message) => base.warn(withPrefix(message)),
|
|
1320
|
+
error: (message) => base.error(withPrefix(message)),
|
|
1321
|
+
debug: base.debug ? (message) => base.debug?.(withPrefix(message)) : void 0
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
function ensureUniqueNames(params) {
|
|
1325
|
+
const accepted = [];
|
|
1326
|
+
for (const rawName of params.names) {
|
|
1327
|
+
const name = rawName.trim();
|
|
1328
|
+
if (!name) {
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
if (params.reserved.has(name)) {
|
|
1332
|
+
params.diagnostics.push({
|
|
1333
|
+
level: "error",
|
|
1334
|
+
pluginId: params.pluginId,
|
|
1335
|
+
source: params.source,
|
|
1336
|
+
message: `${params.kind} already registered by core: ${name}`
|
|
1337
|
+
});
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
1340
|
+
const owner = params.owners.get(name);
|
|
1341
|
+
if (owner && owner !== params.pluginId) {
|
|
1342
|
+
params.diagnostics.push({
|
|
1343
|
+
level: "error",
|
|
1344
|
+
pluginId: params.pluginId,
|
|
1345
|
+
source: params.source,
|
|
1346
|
+
message: `${params.kind} already registered: ${name} (${owner})`
|
|
1347
|
+
});
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
params.owners.set(name, params.pluginId);
|
|
1351
|
+
accepted.push(name);
|
|
1275
1352
|
}
|
|
1276
|
-
return
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1353
|
+
return accepted;
|
|
1354
|
+
}
|
|
1355
|
+
function normalizeToolList(value) {
|
|
1356
|
+
if (!value) {
|
|
1357
|
+
return [];
|
|
1358
|
+
}
|
|
1359
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1360
|
+
return list.filter((entry) => {
|
|
1361
|
+
if (!entry || typeof entry !== "object") {
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1364
|
+
const candidate = entry;
|
|
1365
|
+
return typeof candidate.name === "string" && candidate.name.trim().length > 0 && candidate.parameters !== void 0 && typeof candidate.execute === "function";
|
|
1280
1366
|
});
|
|
1281
1367
|
}
|
|
1282
|
-
function
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1368
|
+
function createPluginRegisterRuntime(params) {
|
|
1369
|
+
return {
|
|
1370
|
+
config: params.config,
|
|
1371
|
+
workspaceDir: params.workspaceDir,
|
|
1372
|
+
logger: params.logger,
|
|
1373
|
+
registry: params.registry,
|
|
1374
|
+
toolNameOwners: /* @__PURE__ */ new Map(),
|
|
1375
|
+
channelIdOwners: /* @__PURE__ */ new Map(),
|
|
1376
|
+
providerIdOwners: /* @__PURE__ */ new Map(),
|
|
1377
|
+
resolvedToolNames: /* @__PURE__ */ new Set(),
|
|
1378
|
+
reservedToolNames: params.reservedToolNames,
|
|
1379
|
+
reservedChannelIds: params.reservedChannelIds,
|
|
1380
|
+
reservedProviderIds: params.reservedProviderIds
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
function registerPluginTool(params) {
|
|
1384
|
+
const toolInput = params.tool;
|
|
1385
|
+
const normalizedNames = [];
|
|
1386
|
+
if (Array.isArray(params.opts?.names)) {
|
|
1387
|
+
for (const name of params.opts?.names ?? []) {
|
|
1388
|
+
const trimmed = String(name).trim();
|
|
1389
|
+
if (trimmed) {
|
|
1390
|
+
normalizedNames.push(trimmed);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
} else if (params.opts?.name && String(params.opts.name).trim()) {
|
|
1394
|
+
normalizedNames.push(String(params.opts.name).trim());
|
|
1288
1395
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1396
|
+
if (typeof toolInput !== "function") {
|
|
1397
|
+
const intrinsic = toolInput.name.trim();
|
|
1398
|
+
if (intrinsic) {
|
|
1399
|
+
normalizedNames.push(intrinsic);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
const acceptedNames = ensureUniqueNames({
|
|
1403
|
+
names: normalizedNames,
|
|
1404
|
+
pluginId: params.pluginId,
|
|
1405
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1406
|
+
source: params.source,
|
|
1407
|
+
owners: params.runtime.toolNameOwners,
|
|
1408
|
+
reserved: params.runtime.reservedToolNames,
|
|
1409
|
+
kind: "tool"
|
|
1410
|
+
});
|
|
1411
|
+
if (acceptedNames.length === 0) {
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
const factory = typeof toolInput === "function" ? toolInput : () => toolInput;
|
|
1415
|
+
const registration = {
|
|
1416
|
+
pluginId: params.pluginId,
|
|
1417
|
+
factory,
|
|
1418
|
+
names: acceptedNames,
|
|
1419
|
+
optional: params.opts?.optional === true,
|
|
1420
|
+
source: params.source
|
|
1421
|
+
};
|
|
1422
|
+
params.runtime.registry.tools.push(registration);
|
|
1423
|
+
params.record.toolNames.push(...acceptedNames);
|
|
1424
|
+
if (typeof toolInput === "function") {
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (!params.runtime.resolvedToolNames.has(toolInput.name)) {
|
|
1428
|
+
params.runtime.resolvedToolNames.add(toolInput.name);
|
|
1429
|
+
params.runtime.registry.resolvedTools.push(toolInput);
|
|
1292
1430
|
}
|
|
1293
|
-
return { ok: false, errors: formatAjvErrors(cached.validate.errors) };
|
|
1294
1431
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1432
|
+
function registerPluginChannel(params) {
|
|
1433
|
+
const normalizedChannel = params.registration && typeof params.registration === "object" && "plugin" in params.registration ? params.registration.plugin : params.registration;
|
|
1434
|
+
if (!normalizedChannel || typeof normalizedChannel !== "object") {
|
|
1435
|
+
params.runtime.registry.diagnostics.push({
|
|
1436
|
+
level: "error",
|
|
1437
|
+
pluginId: params.pluginId,
|
|
1438
|
+
source: params.source,
|
|
1439
|
+
message: "channel registration missing plugin object"
|
|
1440
|
+
});
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
const channelObj = normalizedChannel;
|
|
1444
|
+
const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
|
|
1445
|
+
const accepted = ensureUniqueNames({
|
|
1446
|
+
names: [rawId],
|
|
1447
|
+
pluginId: params.pluginId,
|
|
1448
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1449
|
+
source: params.source,
|
|
1450
|
+
owners: params.runtime.channelIdOwners,
|
|
1451
|
+
reserved: params.runtime.reservedChannelIds,
|
|
1452
|
+
kind: "channel"
|
|
1453
|
+
});
|
|
1454
|
+
if (accepted.length === 0) {
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const channelPlugin = normalizedChannel;
|
|
1458
|
+
params.runtime.registry.channels.push({
|
|
1459
|
+
pluginId: params.pluginId,
|
|
1460
|
+
channel: channelPlugin,
|
|
1461
|
+
source: params.source
|
|
1462
|
+
});
|
|
1463
|
+
const channelId = accepted[0];
|
|
1464
|
+
params.record.channelIds.push(channelId);
|
|
1465
|
+
const configSchema = channelPlugin.configSchema;
|
|
1466
|
+
if (configSchema && typeof configSchema === "object") {
|
|
1467
|
+
const schema = configSchema.schema;
|
|
1468
|
+
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1469
|
+
params.record.configJsonSchema = schema;
|
|
1470
|
+
params.record.configSchema = true;
|
|
1471
|
+
}
|
|
1472
|
+
const uiHints = configSchema.uiHints;
|
|
1473
|
+
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
1474
|
+
params.record.configUiHints = {
|
|
1475
|
+
...params.record.configUiHints ?? {},
|
|
1476
|
+
...uiHints
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
1481
|
+
const previewTools = normalizeToolList(value);
|
|
1482
|
+
if (previewTools.length === 0) {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
const declaredNames = previewTools.map((tool) => tool.name);
|
|
1486
|
+
const acceptedNames = ensureUniqueNames({
|
|
1487
|
+
names: declaredNames,
|
|
1488
|
+
pluginId: params.pluginId,
|
|
1489
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1490
|
+
source: params.source,
|
|
1491
|
+
owners: params.runtime.toolNameOwners,
|
|
1492
|
+
reserved: params.runtime.reservedToolNames,
|
|
1493
|
+
kind: "tool"
|
|
1494
|
+
});
|
|
1495
|
+
if (acceptedNames.length === 0) {
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
const factory = (ctx) => {
|
|
1499
|
+
const tools = normalizeToolList(resolveValue(ctx));
|
|
1500
|
+
if (tools.length === 0) {
|
|
1501
|
+
return [];
|
|
1502
|
+
}
|
|
1503
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
1504
|
+
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
1505
|
+
};
|
|
1506
|
+
params.runtime.registry.tools.push({
|
|
1507
|
+
pluginId: params.pluginId,
|
|
1508
|
+
factory,
|
|
1509
|
+
names: acceptedNames,
|
|
1510
|
+
optional,
|
|
1511
|
+
source: params.source
|
|
1512
|
+
});
|
|
1513
|
+
params.record.toolNames.push(...acceptedNames);
|
|
1514
|
+
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
1515
|
+
for (const name of acceptedNames) {
|
|
1516
|
+
const resolvedTool = previewByName.get(name);
|
|
1517
|
+
if (!resolvedTool || params.runtime.resolvedToolNames.has(resolvedTool.name)) {
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
params.runtime.resolvedToolNames.add(resolvedTool.name);
|
|
1521
|
+
params.runtime.registry.resolvedTools.push(resolvedTool);
|
|
1522
|
+
}
|
|
1523
|
+
params.runtime.registry.diagnostics.push({
|
|
1524
|
+
level: "warn",
|
|
1525
|
+
pluginId: params.pluginId,
|
|
1526
|
+
source: params.source,
|
|
1527
|
+
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
1528
|
+
});
|
|
1529
|
+
};
|
|
1530
|
+
const agentTools = channelPlugin.agentTools;
|
|
1531
|
+
if (typeof agentTools === "function") {
|
|
1532
|
+
pushChannelTools(
|
|
1533
|
+
normalizeToolList(agentTools()),
|
|
1534
|
+
false,
|
|
1535
|
+
`channel "${channelId}"`,
|
|
1536
|
+
() => agentTools()
|
|
1537
|
+
);
|
|
1538
|
+
} else if (agentTools) {
|
|
1539
|
+
pushChannelTools(normalizeToolList(agentTools), false, `channel "${channelId}"`, () => agentTools);
|
|
1307
1540
|
}
|
|
1308
|
-
return plugin10;
|
|
1309
1541
|
}
|
|
1310
|
-
function
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1542
|
+
function registerPluginProvider(params) {
|
|
1543
|
+
const accepted = ensureUniqueNames({
|
|
1544
|
+
names: [params.provider.id],
|
|
1545
|
+
pluginId: params.pluginId,
|
|
1546
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1547
|
+
source: params.source,
|
|
1548
|
+
owners: params.runtime.providerIdOwners,
|
|
1549
|
+
reserved: params.runtime.reservedProviderIds,
|
|
1550
|
+
kind: "provider"
|
|
1551
|
+
});
|
|
1552
|
+
if (accepted.length === 0) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
params.runtime.registry.providers.push({
|
|
1556
|
+
pluginId: params.pluginId,
|
|
1557
|
+
provider: params.provider,
|
|
1558
|
+
source: params.source
|
|
1559
|
+
});
|
|
1560
|
+
params.record.providerIds.push(accepted[0]);
|
|
1561
|
+
}
|
|
1562
|
+
function registerPluginWithApi(params) {
|
|
1563
|
+
const pluginRuntime = createPluginRuntime({ workspace: params.runtime.workspaceDir, config: params.runtime.config });
|
|
1564
|
+
const pluginLogger = buildPluginLogger(params.runtime.logger, params.pluginId);
|
|
1565
|
+
const pushUnsupported = (capability) => {
|
|
1566
|
+
params.runtime.registry.diagnostics.push({
|
|
1567
|
+
level: "warn",
|
|
1568
|
+
pluginId: params.pluginId,
|
|
1569
|
+
source: params.source,
|
|
1570
|
+
message: `${capability} is not supported by nextclaw compat layer yet`
|
|
1571
|
+
});
|
|
1572
|
+
pluginLogger.warn(`${capability} is ignored (not supported yet)`);
|
|
1573
|
+
};
|
|
1574
|
+
const api = {
|
|
1575
|
+
id: params.pluginId,
|
|
1576
|
+
name: params.record.name,
|
|
1577
|
+
version: params.record.version,
|
|
1578
|
+
description: params.record.description,
|
|
1579
|
+
source: params.source,
|
|
1580
|
+
config: params.runtime.config,
|
|
1581
|
+
pluginConfig: params.pluginConfig,
|
|
1582
|
+
runtime: pluginRuntime,
|
|
1583
|
+
logger: pluginLogger,
|
|
1584
|
+
registerTool: (tool, opts) => {
|
|
1585
|
+
registerPluginTool({
|
|
1586
|
+
runtime: params.runtime,
|
|
1587
|
+
record: params.record,
|
|
1588
|
+
pluginId: params.pluginId,
|
|
1589
|
+
source: params.source,
|
|
1590
|
+
tool,
|
|
1591
|
+
opts
|
|
1328
1592
|
});
|
|
1593
|
+
},
|
|
1594
|
+
registerChannel: (registration) => {
|
|
1595
|
+
registerPluginChannel({
|
|
1596
|
+
runtime: params.runtime,
|
|
1597
|
+
record: params.record,
|
|
1598
|
+
pluginId: params.pluginId,
|
|
1599
|
+
source: params.source,
|
|
1600
|
+
registration
|
|
1601
|
+
});
|
|
1602
|
+
},
|
|
1603
|
+
registerProvider: (provider) => {
|
|
1604
|
+
registerPluginProvider({
|
|
1605
|
+
runtime: params.runtime,
|
|
1606
|
+
record: params.record,
|
|
1607
|
+
pluginId: params.pluginId,
|
|
1608
|
+
source: params.source,
|
|
1609
|
+
provider
|
|
1610
|
+
});
|
|
1611
|
+
},
|
|
1612
|
+
registerHook: () => pushUnsupported("registerHook"),
|
|
1613
|
+
registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
|
|
1614
|
+
registerCli: () => pushUnsupported("registerCli"),
|
|
1615
|
+
registerService: () => pushUnsupported("registerService"),
|
|
1616
|
+
registerCommand: () => pushUnsupported("registerCommand"),
|
|
1617
|
+
registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
|
|
1618
|
+
registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
|
|
1619
|
+
resolvePath: (input) => {
|
|
1620
|
+
const trimmed = input.trim();
|
|
1621
|
+
if (!trimmed) {
|
|
1622
|
+
return params.rootDir;
|
|
1623
|
+
}
|
|
1624
|
+
if (path4.isAbsolute(trimmed)) {
|
|
1625
|
+
return path4.resolve(expandHome2(trimmed));
|
|
1626
|
+
}
|
|
1627
|
+
return path4.resolve(params.rootDir, trimmed);
|
|
1329
1628
|
}
|
|
1330
1629
|
};
|
|
1630
|
+
try {
|
|
1631
|
+
const result = params.register(api);
|
|
1632
|
+
if (result && typeof result === "object" && "then" in result) {
|
|
1633
|
+
params.runtime.registry.diagnostics.push({
|
|
1634
|
+
level: "warn",
|
|
1635
|
+
pluginId: params.pluginId,
|
|
1636
|
+
source: params.source,
|
|
1637
|
+
message: "plugin register returned a promise; async registration is ignored"
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
return { ok: true };
|
|
1641
|
+
} catch (err) {
|
|
1642
|
+
const error = `plugin failed during register: ${String(err)}`;
|
|
1643
|
+
return { ok: false, error };
|
|
1644
|
+
}
|
|
1331
1645
|
}
|
|
1332
1646
|
|
|
1333
|
-
// src/plugins/bundled/channels/telegram.ts
|
|
1334
|
-
var plugin = createBundledChannelPlugin({
|
|
1335
|
-
channelId: "telegram",
|
|
1336
|
-
name: "Builtin Telegram Channel",
|
|
1337
|
-
description: "Builtin NextClaw channel plugin for telegram"
|
|
1338
|
-
});
|
|
1339
|
-
var telegram_default = plugin;
|
|
1340
|
-
|
|
1341
|
-
// src/plugins/bundled/channels/whatsapp.ts
|
|
1342
|
-
var plugin2 = createBundledChannelPlugin({
|
|
1343
|
-
channelId: "whatsapp",
|
|
1344
|
-
name: "Builtin WhatsApp Channel",
|
|
1345
|
-
description: "Builtin NextClaw channel plugin for whatsapp"
|
|
1346
|
-
});
|
|
1347
|
-
var whatsapp_default = plugin2;
|
|
1348
|
-
|
|
1349
|
-
// src/plugins/bundled/channels/discord.ts
|
|
1350
|
-
var plugin3 = createBundledChannelPlugin({
|
|
1351
|
-
channelId: "discord",
|
|
1352
|
-
name: "Builtin Discord Channel",
|
|
1353
|
-
description: "Builtin NextClaw channel plugin for discord"
|
|
1354
|
-
});
|
|
1355
|
-
var discord_default = plugin3;
|
|
1356
|
-
|
|
1357
|
-
// src/plugins/bundled/channels/feishu.ts
|
|
1358
|
-
var plugin4 = createBundledChannelPlugin({
|
|
1359
|
-
channelId: "feishu",
|
|
1360
|
-
name: "Builtin Feishu Channel",
|
|
1361
|
-
description: "Builtin NextClaw channel plugin for feishu"
|
|
1362
|
-
});
|
|
1363
|
-
var feishu_default = plugin4;
|
|
1364
|
-
|
|
1365
|
-
// src/plugins/bundled/channels/mochat.ts
|
|
1366
|
-
var plugin5 = createBundledChannelPlugin({
|
|
1367
|
-
channelId: "mochat",
|
|
1368
|
-
name: "Builtin Mochat Channel",
|
|
1369
|
-
description: "Builtin NextClaw channel plugin for mochat"
|
|
1370
|
-
});
|
|
1371
|
-
var mochat_default = plugin5;
|
|
1372
|
-
|
|
1373
|
-
// src/plugins/bundled/channels/dingtalk.ts
|
|
1374
|
-
var plugin6 = createBundledChannelPlugin({
|
|
1375
|
-
channelId: "dingtalk",
|
|
1376
|
-
name: "Builtin DingTalk Channel",
|
|
1377
|
-
description: "Builtin NextClaw channel plugin for dingtalk"
|
|
1378
|
-
});
|
|
1379
|
-
var dingtalk_default = plugin6;
|
|
1380
|
-
|
|
1381
|
-
// src/plugins/bundled/channels/email.ts
|
|
1382
|
-
var plugin7 = createBundledChannelPlugin({
|
|
1383
|
-
channelId: "email",
|
|
1384
|
-
name: "Builtin Email Channel",
|
|
1385
|
-
description: "Builtin NextClaw channel plugin for email"
|
|
1386
|
-
});
|
|
1387
|
-
var email_default = plugin7;
|
|
1388
|
-
|
|
1389
|
-
// src/plugins/bundled/channels/slack.ts
|
|
1390
|
-
var plugin8 = createBundledChannelPlugin({
|
|
1391
|
-
channelId: "slack",
|
|
1392
|
-
name: "Builtin Slack Channel",
|
|
1393
|
-
description: "Builtin NextClaw channel plugin for slack"
|
|
1394
|
-
});
|
|
1395
|
-
var slack_default = plugin8;
|
|
1396
|
-
|
|
1397
|
-
// src/plugins/bundled/channels/qq.ts
|
|
1398
|
-
var plugin9 = createBundledChannelPlugin({
|
|
1399
|
-
channelId: "qq",
|
|
1400
|
-
name: "Builtin QQ Channel",
|
|
1401
|
-
description: "Builtin NextClaw channel plugin for qq"
|
|
1402
|
-
});
|
|
1403
|
-
var qq_default = plugin9;
|
|
1404
|
-
|
|
1405
|
-
// src/plugins/bundled/channels/index.ts
|
|
1406
|
-
var BUNDLED_CHANNEL_PLUGINS = [
|
|
1407
|
-
telegram_default,
|
|
1408
|
-
whatsapp_default,
|
|
1409
|
-
discord_default,
|
|
1410
|
-
feishu_default,
|
|
1411
|
-
mochat_default,
|
|
1412
|
-
dingtalk_default,
|
|
1413
|
-
email_default,
|
|
1414
|
-
slack_default,
|
|
1415
|
-
qq_default
|
|
1416
|
-
];
|
|
1417
|
-
function listBundledChannelPluginDefinitions() {
|
|
1418
|
-
return [...BUNDLED_CHANNEL_PLUGINS];
|
|
1419
|
-
}
|
|
1420
|
-
var BUNDLED_CHANNEL_PLUGIN_IDS = BUNDLED_CHANNEL_PLUGINS.map((plugin10) => plugin10.id).filter((id) => typeof id === "string" && id.trim().length > 0);
|
|
1421
|
-
|
|
1422
1647
|
// src/plugins/loader.ts
|
|
1423
1648
|
var createJiti = createJitiImport;
|
|
1424
1649
|
var defaultLogger2 = {
|
|
@@ -1427,21 +1652,47 @@ var defaultLogger2 = {
|
|
|
1427
1652
|
error: (message) => console.error(message),
|
|
1428
1653
|
debug: (message) => console.debug(message)
|
|
1429
1654
|
};
|
|
1655
|
+
var BUNDLED_CHANNEL_PLUGIN_PACKAGES = [
|
|
1656
|
+
"@nextclaw/channel-plugin-telegram",
|
|
1657
|
+
"@nextclaw/channel-plugin-whatsapp",
|
|
1658
|
+
"@nextclaw/channel-plugin-discord",
|
|
1659
|
+
"@nextclaw/channel-plugin-feishu",
|
|
1660
|
+
"@nextclaw/channel-plugin-mochat",
|
|
1661
|
+
"@nextclaw/channel-plugin-dingtalk",
|
|
1662
|
+
"@nextclaw/channel-plugin-email",
|
|
1663
|
+
"@nextclaw/channel-plugin-slack",
|
|
1664
|
+
"@nextclaw/channel-plugin-qq"
|
|
1665
|
+
];
|
|
1666
|
+
function resolvePackageRootFromEntry(entryFile) {
|
|
1667
|
+
let cursor = path5.dirname(entryFile);
|
|
1668
|
+
for (let i = 0; i < 8; i += 1) {
|
|
1669
|
+
const candidate = path5.join(cursor, "package.json");
|
|
1670
|
+
if (fs5.existsSync(candidate)) {
|
|
1671
|
+
return cursor;
|
|
1672
|
+
}
|
|
1673
|
+
const parent = path5.dirname(cursor);
|
|
1674
|
+
if (parent === cursor) {
|
|
1675
|
+
break;
|
|
1676
|
+
}
|
|
1677
|
+
cursor = parent;
|
|
1678
|
+
}
|
|
1679
|
+
return path5.dirname(entryFile);
|
|
1680
|
+
}
|
|
1430
1681
|
function resolvePluginSdkAliasFile(params) {
|
|
1431
1682
|
try {
|
|
1432
1683
|
const modulePath = fileURLToPath(import.meta.url);
|
|
1433
1684
|
const isProduction = process.env.NODE_ENV === "production";
|
|
1434
|
-
let cursor =
|
|
1685
|
+
let cursor = path5.dirname(modulePath);
|
|
1435
1686
|
for (let i = 0; i < 6; i += 1) {
|
|
1436
|
-
const srcCandidate =
|
|
1437
|
-
const distCandidate =
|
|
1687
|
+
const srcCandidate = path5.join(cursor, "src", "plugin-sdk", params.srcFile);
|
|
1688
|
+
const distCandidate = path5.join(cursor, "dist", "plugin-sdk", params.distFile);
|
|
1438
1689
|
const candidates = isProduction ? [distCandidate, srcCandidate] : [srcCandidate, distCandidate];
|
|
1439
1690
|
for (const candidate of candidates) {
|
|
1440
1691
|
if (fs5.existsSync(candidate)) {
|
|
1441
1692
|
return candidate;
|
|
1442
1693
|
}
|
|
1443
1694
|
}
|
|
1444
|
-
const parent =
|
|
1695
|
+
const parent = path5.dirname(cursor);
|
|
1445
1696
|
if (parent === cursor) {
|
|
1446
1697
|
break;
|
|
1447
1698
|
}
|
|
@@ -1471,19 +1722,6 @@ function resolvePluginModuleExport(moduleExport) {
|
|
|
1471
1722
|
}
|
|
1472
1723
|
return {};
|
|
1473
1724
|
}
|
|
1474
|
-
function normalizeToolList(value) {
|
|
1475
|
-
if (!value) {
|
|
1476
|
-
return [];
|
|
1477
|
-
}
|
|
1478
|
-
const list = Array.isArray(value) ? value : [value];
|
|
1479
|
-
return list.filter((entry) => {
|
|
1480
|
-
if (!entry || typeof entry !== "object") {
|
|
1481
|
-
return false;
|
|
1482
|
-
}
|
|
1483
|
-
const candidate = entry;
|
|
1484
|
-
return typeof candidate.name === "string" && candidate.name.trim().length > 0 && candidate.parameters !== void 0 && typeof candidate.execute === "function";
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
1725
|
function createPluginRecord(params) {
|
|
1488
1726
|
return {
|
|
1489
1727
|
id: params.id,
|
|
@@ -1504,46 +1742,6 @@ function createPluginRecord(params) {
|
|
|
1504
1742
|
configJsonSchema: params.configJsonSchema
|
|
1505
1743
|
};
|
|
1506
1744
|
}
|
|
1507
|
-
function buildPluginLogger(base, pluginId) {
|
|
1508
|
-
const withPrefix = (message) => `[plugins:${pluginId}] ${message}`;
|
|
1509
|
-
return {
|
|
1510
|
-
info: (message) => base.info(withPrefix(message)),
|
|
1511
|
-
warn: (message) => base.warn(withPrefix(message)),
|
|
1512
|
-
error: (message) => base.error(withPrefix(message)),
|
|
1513
|
-
debug: base.debug ? (message) => base.debug?.(withPrefix(message)) : void 0
|
|
1514
|
-
};
|
|
1515
|
-
}
|
|
1516
|
-
function ensureUniqueNames(params) {
|
|
1517
|
-
const accepted = [];
|
|
1518
|
-
for (const rawName of params.names) {
|
|
1519
|
-
const name = rawName.trim();
|
|
1520
|
-
if (!name) {
|
|
1521
|
-
continue;
|
|
1522
|
-
}
|
|
1523
|
-
if (params.reserved.has(name)) {
|
|
1524
|
-
params.diagnostics.push({
|
|
1525
|
-
level: "error",
|
|
1526
|
-
pluginId: params.pluginId,
|
|
1527
|
-
source: params.source,
|
|
1528
|
-
message: `${params.kind} already registered by core: ${name}`
|
|
1529
|
-
});
|
|
1530
|
-
continue;
|
|
1531
|
-
}
|
|
1532
|
-
const owner = params.owners.get(name);
|
|
1533
|
-
if (owner && owner !== params.pluginId) {
|
|
1534
|
-
params.diagnostics.push({
|
|
1535
|
-
level: "error",
|
|
1536
|
-
pluginId: params.pluginId,
|
|
1537
|
-
source: params.source,
|
|
1538
|
-
message: `${params.kind} already registered: ${name} (${owner})`
|
|
1539
|
-
});
|
|
1540
|
-
continue;
|
|
1541
|
-
}
|
|
1542
|
-
params.owners.set(name, params.pluginId);
|
|
1543
|
-
accepted.push(name);
|
|
1544
|
-
}
|
|
1545
|
-
return accepted;
|
|
1546
|
-
}
|
|
1547
1745
|
function isPlaceholderConfigSchema(schema) {
|
|
1548
1746
|
if (!schema || typeof schema !== "object") {
|
|
1549
1747
|
return false;
|
|
@@ -1573,9 +1771,37 @@ function validatePluginConfig(params) {
|
|
|
1573
1771
|
return { ok: false, errors: result.errors };
|
|
1574
1772
|
}
|
|
1575
1773
|
function appendBundledChannelPlugins(params) {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1774
|
+
const require2 = createRequire(import.meta.url);
|
|
1775
|
+
for (const packageName of BUNDLED_CHANNEL_PLUGIN_PACKAGES) {
|
|
1776
|
+
let entryFile = "";
|
|
1777
|
+
let rootDir = "";
|
|
1778
|
+
try {
|
|
1779
|
+
entryFile = require2.resolve(packageName);
|
|
1780
|
+
rootDir = resolvePackageRootFromEntry(entryFile);
|
|
1781
|
+
} catch (err) {
|
|
1782
|
+
params.registry.diagnostics.push({
|
|
1783
|
+
level: "error",
|
|
1784
|
+
source: packageName,
|
|
1785
|
+
message: `bundled plugin package not resolvable: ${String(err)}`
|
|
1786
|
+
});
|
|
1787
|
+
continue;
|
|
1788
|
+
}
|
|
1789
|
+
let moduleExport = null;
|
|
1790
|
+
try {
|
|
1791
|
+
moduleExport = params.jiti(entryFile);
|
|
1792
|
+
} catch (err) {
|
|
1793
|
+
params.registry.diagnostics.push({
|
|
1794
|
+
level: "error",
|
|
1795
|
+
source: entryFile,
|
|
1796
|
+
message: `failed to load bundled plugin: ${String(err)}`
|
|
1797
|
+
});
|
|
1798
|
+
continue;
|
|
1799
|
+
}
|
|
1800
|
+
const resolved = resolvePluginModuleExport(moduleExport);
|
|
1801
|
+
const definition = resolved.definition;
|
|
1802
|
+
const register = resolved.register;
|
|
1803
|
+
const pluginId = typeof definition?.id === "string" ? definition.id.trim() : "";
|
|
1804
|
+
const source = entryFile;
|
|
1579
1805
|
if (!pluginId) {
|
|
1580
1806
|
params.registry.diagnostics.push({
|
|
1581
1807
|
level: "error",
|
|
@@ -1586,18 +1812,17 @@ function appendBundledChannelPlugins(params) {
|
|
|
1586
1812
|
}
|
|
1587
1813
|
const record = createPluginRecord({
|
|
1588
1814
|
id: pluginId,
|
|
1589
|
-
name: definition
|
|
1590
|
-
description: definition
|
|
1591
|
-
version: definition
|
|
1592
|
-
kind: definition
|
|
1815
|
+
name: definition?.name ?? pluginId,
|
|
1816
|
+
description: definition?.description,
|
|
1817
|
+
version: definition?.version,
|
|
1818
|
+
kind: definition?.kind,
|
|
1593
1819
|
source,
|
|
1594
1820
|
origin: "bundled",
|
|
1595
|
-
workspaceDir: params.workspaceDir,
|
|
1821
|
+
workspaceDir: params.runtime.workspaceDir,
|
|
1596
1822
|
enabled: true,
|
|
1597
|
-
configSchema: Boolean(definition
|
|
1598
|
-
configJsonSchema: definition
|
|
1823
|
+
configSchema: Boolean(definition?.configSchema),
|
|
1824
|
+
configJsonSchema: definition?.configSchema
|
|
1599
1825
|
});
|
|
1600
|
-
const register = definition.register ?? definition.activate;
|
|
1601
1826
|
if (typeof register !== "function") {
|
|
1602
1827
|
record.status = "error";
|
|
1603
1828
|
record.error = "plugin export missing register/activate";
|
|
@@ -1610,203 +1835,26 @@ function appendBundledChannelPlugins(params) {
|
|
|
1610
1835
|
});
|
|
1611
1836
|
continue;
|
|
1612
1837
|
}
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
level: "warn",
|
|
1618
|
-
pluginId,
|
|
1619
|
-
source,
|
|
1620
|
-
message: `${capability} is not supported by nextclaw compat layer yet`
|
|
1621
|
-
});
|
|
1622
|
-
pluginLogger.warn(`${capability} is ignored (not supported yet)`);
|
|
1623
|
-
};
|
|
1624
|
-
const api = {
|
|
1625
|
-
id: pluginId,
|
|
1626
|
-
name: record.name,
|
|
1627
|
-
version: record.version,
|
|
1628
|
-
description: record.description,
|
|
1838
|
+
const result = registerPluginWithApi({
|
|
1839
|
+
runtime: params.runtime,
|
|
1840
|
+
record,
|
|
1841
|
+
pluginId,
|
|
1629
1842
|
source,
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
registerChannel: (registration) => {
|
|
1636
|
-
const normalizedChannel = registration && typeof registration === "object" && "plugin" in registration ? registration.plugin : registration;
|
|
1637
|
-
if (!normalizedChannel || typeof normalizedChannel !== "object") {
|
|
1638
|
-
params.registry.diagnostics.push({
|
|
1639
|
-
level: "error",
|
|
1640
|
-
pluginId,
|
|
1641
|
-
source,
|
|
1642
|
-
message: "channel registration missing plugin object"
|
|
1643
|
-
});
|
|
1644
|
-
return;
|
|
1645
|
-
}
|
|
1646
|
-
const channelObj = normalizedChannel;
|
|
1647
|
-
const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
|
|
1648
|
-
const accepted = ensureUniqueNames({
|
|
1649
|
-
names: [rawId],
|
|
1650
|
-
pluginId,
|
|
1651
|
-
diagnostics: params.registry.diagnostics,
|
|
1652
|
-
source,
|
|
1653
|
-
owners: params.channelIdOwners,
|
|
1654
|
-
reserved: params.reservedChannelIds,
|
|
1655
|
-
kind: "channel"
|
|
1656
|
-
});
|
|
1657
|
-
if (accepted.length === 0) {
|
|
1658
|
-
return;
|
|
1659
|
-
}
|
|
1660
|
-
const channelPlugin = normalizedChannel;
|
|
1661
|
-
params.registry.channels.push({
|
|
1662
|
-
pluginId,
|
|
1663
|
-
channel: channelPlugin,
|
|
1664
|
-
source
|
|
1665
|
-
});
|
|
1666
|
-
const channelId = accepted[0];
|
|
1667
|
-
record.channelIds.push(channelId);
|
|
1668
|
-
const configSchema = channelPlugin.configSchema;
|
|
1669
|
-
if (configSchema && typeof configSchema === "object") {
|
|
1670
|
-
const schema = configSchema.schema;
|
|
1671
|
-
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1672
|
-
record.configJsonSchema = schema;
|
|
1673
|
-
record.configSchema = true;
|
|
1674
|
-
}
|
|
1675
|
-
const uiHints = configSchema.uiHints;
|
|
1676
|
-
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
1677
|
-
record.configUiHints = {
|
|
1678
|
-
...record.configUiHints ?? {},
|
|
1679
|
-
...uiHints
|
|
1680
|
-
};
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
1684
|
-
const previewTools = normalizeToolList(value);
|
|
1685
|
-
if (previewTools.length === 0) {
|
|
1686
|
-
return;
|
|
1687
|
-
}
|
|
1688
|
-
const declaredNames = previewTools.map((tool) => tool.name);
|
|
1689
|
-
const acceptedNames = ensureUniqueNames({
|
|
1690
|
-
names: declaredNames,
|
|
1691
|
-
pluginId,
|
|
1692
|
-
diagnostics: params.registry.diagnostics,
|
|
1693
|
-
source,
|
|
1694
|
-
owners: params.toolNameOwners,
|
|
1695
|
-
reserved: params.reservedToolNames,
|
|
1696
|
-
kind: "tool"
|
|
1697
|
-
});
|
|
1698
|
-
if (acceptedNames.length === 0) {
|
|
1699
|
-
return;
|
|
1700
|
-
}
|
|
1701
|
-
const factory = (ctx) => {
|
|
1702
|
-
const tools = normalizeToolList(resolveValue(ctx));
|
|
1703
|
-
if (tools.length === 0) {
|
|
1704
|
-
return [];
|
|
1705
|
-
}
|
|
1706
|
-
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
1707
|
-
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
1708
|
-
};
|
|
1709
|
-
params.registry.tools.push({
|
|
1710
|
-
pluginId,
|
|
1711
|
-
factory,
|
|
1712
|
-
names: acceptedNames,
|
|
1713
|
-
optional,
|
|
1714
|
-
source
|
|
1715
|
-
});
|
|
1716
|
-
record.toolNames.push(...acceptedNames);
|
|
1717
|
-
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
1718
|
-
for (const name of acceptedNames) {
|
|
1719
|
-
const resolvedTool = previewByName.get(name);
|
|
1720
|
-
if (!resolvedTool || params.resolvedToolNames.has(resolvedTool.name)) {
|
|
1721
|
-
continue;
|
|
1722
|
-
}
|
|
1723
|
-
params.resolvedToolNames.add(resolvedTool.name);
|
|
1724
|
-
params.registry.resolvedTools.push(resolvedTool);
|
|
1725
|
-
}
|
|
1726
|
-
params.registry.diagnostics.push({
|
|
1727
|
-
level: "warn",
|
|
1728
|
-
pluginId,
|
|
1729
|
-
source,
|
|
1730
|
-
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
1731
|
-
});
|
|
1732
|
-
};
|
|
1733
|
-
const agentTools = channelPlugin.agentTools;
|
|
1734
|
-
if (typeof agentTools === "function") {
|
|
1735
|
-
pushChannelTools(
|
|
1736
|
-
normalizeToolList(agentTools()),
|
|
1737
|
-
false,
|
|
1738
|
-
`channel "${channelId}"`,
|
|
1739
|
-
() => agentTools()
|
|
1740
|
-
);
|
|
1741
|
-
} else if (agentTools) {
|
|
1742
|
-
pushChannelTools(
|
|
1743
|
-
normalizeToolList(agentTools),
|
|
1744
|
-
false,
|
|
1745
|
-
`channel "${channelId}"`,
|
|
1746
|
-
() => agentTools
|
|
1747
|
-
);
|
|
1748
|
-
}
|
|
1749
|
-
},
|
|
1750
|
-
registerProvider: (provider) => {
|
|
1751
|
-
const accepted = ensureUniqueNames({
|
|
1752
|
-
names: [provider.id],
|
|
1753
|
-
pluginId,
|
|
1754
|
-
diagnostics: params.registry.diagnostics,
|
|
1755
|
-
source,
|
|
1756
|
-
owners: params.providerIdOwners,
|
|
1757
|
-
reserved: params.reservedProviderIds,
|
|
1758
|
-
kind: "provider"
|
|
1759
|
-
});
|
|
1760
|
-
if (accepted.length === 0) {
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
|
-
params.registry.providers.push({
|
|
1764
|
-
pluginId,
|
|
1765
|
-
provider,
|
|
1766
|
-
source
|
|
1767
|
-
});
|
|
1768
|
-
record.providerIds.push(accepted[0]);
|
|
1769
|
-
},
|
|
1770
|
-
registerHook: () => pushUnsupported("registerHook"),
|
|
1771
|
-
registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
|
|
1772
|
-
registerCli: () => pushUnsupported("registerCli"),
|
|
1773
|
-
registerService: () => pushUnsupported("registerService"),
|
|
1774
|
-
registerCommand: () => pushUnsupported("registerCommand"),
|
|
1775
|
-
registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
|
|
1776
|
-
registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
|
|
1777
|
-
resolvePath: (input) => {
|
|
1778
|
-
const trimmed = input.trim();
|
|
1779
|
-
if (!trimmed) {
|
|
1780
|
-
return params.workspaceDir;
|
|
1781
|
-
}
|
|
1782
|
-
if (path4.isAbsolute(trimmed)) {
|
|
1783
|
-
return path4.resolve(expandHome2(trimmed));
|
|
1784
|
-
}
|
|
1785
|
-
return path4.resolve(params.workspaceDir, trimmed);
|
|
1786
|
-
}
|
|
1787
|
-
};
|
|
1788
|
-
try {
|
|
1789
|
-
const result = register(api);
|
|
1790
|
-
if (result && typeof result === "object" && "then" in result) {
|
|
1791
|
-
params.registry.diagnostics.push({
|
|
1792
|
-
level: "warn",
|
|
1793
|
-
pluginId,
|
|
1794
|
-
source,
|
|
1795
|
-
message: "plugin register returned a promise; async registration is ignored"
|
|
1796
|
-
});
|
|
1797
|
-
}
|
|
1798
|
-
params.registry.plugins.push(record);
|
|
1799
|
-
} catch (err) {
|
|
1843
|
+
rootDir,
|
|
1844
|
+
register,
|
|
1845
|
+
pluginConfig: void 0
|
|
1846
|
+
});
|
|
1847
|
+
if (!result.ok) {
|
|
1800
1848
|
record.status = "error";
|
|
1801
|
-
record.error =
|
|
1802
|
-
params.registry.plugins.push(record);
|
|
1849
|
+
record.error = result.error;
|
|
1803
1850
|
params.registry.diagnostics.push({
|
|
1804
1851
|
level: "error",
|
|
1805
1852
|
pluginId,
|
|
1806
1853
|
source,
|
|
1807
|
-
message:
|
|
1854
|
+
message: result.error
|
|
1808
1855
|
});
|
|
1809
1856
|
}
|
|
1857
|
+
params.registry.plugins.push(record);
|
|
1810
1858
|
}
|
|
1811
1859
|
}
|
|
1812
1860
|
function loadOpenClawPlugins(options) {
|
|
@@ -1823,26 +1871,33 @@ function loadOpenClawPlugins(options) {
|
|
|
1823
1871
|
diagnostics: [],
|
|
1824
1872
|
resolvedTools: []
|
|
1825
1873
|
};
|
|
1826
|
-
const toolNameOwners = /* @__PURE__ */ new Map();
|
|
1827
|
-
const channelIdOwners = /* @__PURE__ */ new Map();
|
|
1828
|
-
const providerIdOwners = /* @__PURE__ */ new Map();
|
|
1829
|
-
const resolvedToolNames = /* @__PURE__ */ new Set();
|
|
1830
1874
|
const reservedToolNames = new Set(options.reservedToolNames ?? []);
|
|
1831
1875
|
const reservedChannelIds = new Set(options.reservedChannelIds ?? []);
|
|
1832
1876
|
const reservedProviderIds = new Set(options.reservedProviderIds ?? []);
|
|
1833
|
-
|
|
1834
|
-
registry,
|
|
1877
|
+
const registerRuntime = createPluginRegisterRuntime({
|
|
1835
1878
|
config: options.config,
|
|
1836
|
-
logger,
|
|
1837
1879
|
workspaceDir,
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
providerIdOwners,
|
|
1841
|
-
resolvedToolNames,
|
|
1880
|
+
logger,
|
|
1881
|
+
registry,
|
|
1842
1882
|
reservedToolNames,
|
|
1843
1883
|
reservedChannelIds,
|
|
1844
1884
|
reservedProviderIds
|
|
1845
1885
|
});
|
|
1886
|
+
const pluginSdkAlias = resolvePluginSdkAlias();
|
|
1887
|
+
const jiti = createJiti(import.meta.url, {
|
|
1888
|
+
interopDefault: true,
|
|
1889
|
+
extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
|
|
1890
|
+
...pluginSdkAlias ? {
|
|
1891
|
+
alias: {
|
|
1892
|
+
"openclaw/plugin-sdk": pluginSdkAlias
|
|
1893
|
+
}
|
|
1894
|
+
} : {}
|
|
1895
|
+
});
|
|
1896
|
+
appendBundledChannelPlugins({
|
|
1897
|
+
registry,
|
|
1898
|
+
runtime: registerRuntime,
|
|
1899
|
+
jiti
|
|
1900
|
+
});
|
|
1846
1901
|
if (!loadExternalPlugins) {
|
|
1847
1902
|
return registry;
|
|
1848
1903
|
}
|
|
@@ -1859,17 +1914,9 @@ function loadOpenClawPlugins(options) {
|
|
|
1859
1914
|
});
|
|
1860
1915
|
registry.diagnostics.push(...manifestRegistry.diagnostics);
|
|
1861
1916
|
const manifestByRoot = new Map(manifestRegistry.plugins.map((entry) => [entry.rootDir, entry]));
|
|
1862
|
-
const seenIds =
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
interopDefault: true,
|
|
1866
|
-
extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
|
|
1867
|
-
...pluginSdkAlias ? {
|
|
1868
|
-
alias: {
|
|
1869
|
-
"openclaw/plugin-sdk": pluginSdkAlias
|
|
1870
|
-
}
|
|
1871
|
-
} : {}
|
|
1872
|
-
});
|
|
1917
|
+
const seenIds = new Map(
|
|
1918
|
+
registry.plugins.map((entry) => [entry.id, entry.origin])
|
|
1919
|
+
);
|
|
1873
1920
|
for (const candidate of discovery.candidates) {
|
|
1874
1921
|
const manifest = manifestByRoot.get(candidate.rootDir);
|
|
1875
1922
|
if (!manifest) {
|
|
@@ -2000,264 +2047,30 @@ function loadOpenClawPlugins(options) {
|
|
|
2000
2047
|
});
|
|
2001
2048
|
continue;
|
|
2002
2049
|
}
|
|
2003
|
-
const
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
level: "warn",
|
|
2008
|
-
pluginId,
|
|
2009
|
-
source: candidate.source,
|
|
2010
|
-
message: `${capability} is not supported by nextclaw compat layer yet`
|
|
2011
|
-
});
|
|
2012
|
-
pluginLogger.warn(`${capability} is ignored (not supported yet)`);
|
|
2013
|
-
};
|
|
2014
|
-
const api = {
|
|
2015
|
-
id: pluginId,
|
|
2016
|
-
name: record.name,
|
|
2017
|
-
version: record.version,
|
|
2018
|
-
description: record.description,
|
|
2050
|
+
const registerResult = registerPluginWithApi({
|
|
2051
|
+
runtime: registerRuntime,
|
|
2052
|
+
record,
|
|
2053
|
+
pluginId,
|
|
2019
2054
|
source: candidate.source,
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
const declaredNames = opts && Array.isArray(opts.names) ? opts.names : [];
|
|
2026
|
-
const names = [...declaredNames, ...opts && opts.name ? [opts.name] : []];
|
|
2027
|
-
if (typeof tool !== "function" && typeof tool.name === "string") {
|
|
2028
|
-
names.push(tool.name);
|
|
2029
|
-
}
|
|
2030
|
-
const uniqueNames = Array.from(new Set(names.map((name) => name.trim()).filter(Boolean)));
|
|
2031
|
-
const acceptedNames = ensureUniqueNames({
|
|
2032
|
-
names: uniqueNames,
|
|
2033
|
-
pluginId,
|
|
2034
|
-
diagnostics: registry.diagnostics,
|
|
2035
|
-
source: candidate.source,
|
|
2036
|
-
owners: toolNameOwners,
|
|
2037
|
-
reserved: reservedToolNames,
|
|
2038
|
-
kind: "tool"
|
|
2039
|
-
});
|
|
2040
|
-
if (acceptedNames.length === 0) {
|
|
2041
|
-
registry.diagnostics.push({
|
|
2042
|
-
level: "warn",
|
|
2043
|
-
pluginId,
|
|
2044
|
-
source: candidate.source,
|
|
2045
|
-
message: "tool registration skipped: no available tool names"
|
|
2046
|
-
});
|
|
2047
|
-
return;
|
|
2048
|
-
}
|
|
2049
|
-
const factory = typeof tool === "function" ? tool : (_ctx) => tool;
|
|
2050
|
-
registry.tools.push({
|
|
2051
|
-
pluginId,
|
|
2052
|
-
factory,
|
|
2053
|
-
names: acceptedNames,
|
|
2054
|
-
optional: opts?.optional === true,
|
|
2055
|
-
source: candidate.source
|
|
2056
|
-
});
|
|
2057
|
-
record.toolNames.push(...acceptedNames);
|
|
2058
|
-
try {
|
|
2059
|
-
const previewTools = normalizeToolList(
|
|
2060
|
-
factory({
|
|
2061
|
-
config: options.config,
|
|
2062
|
-
workspaceDir,
|
|
2063
|
-
sandboxed: false
|
|
2064
|
-
})
|
|
2065
|
-
);
|
|
2066
|
-
const byName = new Map(previewTools.map((entry2) => [entry2.name, entry2]));
|
|
2067
|
-
for (const name of acceptedNames) {
|
|
2068
|
-
const resolvedTool = byName.get(name);
|
|
2069
|
-
if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
|
|
2070
|
-
continue;
|
|
2071
|
-
}
|
|
2072
|
-
resolvedToolNames.add(resolvedTool.name);
|
|
2073
|
-
registry.resolvedTools.push(resolvedTool);
|
|
2074
|
-
}
|
|
2075
|
-
} catch (err) {
|
|
2076
|
-
registry.diagnostics.push({
|
|
2077
|
-
level: "warn",
|
|
2078
|
-
pluginId,
|
|
2079
|
-
source: candidate.source,
|
|
2080
|
-
message: `tool preview failed: ${String(err)}`
|
|
2081
|
-
});
|
|
2082
|
-
}
|
|
2083
|
-
},
|
|
2084
|
-
registerChannel: (registration) => {
|
|
2085
|
-
const normalizedChannel = registration && typeof registration === "object" && "plugin" in registration ? registration.plugin : registration;
|
|
2086
|
-
if (!normalizedChannel || typeof normalizedChannel !== "object") {
|
|
2087
|
-
registry.diagnostics.push({
|
|
2088
|
-
level: "error",
|
|
2089
|
-
pluginId,
|
|
2090
|
-
source: candidate.source,
|
|
2091
|
-
message: "channel registration missing plugin object"
|
|
2092
|
-
});
|
|
2093
|
-
return;
|
|
2094
|
-
}
|
|
2095
|
-
const channelObj = normalizedChannel;
|
|
2096
|
-
const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
|
|
2097
|
-
const accepted = ensureUniqueNames({
|
|
2098
|
-
names: [rawId],
|
|
2099
|
-
pluginId,
|
|
2100
|
-
diagnostics: registry.diagnostics,
|
|
2101
|
-
source: candidate.source,
|
|
2102
|
-
owners: channelIdOwners,
|
|
2103
|
-
reserved: reservedChannelIds,
|
|
2104
|
-
kind: "channel"
|
|
2105
|
-
});
|
|
2106
|
-
if (accepted.length === 0) {
|
|
2107
|
-
return;
|
|
2108
|
-
}
|
|
2109
|
-
const channelPlugin = normalizedChannel;
|
|
2110
|
-
registry.channels.push({
|
|
2111
|
-
pluginId,
|
|
2112
|
-
channel: channelPlugin,
|
|
2113
|
-
source: candidate.source
|
|
2114
|
-
});
|
|
2115
|
-
const channelId = accepted[0];
|
|
2116
|
-
record.channelIds.push(channelId);
|
|
2117
|
-
const configSchema = channelPlugin.configSchema;
|
|
2118
|
-
if (configSchema && typeof configSchema === "object") {
|
|
2119
|
-
const schema = configSchema.schema;
|
|
2120
|
-
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
2121
|
-
record.configJsonSchema = schema;
|
|
2122
|
-
record.configSchema = true;
|
|
2123
|
-
}
|
|
2124
|
-
const uiHints = configSchema.uiHints;
|
|
2125
|
-
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
2126
|
-
record.configUiHints = {
|
|
2127
|
-
...record.configUiHints ?? {},
|
|
2128
|
-
...uiHints
|
|
2129
|
-
};
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
2133
|
-
const previewTools = normalizeToolList(value);
|
|
2134
|
-
if (previewTools.length === 0) {
|
|
2135
|
-
return;
|
|
2136
|
-
}
|
|
2137
|
-
const declaredNames = previewTools.map((tool) => tool.name);
|
|
2138
|
-
const acceptedNames = ensureUniqueNames({
|
|
2139
|
-
names: declaredNames,
|
|
2140
|
-
pluginId,
|
|
2141
|
-
diagnostics: registry.diagnostics,
|
|
2142
|
-
source: candidate.source,
|
|
2143
|
-
owners: toolNameOwners,
|
|
2144
|
-
reserved: reservedToolNames,
|
|
2145
|
-
kind: "tool"
|
|
2146
|
-
});
|
|
2147
|
-
if (acceptedNames.length === 0) {
|
|
2148
|
-
return;
|
|
2149
|
-
}
|
|
2150
|
-
const factory = (ctx) => {
|
|
2151
|
-
const tools = normalizeToolList(resolveValue(ctx));
|
|
2152
|
-
if (tools.length === 0) {
|
|
2153
|
-
return [];
|
|
2154
|
-
}
|
|
2155
|
-
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
2156
|
-
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
2157
|
-
};
|
|
2158
|
-
registry.tools.push({
|
|
2159
|
-
pluginId,
|
|
2160
|
-
factory,
|
|
2161
|
-
names: acceptedNames,
|
|
2162
|
-
optional,
|
|
2163
|
-
source: candidate.source
|
|
2164
|
-
});
|
|
2165
|
-
record.toolNames.push(...acceptedNames);
|
|
2166
|
-
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
2167
|
-
for (const name of acceptedNames) {
|
|
2168
|
-
const resolvedTool = previewByName.get(name);
|
|
2169
|
-
if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
|
|
2170
|
-
continue;
|
|
2171
|
-
}
|
|
2172
|
-
resolvedToolNames.add(resolvedTool.name);
|
|
2173
|
-
registry.resolvedTools.push(resolvedTool);
|
|
2174
|
-
}
|
|
2175
|
-
registry.diagnostics.push({
|
|
2176
|
-
level: "warn",
|
|
2177
|
-
pluginId,
|
|
2178
|
-
source: candidate.source,
|
|
2179
|
-
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
2180
|
-
});
|
|
2181
|
-
};
|
|
2182
|
-
const agentTools = channelPlugin.agentTools;
|
|
2183
|
-
if (typeof agentTools === "function") {
|
|
2184
|
-
pushChannelTools(
|
|
2185
|
-
normalizeToolList(agentTools()),
|
|
2186
|
-
false,
|
|
2187
|
-
`channel "${channelId}"`,
|
|
2188
|
-
() => agentTools()
|
|
2189
|
-
);
|
|
2190
|
-
} else if (agentTools) {
|
|
2191
|
-
pushChannelTools(
|
|
2192
|
-
normalizeToolList(agentTools),
|
|
2193
|
-
false,
|
|
2194
|
-
`channel "${channelId}"`,
|
|
2195
|
-
() => agentTools
|
|
2196
|
-
);
|
|
2197
|
-
}
|
|
2198
|
-
},
|
|
2199
|
-
registerProvider: (provider) => {
|
|
2200
|
-
const accepted = ensureUniqueNames({
|
|
2201
|
-
names: [provider.id],
|
|
2202
|
-
pluginId,
|
|
2203
|
-
diagnostics: registry.diagnostics,
|
|
2204
|
-
source: candidate.source,
|
|
2205
|
-
owners: providerIdOwners,
|
|
2206
|
-
reserved: reservedProviderIds,
|
|
2207
|
-
kind: "provider"
|
|
2208
|
-
});
|
|
2209
|
-
if (accepted.length === 0) {
|
|
2210
|
-
return;
|
|
2211
|
-
}
|
|
2212
|
-
registry.providers.push({
|
|
2213
|
-
pluginId,
|
|
2214
|
-
provider,
|
|
2215
|
-
source: candidate.source
|
|
2216
|
-
});
|
|
2217
|
-
record.providerIds.push(accepted[0]);
|
|
2218
|
-
},
|
|
2219
|
-
registerHook: () => pushUnsupported("registerHook"),
|
|
2220
|
-
registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
|
|
2221
|
-
registerCli: () => pushUnsupported("registerCli"),
|
|
2222
|
-
registerService: () => pushUnsupported("registerService"),
|
|
2223
|
-
registerCommand: () => pushUnsupported("registerCommand"),
|
|
2224
|
-
registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
|
|
2225
|
-
registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
|
|
2226
|
-
resolvePath: (input) => {
|
|
2227
|
-
const trimmed = input.trim();
|
|
2228
|
-
if (!trimmed) {
|
|
2229
|
-
return candidate.rootDir;
|
|
2230
|
-
}
|
|
2231
|
-
if (path4.isAbsolute(trimmed)) {
|
|
2232
|
-
return path4.resolve(expandHome2(trimmed));
|
|
2233
|
-
}
|
|
2234
|
-
return path4.resolve(candidate.rootDir, trimmed);
|
|
2235
|
-
}
|
|
2236
|
-
};
|
|
2237
|
-
try {
|
|
2238
|
-
const result = register(api);
|
|
2239
|
-
if (result && typeof result === "object" && "then" in result) {
|
|
2240
|
-
registry.diagnostics.push({
|
|
2241
|
-
level: "warn",
|
|
2242
|
-
pluginId,
|
|
2243
|
-
source: candidate.source,
|
|
2244
|
-
message: "plugin register returned a promise; async registration is ignored"
|
|
2245
|
-
});
|
|
2246
|
-
}
|
|
2247
|
-
registry.plugins.push(record);
|
|
2248
|
-
seenIds.set(pluginId, candidate.origin);
|
|
2249
|
-
} catch (err) {
|
|
2055
|
+
rootDir: candidate.rootDir,
|
|
2056
|
+
register,
|
|
2057
|
+
pluginConfig: validatedConfig.value
|
|
2058
|
+
});
|
|
2059
|
+
if (!registerResult.ok) {
|
|
2250
2060
|
record.status = "error";
|
|
2251
|
-
record.error =
|
|
2252
|
-
registry.plugins.push(record);
|
|
2253
|
-
seenIds.set(pluginId, candidate.origin);
|
|
2061
|
+
record.error = registerResult.error;
|
|
2254
2062
|
registry.diagnostics.push({
|
|
2255
2063
|
level: "error",
|
|
2256
2064
|
pluginId,
|
|
2257
2065
|
source: candidate.source,
|
|
2258
|
-
message:
|
|
2066
|
+
message: registerResult.error
|
|
2259
2067
|
});
|
|
2068
|
+
registry.plugins.push(record);
|
|
2069
|
+
seenIds.set(pluginId, candidate.origin);
|
|
2070
|
+
continue;
|
|
2260
2071
|
}
|
|
2072
|
+
registry.plugins.push(record);
|
|
2073
|
+
seenIds.set(pluginId, candidate.origin);
|
|
2261
2074
|
}
|
|
2262
2075
|
return registry;
|
|
2263
2076
|
}
|
|
@@ -2282,7 +2095,7 @@ function buildPluginStatusReport(params) {
|
|
|
2282
2095
|
|
|
2283
2096
|
// src/plugins/uninstall.ts
|
|
2284
2097
|
import fs6 from "fs/promises";
|
|
2285
|
-
import
|
|
2098
|
+
import path6 from "path";
|
|
2286
2099
|
function isLinkedPathInstall(record) {
|
|
2287
2100
|
if (!record || record.source !== "path") {
|
|
2288
2101
|
return false;
|
|
@@ -2290,7 +2103,7 @@ function isLinkedPathInstall(record) {
|
|
|
2290
2103
|
if (!record.sourcePath || !record.installPath) {
|
|
2291
2104
|
return true;
|
|
2292
2105
|
}
|
|
2293
|
-
return
|
|
2106
|
+
return path6.resolve(record.sourcePath) === path6.resolve(record.installPath);
|
|
2294
2107
|
}
|
|
2295
2108
|
function resolveUninstallDirectoryTarget(params) {
|
|
2296
2109
|
if (!params.hasInstall) {
|
|
@@ -2309,7 +2122,7 @@ function resolveUninstallDirectoryTarget(params) {
|
|
|
2309
2122
|
if (!configuredPath) {
|
|
2310
2123
|
return defaultPath;
|
|
2311
2124
|
}
|
|
2312
|
-
if (
|
|
2125
|
+
if (path6.resolve(configuredPath) === path6.resolve(defaultPath)) {
|
|
2313
2126
|
return configuredPath;
|
|
2314
2127
|
}
|
|
2315
2128
|
return defaultPath;
|
|
@@ -2435,6 +2248,8 @@ export {
|
|
|
2435
2248
|
buildChannelConfigSchema,
|
|
2436
2249
|
buildOauthProviderAuthResult,
|
|
2437
2250
|
buildPluginStatusReport,
|
|
2251
|
+
createNextclawBuiltinChannelPlugin,
|
|
2252
|
+
createPluginRegisterRuntime,
|
|
2438
2253
|
createPluginRuntime,
|
|
2439
2254
|
disablePluginInConfig,
|
|
2440
2255
|
discoverOpenClawPlugins,
|
|
@@ -2456,6 +2271,7 @@ export {
|
|
|
2456
2271
|
normalizePluginHttpPath,
|
|
2457
2272
|
normalizePluginsConfig,
|
|
2458
2273
|
recordPluginInstall,
|
|
2274
|
+
registerPluginWithApi,
|
|
2459
2275
|
removePluginFromConfig,
|
|
2460
2276
|
resolveEnableState,
|
|
2461
2277
|
resolvePluginChannelMessageToolHints,
|