@nextclaw/openclaw-compat 0.1.6 → 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
@@ -520,6 +520,43 @@ declare function createPluginRuntime(params: {
520
520
  config?: Config;
521
521
  }): PluginRuntime;
522
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
+
523
560
  declare function validateJsonSchemaValue(params: {
524
561
  schema: Record<string, unknown>;
525
562
  cacheKey: string;
@@ -578,4 +615,4 @@ declare function uninstallPlugin(params: {
578
615
  extensionsDir?: string;
579
616
  }): Promise<UninstallPluginResult>;
580
617
 
581
- 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
@@ -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,58 +1207,6 @@ function loadPluginUiMetadata(params) {
1208
1207
  return toPluginUiMetadata(registry.plugins);
1209
1208
  }
1210
1209
 
1211
- // src/plugins/runtime.ts
1212
- import { getPackageVersion } from "@nextclaw/core";
1213
- import { MemoryGetTool, MemorySearchTool } from "@nextclaw/core";
1214
- var bridge = {};
1215
- function setPluginRuntimeBridge(next) {
1216
- bridge = next ?? {};
1217
- }
1218
- function toPluginTool(tool) {
1219
- return {
1220
- name: tool.name,
1221
- description: tool.description,
1222
- parameters: tool.parameters,
1223
- execute: (params) => tool.execute(params)
1224
- };
1225
- }
1226
- function loadConfigWithFallback(config) {
1227
- if (bridge.loadConfig) {
1228
- return bridge.loadConfig();
1229
- }
1230
- return config ?? {};
1231
- }
1232
- async function writeConfigWithFallback(next) {
1233
- if (!bridge.writeConfigFile) {
1234
- throw new Error("plugin runtime config.writeConfigFile is unavailable outside gateway runtime");
1235
- }
1236
- await bridge.writeConfigFile(next);
1237
- }
1238
- async function dispatchReplyWithFallback(params) {
1239
- if (!bridge.dispatchReplyWithBufferedBlockDispatcher) {
1240
- throw new Error("plugin runtime channel.reply dispatcher is unavailable outside gateway runtime");
1241
- }
1242
- await bridge.dispatchReplyWithBufferedBlockDispatcher(params);
1243
- }
1244
- function createPluginRuntime(params) {
1245
- return {
1246
- version: getPackageVersion(),
1247
- config: {
1248
- loadConfig: () => loadConfigWithFallback(params.config),
1249
- writeConfigFile: async (next) => writeConfigWithFallback(next)
1250
- },
1251
- tools: {
1252
- createMemorySearchTool: () => toPluginTool(new MemorySearchTool(params.workspace)),
1253
- createMemoryGetTool: () => toPluginTool(new MemoryGetTool(params.workspace))
1254
- },
1255
- channel: {
1256
- reply: {
1257
- dispatchReplyWithBufferedBlockDispatcher: async (dispatchParams) => dispatchReplyWithFallback(dispatchParams)
1258
- }
1259
- }
1260
- };
1261
- }
1262
-
1263
1210
  // src/plugins/schema-validator.ts
1264
1211
  import AjvPkg from "ajv";
1265
1212
  var AjvCtor = AjvPkg;
@@ -1274,9 +1221,9 @@ function formatAjvErrors(errors) {
1274
1221
  return ["invalid config"];
1275
1222
  }
1276
1223
  return errors.map((error) => {
1277
- const path6 = error.instancePath?.replace(/^\//, "").replace(/\//g, ".") || "<root>";
1224
+ const path7 = error.instancePath?.replace(/^\//, "").replace(/\//g, ".") || "<root>";
1278
1225
  const message = error.message ?? "invalid";
1279
- return `${path6}: ${message}`;
1226
+ return `${path7}: ${message}`;
1280
1227
  });
1281
1228
  }
1282
1229
  function validateJsonSchemaValue(params) {
@@ -1419,6 +1366,395 @@ function listBundledChannelPluginDefinitions() {
1419
1366
  }
1420
1367
  var BUNDLED_CHANNEL_PLUGIN_IDS = BUNDLED_CHANNEL_PLUGINS.map((plugin10) => plugin10.id).filter((id) => typeof id === "string" && id.trim().length > 0);
1421
1368
 
1369
+ // src/plugins/registry.ts
1370
+ import path4 from "path";
1371
+ import { expandHome as expandHome2 } from "@nextclaw/core";
1372
+
1373
+ // src/plugins/runtime.ts
1374
+ import { getPackageVersion } from "@nextclaw/core";
1375
+ import { MemoryGetTool, MemorySearchTool } from "@nextclaw/core";
1376
+ var bridge = {};
1377
+ function setPluginRuntimeBridge(next) {
1378
+ bridge = next ?? {};
1379
+ }
1380
+ function toPluginTool(tool) {
1381
+ return {
1382
+ name: tool.name,
1383
+ description: tool.description,
1384
+ parameters: tool.parameters,
1385
+ execute: (params) => tool.execute(params)
1386
+ };
1387
+ }
1388
+ function loadConfigWithFallback(config) {
1389
+ if (bridge.loadConfig) {
1390
+ return bridge.loadConfig();
1391
+ }
1392
+ return config ?? {};
1393
+ }
1394
+ async function writeConfigWithFallback(next) {
1395
+ if (!bridge.writeConfigFile) {
1396
+ throw new Error("plugin runtime config.writeConfigFile is unavailable outside gateway runtime");
1397
+ }
1398
+ await bridge.writeConfigFile(next);
1399
+ }
1400
+ async function dispatchReplyWithFallback(params) {
1401
+ if (!bridge.dispatchReplyWithBufferedBlockDispatcher) {
1402
+ throw new Error("plugin runtime channel.reply dispatcher is unavailable outside gateway runtime");
1403
+ }
1404
+ await bridge.dispatchReplyWithBufferedBlockDispatcher(params);
1405
+ }
1406
+ function createPluginRuntime(params) {
1407
+ return {
1408
+ version: getPackageVersion(),
1409
+ config: {
1410
+ loadConfig: () => loadConfigWithFallback(params.config),
1411
+ writeConfigFile: async (next) => writeConfigWithFallback(next)
1412
+ },
1413
+ tools: {
1414
+ createMemorySearchTool: () => toPluginTool(new MemorySearchTool(params.workspace)),
1415
+ createMemoryGetTool: () => toPluginTool(new MemoryGetTool(params.workspace))
1416
+ },
1417
+ channel: {
1418
+ reply: {
1419
+ dispatchReplyWithBufferedBlockDispatcher: async (dispatchParams) => dispatchReplyWithFallback(dispatchParams)
1420
+ }
1421
+ }
1422
+ };
1423
+ }
1424
+
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);
1463
+ }
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";
1477
+ });
1478
+ }
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());
1506
+ }
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
+ }
1751
+ return { ok: true };
1752
+ } catch (err) {
1753
+ const error = `plugin failed during register: ${String(err)}`;
1754
+ return { ok: false, error };
1755
+ }
1756
+ }
1757
+
1422
1758
  // src/plugins/loader.ts
