mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-17 16:12:21 -06:00
78502eda6d
* feat(workers): run device sessions from Gateway bundles Install the current Gateway bundle before a device environment becomes ready, verify it at attach and tunnel boundaries, launch only from the immutable namespaced bundle directory, and retire stale environments for idempotent reprovisioning. Remove the local execution mode and preserve the node-local build claim only as temporary inventory metadata for the final projection/cleanup slice. * docs(runners): record Gateway bundle cutover * test(ci): repair runner validation fixtures # Conflicts: # src/scripts/test-projects.test.ts * fix(workers): surface outdated node recovery Keep legacy runner inventory diagnostic-only while exposing the update-and-reconnect action through node, environment, provider, placement, and Control UI surfaces. * fix(workers): reject legacy inventory with recovery * fix(workers): bundle worker deploy closure * test(workers): close bundle cutover gates * fix(workers): compose browser runtime at build * fix(workers): satisfy bundle cutover gates * fix(workers): route temp runtime through infra * docs(workers): align bundle host guidance * fix(ui): fence outdated session destinations
81 lines
3.6 KiB
TypeScript
81 lines
3.6 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
createWorkerDeployBuildPlugin,
|
|
WORKER_DEPLOY_OPTIONAL_NATIVE_MODULE_ID,
|
|
} from "../../scripts/lib/worker-deploy-build-plugin.mts";
|
|
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
|
|
|
|
const fail = (message: string): never => {
|
|
throw new Error(message);
|
|
};
|
|
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
|
|
|
describe("worker deploy build plugin", () => {
|
|
it("replaces optional host-native modules with a failing virtual module", () => {
|
|
const plugin = createWorkerDeployBuildPlugin();
|
|
|
|
expect(plugin.load(WORKER_DEPLOY_OPTIONAL_NATIVE_MODULE_ID)).toContain(
|
|
"optional host-native dependency unavailable",
|
|
);
|
|
});
|
|
|
|
it("composes the bundled Browser runtime only in the deploy build", () => {
|
|
const bridgePath = path.resolve("src/worker/worker-deploy-browser-runtime.ts");
|
|
const source = fs.readFileSync(bridgePath, "utf8");
|
|
const plugin = createWorkerDeployBuildPlugin();
|
|
|
|
const transformed = plugin.transform.call({ error: fail }, source, bridgePath);
|
|
|
|
expect(transformed).toContain(
|
|
'import { createAttachedBrowserToolRuntime } from "../../extensions/browser/runtime-api.js";',
|
|
);
|
|
expect(transformed).toContain("export default { createAttachedBrowserToolRuntime };");
|
|
expect(transformed).not.toContain("was not composed by the build");
|
|
});
|
|
|
|
it("inlines Playwright package identity without a runtime manifest read", () => {
|
|
const coreBundlePath = path.resolve("node_modules/playwright-core/lib/coreBundle.js");
|
|
const source = fs.readFileSync(coreBundlePath, "utf8");
|
|
const plugin = createWorkerDeployBuildPlugin();
|
|
|
|
const transformed = plugin.transform.call({ error: fail }, source, coreBundlePath);
|
|
|
|
expect(transformed).toContain('packageJSON = {"name":"playwright-core","version":"1.62.1"};');
|
|
expect(transformed).not.toContain(
|
|
'packageJSON = require(import_path9.default.join(packageRoot, "package.json"));',
|
|
);
|
|
expect(transformed).toContain(
|
|
'registry = new Registry({"comment":"Do not edit this file, use utils/roll_browser.js"',
|
|
);
|
|
expect(transformed).not.toContain(
|
|
'registry = new Registry(require(import_path20.default.join(packageRoot, "browsers.json")));',
|
|
);
|
|
});
|
|
|
|
it("matches the canonical dependency path behind a pnpm-style symlink", () => {
|
|
const sourceRoot = path.resolve("node_modules/playwright-core");
|
|
const source = fs.readFileSync(path.join(sourceRoot, "lib/coreBundle.js"), "utf8");
|
|
const tempRoot = tempDirs.make("openclaw-worker-build-plugin-");
|
|
const linkedRoot = path.join(tempRoot, "node_modules", "playwright-core");
|
|
fs.mkdirSync(path.dirname(linkedRoot), { recursive: true });
|
|
fs.symlinkSync(sourceRoot, linkedRoot, process.platform === "win32" ? "junction" : "dir");
|
|
const plugin = createWorkerDeployBuildPlugin(tempRoot);
|
|
const resolvedId = fs.realpathSync(path.join(linkedRoot, "lib/coreBundle.js"));
|
|
|
|
const transformed = plugin.transform.call({ error: fail }, source, resolvedId);
|
|
|
|
expect(transformed).toContain('packageJSON = {"name":"playwright-core","version":"1.62.1"};');
|
|
});
|
|
|
|
it("fails closed when the dependency-owned bootstrap shape changes", () => {
|
|
const coreBundlePath = path.resolve("node_modules/playwright-core/lib/coreBundle.js");
|
|
const plugin = createWorkerDeployBuildPlugin();
|
|
|
|
expect(() =>
|
|
plugin.transform.call({ error: fail }, "changed upstream source", coreBundlePath),
|
|
).toThrow("playwright-core package bootstrap changed");
|
|
});
|
|
});
|