



























@@ -1454,6 +1454,181 @@ module.exports = {
14541454expect(registry.plugins.find((entry) => entry.id === "alpha")?.status).toBe("loaded");
14551455});
145614561457+it("loads bundled plugins with plugin-sdk imports from an external stage dir", () => {
1458+const packageRoot = makeTempDir();
1459+const stageDir = makeTempDir();
1460+const bundledDir = path.join(packageRoot, "dist", "extensions");
1461+const pluginRoot = path.join(bundledDir, "telegram");
1462+fs.mkdirSync(path.join(packageRoot, "dist", "plugin-sdk"), { recursive: true });
1463+fs.mkdirSync(pluginRoot, { recursive: true });
1464+fs.writeFileSync(
1465+path.join(packageRoot, "package.json"),
1466+JSON.stringify({ name: "openclaw", version: "2026.4.22", type: "module" }),
1467+"utf-8",
1468+);
1469+fs.writeFileSync(
1470+path.join(packageRoot, "dist", "plugin-sdk", "text-runtime.js"),
1471+[
1472+`export function normalizeLowercaseStringOrEmpty(value) {`,
1473+` return typeof value === "string" ? value.toLowerCase() : "";`,
1474+`}`,
1475+"",
1476+].join("\n"),
1477+"utf-8",
1478+);
1479+fs.writeFileSync(
1480+path.join(pluginRoot, "index.js"),
1481+[
1482+`import runtimeDep from "external-runtime";`,
1483+`import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";`,
1484+`export default {`,
1485+` id: "telegram",`,
1486+` register(api) {`,
1487+` api.registerCommand({`,
1488+` name: "external-runtime",`,
1489+` handler: () => normalizeLowercaseStringOrEmpty(runtimeDep.marker),`,
1490+` });`,
1491+` },`,
1492+`};`,
1493+"",
1494+].join("\n"),
1495+"utf-8",
1496+);
1497+fs.writeFileSync(
1498+path.join(pluginRoot, "package.json"),
1499+JSON.stringify(
1500+{
1501+name: "@openclaw/telegram",
1502+version: "1.0.0",
1503+type: "module",
1504+dependencies: {
1505+"external-runtime": "1.0.0",
1506+},
1507+openclaw: { extensions: ["./index.js"] },
1508+},
1509+null,
1510+2,
1511+),
1512+"utf-8",
1513+);
1514+fs.writeFileSync(
1515+path.join(pluginRoot, "openclaw.plugin.json"),
1516+JSON.stringify(
1517+{
1518+id: "telegram",
1519+enabledByDefault: true,
1520+configSchema: EMPTY_PLUGIN_SCHEMA,
1521+},
1522+null,
1523+2,
1524+),
1525+"utf-8",
1526+);
1527+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
1528+process.env.OPENCLAW_PLUGIN_STAGE_DIR = stageDir;
1529+1530+const registry = loadOpenClawPlugins({
1531+cache: false,
1532+config: {
1533+plugins: {
1534+enabled: true,
1535+},
1536+},
1537+bundledRuntimeDepsInstaller: ({ installRoot }) => {
1538+const depRoot = path.join(installRoot, "node_modules", "external-runtime");
1539+fs.mkdirSync(depRoot, { recursive: true });
1540+fs.writeFileSync(
1541+path.join(depRoot, "package.json"),
1542+JSON.stringify({
1543+name: "external-runtime",
1544+version: "1.0.0",
1545+type: "module",
1546+exports: "./index.js",
1547+}),
1548+"utf-8",
1549+);
1550+fs.writeFileSync(
1551+path.join(depRoot, "index.js"),
1552+"export default { marker: 'SDK-OK' };\n",
1553+"utf-8",
1554+);
1555+},
1556+});
1557+1558+expect(registry.plugins.find((entry) => entry.id === "telegram")?.status).toBe("loaded");
1559+});
1560+1561+it("loads bundled plugins with plugin-sdk imports from a package dist root", () => {
1562+const packageRoot = makeTempDir();
1563+const bundledDir = path.join(packageRoot, "dist", "extensions");
1564+const pluginRoot = path.join(bundledDir, "discord");
1565+fs.mkdirSync(path.join(packageRoot, "dist", "plugin-sdk"), { recursive: true });
1566+fs.mkdirSync(pluginRoot, { recursive: true });
1567+fs.writeFileSync(
1568+path.join(packageRoot, "package.json"),
1569+JSON.stringify({ name: "openclaw", version: "2026.4.22", type: "module" }),
1570+"utf-8",
1571+);
1572+fs.writeFileSync(
1573+path.join(packageRoot, "dist", "plugin-sdk", "text-runtime.js"),
1574+"export const normalizeLowercaseStringOrEmpty = (value) => String(value).toLowerCase();\n",
1575+"utf-8",
1576+);
1577+fs.writeFileSync(
1578+path.join(pluginRoot, "index.js"),
1579+[
1580+`import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";`,
1581+`export default {`,
1582+` id: "discord",`,
1583+` register(api) {`,
1584+` api.registerCommand({ name: normalizeLowercaseStringOrEmpty("DISCORD"), handler: () => "ok" });`,
1585+` },`,
1586+`};`,
1587+"",
1588+].join("\n"),
1589+"utf-8",
1590+);
1591+fs.writeFileSync(
1592+path.join(pluginRoot, "package.json"),
1593+JSON.stringify(
1594+{
1595+name: "@openclaw/discord",
1596+version: "1.0.0",
1597+type: "module",
1598+openclaw: { extensions: ["./index.js"] },
1599+},
1600+null,
1601+2,
1602+),
1603+"utf-8",
1604+);
1605+fs.writeFileSync(
1606+path.join(pluginRoot, "openclaw.plugin.json"),
1607+JSON.stringify(
1608+{
1609+id: "discord",
1610+enabledByDefault: true,
1611+configSchema: EMPTY_PLUGIN_SCHEMA,
1612+},
1613+null,
1614+2,
1615+),
1616+"utf-8",
1617+);
1618+process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir;
1619+1620+const registry = loadOpenClawPlugins({
1621+cache: false,
1622+config: {
1623+plugins: {
1624+enabled: true,
1625+},
1626+},
1627+});
1628+1629+expect(registry.plugins.find((entry) => entry.id === "discord")?.status).toBe("loaded");
1630+});
1631+14571632it("loads dist-runtime wrappers from an external stage dir", () => {
14581633const packageRoot = makeTempDir();
14591634const stageDir = makeTempDir();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。