1423
1759
  var createJiti = createJitiImport;
1424
1760
  var defaultLogger2 = {
@@ -1431,17 +1767,17 @@ function resolvePluginSdkAliasFile(params) {
1431
1767
  try {
1432
1768
  const modulePath = fileURLToPath(import.meta.url);
1433
1769
  const isProduction = process.env.NODE_ENV === "production";
1434
- let cursor = path4.dirname(modulePath);
1770
+ let cursor = path5.dirname(modulePath);
1435
1771
  for (let i = 0; i < 6; i += 1) {
1436
- const srcCandidate = path4.join(cursor, "src", "plugin-sdk", params.srcFile);
1437
- 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);
1438
1774
  const candidates = isProduction ? [distCandidate, srcCandidate] : [srcCandidate, distCandidate];
1439
1775
  for (const candidate of candidates) {
1440
1776
  if (fs5.existsSync(candidate)) {
1441
1777
  return candidate;
1442
1778
  }
1443
1779
  }
1444
- const parent = path4.dirname(cursor);
1780
+ const parent = path5.dirname(cursor);
1445
1781
  if (parent === cursor) {
1446
1782
  break;
1447
1783
  }
@@ -1471,19 +1807,6 @@ function resolvePluginModuleExport(moduleExport) {
1471
1807
  }
1472
1808
  return {};
1473
1809
  }
1474
- function normalizeToolList(value) {
1475
- if (!value) {
1476
- return [];
1477
- }
1478
- const list = Array.isArray(value) ? value : [value];
1479
- return list.filter((entry) => {
1480
- if (!entry || typeof entry !== "object") {
1481
- return false;
1482
- }
1483
- const candidate = entry;
1484
- return typeof candidate.name === "string" && candidate.name.trim().length > 0 && candidate.parameters !== void 0 && typeof candidate.execute === "function";
1485
- });
1486
- }
1487
1810
  function createPluginRecord(params) {
1488
1811
  return {
1489
1812
  id: params.id,
@@ -1504,46 +1827,6 @@ function createPluginRecord(params) {
1504
1827
  configJsonSchema: params.configJsonSchema
1505
1828
  };
1506
1829
  }
1507
- function buildPluginLogger(base, pluginId) {
1508
- const withPrefix = (message) => `[plugins:${pluginId}] ${message}`;
1509
- return {
1510
- info: (message) => base.info(withPrefix(message)),
1511
- warn: (message) => base.warn(withPrefix(message)),
1512
- error: (message) => base.error(withPrefix(message)),
1513
- debug: base.debug ? (message) => base.debug?.(withPrefix(message)) : void 0
1514
- };
1515
- }
1516
- function ensureUniqueNames(params) {
1517
- const accepted = [];
1518
- for (const rawName of params.names) {
1519
- const name = rawName.trim();
1520
- if (!name) {
1521
- continue;
1522
- }
1523
- if (params.reserved.has(name)) {
1524
- params.diagnostics.push({
1525
- level: "error",
1526
- pluginId: params.pluginId,
1527
- source: params.source,
1528
- message: `${params.kind} already registered by core: ${name}`
1529
- });
1530
- continue;
1531
- }
1532
- const owner = params.owners.get(name);
1533
- if (owner && owner !== params.pluginId) {
1534
- params.diagnostics.push({
1535
- level: "error",
1536
- pluginId: params.pluginId,
1537
- source: params.source,
1538
- message: `${params.kind} already registered: ${name} (${owner})`
1539
- });
1540
- continue;
1541
- }
1542
- params.owners.set(name, params.pluginId);
1543
- accepted.push(name);
1544
- }
1545
- return accepted;
1546
- }
1547
1830
  function isPlaceholderConfigSchema(schema) {
1548
1831
  if (!schema || typeof schema !== "object") {
1549
1832
  return false;
@@ -1592,7 +1875,7 @@ function appendBundledChannelPlugins(params) {
1592
1875
  kind: definition.kind,
1593
1876
  source,
1594
1877
  origin: "bundled",
1595
- workspaceDir: params.workspaceDir,
1878
+ workspaceDir: params.runtime.workspaceDir,
1596
1879
  enabled: true,
1597
1880
  configSchema: Boolean(definition.configSchema),
1598
1881
  configJsonSchema: definition.configSchema
@@ -1610,203 +1893,26 @@ function appendBundledChannelPlugins(params) {
1610
1893
  });
1611
1894
  continue;
1612
1895
  }
1613
- const pluginRuntime = createPluginRuntime({ workspace: params.workspaceDir, config: params.config });
1614
- const pluginLogger = buildPluginLogger(params.logger, pluginId);
1615
- const pushUnsupported = (capability) => {
1616
- params.registry.diagnostics.push({
1617
- level: "warn",
1618
- pluginId,
1619
- source,
1620
- message: `${capability} is not supported by nextclaw compat layer yet`
1621
- });
1622
- pluginLogger.warn(`${capability} is ignored (not supported yet)`);
1623
- };
1624
- const api = {
1625
- id: pluginId,
1626
- name: record.name,
1627
- version: record.version,
1628
- description: record.description,
1896
+ const result = registerPluginWithApi({
1897
+ runtime: params.runtime,
1898
+ record,
1899
+ pluginId,
1629
1900
  source,
1630
- config: params.config,
1631
- pluginConfig: void 0,
1632
- runtime: pluginRuntime,
1633
- logger: pluginLogger,
1634
- registerTool: () => pushUnsupported("registerTool"),
1635
- registerChannel: (registration) => {
1636
- const normalizedChannel = registration && typeof registration === "object" && "plugin" in registration ? registration.plugin : registration;
1637
- if (!normalizedChannel || typeof normalizedChannel !== "object") {
1638
- params.registry.diagnostics.push({
1639
- level: "error",
1640
- pluginId,
1641
- source,
1642
- message: "channel registration missing plugin object"
1643
- });
1644
- return;
1645
- }
1646
- const channelObj = normalizedChannel;
1647
- const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
1648
- const accepted = ensureUniqueNames({
1649
- names: [rawId],
1650
- pluginId,
1651
- diagnostics: params.registry.diagnostics,
1652
- source,
1653
- owners: params.channelIdOwners,
1654
- reserved: params.reservedChannelIds,
1655
- kind: "channel"
1656
- });
1657
- if (accepted.length === 0) {
1658
- return;
1659
- }
1660
- const channelPlugin = normalizedChannel;
1661
- params.registry.channels.push({
1662
- pluginId,
1663
- channel: channelPlugin,
1664
- source
1665
- });
1666
- const channelId = accepted[0];
1667
- record.channelIds.push(channelId);
1668
- const configSchema = channelPlugin.configSchema;
1669
- if (configSchema && typeof configSchema === "object") {
1670
- const schema = configSchema.schema;
1671
- if (schema && typeof schema === "object" && !Array.isArray(schema)) {
1672
- record.configJsonSchema = schema;
1673
- record.configSchema = true;
1674
- }
1675
- const uiHints = configSchema.uiHints;
1676
- if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
1677
- record.configUiHints = {
1678
- ...record.configUiHints ?? {},
1679
- ...uiHints
1680
- };
1681
- }
1682
- }
1683
- const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
1684
- const previewTools = normalizeToolList(value);
1685
- if (previewTools.length === 0) {
1686
- return;
1687
- }
1688
- const declaredNames = previewTools.map((tool) => tool.name);
1689
- const acceptedNames = ensureUniqueNames({
1690
- names: declaredNames,
1691
- pluginId,
1692
- diagnostics: params.registry.diagnostics,
1693
- source,
1694
- owners: params.toolNameOwners,
1695
- reserved: params.reservedToolNames,
1696
- kind: "tool"
1697
- });
1698
- if (acceptedNames.length === 0) {
1699
- return;
1700
- }
1701
- const factory = (ctx) => {
1702
- const tools = normalizeToolList(resolveValue(ctx));
1703
- if (tools.length === 0) {
1704
- return [];
1705
- }
1706
- const byName = new Map(tools.map((tool) => [tool.name, tool]));
1707
- return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
1708
- };
1709
- params.registry.tools.push({
1710
- pluginId,
1711
- factory,
1712
- names: acceptedNames,
1713
- optional,
1714
- source
1715
- });
1716
- record.toolNames.push(...acceptedNames);
1717
- const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
1718
- for (const name of acceptedNames) {
1719
- const resolvedTool = previewByName.get(name);
1720
- if (!resolvedTool || params.resolvedToolNames.has(resolvedTool.name)) {
1721
- continue;
1722
- }
1723
- params.resolvedToolNames.add(resolvedTool.name);
1724
- params.registry.resolvedTools.push(resolvedTool);
1725
- }
1726
- params.registry.diagnostics.push({
1727
- level: "warn",
1728
- pluginId,
1729
- source,
1730
- message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
1731
- });
1732
- };
1733
- const agentTools = channelPlugin.agentTools;
1734
- if (typeof agentTools === "function") {
1735
- pushChannelTools(
1736
- normalizeToolList(agentTools()),
1737
- false,
1738
- `channel "${channelId}"`,
1739
- () => agentTools()
1740
- );
1741
- } else if (agentTools) {
1742
- pushChannelTools(
1743
- normalizeToolList(agentTools),
1744
- false,
1745
- `channel "${channelId}"`,
1746
- () => agentTools
1747
- );
1748
- }
1749
- },
1750
- registerProvider: (provider) => {
1751
- const accepted = ensureUniqueNames({
1752
- names: [provider.id],
1753
- pluginId,
1754
- diagnostics: params.registry.diagnostics,
1755
- source,
1756
- owners: params.providerIdOwners,
1757
- reserved: params.reservedProviderIds,
1758
- kind: "provider"
1759
- });
1760
- if (accepted.length === 0) {
1761
- return;
1762
- }
1763
- params.registry.providers.push({
1764
- pluginId,
1765
- provider,
1766
- source
1767
- });
1768
- record.providerIds.push(accepted[0]);
1769
- },
1770
- registerHook: () => pushUnsupported("registerHook"),
1771
- registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
1772
- registerCli: () => pushUnsupported("registerCli"),
1773
- registerService: () => pushUnsupported("registerService"),
1774
- registerCommand: () => pushUnsupported("registerCommand"),
1775
- registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
1776
- registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
1777
- resolvePath: (input) => {
1778
- const trimmed = input.trim();
1779
- if (!trimmed) {
1780
- return params.workspaceDir;
1781
- }
1782
- if (path4.isAbsolute(trimmed)) {
1783
- return path4.resolve(expandHome2(trimmed));
1784
- }
1785
- return path4.resolve(params.workspaceDir, trimmed);
1786
- }
1787
- };
1788
- try {
1789
- const result = register(api);
1790
- if (result && typeof result === "object" && "then" in result) {
1791
- params.registry.diagnostics.push({
1792
- level: "warn",
1793
- pluginId,
1794
- source,
1795
- message: "plugin register returned a promise; async registration is ignored"
1796
- });
1797
- }
1798
- params.registry.plugins.push(record);
1799
- } catch (err) {
1901
+ rootDir: params.runtime.workspaceDir,
1902
+ register,
1903
+ pluginConfig: void 0
1904
+ });
1905
+ if (!result.ok) {
1800
1906
  record.status = "error";
1801
- record.error = `plugin failed during register: ${String(err)}`;
1802
- params.registry.plugins.push(record);
1907
+ record.error = result.error;
1803
1908
  params.registry.diagnostics.push({
1804
1909
  level: "error",
1805
1910
  pluginId,
1806
1911
  source,
1807
- message: record.error
1912
+ message: result.error
1808
1913
  });
1809
1914
  }
1915
+ params.registry.plugins.push(record);
1810
1916
  }
1811
1917
  }
1812
1918
  function loadOpenClawPlugins(options) {
@@ -1823,26 +1929,22 @@ function loadOpenClawPlugins(options) {
1823
1929
  diagnostics: [],
1824
1930
  resolvedTools: []
1825
1931
  };
1826
- const toolNameOwners = /* @__PURE__ */ new Map();
1827
- const channelIdOwners = /* @__PURE__ */ new Map();
1828
- const providerIdOwners = /* @__PURE__ */ new Map();
1829
- const resolvedToolNames = /* @__PURE__ */ new Set();
1830
1932
  const reservedToolNames = new Set(options.reservedToolNames ?? []);
1831
1933
  const reservedChannelIds = new Set(options.reservedChannelIds ?? []);
1832
1934
  const reservedProviderIds = new Set(options.reservedProviderIds ?? []);
1833
- appendBundledChannelPlugins({
1834
- registry,
1935
+ const registerRuntime = createPluginRegisterRuntime({
1835
1936
  config: options.config,
1836
- logger,
1837
1937
  workspaceDir,
1838
- toolNameOwners,
1839
- channelIdOwners,
1840
- providerIdOwners,
1841
- resolvedToolNames,
1938
+ logger,
1939
+ registry,
1842
1940
  reservedToolNames,
1843
1941
  reservedChannelIds,
1844
1942
  reservedProviderIds
1845
1943
  });
1944
+ appendBundledChannelPlugins({
1945
+ registry,
1946
+ runtime: registerRuntime
1947
+ });
1846
1948
  if (!loadExternalPlugins) {
1847
1949
  return registry;
1848
1950
  }
@@ -2000,264 +2102,30 @@ function loadOpenClawPlugins(options) {
2000
2102
  });
2001
2103
  continue;
2002
2104
  }
2003
- const pluginRuntime = createPluginRuntime({ workspace: workspaceDir, config: options.config });
2004
- const pluginLogger = buildPluginLogger(logger, pluginId);
2005
- const pushUnsupported = (capability) => {
2006
- registry.diagnostics.push({
2007
- level: "warn",
2008
- pluginId,
2009
- source: candidate.source,
2010
- message: `${capability} is not supported by nextclaw compat layer yet`
2011
- });
2012
- pluginLogger.warn(`${capability} is ignored (not supported yet)`);
2013
- };
2014
- const api = {
2015
- id: pluginId,
2016
- name: record.name,
2017
- version: record.version,
2018
- description: record.description,
2105
+ const registerResult = registerPluginWithApi({
2106
+ runtime: registerRuntime,
2107
+ record,
2108
+ pluginId,
2019
2109
  source: candidate.source,
2020
- config: options.config,
2021
- pluginConfig: validatedConfig.value,
2022
- runtime: pluginRuntime,
2023
- logger: pluginLogger,
2024
- registerTool: (tool, opts) => {
2025
- const declaredNames = opts && Array.isArray(opts.names) ? opts.names : [];
2026
- const names = [...declaredNames, ...opts && opts.name ? [opts.name] : []];
2027
- if (typeof tool !== "function" && typeof tool.name === "string") {
2028
- names.push(tool.name);
2029
- }
2030
- const uniqueNames = Array.from(new Set(names.map((name) => name.trim()).filter(Boolean)));
2031
- const acceptedNames = ensureUniqueNames({
2032
- names: uniqueNames,
2033
- pluginId,
2034
- diagnostics: registry.diagnostics,
2035
- source: candidate.source,
2036
- owners: toolNameOwners,
2037
- reserved: reservedToolNames,
2038
- kind: "tool"
2039
- });
2040
- if (acceptedNames.length === 0) {
2041
- registry.diagnostics.push({
2042
- level: "warn",
2043
- pluginId,
2044
- source: candidate.source,
2045
- message: "tool registration skipped: no available tool names"
2046
- });
2047
- return;
2048
- }
2049
- const factory = typeof tool === "function" ? tool : (_ctx) => tool;
2050
- registry.tools.push({
2051
- pluginId,
2052
- factory,
2053
- names: acceptedNames,
2054
- optional: opts?.optional === true,
2055
- source: candidate.source
2056
- });
2057
- record.toolNames.push(...acceptedNames);
2058
- try {
2059
- const previewTools = normalizeToolList(
2060
- factory({
2061
- config: options.config,
2062
- workspaceDir,
2063
- sandboxed: false
2064
- })
2065
- );
2066
- const byName = new Map(previewTools.map((entry2) => [entry2.name, entry2]));
2067
- for (const name of acceptedNames) {
2068
- const resolvedTool = byName.get(name);
2069
- if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
2070
- continue;
2071
- }
2072
- resolvedToolNames.add(resolvedTool.name);
2073
- registry.resolvedTools.push(resolvedTool);
2074
- }
2075
- } catch (err) {
2076
- registry.diagnostics.push({
2077
- level: "warn",
2078
- pluginId,
2079
- source: candidate.source,
2080
- message: `tool preview failed: ${String(err)}`
2081
- });
2082
- }
2083
- },
2084
- registerChannel: (registration) => {
2085
- const normalizedChannel = registration && typeof registration === "object" && "plugin" in registration ? registration.plugin : registration;
2086
- if (!normalizedChannel || typeof normalizedChannel !== "object") {
2087
- registry.diagnostics.push({
2088
- level: "error",
2089
- pluginId,
2090
- source: candidate.source,
2091
- message: "channel registration missing plugin object"
2092
- });
2093
- return;
2094
- }
2095
- const channelObj = normalizedChannel;
2096
- const rawId = typeof channelObj.id === "string" ? channelObj.id : String(channelObj.id ?? "");
2097
- const accepted = ensureUniqueNames({
2098
- names: [rawId],
2099
- pluginId,
2100
- diagnostics: registry.diagnostics,
2101
- source: candidate.source,
2102
- owners: channelIdOwners,
2103
- reserved: reservedChannelIds,
2104
- kind: "channel"
2105
- });
2106
- if (accepted.length === 0) {
2107
- return;
2108
- }
2109
- const channelPlugin = normalizedChannel;
2110
- registry.channels.push({
2111
- pluginId,
2112
- channel: channelPlugin,
2113
- source: candidate.source
2114
- });
2115
- const channelId = accepted[0];
2116
- record.channelIds.push(channelId);
2117
- const configSchema = channelPlugin.configSchema;
2118
- if (configSchema && typeof configSchema === "object") {
2119
- const schema = configSchema.schema;
2120
- if (schema && typeof schema === "object" && !Array.isArray(schema)) {
2121
- record.configJsonSchema = schema;
2122
- record.configSchema = true;
2123
- }
2124
- const uiHints = configSchema.uiHints;
2125
- if (uiHints && typeof uiHints === "object" && !Array.isArray(uiHints)) {
2126
- record.configUiHints = {
2127
- ...record.configUiHints ?? {},
2128
- ...uiHints
2129
- };
2130
- }
2131
- }
2132
- const pushChannelTools = (value, optional, sourceLabel, resolveValue) => {
2133
- const previewTools = normalizeToolList(value);
2134
- if (previewTools.length === 0) {
2135
- return;
2136
- }
2137
- const declaredNames = previewTools.map((tool) => tool.name);
2138
- const acceptedNames = ensureUniqueNames({
2139
- names: declaredNames,
2140
- pluginId,
2141
- diagnostics: registry.diagnostics,
2142
- source: candidate.source,
2143
- owners: toolNameOwners,
2144
- reserved: reservedToolNames,
2145
- kind: "tool"
2146
- });
2147
- if (acceptedNames.length === 0) {
2148
- return;
2149
- }
2150
- const factory = (ctx) => {
2151
- const tools = normalizeToolList(resolveValue(ctx));
2152
- if (tools.length === 0) {
2153
- return [];
2154
- }
2155
- const byName = new Map(tools.map((tool) => [tool.name, tool]));
2156
- return acceptedNames.map((name) => byName.get(name)).filter(Boolean);
2157
- };
2158
- registry.tools.push({
2159
- pluginId,
2160
- factory,
2161
- names: acceptedNames,
2162
- optional,
2163
- source: candidate.source
2164
- });
2165
- record.toolNames.push(...acceptedNames);
2166
- const previewByName = new Map(previewTools.map((tool) => [tool.name, tool]));
2167
- for (const name of acceptedNames) {
2168
- const resolvedTool = previewByName.get(name);
2169
- if (!resolvedTool || resolvedToolNames.has(resolvedTool.name)) {
2170
- continue;
2171
- }
2172
- resolvedToolNames.add(resolvedTool.name);
2173
- registry.resolvedTools.push(resolvedTool);
2174
- }
2175
- registry.diagnostics.push({
2176
- level: "warn",
2177
- pluginId,
2178
- source: candidate.source,
2179
- message: `${sourceLabel} registered channel-owned tools: ${acceptedNames.join(", ")}`
2180
- });
2181
- };
2182
- const agentTools = channelPlugin.agentTools;
2183
- if (typeof agentTools === "function") {
2184
- pushChannelTools(
2185
- normalizeToolList(agentTools()),
2186
- false,
2187
- `channel "${channelId}"`,
2188
- () => agentTools()
2189
- );
2190
- } else if (agentTools) {
2191
- pushChannelTools(
2192
- normalizeToolList(agentTools),
2193
- false,
2194
- `channel "${channelId}"`,
2195
- () => agentTools
2196
- );
2197
- }
2198
- },
2199
- registerProvider: (provider) => {
2200
- const accepted = ensureUniqueNames({
2201
- names: [provider.id],
2202
- pluginId,
2203
- diagnostics: registry.diagnostics,
2204
- source: candidate.source,
2205
- owners: providerIdOwners,
2206
- reserved: reservedProviderIds,
2207
- kind: "provider"
2208
- });
2209
- if (accepted.length === 0) {
2210
- return;
2211
- }
2212
- registry.providers.push({
2213
- pluginId,
2214
- provider,
2215
- source: candidate.source
2216
- });
2217
- record.providerIds.push(accepted[0]);
2218
- },
2219
- registerHook: () => pushUnsupported("registerHook"),
2220
- registerGatewayMethod: () => pushUnsupported("registerGatewayMethod"),
2221
- registerCli: () => pushUnsupported("registerCli"),
2222
- registerService: () => pushUnsupported("registerService"),
2223
- registerCommand: () => pushUnsupported("registerCommand"),
2224
- registerHttpHandler: () => pushUnsupported("registerHttpHandler"),
2225
- registerHttpRoute: () => pushUnsupported("registerHttpRoute"),
2226
- resolvePath: (input) => {
2227
- const trimmed = input.trim();
2228
- if (!trimmed) {
2229
- return candidate.rootDir;
2230
- }
2231
- if (path4.isAbsolute(trimmed)) {
2232
- return path4.resolve(expandHome2(trimmed));
2233
- }
2234
- return path4.resolve(candidate.rootDir, trimmed);
2235
- }
2236
- };
2237
- try {
2238
- const result = register(api);
2239
- if (result && typeof result === "object" && "then" in result) {
2240
- registry.diagnostics.push({
2241
- level: "warn",
2242
- pluginId,
2243
- source: candidate.source,
2244
- message: "plugin register returned a promise; async registration is ignored"
2245
- });
2246
- }
2247
- registry.plugins.push(record);
2248
- seenIds.set(pluginId, candidate.origin);
2249
- } catch (err) {
2110
+ rootDir: candidate.rootDir,
2111
+ register,
2112
+ pluginConfig: validatedConfig.value
2113
+ });
2114
+ if (!registerResult.ok) {
2250
2115
  record.status = "error";
2251
- record.error = `plugin failed during register: ${String(err)}`;
2252
- registry.plugins.push(record);
2253
- seenIds.set(pluginId, candidate.origin);
2116
+ record.error = registerResult.error;
2254
2117
  registry.diagnostics.push({
2255
2118
  level: "error",
2256
2119
  pluginId,
2257
2120
  source: candidate.source,
2258
- message: record.error
2121
+ message: registerResult.error
2259
2122
  });
2123
+ registry.plugins.push(record);
2124
+ seenIds.set(pluginId, candidate.origin);
2125
+ continue;
2260
2126
  }
2127
+ registry.plugins.push(record);
2128
+ seenIds.set(pluginId, candidate.origin);
2261
2129
  }
2262
2130
  return registry;
2263
2131
  }
