blob: b2bcbc1faf9438141bc18059856265b0398d2c9f [file]
// Build the cursor overlay renderer bundle + preload into apps/desktop/dist/overlay.
// - cursor-overlay.js: the Canvas engine host (IIFE, browser). The `js→ts` resolve
// shim lets us bundle the engine's NodeNext `./x.js` imports straight from source.
// - cursor-overlay-preload.cjs: receive-only main→renderer bridge (CJS, electron external).
// - cursor-overlay.html: copied verbatim.
import * as esbuild from 'esbuild';
import { resolve, dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { mkdir, copyFile } from 'node:fs/promises';
const here = dirname(fileURLToPath(import.meta.url));
const desktop = resolve(here, '..', 'apps', 'desktop');
const srcOverlay = join(desktop, 'src', 'overlay');
const outDir = join(desktop, 'dist', 'overlay');
const jsToTs = {
name: 'js-to-ts',
setup(build) {
build.onResolve({ filter: /^\.\.?\/.*\.js$/ }, (args) => ({
path: resolve(args.resolveDir, args.path.replace(/\.js$/, '.ts')),
}));
},
};
/** Build the overlay renderer bundle + preload + html into dist/overlay. */
export async function buildCursorOverlay({ logLevel = 'info' } = {}) {
await mkdir(outDir, { recursive: true });
await esbuild.build({
entryPoints: [join(srcOverlay, 'cursor-overlay.ts')],
bundle: true,
format: 'iife',
platform: 'browser',
target: 'chrome120',
outfile: join(outDir, 'cursor-overlay.js'),
plugins: [jsToTs],
logLevel,
});
await esbuild.build({
entryPoints: [join(srcOverlay, 'cursor-overlay-preload.ts')],
bundle: true,
format: 'cjs',
platform: 'node',
external: ['electron'],
outfile: join(outDir, 'cursor-overlay-preload.cjs'),
logLevel,
});
await copyFile(join(srcOverlay, 'cursor-overlay.html'), join(outDir, 'cursor-overlay.html'));
await buildPermissionOverlay({ logLevel });
await buildComputerUsePip({ logLevel });
return outDir;
}
/**
* The Computer Use picture-in-picture mirror. Same shape as the cursor overlay
* — module page bundle + CJS preload + verbatim html — sharing `dist/overlay`
* so one `build:overlay` step covers all three panels.
*
* Its preload is receive-only and narrower than the cursor overlay's: the
* mirror displays frames main hands it and has nothing to report back.
*/
export async function buildComputerUsePip({ logLevel = 'info' } = {}) {
await mkdir(outDir, { recursive: true });
await esbuild.build({
entryPoints: [join(srcOverlay, 'pip.ts')],
bundle: true,
format: 'esm',
platform: 'browser',
target: 'chrome120',
outfile: join(outDir, 'pip.js'),
plugins: [jsToTs],
logLevel,
});
await esbuild.build({
entryPoints: [join(srcOverlay, 'pip-preload.ts')],
bundle: true,
format: 'cjs',
platform: 'node',
external: ['electron'],
outfile: join(outDir, 'pip-preload.cjs'),
logLevel,
});
await copyFile(join(srcOverlay, 'pip.html'), join(outDir, 'pip.html'));
return outDir;
}
/**
* The drag-to-grant permission card. Same shape as the cursor overlay —
* IIFE page bundle + CJS preload + verbatim html — and it shares
* `dist/overlay`, so one `build:overlay` step covers both panels.
*
* Unlike the cursor overlay this page IS interactive (the user grabs the
* row out of it), so its preload is send-capable; see the preload source
* for what it is allowed to say.
*/
export async function buildPermissionOverlay({ logLevel = 'info' } = {}) {
await mkdir(outDir, { recursive: true });
await esbuild.build({
entryPoints: [join(srcOverlay, 'permission-overlay.ts')],
bundle: true,
format: 'iife',
platform: 'browser',
target: 'chrome120',
outfile: join(outDir, 'permission-overlay.js'),
plugins: [jsToTs],
logLevel,
});
await esbuild.build({
entryPoints: [join(srcOverlay, 'permission-overlay-preload.ts')],
bundle: true,
format: 'cjs',
platform: 'node',
external: ['electron'],
outfile: join(outDir, 'permission-overlay-preload.cjs'),
logLevel,
});
await copyFile(
join(srcOverlay, 'permission-overlay.html'),
join(outDir, 'permission-overlay.html'),
);
return outDir;
}
// Run directly (npm run build:overlay) or import buildCursorOverlay (dev.mjs).
if (import.meta.url === `file://${process.argv[1]}`) {
const dir = await buildCursorOverlay();
console.log('overlays built →', dir);
}