Skip to content

feat: open the active workspace in VS Code, local or over SSH (#63) - #65

Merged
Lexus2016 merged 1 commit into
mainfrom
feat/63-open-in-vscode
Aug 24, 2026
Merged

Lexus2016 merged 1 commit into
mainfrom
feat/63-open-in-vscode

Conversation

@Lexus2016

Copy link
Copy Markdown
Owner

Closes #63.

What you get

A project row and the file viewer hand the workspace to your desktop editor. A remote SSH project opens through VS Code Remote-SSH already at the right path — no reconnecting, no hunting for the folder.

Selectable in Settings → UI: VS Code, Insiders, VSCodium, Cursor, Windsurf.

Why there are two launch paths

The studio is not always running on the machine the browser is on, and each way of opening an editor is broken in the case the other handles:

detectable? opens on
code <path> spawned by the server yes — $PATH either resolves it or not the server host — wrong in Docker, over a tunnel, from a phone
vscode://… deep link followed by the browser no — no browser reports whether a protocol handler exists or ran the machine with the screen

POST /api/editor/open prefers the CLI and falls back to the deep link. A resolvable code binary means the server is a workstation, so it opens the window itself and can report failure honestly; no binary means Docker / headless / Windows, and there the browser follows vscode://. One rule, no process.platform test, correct in every deployment shape.

Because the deep-link outcome is genuinely unobservable, the SPA states the condition every time it takes that path ("if nothing opened, …") instead of claiming an error it cannot see.

The two URI shapes are not the same string

browser :  vscode://vscode-remote/ssh-remote+user@host/srv/app
CLI     :  --folder-uri vscode-remote://ssh-remote+user@host/srv/app

In the first, the editor's scheme is the scheme and vscode-remote is the URI authority — that is how the desktop URL handler routes it. In the second, vscode-remote is the scheme. Collapse them and one path silently stops working. Both are pinned literally in the tests.

Guards

  • $PATH is walked in-process, never through which/where. A subprocess would need a shell on Windows, and the launched value is a user-chosen filesystem path — the BatBadBut re-parse delegate-terminal.js already had to work around. _EXEC_EXTS excludes .CMD on purpose: Node refuses to spawn one without shell: true, so accepting it would turn every Windows launch into a throw instead of the deep-link fallback that works there.
  • Authorisation is the file browser's resolver, not a second guard: you may open in an editor whatever you may browse. It also supplies the default-WORKDIR fallback and isRemote from the project record — inferring remoteness from the path would hand a local POSIX-looking workdir to Remote-SSH.
  • A ~/project remote workdir is refused by name. A URI has no shell, so Remote-SSH would look for a directory literally called ~. Resolving it would need an SSH round trip.
  • A non-standard SSH port is carried into the authority. Dropping it is not the cautious choice — the connection would then be attempted against 22 and fail.
  • Per-file open is local-only. The remote folder link works; VS Code's URL handler opens a remote file uri as a folder (vscode-remote-release#4333). The button comes off rather than doing the wrong thing; the project row still opens the remote workspace.
  • The editor is a fixed catalog, not a binary-name field — the value becomes both a URI scheme and an argv[0].

Verification

npm test — 65 files, exit 0, 0 failures.

  • test/editor-links.test.js — 57 assertions: both URI shapes literally, port handling, percent-encoding (a # that would truncate the path, a : that must survive for a Windows drive letter), ~/backslash/NUL/newline refusals, traversal containment on both sides, the fork catalog, plus source-level pins on the wiring (resolveFilesWorkdir is the authoriser, no shell:, .CMD stays out, loadMergedConfig resolves editor with ||).
  • test/editor-open-api.test.js — 22 assertions against a real booted server: local + remote links end to end, the host and non-standard port surviving data/projects.json → URI, a 403 for an unregistered workdir, 400s for traversal / NUL / non-string, the default-workspace fallback, and the configured editor reaching both the URI scheme and /api/version. $PATH points at an empty directory, which makes opened:'client' deterministic and guarantees the suite never launches an editor window on a developer's desktop.

Not shipped, deliberately

"Reveal current file" and "Open terminal in VS Code" from the issue's Additional Enhancements — neither has a URI or CLI primitive that does the right thing across the local/remote split. Remote per-file open is blocked upstream (above).

🤖 Generated with Claude Code

A project row and the file viewer now hand the workspace to a desktop
editor. A remote SSH project opens through VS Code Remote-SSH already at
the right path, instead of reconnecting and hunting for the folder by hand.

Two ways exist to do this from a web app, and the studio needs both,
because it is not always running on the machine the browser is on:

  * the `code` CLI, spawned by the server. Detectable — it either resolves
    on $PATH or it does not — but it opens a window on the SERVER host,
    which is wrong inside Docker, over a tunnel, or from a phone.
  * a `vscode://` deep link, followed by the browser. Lands on the machine
    with the screen, by definition. Nothing about it is detectable: no
    browser reports whether a protocol handler exists or ran.

`POST /api/editor/open` prefers the first and falls back to the second, so
a workstation opens its own window and a container hands the browser a
link — one rule, no `process.platform` test, correct in every deployment.
The SPA states the condition every time it takes the deep-link path rather
than claiming an error it cannot observe.

`editor-links.js` is the pure half. The two URI shapes are NOT the same
string and conflating them silently breaks one path:

    browser :  vscode://vscode-remote/ssh-remote+user@host/srv/app
    CLI     :  --folder-uri vscode-remote://ssh-remote+user@host/srv/app

Notes on the guards:

- $PATH is walked in-process, never through `which`/`where`. A subprocess
  would need a shell on Windows, and the launched value is a user-chosen
  filesystem path — the BatBadBut re-parse delegate-terminal.js already had
  to work around. `_EXEC_EXTS` excludes `.CMD` deliberately: Node refuses to
  spawn one without `shell: true`, so accepting it would turn every Windows
  launch into a throw instead of the deep-link fallback that works there.
- Authorisation reuses `resolveFilesWorkdir()` — "you may open in an editor
  whatever you may browse" — which also supplies the default-WORKDIR
  fallback and `isRemote` from the PROJECT RECORD. Inferring remoteness from
  the path would hand a local POSIX-looking workdir to Remote-SSH.
- A `~/project` remote workdir is refused by name: a URI has no shell, so
  Remote-SSH would look for a directory literally called `~`.
- Per-file open is local-only. The remote FOLDER link works; VS Code's URL
  handler opens a remote FILE uri as a folder
  (microsoft/vscode-remote-release#4333).
- The editor is a fixed catalog (VS Code, Insiders, VSCodium, Cursor,
  Windsurf), not a binary-name field: the value becomes both a URI scheme
  and an argv[0]. Settings gets its row from `config-resolve.js`.

Tests: `test/editor-links.test.js` (57) pins the URI shapes literally plus
the wiring; `test/editor-open-api.test.js` (22) boots a real server with
$PATH pointed at an EMPTY directory, which makes the `opened:'client'`
fallback deterministic and guarantees the suite never launches an editor
window on a developer's desktop.

Closes #63

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lexus2016
Lexus2016 merged commit 4ae8659 into main Aug 24, 2026
2 checks passed
@Lexus2016
Lexus2016 deleted the feat/63-open-in-vscode branch August 24, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Open Current Workspace Directly in VS Code (Local or Remote SSH)

1 participant