feat(FN-3717): gate bootstrap on openclaw bridge asset

Stabilizes the OpenClaw bundle by hardening the asset copy logic and gating the bootstrap flow on the openclaw bridge asset being present, with regression tests covering the new bundle-output helpers and a patch changeset for `@runfusion/fusion`.

Fusion-Task-Id: FN-3717
This commit is contained in:
Fusion
2026-05-07 18:56:46 -07:00
committed by gsxdsm
parent c0ed278a4d
commit a732ebb8c9
8 changed files with 92 additions and 8 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
Stabilize CLI bundle-output test for the fusion-plugin-openclaw-runtime
`mcp-schema-server.cjs` bridge asset on clean checkouts and fail loudly
in tsup if the source asset is missing.

View File

@@ -0,0 +1,60 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const state = {
existingPaths: new Set<string>(),
indexHtml: "",
};
vi.mock("node:fs", () => ({
existsSync: (path: string) => state.existingPaths.has(path),
readFileSync: () => state.indexHtml,
execFileSync: vi.fn(),
execSync: vi.fn(),
}));
import {
bundlePath,
clientIndexPath,
dashboardClientStubMarker,
hasBuiltDashboardAssets,
openclawMcpSchemaServerPath,
} from "./bundle-output-helpers";
const cursorPluginManifestPath = bundlePath.replace(
"dist/bin.js",
"dist/plugins/fusion-plugin-cursor-runtime/manifest.json",
);
describe("hasBuiltDashboardAssets", () => {
beforeEach(() => {
state.existingPaths.clear();
state.indexHtml = "<html><body><script src=\"assets/app.js\"></script></body></html>";
});
it("returns false when openclaw mcp-schema-server.cjs is missing", () => {
state.existingPaths.add(bundlePath);
state.existingPaths.add(clientIndexPath);
state.existingPaths.add(cursorPluginManifestPath);
expect(hasBuiltDashboardAssets()).toBe(false);
});
it("returns true when all required assets exist and dashboard stub marker is absent", () => {
state.existingPaths.add(bundlePath);
state.existingPaths.add(clientIndexPath);
state.existingPaths.add(cursorPluginManifestPath);
state.existingPaths.add(openclawMcpSchemaServerPath);
expect(hasBuiltDashboardAssets()).toBe(true);
});
it("returns false when dashboard client index contains stub marker", () => {
state.existingPaths.add(bundlePath);
state.existingPaths.add(clientIndexPath);
state.existingPaths.add(cursorPluginManifestPath);
state.existingPaths.add(openclawMcpSchemaServerPath);
state.indexHtml = dashboardClientStubMarker;
expect(hasBuiltDashboardAssets()).toBe(false);
});
});

View File

