From ff2df1f70fb30b5539fc7846dd8e75c22c2c2918 Mon Sep 17 00:00:00 2001 From: AstroHan Date: Fri, 9 Oct 2026 12:00:43 +1000 Subject: [PATCH] fix(runtime): emit the filesystem worker bundle as .mjs The worker bundle was emitted as dist/workers/filesystem-worker.js, so Node walked up to the nearest package.json to decide the module type. Inside the Windows AppContainer sandbox that read is denied, and the worker crashed at launch with ERR_INVALID_PACKAGE_CONFIG. The windows_sandbox_w0_protocol job has failed on main because of it. An .mjs bundle is ESM by extension, so Node never performs the lookup. The build and desktop copy scripts now take the file name from FILESYSTEM_WORKER_BUNDLE_NAME so the producer cannot drift from the resolver; packaging verifiers keep literal paths because they check the shipped layout independently. Split out of #5969, which carries the same rename. Generated-by: Claude Code --- apps/desktop/electron-builder.config.mjs | 4 ++-- .../scripts/copy-runtime-filesystem-worker.mjs | 5 +++-- .../runtime/scripts/build-filesystem-worker.mjs | 3 ++- .../__tests__/filesystem-worker-client.test.ts | 16 ++++++++-------- .../runtime/src/__tests__/linux-sandbox.test.ts | 6 +++--- .../src/filesystem-worker/resource-resolver.ts | 4 +++- scripts/release-cli-package.mjs | 6 +++--- scripts/smoke-release-cli-package.mjs | 2 +- scripts/verify-macos-dmg.mjs | 2 +- scripts/verify-packaged-app.mjs | 2 +- scripts/verify-windows-sandbox-e2e.mjs | 4 ++-- scripts/windows-smoke.mjs | 2 +- 12 files changed, 30 insertions(+), 26 deletions(-) diff --git a/apps/desktop/electron-builder.config.mjs b/apps/desktop/electron-builder.config.mjs index 2479e7fd62a..272bb3915e0 100644 --- a/apps/desktop/electron-builder.config.mjs +++ b/apps/desktop/electron-builder.config.mjs @@ -132,8 +132,8 @@ const baseDesktopBuilderConfig = { to: 'status', }, { - from: 'resources/workers/filesystem-worker.js', - to: 'workers/filesystem-worker.js', + from: 'resources/workers/filesystem-worker.mjs', + to: 'workers/filesystem-worker.mjs', }, { from: '../../native/runtime-host-peer/target/release/maka_runtime_host_peer.node', diff --git a/apps/desktop/scripts/copy-runtime-filesystem-worker.mjs b/apps/desktop/scripts/copy-runtime-filesystem-worker.mjs index a04ad3f09cd..d2eecdada3b 100644 --- a/apps/desktop/scripts/copy-runtime-filesystem-worker.mjs +++ b/apps/desktop/scripts/copy-runtime-filesystem-worker.mjs @@ -20,10 +20,11 @@ import { copyFile, mkdir, stat } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { FILESYSTEM_WORKER_BUNDLE_NAME } from '../../../packages/runtime/dist/filesystem-worker/resource-resolver.js'; const desktopRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const source = resolve(desktopRoot, '..', '..', 'packages', 'runtime', 'dist', 'workers', 'filesystem-worker.js'); -const target = resolve(desktopRoot, 'resources', 'workers', 'filesystem-worker.js'); +const source = resolve(desktopRoot, '..', '..', 'packages', 'runtime', 'dist', 'workers', FILESYSTEM_WORKER_BUNDLE_NAME); +const target = resolve(desktopRoot, 'resources', 'workers', FILESYSTEM_WORKER_BUNDLE_NAME); const metadata = await stat(source).catch(() => undefined); if (!metadata?.isFile()) throw new Error(`Runtime filesystem worker bundle is missing: ${source}`); await mkdir(dirname(target), { recursive: true }); diff --git a/packages/runtime/scripts/build-filesystem-worker.mjs b/packages/runtime/scripts/build-filesystem-worker.mjs index 69b40fb7751..1d1b7fc04b6 100644 --- a/packages/runtime/scripts/build-filesystem-worker.mjs +++ b/packages/runtime/scripts/build-filesystem-worker.mjs @@ -21,9 +21,10 @@ import { mkdir } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { build } from 'esbuild'; +import { FILESYSTEM_WORKER_BUNDLE_NAME } from '../dist/filesystem-worker/resource-resolver.js'; const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const outfile = resolve(packageRoot, 'dist', 'workers', 'filesystem-worker.js'); +const outfile = resolve(packageRoot, 'dist', 'workers', FILESYSTEM_WORKER_BUNDLE_NAME); const agentsCoreUtils = fileURLToPath(import.meta.resolve('@openai/agents-core/utils')); await mkdir(dirname(outfile), { recursive: true }); diff --git a/packages/runtime/src/__tests__/filesystem-worker-client.test.ts b/packages/runtime/src/__tests__/filesystem-worker-client.test.ts index d42799cf995..82471edb10f 100644 --- a/packages/runtime/src/__tests__/filesystem-worker-client.test.ts +++ b/packages/runtime/src/__tests__/filesystem-worker-client.test.ts @@ -669,9 +669,9 @@ function fakeClient( ok: true, spec: { program: '/usr/bin/node', - args: ['/runtime/filesystem-worker.js', '--grep-executable', '/usr/bin/rg'], + args: ['/runtime/filesystem-worker.mjs', '--grep-executable', '/usr/bin/rg'], env: {}, - runtimeReadableRoots: ['/runtime/filesystem-worker.js'], + runtimeReadableRoots: ['/runtime/filesystem-worker.mjs'], executableRoots: ['/usr/bin/node', '/usr/bin/rg'], }, }; @@ -787,9 +787,9 @@ describe('filesystem worker client dispatch classification', () => { ok: true, spec: { program: '/usr/bin/node', - args: ['/runtime/filesystem-worker.js', '--grep-executable', '/usr/bin/rg'], + args: ['/runtime/filesystem-worker.mjs', '--grep-executable', '/usr/bin/rg'], env: {}, - runtimeReadableRoots: ['/runtime/filesystem-worker.js'], + runtimeReadableRoots: ['/runtime/filesystem-worker.mjs'], executableRoots: ['/usr/bin/node', '/usr/bin/rg'], }, }), @@ -882,9 +882,9 @@ describe('filesystem worker client dispatch classification', () => { ok: true, spec: { program: '/usr/bin/node', - args: ['/runtime/filesystem-worker.js', '--grep-executable', '/usr/bin/rg'], + args: ['/runtime/filesystem-worker.mjs', '--grep-executable', '/usr/bin/rg'], env: {}, - runtimeReadableRoots: ['/runtime/filesystem-worker.js'], + runtimeReadableRoots: ['/runtime/filesystem-worker.mjs'], executableRoots: ['/usr/bin/node', '/usr/bin/rg'], }, }), @@ -940,9 +940,9 @@ describe('filesystem worker client dispatch classification', () => { ok: true, spec: { program: '/usr/bin/node', - args: ['/runtime/filesystem-worker.js', '--grep-executable', '/usr/bin/rg'], + args: ['/runtime/filesystem-worker.mjs', '--grep-executable', '/usr/bin/rg'], env: {}, - runtimeReadableRoots: ['/runtime/filesystem-worker.js'], + runtimeReadableRoots: ['/runtime/filesystem-worker.mjs'], executableRoots: ['/usr/bin/node', '/usr/bin/rg'], }, }), diff --git a/packages/runtime/src/__tests__/linux-sandbox.test.ts b/packages/runtime/src/__tests__/linux-sandbox.test.ts index dc341b47af0..b86f34016a6 100644 --- a/packages/runtime/src/__tests__/linux-sandbox.test.ts +++ b/packages/runtime/src/__tests__/linux-sandbox.test.ts @@ -278,7 +278,7 @@ describe('buildBubblewrapArgv', () => { const request = workspaceRequest(profile); const pathContext: SandboxPathContext = { ...request.command.pathContext, - runtimeReadableRoots: ['/runtime/filesystem-worker.js'], + runtimeReadableRoots: ['/runtime/filesystem-worker.mjs'], executableRoots: ['/opt/node/bin/node', '/opt/rg/bin/rg'], runtimeWritableRoots: ['/outside'], }; @@ -294,8 +294,8 @@ describe('buildBubblewrapArgv', () => { hasTriple( argv, '--ro-bind', - '/runtime/filesystem-worker.js', - '/runtime/filesystem-worker.js', + '/runtime/filesystem-worker.mjs', + '/runtime/filesystem-worker.mjs', ), ); assert.ok(hasTriple(argv, '--ro-bind', '/opt/node/bin/node', '/opt/node/bin/node')); diff --git a/packages/runtime/src/filesystem-worker/resource-resolver.ts b/packages/runtime/src/filesystem-worker/resource-resolver.ts index 57bad5e499c..9373a8d5181 100644 --- a/packages/runtime/src/filesystem-worker/resource-resolver.ts +++ b/packages/runtime/src/filesystem-worker/resource-resolver.ts @@ -21,7 +21,9 @@ import { realpath, stat } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -export const FILESYSTEM_WORKER_BUNDLE_NAME = 'filesystem-worker.js'; +// `.mjs` so Node never looks for a package.json to decide the module type: +// the Windows AppContainer sandbox denies that read and the worker crashes. +export const FILESYSTEM_WORKER_BUNDLE_NAME = 'filesystem-worker.mjs'; export type FilesystemWorkerResourceLocation = | { kind: 'runtime'; moduleUrl?: string } diff --git a/scripts/release-cli-package.mjs b/scripts/release-cli-package.mjs index c9a43f2c2ae..e54ed659d3d 100644 --- a/scripts/release-cli-package.mjs +++ b/scripts/release-cli-package.mjs @@ -77,7 +77,7 @@ const internalPackageNames = workspacePackages const internalPackageSet = new Set(internalPackageNames); const buildOrder = orderWorkspaceBuilds(workspacePackages); const developmentGeneratedFiles = new Map([ - ['@maka/runtime', new Set(['workers/filesystem-worker.js'])], + ['@maka/runtime', new Set(['workers/filesystem-worker.mjs'])], ]); const strippedInstallScripts = new Map([ // The clean repository install has already produced every generated file and @@ -749,7 +749,7 @@ function validateStaging(publishable) { 'DISCLAIMER-WIP', 'RUNTIME_HOST_PEER_DEPENDENCIES.rust.tsv', 'RUNTIME_HOST_PEER_THIRD_PARTY_NOTICES.txt', - 'node_modules/@maka/runtime/dist/workers/filesystem-worker.js', + 'node_modules/@maka/runtime/dist/workers/filesystem-worker.mjs', 'node_modules/@maka/runtime-host/dist/execution-candidate-main.js', 'node_modules/@maka/eval/dist/harbor-external-subject.js', 'node_modules/@maka/eval/harbor/relay_agent.py', @@ -862,7 +862,7 @@ function validatePackedFiles(files, expectedDependencyManifests, publishable) { const requiredPacked = [ 'dist/cli.js', 'DISCLAIMER-WIP', - 'node_modules/@maka/runtime/dist/workers/filesystem-worker.js', + 'node_modules/@maka/runtime/dist/workers/filesystem-worker.mjs', 'node_modules/@maka/runtime-host/dist/execution-candidate-main.js', 'node_modules/@maka/eval/harbor/relay_agent.py', ...(publishable || privateRuntimeHostTarget !== 'none' diff --git a/scripts/smoke-release-cli-package.mjs b/scripts/smoke-release-cli-package.mjs index 783a29b51c7..0d6e2752900 100644 --- a/scripts/smoke-release-cli-package.mjs +++ b/scripts/smoke-release-cli-package.mjs @@ -612,7 +612,7 @@ function validateInstalledRuntimeFiles(packageRoot) { // Incubator policy: the installed package carries the incubating // disclaimer next to LICENSE/NOTICE, like every other Maka release. 'DISCLAIMER-WIP', - 'node_modules/@maka/runtime/dist/workers/filesystem-worker.js', + 'node_modules/@maka/runtime/dist/workers/filesystem-worker.mjs', 'node_modules/@maka/runtime-host/dist/execution-candidate-main.js', 'node_modules/@maka/eval/dist/index.js', 'node_modules/@maka/eval/harbor/relay_agent.py', diff --git a/scripts/verify-macos-dmg.mjs b/scripts/verify-macos-dmg.mjs index 0ef0f7e5beb..1d041951e4a 100644 --- a/scripts/verify-macos-dmg.mjs +++ b/scripts/verify-macos-dmg.mjs @@ -342,7 +342,7 @@ export async function verifyPackagedMacApp( } const executableName = await readPlistValue(run, infoPlist, 'CFBundleExecutable'); const executable = join(contents, 'MacOS', executableName); - const filesystemWorker = join(resources, 'workers', 'filesystem-worker.js'); + const filesystemWorker = join(resources, 'workers', 'filesystem-worker.mjs'); const appAsar = join(resources, 'app.asar'); await requirePath(executable); diff --git a/scripts/verify-packaged-app.mjs b/scripts/verify-packaged-app.mjs index c0d150d50f1..800a89b94aa 100644 --- a/scripts/verify-packaged-app.mjs +++ b/scripts/verify-packaged-app.mjs @@ -1059,7 +1059,7 @@ export async function assertPackagedResources( 'app.asar', 'bundled-tools.json', ...(requireCanonicalIcon ? [join('assets', 'icon.png')] : []), - join('workers', 'filesystem-worker.js'), + join('workers', 'filesystem-worker.mjs'), ...(requireDirectPeerArtifact ? [ join('runtime-host-peer', 'maka_runtime_host_peer.node'), diff --git a/scripts/verify-windows-sandbox-e2e.mjs b/scripts/verify-windows-sandbox-e2e.mjs index c47646d83f6..b5f59df9acd 100644 --- a/scripts/verify-windows-sandbox-e2e.mjs +++ b/scripts/verify-windows-sandbox-e2e.mjs @@ -86,7 +86,7 @@ function assertCondition(condition, message) { * PACKAGED Windows app: the packaged broker executable enforces the * AppContainer boundary, the packaged Electron executable is the worker * runtime (ELECTRON_RUN_AS_NODE, exactly as production launches it) and the - * packaged `resources\workers\filesystem-worker.js` is the worker bundle. + * packaged `resources\workers\filesystem-worker.mjs` is the worker bundle. * Only the driver (client + launch-spec code) comes from the repository * build, because the packaged copy lives inside app.asar which plain node * cannot import; every executed artifact is the shipped one. @@ -96,7 +96,7 @@ export async function verifyWindowsSandboxWorkerE2E(appDirectoryPath) { const appExecutable = join(appDirectory, 'Maka.exe'); const resourcesPath = join(appDirectory, 'resources'); const sandboxExecutable = join(resourcesPath, 'windows-sandbox', 'maka-windows-sandbox.exe'); - const workerBundle = join(resourcesPath, 'workers', 'filesystem-worker.js'); + const workerBundle = join(resourcesPath, 'workers', 'filesystem-worker.mjs'); for (const [path, label] of [ [appExecutable, 'packaged Electron executable'], [sandboxExecutable, 'packaged sandbox broker'], diff --git a/scripts/windows-smoke.mjs b/scripts/windows-smoke.mjs index 9581182b0f1..34aca2644da 100644 --- a/scripts/windows-smoke.mjs +++ b/scripts/windows-smoke.mjs @@ -36,7 +36,7 @@ const DESKTOP_RUNTIME_WORKER = join( 'desktop', 'resources', 'workers', - 'filesystem-worker.js', + 'filesystem-worker.mjs', ); const DESKTOP_SMOKE = join(REPO_ROOT, 'scripts', 'desktop-real-window-smoke.mjs'); const CLI_TIMEOUT_MS = 15_000;