Scan merge proofs run with lazy fetches and transports off, so partial
clones never download blobs; direct WSL reads forward those variables.
Base and coordinator refs resolve once per repo per scan, and the squash
search lists target commits once and only patch-ids commits that touch
the branch's exact file set.
gh 2.91.0 and 2.92.0 start `gh send-telemetry` with DETACHED_PROCESS. Its
`tzutil /g` child then gets a new console, which shows a terminal window for
about 0.2s. Orca's background PR polling runs gh about once a minute, so
Windows users on those gh versions see the window every few minutes while
Orca sits idle. Default GH_TELEMETRY to false in the gh child env, next to
GH_PROMPT_DISABLED, and keep any value the user already set.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Adds commit actions to the Git Graph: check out a commit or branch, cherry-pick, revert, and create a branch from a commit. Conflicts hand off to Source Control with continue and abort. Works on local, WSL and remote hosts.
* Upload GitHub images when pasted or dropped
Keep image bytes out of issue and review bodies by uploading from the owning composer and inserting hosted attachment URLs.
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>
* Preserve GitHub image intake across editor and thread states
* Keep image placeholder boundaries and ordinary HTML paste intact
* Match the native replace overload in the image projection fixture
* Use typed element queries in the image intake fixture
* Narrow textarea elements at the fixture boundary
* Show failed GitHub draft images as filename links
* Keep GitHub draft attachment links current across updates
* Supply the repository address in the attachment preview fixture
---------
Co-authored-by: lydiassssz <60514233+lydiassssz@users.noreply.github.com>
* Keep a lifetime owner for claimed worktree preparation
* Record preparation ownership loss before retirement
* Type the preparation lock-write fixture without an assertion
* Revoke preparation cleanup when ownership changes
* fix(git): refuse unsafe branch switches in an existing workspace
The phone's Switch branch ran `git checkout` with no checks: uncommitted
files moved to the other branch, and a switch could land under a working
agent or mid-rebase. One host check now covers every client: it refuses,
with a plain reason, when files are uncommitted, a merge/rebase/
cherry-pick/revert is in progress, HEAD is detached or unborn, another
git action is running, or an agent in the checkout is working or waiting
for approval. Checks and the checkout run under a per-checkout lock.
After a switch the host clears the old branch's review links and push
target and tells every client, so a phone-only host stays correct, and
records that the user chose the branch so first-work naming never
renames it. The open Commits list follows the new branch.
* fix(git): review round 1 repairs for the guarded branch switch
- check out through the provider so the user's switch keeps the interactive git queue
- a landed switch that Windows left files behind on now tells the user instead of reporting success
- never let a Windows yes/no prompt hold the switch lock
- refuse submodule edits that submodule ignore config hides from status
- record the switch on the target host's metadata row and never fail a landed switch on bookkeeping
- read workspace paths from their ids instead of scanning the catalog on every switch
- admit agent rows like the sidebar roster (listed tab, or a live terminal by pane, tab or handle)
- move the host-side switch hooks into their own module
* test: type the new switch test fakes instead of casting them
* fix(git): second repair round for the guarded branch switch
- report files Windows left behind from git's own unlink warnings, not a status re-read, so
ordinary branch differences and submodule commit changes are never called failures
- the phone refreshes its branch and files after a switch that landed with a warning
- refuse only edits inside a submodule its ignore config hides, never a commit mismatch alone,
reading status without optional locks in the interactive queue
- read the agent process probe when a switch runs, not while the runtime is constructed
- check the agent's checkout path before terminal liveness and build the tab list once per switch
- the runtime wiring test no longer reaches real git
* fix(git): scope the switch's agent check to the checkout and keep landed-switch outcomes honest
- find candidate agents by checkout path first; build terminal liveness once, only from this
checkout's terminals and its workspaces' saved tabs; probe candidates together and re-read
the snapshot once; no work for unrelated workspaces (contract test at N and 10N)
- a checkout that fails after HEAD moved is recorded as landed; files left behind are named only
when git reports it could not replace them, otherwise git's own error is shown
- parse git's unlink warnings for paths with apostrophes
- the phone keeps the refusal or warning visible while it reloads the branch
- cover a submodule that is only at another commit
* fix(git): name git's own error when a switch lands after a failing hook; use the shared unlink parser
* fix(git): keep the switch's agent check flat for unrelated folder workspaces
- read folder workspace directories once per switch instead of a linear search per row and terminal
- re-read each candidate's current status by pane key instead of rebuilding the whole snapshot
- skip the hidden-submodule status pass in repos without submodules
- the cost contract covers folder workspaces, many in-checkout agents and PTY passes
- a real-git test covers a switch that lands before a failing post-checkout hook
* fix(git): never quote git's progress line as a landed switch's error; fixed clock in the cost test
* fix(git): decide the hidden-submodule check from the index, not a visible .gitmodules
* perf(git): read only index modes for the submodule shortcut so large repos stay under the output cap
* fix(git): keep the agent-terminal credential guard scalar-only so env scrubs can't break git
Agents that scrub env names matching KEY/TOKEN/... (DeepSeek Harness) dropped
GIT_CONFIG_KEY_n but kept GIT_CONFIG_COUNT, so every git command in those
terminals failed with "missing config key GIT_CONFIG_KEY_0". GCM_INTERACTIVE
already carries credential.interactive and suppresses GCM's GUI, so the guard
now emits only scalar variables. Tracked in #26594.
Co-authored-by: yu.xia <yuxianice@163.com>
* chore(git): drop stale indexed-config comments and a dead WSL forward branch
---------
Co-authored-by: yu.xia <yuxianice@163.com>
- Codex managed-home ownership check runs async in the distro via runWslProcess, fenced
- transcript running observer reuses fresh running-list reads; 5s cadence, first look at 2s
- synchronous Git refuses a WSL cwd; the setup runner reads a WSL worktree's .git link instead
* test: remove low-value suites and cases
* test: shrink flaky-pattern counts after case removals
* test: remove empty suite and stale release workflow fixture
Buffered gitExecFileAsync reads now always fence login-shell rc output, and
non-zero exits de-fence error.stdout. The per-call captureWslLoginShellOutput
opt-in is removed since it is no longer meaningful.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(wsl): user clicks on cwd-less gh may start the stopped default distro
#35709 stopped background gh/glab from booting a stopped default distro,
which also refused explicit clicks for users whose gh lives only in WSL.
Starring Orca, the auth diagnosis, the project picker, opening a work
item and board edits now run as a user act on the distro the fallback
uses; the board table reload, which also runs unprompted, stays gated.
The GitHub and GitLab rate-limit cards keep their last snapshot on the
not-running refusal instead of flipping to unavailable.
* fix(wsl): only an explicit click may start the stopped distro for project gh calls
Wrapping the project-view and auth-diagnosis IPC handlers as user acts
also let mount effects (useProjectViewTable listing a restored board's
views, GhAuthErrorHelp's diagnosis) start a stopped default distro. The
handlers now wake only when the renderer passes wakeWslDistro, which the
picker browse/select, opening an item and every edit set; mount effects
leave it unset, and the auth diagnosis never wakes.
* fix(wsl): every local Git call follows its project's runtime unless it says why not (D1c-6)
* fix(wsl): rebuild Git routes on the store's own writes, never on a timer, and route a new worktree by its link
* fix(wsl): route WSL-made worktree links, aliased checkouts and sync Git; host Git only where marked; no wsl.exe storms
* fix(wsl): map WSL-made worktree links through each project distro's automount root
* fix(wsl): arm the missing-distro cache only with the Git router on, and feed it spawn failures
* fix(wsl): keep synchronous Git host-only, read the setup runner's path from the link, and keep the sync launch under the ratchet
* chore(wsl): move the sync Git runner's process-host import allowance with it
* fix(wsl): read only per-worktree git paths from the link, and only from a git dir that still exists
* fix(wsl): name which Git ran on stream and spawn spans too, so status shows its route
* test(wsl): setup runner lookups declare host Git; cover the link read with the router on and off
The hooks tests expected the setup runner's `rev-parse --git-path` call to
carry `wslDistro: 'Ubuntu'` for a WSL-runtime project. On main that field
never reached Git: main's gitExecFileSync options have no wslDistro and it
calls resolveCommand('git', args, cwd) with no distro override, so the
lookup ran host Git (WSL only when the cwd itself is a WSL path). The tests
pinned call arguments, not what ran. The sync runner now states that with
`hostGit: true` and resolves exactly as main did, so the tests assert that.
New worktree-runner-script-link tests cover the router-gated link read:
router on reads the link; router on with no usable link falls back to host
Git and converts its Linux path; router off makes main's host Git call and
never reads the link.
* test(git): read src/main once in the host-Git routing guard, so it holds under load
* test(wsl): pin the setup runner's sync Git spawn to main's exact launch on POSIX
The setup runner's path lookup now passes hostGit: true where it passed a
wslDistro that gitExecFileSync never read, so the binary, args, cwd and env
it spawns are unchanged. Update the call-shape assertions and pin the POSIX
execFileSync call itself.
(cherry picked from commit 6aae6d4d090e13b75c1d9ad2734f2f717dde7570)
* fix(wsl): await WSL Git admission in spawns only when there is one
With the Git router off admitWslGit returns null; awaiting it anyway added a
microtask to every spawn's admission path that main doesn't have.
(cherry picked from commit 883aaeb90bc23e89cafb039708a565ab3d72620e)
* fix(wsl): keep main's Git scheduling when the D1c Git router is off
The remote-identity sweep moved every user's probes to the background
admission tier, which only the router reads; it now keeps its tier unless the
router is on. Admission wrapping and the spawn stderr tail also step aside
without the router, so those calls run exactly as on main.
(cherry picked from commit 151a3091307c03078d0c0b98487bbe3bf467ec27)
* test(wsl): point the distro allowlist test at the sync runner's new home, as host Git
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 255e85fc93deba83addc4370f889c1b721180188)
* test(wsl): installing the Git router with the gate closed or off Windows leaves none installed
Co-Authored-By: Claude <noreply@anthropic.com>
* perf(wsl): skip the span-only Git resolution on every spawn while the Git router is off
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): read a distro's automount root only from a running list probed after its stop settled, so it never boots a terminated distro
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Cwd-less gh/glab calls whose host CLI is missing fell back to the default
WSL distro with no running check, so background work (rate limits, auth
status, Settings, task-source probes) booted a stopped distro. The
fallback now asks the background exec gate first: stopped or
unverifiable refuses with the distro-stopped error, running and user
acts fall back as before.
* feat(wsl): run Git for Windows for a WSL project on a Windows drive
A project on C:\ whose runtime is WSL ran every Orca Git command through wsl.exe on
/mnt/c: ~300x slower than Windows Git, and blind to Windows-side edits. The project's
WSL runtime preference gains an optional `git: 'windows-host'`. With it, Orca's Git
(and where new worktrees go) is Windows; terminals, agents, accounts and hooks still
resolve to WSL, so nothing else changes. Older builds drop the field and go back to WSL
Git.
The conversion checks first, then the caller saves the returned preference through the
normal project update:
- Git for Windows must exist.
- New worktrees must not be set to go inside the distro.
- No linked worktree may have a Linux-path link. WSL Git made those; Windows Git sees
them as prunable, and Orca's prune after a worktree removal would delete their
metadata.
- Optionally writes core.autocrlf=true into the repo when Windows Git uses it, so WSL
Git in the project's terminals stops seeing CRLF changes. Never core.checkStat.
IPC is refused off Windows and with the internal WSL hosts gate closed.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl): mock the drive-project IPC in the core handler registration test
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl): pin WSL Git for a drive project that never chose Windows Git, and record which Git ran
* fix(wsl): base-ref lookups and the remote-identity sweep run Git where the project's runtime does
* fix(wsl): route base-ref and remote-identity reads by runtime only with WSL hosts on
These reads ran host Git on main. Routing them into a WSL-runtime project's
distro is part of D1c, so with the WSL hosts gate closed they run host Git
exactly as before.
(cherry picked from commit 2ed82987dc5b82c3a86ea7e03ce05e9efc3e77fb)
* refactor(ipc): register the filesystem handlers in one call, keeping core registration under its line cap
The optional commit-message resolvers pass straight through, so the call is the same with or
without them. #34059 left this file at the 300-line cap and the WSL drive-project wiring adds to it.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): skip folder repos in the Windows Git check, and read worktree links with the prune guard's reader
Folder repos run no Git, so rev-parse on them always failed the preview. The link reader and
the WSL-authored test now come from worktree-prune-guard.ts; the copy's startsWith('/') wrongly
refused //wsl.localhost links, which Windows Git writes itself.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): the remote-identity sweep checks the distro a drive project's Git runs in, so it never boots a stopped one
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix: bound local iteration checks and show live progress
* fix: harden check lifecycles and cached test evidence
* fix: preserve process instrumentation and fixture lifecycles
* fix: give fixture unref spy a portable function type
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* feat(wsl): internal distro allowlist for WSL execs on shared test boxes
ORCA_INTERNAL_WSL_DISTRO_ALLOWLIST (comma-separated distro names) keeps every
wsl.exe call out of distros not on the list: process-host's resolveSpawn,
the main and daemon node-pty spawns, and the two codex-accounts calls that
bypass process-host. Pure list/status/version calls stay allowed; any other
form must name an allowlisted distro, and --shutdown or a default-distro exec
is refused. A malformed value refuses every distro and logs once. Unset, the
check reads the variable and returns, so behavior is identical to today.
* fix(wsl): cover every direct wsl.exe exec with the internal distro allowlist
- Restore #34525's worktree-create payload and captured-host test, reverted by
accident in the first commit.
- Check the allowlist in execFileCapture, the choke point for WSL Git, gh and
worker-thread captures, and before the WSL git-read probe, the Codex hook
path canonicalization and the CLI login spawn. The WSL watcher now spawns
through process-host.
- Stop scanning wsl.exe argv at the first positional argument, which wsl.exe
runs in the default distro.
- check-process-host-imports fails on any direct wsl.exe exec outside
process-host that does not call assertWslDistroAllowed.
* fix(wsl): check the distro allowlist where resolveCommand produces the wsl.exe form
Every Git, gh and glab path into a distro resolves through resolveCommand, so
gitExecFileSync, gitSpawn, git stream reads and wslAwareSpawn are covered too;
the execFileCapture check is now redundant and removed. The import check also
treats buildWslExecArgs as a wsl.exe exec and accepts resolveCommand as covered.
* fix(wsl): say why a silent WSL guest command failed
A guest command that exits non-zero with empty stderr was reported as
"WSL <distro>: command failed". When wsl.exe itself fails it writes its
error to stdout, so the real cause was dropped. Report stderr, else
wsl.exe's own error, else the exit code, for the Claude account pointer,
OpenCode reader, WSL CLI install and WSL file operations.
Refs STA-12262 (#33917)
* refactor(wsl): share the wsl.exe host-failure exit check
* test(wsl): type the guest failure fixture instead of asserting it
* fix(wsl): background Git and the roots catalog never start a stopped WSL distro
git status ran on the UNC project root 0.45 s after a terminate, next to the
explorer read; either boots the distro. Background Git (status, conflict
operation, upstream status, branch compare, the upstream-ref watch) now asks the
shared running gate first and refuses for a stopped distro, including host
paths whose Git runs through wsl.exe. The authorized-roots rebuild skips a
stopped distro's repo and leaves it dirty, and the detected-worktree scan fails
as unavailable, so rows are kept and the next scan after the distro runs lists it.
* fix(wsl): the active workspace's first status and a wake read's roots rebuild may start WSL
- Drive-path projects whose Git runs through WSL had no wake path: the active
workspace's first git:status after it becomes active now passes
wakeWslDistro, so Source Control starts the distro; later polls stay gated.
- A user act runs in an async scope naming its distro; gated work inside it
(the authorized-roots rebuild an authorization miss triggers, the detected
scan, the Git) may start that distro and no other. External worktrees on a
stopped distro no longer fail a wake read with access denied.
- After a user act wakes a distro, background reads stop trusting the older
'stopped' read and probe again.
* fix(wsl): explicit WSL launches refresh the running read; wake only on tab change; gate the home probe
- Any wsl.exe Git/CLI run (commit, push, fetch) or WSL terminal spawn for a
distro last read as stopped records that it started, so background reads probe
again instead of refusing for up to 60 s.
- The active editor tab wakes only when the active tab changes; effect re-runs
driven by git status or overview views read without waking.
- The authorization roots' WSL home probe no longer runs wsl.exe in a stopped
distro when the home is uncached.
- The settle window no longer imports the orcad liveness module (it pulled main
code into the web typecheck); a test pins it to EXIT_SETTLE_MS.
* fix(wsl): deferred work and running-list listeners never inherit a user act
A user act's async scope could leak into work it triggers indirectly: a drain of
deferred tasks it caused, or listeners of a running-list probe started inside
it. Both now run outside the scope, so only the act's own work may start its
distro.
* fix(wsl): keep shared modules free of main-only gate imports
worktree-logic.ts and wsl-running-distro-cache.ts are also compiled by the web
project, which cannot see main-only modules (AsyncLocalStorage, wsl.exe).
getAllowedRoots now injects the gated home lookup into computeWorkspaceRootWithin,
and the background gate's own cache subscriptions run outside the user-act scope
instead of the cache knowing about it.
Issue create (including the empty-body fallback and follow-up PATCH),
issue body edits, and issue comments passed the body as
`--raw-field body=...` on argv. Windows caps the command line at
32,767 chars, so bodies with pasted inline images failed with
`spawn ENAMETOOLONG` before reaching GitHub.
These calls now use `gh api -X <METHOD> <endpoint> --input -` with a
JSON payload on stdin. ghExecFileWithScopeAsync also now forwards
`options.stdin` to the child process; it was previously dropped.
Fixes#15832
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>