mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 00:03:46 +00:00
188 lines
7.2 KiB
TypeScript
188 lines
7.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
encodePowerShellCommand,
|
|
getPowerShellOsc133Bootstrap
|
|
} from '../powershell-osc133-bootstrap'
|
|
import {
|
|
buildWslInteractiveLoginShellCommand,
|
|
escapeWslShCommandForWindows
|
|
} from '../../shared/wsl-login-shell-command'
|
|
import { resolveWindowsShellLaunchArgs } from './windows-shell-args'
|
|
|
|
function expectedWslArgs(linuxCwd: string, distro?: string): string[] {
|
|
const command = `cd '${linuxCwd}' && export PATH="$HOME/.local/bin:$PATH" && ${buildWslInteractiveLoginShellCommand()}`
|
|
const shellArgs = ['--', 'sh', '-c', escapeWslShCommandForWindows(command)]
|
|
return distro ? ['-d', distro, ...shellArgs] : shellArgs
|
|
}
|
|
|
|
describe('resolveWindowsShellLaunchArgs', () => {
|
|
it('returns cmd.exe args with chcp 65001 for UTF-8 output', () => {
|
|
const result = resolveWindowsShellLaunchArgs('cmd.exe', 'C:\\Users\\alice', 'C:\\Users\\alice')
|
|
expect(result.shellArgs).toEqual(['/K', 'chcp 65001 > nul'])
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice')
|
|
expect(result.validationCwd).toBe('C:\\Users\\alice')
|
|
})
|
|
|
|
it('returns PowerShell args that install OSC 133 bootstrap after normal profile loading', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'powershell.exe',
|
|
'C:\\Users\\alice',
|
|
'C:\\Users\\alice'
|
|
)
|
|
expect(result.shellArgs).toEqual([
|
|
'-NoLogo',
|
|
'-NoExit',
|
|
'-EncodedCommand',
|
|
encodePowerShellCommand(getPowerShellOsc133Bootstrap())
|
|
])
|
|
|
|
const command = Buffer.from(result.shellArgs[3] ?? '', 'base64').toString('utf16le')
|
|
const outputEncodingIndex = command.indexOf('[Console]::OutputEncoding')
|
|
const opencodeRestoreIndex = command.indexOf(
|
|
'$env:OPENCODE_CONFIG_DIR = $env:ORCA_OPENCODE_CONFIG_DIR'
|
|
)
|
|
const piRestoreIndex = command.indexOf(
|
|
'$env:PI_CODING_AGENT_DIR = $env:ORCA_PI_CODING_AGENT_DIR'
|
|
)
|
|
const ompRestoreIndex = command.indexOf(
|
|
'$env:PI_CODING_AGENT_DIR = $env:ORCA_OMP_CODING_AGENT_DIR'
|
|
)
|
|
const codexRestoreIndex = command.indexOf('$env:CODEX_HOME = $env:ORCA_CODEX_HOME')
|
|
const promptIndex = command.indexOf('function Global:prompt')
|
|
|
|
expect(command).not.toContain('$PROFILE')
|
|
expect(outputEncodingIndex).toBeGreaterThanOrEqual(0)
|
|
expect(opencodeRestoreIndex).toBeGreaterThan(outputEncodingIndex)
|
|
expect(piRestoreIndex).toBeGreaterThan(outputEncodingIndex)
|
|
expect(ompRestoreIndex).toBeGreaterThan(piRestoreIndex)
|
|
expect(codexRestoreIndex).toBeGreaterThan(outputEncodingIndex)
|
|
expect(codexRestoreIndex).toBeGreaterThan(ompRestoreIndex)
|
|
expect(promptIndex).toBeGreaterThan(codexRestoreIndex)
|
|
expect(command).toContain('Esc = [char]27')
|
|
expect(command).toContain('Bel = [char]7')
|
|
expect(command).toContain(')]133;D;$fakeExitCode$(')
|
|
expect(command).toContain(')]133;C$(')
|
|
expect(command).not.toContain('`e]133')
|
|
})
|
|
|
|
it('handles pwsh.exe (PowerShell Core) the same as Windows PowerShell', () => {
|
|
const result = resolveWindowsShellLaunchArgs('pwsh.exe', 'C:\\', 'C:\\Users\\alice')
|
|
expect(result.shellArgs).toEqual([
|
|
'-NoLogo',
|
|
'-NoExit',
|
|
'-EncodedCommand',
|
|
encodePowerShellCommand(getPowerShellOsc133Bootstrap())
|
|
])
|
|
})
|
|
|
|
it('starts Git Bash as an interactive login shell without changing cwd', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
'C:\\Users\\alice\\code',
|
|
'C:\\Users\\alice'
|
|
)
|
|
|
|
expect(result.shellArgs).toEqual(['--login', '-i'])
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice\\code')
|
|
expect(result.validationCwd).toBe('C:\\Users\\alice\\code')
|
|
})
|
|
|
|
it('does not apply Git Bash launch args to unrelated bash.exe paths', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'C:\\msys64\\usr\\bin\\bash.exe',
|
|
'C:\\Users\\alice\\code',
|
|
'C:\\Users\\alice'
|
|
)
|
|
|
|
expect(result.shellArgs).toEqual([])
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice\\code')
|
|
expect(result.validationCwd).toBe('C:\\Users\\alice\\code')
|
|
})
|
|
|
|
it('translates Windows cwd to /mnt/<drive>/... for wsl.exe', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'wsl.exe',
|
|
'C:\\Users\\alice\\code',
|
|
'C:\\Users\\alice'
|
|
)
|
|
expect(result.shellArgs).toEqual(expectedWslArgs('/mnt/c/Users/alice/code'))
|
|
// Why: WSL cannot cd into a Windows path, so node-pty must start from the
|
|
// user's Windows home and we inject the Linux cd into the shellArgs above.
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice')
|
|
expect(result.validationCwd).toBe('C:\\Users\\alice\\code')
|
|
})
|
|
|
|
it('escapes single quotes when translating a WSL cwd', () => {
|
|
const result = resolveWindowsShellLaunchArgs('wsl.exe', "C:\\weird'path", 'C:\\Users\\alice')
|
|
// The injected sh cmd must not break out of the surrounding single quotes
|
|
// when the path contains a ' character.
|
|
expect(result.shellArgs[3]).toContain("cd '/mnt/c/weird'\\''path'")
|
|
expect(result.shellArgs[3]).toContain('exec "\\$_orca_wsl_shell" -l')
|
|
})
|
|
|
|
it('falls back to /mnt/c when cwd is not a drive-letter path', () => {
|
|
const result = resolveWindowsShellLaunchArgs('wsl.exe', '\\\\server\\share', 'C:\\Users\\alice')
|
|
expect(result.shellArgs[3]).toContain(
|
|
'cd \'/mnt/c\' && export PATH="\\$HOME/.local/bin:\\$PATH"'
|
|
)
|
|
})
|
|
|
|
it('keeps WSL UNC worktree cwd inside the matching distro', () => {
|
|
const originalPlatform = process.platform
|
|
Object.defineProperty(process, 'platform', {
|
|
configurable: true,
|
|
value: 'win32'
|
|
})
|
|
|
|
try {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'wsl.exe',
|
|
'\\\\wsl.localhost\\Ubuntu\\home\\alice\\repo',
|
|
'C:\\Users\\alice'
|
|
)
|
|
expect(result.shellArgs).toEqual(expectedWslArgs('/home/alice/repo', 'Ubuntu'))
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice')
|
|
expect(result.validationCwd).toBe('\\\\wsl.localhost\\Ubuntu\\home\\alice\\repo')
|
|
} finally {
|
|
Object.defineProperty(process, 'platform', {
|
|
configurable: true,
|
|
value: originalPlatform
|
|
})
|
|
}
|
|
})
|
|
|
|
it('keeps POSIX cwd inside the worktree distro when WSL context is provided', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'wsl.exe',
|
|
'/home/alice/repo/subdir',
|
|
'C:\\Users\\alice',
|
|
{ distro: 'Ubuntu', treatPosixCwdAsWsl: true }
|
|
)
|
|
|
|
expect(result.shellArgs).toEqual(expectedWslArgs('/home/alice/repo/subdir', 'Ubuntu'))
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice')
|
|
expect(result.validationCwd).toBe('\\\\wsl.localhost\\Ubuntu\\home\\alice\\repo\\subdir')
|
|
})
|
|
|
|
it('falls back to empty args + same cwd for unknown shells', () => {
|
|
const result = resolveWindowsShellLaunchArgs(
|
|
'C:\\tools\\fish.exe',
|
|
'C:\\Users\\alice',
|
|
'C:\\Users\\alice'
|
|
)
|
|
expect(result.shellArgs).toEqual([])
|
|
expect(result.effectiveCwd).toBe('C:\\Users\\alice')
|
|
expect(result.validationCwd).toBe('C:\\Users\\alice')
|
|
})
|
|
|
|
it('is case-insensitive on the shell basename', () => {
|
|
const result = resolveWindowsShellLaunchArgs('PowerShell.EXE', 'C:\\', 'C:\\')
|
|
expect(result.shellArgs).toEqual([
|
|
'-NoLogo',
|
|
'-NoExit',
|
|
'-EncodedCommand',
|
|
encodePowerShellCommand(getPowerShellOsc133Bootstrap())
|
|
])
|
|
})
|
|
})
|