fix: resolve bunfig preload conflict via postinstall symlink (#245)#252
Merged
shuv1337 merged 3 commits intointegrationfrom Jan 2, 2026
Merged
fix: resolve bunfig preload conflict via postinstall symlink (#245)#252shuv1337 merged 3 commits intointegrationfrom
shuv1337 merged 3 commits intointegrationfrom
Conversation
Add postinstall.mjs that creates a symlink from bin/shuvcode to the platform-specific compiled binary, matching upstream opencode behavior. This ensures users execute the binary directly, bypassing Bun's bunfig.toml loading that causes preload resolution failures. Changes: - Add postinstall.mjs with platform detection and symlink creation - Update build.ts to enable autoloadTsconfig and autoloadPackageJson - Update publish.ts to include postinstall.mjs in published package
Comment on lines
50
to
68
| function findBinary() { | ||
| const { platform, arch } = detectPlatformAndArch() | ||
| const packageName = `shuvcode-${platform}-${arch}` | ||
| const binaryName = platform === "windows" ? "shuvcode.exe" : "shuvcode" | ||
|
|
||
| try { | ||
| // Use require.resolve to find the package | ||
| const packageJsonPath = require.resolve(`${packageName}/package.json`) | ||
| const packageDir = path.dirname(packageJsonPath) | ||
| const binaryPath = path.join(packageDir, "bin", binaryName) | ||
|
|
||
| if (!fs.existsSync(binaryPath)) { | ||
| throw new Error(`Binary not found at ${binaryPath}`) | ||
| } | ||
|
|
||
| return { binaryPath, binaryName } | ||
| } catch (error) { | ||
| throw new Error(`Could not find package ${packageName}: ${error.message}`) | ||
| } |
There was a problem hiding this comment.
logic: Missing baseline variant fallback - will fail for baseline packages like shuvcode-linux-x64-baseline
The current implementation only tries the exact package name shuvcode-${platform}-${arch}, but the build script creates baseline variants (e.g., shuvcode-linux-x64-baseline). The existing bin/shuvcode launcher handles this by searching for any package that starts with the base name (line 57: if (!entry.startsWith(base))).
Suggested change
| function findBinary() { | |
| const { platform, arch } = detectPlatformAndArch() | |
| const packageName = `shuvcode-${platform}-${arch}` | |
| const binaryName = platform === "windows" ? "shuvcode.exe" : "shuvcode" | |
| try { | |
| // Use require.resolve to find the package | |
| const packageJsonPath = require.resolve(`${packageName}/package.json`) | |
| const packageDir = path.dirname(packageJsonPath) | |
| const binaryPath = path.join(packageDir, "bin", binaryName) | |
| if (!fs.existsSync(binaryPath)) { | |
| throw new Error(`Binary not found at ${binaryPath}`) | |
| } | |
| return { binaryPath, binaryName } | |
| } catch (error) { | |
| throw new Error(`Could not find package ${packageName}: ${error.message}`) | |
| } | |
| function findBinary() { | |
| const { platform, arch } = detectPlatformAndArch() | |
| const basePackageName = `shuvcode-${platform}-${arch}` | |
| const binaryName = platform === "windows" ? "shuvcode.exe" : "shuvcode" | |
| try { | |
| // Try exact package name first | |
| try { | |
| const packageJsonPath = require.resolve(`${basePackageName}/package.json`) | |
| const packageDir = path.dirname(packageJsonPath) | |
| const binaryPath = path.join(packageDir, "bin", binaryName) | |
| if (fs.existsSync(binaryPath)) { | |
| return { binaryPath, binaryName } | |
| } | |
| } catch (error) { | |
| // Exact match failed, try baseline variant | |
| } | |
| // Fallback: search for baseline variants (e.g., shuvcode-linux-x64-baseline) | |
| const nodeModulesPath = path.join(__dirname, "..", "node_modules") | |
| if (fs.existsSync(nodeModulesPath)) { | |
| const entries = fs.readdirSync(nodeModulesPath) | |
| for (const entry of entries) { | |
| if (entry.startsWith(basePackageName)) { | |
| const binaryPath = path.join(nodeModulesPath, entry, "bin", binaryName) | |
| if (fs.existsSync(binaryPath)) { | |
| return { binaryPath, binaryName } | |
| } | |
| } | |
| } | |
| } | |
| throw new Error(`No binary package found for ${basePackageName}`) | |
| } catch (error) { | |
| throw new Error(`Could not find package ${basePackageName}: ${error.message}`) | |
| } | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/opencode/postinstall.mjs
Line: 50:68
Comment:
**logic:** Missing baseline variant fallback - will fail for baseline packages like `shuvcode-linux-x64-baseline`
The current implementation only tries the exact package name `shuvcode-${platform}-${arch}`, but the build script creates baseline variants (e.g., `shuvcode-linux-x64-baseline`). The existing `bin/shuvcode` launcher handles this by searching for any package that **starts with** the base name (line 57: `if (!entry.startsWith(base))`).
```suggestion
function findBinary() {
const { platform, arch } = detectPlatformAndArch()
const basePackageName = `shuvcode-${platform}-${arch}`
const binaryName = platform === "windows" ? "shuvcode.exe" : "shuvcode"
try {
// Try exact package name first
try {
const packageJsonPath = require.resolve(`${basePackageName}/package.json`)
const packageDir = path.dirname(packageJsonPath)
const binaryPath = path.join(packageDir, "bin", binaryName)
if (fs.existsSync(binaryPath)) {
return { binaryPath, binaryName }
}
} catch (error) {
// Exact match failed, try baseline variant
}
// Fallback: search for baseline variants (e.g., shuvcode-linux-x64-baseline)
const nodeModulesPath = path.join(__dirname, "..", "node_modules")
if (fs.existsSync(nodeModulesPath)) {
const entries = fs.readdirSync(nodeModulesPath)
for (const entry of entries) {
if (entry.startsWith(basePackageName)) {
const binaryPath = path.join(nodeModulesPath, entry, "bin", binaryName)
if (fs.existsSync(binaryPath)) {
return { binaryPath, binaryName }
}
}
}
}
throw new Error(`No binary package found for ${basePackageName}`)
} catch (error) {
throw new Error(`Could not find package ${basePackageName}: ${error.message}`)
}
}
```
How can I resolve this? If you propose a fix, please make it concise.Apply Greptile suggestion to handle baseline packages like shuvcode-linux-x64-baseline by searching for packages that start with the base package name when exact match fails.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes issue #245 where shuvcode fails with "preload not found @opentui/solid/preload" when run from directories with their own bunfig.toml.
Changes
Fixes
postinstall.mjsthat creates a symlink frombin/shuvcodeto the platform-specific compiled binary, matching upstream opencode behaviorbuild.tsto enableautoloadTsconfigandautoloadPackageJsoncompiler optionspublish.tsto include postinstall.mjs in the published package and configure the postinstall scriptDocumentation
CONTEXT/PLAN-245-bunfig-preload-conflict-fix-2026-01-02.mdexplaining the root cause analysis and solutionRoot Cause
The shuvcode package used a Node.js launcher script at
bin/shuvcode, while upstream opencode uses a symlink to the compiled ELF binary. When Bun executes the launcher script, it reads the CWD'sbunfig.tomland attempts to apply preloads before the actual binary runs.Breaking Changes
None
Testing
Manual testing required:
bun install -g shuvcodebunfig.tomlcontaining preloadsshuvcode- should launch successfully without preload errorsGreptile Summary
Fixes issue #245 by adding a postinstall script that creates a symlink from
bin/shuvcodeto the platform-specific compiled binary, matching upstreamopencode-aibehavior. This ensures the compiled ELF binary runs directly instead of through a Node.js launcher script, preventing Bun from loading the CWD'sbunfig.tomlconfiguration.Key changes:
postinstall.mjsthat detects platform/arch and creates symlink to the appropriate binary packagepublish.tsto include postinstall script and copypostinstall.mjsto published packagebuild.tsto enableautoloadTsconfigandautoloadPackageJsoncompiler optionsIssue found:
postinstall.mjsscript only tries to resolve the exact package name (e.g.,shuvcode-linux-x64) and will fail for baseline variants likeshuvcode-linux-x64-baseline. The existingbin/shuvcodelauncher handles this by searching for packages that start with the base name. The postinstall script needs similar fallback logic.Confidence Score: 3/5
packages/opencode/postinstall.mjs- missing baseline variant fallback will cause installation failures on some systemsImportant Files Changed
bin/shuvcodeto platform-specific binary; missing baseline variant fallback logicautoloadTsconfig: trueandautoloadPackageJson: trueto compiler optionspostinstall.mjsto published packageSequence Diagram
sequenceDiagram participant User participant Shell participant NPM as npm/bun participant PostInstall as postinstall.mjs participant BinDir as bin/shuvcode participant PlatformBinary as shuvcode-linux-x64/bin/shuvcode participant BunRuntime as Bun Runtime Note over User,BunRuntime: Installation Phase User->>NPM: bun install -g shuvcode NPM->>NPM: Install main package NPM->>NPM: Install optional dependency (shuvcode-linux-x64) NPM->>PostInstall: Run postinstall script PostInstall->>PostInstall: detectPlatformAndArch() PostInstall->>PostInstall: findBinary() - resolve shuvcode-linux-x64 PostInstall->>BinDir: Create bin/ directory PostInstall->>BinDir: fs.symlinkSync(PlatformBinary, bin/shuvcode) BinDir-->>PostInstall: Symlink created PostInstall-->>NPM: Success NPM-->>User: Installation complete Note over User,BunRuntime: Execution Phase (Before Fix) User->>Shell: shuvcode (in dir with bunfig.toml) Shell->>BinDir: Execute bin/shuvcode (Node launcher script) BinDir->>BunRuntime: #!/usr/bin/env node BunRuntime->>BunRuntime: Read CWD's bunfig.toml BunRuntime->>BunRuntime: Try to load preload "@opentui/solid/preload" BunRuntime-->>User: ERROR: preload not found Note over User,BunRuntime: Execution Phase (After Fix) User->>Shell: shuvcode (in dir with bunfig.toml) Shell->>BinDir: Resolve bin/shuvcode symlink BinDir->>PlatformBinary: Follow symlink to ELF binary PlatformBinary->>PlatformBinary: Execute compiled binary directly PlatformBinary->>PlatformBinary: autoloadBunfig: false (compiled in) PlatformBinary->>PlatformBinary: Ignore CWD's bunfig.toml PlatformBinary-->>User: TUI launches successfully