@@ -2282,7 +2150,7 @@ function buildPluginStatusReport(params) {
2282
2150
 
2283
2151
  // src/plugins/uninstall.ts
2284
2152
  import fs6 from "fs/promises";
2285
- import path5 from "path";
2153
+ import path6 from "path";
2286
2154
  function isLinkedPathInstall(record) {
2287
2155
  if (!record || record.source !== "path") {
2288
2156
  return false;
@@ -2290,7 +2158,7 @@ function isLinkedPathInstall(record) {
2290
2158
  if (!record.sourcePath || !record.installPath) {
2291
2159
  return true;
2292
2160
  }
2293
- return path5.resolve(record.sourcePath) === path5.resolve(record.installPath);
2161
+ return path6.resolve(record.sourcePath) === path6.resolve(record.installPath);
2294
2162
  }
2295
2163
  function resolveUninstallDirectoryTarget(params) {
2296
2164
  if (!params.hasInstall) {
@@ -2309,7 +2177,7 @@ function resolveUninstallDirectoryTarget(params) {
2309
2177
  if (!configuredPath) {
2310
2178
  return defaultPath;
2311
2179
  }
2312
- if (path5.resolve(configuredPath) === path5.resolve(defaultPath)) {
2180
+ if (path6.resolve(configuredPath) === path6.resolve(defaultPath)) {
2313
2181
  return configuredPath;
2314
2182
  }
2315
2183
  return defaultPath;
@@ -2435,6 +2303,7 @@ export {
2435
2303
  buildChannelConfigSchema,
2436
2304
  buildOauthProviderAuthResult,
2437
2305
  buildPluginStatusReport,
2306
+ createPluginRegisterRuntime,
2438
2307
  createPluginRuntime,
2439
2308
  disablePluginInConfig,
2440
2309
  discoverOpenClawPlugins,
@@ -2456,6 +2325,7 @@ export {
2456
2325
  normalizePluginHttpPath,
2457
2326
  normalizePluginsConfig,
2458
2327
  recordPluginInstall,
2328
+ registerPluginWithApi,
2459
2329
  removePluginFromConfig,
2460
2330
  resolveEnableState,
2461
2331
  resolvePluginChannelMessageToolHints,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/openclaw-compat",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "description": "OpenClaw plugin compatibility layer for NextClaw.",
6
6
  "type": "module",