* ci: install fish 4 from its GitHub release when the Launchpad PPA is down
* TEMP: skip the fish PPA to prove the GitHub release fallback (revert)
* Revert "TEMP: skip the fish PPA to prove the GitHub release fallback (revert)"
This reverts commit 58ba0c5074.
* ci: install pinned fish directly from its verified release
* ci: isolate standalone fish from runner resources
* Prepare template assembly during qualification and cache Intel downloads
* Limit early template qualification polling to fifteen seconds
* Verify Windows retains its download cache policy
* Drop Intel store restoration after measuring its overhead
* Parallelize adhoc Mac architecture packaging
* Include parallel Mac jobs in release timing reports
* Cover parallel Mac publication and failure gates
* Explicitly scope archive targets to each Mac architecture
* ci: one list for Windows boundary tests and one step for ratchets
The Windows boundary step's 74 test paths were hand-listed in pr.yml and
again in WINDOWS_PACKAGE_TESTS, and the copies had drifted: six files ran
in the step but could not trigger the job. The step now prints
WINDOWS_BOUNDARY_TESTS, which WINDOWS_PACKAGE_TESTS spreads.
The ten per-ratchet preflight steps and the eight lint entries become one
run-ratchets.mjs that runs every check-*-ratchet(s).mjs it finds.
* fix(ci): preserve existing local lint ratchet scope
* fix(runtime): a phone reads and saves Markdown tabs on a headless server
With no window to relay through, markdown.readTab and markdown.saveTab answered
renderer_unavailable. Main now reads the tab's file (or its saved draft) from disk and
saves with a version compare plus the disk write precondition, in the shapes the
window's editor relay returns. With a window attached the relay is unchanged.
* Headless Markdown save: keep the draft's disk baseline, honour read-only tabs, re-find the record to clear
* Use the disk baseline only for a draft
* ci: run the phone Markdown spec's orcad case in the orca serve mode-switch job
* Headless Markdown: answer from disk only; a window's saved draft stays its view state
Clearing a saved draft wrote workspace layout from main, which no layout command carries.
Main now never shows or edits a draft; the desktop's restore check reports a disk change.
* Phone Markdown: one path through main and the disk, window or not
A paired server's workspace is read and saved on that server with files.read /
files.writeIfUnchanged, so it answers from its own disk and keeps the precondition.
The window relay (ui:mobileMarkdownRequest and the renderer bridge) is removed.
* e2e: a phone saves a Markdown tab the desktop holds unsaved edits in
The phone reads the disk with the tab marked dirty; its save lands on disk, and the
desktop keeps its draft and shows the changed-on-disk banner.
* Group the Markdown disk host's imports
* Drop an unneeded store cast from the dirty-readers test
* Phone Markdown: refuse a save on a server too old to check the disk; cover the untitled tab
A server before #30605 has no files.writeIfUnchanged, so the save is refused with the
existing update-required message rather than written unchecked.
* Phone Markdown: refuse a file an SSH host holds outside the workspace; pin the untitled answer
* Phone Markdown: untitled tabs stay read-only; older servers save like the desktop editor; a closed-source preview still reads
- The desktop lists an untitled document's tab with isUntitled (optional, additive); main answers
it read-only with unsupported_untitled and refuses its save before touching the disk.
- A server without the files.write.disk-precondition capability gets the desktop editor's guarded
save: compare from here, then a plain files.write, or a conflict. Every call of a save is pinned
to the pairing it probed.
- A preview whose source tab was closed has no saved record; it reads its own file, read-only.
* e2e: read the untitled tab's answer without a cast
* Phone Markdown: pin a save's pairing before its first read
A save captures the server's pairing before it reads, and every call of the save, the read
included, is pinned to it, so a re-pair between the read and the write is refused.
* Test: with no window, a phone saves an existing untitled.md and never creates a deleted one
---------
Co-authored-by: E2E Test <e2e@test.local>
* A paired desktop shows a layout-owner server's held panes on the existing banner; Reopen asks the server (switch-on builds only)
The server's frames carry status 'held' on a pane a newer build's terminal service may still
run. The desktop now lists those panes on its existing newer-build banner, with the same wording
and states. Reopen calls the server's new `layout.reopenHeldPanes` under the server's ids: the
server stops its newer service, as the desktop's own Reopen does, and starts each pane still
held. The desktop starts nothing; the server's next frames clear the status and bind the pane.
A refusal or failure shows the banner's failed state.
Served and advertised (`layout.reopenHeldPanes.v1`) only by a layout-owner build, to paired
desktops (not phones). A server without the capability, or that publishes no status, shows no
banner, as today.
* test(layout): held server pane stays Reopening until the reattach frame, stays failed after a refusal, and shows nothing without the reopen capability
* fix(layout): a held pane's Reopen acts only on its own host and on main's published status (switch-on builds only)
- Reopen needs the clicked pane's key; a pane that already left the banner's store does nothing,
so a server banner clicked as its frame drops the pane never stops this machine's newer service.
- Local versus server is decided by the pane's host, not by whether it has a release.
- The banner portal for a pane with no terminal handle exists only in a layout-owner build.
- The server reopens only panes its published layout shows held, the status the desktop saw.
* test(layout): Reopen ignores a pane rebound to a new terminal whose held entry is still stored
* test(layout): the dropped-pane Reopen test checks for the reopen method, since the view report shares the RPC client
* fix(deps): root and mobile resolve one zod, and CI fails if they drift
Mobile type-checks src/shared zod schemas. With mobile on zod 4.6.5 and the
root on 4.6.7, TypeScript treated them as unrelated packages, so wrapped
schemas inferred {} (tests/e2e/helpers/phone-feed-list.ts:154) whenever a
job installed mobile deps.
* fix(deps): guard every package mobile's tsconfig remaps, not only zod
* test(ci): pin the shared-dependency version check to the static phase
* perf(ci): accelerate adhoc release builds and runner scheduling
* Overlap adhoc release preparation and reuse qualified build inputs
* Bind qualified template reuse to its embedded CLI source commit
* Use the available CPUs for native compilation in fast dev builds
* Verify qualified template cache provenance and daily invalidation
* Avoid incremental MSBuild tracking for fresh fast-release builds
* Right-size Intel macOS and Windows ARM release qualification
* Route Intel qualification through the standard larger macOS label
* Overlap Windows preparation and initialize the server native compiler once
* Test server compiler invocation through its process-runner interface
* Align adhoc signing contract with its larger packaging runner
* Recognize the native cache fingerprint as batch-file metadata
* fix(process-host): let a slow Windows taskkill finish instead of orphaning the grandchild
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(process-host): abandon taskkill shortly after the root exits so it cannot walk a reissued pid
Co-Authored-By: Claude <noreply@anthropic.com>
* test(process-host): log the taskkill outcome and caller settle time under load
Co-Authored-By: Claude <noreply@anthropic.com>
* ci: register the late-taskkill Windows test in the package-windows path list
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(process-host): release the git admission slot on root close again; cap the background taskkill at 30 s
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(layout-owner): a CLI or phone file on a layout-owner server opens in the group a paired desktop shows
Each paired desktop reports, through a new layout.reportView (served only by layout.intents.v1
servers, never to phones), the group it shows in each workspace the server's frames draw. The
server keeps reports per connection beside the window's, opens files in the latest one's group,
and drops a connection's reports when it closes, falling back to the saved view.
* test(e2e): a CLI file open on a switch-on server lands in the group a paired desktop shows
* fix(layout-owner): layout.reportView refuses a caller with no connection, as sidebarInputs.reportView does
* feat(layout-owner): a desktop's re-sent view after a reconnect never outranks another desktop's live report
layout.reportView takes an optional refresh flag. The desktop's first report of each workspace
after a stream snapshot carries it; the server ranks such entries below every live report, while
they still replace the connection's own earlier entries and beat the saved view.
* feat(layout-owner): a paired desktop re-sends its view, as a refresh, when its control connection to the server comes up on a new socket
The server drops a connection's view reports when it closes, and the layout stream can stay up
across that, so the desktop watches the shared control diagnostics for a new socket.
* fix(layout-owner): a desktop's refresh keeps its own live rank; stop reporting to a server without layout.reportView
A same-connection resubscribe re-sends its view as a refresh, which demoted the connection's
own live report below an older desktop's. Ranks are now an explicit live/refresh tier. A pre-PR
switch-on server answers method_not_found; the desktop then stops sending for that stream.
* fix(layout-owner): a group the server's own frames move is re-sent as a refresh, never a live report
The snapshot resend read the store before the sync applied the snapshot, so the flush's group
change reached the store subscription as the user's. Writes made by the frame sync now report as
refreshes, and the snapshot resend runs after the flush.
* test(layout-owner): a change frame's group move goes out as a refresh; the frame-write mark survives nested writes
Matrix the lane over distro families. Debian 12 and Fedora 41 rootfs are exported from their
container images (systemd off only, since the images ship no systemd). The lane test now makes the
systemd distro optional and writes its login-env export to the file a login bash actually reads
(~/.bash_profile on Fedora and Arch), which made new distros fail for the wrong reason.
Co-authored-by: Claude <noreply@anthropic.com>
* feat(ci): ratchet raw repo connectionId host reads; one drop-in resolver
Codex review 6 class fix (#4/#6/#7): host decisions read off a repo row's
legacy connectionId miss rows that name SSH only as executionHostId.
- getRepoRoutingConnectionId (shared/execution-host.ts): drop-in for a raw
repo.connectionId routing check that also finds executionHostId-only SSH.
- check-repo-host-read-ratchet: per-file count of raw repo connectionId
reads in src/main, src/shared, src/cli; counts may only shrink.
- Migrated 66 cheap reads: runtime GitHub/GitLab commands, PR/MR head ref
fetches, preserved-branch cleanup, ref queries, base-ref IPC, worktree
preparation, trash sweep, scan cache TTL, usage metadata.
* fix(ipc): PR base IPC routes executionHostId-only SSH rows; ratchet is a stated lower bound
Review follow-up (Opus on #31096):
- worktrees:resolvePrBase decided git/gh routing on the raw connectionId while
its head-ref fetches already used the resolver; one resolved connectionId
now drives all of it (test fails on main).
- getRepoRoutingConnectionId's contract is stated exactly: never local when the
raw field is set; on a contradictory ssh row executionHostId wins.
- The ratchet regex no longer matches report.connectionId; header and docs
say it is a lower bound.
- Regression tests for a runtime GitHub and GitLab command site.
* test(ci): pin the repo host-read ratchet step to the static phase
* fix(ci): repo host-read ratchet skips verbatim field copies into projected rows
A copy of connectionId into a projected row decides nothing; migrating it to
the resolver would change what the projection publishes. The sidebar feed
catalog's copy (added after the baseline) and two older projections no longer
count; baseline pruned to 91.
* review: shorten a test comment; the methods file header names layout.apply
Co-Authored-By: Claude <noreply@anthropic.com>
* wip(h5b): a lost remote layout stream reopens with the local backoff
* wip(h5b): server frame id translation (pending the binding handle)
* wip(h5b): frame syncs take a source; the mirror gates frame-drawn server workspaces and indexes handles; ids translate with session.tabs handles
* wip(h5b): one layout stream per capable paired server, handing workspaces between frames and the mirror
* wip(h5b): tests for server frames; layout.getRemoteSnapshots returns only paired servers (L18)
* wip(h5b): re-gate a server workspace when its routing arrives after the snapshot; e2e hook and spec
* wip(h5b): late-owner test; e2e spec on the switch-on leg
* wip(h5b): server streams follow every paired capable server, not the focused one; a known-kind guard without a cast
* wip(h5b): server-frames tests read real paired-server state; no casts
* fix(h5b): a handed-back workspace is the mirror's alone; frozen frames draw only gated workspaces
* fix(h5b): a workspace rejoining the gate takes the full build
---------
Co-authored-by: E2E Test <e2e@test.local>
Co-authored-by: Claude <noreply@anthropic.com>
* ci: the manual switch-on leg runs the headless serve, paired-host and serve-restart specs
With H1's switch-on server template, these exercise main as the layout owner with no window.
Spec paths are exact: the changed-spec job greps each file, so prefixes only work for ssh-orcad-.
* ci: keep the Windows serve job out of the switch-on leg; it builds switch-off
* ci: the switch-on leg also runs the server-workspace tab composition and serve-restart binding specs
---------
Co-authored-by: E2E Test <e2e@test.local>
build-orcad-template.mjs takes --dark-test-template to let ORCA_LAYOUT_OWNER=main
through for test servers; the template and out/orcad carry the switch marker, and
packaging refuses a marked template. The e2e template steps build a switch-on server
when the workflow runs with layout_owner=main.
Co-authored-by: E2E Test <e2e@test.local>
Both sat 10-20 min in the shared ubuntu-latest queue on 10-19/20, leaving
reserve cells unwatched between segments. The rollout workflows already
run on this pool.
* fix(ssh): let the host download the pinned Node when this computer can't
* fix(ssh): keep both host download tools inside one time budget
* fix(ssh): use timeout for wget only where it runs as expected
* ci: fail the static job on unformatted files
Runs oxfmt --check over the same tree pnpm format writes (~2s), and makes the
pre-commit hook format markdown and YAML so it covers what CI now checks.
* ci: route docs-only and workflow-only diffs through the formatting check
The format check reads the whole tree, so a diff that skipped the static job
could land drift that fails every later PR. Any changed file oxfmt formats now
selects static analysis (not typecheck or units), like the mobile-only route.
The path detector checks out .oxfmtrc.json for its ignores. The hook no longer
fails a commit whose only matches oxfmt ignores (lockfiles).
* fix(renderer): list a pane main holds before the window mounts it, so a tab close by a split's handle finds it (dark, layout-owner build only)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(e2e): the split-close spec polls through the host's "can't answer yet" terminal list
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(runtime): a pane the window lists before main binds its terminal keeps main's terminal (dark, layout-owner build only)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(runtime): a tab close by a main-side split's handle stands on main's own record of the pane (dark, layout-owner build only)
Replaces the window-side listing and the binding fill: the window's list lags main in three
ways (built before main wrote the pane, from it before the binding, or before the window mounts
it), and only main's own layout answers all three.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(runtime): main's relisting for a close tells no clients (dark, layout-owner build only)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: E2E Test <e2e@test.local>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(terminal): a pane main first sees at its binding goes where the window split it (dark, layout-owner build only)
* fix(terminal): keep main's divider positions when taking the window's split tree
* test(terminal): main's divider above the window's new split is kept
* ci: the layout-owner switch-on job runs the hidden-terminal load spec that caught the split graft
* test(terminal): type the side-by-side fixture as a split so ratio spreads typecheck
---------
Co-authored-by: E2E Test <e2e@test.local>
* fix(ci): background steps are single run steps, so no JavaScript action reads the event payload while the runner rewrites it
* test(ci): guard the background slot cap and pin the payload-free allowlist
* fix(persistence): repo-row store writes take the row, not the id; ratchet the rest (R4-2a)
* fix(persistence): host-filter the runtime nested import; widen the id-only write ratchet (review)
* fix(runtime): nested import keeps matching runtime-stamped native rows on a paired host
* fix(persistence): class-scope the ratchet param exemptions; update a new main test to the target shape
* fix(ipc): fence a project-group move by the resolved twin host, so an SSH twin is not WSL-fenced
* test(ci): pin the id-only store write ratchet step to the static phase
* refactor(pty): every PTY retirement names its exit proof; ratchet the unproven ones
* refactor(pty): count raw ownership drops, route an abandoned relay stop to unverifiable, honest proof labels
* fix(relay-ops): let same-cap rolls run while another cell is reserve; refuse a reserve roll target by name
The director refuses cell-status for a step-5 reserve cell with a 404
{error: cell_in_reserve_mode}. The same-cap headroom check read it for
every general cell, so any roll failed while c7 was reserve. A reserve
cell that is not being rolled now counts as no free slots (its seats are
not in the database) and is listed with reserve: true. A reserve roll
target, in the headroom check, the same-cap job's first cell-status read
and the candidate tool, now fails with the design's procedure: flip it to
admitMode=db first, roll, then flip it back. Any other 404 still fails.
* fix(relay-ops): pin the headroom gate's imports as evidence code; name both cells in a two-cell reserve refusal
* ci: run the layout-owner switch-on specs as an advisory PR job
Build the e2e app with ORCA_LAYOUT_OWNER=main through the existing e2e.yml
(new layout_owner input, read only by the app and orcad builds), run the
layout oracle, its positive control and the layout-owner acceptance specs
with the save-divergence log on, and upload a summary by kind and spec.
Not in the PR aggregate's needs.
* ci: summarize divergence logs without a test report, and drop file-path ids from kinds
* ci: switch-on job adds the stream-loss spec and the managed-SSH Docker lane, drops diff-word-wrap (fails switch off), and names each looped test in the summary
* test(e2e): editor-model-host-isolation opens both files through the store's open action, so a layout-owner build's main holds the tabs
* ci: the divergence summary skips a cut-short test report instead of failing
* ci: re-run PR checks on a merge ref that includes the main typecheck repair (#30680)
* feat(relay): add the per-cell phonePath switch, effective only in reserve mode
Step 6 of the relay redesign keys every phone-path change on this switch. The cell
reports the effective value in runtime status, and the flag tool refuses phonePath=memory
unless the cell is reserve, and a reserve flip that would turn phones over unnamed.
* feat(relay-ops): watch a memory phone cell and turn its phone path off on a breach
The reserve watch now also judges five phone rules while the switch file says
phonePath=memory, from the cell's own runtime metrics against the 10 minutes before
flipped-at: 4401s, confirm failures, attach-deadline 4404s and accept database errors
over their lines for 3 minutes, and completed accepts under half of background. A
phone-rule trip writes phonePath=db only; any other trip still flips the cell back
whole. Resume audit drops page after 5 minutes and flip nothing.
* fix(relay-ops): store phonePath=db as no key, so old images keep taking writes
An explicit phonePath=db left in the switch file would make the flag tool refuse every
later write after an image rollback, including a watcher's admitMode=db flip back.
* fix(relay-ops): keep phone watch rules off traffic noise, and keep watching after a phone trip
Completed accepts are no longer judged. Rate lines use the background mean plus
max(margin, share, 4 Poisson deviations), with a margin of 3 for attach deadlines. A
phone trip writes phonePath=db mid-watch and the reserve rules go on; both flip backs
remove the phonePath key so a cell rolled back to an image without it takes the write.
The phone background starts where phonePath went memory, and a background broken by a
restart refuses the watch. Audit drops page only while rising; failing renewals page too.
* test(relay-ops): replay the phone rules on 26 recorded hours of c7 and c29
Per-minute counts from the cells' runtime metrics (read-only, 10-18/19) replace the
synthetic quiet window. c29's bursty auth failures tripped the attach-deadline rule at a
margin of 3 in 29% of 300-minute watches, so its margin is now 5 like the others.
* fix(relay): judge the phone rules as a share of attempts, retry a failed phonePath write
The count rule false-tripped busy c28 (33/121 five-hour watches). The share rule (over half of
the minute's attempts, 0.25 over the background, capped at 0.6) trips none of the recorded c7,
c28 and c29 watches and catches two refusals per accept within 3 minutes. A failed mid-watch
phonePath=db write now keeps watching, retries each sample and pages after 3 failures; break
glass also drops phonePath.
Co-Authored-By: Claude <noreply@anthropic.com>
* docs(relay): cite the replayed c28 count-rule false trips
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(relay): judge phone confirm failures against completed accepts
Each completed accept makes one confirm, so failures/(failures + accepts) could never pass half
and a total confirm outage never tripped. Confirm failures are now a share of accepts.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(relay): note why the confirm replay tests only trips
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(relay): add the per-cell phonePath switch, effective only in reserve mode
Step 6 of the relay redesign keys every phone-path change on this switch. The cell
reports the effective value in runtime status, and the flag tool refuses phonePath=memory
unless the cell is reserve, and a reserve flip that would turn phones over unnamed.
* fix(relay-ops): store phonePath=db as no key, so old images keep taking writes
An explicit phonePath=db left in the switch file would make the flag tool refuse every
later write after an image rollback, including a watcher's admitMode=db flip back.
* refactor(terminal): one PTY attribution for teardown, close and identity; delete the deprecated resolver pair
- strict ssh: route: a proven direct listing beats a same-id server proxy; other contradictions refuse
- terminal spawn's git branch takes the strict route when a host is named (rivals refuse)
- resolveTerminalPtyOwner + isUnattributedTwinWorktree replace resolveRuntimeOwnerForWorktree in
shutdown, pane and agent hibernation, and PTY identity; close logs unroutable runtime ids
- delete getRuntimeEnvironmentIdForWorktree/resolveRuntimeOwnerForWorktree (legacy branch moved
into the adapter), the alias golden test, the importer ratchet, its baseline and pr.yml step
- hasHostEvidence reads the owner indexes instead of scanning repos and groups
* fix(terminal): close and identity read spawn's attribution for unscoped remote ids (Opus P2)
- an unattributed twin's unscoped remote: id is skipped and logged on close, never closed locally
- setup terminals: identity and close follow spawn's runtime; raw-id teardown stays local
- drop the last stale getRuntimeEnvironmentIdForWorktree mock (tests/e2e unit suite)
* refactor(terminal): one ownership read in resolveTerminalPtyOwner
* test(terminal): pin the close-path twin skip and the two-proxy direct listing (Opus P3)
* test(terminal): keep the close-provider owner fixture's full union type (Codex P1)
The root moved to pnpm 12 in #17156 but these two isolated workspaces were
left on pnpm 10, so CI and deploys carried a second pnpm and pnpm/action-setup.
- Pin the root's integrity-checked pnpm 12.14.0 and regenerate both
lockfiles (only the pnpm 12 package-manager document is added; the
dependency graph is unchanged).
- Move settings pnpm 12 ignores out of .npmrc and package.json#pnpm into
each pnpm-workspace.yaml; onlyBuiltDependencies becomes allowBuilds, and
cloud keeps esbuild's script skipped as pnpm 10 did. package-manager-strict
is gone in pnpm 12, whose own version pinning supersedes it.
- docs/site drops --ignore-workspace: under pnpm 12 it skips the workspace
file, losing the overrides and failing the frozen install. vercel.json now
pins install/build so a stale dashboard command cannot reintroduce it.
- Cloud and docs workflows use pnpm/setup@v2 like the root; the relay
unit-test step uses the root's pnpm instead of npx pnpm@10.
* test(browser): expose native popup admission blockers with faithful app events
* test(browser): probe Electron popup identity and inherited sandbox API limits
* test(browser): handle requests without associated contents in popup probe
* docs(browser): record blocked Electron popup compatibility gates and test routing
* docs(browser): keep popup evidence in PR
Without the symlink privilege pnpm links the global virtual store with junctions,
which standard users can create. Verified on Windows 10.0.26200 at medium
integrity with no SeCreateSymbolicLinkPrivilege and Developer Mode off: the
install, both native runtime checks, a ConPTY spawn and windows-process-tree all
pass. ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0 still opts out; CI stays off.
* test(wsl): exercise structured chat on real guest hosts
* test(wsl): keep chat contract within the module size limit
* test(wsl): use braced conditions in chat lane
* test(wsl): configure the fixture through host launch settings
* test(wsl): keep cancellation assertion at the RPC boundary
* test(wsl): avoid assuming cancelled turn publication timing
* ci(wsl): run guest chat coverage for Claude environment changes
* test(ci): match the WSL lane's merged unit-test exclusion
* ci(wsl): drop lane trigger paths that no longer exist
* ci(wsl): run the WSL lane when the shared process-host package changes
* refactor(ssh): split ssh-connection-utils into concretely named modules
- classifiers -> ssh-reconnect-error-classification.ts
- retry/timeout constants and sleep -> connection/ssh-connection-timing.ts
- buildConnectConfig -> connection/ssh-connect-config.ts
- credential callbacks -> connection/ssh-connection-callbacks.ts
- exec options and abort error -> connection/ssh-exec-options.ts
- wrapRemoteCommandForPosixShell -> ssh-posix-command-wrapper.ts
- shellEscape and shared/wsl-login-shell-command quotePosixShell (identical) -> shared/shell-argument-quoting.ts quotePosixShell
No re-exports are left behind.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: point the WSL git benchmark and the WSL lane route at shell-argument-quoting
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* build: share one pnpm virtual store across worktrees, off under CI
Each worktree carried a full node_modules; the global virtual store links
one slot per package version instead. pnpm keeps an explicit setting on
under CI, so a pnpmfile hook turns it off there: CI packages from,
caches and verifies a project-local node_modules.
* fix(build): keep shared electron and windows-process-tree dirs untouched under GVS
Every worktree runs Electron from the one shared electron package, so the
per-repo dist cache must not swap that dist and a foreign-arch install must
not land in it. The relay addon builder now repairs and compiles a private
copy instead of the shared windows-process-tree dir.
* fix(build): accept CLI runtime imports reached through an in-artifact store link
Under the global virtual store node_modules/<pkg> realpaths into a store
outside the repo. The check still rejects anything not reached through a
node_modules link inside the artifact, such as a stray ~/node_modules.
* docs: explain the global virtual store layout and the ~/node_modules hazard
* test: compare CLI closure paths with POSIX separators so the suite passes on Windows
* build: keep Windows on the normal pnpm layout unless ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1
Store links are true symlinks on Windows, and installs without admin or
Developer Mode are unverified; CI still forces the normal layout first.
* fix(build): close the remaining shared-slot gaps under the global virtual store
- verify-skills-cli-runtime resolves each import from the importer's realpath,
as Node does, so an artifact-local copy can't mask a ~/node_modules load.
- A concurrent sibling install of the shared Electron dist is kept, not swapped out.
- rebuild:node goes through ensure-native-runtime, which builds a shared
node-pty beside the slot instead of node-gyp cleaning its build/ dir.
* fix(build): keep pnpm rebuild:node a forced rebuild
It replaced pnpm rebuild node-pty, which always rebuilt; without --force it
only rebuilt a node-pty that failed to load.
* docs: note that the store switches must stay set, since pnpm run relinks
* build: move the pnpmfile under config/ to keep the repo root allowlisted
pnpm-workspace.yaml points pnpm at it; the lockfile checksum is unchanged
because the content is.
* fix(build): enable the global virtual store from the pnpmfile, not the workspace file
pnpm exec derives NODE_PATH from the file setting, so even with the store
forced off under CI every child process got the root node_modules on its
NODE_PATH; a Windows rebuild fixture then resolved the real
@orca/windows-registry it deliberately omits. The hook now sets the store
both ways, and ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0/1 is the one switch.
* test(pty): keep F3's concurrent spawns on the node-pty mock
Two concurrent first import('node-pty') calls race vitest's mock registry
and the loser loads the real addon under the mocked linux platform. It
passed only where a platform-agnostic build/Release happened to exist,
so it failed on every shared-store worktree.
* ci: fail PRs whose packages need a dependency they never declared
A new dependency_isolation job installs with the global virtual store
forced on (ORCA_PNPM_FORCE_GLOBAL_VIRTUAL_STORE_IN_CI), HOME and the store
in an empty temp dir, then runs pnpm tc and the undeclared-dependency test.
Postinstall now warns when a node_modules above the shared store, such as
~/node_modules, would mask the same class of bug locally.
* ci: set the isolation job's HOME and store through GITHUB_ENV
Job-level env cannot read the runner context, which made pr.yml invalid.