Commit Graph
6 Commits
Author SHA1 Message Date
Brennan Benson 7a59aa39d0 fix(worktrees): decide setup before git worktree add on the host's create (#26006)
* fix(worktrees): decide setup before git worktree add on the host's create, so an undecided ask repo leaves nothing behind

The host's create (agent.launch, worktree.create, the phone and the CLI) only checked the setup policy
after adding the worktree. An ask repo with no setup decision then threw with the worktree already on
disk and no worktrees-changed event. It now refuses before the add, as the desktop create does, and a
setup hook the new branch adds (one nobody decided on) is skipped with a warning instead of failing a
create that already exists.

* fix(worktrees): read the host create's setup decision in one place, after recording its host

The pre-add refusal now runs after the create records its execution host, so a refused create's
failure telemetry still says where it ran; it still runs before any git work. Both setup checks
read the decision from one helper so they cannot disagree, and the post-add skip logs once.
The refusal test now also proves no base resolution, fetch or branch naming ran and that the
hooks came from the main checkout.

* test(worktrees): cover a setup hook only the new branch adds through the managed create

An ask repo with no decision, whose setup hook exists only in the new worktree's orca.yaml, now
creates, refreshes the worktree list, reports setup as skipped and returns the warning.

* fix(cli): name the --setup flag when a worktree create needs a setup decision

