@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 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((plugin) => ({
228
- id: plugin.id,
229
- configSchema: plugin.configJsonSchema,
230
- configUiHints: plugin.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 path4 from "path";
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/schema-validator.ts
1264
- import AjvPkg from "ajv";
1265
- var AjvCtor = AjvPkg;
1266
- var ajv = new AjvCtor({
1267
- allErrors: true,
1268
- strict: false,
1269
- removeAdditional: false
1270
- });
1271
- var schemaCache = /* @__PURE__ */ new Map();
1272
- function formatAjvErrors(errors) {
1273
- if (!errors || errors.length === 0) {
1274
- return ["invalid config"];
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 errors.map((error) => {
1277
- const path6 = error.instancePath?.replace(/^\//, "").replace(/\//g, ".") || "<root>";
1278
- const message = error.message ?? "invalid";
1279
- return `${path6}: ${message}`;
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 validateJsonSchemaValue(params) {
1283
- let cached = schemaCache.get(params.cacheKey);
1284
- if (!cached || cached.schema !== params.schema) {
1285
- const validate = ajv.compile(params.schema);
1286
- cached = { validate, schema: params.schema };
1287
- schemaCache.set(params.cacheKey, cached);
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
- const ok = cached.validate(params.value);
1290
- if (ok) {
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 = path4.dirname(modulePath);
1770
+ let cursor = path5.dirname(modulePath);
1309
1771
  for (let i = 0; i < 6; i += 1) {
1310
- const srcCandidate = path4.join(cursor, "src", "plugin-sdk", params.srcFile);
1311
- const distCandidate = path4.join(cursor, "dist", "plugin-sdk", params.distFile);
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 = path4.dirname(cursor);
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 loadOpenClawPlugins(options) {
1450
- if (process.env.NEXTCLAW_ENABLE_OPENCLAW_PLUGINS === "0") {
1451
- return {
1452
- plugins: [],
1453
- tools: [],
1454
- channels: [],
1455
- providers: [],
1456
- diagnostics: [],
1457
- resolvedTools: []
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 pluginRuntime = createPluginRuntime({ workspace: workspaceDir, config: options.config });
1634
- const pluginLogger = buildPluginLogger(logger, pluginId);
1635
- const pushUnsupported = (capability) => {
1636
- registry.diagnostics.push({
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
- config: options.config,
1651
- pluginConfig: validatedConfig.value,
1652
- runtime: pluginRuntime,
1653
- logger: pluginLogger,
1654
- registerTool: (tool, opts) => {
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 = `plugin failed during register: ${String(err)}`;
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: record.error
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 path5 from "path";
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 path5.resolve(record.sourcePath) === path5.resolve(record.installPath);
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 (path5.resolve(configuredPath) === path5.resolve(defaultPath)) {
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.5",
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.2"
21
+ "@nextclaw/core": "^0.6.16"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.17.6",