Skip to content
Closed
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
32 changes: 32 additions & 0 deletions src/utils/__tests__/bundledMode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { afterEach, describe, expect, test } from 'bun:test'
import { isBunVirtualPath, isInBundledMode } from '../bundledMode.js'

const originalArgv = [...process.argv]

afterEach(() => {
process.argv = [...originalArgv]
})

describe('isBunVirtualPath', () => {
test('detects POSIX bun virtual filesystem paths', () => {
expect(isBunVirtualPath('/$bunfs/root/claude-sidecar')).toBe(true)
})

test('detects Windows bun virtual filesystem paths', () => {
expect(isBunVirtualPath('B:\\~BUN\\root\\claude-sidecar.exe')).toBe(true)
})

test('ignores regular filesystem paths', () => {
expect(isBunVirtualPath('/Applications/Claude.app/Contents/MacOS/claude-sidecar')).toBe(false)
})
})

describe('isInBundledMode', () => {
test('treats bun-compile virtual entrypoints as bundled even when embeddedFiles is empty', () => {
process.argv = ['bun', '/$bunfs/root/claude-sidecar']

expect(Array.isArray(Bun.embeddedFiles)).toBe(true)
expect(Bun.embeddedFiles.length).toBe(0)
expect(isInBundledMode()).toBe(true)
})
})
25 changes: 21 additions & 4 deletions src/utils/bundledMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,31 @@ export function isRunningWithBun(): boolean {
return process.versions.bun !== undefined
}

const BUN_VIRTUAL_PATH_MARKERS = ['/$bunfs/', '/~bun/']

export function isBunVirtualPath(candidatePath: string | null | undefined): boolean {
if (!candidatePath) {
return false
}

const normalized = candidatePath.replace(/\\/g, '/').toLowerCase()
return BUN_VIRTUAL_PATH_MARKERS.some(marker => normalized.includes(marker))
}

/**
* Detects if running as a Bun-compiled standalone executable.
* This checks for embedded files which are present in compiled binaries.
* Bun compile loads the entry module from Bun's virtual filesystem
* (`/$bunfs/...` on POSIX, `~BUN\\...` on Windows). `Bun.embeddedFiles`
* alone is not sufficient because compiled binaries can still report an
* empty embedded file list at runtime.
*/
export function isInBundledMode(): boolean {
if (typeof Bun === 'undefined') {
return false
}

return (
typeof Bun !== 'undefined' &&
Array.isArray(Bun.embeddedFiles) &&
Bun.embeddedFiles.length > 0
isBunVirtualPath(process.argv[1]) ||
(Array.isArray(Bun.embeddedFiles) && Bun.embeddedFiles.length > 0)
)
}
9 changes: 1 addition & 8 deletions src/utils/ripgrep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { homedir } from 'os'
import * as path from 'path'
import { logEvent } from 'src/services/analytics/index.js'
import { fileURLToPath } from 'url'
import { isInBundledMode } from './bundledMode.js'
import { isBunVirtualPath, isInBundledMode } from './bundledMode.js'
import { logForDebugging } from './debug.js'
import { isEnvDefinedFalsy } from './envUtils.js'
import { execFileNoThrow } from './execFileNoThrow.js'
Expand All @@ -22,20 +22,13 @@ const __dirname = path.join(
process.env.NODE_ENV === 'test' ? '../../../' : '../',
)

const BUN_VIRTUAL_PATH_MARKERS = ['$bunfs', '~BUN']

type RipgrepConfig = {
mode: 'system' | 'builtin' | 'embedded' | 'unavailable'
command: string
args: string[]
argv0?: string
}

function isBunVirtualPath(candidatePath: string): boolean {
const normalized = candidatePath.replace(/\\/g, '/')
return BUN_VIRTUAL_PATH_MARKERS.some(marker => normalized.includes(marker))
}

export function isUsableBuiltinRipgrepPath(candidatePath: string): boolean {
return !isBunVirtualPath(candidatePath) && existsSync(candidatePath)
}
Expand Down
Loading