diff --git a/bin/openclaude b/bin/openclaude index a66e13659..9f3f66e7f 100755 --- a/bin/openclaude +++ b/bin/openclaude @@ -75,9 +75,19 @@ function relaunchWithLongSessionHeapIfNeeded() { arg => !arg.startsWith('--max-memory=') && arg !== '--max-memory', ) + // Preserve the original argv[1] (which may be a symlink like + // /usr/local/bin/openclaude) instead of resolving it via import.meta.url. + // Resolving symlinks here defeats install-type detection downstream: a real + // npm global install (symlink → node_modules/@gitlawb/openclaude/bin) would + // resolve to the package's real path inside node_modules, which is fine, but + // a `npm install -g .` dev symlink resolves back to the repo and looks like + // a source-tree dev run. Using argv[1] keeps the invocation path stable so + // doctorDiagnostic's npm-global path markers can match correctly. + const launcherPath = process.argv[1] || fileURLToPath(import.meta.url) + const result = spawnSync(process.execPath, [ ...execArgv, - fileURLToPath(import.meta.url), + launcherPath, ...childArgs, ], { stdio: 'inherit', diff --git a/src/utils/doctorDiagnostic.ts b/src/utils/doctorDiagnostic.ts index 34aabeeb8..122f6ad4c 100644 --- a/src/utils/doctorDiagnostic.ts +++ b/src/utils/doctorDiagnostic.ts @@ -99,10 +99,6 @@ function getNormalizedPaths(): [invokedPath: string, execPath: string] { } export async function getCurrentInstallationType(): Promise { - if (process.env.NODE_ENV === 'development') { - return 'development' - } - const [invokedPath] = getNormalizedPaths() // Check if running in bundled mode first @@ -158,6 +154,15 @@ export async function getCurrentInstallationType(): Promise { return 'npm-global' } + // Development build: running from a source tree (e.g. `bun run dev`) with + // NODE_ENV=development. Checked AFTER all real-install path markers so that + // a user shell exporting NODE_ENV=development can't downgrade a real npm + // install to 'development' (which would block /update). A source-tree run + // matches none of the path markers above, so it lands here. + if (process.env.NODE_ENV === 'development') { + return 'development' + } + // If we can't determine, return unknown return 'unknown' }