@nextclaw/openclaw-compat 0.1.4 → 0.1.6

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
  };
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) {
@@ -291,7 +291,6 @@ async function stopPluginChannelGateways(handles) {
291
291
  // src/plugins/discovery.ts
292
292
  import fs2 from "fs";
293
293
  import path2 from "path";
294
- import { homedir } from "os";
295
294
  import { expandHome, getDataPath } from "@nextclaw/core";
296
295
 
297
296
  // src/plugins/manifest.ts
@@ -606,7 +605,7 @@ function discoverOpenClawPlugins(params) {
606
605
  }
607
606
  if (workspaceDir) {
608
607
  discoverInDirectory({
609
- dir: path2.join(workspaceDir, ".openclaw", "extensions"),
608
+ dir: path2.join(workspaceDir, ".nextclaw", "extensions"),
610
609
  origin: "workspace",
611
610
  workspaceDir,
612
611
  candidates,
@@ -621,13 +620,6 @@ function discoverOpenClawPlugins(params) {
621
620
  diagnostics,
622
621
  seen
623
622
  });
624
- discoverInDirectory({
625
- dir: path2.join(homedir(), ".openclaw", "extensions"),
626
- origin: "global",
627
- candidates,
628
- diagnostics,
629
- seen
630
- });
631
623
  return { candidates, diagnostics };
632
624
  }
633
625
 
@@ -1301,6 +1293,132 @@ function validateJsonSchemaValue(params) {
1301
1293
  return { ok: false, errors: formatAjvErrors(cached.validate.errors) };
1302
1294
  }
1303
1295
 
1296
+ // src/plugins/bundled/channels/factory.ts
1297
+ import { listBuiltinChannelPlugins } from "@nextclaw/core";
1298
+ var EMPTY_PLUGIN_CONFIG_SCHEMA = {
1299
+ type: "object",
1300
+ additionalProperties: false,
1301
+ properties: {}
1302
+ };
1303
+ function resolveBuiltinChannelPlugin(channelId) {
1304
+ const plugin10 = listBuiltinChannelPlugins().find((entry) => entry.id === channelId);
1305
+ if (!plugin10) {
1306
+ throw new Error(`builtin channel plugin not found: ${channelId}`);
1307
+ }
1308
+ return plugin10;
1309
+ }
1310
+ function createBundledChannelPlugin(params) {
1311
+ const pluginId = `builtin-channel-${params.channelId}`;
1312
+ const sourceDescription = params.description ?? `Builtin NextClaw channel plugin for ${params.channelId}`;
1313
+ return {
1314
+ id: pluginId,
1315
+ name: params.name,
1316
+ description: sourceDescription,
1317
+ configSchema: EMPTY_PLUGIN_CONFIG_SCHEMA,
1318
+ register(api) {
1319
+ const builtin = resolveBuiltinChannelPlugin(params.channelId);
1320
+ api.registerChannel({
1321
+ plugin: {
1322
+ id: params.channelId,
1323
+ nextclaw: {
1324
+ isEnabled: builtin.isEnabled,
1325
+ createChannel: builtin.create
1326
+ }
1327
+ }
1328
+ });
1329
+ }
1330
+ };
1331
+ }
1332
+
1333
+ // src/plugins/bundled/channels/telegram.ts
1334
+ var plugin = createBundledChannelPlugin({
1335
+ channelId: "telegram",
1336
+ name: "Builtin Telegram Channel",
1337
+ description: "Builtin NextClaw channel plugin for telegram"
1338
+ });
1339
+ var telegram_default = plugin;
1340
+
1341
+ // src/plugins/bundled/channels/whatsapp.ts
1342
+ var plugin2 = createBundledChannelPlugin({
1343
+ channelId: "whatsapp",
1344
+ name: "Builtin WhatsApp Channel",
1345
+ description: "Builtin NextClaw channel plugin for whatsapp"
1346
+ });
1347
+ var whatsapp_default = plugin2;
1348
+
1349
+ // src/plugins/bundled/channels/discord.ts
1350
+ var plugin3 = createBundledChannelPlugin({
1351
+ channelId: "discord",
1352
+ name: "Builtin Discord Channel",
1353
+ description: "Builtin NextClaw channel plugin for discord"
1354
+ });
1355
+ var discord_default = plugin3;
1356
+
1357
+ // src/plugins/bundled/channels/feishu.ts
1358
+ var plugin4 = createBundledChannelPlugin({
1359
+ channelId: "feishu",
1360
+ name: "Builtin Feishu Channel",
1361
+ description: "Builtin NextClaw channel plugin for feishu"
1362
+ });
1363
+ var feishu_default = plugin4;
1364
+
1365
+ // src/plugins/bundled/channels/mochat.ts
1366
+ var plugin5 = createBundledChannelPlugin({
1367
+ channelId: "mochat",
1368
+ name: "Builtin Mochat Channel",
1369
+ description: "Builtin NextClaw channel plugin for mochat"
1370
+ });
1371
+ var mochat_default = plugin5;
1372
+
1373
+ // src/plugins/bundled/channels/dingtalk.ts
1374
+ var plugin6 = createBundledChannelPlugin({
1375
+ channelId: "dingtalk",
1376
+ name: "Builtin DingTalk Channel",
1377
+ description: "Builtin NextClaw channel plugin for dingtalk"
1378
+ });
1379
+ var dingtalk_default = plugin6;
1380
+
1381
+ // src/plugins/bundled/channels/email.ts
1382
+ var plugin7 = createBundledChannelPlugin({
1383
+ channelId: "email",
1384
+ name: "Builtin Email Channel",
1385
+ description: "Builtin NextClaw channel plugin for email"
1386
+ });
1387
+ var email_default = plugin7;
1388
+
1389
+ // src/plugins/bundled/channels/slack.ts
1390
+ var plugin8 = createBundledChannelPlugin({
1391
+ channelId: "slack",
1392
+ name: "Builtin Slack Channel",
1393
+ description: "Builtin NextClaw channel plugin for slack"
1394
+ });
1395
+ var slack_default = plugin8;
1396
+
1397
+ // src/plugins/bundled/channels/qq.ts
1398
+ var plugin9 = createBundledChannelPlugin({
1399
+ channelId: "qq",
1400
+ name: "Builtin QQ Channel",
1401
+ description: "Builtin NextClaw channel plugin for qq"
1402
+ });
1403
+ var qq_default = plugin9;
1404
+
1405
+ // src/plugins/bundled/channels/index.ts
1406
+ var BUNDLED_CHANNEL_PLUGINS = [
1407
+ telegram_default,
1408
+ whatsapp_default,
1409
+ discord_default,
1410
+ feishu_default,
1411
+ mochat_default,
1412
+ dingtalk_default,
1413
+ email_default,
1414
+ slack_default,
1415
+ qq_default
1416
+ ];
1417
+ function listBundledChannelPluginDefinitions() {
1418
+ return [...BUNDLED_CHANNEL_PLUGINS];
1419
+ }
1420
+ var BUNDLED_CHANNEL_PLUGIN_IDS = BUNDLED_CHANNEL_PLUGINS.map((plugin10) => plugin10.id).filter((id) => typeof id === "string" && id.trim().length > 0);
1421
+
1304
1422
  // src/plugins/loader.ts
1305
1423
  var createJiti = createJitiImport;
1306
1424
  var defaultLogger2 = {
@@ -1454,17 +1572,245 @@ function validatePluginConfig(params) {
1454
1572
  }
1455
1573
  return { ok: false, errors: result.errors };
1456
1574
  }
1457
- function loadOpenClawPlugins(options) {
1458
- if (process.env.NEXTCLAW_ENABLE_OPENCLAW_PLUGINS !== "1") {
1459
- return {
1460
- plugins: [],
1461
- tools: [],
1462
- channels: [],
1463
- providers: [],
1464
- diagnostics: [],
1465
- resolvedTools: []
1575
+ function appendBundledChannelPlugins(params) {
1576
+ for (const definition of listBundledChannelPluginDefinitions()) {
1577
+ const pluginId = typeof definition.id === "string" ? definition.id.trim() : "";
1578
+ const source = `builtin:nextclaw-openclaw-compat/channels/${pluginId || "unknown"}`;
1579
+ if (!pluginId) {
1580
+ params.registry.diagnostics.push({
1581
+ level: "error",
1582
+ source,
1583
+ message: "bundled plugin definition missing id"
1584
+ });
1585
+ continue;
1586
+ }
1587
+ const record = createPluginRecord({
1588
+ id: pluginId,
1589
+ name: definition.name ?? pluginId,
1590
+ description: definition.description,
1591
+ version: definition.version,
1592
+ kind: definition.kind,
1593
+ source,
1594
+ origin: "bundled",
1595
+ workspaceDir: params.workspaceDir,
1596
+ enabled: true,
1597
+ configSchema: Boolean(definition.configSchema),
1598
+ configJsonSchema: definition.configSchema
1599
+ });
1600
+ const register = definition.register ?? definition.activate;
1601
+ if (typeof register !== "function") {
1602
+ record.status = "error";
1603
+ record.error = "plugin export missing register/activate";
1604
+ params.registry.plugins.push(record);
1605
+ params.registry.diagnostics.push({
1606
+ level: "error",
1607
+ pluginId,
1608
+ source,
1609
+ message: record.error
1610
+ });
1611
+ continue;
1612
+ }
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)`);
1466
1623
  };
1624
+ const api = {
1625
+ id: pluginId,
1626
+ name: record.name,
1627
+ version: record.version,
1628
+ description: record.description,
1629
+ 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) {
1800
+ record.status = "error";
1801
+ record.error = `plugin failed during register: ${String(err)}`;
1802
+ params.registry.plugins.push(record);
1803
+ params.registry.diagnostics.push({
1804
+ level: "error",
1805
+ pluginId,
1806
+ source,
1807
+ message: record.error
1808
+ });
1809
+ }
1467
1810
  }
1811
+ }
1812
+ function loadOpenClawPlugins(options) {
1813
+ const loadExternalPlugins = process.env.NEXTCLAW_ENABLE_OPENCLAW_PLUGINS !== "0";
1468
1814
  const logger = options.logger ?? defaultLogger2;
1469
1815
  const workspaceDir = options.workspaceDir?.trim() || getWorkspacePathFromConfig(options.config);
1470
1816
  const normalized = normalizePluginsConfig(options.config.plugins);
@@ -1484,6 +1830,22 @@ function loadOpenClawPlugins(options) {
1484
1830
  const reservedToolNames = new Set(options.reservedToolNames ?? []);
1485
1831
  const reservedChannelIds = new Set(options.reservedChannelIds ?? []);
1486
1832
  const reservedProviderIds = new Set(options.reservedProviderIds ?? []);
1833
+ appendBundledChannelPlugins({
1834
+ registry,
1835
+ config: options.config,
1836
+ logger,
1837
+ workspaceDir,
1838
+ toolNameOwners,
1839
+ channelIdOwners,
1840
+ providerIdOwners,
1841
+ resolvedToolNames,
1842
+ reservedToolNames,
1843
+ reservedChannelIds,
1844
+ reservedProviderIds
1845
+ });
1846
+ if (!loadExternalPlugins) {
1847
+ return registry;
1848
+ }
1487
1849
  const discovery = discoverOpenClawPlugins({
1488
1850
  config: options.config,
1489
1851
  workspaceDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/openclaw-compat",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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.5.3"
21
+ "@nextclaw/core": "^0.6.16"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.17.6",