@nextclaw/openclaw-compat 0.1.5 → 0.1.7
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 +41 -2
- package/dist/index.js +595 -355
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Config } from '@nextclaw/core';
|
|
1
|
+
import { Config, ExtensionChannel } from '@nextclaw/core';
|
|
2
2
|
|
|
3
3
|
type PluginConfigUiHint = {
|
|
4
4
|
label?: string;
|
|
@@ -105,6 +105,7 @@ type OpenClawChannelPlugin = {
|
|
|
105
105
|
id: string;
|
|
106
106
|
meta?: Record<string, unknown>;
|
|
107
107
|
capabilities?: Record<string, unknown>;
|
|
108
|
+
nextclaw?: ExtensionChannel["nextclaw"];
|
|
108
109
|
configSchema?: OpenClawChannelConfigSchema;
|
|
109
110
|
config?: OpenClawChannelConfigAdapter;
|
|
110
111
|
setup?: OpenClawChannelSetup;
|
|
@@ -136,6 +137,7 @@ type OpenClawPluginDefinition = {
|
|
|
136
137
|
description?: string;
|
|
137
138
|
version?: string;
|
|
138
139
|
kind?: PluginKind;
|
|
140
|
+
configSchema?: Record<string, unknown>;
|
|
139
141
|
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
140
142
|
activate?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
141
143
|
};
|
|
@@ -518,6 +520,43 @@ declare function createPluginRuntime(params: {
|
|
|
518
520
|
config?: Config;
|
|
519
521
|
}): PluginRuntime;
|
|
520
522
|
|
|
523
|
+
type PluginRegisterRuntime = {
|
|
524
|
+
config: Config;
|
|
525
|
+
workspaceDir: string;
|
|
526
|
+
logger: PluginLogger;
|
|
527
|
+
registry: PluginRegistry;
|
|
528
|
+
toolNameOwners: Map<string, string>;
|
|
529
|
+
channelIdOwners: Map<string, string>;
|
|
530
|
+
providerIdOwners: Map<string, string>;
|
|
531
|
+
resolvedToolNames: Set<string>;
|
|
532
|
+
reservedToolNames: Set<string>;
|
|
533
|
+
reservedChannelIds: Set<string>;
|
|
534
|
+
reservedProviderIds: Set<string>;
|
|
535
|
+
};
|
|
536
|
+
declare function createPluginRegisterRuntime(params: {
|
|
537
|
+
config: Config;
|
|
538
|
+
workspaceDir: string;
|
|
539
|
+
logger: PluginLogger;
|
|
540
|
+
registry: PluginRegistry;
|
|
541
|
+
reservedToolNames: Set<string>;
|
|
542
|
+
reservedChannelIds: Set<string>;
|
|
543
|
+
reservedProviderIds: Set<string>;
|
|
544
|
+
}): PluginRegisterRuntime;
|
|
545
|
+
declare function registerPluginWithApi(params: {
|
|
546
|
+
runtime: PluginRegisterRuntime;
|
|
547
|
+
record: PluginRecord;
|
|
548
|
+
pluginId: string;
|
|
549
|
+
source: string;
|
|
550
|
+
rootDir: string;
|
|
551
|
+
register: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
552
|
+
pluginConfig?: Record<string, unknown>;
|
|
553
|
+
}): {
|
|
554
|
+
ok: true;
|
|
555
|
+
} | {
|
|
556
|
+
ok: false;
|
|
557
|
+
error: string;
|
|
558
|
+
};
|
|
559
|
+
|
|
521
560
|
declare function validateJsonSchemaValue(params: {
|
|
522
561
|
schema: Record<string, unknown>;
|
|
523
562
|
cacheKey: string;
|
|
@@ -576,4 +615,4 @@ declare function uninstallPlugin(params: {
|
|
|
576
615
|
extensionsDir?: string;
|
|
577
616
|
}): Promise<UninstallPluginResult>;
|
|
578
617
|
|
|
579
|
-
export { DEFAULT_ACCOUNT_ID, type InstallPluginResult, type NormalizedPluginsConfig, type OpenClawChannelAgentPrompt, type OpenClawChannelConfigAdapter, type OpenClawChannelConfigSchema, type OpenClawChannelGateway, type OpenClawChannelGatewayStartContext, type OpenClawChannelPlugin, type OpenClawChannelSetup, type OpenClawPluginApi, type OpenClawPluginChannelRegistration, type OpenClawPluginConfigSchema, type OpenClawPluginDefinition, type OpenClawPluginModule, type OpenClawPluginTool, type OpenClawPluginToolContext, type OpenClawPluginToolFactory, type OpenClawPluginToolOptions, type OpenClawProviderPlugin, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PackageManifest, type PluginCandidate, type PluginChannelBinding, type PluginChannelGatewayHandle, type PluginChannelRegistration, type PluginConfigUiHint, type PluginDiagnostic, type PluginDiscoveryResult, type PluginInstallLogger, type PluginInstallSource, type PluginInstallUpdate, type PluginKind, type PluginLoadOptions, type PluginLogger, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRecord, type PluginManifestRegistry, type PluginOrigin, type PluginProviderRegistration, type PluginRecord, type PluginRegistry, type PluginReplyDispatchParams, type PluginRuntime, type PluginRuntimeBridge, type PluginStatusReport, type PluginToolRegistration, type PluginUiMetadata, type UninstallActions, type UninstallPluginResult, type _CompatOnly, __nextclawPluginSdkCompat, addPluginLoadPath, buildChannelConfigSchema, buildOauthProviderAuthResult, buildPluginStatusReport, createPluginRuntime, disablePluginInConfig, discoverOpenClawPlugins, emptyPluginConfigSchema, enablePluginInConfig, getPackageManifestMetadata, getPluginChannelBindings, getPluginUiMetadataFromRegistry, installPluginFromArchive, installPluginFromDir, installPluginFromFile, installPluginFromNpmSpec, installPluginFromPath, loadOpenClawPlugins, loadPluginManifest, loadPluginManifestRegistry, loadPluginUiMetadata, normalizeAccountId, normalizePluginHttpPath, normalizePluginsConfig, recordPluginInstall, removePluginFromConfig, resolveEnableState, resolvePluginChannelMessageToolHints, resolvePluginInstallDir, resolvePluginManifestPath, resolveUninstallDirectoryTarget, setPluginRuntimeBridge, sleep, startPluginChannelGateways, stopPluginChannelGateways, toPluginUiMetadata, uninstallPlugin, validateJsonSchemaValue };
|
|
618
|
+
export { DEFAULT_ACCOUNT_ID, type InstallPluginResult, type NormalizedPluginsConfig, type OpenClawChannelAgentPrompt, type OpenClawChannelConfigAdapter, type OpenClawChannelConfigSchema, type OpenClawChannelGateway, type OpenClawChannelGatewayStartContext, type OpenClawChannelPlugin, type OpenClawChannelSetup, type OpenClawPluginApi, type OpenClawPluginChannelRegistration, type OpenClawPluginConfigSchema, type OpenClawPluginDefinition, type OpenClawPluginModule, type OpenClawPluginTool, type OpenClawPluginToolContext, type OpenClawPluginToolFactory, type OpenClawPluginToolOptions, type OpenClawProviderPlugin, PLUGIN_MANIFEST_FILENAME, PLUGIN_MANIFEST_FILENAMES, type PackageManifest, type PluginCandidate, type PluginChannelBinding, type PluginChannelGatewayHandle, type PluginChannelRegistration, type PluginConfigUiHint, type PluginDiagnostic, type PluginDiscoveryResult, type PluginInstallLogger, type PluginInstallSource, type PluginInstallUpdate, type PluginKind, type PluginLoadOptions, type PluginLogger, type PluginManifest, type PluginManifestLoadResult, type PluginManifestRecord, type PluginManifestRegistry, type PluginOrigin, type PluginProviderRegistration, type PluginRecord, type PluginRegisterRuntime, type PluginRegistry, type PluginReplyDispatchParams, type PluginRuntime, type PluginRuntimeBridge, type PluginStatusReport, type PluginToolRegistration, type PluginUiMetadata, type UninstallActions, type UninstallPluginResult, type _CompatOnly, __nextclawPluginSdkCompat, addPluginLoadPath, buildChannelConfigSchema, buildOauthProviderAuthResult, buildPluginStatusReport, createPluginRegisterRuntime, createPluginRuntime, disablePluginInConfig, discoverOpenClawPlugins, emptyPluginConfigSchema, enablePluginInConfig, getPackageManifestMetadata, getPluginChannelBindings, getPluginUiMetadataFromRegistry, installPluginFromArchive, installPluginFromDir, installPluginFromFile, installPluginFromNpmSpec, installPluginFromPath, loadOpenClawPlugins, loadPluginManifest, loadPluginManifestRegistry, loadPluginUiMetadata, normalizeAccountId, normalizePluginHttpPath, normalizePluginsConfig, recordPluginInstall, registerPluginWithApi, removePluginFromConfig, resolveEnableState, resolvePluginChannelMessageToolHints, resolvePluginInstallDir, resolvePluginManifestPath, resolveUninstallDirectoryTarget, setPluginRuntimeBridge, sleep, startPluginChannelGateways, stopPluginChannelGateways, toPluginUiMetadata, uninstallPlugin, validateJsonSchemaValue };
|
package/dist/index.js
CHANGED
|
@@ -224,10 +224,10 @@ function resolvePluginChannelMessageToolHints(params) {
|
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
function getPluginUiMetadataFromRegistry(registry) {
|
|
227
|
-
return registry.plugins.map((
|
|
228
|
-
id:
|
|
229
|
-
configSchema:
|
|
230
|
-
configUiHints:
|
|
227
|
+
return registry.plugins.map((plugin10) => ({
|
|
228
|
+
id: plugin10.id,
|
|
229
|
+
configSchema: plugin10.configJsonSchema,
|
|
230
|
+
configUiHints: plugin10.configUiHints
|
|
231
231
|
}));
|
|
232
232
|
}
|
|
233
233
|
async function startPluginChannelGateways(params) {
|
|
@@ -1057,11 +1057,10 @@ async function installPluginFromPath(params) {
|
|
|
1057
1057
|
|
|
1058
1058
|
// src/plugins/loader.ts
|
|
1059
1059
|
import fs5 from "fs";
|
|
1060
|
-
import
|
|
1060
|
+
import path5 from "path";
|
|
1061
1061
|
import { fileURLToPath } from "url";
|
|
1062
1062
|
import createJitiImport from "jiti";
|
|
1063
1063
|
import { getWorkspacePathFromConfig } from "@nextclaw/core";
|
|
1064
|
-
import { expandHome as expandHome2 } from "@nextclaw/core";
|
|
1065
1064
|
|
|
1066
1065
|
// src/plugins/manifest-registry.ts
|
|
1067
1066
|
import fs4 from "fs";
|
|
@@ -1208,6 +1207,169 @@ function loadPluginUiMetadata(params) {
|
|
|
1208
1207
|
return toPluginUiMetadata(registry.plugins);
|
|
1209
1208
|
}
|
|
1210
1209
|
|
|
1210
|
+
// src/plugins/schema-validator.ts
|
|
1211
|
+
import AjvPkg from "ajv";
|
|
1212
|
+
var AjvCtor = AjvPkg;
|
|
1213
|
+
var ajv = new AjvCtor({
|
|
1214
|
+
allErrors: true,
|
|
1215
|
+
strict: false,
|
|
1216
|
+
removeAdditional: false
|
|
1217
|
+
});
|
|
1218
|
+
var schemaCache = /* @__PURE__ */ new Map();
|
|
1219
|
+
function formatAjvErrors(errors) {
|
|
1220
|
+
if (!errors || errors.length === 0) {
|
|
1221
|
+
return ["invalid config"];
|
|
1222
|
+
}
|
|
1223
|
+
return errors.map((error) => {
|
|
1224
|
+
const path7 = error.instancePath?.replace(/^\//, "").replace(/\//g, ".") || "<root>";
|
|
1225
|
+
const message = error.message ?? "invalid";
|
|
1226
|
+
return `${path7}: ${message}`;
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
function validateJsonSchemaValue(params) {
|
|
1230
|
+
let cached = schemaCache.get(params.cacheKey);
|
|
1231
|
+
if (!cached || cached.schema !== params.schema) {
|
|
1232
|
+
const validate = ajv.compile(params.schema);
|
|
1233
|
+
cached = { validate, schema: params.schema };
|
|
1234
|
+
schemaCache.set(params.cacheKey, cached);
|
|
1235
|
+
}
|
|
1236
|
+
const ok = cached.validate(params.value);
|
|
1237
|
+
if (ok) {
|
|
1238
|
+
return { ok: true };
|
|
1239
|
+
}
|
|
1240
|
+
return { ok: false, errors: formatAjvErrors(cached.validate.errors) };
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// src/plugins/bundled/channels/factory.ts
|
|
1244
|
+
import { listBuiltinChannelPlugins } from "@nextclaw/core";
|
|
1245
|
+
var EMPTY_PLUGIN_CONFIG_SCHEMA = {
|
|
1246
|
+
type: "object",
|
|
1247
|
+
additionalProperties: false,
|
|
1248
|
+
properties: {}
|
|
1249
|
+
};
|
|
1250
|
+
function resolveBuiltinChannelPlugin(channelId) {
|
|
1251
|
+
const plugin10 = listBuiltinChannelPlugins().find((entry) => entry.id === channelId);
|
|
1252
|
+
if (!plugin10) {
|
|
1253
|
+
throw new Error(`builtin channel plugin not found: ${channelId}`);
|
|
1254
|
+
}
|
|
1255
|
+
return plugin10;
|
|
1256
|
+
}
|
|
1257
|
+
function createBundledChannelPlugin(params) {
|
|
1258
|
+
const pluginId = `builtin-channel-${params.channelId}`;
|
|
1259
|
+
const sourceDescription = params.description ?? `Builtin NextClaw channel plugin for ${params.channelId}`;
|
|
1260
|
+
return {
|
|
1261
|
+
id: pluginId,
|
|
1262
|
+
name: params.name,
|
|
1263
|
+
description: sourceDescription,
|
|
1264
|
+
configSchema: EMPTY_PLUGIN_CONFIG_SCHEMA,
|
|
1265
|
+
register(api) {
|
|
1266
|
+
const builtin = resolveBuiltinChannelPlugin(params.channelId);
|
|
1267
|
+
api.registerChannel({
|
|
1268
|
+
plugin: {
|
|
1269
|
+
id: params.channelId,
|
|
1270
|
+
nextclaw: {
|
|
1271
|
+
isEnabled: builtin.isEnabled,
|
|
1272
|
+
createChannel: builtin.create
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/plugins/bundled/channels/telegram.ts
|
|
1281
|
+
var plugin = createBundledChannelPlugin({
|
|
1282
|
+
channelId: "telegram",
|
|
1283
|
+
name: "Builtin Telegram Channel",
|
|
1284
|
+
description: "Builtin NextClaw channel plugin for telegram"
|
|
1285
|
+
});
|
|
1286
|
+
var telegram_default = plugin;
|
|
1287
|
+
|
|
1288
|
+
// src/plugins/bundled/channels/whatsapp.ts
|
|
1289
|
+
var plugin2 = createBundledChannelPlugin({
|
|
1290
|
+
channelId: "whatsapp",
|
|
1291
|
+
name: "Builtin WhatsApp Channel",
|
|
1292
|
+
description: "Builtin NextClaw channel plugin for whatsapp"
|
|
1293
|
+
});
|
|
1294
|
+
var whatsapp_default = plugin2;
|
|
1295
|
+
|
|
1296
|
+
// src/plugins/bundled/channels/discord.ts
|
|
1297
|
+
var plugin3 = createBundledChannelPlugin({
|
|
1298
|
+
channelId: "discord",
|
|
1299
|
+
name: "Builtin Discord Channel",
|
|
1300
|
+
description: "Builtin NextClaw channel plugin for discord"
|
|
1301
|
+
});
|
|
1302
|
+
var discord_default = plugin3;
|
|
1303
|
+
|
|
1304
|
+
// src/plugins/bundled/channels/feishu.ts
|
|
1305
|
+
var plugin4 = createBundledChannelPlugin({
|
|
1306
|
+
channelId: "feishu",
|
|
1307
|
+
name: "Builtin Feishu Channel",
|
|
1308
|
+
description: "Builtin NextClaw channel plugin for feishu"
|
|
1309
|
+
});
|
|
1310
|
+
var feishu_default = plugin4;
|
|
1311
|
+
|
|
1312
|
+
// src/plugins/bundled/channels/mochat.ts
|
|
1313
|
+
var plugin5 = createBundledChannelPlugin({
|
|
1314
|
+
channelId: "mochat",
|
|
1315
|
+
name: "Builtin Mochat Channel",
|
|
1316
|
+
description: "Builtin NextClaw channel plugin for mochat"
|
|
1317
|
+
});
|
|
1318
|
+
var mochat_default = plugin5;
|
|
1319
|
+
|
|
1320
|
+
// src/plugins/bundled/channels/dingtalk.ts
|
|
1321
|
+
var plugin6 = createBundledChannelPlugin({
|
|
1322
|
+
channelId: "dingtalk",
|
|
1323
|
+
name: "Builtin DingTalk Channel",
|
|
1324
|
+
description: "Builtin NextClaw channel plugin for dingtalk"
|
|
1325
|
+
});
|
|
1326
|
+
var dingtalk_default = plugin6;
|
|
1327
|
+
|
|
1328
|
+
// src/plugins/bundled/channels/email.ts
|
|
1329
|
+
var plugin7 = createBundledChannelPlugin({
|
|
1330
|
+
channelId: "email",
|
|
1331
|
+
name: "Builtin Email Channel",
|
|
1332
|
+
description: "Builtin NextClaw channel plugin for email"
|
|
1333
|
+
});
|
|
1334
|
+
var email_default = plugin7;
|
|
1335
|
+
|
|
1336
|
+
// src/plugins/bundled/channels/slack.ts
|
|
1337
|
+
var plugin8 = createBundledChannelPlugin({
|
|
1338
|
+
channelId: "slack",
|
|
1339
|
+
name: "Builtin Slack Channel",
|
|
1340
|
+
description: "Builtin NextClaw channel plugin for slack"
|
|
1341
|
+
});
|
|
1342
|
+
var slack_default = plugin8;
|
|
1343
|
+
|
|
1344
|
+
// src/plugins/bundled/channels/qq.ts
|
|
1345
|
+
var plugin9 = createBundledChannelPlugin({
|
|
1346
|
+
channelId: "qq",
|
|
1347
|
+
name: "Builtin QQ Channel",
|
|
1348
|
+
description: "Builtin NextClaw channel plugin for qq"
|
|
1349
|
+
});
|
|
1350
|
+
var qq_default = plugin9;
|
|
1351
|
+
|
|
1352
|
+
// src/plugins/bundled/channels/index.ts
|
|
1353
|
+
var BUNDLED_CHANNEL_PLUGINS = [
|
|
1354
|
+
telegram_default,
|
|
1355
|
+
whatsapp_default,
|
|
1356
|
+
discord_default,
|
|
1357
|
+
feishu_default,
|
|
1358
|
+
mochat_default,
|
|
1359
|
+
dingtalk_default,
|
|
1360
|
+
email_default,
|
|
1361
|
+
slack_default,
|
|
1362
|
+
qq_default
|
|
1363
|
+
];
|
|
1364
|
+
function listBundledChannelPluginDefinitions() {
|
|
1365
|
+
return [...BUNDLED_CHANNEL_PLUGINS];
|
|
1366
|
+
}
|
|
1367
|
+
var BUNDLED_CHANNEL_PLUGIN_IDS = BUNDLED_CHANNEL_PLUGINS.map((plugin10) => plugin10.id).filter((id) => typeof id === "string" && id.trim().length > 0);
|
|
1368
|
+
|
|
1369
|
+
// src/plugins/registry.ts
|
|
1370
|
+
import path4 from "path";
|
|
1371
|
+
import { expandHome as expandHome2 } from "@nextclaw/core";
|
|
1372
|
+
|
|
1211
1373
|
// src/plugins/runtime.ts
|
|
1212
1374
|
import { getPackageVersion } from "@nextclaw/core";
|
|
1213
1375
|
import { MemoryGetTool, MemorySearchTool } from "@nextclaw/core";
|
|
@@ -1260,37 +1422,337 @@ function createPluginRuntime(params) {
|
|
|
1260
1422
|
};
|
|
1261
1423
|
}
|
|
1262
1424
|
|
|
1263
|
-
// src/plugins/
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1425
|
+
// src/plugins/registry.ts
|
|
1426
|
+
function buildPluginLogger(base, pluginId) {
|
|
1427
|
+
const withPrefix = (message) => `[plugins:${pluginId}] ${message}`;
|
|
1428
|
+
return {
|
|
1429
|
+
info: (message) => base.info(withPrefix(message)),
|
|
1430
|
+
warn: (message) => base.warn(withPrefix(message)),
|
|
1431
|
+
error: (message) => base.error(withPrefix(message)),
|
|
1432
|
+
debug: base.debug ? (message) => base.debug?.(withPrefix(message)) : void 0
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
function ensureUniqueNames(params) {
|
|
1436
|
+
const accepted = [];
|
|
1437
|
+
for (const rawName of params.names) {
|
|
1438
|
+
const name = rawName.trim();
|
|
1439
|
+
if (!name) {
|
|
1440
|
+
continue;
|
|
1441
|
+
}
|
|
1442
|
+
if (params.reserved.has(name)) {
|
|
1443
|
+
params.diagnostics.push({
|
|
1444
|
+
level: "error",
|
|
1445
|
+
pluginId: params.pluginId,
|
|
1446
|
+
source: params.source,
|
|
1447
|
+
message: `${params.kind} already registered by core: ${name}`
|
|
1448
|
+
});
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
const owner = params.owners.get(name);
|
|
1452
|
+
if (owner && owner !== params.pluginId) {
|
|
1453
|
+
params.diagnostics.push({
|
|
1454
|
+
level: "error",
|
|
1455
|
+
pluginId: params.pluginId,
|
|
1456
|
+
source: params.source,
|
|
1457
|
+
message: `${params.kind} already registered: ${name} (${owner})`
|
|
1458
|
+
});
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
params.owners.set(name, params.pluginId);
|
|
1462
|
+
accepted.push(name);
|
|
1275
1463
|
}
|
|
1276
|
-
return
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1464
|
+
return accepted;
|
|
1465
|
+
}
|
|
1466
|
+
function normalizeToolList(value) {
|
|
1467
|
+
if (!value) {
|
|
1468
|
+
return [];
|
|
1469
|
+
}
|
|
1470
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1471
|
+
return list.filter((entry) => {
|
|
1472
|
+
if (!entry || typeof entry !== "object") {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
const candidate = entry;
|
|
1476
|
+
return typeof candidate.name === "string" && candidate.name.trim().length > 0 && candidate.parameters !== void 0 && typeof candidate.execute === "function";
|
|
1280
1477
|
});
|
|
1281
1478
|
}
|
|
1282
|
-
function
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1479
|
+
function createPluginRegisterRuntime(params) {
|
|
1480
|
+
return {
|
|
1481
|
+
config: params.config,
|
|
1482
|
+
workspaceDir: params.workspaceDir,
|
|
1483
|
+
logger: params.logger,
|
|
1484
|
+
registry: params.registry,
|
|
1485
|
+
toolNameOwners: /* @__PURE__ */ new Map(),
|
|
1486
|
+
channelIdOwners: /* @__PURE__ */ new Map(),
|
|
1487
|
+
providerIdOwners: /* @__PURE__ */ new Map(),
|
|
1488
|
+
resolvedToolNames: /* @__PURE__ */ new Set(),
|
|
1489
|
+
reservedToolNames: params.reservedToolNames,
|
|
1490
|
+
reservedChannelIds: params.reservedChannelIds,
|
|
1491
|
+
reservedProviderIds: params.reservedProviderIds
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function registerPluginTool(params) {
|
|
1495
|
+
const toolInput = params.tool;
|
|
1496
|
+
const normalizedNames = [];
|
|
1497
|
+
if (Array.isArray(params.opts?.names)) {
|
|
1498
|
+
for (const name of params.opts?.names ?? []) {
|
|
1499
|
+
const trimmed = String(name).trim();
|
|
1500
|
+
if (trimmed) {
|
|
1501
|
+
normalizedNames.push(trimmed);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
} else if (params.opts?.name && String(params.opts.name).trim()) {
|
|
1505
|
+
normalizedNames.push(String(params.opts.name).trim());
|
|
1288
1506
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1507
|
+
if (typeof toolInput !== "function") {
|
|
1508
|
+
const intrinsic = toolInput.name.trim();
|
|
1509
|
+
if (intrinsic) {
|
|
1510
|
+
normalizedNames.push(intrinsic);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
const acceptedNames = ensureUniqueNames({
|
|
1514
|
+
names: normalizedNames,
|
|
1515
|
+
pluginId: params.pluginId,
|
|
1516
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1517
|
+
source: params.source,
|
|
1518
|
+
owners: params.runtime.toolNameOwners,
|
|
1519
|
+
reserved: params.runtime.reservedToolNames,
|
|
1520
|
+
kind: "tool"
|
|
1521
|
+
});
|
|
1522
|
+
if (acceptedNames.length === 0) {
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
const factory = typeof toolInput === "function" ? toolInput : () => toolInput;
|
|
1526
|
+
const registration = {
|
|
1527
|
+
pluginId: params.pluginId,
|
|
1528
|
+
factory,
|
|
1529
|
+
names: acceptedNames,
|
|
1530
|
+
optional: params.opts?.optional === true,
|
|
1531
|
+
source: params.source
|
|
1532
|
+
};
|
|
1533
|
+
params.runtime.registry.tools.push(registration);
|
|
1534
|
+
params.record.toolNames.push(...acceptedNames);
|
|
1535
|
+
if (typeof toolInput === "function") {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (!params.runtime.resolvedToolNames.has(toolInput.name)) {
|
|
1539
|
+
params.runtime.resolvedToolNames.add(toolInput.name);
|
|
1540
|
+
params.runtime.registry.resolvedTools.push(toolInput);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
function registerPluginChannel(params) {
|
|
1544
|
+
const normalizedChannel = params.registration && typeof params.registration === "object" && "plugin" in params.registration ? params.registration.plugin : params.registration;
|
|
1545
|
+
if (!normalizedChannel || typeof normalizedChannel !== "object") {
|
|
1546
|
+
params.runtime.registry.diagnostics.push({
|
|
1547
|
+
level: "error",
|
|
1548
|
+
pluginId: params.pluginId,
|
|
1549
|
+
source: params.source,
|
|
1550
|
+
message: "channel registration missing plugin object"
|
|
1551
|
+
});
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
const channelObj = normalizedChannel;
|
|
1555
|
+
const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
|
|
1556
|
+
const accepted = ensureUniqueNames({
|
|
1557
|
+
names: [rawId],
|
|
1558
|
+
pluginId: params.pluginId,
|
|
1559
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1560
|
+
source: params.source,
|
|
1561
|
+
owners: params.runtime.channelIdOwners,
|
|
1562
|
+
reserved: params.runtime.reservedChannelIds,
|
|
1563
|
+
kind: "channel"
|
|
1564
|
+
});
|
|
1565
|
+
if (accepted.length === 0) {
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
const channelPlugin = normalizedChannel;
|
|
1569
|
+
params.runtime.registry.channels.push({
|
|
1570
|
+
pluginId: params.pluginId,
|
|
1571
|
+
channel: channelPlugin,
|
|
1572
|
+
source: params.source
|
|
1573
|
+
});
|
|
1574
|
+
const channelId = accepted[0];
|
|
1575
|
+
params.record.channelIds.push(channelId);
|
|
1576
|
+
const configSchema = channelPlugin.configSchema;
|
|
1577
|
+
if (configSchema && typeof configSchema === "object") {
|
|
1578
|
+
const schema = configSchema.schema;
|
|
1579
|
+
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1580
|
+
params.record.configJsonSchema = schema;
|
|
1581
|
+
params.record.configSchema = true;
|
|
1582
|
+
}
|
|
1583
|
+
const uiHints = configSchema.uiHints;
|
|
1584
|
+
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
1585
|
+
params.record.configUiHints = {
|
|
1586
|
+
...params.record.configUiHints ?? {},
|
|
1587
|
+
...uiHints
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
1592
|
+
const previewTools = normalizeToolList(value);
|
|
1593
|
+
if (previewTools.length === 0) {
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
const declaredNames = previewTools.map((tool) => tool.name);
|
|
1597
|
+
const acceptedNames = ensureUniqueNames({
|
|
1598
|
+
names: declaredNames,
|
|
1599
|
+
pluginId: params.pluginId,
|
|
1600
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1601
|
+
source: params.source,
|
|
1602
|
+
owners: params.runtime.toolNameOwners,
|
|
1603
|
+
reserved: params.runtime.reservedToolNames,
|
|
1604
|
+
kind: "tool"
|
|
1605
|
+
});
|
|
1606
|
+
if (acceptedNames.length === 0) {
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
const factory = (ctx) => {
|
|
1610
|
+
const tools = normalizeToolList(resolveValue(ctx));
|
|
1611
|
+
if (tools.length === 0) {
|
|
1612
|
+
return [];
|
|
1613
|
+
}
|
|
1614
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
1615
|
+
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
1616
|
+
};
|
|
1617
|
+
params.runtime.registry.tools.push({
|
|
1618
|
+
pluginId: params.pluginId,
|
|
1619
|
+
factory,
|
|
1620
|
+
names: acceptedNames,
|
|
1621
|
+
optional,
|
|
1622
|
+
source: params.source
|
|
1623
|
+
});
|
|
1624
|
+
params.record.toolNames.push(...acceptedNames);
|
|
1625
|
+
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
1626
|
+
for (const name of acceptedNames) {
|
|
1627
|
+
const resolvedTool = previewByName.get(name);
|
|
1628
|
+
if (!resolvedTool || params.runtime.resolvedToolNames.has(resolvedTool.name)) {
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
params.runtime.resolvedToolNames.add(resolvedTool.name);
|
|
1632
|
+
params.runtime.registry.resolvedTools.push(resolvedTool);
|
|
1633
|
+
}
|
|
1634
|
+
params.runtime.registry.diagnostics.push({
|
|
1635
|
+
level: "warn",
|
|
1636
|
+
pluginId: params.pluginId,
|
|
1637
|
+
source: params.source,
|
|
1638
|
+
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
1639
|
+
});
|
|
1640
|
+
};
|
|
1641
|
+
const agentTools = channelPlugin.agentTools;
|
|
1642
|
+
if (typeof agentTools === "function") {
|
|
1643
|
+
pushChannelTools(
|
|
1644
|
+
normalizeToolList(agentTools()),
|
|
1645
|
+
false,
|
|
1646
|
+
`channel "${channelId}"`,
|
|
1647
|
+
() => agentTools()
|
|
1648
|
+
);
|
|
1649
|
+
} else if (agentTools) {
|
|
1650
|
+
pushChannelTools(normalizeToolList(agentTools), false, `channel "${channelId}"`, () => agentTools);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
function registerPluginProvider(params) {
|
|
1654
|
+
const accepted = ensureUniqueNames({
|
|
1655
|
+
names: [params.provider.id],
|
|
1656
|
+
pluginId: params.pluginId,
|
|
1657
|
+
diagnostics: params.runtime.registry.diagnostics,
|
|
1658
|
+
source: params.source,
|
|
1659
|
+
owners: params.runtime.providerIdOwners,
|
|
1660
|
+
reserved: params.runtime.reservedProviderIds,
|
|
1661
|
+
kind: "provider"
|
|
1662
|
+
});
|
|
1663
|
+
if (accepted.length === 0) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
params.runtime.registry.providers.push({
|
|
1667
|
+
pluginId: params.pluginId,
|
|
1668
|
+
provider: params.provider,
|
|
1669
|
+
source: params.source
|
|
1670
|
+
});
|
|
1671
|
+
params.record.providerIds.push(accepted[0]);
|
|
1672
|
+
}
|
|
1673
|
+
function registerPluginWithApi(params) {
|
|
1674
|
+
const pluginRuntime = createPluginRuntime({ workspace: params.runtime.workspaceDir, config: params.runtime.config });
|
|
1675
|
+
const pluginLogger = buildPluginLogger(params.runtime.logger, params.pluginId);
|
|
1676
|
+
const pushUnsupported = (capability) => {
|
|
1677
|
+
params.runtime.registry.diagnostics.push({
|
|
1678
|
+
level: "warn",
|
|
1679
|
+
pluginId: params.pluginId,
|
|
1680
|
+
source: params.source,
|
|
1681
|
+
message: `${capability} is not supported by nextclaw compat layer yet`
|
|
1682
|
+
});
|
|
1683
|
+
pluginLogger.warn(`${capability} is ignored (not supported yet)`);
|
|
1684
|
+
};
|
|
1685
|
+
const api = {
|
|
1686
|
+
id: params.pluginId,
|
|
1687
|
+
name: params.record.name,
|
|
1688
|
+
version: params.record.version,
|
|
1689
|
+
description: params.record.description,
|
|
1690
|
+
source: params.source,
|
|
1691
|
+
config: params.runtime.config,
|
|
1692
|
+
pluginConfig: params.pluginConfig,
|
|
1693
|
+
runtime: pluginRuntime,
|
|
1694
|
+
logger: pluginLogger,
|
|
1695
|
+
registerTool: (tool, opts) => {
|
|
1696
|
+
registerPluginTool({
|
|
1697
|
+
runtime: params.runtime,
|
|
1698
|
+
record: params.record,
|
|
1699
|
+
pluginId: params.pluginId,
|
|
1700
|
+
source: params.source,
|
|
1701
|
+
tool,
|
|
1702
|
+
opts
|
|
1703
|
+
});
|
|
1704
|
+
},
|
|
1705
|
+
registerChannel: (registration) => {
|
|
1706
|
+
registerPluginChannel({
|
|
1707
|
+
runtime: params.runtime,
|
|
1708
|
+
record: params.record,
|
|
1709
|
+
pluginId: params.pluginId,
|
|
1710
|
+
source: params.source,
|
|
1711
|
+
registration
|
|
1712
|
+
});
|
|
1713
|
+
},
|
|
1714
|
+
registerProvider: (provider) => {
|
|
1715
|
+
registerPluginProvider({
|
|
1716
|
+
runtime: params.runtime,
|
|
1717
|
+
record: params.record,
|
|
1718
|
+
pluginId: params.pluginId,
|
|
1719
|
+
source: params.source,
|
|
1720
|
+
provider
|
|
1721
|
+
});
|
|
1722
|
+
},
|
|
1723
|
+
registerHook: () => pushUnsupported("registerHook"),
|
|
1724
|
+
registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
|
|
1725
|
+
registerCli: () => pushUnsupported("registerCli"),
|
|
1726
|
+
registerService: () => pushUnsupported("registerService"),
|
|
1727
|
+
registerCommand: () => pushUnsupported("registerCommand"),
|
|
1728
|
+
registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
|
|
1729
|
+
registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
|
|
1730
|
+
resolvePath: (input) => {
|
|
1731
|
+
const trimmed = input.trim();
|
|
1732
|
+
if (!trimmed) {
|
|
1733
|
+
return params.rootDir;
|
|
1734
|
+
}
|
|
1735
|
+
if (path4.isAbsolute(trimmed)) {
|
|
1736
|
+
return path4.resolve(expandHome2(trimmed));
|
|
1737
|
+
}
|
|
1738
|
+
return path4.resolve(params.rootDir, trimmed);
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
try {
|
|
1742
|
+
const result = params.register(api);
|
|
1743
|
+
if (result && typeof result === "object" && "then" in result) {
|
|
1744
|
+
params.runtime.registry.diagnostics.push({
|
|
1745
|
+
level: "warn",
|
|
1746
|
+
pluginId: params.pluginId,
|
|
1747
|
+
source: params.source,
|
|
1748
|
+
message: "plugin register returned a promise; async registration is ignored"
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1291
1751
|
return { ok: true };
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
const error = `plugin failed during register: ${String(err)}`;
|
|
1754
|
+
return { ok: false, error };
|
|
1292
1755
|
}
|
|
1293
|
-
return { ok: false, errors: formatAjvErrors(cached.validate.errors) };
|
|
1294
1756
|
}
|
|
1295
1757
|
|
|
1296
1758
|
// src/plugins/loader.ts
|
|
@@ -1305,17 +1767,17 @@ function resolvePluginSdkAliasFile(params) {
|
|
|
1305
1767
|
try {
|
|
1306
1768
|
const modulePath = fileURLToPath(import.meta.url);
|
|
1307
1769
|
const isProduction = process.env.NODE_ENV === "production";
|
|
1308
|
-
let cursor =
|
|
1770
|
+
let cursor = path5.dirname(modulePath);
|
|
1309
1771
|
for (let i = 0; i < 6; i += 1) {
|
|
1310
|
-
const srcCandidate =
|
|
1311
|
-
const distCandidate =
|
|
1772
|
+
const srcCandidate = path5.join(cursor, "src", "plugin-sdk", params.srcFile);
|
|
1773
|
+
const distCandidate = path5.join(cursor, "dist", "plugin-sdk", params.distFile);
|
|
1312
1774
|
const candidates = isProduction ? [distCandidate, srcCandidate] : [srcCandidate, distCandidate];
|
|
1313
1775
|
for (const candidate of candidates) {
|
|
1314
1776
|
if (fs5.existsSync(candidate)) {
|
|
1315
1777
|
return candidate;
|
|
1316
1778
|
}
|
|
1317
1779
|
}
|
|
1318
|
-
const parent =
|
|
1780
|
+
const parent = path5.dirname(cursor);
|
|
1319
1781
|
if (parent === cursor) {
|
|
1320
1782
|
break;
|
|
1321
1783
|
}
|
|
@@ -1345,19 +1807,6 @@ function resolvePluginModuleExport(moduleExport) {
|
|
|
1345
1807
|
}
|
|
1346
1808
|
return {};
|
|
1347
1809
|
}
|
|
1348
|
-
function normalizeToolList(value) {
|
|
1349
|
-
if (!value) {
|
|
1350
|
-
return [];
|
|
1351
|
-
}
|
|
1352
|
-
const list = Array.isArray(value) ? value : [value];
|
|
1353
|
-
return list.filter((entry) => {
|
|
1354
|
-
if (!entry || typeof entry !== "object") {
|
|
1355
|
-
return false;
|
|
1356
|
-
}
|
|
1357
|
-
const candidate = entry;
|
|
1358
|
-
return typeof candidate.name === "string" && candidate.name.trim().length > 0 && candidate.parameters !== void 0 && typeof candidate.execute === "function";
|
|
1359
|
-
});
|
|
1360
|
-
}
|
|
1361
1810
|
function createPluginRecord(params) {
|
|
1362
1811
|
return {
|
|
1363
1812
|
id: params.id,
|
|
@@ -1378,46 +1827,6 @@ function createPluginRecord(params) {
|
|
|
1378
1827
|
configJsonSchema: params.configJsonSchema
|
|
1379
1828
|
};
|
|
1380
1829
|
}
|
|
1381
|
-
function buildPluginLogger(base, pluginId) {
|
|
1382
|
-
const withPrefix = (message) => `[plugins:${pluginId}] ${message}`;
|
|
1383
|
-
return {
|
|
1384
|
-
info: (message) => base.info(withPrefix(message)),
|
|
1385
|
-
warn: (message) => base.warn(withPrefix(message)),
|
|
1386
|
-
error: (message) => base.error(withPrefix(message)),
|
|
1387
|
-
debug: base.debug ? (message) => base.debug?.(withPrefix(message)) : void 0
|
|
1388
|
-
};
|
|
1389
|
-
}
|
|
1390
|
-
function ensureUniqueNames(params) {
|
|
1391
|
-
const accepted = [];
|
|
1392
|
-
for (const rawName of params.names) {
|
|
1393
|
-
const name = rawName.trim();
|
|
1394
|
-
if (!name) {
|
|
1395
|
-
continue;
|
|
1396
|
-
}
|
|
1397
|
-
if (params.reserved.has(name)) {
|
|
1398
|
-
params.diagnostics.push({
|
|
1399
|
-
level: "error",
|
|
1400
|
-
pluginId: params.pluginId,
|
|
1401
|
-
source: params.source,
|
|
1402
|
-
message: `${params.kind} already registered by core: ${name}`
|
|
1403
|
-
});
|
|
1404
|
-
continue;
|
|
1405
|
-
}
|
|
1406
|
-
const owner = params.owners.get(name);
|
|
1407
|
-
if (owner && owner !== params.pluginId) {
|
|
1408
|
-
params.diagnostics.push({
|
|
1409
|
-
level: "error",
|
|
1410
|
-
pluginId: params.pluginId,
|
|
1411
|
-
source: params.source,
|
|
1412
|
-
message: `${params.kind} already registered: ${name} (${owner})`
|
|
1413
|
-
});
|
|
1414
|
-
continue;
|
|
1415
|
-
}
|
|
1416
|
-
params.owners.set(name, params.pluginId);
|
|
1417
|
-
accepted.push(name);
|
|
1418
|
-
}
|
|
1419
|
-
return accepted;
|
|
1420
|
-
}
|
|
1421
1830
|
function isPlaceholderConfigSchema(schema) {
|
|
1422
1831
|
if (!schema || typeof schema !== "object") {
|
|
1423
1832
|
return false;
|
|
@@ -1446,17 +1855,68 @@ function validatePluginConfig(params) {
|
|
|
1446
1855
|
}
|
|
1447
1856
|
return { ok: false, errors: result.errors };
|
|
1448
1857
|
}
|
|
1449
|
-
function
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1858
|
+
function appendBundledChannelPlugins(params) {
|
|
1859
|
+
for (const definition of listBundledChannelPluginDefinitions()) {
|
|
1860
|
+
const pluginId = typeof definition.id === "string" ? definition.id.trim() : "";
|
|
1861
|
+
const source = `builtin:nextclaw-openclaw-compat/channels/${pluginId || "unknown"}`;
|
|
1862
|
+
if (!pluginId) {
|
|
1863
|
+
params.registry.diagnostics.push({
|
|
1864
|
+
level: "error",
|
|
1865
|
+
source,
|
|
1866
|
+
message: "bundled plugin definition missing id"
|
|
1867
|
+
});
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1870
|
+
const record = createPluginRecord({
|
|
1871
|
+
id: pluginId,
|
|
1872
|
+
name: definition.name ?? pluginId,
|
|
1873
|
+
description: definition.description,
|
|
1874
|
+
version: definition.version,
|
|
1875
|
+
kind: definition.kind,
|
|
1876
|
+
source,
|
|
1877
|
+
origin: "bundled",
|
|
1878
|
+
workspaceDir: params.runtime.workspaceDir,
|
|
1879
|
+
enabled: true,
|
|
1880
|
+
configSchema: Boolean(definition.configSchema),
|
|
1881
|
+
configJsonSchema: definition.configSchema
|
|
1882
|
+
});
|
|
1883
|
+
const register = definition.register ?? definition.activate;
|
|
1884
|
+
if (typeof register !== "function") {
|
|
1885
|
+
record.status = "error";
|
|
1886
|
+
record.error = "plugin export missing register/activate";
|
|
1887
|
+
params.registry.plugins.push(record);
|
|
1888
|
+
params.registry.diagnostics.push({
|
|
1889
|
+
level: "error",
|
|
1890
|
+
pluginId,
|
|
1891
|
+
source,
|
|
1892
|
+
message: record.error
|
|
1893
|
+
});
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1896
|
+
const result = registerPluginWithApi({
|
|
1897
|
+
runtime: params.runtime,
|
|
1898
|
+
record,
|
|
1899
|
+
pluginId,
|
|
1900
|
+
source,
|
|
1901
|
+
rootDir: params.runtime.workspaceDir,
|
|
1902
|
+
register,
|
|
1903
|
+
pluginConfig: void 0
|
|
1904
|
+
});
|
|
1905
|
+
if (!result.ok) {
|
|
1906
|
+
record.status = "error";
|
|
1907
|
+
record.error = result.error;
|
|
1908
|
+
params.registry.diagnostics.push({
|
|
1909
|
+
level: "error",
|
|
1910
|
+
pluginId,
|
|
1911
|
+
source,
|
|
1912
|
+
message: result.error
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
params.registry.plugins.push(record);
|
|
1459
1916
|
}
|
|
1917
|
+
}
|
|
1918
|
+
function loadOpenClawPlugins(options) {
|
|
1919
|
+
const loadExternalPlugins = process.env.NEXTCLAW_ENABLE_OPENCLAW_PLUGINS !== "0";
|
|
1460
1920
|
const logger = options.logger ?? defaultLogger2;
|
|
1461
1921
|
const workspaceDir = options.workspaceDir?.trim() || getWorkspacePathFromConfig(options.config);
|
|
1462
1922
|
const normalized = normalizePluginsConfig(options.config.plugins);
|
|
@@ -1469,13 +1929,25 @@ function loadOpenClawPlugins(options) {
|
|
|
1469
1929
|
diagnostics: [],
|
|
1470
1930
|
resolvedTools: []
|
|
1471
1931
|
};
|
|
1472
|
-
const toolNameOwners = /* @__PURE__ */ new Map();
|
|
1473
|
-
const channelIdOwners = /* @__PURE__ */ new Map();
|
|
1474
|
-
const providerIdOwners = /* @__PURE__ */ new Map();
|
|
1475
|
-
const resolvedToolNames = /* @__PURE__ */ new Set();
|
|
1476
1932
|
const reservedToolNames = new Set(options.reservedToolNames ?? []);
|
|
1477
1933
|
const reservedChannelIds = new Set(options.reservedChannelIds ?? []);
|
|
1478
1934
|
const reservedProviderIds = new Set(options.reservedProviderIds ?? []);
|
|
1935
|
+
const registerRuntime = createPluginRegisterRuntime({
|
|
1936
|
+
config: options.config,
|
|
1937
|
+
workspaceDir,
|
|
1938
|
+
logger,
|
|
1939
|
+
registry,
|
|
1940
|
+
reservedToolNames,
|
|
1941
|
+
reservedChannelIds,
|
|
1942
|
+
reservedProviderIds
|
|
1943
|
+
});
|
|
1944
|
+
appendBundledChannelPlugins({
|
|
1945
|
+
registry,
|
|
1946
|
+
runtime: registerRuntime
|
|
1947
|
+
});
|
|
1948
|
+
if (!loadExternalPlugins) {
|
|
1949
|
+
return registry;
|
|
1950
|
+
}
|
|
1479
1951
|
const discovery = discoverOpenClawPlugins({
|
|
1480
1952
|
config: options.config,
|
|
1481
1953
|
workspaceDir,
|
|
@@ -1630,264 +2102,30 @@ function loadOpenClawPlugins(options) {
|
|
|
1630
2102
|
});
|
|
1631
2103
|
continue;
|
|
1632
2104
|
}
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
level: "warn",
|
|
1638
|
-
pluginId,
|
|
1639
|
-
source: candidate.source,
|
|
1640
|
-
message: `${capability} is not supported by nextclaw compat layer yet`
|
|
1641
|
-
});
|
|
1642
|
-
pluginLogger.warn(`${capability} is ignored (not supported yet)`);
|
|
1643
|
-
};
|
|
1644
|
-
const api = {
|
|
1645
|
-
id: pluginId,
|
|
1646
|
-
name: record.name,
|
|
1647
|
-
version: record.version,
|
|
1648
|
-
description: record.description,
|
|
2105
|
+
const registerResult = registerPluginWithApi({
|
|
2106
|
+
runtime: registerRuntime,
|
|
2107
|
+
record,
|
|
2108
|
+
pluginId,
|
|
1649
2109
|
source: candidate.source,
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
const declaredNames = opts && Array.isArray(opts.names) ? opts.names : [];
|
|
1656
|
-
const names = [...declaredNames, ...opts && opts.name ? [opts.name] : []];
|
|
1657
|
-
if (typeof tool !== "function" && typeof tool.name === "string") {
|
|
1658
|
-
names.push(tool.name);
|
|
1659
|
-
}
|
|
1660
|
-
const uniqueNames = Array.from(new Set(names.map((name) => name.trim()).filter(Boolean)));
|
|
1661
|
-
const acceptedNames = ensureUniqueNames({
|
|
1662
|
-
names: uniqueNames,
|
|
1663
|
-
pluginId,
|
|
1664
|
-
diagnostics: registry.diagnostics,
|
|
1665
|
-
source: candidate.source,
|
|
1666
|
-
owners: toolNameOwners,
|
|
1667
|
-
reserved: reservedToolNames,
|
|
1668
|
-
kind: "tool"
|
|
1669
|
-
});
|
|
1670
|
-
if (acceptedNames.length === 0) {
|
|
1671
|
-
registry.diagnostics.push({
|
|
1672
|
-
level: "warn",
|
|
1673
|
-
pluginId,
|
|
1674
|
-
source: candidate.source,
|
|
1675
|
-
message: "tool registration skipped: no available tool names"
|
|
1676
|
-
});
|
|
1677
|
-
return;
|
|
1678
|
-
}
|
|
1679
|
-
const factory = typeof tool === "function" ? tool : (_ctx) => tool;
|
|
1680
|
-
registry.tools.push({
|
|
1681
|
-
pluginId,
|
|
1682
|
-
factory,
|
|
1683
|
-
names: acceptedNames,
|
|
1684
|
-
optional: opts?.optional === true,
|
|
1685
|
-
source: candidate.source
|
|
1686
|
-
});
|
|
1687
|
-
record.toolNames.push(...acceptedNames);
|
|
1688
|
-
try {
|
|
1689
|
-
const previewTools = normalizeToolList(
|
|
1690
|
-
factory({
|
|
1691
|
-
config: options.config,
|
|
1692
|
-
workspaceDir,
|
|
1693
|
-
sandboxed: false
|
|
1694
|
-
})
|
|
1695
|
-
);
|
|
1696
|
-
const byName = new Map(previewTools.map((entry2) => [entry2.name, entry2]));
|
|
1697
|
-
for (const name of acceptedNames) {
|
|
1698
|
-
const resolvedTool = byName.get(name);
|
|
1699
|
-
if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
|
|
1700
|
-
continue;
|
|
1701
|
-
}
|
|
1702
|
-
resolvedToolNames.add(resolvedTool.name);
|
|
1703
|
-
registry.resolvedTools.push(resolvedTool);
|
|
1704
|
-
}
|
|
1705
|
-
} catch (err) {
|
|
1706
|
-
registry.diagnostics.push({
|
|
1707
|
-
level: "warn",
|
|
1708
|
-
pluginId,
|
|
1709
|
-
source: candidate.source,
|
|
1710
|
-
message: `tool preview failed: ${String(err)}`
|
|
1711
|
-
});
|
|
1712
|
-
}
|
|
1713
|
-
},
|
|
1714
|
-
registerChannel: (registration) => {
|
|
1715
|
-
const normalizedChannel = registration && typeof registration === "object" && "plugin" in registration ? registration.plugin : registration;
|
|
1716
|
-
if (!normalizedChannel || typeof normalizedChannel !== "object") {
|
|
1717
|
-
registry.diagnostics.push({
|
|
1718
|
-
level: "error",
|
|
1719
|
-
pluginId,
|
|
1720
|
-
source: candidate.source,
|
|
1721
|
-
message: "channel registration missing plugin object"
|
|
1722
|
-
});
|
|
1723
|
-
return;
|
|
1724
|
-
}
|
|
1725
|
-
const channelObj = normalizedChannel;
|
|
1726
|
-
const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
|
|
1727
|
-
const accepted = ensureUniqueNames({
|
|
1728
|
-
names: [rawId],
|
|
1729
|
-
pluginId,
|
|
1730
|
-
diagnostics: registry.diagnostics,
|
|
1731
|
-
source: candidate.source,
|
|
1732
|
-
owners: channelIdOwners,
|
|
1733
|
-
reserved: reservedChannelIds,
|
|
1734
|
-
kind: "channel"
|
|
1735
|
-
});
|
|
1736
|
-
if (accepted.length === 0) {
|
|
1737
|
-
return;
|
|
1738
|
-
}
|
|
1739
|
-
const channelPlugin = normalizedChannel;
|
|
1740
|
-
registry.channels.push({
|
|
1741
|
-
pluginId,
|
|
1742
|
-
channel: channelPlugin,
|
|
1743
|
-
source: candidate.source
|
|
1744
|
-
});
|
|
1745
|
-
const channelId = accepted[0];
|
|
1746
|
-
record.channelIds.push(channelId);
|
|
1747
|
-
const configSchema = channelPlugin.configSchema;
|
|
1748
|
-
if (configSchema && typeof configSchema === "object") {
|
|
1749
|
-
const schema = configSchema.schema;
|
|
1750
|
-
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
1751
|
-
record.configJsonSchema = schema;
|
|
1752
|
-
record.configSchema = true;
|
|
1753
|
-
}
|
|
1754
|
-
const uiHints = configSchema.uiHints;
|
|
1755
|
-
if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
|
|
1756
|
-
record.configUiHints = {
|
|
1757
|
-
...record.configUiHints ?? {},
|
|
1758
|
-
...uiHints
|
|
1759
|
-
};
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
|
|
1763
|
-
const previewTools = normalizeToolList(value);
|
|
1764
|
-
if (previewTools.length === 0) {
|
|
1765
|
-
return;
|
|
1766
|
-
}
|
|
1767
|
-
const declaredNames = previewTools.map((tool) => tool.name);
|
|
1768
|
-
const acceptedNames = ensureUniqueNames({
|
|
1769
|
-
names: declaredNames,
|
|
1770
|
-
pluginId,
|
|
1771
|
-
diagnostics: registry.diagnostics,
|
|
1772
|
-
source: candidate.source,
|
|
1773
|
-
owners: toolNameOwners,
|
|
1774
|
-
reserved: reservedToolNames,
|
|
1775
|
-
kind: "tool"
|
|
1776
|
-
});
|
|
1777
|
-
if (acceptedNames.length === 0) {
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
const factory = (ctx) => {
|
|
1781
|
-
const tools = normalizeToolList(resolveValue(ctx));
|
|
1782
|
-
if (tools.length === 0) {
|
|
1783
|
-
return [];
|
|
1784
|
-
}
|
|
1785
|
-
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
1786
|
-
return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
|
|
1787
|
-
};
|
|
1788
|
-
registry.tools.push({
|
|
1789
|
-
pluginId,
|
|
1790
|
-
factory,
|
|
1791
|
-
names: acceptedNames,
|
|
1792
|
-
optional,
|
|
1793
|
-
source: candidate.source
|
|
1794
|
-
});
|
|
1795
|
-
record.toolNames.push(...acceptedNames);
|
|
1796
|
-
const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
|
|
1797
|
-
for (const name of acceptedNames) {
|
|
1798
|
-
const resolvedTool = previewByName.get(name);
|
|
1799
|
-
if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
|
|
1800
|
-
continue;
|
|
1801
|
-
}
|
|
1802
|
-
resolvedToolNames.add(resolvedTool.name);
|
|
1803
|
-
registry.resolvedTools.push(resolvedTool);
|
|
1804
|
-
}
|
|
1805
|
-
registry.diagnostics.push({
|
|
1806
|
-
level: "warn",
|
|
1807
|
-
pluginId,
|
|
1808
|
-
source: candidate.source,
|
|
1809
|
-
message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
|
|
1810
|
-
});
|
|
1811
|
-
};
|
|
1812
|
-
const agentTools = channelPlugin.agentTools;
|
|
1813
|
-
if (typeof agentTools === "function") {
|
|
1814
|
-
pushChannelTools(
|
|
1815
|
-
normalizeToolList(agentTools()),
|
|
1816
|
-
false,
|
|
1817
|
-
`channel "${channelId}"`,
|
|
1818
|
-
() => agentTools()
|
|
1819
|
-
);
|
|
1820
|
-
} else if (agentTools) {
|
|
1821
|
-
pushChannelTools(
|
|
1822
|
-
normalizeToolList(agentTools),
|
|
1823
|
-
false,
|
|
1824
|
-
`channel "${channelId}"`,
|
|
1825
|
-
() => agentTools
|
|
1826
|
-
);
|
|
1827
|
-
}
|
|
1828
|
-
},
|
|
1829
|
-
registerProvider: (provider) => {
|
|
1830
|
-
const accepted = ensureUniqueNames({
|
|
1831
|
-
names: [provider.id],
|
|
1832
|
-
pluginId,
|
|
1833
|
-
diagnostics: registry.diagnostics,
|
|
1834
|
-
source: candidate.source,
|
|
1835
|
-
owners: providerIdOwners,
|
|
1836
|
-
reserved: reservedProviderIds,
|
|
1837
|
-
kind: "provider"
|
|
1838
|
-
});
|
|
1839
|
-
if (accepted.length === 0) {
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
registry.providers.push({
|
|
1843
|
-
pluginId,
|
|
1844
|
-
provider,
|
|
1845
|
-
source: candidate.source
|
|
1846
|
-
});
|
|
1847
|
-
record.providerIds.push(accepted[0]);
|
|
1848
|
-
},
|
|
1849
|
-
registerHook: () => pushUnsupported("registerHook"),
|
|
1850
|
-
registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
|
|
1851
|
-
registerCli: () => pushUnsupported("registerCli"),
|
|
1852
|
-
registerService: () => pushUnsupported("registerService"),
|
|
1853
|
-
registerCommand: () => pushUnsupported("registerCommand"),
|
|
1854
|
-
registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
|
|
1855
|
-
registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
|
|
1856
|
-
resolvePath: (input) => {
|
|
1857
|
-
const trimmed = input.trim();
|
|
1858
|
-
if (!trimmed) {
|
|
1859
|
-
return candidate.rootDir;
|
|
1860
|
-
}
|
|
1861
|
-
if (path4.isAbsolute(trimmed)) {
|
|
1862
|
-
return path4.resolve(expandHome2(trimmed));
|
|
1863
|
-
}
|
|
1864
|
-
return path4.resolve(candidate.rootDir, trimmed);
|
|
1865
|
-
}
|
|
1866
|
-
};
|
|
1867
|
-
try {
|
|
1868
|
-
const result = register(api);
|
|
1869
|
-
if (result && typeof result === "object" && "then" in result) {
|
|
1870
|
-
registry.diagnostics.push({
|
|
1871
|
-
level: "warn",
|
|
1872
|
-
pluginId,
|
|
1873
|
-
source: candidate.source,
|
|
1874
|
-
message: "plugin register returned a promise; async registration is ignored"
|
|
1875
|
-
});
|
|
1876
|
-
}
|
|
1877
|
-
registry.plugins.push(record);
|
|
1878
|
-
seenIds.set(pluginId, candidate.origin);
|
|
1879
|
-
} catch (err) {
|
|
2110
|
+
rootDir: candidate.rootDir,
|
|
2111
|
+
register,
|
|
2112
|
+
pluginConfig: validatedConfig.value
|
|
2113
|
+
});
|
|
2114
|
+
if (!registerResult.ok) {
|
|
1880
2115
|
record.status = "error";
|
|
1881
|
-
record.error =
|
|
1882
|
-
registry.plugins.push(record);
|
|
1883
|
-
seenIds.set(pluginId, candidate.origin);
|
|
2116
|
+
record.error = registerResult.error;
|
|
1884
2117
|
registry.diagnostics.push({
|
|
1885
2118
|
level: "error",
|
|
1886
2119
|
pluginId,
|
|
1887
2120
|
source: candidate.source,
|
|
1888
|
-
message:
|
|
2121
|
+
message: registerResult.error
|
|
1889
2122
|
});
|
|
2123
|
+
registry.plugins.push(record);
|
|
2124
|
+
seenIds.set(pluginId, candidate.origin);
|
|
2125
|
+
continue;
|
|
1890
2126
|
}
|
|
2127
|
+
registry.plugins.push(record);
|
|
2128
|
+
seenIds.set(pluginId, candidate.origin);
|
|
1891
2129
|
}
|
|
1892
2130
|
return registry;
|
|
1893
2131
|
}
|
|
@@ -1912,7 +2150,7 @@ function buildPluginStatusReport(params) {
|
|
|
1912
2150
|
|
|
1913
2151
|
// src/plugins/uninstall.ts
|
|
1914
2152
|
import fs6 from "fs/promises";
|
|
1915
|
-
import
|
|
2153
|
+
import path6 from "path";
|
|
1916
2154
|
function isLinkedPathInstall(record) {
|
|
1917
2155
|
if (!record || record.source !== "path") {
|
|
1918
2156
|
return false;
|
|
@@ -1920,7 +2158,7 @@ function isLinkedPathInstall(record) {
|
|
|
1920
2158
|
if (!record.sourcePath || !record.installPath) {
|
|
1921
2159
|
return true;
|
|
1922
2160
|
}
|
|
1923
|
-
return
|
|
2161
|
+
return path6.resolve(record.sourcePath) === path6.resolve(record.installPath);
|
|
1924
2162
|
}
|
|
1925
2163
|
function resolveUninstallDirectoryTarget(params) {
|
|
1926
2164
|
if (!params.hasInstall) {
|
|
@@ -1939,7 +2177,7 @@ function resolveUninstallDirectoryTarget(params) {
|
|
|
1939
2177
|
if (!configuredPath) {
|
|
1940
2178
|
return defaultPath;
|
|
1941
2179
|
}
|
|
1942
|
-
if (
|
|
2180
|
+
if (path6.resolve(configuredPath) === path6.resolve(defaultPath)) {
|
|
1943
2181
|
return configuredPath;
|
|
1944
2182
|
}
|
|
1945
2183
|
return defaultPath;
|
|
@@ -2065,6 +2303,7 @@ export {
|
|
|
2065
2303
|
buildChannelConfigSchema,
|
|
2066
2304
|
buildOauthProviderAuthResult,
|
|
2067
2305
|
buildPluginStatusReport,
|
|
2306
|
+
createPluginRegisterRuntime,
|
|
2068
2307
|
createPluginRuntime,
|
|
2069
2308
|
disablePluginInConfig,
|
|
2070
2309
|
discoverOpenClawPlugins,
|
|
@@ -2086,6 +2325,7 @@ export {
|
|
|
2086
2325
|
normalizePluginHttpPath,
|
|
2087
2326
|
normalizePluginsConfig,
|
|
2088
2327
|
recordPluginInstall,
|
|
2328
|
+
registerPluginWithApi,
|
|
2089
2329
|
removePluginFromConfig,
|
|
2090
2330
|
resolveEnableState,
|
|
2091
2331
|
resolvePluginChannelMessageToolHints,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/openclaw-compat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw plugin compatibility layer for NextClaw.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"jiti": "^1.21.7",
|
|
19
19
|
"jszip": "^3.10.1",
|
|
20
20
|
"tar": "^7.4.3",
|
|
21
|
-
"@nextclaw/core": "^0.6.
|
|
21
|
+
"@nextclaw/core": "^0.6.16"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.17.6",
|