[codex] Share Docker agent auth across containers#2
Draft
brooksc wants to merge 27 commits into
Draft
Conversation
Drag a file or paste an image-from-Finder into the terminal and the absolute path is typed (escaped, then wrapped via term.paste so xterm emits bracketed-paste markers). CLI agents like Claude Code see the path as a paste rather than literal typing, which triggers their file-attachment recognition and turns "/Users/.../image.png" into [Image #N] instead of a "no such file" error. Implementation: - new IPC ResolveClipboardPaste — main-process picks file URL → image → text in priority order, so Finder-copied image files pass an absolute path instead of the bare basename - new IPC SaveDroppedImage — base64 round-trip (renderer's invoke() wrapper destroys typed arrays via JSON.parse(JSON.stringify())) so browser-origin <img> drops still produce a usable temp path - webUtils.getPathForFile exposed via preload as window.electron.getPathForFile (Electron 32+ replacement for File.path) - TerminalView capture-phase dragover/drop listeners so xterm's own bubble-phase handler doesn't insert the basename first - escapePath helper backslash-escapes whitespace + shell metacharacters so paths round-trip cleanly through both POSIX shells and agent prompt parsers - legacy SaveClipboardImage handler removed Linux clipboard support reads x-special/gnome-copied-files (Files, Nemo, Caja) ahead of text/uri-list (KDE, Xfce). Per-file resolution runs in its own try/catch so one unreadable item in a mixed drop doesn't cancel the resolvable siblings. Temp filenames append a 6-char random suffix so concurrent same-name drops don't collide. Spec captured under openspec capability terminal-image-paste (6 requirements, 32 scenarios) plus an archived change record at openspec/changes/archive/2026-04-28-support-paste-images/. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Panels gated their focus border on `isActive && focusedPanel[id] === '...'`, which stayed true after the sidebar grabbed focus. Centralize the predicate in `isPanelFocused`/`isPanelFocusedPrefix` so sidebar/placeholder focus also suppresses the border. Also enter the leftmost task on Right from sidebar and drop the dead `data-shell-focused` attribute.
Add Copilot CLI to the supported-agents list, expand "More features" with focus mode, steps panel, PR CI watcher, notes-to-agent, worktree import, project Dockerfiles, coverage radar, configurable keybindings, and folders-without-git support. Bump theme count from 6 to 10. Add Ctrl+Shift+F to the shortcuts table.
The Terminal and bookmark buttons stopped click propagation, which kept the parent's focusedPanel handler from running while their actions did not touch focus — so any previously focused panel hung onto its border until the user clicked elsewhere.
TUI renderers (Claude Code, etc.) pad each rendered line out to terminal width and emit real \n at wrap points, so the clipboard ends up with ragged trailing whitespace and mid-paragraph hard breaks. Cmd+C / Ctrl+Shift+C now run the selection through a deterministic pipeline: normalize CR/CRLF, strip per-line trailing whitespace, then reflow paragraphs whose interior lines are uniformly long (≥40 chars, variance ≤8). Haiku-shaped and tabular content stays intact. Hooked at both the keybinding handler and a capture-phase DOM `copy` listener — the latter catches Electron's default Edit→Copy menu role, which fires a synthetic copy event that bypasses attachCustomKeyEventHandler.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a branch's history contains commits that are patch-equivalent to ones already on main (e.g. from a `git merge origin/main` followed by a rebase that re-applies those merged-in commits with new SHAs), the changed-files view used to surface them as branch work. Add a cherry-pick refinement layer on top of the existing merge-base picker: filter unique commits via `git log --cherry-pick --right-only` and, when they're contiguous at the tip, refine the diff base to the oldest unique commit's parent. Falls back to the picked base on interleaving or any failure.
…k calls Address review findings on the cherry-pick refinement layer: - When `git log --cherry-pick` returns no unique commits the branch is fully merged upstream — return `head...head` instead of the picked base, so the user sees zero changes instead of the patch-equivalent noise (`base...head` would still surface every duplicate file). - Embed parent SHA via `--pretty=%H %P` and drop the separate `git rev-parse <sha>^` call (1 fewer git invocation per refinement). - Log the interleaved fallback path so it's diagnosable. - Rename `mergeBaseCache` → `diffBaseCache` (now stores PickedMergeBase post-refinement, not just the raw merge-base SHA). Tests: flip the fully-merged assertion to expect the empty range, add a multi-commit contiguous case, and cover the from-branch refinement path.
Chevron-left from "All" now lands on a new "uncommitted only" view before stepping into commit history; a U pill sits left of the All pill as a direct affordance. The diff viewer mirrors the state via a new GetUncommittedFileDiffs IPC built from git diff HEAD plus untracked pseudo-diffs (extracted shared helper).
`checkMergeStatus` counted `HEAD..mainBranch` raw, so a rebased branch whose history carried patch-equivalents of recent main commits would trigger a false "Rebase onto main first" prompt. Switch to `rev-list --cherry-pick --right-only --no-merges HEAD...mainBranch`, matching the cherry-pick filter the changed-files diff base uses, so patch-equivalent commits stop counting as ahead. Scope kept to local mainBranch — that's what mergeTask and rebaseTask operate on, so the count tracks what the dialog's buttons can fix.
Multi-agent review (correctness reviewer, empirically reproduced on git 2.43.0) caught that --no-merges silently drops merge commits whose own content is unique to main (evil merges / non-trivial merge resolutions). Combined with --cherry-pick --right-only this turned a real "Rebase first" warning into a zero, hiding the rebase need from the dialog. The flag was a copy-paste from refineDiffBaseWithCherryPick, where it's load-bearing because that helper parses %H %P and assumes single parents. Here we only ask for --count, so the flag is gratuitous — worse than that, it's wrong. Tests: assert --no-merges is *absent* from the rev-list args. Folded the >0-ahead test into a richer case that exercises the merge-tree conflict probe (previously asserted only the count). Added a docstring back-reference in refineDiffBaseWithCherryPick so the dual filter is discoverable from either direction.
The isActive gate skipped both the initial fetch and the 5 s poll, so non-active tasks had an empty file list until something inside the panel was clicked. CommitNavBar buttons stopPropagation, so navigating with U / All / chevrons changed selectedCommit but never activated the task — the panel stayed empty until you clicked its body. Always run the initial refresh on mount and on input changes; keep polling gated on isActive so off-screen tasks don't run a git pipeline every 5 s.
console.* writes to process.stdout/stderr asynchronously, so an EPIPE from a closed parent pipe surfaces as an unhandled stream 'error' event the per-call try/catch can't catch. Install module-level handlers that swallow EPIPE and re-throw anything else, so a routine teardown (e.g. concurrently SIGTERMing us after vite dies) no longer becomes an Uncaught Exception. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Embed ChangedFilesList in the diff viewer dialog so users can switch between files without closing the dialog. Track the open file via an activeFilePath signal mirrored from the scrollToFile prop, and pass it into the list to highlight the current row. Forward coverageReportPath through TaskPanel → DiffViewerDialog → ChangedFilesList so coverage overlays stay in sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Codex arguments * Add Codex argument regression tests
- Use path.basename() for agent command lookup so full paths work - Incorporate relDir into hostDir to avoid cross-contamination if an agent has multiple config dirs in future - Create host auth dirs with mode 0o700 to restrict access to credentials - Degrade gracefully if mkdirSync fails rather than aborting Docker spawn - Add shareDockerAgentAuth to autosave snapshot so toggling persists immediately Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude stores its main auth config in ~/.claude.json (at HOME level) in addition to ~/.claude/ — without mounting this file, credentials written in the first container are lost when the container exits and the next container prompts for login again. Also add a note to the new-task Docker info message when auth sharing is enabled so users know credentials will carry over. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
An empty file causes Claude to reject it as invalid JSON on startup. Seed it with a valid empty object so the container starts cleanly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
Docker-mode agents currently start with a fresh writable home each time, so users have to re-sign into Claude, Codex, Gemini, OpenCode, or Copilot for every new Docker container. That repeated authentication overhead makes Docker isolation less appealing, especially when creating multiple worktrees or trying short-lived tasks.
This PR adds an opt-in setting to share agent auth across Linux containers. When enabled, the app creates a user-owned host directory under
~/.parallel-code/agent-auth/<agent>and bind-mounts it into that agent's config directory inside Docker, such as/tmp/.codexor/tmp/.claude. Signing in once inside a Docker container then persists for later Docker containers of the same agent type, including containers launched from different worktrees.Implementation
shareDockerAgentAuthsetting and a checkbox in Settings.Limitations
~/.codexor~/.claude; it persists credentials created inside Docker after the setting is enabled.Validation
npm test -- electron/ipc/pty.test.tsnpm run typechecknpm run lint -- --quietnpm run format:checknpm run check.