The host refuses an undecided create in an ask repo with "Setup decision required for this
repository", which desktop and phone answer in their own UI. The CLI now adds the next step:
pass --setup run or --setup skip.
2026-10-06 19:11:48 -07:00
Neil 6a9ba9d733 Keep remote worktree creation from navigating paired clients (#25793)
* fix(workspaces): keep remote creation from navigating paired viewers

* fix(workspaces): revoke pending navigation after connection replacement

* fix(workspaces): provision when the host renderer is unavailable

* test: align navigation and cache-scan expectations with current behavior

* fix(workspaces): provision broadcast creates without a host renderer
2026-10-06 00:38:53 -07:00
Jinwoo Hong 8f15f217a2 Preserve user-set workspace names across branch changes (#17448)
* fix(worktrees): preserve user workspace names across branch changes

* test(worktrees): cover pinned rename metadata

* fix(workspaces): address display-name review edge cases

* fix(workspaces): keep automatic names fresh across refreshes

* fix(workspaces): preserve legacy CLI labels

* fix(workspaces): preserve display-name provenance across hosts

* fix(workspaces): honor legacy display-name provenance

* fix(workspaces): fence display-name refresh races

* fix(workspaces): accept peer renames from provenance-less hosts

The old-host preserve fence kept a pinned local label on every refresh,
which also suppressed a legitimate rename another client persisted
through the same host until app restart. Narrow it to labels the host
re-derived itself (branch short name, or path basename when detached);
any other changed label in a mode-less response is explicit meta a peer
wrote there. Stale prior-label responses stay covered by the downstream
staleness fence, in-flight writes by the pending fence.

* refactor(workspaces): unify display-name pin derivation

Three call sites (renderer optimistic update, local IPC updateMeta
handler, remote worktree.set handler) each restated the same formula;
a future edit to one would silently skew provenance between paths.
2026-08-31 19:08:05 -04:00
Jinwoo Hong 9b5538d786 fix(runtime): scope create-with-activate navigation to the requesting client (STA-2802) (#15407) 2026-08-18 21:37:35 -07:00
Neil 4cc7e7859a fix(cli): route --host runtime:<id> to that server instead of answering locally (#15364)
* fix(cli): route --host runtime:<id> to that server instead of answering locally

`--host` was only ever a local filter over whatever runtime the CLI happened
to connect to, so `--host runtime:<id>` silently answered for (and mutated)
the local machine. A real environment id and a made-up one were
indistinguishable: both returned ok:true with an empty list and the local
runtimeId in _meta, and `project setup-clone --host runtime:<id>` cloned into
the caller's own machine.

Resolve the flag before the client is built: unparseable host ids and runtime
ids that no paired environment owns are rejected, and a known runtime id
selects that environment as the connection (conflicting with --pairing-code or
a different --environment is an error). Once routed, a host filter also
accepts the runtime's own `local`-stamped rows, since both spellings name the
machine we are now talking to.

* fix(cli): close --host routing gaps found in review

- Conflict-check an ambient ORCA_ENVIRONMENT, not just the --environment flag.
  `ORCA_ENVIRONMENT=staging orca ... --host runtime:<prod-id>` silently routed
  to prod while the flag spelling errored. An ambient pairing code still loses
  to the explicit flag, because it cannot be resolved to an id to compare.
- Attach the known environment ids to the unknown-id error as `error.data`, so
  a --json consumer can retry without parsing prose, and say outright that
  runtime:<id> matches ids only and never environment names.
- Fix four command examples that documented `--host runtime:gpu`. `gpu` is an
  environment name, so every one of them would now be rejected; use an id.
- Cover the routed connection on `worktree create` and `automations create`
  (the mutating paths), the `--environment X --host local` filter-only case,
  and assert error.code/error.data rather than only substrings.

* test(cli): pin execution-host-flag to the deferred error-class import

index.ts now loads execution-host-flag.ts on every invocation, making it the
sixth module on the --help path. It imports RuntimeClientError from
./runtime/types today, but nothing enforced that; switching it to the barrel
would silently drag zod/ws/tweetnacl back onto --help, which is exactly what
this guard exists to prevent. Verified the assertion fails when the import is
flipped to the barrel.
2026-08-18 14:12:24 -07:00
Neil 9367169888 refactor(tests): split every oversized test file off the max-lines suppression list (#14728)
* refactor(tests): split oversized test files off the max-lines suppression list

Every `*.test.ts`/`*.spec.ts` that carried an `eslint/oxlint-disable max-lines`
directive is now split into focused, behavior-scoped suites that fit the 800-line
test budget, with shared setup extracted into co-located `*-test-harness.ts` /
`*-test-fixtures.ts` modules (300-line budget). 83 files became ~930; the largest
output is 797 effective lines. `orca-runtime.test.ts` is intentionally untouched.

Test bodies were moved by scripted line-range slicing rather than retyped, so
assertions are byte-identical. The only permitted body edits were mechanical
rebinding where a shared value moved into a harness (e.g. `tmpHome` ->
`homes.tmpHome`).

Registries that enumerate test files were updated in lockstep:
- config/max-lines-baseline.txt: pruned 341 -> 258 entries (all 83 removed).
- config/reliability-gates.jsonc: 33 gates repointed at the split files, with
  assertionRefs split per file where a gate's coverage now spans several.
- .github/workflows/pr.yml: the real-zsh lane now lists the 4 split files that
  actually exercise zsh, so they keep running in the dedicated shell lane.

Also renamed agent-hooks `server-test-fixtures.ts` to `server.test-fixtures.ts`
so the global-fetch call-site audit keeps skipping it, and added `.js` extensions
to the CLI suites' dynamic harness imports (node16 resolution) to unbreak
`build:cli`.

Verification: full suite 52,449 passing vs 52,448 at baseline with zero
assertions lost; `pnpm lint`, `pnpm typecheck`, and `pnpm build:cli` all exit 0;
the terminal-pane e2e spec runs 31/31 headless.

* refactor(tests): split hook-idle arbitration suite that oxfmt pushed over budget

The pre-commit oxfmt pass reflowed pty-connection-hook-idle-arbitration.test.ts
to 811 effective lines, 11 over the test budget. Split the hook-completion side
effect and replacement-agent veto cases into their own suite; both files now sit
well under the cap and the 15 tests are unchanged.

* test: port upstream test changes into the split files after rebase

Rebasing onto main surfaced 27 tests that main had added to files this branch
deleted, plus edits to tests that had already moved. Taking the deletion side of
those modify/delete conflicts would have dropped that coverage silently, so each
upstream change is ported into the split file that now owns the behavior — for
example main's six orchestration mailbox tests land across orchestration-runs,
-send, and -check.

Also repoints `orchestration.notification-mailbox-consistency`, a gate main added
after this branch's gate remap, at those same three split files, and re-prunes
the max-lines baseline against main's (257 entries).

Verified: all 27 upstream test titles present; full suite 52,761 passing with the
only diff vs baseline being 12 tests main itself removed and 3 that moved from
skipped to passing; lint and typecheck exit 0.

* fix(test): flush pending continuations before tearing down terminal test globals

CI shard 5/16 failed on both Node 24 and 26 with `ReferenceError: window is not
defined` from pty-connection.ts, surfacing through
pty-connection-daemon-snapshot-replay.test.ts.

The reattach/settle chains `await` a real promise and then touch `window.api`.
Under fake timers those continuations cannot run, so they only become schedulable
once restoreTerminalTestGlobals() switches back to real timers — which previously
happened immediately before `delete globalThis.window`, so a late continuation
threw and failed the whole file. Flush async ticks in that window instead.

This is latent in the source rather than new: the pre-split 25k-line file kept
running other tests after these, which gave the chains time to settle before
teardown. Splitting the file moved teardown directly behind them.

* fix(test): keep an inert window after terminal test teardown instead of deleting it

The async-tick flush was not enough: the reattach/settle chain can resolve after
teardown regardless of how long we drain, so CI shard 5/16 still failed with
`ReferenceError: window is not defined` from pty-connection.ts.

A real renderer never loses `window`, so deleting it was the artificial part.
Swap in an inert proxy whose properties resolve to callables and whose calls
resolve to undefined, making a late `window.api.pty.*` call a harmless no-op.
The next test replaces it wholesale via installTerminalTestGlobals(), and no test
asserts that `window` is absent.
2026-08-15 00:54:20 -07:00