Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions packages/opencode/bin/altimate
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,55 @@ const fs = require("fs")
const path = require("path")
const os = require("os")

// 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)) paths.push(modules)
const parent = path.dirname(current)
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 }
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), {
stdio: "inherit",
env,
})
if (result.error) {
console.error(result.error.message)
Expand All @@ -22,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)) {
Expand Down
49 changes: 46 additions & 3 deletions packages/opencode/bin/altimate-code
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,55 @@ const fs = require("fs")
const path = require("path")
const os = require("os")

// 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)) paths.push(modules)
const parent = path.dirname(current)
if (parent === current) break
current = parent
}
return paths
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why NODE_PATH?

Bun compiled binaries resolve external require() calls from /$bunfs/root/ — a virtual filesystem with no node_modules. Standard Node resolution (walking up parent dirs from the binary's physical location) doesn't apply.

NODE_PATH is the only mechanism that works across all Bun versions to inject additional module search paths into a compiled binary. Tested and confirmed working with Bun 1.3.10.

Alternative considered: shipping altimate-core alongside the binary in the platform package — rejected because it would require cross-compiling the NAPI addon per-platform in our CI, which the altimate-core repo already handles via its own release pipeline.

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 }
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), {
stdio: "inherit",
env,
})
if (result.error) {
console.error(result.error.message)
Expand All @@ -22,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)) {
Expand Down
25 changes: 17 additions & 8 deletions packages/opencode/script/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key insight: external ≠ lazy without code splitting.

Bun's --compile without splitting: true inlines all modules (including dynamic import() targets) into a single chunk. Any external package referenced transitively from a dynamic import will emit a top-level require() that runs at startup — before the try/catch around the import() can catch it.

This is why @altimateai/dbt-integration and yaml were crashing the binary at startup even though they were only referenced inside lazy import() calls wrapped in try/catch.

Rule of thumb for this build config: Only mark packages as external if they truly cannot be bundled (native addons like NAPI .node files or database drivers).

// 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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why altimate-core must be external (not bundled):

@altimateai/altimate-core is a NAPI-RS package. Its index.js is a dynamic loader that does conditional require() to find platform-specific .node binaries (e.g. @altimateai/altimate-core-darwin-arm64). Bun's docs confirm you can embed .node files with direct require('./addon.node'), but the NAPI-RS auto-generated loader uses dynamic platform detection that Bun's bundler can't statically analyze.

So the JS loader gets inlined but the native binary doesn't → runtime crash. Making it external + installing via npm deps is the correct approach.

// 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,
Expand Down
14 changes: 14 additions & 0 deletions packages/opencode/script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ 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 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<string, string> = {
"@altimateai/altimate-core": altimateCoreDep,
}

const binaries: Record<string, string> = {}
for (const filepath of new Bun.Glob("**/package.json").scanSync({ cwd: "./dist" })) {
const pkg = await Bun.file(`./dist/${filepath}`).json()
Expand Down Expand Up @@ -34,6 +46,7 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write(
},
version: version,
license: pkg.license,
dependencies: runtimeDependencies,
optionalDependencies: binaries,
},
null,
Expand Down Expand Up @@ -81,6 +94,7 @@ try {
},
version: version,
license: pkg.license,
dependencies: runtimeDependencies,
optionalDependencies: binaries,
},
null,
Expand Down
Loading