mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 00:03:08 +00:00
fix(windows): support VS Code Insiders WSL launch
This commit is contained in:
@@ -20,7 +20,7 @@ The deterministic reproduction for `\\wsl.localhost\Ubuntu\home\aliuq\project` p
|
||||
## Design
|
||||
|
||||
1. In the external-editor launch-spec builder, parse the target path with the shared WSL UNC parser when the host platform is Windows.
|
||||
2. For direct/executable VS Code launchers only, reuse the existing normalized launcher-basename check and translate a recognized WSL target into `['--remote', 'wsl+<distro>', '<linuxPath>']`. The match is case-insensitive and strips every Windows launcher suffix already supported by Orca (`.cmd`, `.exe`, and `.bat`), so direct paths such as `Code.exe` and resolved shims such as `CODE.CMD` or `code.bat` all identify as basename `code`.
|
||||
2. For direct/executable VS Code Stable or Insiders launchers only, reuse the existing normalized launcher-basename check and translate a recognized WSL target into `['--remote', 'wsl+<distro>', '<linuxPath>']`. The exact allowlist recognizes Stable's `code`, Insiders' `code-insiders`, and the direct `Code - Insiders.exe` basename without matching unrelated `code-*` editors. Matching is case-insensitive and strips every Windows launcher suffix already supported by Orca (`.cmd`, `.exe`, and `.bat`).
|
||||
3. Keep local paths, non-Windows hosts, non-VS-Code applications, and compound commands on their existing argument paths. The existing main-process spawn and Windows shim handling remain unchanged.
|
||||
4. Replace the temporary reproduction harness with focused regression cases in `src/main/external-editor-launch.test.ts` covering modern and legacy WSL UNC forms plus unaffected local/custom-editor behavior.
|
||||
|
||||
@@ -49,7 +49,7 @@ The deterministic reproduction for `\\wsl.localhost\Ubuntu\home\aliuq\project` p
|
||||
- Unit: demonstrate the pre-fix launch spec lacks `--remote` for a modern WSL UNC path.
|
||||
- Unit: assert the fixed modern UNC launch is `--remote`, `wsl+Ubuntu`, `/home/...`.
|
||||
- Unit: assert legacy `\\wsl$` and distro-root paths produce the same Remote - WSL form.
|
||||
- Unit: assert direct and resolved Windows VS Code launchers are matched case-insensitively across `.exe`, `.cmd`, and `.bat` suffixes.
|
||||
- Unit: assert direct and resolved Windows VS Code Stable and Insiders launchers are matched case-insensitively across `.exe`, `.cmd`, and `.bat` suffixes.
|
||||
- Unit: assert distro names and Linux folder paths containing spaces remain intact arguments through launch-spec construction and Windows shim forwarding.
|
||||
- Unit: assert a Windows local path remains unchanged and explicit `darwin` and `linux` hosts do not acquire WSL remote arguments.
|
||||
- Unit: assert Cursor and another custom editor are not given VS Code remote arguments.
|
||||
|
||||
@@ -136,13 +136,18 @@ describe('resolveExternalEditorLaunchSpec', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('opens modern WSL UNC workspaces in the matching VS Code remote', () => {
|
||||
expect(
|
||||
resolveExternalEditorLaunchSpec('code', '\\\\wsl.localhost\\Ubuntu\\home\\aliuq\\project', {
|
||||
platform: 'win32'
|
||||
}).spawnArgs
|
||||
).toEqual(['--remote', 'wsl+Ubuntu', '/home/aliuq/project'])
|
||||
})
|
||||
it.each(['code', 'code-insiders'])(
|
||||
'opens modern WSL UNC workspaces with %s in the matching VS Code remote',
|
||||
(editorCommand) => {
|
||||
expect(
|
||||
resolveExternalEditorLaunchSpec(
|
||||
editorCommand,
|
||||
'\\\\wsl.localhost\\Ubuntu\\home\\aliuq\\project',
|
||||
{ platform: 'win32' }
|
||||
).spawnArgs
|
||||
).toEqual(['--remote', 'wsl+Ubuntu', '/home/aliuq/project'])
|
||||
}
|
||||
)
|
||||
|
||||
it.each([
|
||||
[
|
||||
@@ -161,8 +166,10 @@ describe('resolveExternalEditorLaunchSpec', () => {
|
||||
|
||||
it.each([
|
||||
'C:\\Program Files\\Microsoft VS Code\\Code.exe',
|
||||
'C:\\Program Files\\Microsoft VS Code Insiders\\Code - Insiders.exe',
|
||||
'C:\\Tools\\CODE.CMD',
|
||||
'C:\\Tools\\code.bat'
|
||||
'C:\\Tools\\code.bat',
|
||||
'C:\\Tools\\code-insiders.cmd'
|
||||
])('recognizes the direct Windows VS Code launcher %s', (editorCommand) => {
|
||||
expect(
|
||||
resolveExternalEditorLaunchSpec(
|
||||
@@ -173,23 +180,26 @@ describe('resolveExternalEditorLaunchSpec', () => {
|
||||
).toEqual(['--remote', 'wsl+Ubuntu', '/home/ada/project'])
|
||||
})
|
||||
|
||||
it.each(['C:\\Tools\\CODE.CMD', 'C:\\Tools\\code.bat'])(
|
||||
'recognizes the resolved Windows VS Code launcher %s',
|
||||
(resolvedCommand) => {
|
||||
resolveCliCommandMock.mockReturnValueOnce(resolvedCommand)
|
||||
it.each([
|
||||
['code', 'C:\\Tools\\CODE.CMD'],
|
||||
['code', 'C:\\Tools\\code.bat'],
|
||||
['code-insiders', 'C:\\Tools\\code-insiders.cmd']
|
||||
])('recognizes the resolved Windows VS Code launcher %s', (editorCommand, resolvedCommand) => {
|
||||
resolveCliCommandMock.mockReturnValueOnce(resolvedCommand)
|
||||
|
||||
expect(
|
||||
resolveExternalEditorLaunchSpec('code', '\\\\wsl.localhost\\Ubuntu\\home\\ada\\project', {
|
||||
platform: 'win32'
|
||||
})
|
||||
).toEqual({
|
||||
kind: 'executable',
|
||||
hideWindowsConsole: true,
|
||||
spawnCmd: resolvedCommand,
|
||||
spawnArgs: ['--remote', 'wsl+Ubuntu', '/home/ada/project']
|
||||
})
|
||||
}
|
||||
)
|
||||
expect(
|
||||
resolveExternalEditorLaunchSpec(
|
||||
editorCommand,
|
||||
'\\\\wsl.localhost\\Ubuntu\\home\\ada\\project',
|
||||
{ platform: 'win32' }
|
||||
)
|
||||
).toEqual({
|
||||
kind: 'executable',
|
||||
hideWindowsConsole: true,
|
||||
spawnCmd: resolvedCommand,
|
||||
spawnArgs: ['--remote', 'wsl+Ubuntu', '/home/ada/project']
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves spaces in WSL distro and folder arguments', () => {
|
||||
expect(
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getCmdExePath } from './win32-utils'
|
||||
|
||||
export const EXTERNAL_EDITOR_CLI_COMMAND = 'code'
|
||||
const WINDOWS_CONSOLE_EDITORS = new Set(['nvim', 'vim'])
|
||||
const VSCODE_REMOTE_EDITORS = new Set(['code', 'code-insiders', 'code - insiders'])
|
||||
|
||||
export type ExternalEditorLaunchSpec =
|
||||
| {
|
||||
@@ -112,12 +113,13 @@ function buildExecutableArgs(
|
||||
pathValue: string,
|
||||
platform: NodeJS.Platform
|
||||
): string[] {
|
||||
if (getLauncherBaseName(editorCommand) === 'cursor') {
|
||||
const launcherBaseName = getLauncherBaseName(editorCommand)
|
||||
if (launcherBaseName === 'cursor') {
|
||||
// Why: Cursor can route bare folder launches through the last active
|
||||
// workbench. A new window keeps "Open in Cursor" scoped to this worktree.
|
||||
return ['--new-window', pathValue]
|
||||
}
|
||||
if (platform === 'win32' && getLauncherBaseName(editorCommand) === 'code') {
|
||||
if (platform === 'win32' && VSCODE_REMOTE_EDITORS.has(launcherBaseName)) {
|
||||
const wslPath = parseWslUncPath(pathValue)
|
||||
if (wslPath) {
|
||||
// Why: VS Code otherwise treats a WSL UNC path as a local Windows folder.
|
||||
|
||||
Reference in New Issue
Block a user