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:
7
.changeset/FN-3717-openclaw-bundle-stabilize.md
Normal file
7
.changeset/FN-3717-openclaw-bundle-stabilize.md
Normal 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.
|
||||||
60
packages/cli/src/__tests__/bundle-output-helpers.test.ts
Normal file
60
packages/cli/src/__tests__/bundle-output-helpers.test.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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`);
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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"}
|
||||||
@@ -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
|
||||||
@@ -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"}
|
||||||
Reference in New Issue
Block a user