Files
openclaw/scripts/lib/worker-deploy-build-plugin.mts
T
Peter Steinberger 78502eda6d feat(workers): run device sessions from Gateway bundles (#124037)
* 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
2026-08-15 17:46:44 -07:00

70 lines
2.9 KiB
TypeScript

import fs from "node:fs";
import path from "node:path";
const WORKER_DEPLOY_BUILD_PLUGIN_NAME = "openclaw:worker-deploy";
export const WORKER_DEPLOY_OPTIONAL_NATIVE_MODULE_ID = `${path.resolve("src/worker/worker-deploy-runtime.ts")}?optional-native`;
const PLAYWRIGHT_PACKAGE_INIT = ` packageRoot = import_path9.default.join(__dirname, "..");
packageJSON = require(import_path9.default.join(packageRoot, "package.json"));
binPath = import_path9.default.join(packageRoot, "bin");`;
const PLAYWRIGHT_BROWSER_REGISTRY_INIT =
' registry = new Registry(require(import_path20.default.join(packageRoot, "browsers.json")));';
const WORKER_BROWSER_RUNTIME_COMPOSITION = `import { createAttachedBrowserToolRuntime } from "../../extensions/browser/runtime-api.js";
export default { createAttachedBrowserToolRuntime };`;
/** Composes bundled-plugin runtime and removes dependency package reads from the worker build. */
export function createWorkerDeployBuildPlugin(rootDir = process.cwd()) {
const playwrightRoot = fs.realpathSync(path.resolve(rootDir, "node_modules/playwright-core"));
const coreBundlePath = fs.realpathSync(path.join(playwrightRoot, "lib/coreBundle.js"));
const browserRuntimeBridgePath = fs.realpathSync(
path.resolve("src/worker/worker-deploy-browser-runtime.ts"),
);
const packageJson = JSON.parse(
fs.readFileSync(path.join(playwrightRoot, "package.json"), "utf8"),
) as { name: string; version: string };
const browsersJson = JSON.parse(
fs.readFileSync(path.join(playwrightRoot, "browsers.json"), "utf8"),
) as unknown;
const replacement = ` packageRoot = __dirname;
packageJSON = ${JSON.stringify({ name: packageJson.name, version: packageJson.version })};
binPath = packageRoot;`;
return {
name: WORKER_DEPLOY_BUILD_PLUGIN_NAME,
load(id: string) {
return id === WORKER_DEPLOY_OPTIONAL_NATIVE_MODULE_ID
? 'throw new Error("optional host-native dependency unavailable in portable worker runtime");'
: null;
},
transform(this: { error(message: string): never }, code: string, id: string) {
let resolvedId: string;
try {
resolvedId = fs.realpathSync(path.resolve(id));
} catch {
return null;
}
if (resolvedId === browserRuntimeBridgePath) {
return WORKER_BROWSER_RUNTIME_COMPOSITION;
}
if (
resolvedId !== coreBundlePath ||
!id.replaceAll("\\", "/").endsWith("/playwright-core/lib/coreBundle.js")
) {
return null;
}
if (
!code.includes(PLAYWRIGHT_PACKAGE_INIT) ||
!code.includes(PLAYWRIGHT_BROWSER_REGISTRY_INIT)
) {
this.error("playwright-core package bootstrap changed; update the worker deploy transform");
}
return code
.replace(PLAYWRIGHT_PACKAGE_INIT, replacement)
.replace(
PLAYWRIGHT_BROWSER_REGISTRY_INIT,
` registry = new Registry(${JSON.stringify(browsersJson)});`,
);
},
};
}