mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 05:02:07 +00:00
fix(coding-agent): load photon wasm in compiled binaries
This commit is contained in:
parent
61833b3dc9
commit
964f17b8d1
3 changed files with 99 additions and 4 deletions
|
|
@ -33,7 +33,7 @@
|
|||
"build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js && npm run copy-assets",
|
||||
"build:binary": "npm run build && bun build --compile ./dist/cli.js --outfile dist/pi && npm run copy-binary-assets",
|
||||
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
|
||||
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/",
|
||||
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
|
||||
"test": "vitest --run",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,17 +8,107 @@
|
|||
* The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')
|
||||
* which bakes the build machine's absolute path into Bun compiled binaries.
|
||||
*
|
||||
* Solution: Lazy-load photon via dynamic import and gracefully handle failures.
|
||||
* Image processing functions have fallbacks that return original images when photon isn't available.
|
||||
* Solution:
|
||||
* 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads
|
||||
* 2. Copy photon_rs_bg.wasm next to the executable in build:binary
|
||||
*/
|
||||
|
||||
import type { PathOrFileDescriptor } from "fs";
|
||||
import { createRequire } from "module";
|
||||
import * as path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const fs = require("fs") as typeof import("fs");
|
||||
|
||||
// Re-export types from the main package
|
||||
export type { PhotonImage as PhotonImageType } from "@silvia-odwyer/photon-node";
|
||||
|
||||
type ReadFileSync = typeof fs.readFileSync;
|
||||
|
||||
const WASM_FILENAME = "photon_rs_bg.wasm";
|
||||
|
||||
// Lazy-loaded photon module
|
||||
let photonModule: typeof import("@silvia-odwyer/photon-node") | null = null;
|
||||
let loadPromise: Promise<typeof import("@silvia-odwyer/photon-node") | null> | null = null;
|
||||
|
||||
function pathOrNull(file: PathOrFileDescriptor): string | null {
|
||||
if (typeof file === "string") {
|
||||
return file;
|
||||
}
|
||||
if (file instanceof URL) {
|
||||
return fileURLToPath(file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFallbackWasmPaths(): string[] {
|
||||
const execDir = path.dirname(process.execPath);
|
||||
return [
|
||||
path.join(execDir, WASM_FILENAME),
|
||||
path.join(execDir, "photon", WASM_FILENAME),
|
||||
path.join(process.cwd(), WASM_FILENAME),
|
||||
];
|
||||
}
|
||||
|
||||
function patchPhotonWasmRead(): () => void {
|
||||
const originalReadFileSync: ReadFileSync = fs.readFileSync.bind(fs);
|
||||
const fallbackPaths = getFallbackWasmPaths();
|
||||
const mutableFs = fs as { readFileSync: ReadFileSync };
|
||||
|
||||
const patchedReadFileSync: ReadFileSync = ((...args: Parameters<ReadFileSync>) => {
|
||||
const [file, options] = args;
|
||||
const resolvedPath = pathOrNull(file);
|
||||
|
||||
if (resolvedPath?.endsWith(WASM_FILENAME)) {
|
||||
try {
|
||||
return originalReadFileSync(...args);
|
||||
} catch (error) {
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err?.code && err.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
for (const fallbackPath of fallbackPaths) {
|
||||
if (!fs.existsSync(fallbackPath)) {
|
||||
continue;
|
||||
}
|
||||
if (options === undefined) {
|
||||
return originalReadFileSync(fallbackPath);
|
||||
}
|
||||
return originalReadFileSync(fallbackPath, options);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return originalReadFileSync(...args);
|
||||
}) as ReadFileSync;
|
||||
|
||||
try {
|
||||
mutableFs.readFileSync = patchedReadFileSync;
|
||||
} catch {
|
||||
Object.defineProperty(fs, "readFileSync", {
|
||||
value: patchedReadFileSync,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
try {
|
||||
mutableFs.readFileSync = originalReadFileSync;
|
||||
} catch {
|
||||
Object.defineProperty(fs, "readFileSync", {
|
||||
value: originalReadFileSync,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the photon module asynchronously.
|
||||
* Returns cached module on subsequent calls.
|
||||
|
|
@ -33,12 +123,16 @@ export async function loadPhoton(): Promise<typeof import("@silvia-odwyer/photon
|
|||
}
|
||||
|
||||
loadPromise = (async () => {
|
||||
const restoreReadFileSync = patchPhotonWasmRead();
|
||||
try {
|
||||
photonModule = await import("@silvia-odwyer/photon-node");
|
||||
return photonModule;
|
||||
} catch {
|
||||
photonModule = null;
|
||||
return photonModule;
|
||||
} finally {
|
||||
restoreReadFileSync();
|
||||
}
|
||||
return photonModule;
|
||||
})();
|
||||
|
||||
return loadPromise;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ for platform in "${PLATFORMS[@]}"; do
|
|||
cp package.json binaries/$platform/
|
||||
cp README.md binaries/$platform/
|
||||
cp CHANGELOG.md binaries/$platform/
|
||||
cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm binaries/$platform/
|
||||
mkdir -p binaries/$platform/theme
|
||||
cp dist/modes/interactive/theme/*.json binaries/$platform/theme/
|
||||
cp -r examples binaries/$platform/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue