fix: preserve packaged windows cli launcher (#4180)

This commit is contained in:
Neil
2026-05-31 07:11:33 -07:00
committed by GitHub
parent 0ffdfb569b
commit 5577fb0541
2 changed files with 85 additions and 0 deletions
+40
View File
@@ -668,6 +668,46 @@ describe('CliInstaller', () => {
)
})
it('does not overwrite the packaged Windows launcher while registering PATH', async () => {
const fixture = await makeFixture()
const localAppDataPath = fixture.root
const resourcesPath = join(localAppDataPath, 'Programs', 'Orca', 'resources')
const bundledLauncher = join(resourcesPath, 'bin', 'orca.cmd')
const bundledContent = '@echo off\r\necho bundled-orca %*\r\n'
await mkdir(dirname(bundledLauncher), { recursive: true })
await writeFile(bundledLauncher, bundledContent, 'utf8')
let userPath: string | null = null
const installer = new CliInstaller({
platform: 'win32',
isPackaged: true,
resourcesPath,
localAppDataPath,
userDataPath: fixture.userDataPath,
execPath: join(localAppDataPath, 'Programs', 'Orca', 'Orca.exe'),
appPath: fixture.appPath,
userPathReader: async () => userPath,
userPathWriter: async (value) => {
userPath = value
}
})
const installed = await installer.install()
expect(installed.state).toBe('installed')
expect(installed.pathConfigured).toBe(true)
expect(installed.commandPath).toBe(bundledLauncher)
expect(userPath).toBe(dirname(bundledLauncher))
await expect(readFile(bundledLauncher, 'utf8')).resolves.toBe(bundledContent)
const removed = await installer.remove()
expect(removed.state).toBe('not_installed')
expect(removed.pathConfigured).toBe(false)
expect(userPath).toBe('')
await expect(readFile(bundledLauncher, 'utf8')).resolves.toBe(bundledContent)
})
// Why: the arm64 fallback must apply for packaged builds, not just dev launchers.
it.skipIf(process.platform === 'win32')(
'resolves to ~/.local/bin/orca on arm64 even when isPackaged is true',
+45
View File
@@ -173,6 +173,9 @@ export class CliInstaller {
} else if (this.isLinuxAppImage()) {
await this.installAppImageWrapper(status.commandPath, status.launcherPath)
await this.removeLegacyLinuxCommandIfManaged(status.launcherPath)
} else if (this.isWindowsPackagedBundledCommand(status.commandPath, status.launcherPath)) {
// Why: packaged Windows already ships resources/bin/orca.cmd. Registration
// only owns the user PATH entry; rewriting the asset makes it recurse.
} else {
// Why: mkdir stays here for the Windows wrapper path — the target dir is
// user-writable (%LOCALAPPDATA%) so EACCES cannot occur. The symlink path
@@ -215,6 +218,8 @@ export class CliInstaller {
if (status.installMethod === 'symlink') {
await this.removeSymlink(status.commandPath)
await this.removeLegacyLinuxCommandIfManaged(status.launcherPath)
} else if (this.isWindowsPackagedBundledCommand(status.commandPath, status.launcherPath)) {
await this.removeWindowsPathEntry(dirname(status.commandPath))
} else {
await unlink(status.commandPath)
await this.removeWindowsPathEntry(dirname(status.commandPath))
@@ -571,6 +576,19 @@ export class CliInstaller {
return this.platform === 'linux' && Boolean(this.appImagePath)
}
private isWindowsPackagedBundledCommand(
commandPath: string | null,
launcherPath: string | null
): commandPath is string {
return (
this.platform === 'win32' &&
this.isPackaged &&
commandPath !== null &&
launcherPath !== null &&
samePathEntry('win32', commandPath, launcherPath)
)
}
private async inspectWindowsWrapper(
commandPath: string,
launcherPath: string
@@ -589,6 +607,18 @@ export class CliInstaller {
})
}
if (this.isWindowsPackagedBundledCommand(commandPath, launcherPath)) {
return this.buildStatus({
commandPath,
launcherPath,
installMethod: 'wrapper',
supported: true,
state: 'installed',
currentTarget: launcherPath,
detail: `Registered at ${commandPath}.`
})
}
const currentContent = await readFile(commandPath, 'utf8')
const expectedContent = buildWindowsForwarder(launcherPath)
return this.buildStatus({
@@ -657,6 +687,21 @@ export class CliInstaller {
pathDirectory: string,
pathConfigured: boolean
): CliInstallStatus {
if (
this.isWindowsPackagedBundledCommand(status.commandPath, status.launcherPath) &&
status.state === 'installed' &&
!pathConfigured
) {
return {
...status,
pathDirectory,
pathConfigured,
state: 'not_installed',
currentTarget: null,
detail: `Register ${status.commandPath} to use Orca from Command Prompt or PowerShell.`
}
}
if (status.state !== 'installed') {
return {
...status,