-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild.ts
More file actions
167 lines (151 loc) · 5.2 KB
/
build.ts
File metadata and controls
167 lines (151 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env bun
/**
* Build script for memex-claude standalone binaries.
*
* Compiles the TypeScript source into a self-contained executable using
* `bun build --compile`. Sharp is stubbed out (we only use text embeddings).
* The ONNX runtime shared library is copied alongside the binary.
*
* Usage:
* bun run build.ts # build for current platform
* bun run build.ts --target bun-linux-x64 # cross-compile
*/
import { mkdirSync, cpSync, rmSync, symlinkSync, readlinkSync, existsSync, readdirSync, readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { execSync } from "node:child_process";
import { platform, arch } from "node:os";
/** Resolve the ONNX runtime base path dynamically from node_modules. */
function resolveOnnxBase(): string {
// Try the pnpm store first (versioned directory)
const pnpmBase = "node_modules/.pnpm";
if (existsSync(pnpmBase)) {
const entries = readdirSync(pnpmBase);
const onnxDir = entries.find((e) => e.startsWith("onnxruntime-node@"));
if (onnxDir) {
return join(pnpmBase, onnxDir, "node_modules/onnxruntime-node/bin/napi-v3");
}
}
// Fallback: direct node_modules path (npm/yarn)
return "node_modules/onnxruntime-node/bin/napi-v3";
}
const ONNX_BASE = resolveOnnxBase();
const SHARP_SYMLINK = "node_modules/.pnpm/@huggingface+transformers@3.8.1/node_modules/sharp";
interface PlatformFiles {
onnxDir: string;
sharedLibs: string[];
binaryName: string;
}
const PLATFORMS: Record<string, PlatformFiles> = {
"linux-x64": {
onnxDir: join(ONNX_BASE, "linux/x64"),
sharedLibs: ["libonnxruntime.so.1", "libonnxruntime_providers_shared.so"],
binaryName: "memex",
},
"linux-arm64": {
onnxDir: join(ONNX_BASE, "linux/arm64"),
sharedLibs: ["libonnxruntime.so.1"],
binaryName: "memex",
},
"darwin-x64": {
onnxDir: join(ONNX_BASE, "darwin/x64"),
sharedLibs: ["libonnxruntime.1.21.0.dylib"],
binaryName: "memex",
},
"darwin-arm64": {
onnxDir: join(ONNX_BASE, "darwin/arm64"),
sharedLibs: ["libonnxruntime.1.21.0.dylib"],
binaryName: "memex",
},
"win32-x64": {
onnxDir: join(ONNX_BASE, "win32/x64"),
sharedLibs: ["onnxruntime.dll", "DirectML.dll"],
binaryName: "memex.exe",
},
"win32-arm64": {
onnxDir: join(ONNX_BASE, "win32/arm64"),
sharedLibs: ["onnxruntime.dll", "DirectML.dll"],
binaryName: "memex.exe",
},
};
function detectPlatformKey(): string {
const p = platform();
const a = arch();
const key = `${p}-${a}`;
if (!(key in PLATFORMS)) {
console.error(`Unsupported platform: ${key}`);
process.exit(1);
}
return key;
}
function parseBunTarget(target: string): string {
// e.g. "bun-linux-x64" → "linux-x64"
const match = target.match(/^bun-(linux|darwin|win(?:dows|32))-(x64|arm64)$/);
if (!match) {
console.error(`Invalid target: ${target}. Expected bun-{linux,darwin,windows}-{x64,arm64}`);
process.exit(1);
}
const os = match[1] === "windows" ? "win32" : match[1];
return `${os}-${match[2]}`;
}
// Parse args
const targetArg = process.argv.find((a) => a.startsWith("--target"));
let targetFlag: string | undefined;
let platformKey: string;
if (targetArg) {
const idx = process.argv.indexOf(targetArg);
targetFlag = targetArg.includes("=")
? targetArg.split("=")[1]
: process.argv[idx + 1];
platformKey = parseBunTarget(targetFlag);
} else {
platformKey = detectPlatformKey();
}
const platConfig = PLATFORMS[platformKey];
const outDir = join("dist", platformKey);
console.log(`Building for ${platformKey}...`);
// 1. Stub sharp in node_modules so bun doesn't bundle native sharp
let sharpOrigTarget: string | null = null;
if (existsSync(SHARP_SYMLINK)) {
try {
sharpOrigTarget = readlinkSync(SHARP_SYMLINK);
} catch {
// not a symlink, might already be stubbed
}
rmSync(SHARP_SYMLINK, { recursive: true, force: true });
}
mkdirSync(SHARP_SYMLINK, { recursive: true });
Bun.write(join(SHARP_SYMLINK, "package.json"), JSON.stringify({ name: "sharp", version: "0.0.0", main: "index.js" }));
Bun.write(join(SHARP_SYMLINK, "index.js"), "module.exports = {};");
try {
// 2. Compile (inject version at compile time via --define)
const pkgVersion = JSON.parse(readFileSync("package.json", "utf-8")).version;
mkdirSync(outDir, { recursive: true });
const outFile = join(outDir, platConfig.binaryName);
const args = [
"build", "--compile", "src/main.ts", "--outfile", outFile,
"--define", `process.env.SKILL_ROUTER_VERSION='"${pkgVersion}"'`,
];
if (targetFlag) {
args.push("--target", targetFlag);
}
execSync(`bun ${args.join(" ")}`, { stdio: "inherit" });
// 3. Copy ONNX shared libraries alongside binary
for (const lib of platConfig.sharedLibs) {
const src = join(platConfig.onnxDir, lib);
const dest = join(outDir, lib);
if (existsSync(src)) {
cpSync(src, dest);
console.log(` Copied ${lib}`);
} else {
console.warn(` Warning: ${src} not found, skipping`);
}
}
console.log(`\nBuild complete: ${outDir}/`);
} finally {
// 4. Restore sharp symlink
rmSync(SHARP_SYMLINK, { recursive: true, force: true });
if (sharpOrigTarget) {
symlinkSync(sharpOrigTarget, SHARP_SYMLINK);
console.log("Restored sharp symlink");
}
}