Package the portable DSH profiles, local plugins, desktop integration, Firefox wrapper, and ownership-aware installer lifecycle. Bundle checksum-pinned OpenVSCode, editor extensions, translation assets, and cloudflared so unreliable upstream artifact downloads cannot break a clean installation. |
||
|---|---|---|
| .. | ||
| editor-file-bridge | ||
| editor-preferences | ||
| lib | ||
| scripts | ||
| test | ||
| .gitignore | ||
| cordis.patch.yml | ||
| editor-release.json | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
DSH Git workspaces
The Git Working Dirs dropdown in the session header lists directories recorded by the agent's existing add/remove/get tools. It sits immediately left of the right-aligned … utilities menu. Each valid directory has an Open VS Code button that opens a separate browser tab using OpenVSCode Server (Code OSS, not Microsoft's branded VS Code distribution).
Startup and resource contract
- Importing the plugin, registering tools, adding a directory, listing directories, polling, and mounting the Git Working Dirs header action never start an editor.
- Only a successful explicit Open VS Code action calls the POST launch endpoint.
- A blocked popup does not request startup.
- One loopback server is shared by all workspaces in this DSH host process. Concurrent requests share one startup promise.
- Each opened browser workspace may have its own extension host, language servers, Git watchers, and terminals. Keep unnecessary tabs and extensions closed.
- Reopening a directory focuses its existing browser window when the DSH client still has that window reference. Refreshing DSH loses these in-memory references; reopening may create another tab. It never deliberately reloads an existing editor whose reference was lost, preserving unsaved work.
- Closing an editor tab does not stop the shared server. VS Code owns extension-host reconnection and cleanup. The launcher does not force idle shutdown, which could terminate active terminals or other workspaces.
- Server exit or startup failure does not trigger an automatic restart. A subsequent explicit click may start it again.
- Plugin disposal requests server shutdown. Do not restart DSH while editor terminals or unsaved work are active without saving first.
Git-scope guard for write and edit
The plugin checks both structured file-changing tools before dispatch:
- A target outside Git is allowed with an explicit warning.
- A target in a Git repository or linked worktree is blocked unless that exact root is registered in the current session's Git Working Dirs menu.
- New, untracked files inside a registered repository are allowed; this is repository-scope enforcement, not an index-membership requirement.
- Nested repositories, submodules, and linked worktrees are separate scopes. The active-header repository and another session's registrations do not grant permission.
- Paths are resolved through DSH's filesystem provider and checked physically, including new parent directories and symlinks. Broken Git metadata, probe failures, missing session identity, and uncertain scope fail closed.
- Registration must finish before a dependent write. A blocked mutation must not be rerouted through a shell or another tool.
An async preflight supplies a per-call certificate to DSH's synchronous monotonic tool guard. A secondary check validates the actual filesystem-intent target and preserves the existing observation intent. DSH's sandbox, approval, read-before-write, and stale-version checks are not replaced.
Boundary: this guards registry calls named write and edit, including those dispatched through Code Mode. It does not police arbitrary shell/Python commands, external editors, other mutation tools, or direct plugin filesystem calls. Like the existing provider boundary, it is not immune to malicious filesystem changes racing between path validation and use. It is a workflow guard, not a kernel filesystem sandbox or a hostile-plugin security boundary.
Expanded tool diffs and file actions
Both file-tool rows reuse the installed dsh-diff-viewer split renderer, expanded by default with no line-count clipping and horizontal scrolling for long lines. Settled successful results show their actual supplied hunks; running calls label proposed changes, and errors remain errors rather than appearing as applied diffs. Warnings remain visible alongside the diff.
The installed dsh-diff-viewer 0.1.1 profile package originally kept DiffViewer private. Its source entry and generated client bundle currently expose that component for this integration. Replacing or recomposing that package can overwrite the compatibility export; upstreaming the public export is the durable fix.
Every row has an Open in VS Code button followed by a native Open button that uses the same Host file-opening callback as read-tool path links. Running/failed calls and historical calls without a successful mutation record show a disabled button with an explanation. New successful calls record only session/call identity, canonical path, and repository in touched-git/mutations.json, not file contents. The button never guesses a target from today's working directory or the active Git selection.
Rendering diffs and retrieving button metadata do not launch an editor. On click, the host revalidates the recorded regular file, its physical path, and current Git registration. A non-Git file remains openable with a warning, in its parent-folder workspace; no repository is initialized or auto-registered.
For an existing workspace, the bundled workspace extension receives an acknowledged file-open request through a private local Unix socket and uses the public VS Code document API. It never saves, reverts, closes, or reloads an existing editor. The socket directory is private per runtime launch, and each socket is mode 0600. New workspaces receive a file-open startup payload instead. If an existing bridge fails, the action reports the error instead of reloading or opening a replacement workspace. After DSH-page refresh loses browser window references, an existing workspace can still receive the file; the UI asks the user to switch to that tab when it cannot focus it.
Install
Requires Linux x64, curl, tar, Python 3, and Node.js. The runtime is a pinned portable archive with its original license files preserved. It is installed beside the plugin, not globally and not as a service.
node scripts/install-editor.mjs
The installer reads editor-release.json, downloads from the official GitHub release, verifies the pinned SHA-256 before extraction, and installs into ignored runtime/current/. It also installs the local preferences and file-bridge extensions. It never starts the editor. A matching installation is reused. Updating the pin does not silently overwrite an existing runtime.
If the release host is unreachable, download openvscode-server-v1.109.5-linux-x64.tar.gz separately and install with the same mandatory checksum verification:
node scripts/install-editor.mjs --archive /path/to/openvscode-server-v1.109.5-linux-x64.tar.gz
The downloader honors curl's standard proxy environment variables. No proxy is required by the running editor.
Release provenance: https://github.com/gitpod-io/openvscode-server/releases/tag/openvscode-server-v1.109.5
After plugin changes, save active editor work, restart your existing DSH web service yourself, and refresh http://127.0.0.1:3080. Reopen editor workspaces from the refreshed Git Working Dirs menu so the new runtime receives its private bridge directory. Tabs connected to a runtime started before the bridge update cannot gain that startup environment through a page refresh alone. No replacement DSH server is needed. Client HMR is not assumed.
To install/update the two bundled extensions in an already installed runtime without starting a server:
node scripts/install-editor-extensions.mjs
Then open Git Working Dirs → Open VS Code. Select Source Control (Ctrl+Shift+G) for Git status, staging, commits, and diffs. Extension availability follows OpenVSCode Server's configured extension registry; Microsoft Marketplace compatibility is not guaranteed.
Security and data
The editor binds only to 127.0.0.1 on an OS-assigned port and requires a fresh random connection token for each server lifetime. The token is stored in a private per-launch directory with file mode 0600, passed via --connection-token-file, and returned only by the no-store launch response. Do not share the editor URL: it contains its access token. Normal editor authentication may retain browser cookies or history.
The launch route requires POST, a same-origin custom header, the plugin's existing loopback/Host/Origin fence, and a valid directory tracked by that session. It revalidates the repository before startup. This is a trusted local-user editor, not a sandbox: a user with editor access can use terminals and access the local account's files beyond the initially opened folder. Do not expose the editor port through a tunnel or public reverse proxy.
At the user's request, the bundled preferences extension disables workspace trust by default, selects Dark Modern and JetBrains Mono, and hides the secondary sidebar. Trust prompts and restricted-mode protections therefore no longer protect unfamiliar folders after those defaults are applied. Telemetry is disabled. Only a limited environment needed by local tools is passed to the editor, rather than copying DSH's entire environment.
Server data and installed extensions live in ${DSH_HOME:-~/.dsh}/touched-git/editor/. OpenVSCode's web user settings are browser-local. Runtime binaries are ignored by Git. Tracked directory state remains in the existing store and is unchanged by this integration.
Editor preferences
editor-preferences/extension.js is the authoritative default-settings declaration. The installer packages this small web extension locally and installs it through OpenVSCode's extension CLI, without starting a server. It uses the public VS Code configuration API instead of writing an unused server-side user settings file.
On first activation it applies the requested settings. Versioned per-setting updates apply newly requested defaults once without resetting unrelated preferences. Later activations preserve explicit user changes and seed only missing defaults, including after a new browser origin is created. It closes the auxiliary sidebar on workspace startup, but does not disable chat features; the user can reopen them. The extension supports untrusted workspaces so it can apply the trust preference there too.
For an existing runtime, install or update just the preferences with:
node scripts/install-editor-preferences.mjs
Refresh the VS Code tab to load a newly installed preferences extension. No DSH service restart is needed.
Validation
npm test
node --check lib/index.js
node --check lib/client.js
node --check lib/editor-runtime.js
node --check lib/editor-route.js
node --check scripts/install-editor.mjs
git diff --check
Tests use fake editor processes and browser windows. They do not start a real editor or restart DSH.
Live acceptance after the user restarts DSH:
- Before opening a workspace, verify no OpenVSCode server is running.
- Open the Git Working Dirs menu and allow directory polling; verify it still has not started.
- Click Open VS Code for a tracked repository; verify that folder opens and Source Control shows its Git state.
- Open another tracked directory; verify a distinct workspace uses the same server port.
- Click the first directory again; verify its existing tab is focused.
- Attempt
writeandeditinside an unregistered test repository; verify denial and unchanged contents. Register it, then verify a read-before-write-aware retry succeeds. - Verify an outside-Git write succeeds with a warning.
- Verify both file-tool rows show all diff hunks expanded and retain errors/warnings.
- Click a recorded file's Open button, then repeat with an unsaved buffer in that workspace; verify file navigation without reloading or losing unsaved contents.
- Verify old calls without recorded provenance remain readable, with disabled file actions rather than guessed targets.
The old read-only Git helper routes and vendored libraries remain available for compatibility, but the new tab does not fetch or render them. The previous custom UI is preserved in baseline commit 0e8c9d2.