feat(providers): docker provider foundation (pty / filesystem / git)#1349
Open
mvanhorn wants to merge 2 commits intostablyai:mainfrom
Open
feat(providers): docker provider foundation (pty / filesystem / git)#1349mvanhorn wants to merge 2 commits intostablyai:mainfrom
mvanhorn wants to merge 2 commits intostablyai:mainfrom
Conversation
Adds Docker as a fourth provider triple alongside local and SSH. Pure plumbing: pty / filesystem / git providers + docker engine detection + image build + container lifecycle + bind-mount path resolution. No user-facing UI yet, no dispatch wiring. Mirrors the SSH provider triple's API. Cross-platform: macOS (Docker Desktop / Colima), Linux (Docker Engine, rootless), Windows (Docker Desktop WSL2 named pipe). Tests cover happy and error paths through a docker-engine-fake.ts recorder, so no real Docker daemon is required. Foundation PR for the docker isolation series. Follow-ups will add the user-facing toggle and dispatch wiring.
- Allocate TTY for Docker PTY sessions via tty flag on spawnExec, so isatty() returns true for shells, vim, and ncurses programs. - Return originalContent + modifiedContent for working-tree diffs instead of returning a unified patch as modifiedContent. - Return blob contents for branch diffs and honor options.oldPath for renames, matching the local provider's GitDiffResult shape. - Preserve the new path as path and the old path as oldPath when parsing R100 rename entries (was reversed). - Surface git porcelain v2 u records as unresolved conflict entries so docker worktrees in conflict show their conflicted files. - Resolve repo default branch via origin/HEAD before browseFile, instead of hardcoding 'main' for remote file URLs.
This was referenced May 2, 2026
Contributor
|
@nwparker should be able to get to this soon! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Docker as a fourth provider triple alongside local and SSH. Pure plumbing: pty / filesystem / git providers + docker engine detection + image build + container lifecycle + bind-mount path resolution. No UI, no dispatch wiring.
This is the foundation PR for an opt-in Docker isolation feature. Follow-up PRs add the worktree-level toggle and dispatch routing. Worktree-native stays the default and remains zero-friction for everyone else.
Motivation: Sculptor (Imbue) ships per-task Docker container isolation as its pillar feature, and users in agent-orchestration discussions ask for the same primitive on Orca. Issue #993 ("Something like an ai orchestrator") and Discussion #681 (multi-agent orchestration coordinator pattern, 15 comments) both signal demand for sandboxed agent execution.
Architectural fit:
src/main/providers/already abstracts pty / filesystem / git through three interfaces with two implementations (local, SSH). Docker is a third target. The new triple mirrors the SSH triple's API exactly so the upcoming dispatch PR slots in cleanly.Screenshots
No visual UI change. This PR is foundation-only: provider classes plus docker engine modules with no dispatch wiring or runtime behavior yet (the follow-up PR adds the user-facing toggle, the third PR wires it up).
A simulated demo of the architectural change this PR adds:
Simulated demo (Remotion). Shows the three provider triples (local, ssh, docker-new) and the receipts: 17 files, 2474 lines, 41 tests, 0 dispatch edits.
Testing
pnpm lintpnpm typecheckpnpm test --run src/main/providers/docker-*.test.ts src/main/docker/pnpm buildplatform. Real Docker integration is out of scope for this PR and gated behindRUN_DOCKER_E2E=1for follow-up work.AI Review Report
A code review pass was run before submission. Risks checked:
/mnt/<drive>path translation). All platform branches covered indocker-engine-detect.test.tsanddocker-mount.test.tsvia injectedplatformso the same suite passes on each OS.getDiffandgetBranchDiffreturnoriginalContentandmodifiedContent(not unified-patch text); rename parsing keepspathas the new path andoldPathas the old; porcelain v2urecords surface as conflict entries;getRemoteFileUrlresolves the actual default branch viaorigin/HEADinstead of hardcodingmain. These were flagged and fixed before submission.DockerPtyProviderrequeststty: truefrom the engine client so interactive programs see a real terminal. Caveat below.helpers.ts/utils.ts), project types in.tsnot.d.ts, no hardcodedmetaKey, all paths viapath.joinorpath.posix.join.Known caveat surfaced by review: when wired in a future PR,
docker exec -tfrom a piped-stdio Electron parent can fail with "input device is not a TTY" on some packaged builds. The cleanest fix is wrapping the docker CLI under node-pty, matching the local provider's pattern. This PR's TTY flag is correct; the wrapping happens in the dispatch PR. Search-flag handling (useRegex,wholeWord, include/exclude patterns) and binary-blob metadata in diffs are also follow-up items, called out for the wiring PR.Security Audit
Input handling: only the host paths the user already trusts (worktree path, Dockerfile path) flow into engine commands. No user-supplied strings are interpolated into shell.
Command execution: the engine client builds argv arrays for
child_process.spawn(no shell). All user paths land as separate argv entries, never concatenated.Path handling: bind-mount source is the host worktree; mount target is
/workspaceinside the container. Windows paths are translated via the dedicated helper with vitest coverage so the translation is auditable.IPC and preload: this PR does not add or change any IPC handler. The provider classes are not yet routed through
provider-dispatch. No new exposed surface from main to renderer.Dependencies: no
package.jsonorpnpm-lock.yamlchanges.Auth and secrets: no auth flow changes. The agent inside a container would run with the host user's uid/gid (when wired in PR 3); credentials remain on the host filesystem and are not copied into images.
Follow-up: the dispatch PR will need its own audit covering how routing decisions are gated and how the toggle persists.
Notes
This is PR 1 of a 3-PR series. The other two PRs add the user-facing toggle (worktree row, repo settings) and the dispatch wiring (provider-dispatch + orca-runtime + image cache UX). Each lands independently; PR 1 has no observable behavior change on its own.
Tested on macOS. Linux and Windows behavior covered in unit tests via injected platform.
X: @mvanhorn
AI was used for assistance.