From 35230ec6f54cfdfc98467444c39c833e2f4ca3b3 Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Wed, 18 Mar 2026 06:57:29 -0700 Subject: [PATCH 1/2] fix: resolve `Cannot find module '@altimateai/altimate-core'` on npm install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three issues prevented `npm install -g altimate-code` from working: 1. `@altimateai/altimate-core` (NAPI-RS native module) cannot be embedded in Bun single-file executables — mark it as external and add it as a dependency in the published wrapper packages so npm installs it. 2. `@altimateai/dbt-integration` and `yaml` were external but without code splitting, Bun inlines dynamic `import()` targets into the main chunk — external `require()` fails at startup. Remove them from externals so they get bundled. 3. Bun compiled binaries resolve externals from `/$bunfs/root/` (virtual FS), not the physical binary location. The bin wrapper now sets `NODE_PATH` to the nearest `node_modules` so the binary can find external packages. Closes #258 Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/bin/altimate | 26 ++++++++++++++++++++++++++ packages/opencode/bin/altimate-code | 26 ++++++++++++++++++++++++++ packages/opencode/script/build.ts | 25 +++++++++++++++++-------- packages/opencode/script/publish.ts | 9 +++++++++ 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/packages/opencode/bin/altimate b/packages/opencode/bin/altimate index c842b49deb..4d715e2e10 100755 --- a/packages/opencode/bin/altimate +++ b/packages/opencode/bin/altimate @@ -5,9 +5,35 @@ const fs = require("fs") const path = require("path") const os = require("os") +// Find the nearest node_modules directory from a starting path. +// The Bun compiled binary resolves external packages (e.g. NAPI native +// modules like @altimateai/altimate-core) via NODE_PATH because its virtual +// filesystem (/$bunfs/root/) has no node_modules. +function findNodeModules(startDir) { + let current = startDir + for (;;) { + const modules = path.join(current, "node_modules") + if (fs.existsSync(modules)) return modules + const parent = path.dirname(current) + if (parent === current) return undefined + current = parent + } +} + function run(target) { + // Resolve NODE_PATH so the compiled Bun binary can find external packages + // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module). + const env = { ...process.env } + const targetDir = path.dirname(path.dirname(fs.realpathSync(target))) + const modules = findNodeModules(targetDir) + if (modules) { + const sep = process.platform === "win32" ? ";" : ":" + env.NODE_PATH = env.NODE_PATH ? modules + sep + env.NODE_PATH : modules + } + const result = childProcess.spawnSync(target, process.argv.slice(2), { stdio: "inherit", + env, }) if (result.error) { console.error(result.error.message) diff --git a/packages/opencode/bin/altimate-code b/packages/opencode/bin/altimate-code index c842b49deb..4d715e2e10 100755 --- a/packages/opencode/bin/altimate-code +++ b/packages/opencode/bin/altimate-code @@ -5,9 +5,35 @@ const fs = require("fs") const path = require("path") const os = require("os") +// Find the nearest node_modules directory from a starting path. +// The Bun compiled binary resolves external packages (e.g. NAPI native +// modules like @altimateai/altimate-core) via NODE_PATH because its virtual +// filesystem (/$bunfs/root/) has no node_modules. +function findNodeModules(startDir) { + let current = startDir + for (;;) { + const modules = path.join(current, "node_modules") + if (fs.existsSync(modules)) return modules + const parent = path.dirname(current) + if (parent === current) return undefined + current = parent + } +} + function run(target) { + // Resolve NODE_PATH so the compiled Bun binary can find external packages + // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module). + const env = { ...process.env } + const targetDir = path.dirname(path.dirname(fs.realpathSync(target))) + const modules = findNodeModules(targetDir) + if (modules) { + const sep = process.platform === "win32" ? ";" : ":" + env.NODE_PATH = env.NODE_PATH ? modules + sep + env.NODE_PATH : modules + } + const result = childProcess.spawnSync(target, process.argv.slice(2), { stdio: "inherit", + env, }) if (result.error) { console.error(result.error.message) diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 802f475104..2206a093a9 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -204,17 +204,26 @@ for (const item of targets) { tsconfig: "./tsconfig.json", plugins: [solidPlugin], sourcemap: "external", - // Packages excluded from the compiled binary — loaded lazily at runtime. - // NOTE: @altimateai/altimate-core is intentionally NOT external — it's a - // napi binary that must be bundled for the CLI to work out of the box. + // Packages excluded from the compiled binary — resolved from node_modules + // at runtime. Bun compiled binaries resolve externals via standard Node + // resolution from the binary's location, walking up to the wrapper + // package's node_modules. + // + // IMPORTANT: Without code splitting, Bun inlines dynamic import() targets + // into the main chunk. Any external require() in those targets will fail + // at startup — not when the import() is called. Only mark packages as + // external when they truly cannot be bundled (e.g. NAPI native addons). external: [ - // dbt integration — heavy transitive deps, loaded on first dbt operation - "@altimateai/dbt-integration", - // Database drivers — users install on demand per warehouse + // NAPI native module — cannot be embedded in Bun single-file executable. + // The JS loader dynamically require()s platform-specific .node binaries + // (e.g. @altimateai/altimate-core-darwin-arm64). + // Must be installed as a dependency of the published wrapper package. + "@altimateai/altimate-core", + // Database drivers — native addons, users install on demand per warehouse "pg", "snowflake-sdk", "@google-cloud/bigquery", "@databricks/sql", "mysql2", "mssql", "oracledb", "duckdb", "better-sqlite3", - // Optional infra packages - "keytar", "ssh2", "dockerode", "yaml", + // Optional infra packages — native addons or heavy optional deps + "keytar", "ssh2", "dockerode", ], compile: { autoloadBunfig: false, diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index 73d46e4a0f..c7b6341399 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -7,6 +7,13 @@ import { fileURLToPath } from "url" const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) +// NAPI native modules that must be installed alongside the CLI binary. +// These cannot be embedded in Bun's single-file executable — the JS loader +// dynamically require()s platform-specific .node binaries at runtime. +const runtimeDependencies: Record = { + "@altimateai/altimate-core": pkg.dependencies["@altimateai/altimate-core"], +} + const binaries: Record = {} for (const filepath of new Bun.Glob("**/package.json").scanSync({ cwd: "./dist" })) { const pkg = await Bun.file(`./dist/${filepath}`).json() @@ -34,6 +41,7 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write( }, version: version, license: pkg.license, + dependencies: runtimeDependencies, optionalDependencies: binaries, }, null, @@ -81,6 +89,7 @@ try { }, version: version, license: pkg.license, + dependencies: runtimeDependencies, optionalDependencies: binaries, }, null, From c7e41b4edfa67aecb9d26e43925408e9245b8eae Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Wed, 18 Mar 2026 07:19:26 -0700 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20address=20code=20review=20findings?= =?UTF-8?q?=20=E2=80=94=20`realpathSync`=20try-catch,=20multi-path=20NODE?= =?UTF-8?q?=5FPATH,=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes from 6-model consensus code review: 1. Wrap `fs.realpathSync(target)` in try-catch — previously would crash with a stack trace if `ALTIMATE_CODE_BIN_PATH` pointed to a missing file. Now falls back gracefully to `spawnSync` error handling. (Flagged by 4/6 models) 2. Collect ALL `node_modules` paths walking upward (not just first found) and search from BOTH the binary dir AND the wrapper script dir. This handles pnpm strict layouts, hoisted monorepos, and npm flat installs. (Suggested by Gemini 3.1 Pro) 3. Move `scriptDir` initialization before `run()` to avoid ReferenceError when `ALTIMATE_CODE_BIN_PATH` is set (calls `run()` before `scriptDir` was previously defined). (Flagged by Gemini 3.1 Pro) 4. Add fail-fast validation for `@altimateai/altimate-core` dependency in `publish.ts` — prevents silent `undefined` if accidentally removed from `package.json`. (Flagged by Kimi K2.5) Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/bin/altimate | 47 ++++++++++++++++++++--------- packages/opencode/bin/altimate-code | 47 ++++++++++++++++++++--------- packages/opencode/script/publish.ts | 7 ++++- 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/packages/opencode/bin/altimate b/packages/opencode/bin/altimate index 4d715e2e10..dea3eecea6 100755 --- a/packages/opencode/bin/altimate +++ b/packages/opencode/bin/altimate @@ -5,30 +5,50 @@ const fs = require("fs") const path = require("path") const os = require("os") -// Find the nearest node_modules directory from a starting path. -// The Bun compiled binary resolves external packages (e.g. NAPI native -// modules like @altimateai/altimate-core) via NODE_PATH because its virtual -// filesystem (/$bunfs/root/) has no node_modules. -function findNodeModules(startDir) { +// Resolve script location early — needed by both run() and findBinary(). +const scriptPath = fs.realpathSync(__filename) +const scriptDir = path.dirname(scriptPath) + +// Collect ALL node_modules directories walking upward from startDir. +// Bun's single-file executable uses a virtual filesystem (/$bunfs/root/) without +// node_modules. External packages are resolved via NODE_PATH instead. +// We collect every node_modules in the hierarchy (not just the first) to handle +// pnpm strict layouts, hoisted monorepos, and npm flat installs alike. +function findAllNodeModules(startDir) { + const paths = [] let current = startDir for (;;) { const modules = path.join(current, "node_modules") - if (fs.existsSync(modules)) return modules + if (fs.existsSync(modules)) paths.push(modules) const parent = path.dirname(current) - if (parent === current) return undefined + if (parent === current) break current = parent } + return paths } function run(target) { // Resolve NODE_PATH so the compiled Bun binary can find external packages // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module). + // Search from BOTH the binary's location AND the wrapper script's location + // to cover npm flat installs, pnpm isolated stores, and hoisted monorepos. const env = { ...process.env } - const targetDir = path.dirname(path.dirname(fs.realpathSync(target))) - const modules = findNodeModules(targetDir) - if (modules) { - const sep = process.platform === "win32" ? ";" : ":" - env.NODE_PATH = env.NODE_PATH ? modules + sep + env.NODE_PATH : modules + try { + const resolvedTarget = fs.realpathSync(target) + const targetDir = path.dirname(path.dirname(resolvedTarget)) + + const targetModules = findAllNodeModules(targetDir) + const scriptModules = findAllNodeModules(scriptDir) + const allPaths = [...new Set([...scriptModules, ...targetModules])] + + if (allPaths.length > 0) { + const sep = process.platform === "win32" ? ";" : ":" + const joined = allPaths.join(sep) + env.NODE_PATH = env.NODE_PATH ? joined + sep + env.NODE_PATH : joined + } + } catch { + // realpathSync failed (e.g. target doesn't exist) — continue without + // NODE_PATH; spawnSync will report the missing binary via result.error. } const result = childProcess.spawnSync(target, process.argv.slice(2), { @@ -48,9 +68,6 @@ if (envPath) { run(envPath) } -const scriptPath = fs.realpathSync(__filename) -const scriptDir = path.dirname(scriptPath) - // const cached = path.join(scriptDir, ".altimate-code") if (fs.existsSync(cached)) { diff --git a/packages/opencode/bin/altimate-code b/packages/opencode/bin/altimate-code index 4d715e2e10..dea3eecea6 100755 --- a/packages/opencode/bin/altimate-code +++ b/packages/opencode/bin/altimate-code @@ -5,30 +5,50 @@ const fs = require("fs") const path = require("path") const os = require("os") -// Find the nearest node_modules directory from a starting path. -// The Bun compiled binary resolves external packages (e.g. NAPI native -// modules like @altimateai/altimate-core) via NODE_PATH because its virtual -// filesystem (/$bunfs/root/) has no node_modules. -function findNodeModules(startDir) { +// Resolve script location early — needed by both run() and findBinary(). +const scriptPath = fs.realpathSync(__filename) +const scriptDir = path.dirname(scriptPath) + +// Collect ALL node_modules directories walking upward from startDir. +// Bun's single-file executable uses a virtual filesystem (/$bunfs/root/) without +// node_modules. External packages are resolved via NODE_PATH instead. +// We collect every node_modules in the hierarchy (not just the first) to handle +// pnpm strict layouts, hoisted monorepos, and npm flat installs alike. +function findAllNodeModules(startDir) { + const paths = [] let current = startDir for (;;) { const modules = path.join(current, "node_modules") - if (fs.existsSync(modules)) return modules + if (fs.existsSync(modules)) paths.push(modules) const parent = path.dirname(current) - if (parent === current) return undefined + if (parent === current) break current = parent } + return paths } function run(target) { // Resolve NODE_PATH so the compiled Bun binary can find external packages // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module). + // Search from BOTH the binary's location AND the wrapper script's location + // to cover npm flat installs, pnpm isolated stores, and hoisted monorepos. const env = { ...process.env } - const targetDir = path.dirname(path.dirname(fs.realpathSync(target))) - const modules = findNodeModules(targetDir) - if (modules) { - const sep = process.platform === "win32" ? ";" : ":" - env.NODE_PATH = env.NODE_PATH ? modules + sep + env.NODE_PATH : modules + try { + const resolvedTarget = fs.realpathSync(target) + const targetDir = path.dirname(path.dirname(resolvedTarget)) + + const targetModules = findAllNodeModules(targetDir) + const scriptModules = findAllNodeModules(scriptDir) + const allPaths = [...new Set([...scriptModules, ...targetModules])] + + if (allPaths.length > 0) { + const sep = process.platform === "win32" ? ";" : ":" + const joined = allPaths.join(sep) + env.NODE_PATH = env.NODE_PATH ? joined + sep + env.NODE_PATH : joined + } + } catch { + // realpathSync failed (e.g. target doesn't exist) — continue without + // NODE_PATH; spawnSync will report the missing binary via result.error. } const result = childProcess.spawnSync(target, process.argv.slice(2), { @@ -48,9 +68,6 @@ if (envPath) { run(envPath) } -const scriptPath = fs.realpathSync(__filename) -const scriptDir = path.dirname(scriptPath) - // const cached = path.join(scriptDir, ".altimate-code") if (fs.existsSync(cached)) { diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index c7b6341399..29525a10f0 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -10,8 +10,13 @@ process.chdir(dir) // NAPI native modules that must be installed alongside the CLI binary. // These cannot be embedded in Bun's single-file executable — the JS loader // dynamically require()s platform-specific .node binaries at runtime. +const altimateCoreDep = pkg.dependencies["@altimateai/altimate-core"] +if (!altimateCoreDep) { + console.error("Missing required dependency: @altimateai/altimate-core in package.json") + process.exit(1) +} const runtimeDependencies: Record = { - "@altimateai/altimate-core": pkg.dependencies["@altimateai/altimate-core"], + "@altimateai/altimate-core": altimateCoreDep, } const binaries: Record = {}