fix(app): dev CLI beats a persisted/global codeburn path

The dev-mode repo dist/cli.js fallback ran AFTER the persisted-path file,
so a stale globally-installed codeburn (e.g. a Homebrew build lacking the
new sessions/compare commands) shadowed the repo build and every Sessions
call errored. Move the Vite-dev fallback ahead of the persisted-path
lookup; CODEBURN_BIN still overrides, and production (no VITE_DEV_SERVER_URL)
is unchanged.
This commit is contained in:
iamtoruk 2026-07-11 16:48:36 -07:00
parent 781d37674b
commit ea56ed33f0
2 changed files with 33 additions and 7 deletions

View file

@ -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 = ''

View file

@ -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
}