diff --git a/app/electron/cli.test.ts b/app/electron/cli.test.ts index b179551..94bcda0 100644 --- a/app/electron/cli.test.ts +++ b/app/electron/cli.test.ts @@ -47,6 +47,25 @@ describe('resolveCodeburnPath (Vite development)', () => { expect(resolveCodeburnPath()).toMatch(/dist\/cli\.js$/) }) + it('prefers the repo dev CLI over a persisted-path file (stale global) in dev', () => { + // A persisted global (e.g. an older Homebrew codeburn) must NOT shadow the + // repo build in dev, or newly-added commands break. Regression: 0.9.15 + // lacked `sessions`, so the persisted path produced a CLI error. + delete process.env.CODEBURN_BIN + process.env.CODEBURN_PATH_DIRS = '' + const persistedTarget = join(dir, 'stale-codeburn') + writeFileSync(persistedTarget, '#!/usr/bin/env node\n', { mode: 0o755 }) + chmodSync(persistedTarget, 0o755) + const persistedFile = join(dir, 'cli-path.v1') + writeFileSync(persistedFile, persistedTarget) + process.env.CODEBURN_CLI_PATH_FILE = persistedFile + process.env.VITE_DEV_SERVER_URL = 'http://localhost:5173' + + const resolved = resolveCodeburnPath() + expect(resolved).toMatch(/dist\/cli\.js$/) + expect(resolved).not.toBe(persistedTarget) + }) + it('does not return the repo dev CLI outside the Vite dev server', () => { delete process.env.CODEBURN_BIN process.env.CODEBURN_PATH_DIRS = '' diff --git a/app/electron/cli.ts b/app/electron/cli.ts index 49651a7..aa054f2 100644 --- a/app/electron/cli.ts +++ b/app/electron/cli.ts @@ -97,19 +97,23 @@ function readPersistedPath(): string | null { /** * Resolve the absolute path to the `codeburn` binary, or null if not found. - * Order: dev override (`CODEBURN_BIN`) → persisted-path file → repo CLI in - * Vite development → PATH / brew / nvm / volta / asdf → null. + * Order: dev override (`CODEBURN_BIN`) → repo CLI in Vite development → + * persisted-path file → PATH / brew / nvm / volta / asdf → null. + * + * The dev repo CLI intentionally beats the persisted-path file: in `npm run + * dev` the developer is iterating on this repo, so its freshly-built + * `dist/cli.js` must win over a stale globally-installed/persisted binary + * (which may lack newly-added commands). Setting `CODEBURN_BIN` still overrides + * everything. In production `VITE_DEV_SERVER_URL` is unset, so the persisted + * path behaves exactly as before. */ export function resolveCodeburnPath(): string | null { const override = process.env.CODEBURN_BIN if (override && override.startsWith('/') && isExecutableFile(override)) return override - const persisted = readPersistedPath() - if (persisted) return persisted - // Dev convenience: when launched by the Vite dev server, prefer the repo's own - // freshly-built CLI over a stale globally-installed one, so newly-added - // commands (sessions/compare/act JSON) work without setting CODEBURN_BIN. + // freshly-built CLI over a stale globally-installed/persisted one, so + // newly-added commands (sessions/compare/act JSON) work without CODEBURN_BIN. if (process.env.VITE_DEV_SERVER_URL) { const devBin = join(__dirname, '..', '..', '..', 'dist', 'cli.js') if (isExecutableFile(devBin)) return devBin @@ -119,6 +123,9 @@ export function resolveCodeburnPath(): string | null { if (isExecutableFile(sourceDevBin)) return sourceDevBin } + const persisted = readPersistedPath() + if (persisted) return persisted + for (const bin of searchDirs().map(dir => join(dir, 'codeburn'))) { if (isExecutableFile(bin)) return bin }