@@ -7,6 +7,13 @@ export const workspaceRoot = join(cliRoot, "..", "..");
export const bundlePath = join(cliRoot, "dist", "bin.js"); export const bundlePath = join(cliRoot, "dist", "bin.js");
export const clientIndexPath = join(cliRoot, "dist", "client", "index.html"); export const clientIndexPath = join(cliRoot, "dist", "client", "index.html");
const cursorPluginManifestPath = join(cliRoot, "dist", "plugins", "fusion-plugin-cursor-runtime", "manifest.json"); const cursorPluginManifestPath = join(cliRoot, "dist", "plugins", "fusion-plugin-cursor-runtime", "manifest.json");
export const openclawMcpSchemaServerPath = join(
cliRoot,
"dist",
"plugins",
"fusion-plugin-openclaw-runtime",
"mcp-schema-server.cjs",
);
export const dashboardClientStubMarker = "Dashboard assets not built"; export const dashboardClientStubMarker = "Dashboard assets not built";
@@ -28,8 +35,13 @@ function runBuildCommand(command: string, cwd: string) {
}); });
} }
function hasBuiltDashboardAssets(): boolean { export function hasBuiltDashboardAssets(): boolean {
if (!existsSync(bundlePath) || !existsSync(clientIndexPath) || !existsSync(cursorPluginManifestPath)) { if (
!existsSync(bundlePath) ||
!existsSync(clientIndexPath) ||
!existsSync(cursorPluginManifestPath) ||
!existsSync(openclawMcpSchemaServerPath)
) {
return false; return false;
} }

View File

@@ -216,9 +216,12 @@ export default defineConfig({
if (pluginId === "fusion-plugin-openclaw-runtime") { if (pluginId === "fusion-plugin-openclaw-runtime") {
const mcpServerAsset = join(pluginSrcDir, "src", "mcp-schema-server.cjs"); const mcpServerAsset = join(pluginSrcDir, "src", "mcp-schema-server.cjs");
if (existsSync(mcpServerAsset)) { if (!existsSync(mcpServerAsset)) {
cpSync(mcpServerAsset, join(pluginDestDir, "mcp-schema-server.cjs")); throw new Error(
`[tsup] Missing required openclaw bridge asset at ${mcpServerAsset}; expected committed source file mcp-schema-server.cjs.`,
);
} }
cpSync(mcpServerAsset, join(pluginDestDir, "mcp-schema-server.cjs"));
} }
console.log(`Bundled runtime plugin ${pluginId} to dist/plugins/${pluginId}/bundled.js`); console.log(`Bundled runtime plugin ${pluginId} to dist/plugins/${pluginId}/bundled.js`);

View File

@@ -12,8 +12,9 @@ declare const plugin: FusionPlugin;
export default plugin; export default plugin;
export { openclawRuntimeMetadata, openclawRuntimeFactory, OPENCLAW_RUNTIME_ID }; export { openclawRuntimeMetadata, openclawRuntimeFactory, OPENCLAW_RUNTIME_ID };
export { OpenClawRuntimeAdapter } from "./runtime-adapter.js"; export { OpenClawRuntimeAdapter } from "./runtime-adapter.js";
export { resolveCliConfig, buildOpenClawArgs, createCliSession, promptCli, describeCliModel, extractStderrError, } from "./pi-module.js"; export { resolveCliConfig, buildOpenClawArgs, createCliSession, promptCli, describeCliModel, extractStderrError, configureOpenClawMcpServer, } from "./pi-module.js";
export type { CliConfig, GatewaySession, OpenClawAgentJson } from "./types.js"; export type { CliConfig, GatewaySession, OpenClawAgentJson } from "./types.js";
export { toolsToMcpToolDefs, writeOpenClawMcpBridgeFiles, } from "./mcp-config.js";
export { probeOpenClawBinary } from "./probe.js"; export { probeOpenClawBinary } from "./probe.js";
export type { OpenClawBinaryStatus } from "./probe.js"; export type { OpenClawBinaryStatus } from "./probe.js";
//# sourceMappingURL=index.d.ts.map //# sourceMappingURL=index.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,YAAY,EAEZ,oBAAoB,EACpB,6BAA6B,EAC9B,MAAM,oBAAoB,CAAC;AAE5B,QAAA,MAAM,mBAAmB,aAAa,CAAC;AAGvC,QAAA,MAAM,uBAAuB,EAAE,6BAK9B,CAAC;AAEF,QAAA,MAAM,sBAAsB,EAAE,oBAE7B,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE,YAqCZ,CAAC;AAEH,eAAe,MAAM,CAAC;AAItB,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"} {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,YAAY,EAEZ,oBAAoB,EACpB,6BAA6B,EAC9B,MAAM,oBAAoB,CAAC;AAE5B,QAAA,MAAM,mBAAmB,aAAa,CAAC;AAGvC,QAAA,MAAM,uBAAuB,EAAE,6BAK9B,CAAC;AAEF,QAAA,MAAM,sBAAsB,EAAE,oBAE7B,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE,YAqCZ,CAAC;AAEH,eAAe,MAAM,CAAC;AAItB,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"}

View File

@@ -57,7 +57,8 @@ export default plugin;
// ── Public exports ──────────────────────────────────────────────────────────── // ── Public exports ────────────────────────────────────────────────────────────
export { openclawRuntimeMetadata, openclawRuntimeFactory, OPENCLAW_RUNTIME_ID }; export { openclawRuntimeMetadata, openclawRuntimeFactory, OPENCLAW_RUNTIME_ID };
export { OpenClawRuntimeAdapter } from "./runtime-adapter.js"; export { OpenClawRuntimeAdapter } from "./runtime-adapter.js";
export { resolveCliConfig, buildOpenClawArgs, createCliSession, promptCli, describeCliModel, extractStderrError, } from "./pi-module.js"; export { resolveCliConfig, buildOpenClawArgs, createCliSession, promptCli, describeCliModel, extractStderrError, configureOpenClawMcpServer, } from "./pi-module.js";
export { toolsToMcpToolDefs, writeOpenClawMcpBridgeFiles, } from "./mcp-config.js";
// Probe re-export for the dashboard's runtime-provider-probes façade. // Probe re-export for the dashboard's runtime-provider-probes façade.
export { probeOpenClawBinary } from "./probe.js"; export { probeOpenClawBinary } from "./probe.js";
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQjD,MAAM,mBAAmB,GAAG,UAAU,CAAC;AACvC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEzC,MAAM,uBAAuB,GAAkC;IAC7D,SAAS,EAAE,mBAAmB;IAC9B,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,qDAAqD;IAClE,OAAO,EAAE,wBAAwB;CAClC,CAAC;AAEF,MAAM,sBAAsB,GAAyB,KAAK,EAAE,GAAmB,EAAE,EAAE;IACjF,OAAO,IAAI,sBAAsB,CAAC,GAAG,EAAE,QAA+C,CAAC,CAAC;AAC1F,CAAC,CAAC;AAEF,MAAM,MAAM,GAAiB,YAAY,CAAC;IACxC,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,IAAI,EAAE,yBAAyB;QAC/B,OAAO,EAAE,wBAAwB;QACjC,WAAW,EACT,2GAA2G;QAC7G,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,2BAA2B;QACrC,OAAO,EAAE,uBAAuB;KACjC;IACD,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE;QACL,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3E,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,KAAK,CAAC,SAAS;gBACb,CAAC,CAAC,2CAA2C,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC7G,CAAC,CAAC,2DAA2D,KAAK,CAAC,MAAM,IAAI,SAAS,EAAE,CAC3F,CAAC;YACF,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE;gBACvC,SAAS,EAAE,mBAAmB;gBAC9B,OAAO,EAAE,wBAAwB;gBACjC,eAAe,EAAE,KAAK,CAAC,SAAS;gBAChC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU;aAClD,CAAC,CAAC;QACL,CAAC;QACD,QAAQ,EAAE,GAAG,EAAE;YACb,2EAA2E;QAC7E,CAAC;KACF;IACD,OAAO,EAAE;QACP,QAAQ,EAAE,uBAAuB;QACjC,OAAO,EAAE,sBAAsB;KAChC;CACF,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC;AAEtB,iFAAiF;AAEjF,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,sEAAsE;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQjD,MAAM,mBAAmB,GAAG,UAAU,CAAC;AACvC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEzC,MAAM,uBAAuB,GAAkC;IAC7D,SAAS,EAAE,mBAAmB;IAC9B,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,qDAAqD;IAClE,OAAO,EAAE,wBAAwB;CAClC,CAAC;AAEF,MAAM,sBAAsB,GAAyB,KAAK,EAAE,GAAmB,EAAE,EAAE;IACjF,OAAO,IAAI,sBAAsB,CAAC,GAAG,EAAE,QAA+C,CAAC,CAAC;AAC1F,CAAC,CAAC;AAEF,MAAM,MAAM,GAAiB,YAAY,CAAC;IACxC,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,IAAI,EAAE,yBAAyB;QAC/B,OAAO,EAAE,wBAAwB;QACjC,WAAW,EACT,2GAA2G;QAC7G,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,2BAA2B;QACrC,OAAO,EAAE,uBAAuB;KACjC;IACD,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE;QACL,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3E,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,KAAK,CAAC,SAAS;gBACb,CAAC,CAAC,2CAA2C,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC7G,CAAC,CAAC,2DAA2D,KAAK,CAAC,MAAM,IAAI,SAAS,EAAE,CAC3F,CAAC;YACF,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE;gBACvC,SAAS,EAAE,mBAAmB;gBAC9B,OAAO,EAAE,wBAAwB;gBACjC,eAAe,EAAE,KAAK,CAAC,SAAS;gBAChC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU;aAClD,CAAC,CAAC;QACL,CAAC;QACD,QAAQ,EAAE,GAAG,EAAE;YACb,2EAA2E;QAC7E,CAAC;KACF;IACD,OAAO,EAAE;QACP,QAAQ,EAAE,uBAAuB;QACjC,OAAO,EAAE,sBAAsB;KAChC;CACF,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC;AAEtB,iFAAiF;AAEjF,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAEzB,sEAAsE;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}