mirror of
https://github.com/stablyai/orca.git
synced 2026-11-06 03:57:35 +00:00
d2baeff227ca80de6146d45893b23e83ccba50f6
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4687e90a16 |
[comment audit] Continue main-process comment cleanup (#32946)
* [comment audit] Shorten daemon, hook, and emulator comments [skip ci] * [comment audit] Shorten VM, conversation, SQLite, and theme-import comments [skip ci] * [comment audit] Tighten Git execution and source-control comment contracts [skip ci] * [comment audit] Clarify repository probes and maintenance comments [skip ci] * [comment audit] Shorten status, diff-cache, and checkout comments [skip ci] * [comment audit] Clarify worktree lifecycle and WSL routing comments [skip ci] * [comment audit] Shorten forge identity and review-refresh comments [skip ci] * [comment audit] Tighten hosted-review client comment contracts [skip ci] * [comment audit] Clarify GitLab compatibility and review comments [skip ci] * [comment audit] Tighten hook ownership and watchdog rationale [skip ci] * [comment audit] Condense host and integration compatibility comments [skip ci] * [comment audit] Clarify IPC authority and remote-routing rationale [skip ci] * [comment audit] Finalize file-import and containment comment cleanup * [comment audit] Fix stale Jira type imports blocking full CI --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
6f2a7d05c9 |
fix(worktrees): let git delete removed checkouts so chat sends never wait behind them (#23837)
* fix(worktrees): delete removed checkouts in git, not in Orca's file pool Local worktree removal renamed the checkout into a sibling trash root and deleted it in the background with a recursive fs.rm in the main process. That queued one request per entry on libuv's shared 4-thread file pool, so for minutes every other async fs call in the main process (the agent-session store behind chat sends, file explorer reads) waited behind the delete. `git worktree remove` now deletes the checkout inline in git's own process again, so the card stays in its Deleting state for the length of the delete while Orca's file pool stays free. No timeout applies to the call, so a large delete is never killed halfway. If git reports success but the path still exists (Git for Windows leaves junctions and their parent directories in place), the leftover is deleted with the existing removeHostTree; WSL checkouts stay with the distro. Nothing creates trash any more: the scheduling queue, rename/restore helpers and the trash_rename span are gone. The startup sweep stays to drain entries older releases left behind, and now removes each emptied trash root so the obligation ends. * fix(worktrees): let Git delete Windows checkouts with long paths enabled Removal now always runs Git's own recursive delete, and worktree creation checks out with core.longpaths on Windows, so a deep checkout Orca created could fail to delete with "Filename too long" (#6433). The Windows recovery then finishes the delete but keeps the branch. Pass the same command-scoped core.longpaths option to `git worktree remove` so Git can delete what it created. Also point the CI shard timing entry at the renamed real-git removal suite. * fix(worktrees): keep an inherited GIT_ASK_YESNO out of the worktree delete Git for Windows asks $GIT_ASK_YESNO whether to retry when a file stays locked during a recursive delete. Orca's git env inherits the user's environment, so an inherited value would run an arbitrary prompt program in the middle of a removal. Drop it for the removal call only. * perf(worktrees): run worktree deletes under their own limit, outside git admission `git worktree remove` now deletes the whole checkout in Git's own process, which takes 20-35 s on a large tree. It took a general git admission slot at status tier for that whole time, and that cap is as small as two slots on a machine with six or fewer cores, so two deletes blocked every status read. Deletes now skip general admission and queue under their own limit of two per host instead: two concurrent deletes already saturate one disk, and more only slow each other down. Leftover cleanup runs inside the same slot. * fix(worktrees): delete removed checkouts in the background and mark them removing Since the checkout is deleted by `git worktree remove` in Git's own process, a large delete takes 20-35 s. Answering the request only after that made web and mobile (30 s), paired desktop (60/180 s) and the CLI (60 s) report a failure for a delete that was still going, and mobile silently re-showed the row. The request now does everything that can refuse (lock, cleanliness, archive hook, watcher/terminal gate, terminal stop, shared-link unlink), records the removal in an in-memory table on the host and answers `removing: true`. The delete, branch cleanup and metadata purge run after it in the same order as before, and the watcher/terminal gate stays held until they finish. - Listings mark rows in the table `removing` for clients that advertise `worktree.background-removal.v1` (the desktop renderer, paired desktop and web), and leave them out for everyone else (older clients, mobile, the CLI), which already dropped the row when the request answered. - The outcome (removed, with any preserved branch, or the error) rides the existing worktrees-changed event as an optional field, sent after the row has left the table. - A repeat delete while Git runs joins it. A create at the same path or with the same branch is refused with "Cleanup is pending; try again shortly"; create's name search skips the path, so generated names move on. - Nothing is persisted: after a quit or crash Git still lists the checkout and it can be deleted again. WSL checkouts still delete inline. - `orca worktree rm` says the checkout is still being deleted. * fix(worktrees): keep the existing Deleting card until the host's Git finishes The host now answers a local worktree delete on acceptance and deletes in the background. The renderer keeps the existing delete state set until the host publishes how it ended: - The delete that asked waits for the outcome on the worktrees-changed event (local IPC or the paired runtime's client event), then runs the same teardown, preserved-branch toast and card error an inline delete did. If that event is lost to a dropped connection, a listing that shows the row gone after it was marked removing finishes the wait, and one that shows it back without the marker fails it. - Any other renderer (a reload, a paired desktop, web) sets the same delete state from the host's `removing` marker and clears it when the marker goes. A failure the host publishes lands on that card's existing error. - Web advertises `worktree.background-removal.v1` so the host sends it the marker; paired desktop does through the Electron capability list. No new component, style or state: the card reads the delete state it always did. A host that predates this answers when done without `removing`, and the renderer takes that as finished, as before. * test(worktrees): type the removal harness and projection for the node typecheck * fix(worktrees): don't fail a delete retry with an earlier attempt's buffered failure A background removal's outcome that reached this renderer with no waiter (another client's delete, a host-marked card, or one already settled from listings) was buffered for 60 s and consumed by the next delete of the same workspace, so retrying a failed delete failed at once with the old error while the host was deleting. Drop the buffered outcome before sending the request; only an outcome that arrives after it can belong to it. * fix(worktrees): let only a gap in host events settle a background delete from listings Git unlists the checkout before the host deletes the branch, cleans the push target and purges metadata, and the worktree-directory watcher refetches within 250 ms. The renderer read the missing row as a finished delete, so the waiter resolved without the preserved branch (no toast) and a failure in those last steps showed as success; the real outcome was then dropped. The listing fallback exists only for a lost outcome event, so it now applies only after this host's event stream had a gap: a new subscription or a replay after reconnect. * perf(worktrees): let a bulk delete start each same-repo checkout delete once the host accepts the last A bulk delete ran one worktree at a time per repo (#2259, for packed-refs and ref-lock races in branch cleanup). With Git now deleting each checkout for 20-35 s before the request settles, N worktrees in one repo took N times that. The renderer now queues same-repo deletes only until the host accepts each one; a parent still waits for its nested children to finish. The host serializes the branch cleanup step per repo itself, which also covers removals started by different clients. * test(worktrees): pin the host platform in the mocked removal suites so they pass on Windows Removal now passes -c core.longpaths=true on Windows, so the exact-argv assertions and command-keyed mocks never matched there (17 failures on a Windows host). Pin darwin as the add-worktree suites already do, and drive the one Windows-specific case through the same spy. * test(worktrees): type the blocked git remove result instead of a broad object The anti-slop static-analysis gate rejects `object` parameters. * test(worktrees): clear the changed-code quality gate in the removal suites Merge the duplicate node:fs import, build the mock child without a cast, read worktrees:list rows through one typed helper, and give the remaining casts a SAFETY line. * fix(worktrees): record each background delete durably and finish it after a quit or crash A quit mid-delete left git to finish the checkout on its own while the branch delete and metadata purge never ran; a crash left a normal-looking row. Each accepted local removal now writes a record beside the profile state before git starts, clears it on success or failure, and the host runs the same delete again for any record left at startup, re-deriving what remains from git and disk. An orderly quit stops the checkout delete without waiting for it. * test(worktrees): type the interrupted-removal assertions for the node typecheck * fix(worktrees): finish an interrupted delete that already removed the checkout's .git file Quit stops git worktree remove mid-delete, and Git deletes the checkout's .git file wherever it falls in directory order. Git then refuses the checkout ("validation failed ... .git does not exist") on every retry, so the startup finish failed and the row could never be deleted from Orca. A registered checkout this record owns that has lost its .git file now finishes like an unregistered one: leftover files, prune, then the branch. * fix(worktrees): let Git finish an interrupted delete, and never take a different checkout A quit or crash that stops `git worktree remove` after it deleted the checkout's .git file left a registered checkout Git refuses to remove. The previous fix deleted that leftover inside Orca's process, which is the bulk delete this change exists to avoid (and on Windows the leftover can be most of the checkout). The startup finish now rewrites the missing .git file from Git's own admin entry for that path and lets `git worktree remove --force` delete it. `git worktree repair` is not used: it also re-points every other registered path, including a checkout another repository now owns there. Orca deletes the leftover itself only when no admin entry claims the path. The startup finish forces, so it now leaves the path alone when the checkout there is not the one recorded: a registered worktree on a different branch or head, or a `.git` at a path Git already unregistered. The record is dropped and the card shows why. The record write before Git starts is now bounded (2 s, logged when exceeded) so a stalled disk cannot hold the delete, and the outcome is published before the record's clear reaches disk. * test(worktrees): compare worktree paths by value and tear down with Windows lock retries Git prints forward slashes in `git worktree list` on Windows, so the real-Git removal suites never found a joined path there: positive checks failed and negative ones passed without proving anything. They now compare Git's parsed rows by value. Teardown uses the shared retrying removeTree, since Windows can hold the deleted checkout busy for a moment after Git exits. Adds a relative-path worktree case for the .git restore (skipped before Git 2.48). * fix(worktrees): reply to a worktree delete when it has finished, not on a broadcast event A current client's delete request now waits for the host's background delete and gets its real result (removed, a preserved branch, or the error) as the reply, the way it did before the delete moved off the request. A request that arrives while the delete runs joins it and gets the same result. Every other view keeps reading the host's `removing` marker: the row leaving means the delete finished, and the row listed again without the marker shows "The delete did not finish. Try again." on a card that view had marked Deleting. A request whose reply is lost (a timeout or a dropped connection) settles the same way from a fresh listing instead of reporting a failure. Clients without the background-removal capability (mobile, the CLI, older desktops) are still answered on acceptance and have rows under removal left out of their listings. This removes the outcome on worktreesChanged and everything it needed: the renderer's outcome waiters, early-outcome buffer and TTL, per-host event-gap generations, the request pre-registration, and the accept callback bulk delete used. Bulk delete runs same-repo deletes in parallel only on this machine, whose host serializes branch cleanup per repo; SSH and paired hosts stay serialized. * test(worktrees): type the pending-removal host id in the background-removal suite * fix(worktrees): answer a delete request even when a concurrent removal of the same worktree replaced its record The desktop app's removal and the runtime removal (CLI, paired clients) coalesce separately, so both can be accepted for one worktree. The second replaced the first's record, and the first delete then finished without resolving the request waiting on it, leaving the desktop card on Deleting indefinitely. Each delete now settles the request it was started for. * fix(worktrees): run same-repo removal archive hooks and teardown one at a time on the host Local bulk delete now sends same-repo removals in parallel, so their archive hooks, terminal teardown and preflight ran at once; a hook that writes refs can race the repo's ref locks (#2259). The host now serializes each local removal up to acceptance per repo, for every client; Git's checkout delete still runs in parallel under the delete limit. * fix(runtime): keep waiting worktree deletes out of a host's foreground call slots worktree.rm now replies only after Git deletes the checkout (up to minutes), so on paired desktop and web each waiting delete held one of the host's 8 foreground call slots, and a bulk delete queued listing refreshes and every other foreground call behind it. Deletes now run in their own lane with the same bound; the 2-slot background lane stays for status polls. * fix(worktrees): join a same-worktree delete accepted while a removal waited its repo turn The desktop app and the runtime (CLI, paired clients, web) check for a running delete before they queue for the repo's acceptance turn. A delete of the same worktree from the other path, accepted while this one queued, was missed: this request re-ran the archive hook, stopped the terminals again and started a second `git worktree remove` on the directory Git was deleting. The queued acceptance now re-checks and joins the running delete. * fix(worktrees): fence a resumed delete's checkout from startup, and drop rows a listing read before the delete finished A delete a quit or crash interrupted took its terminal and file-watcher gate only when the resume job ran, after the first window was shown; session restore could open a shell or watcher inside the half-deleted checkout first, and on Windows that handle can fail the resumed git delete. Loading the records now fences each recorded path, and the resumed job takes the fence over in the same tick it takes its own gate. A listing that read git's registration before a delete finished, and replied after the removal record cleared, returned the row unmarked, so other views briefly showed "The delete did not finish". Listings now capture the pending removals before reading git and leave out a row whose delete finished successfully since; a row whose delete failed stays listed as before. * test(worktrees): keep git's auto-maintenance out of the real-git removal suite CI's Git 2.55 failed the file-pool test in teardown with ENOTEMPTY on the scratch repo's objects/pack after the test body passed: the 3,000-file commit's detached auto-maintenance was still writing a pack. The scratch repo now disables auto-maintenance and auto-gc. * fix(worktrees): one archive-hook approval covers a same-repo bulk delete again Local same-repo deletes now start together, so each queued its trust prompt with a state snapshot taken before the first prompt was answered; approving the first still showed the same prompt once per remaining worktree. The queued check now reads the store when its turn comes. |
||
|
|
52b6851b6e |
fix(worktree-create): prioritize creation Git and defer background preparation (#20722)
* fix(worktree-create): run create git commands at interactive tier, defer pool side jobs, bound queue wait by timeout
Creating a worktree on a busy machine stalled for minutes because the create's
own git competed for the same admission budget as everything else.
- The create path never set an admission tier, so it defaulted to 'status' and
could never use the scheduler's headroom slots. It now tags the option objects
that reach git directly: the add, the post-add listing, the base-ref probes and
the prepared-checkout finalize. The speculative warm-up and the SSH path are
unchanged.
- The prepared-pool re-arm is a full `reset --hard`; it ran mid-create and held a
general slot. `consumePreparedWorktreeCreate` now returns it as a thunk the
create runs after the startup terminal is spawned. Stale-preparation
reclamation (`worktree unlock` / `worktree remove`) drops to 'background'.
- A command's timeout only armed once its child spawned, so a saturated queue
could hold a 1s command indefinitely. Admission now takes the same deadline and
raises GitCommandTimeoutError without spawning; a caller abort still reports as
an abort.
The tier is kept off the `{ wslDistro }` routing objects: several callers test
those for emptiness to decide whether a repo has local git routing at all.
* fix(worktree-create): keep a bounded queue wait from reading as an absent base ref
The admission deadline added in the previous commit made every create-path probe's
15s/120s budget cover the queue wait. The default-base and worktree-base probes answer
`false`/`null` for any failure, so a saturated queue reported a repo that has origin/main
as having no default base and the create refused to start. Both probe families now let
`GitCommandTimeoutError` through, and the branch-name resolution loop, the push-target
configuration and the post-add listing run at the create's interactive tier so they reach
the headroom the rest of the create already uses.
Also: the deferred pool re-arm re-checks the pool inside the thunk, since `startPreparation`
replaces a map entry outright and would strand a prefetch's locked checkout with no owner;
the shared worktree scan keys on the tier so an interactive listing cannot inherit a queued
status scan's wait; and the deadline's microtask hop is gone, along with two fake-timer
`vi.waitFor` calls that jumped the clock past a 10ms budget before the grant settled.
* fix(worktree-create): preserve probe fallbacks and defer runtime replenishment
* fix(worktree-create): preserve interactive priority through prepared claims
* fix(worktree-create): prioritize CLI creation and preserve SHA probe timeouts
* fix(worktree-create): scope Git execution policy at creation boundaries
* fix(worktree-create): preserve inconclusive Git probe timeouts
* test(runtime): align creation fixtures with scoped Git execution
* test(native-chat): extract windowing layout fixture to satisfy file limit
* fix(git): restore execution-only timeouts while queued
* refactor(worktree-create): remove unrelated error-handling changes
* chore: narrow review scope and clarify preparation timing
* test(native-chat): restore fixture extraction to fix CI lint
* refactor(git): keep the admission scheduler in its original module
Reverts a move-only extraction. Inlines the single-use command-class
wrapper so the tier-resolution import fits the file's line budget.
* fix(worktrees): re-arm the prepared pool after CLI create launches terminals
The runtime create fired the pool re-arm right after materialization, so its
`reset --hard` competed with the startup agent's first git reads. Return the
thunk to the caller and fire it last, matching the desktop path.
* fix(worktrees): skip a preparation whose checkout is still running
An interactive create that claimed an in-flight preparation awaited a checkout
queued at background, so on a saturated budget it yielded to every arriving
status poller until aging promoted it. The create now misses with not_ready and
does its own add at interactive; the preparation stays armed for the next one.
Also drops the one-field policy object from the Git operation executor.
* fix(worktrees): report repo_mismatch before not_ready when selecting a preparation
The readiness filter ran before the same-repo check, so another repo's
in-flight preparation was labeled not_ready instead of repo_mismatch, hiding
the cap-thrash signal for multi-project users. The hit/miss decision is
unchanged.
* test(runtime): type the worktree-meta stub against WorktreeMeta
Main now rejects bare object parameters, and the merge picked that rule up.
* fix(worktrees): wait on in-flight preparations and re-arm the pool on failed creates
A create landing mid-checkout now claims the in-flight preparation and awaits it, as main
did. The `checkoutFinished` filter and its `not_ready` miss reason made the create skip a
prepared checkout that was seconds from done and pay a full cold add instead; on a 40k-file
repo that turned a 0.2-1.5s create into 2.4-4.3s. The preparation's own git also runs at
`status` again rather than `background`, so awaiting it does not park behind status pollers.
Only the stale reclaim stays `background`, which no create waits on.
The deferred pool re-arm now fires on every path, not just the success path. Main armed the
replacement synchronously inside the consume, so a later failure in include copy, push-target
setup, or terminal startup still left one warming. The thunk stays deferred until after
terminal startup for admission ordering, but a `finally` on the desktop create and matching
failure-path fires on the runtime create restore that guarantee. It fires exactly once.
* refactor(runtime): carry the pool re-arm in one holder
The runtime create used three mechanisms to guarantee the deferred pool re-arm fires: a
catch in the git create, a catch on materialization, and a holder fired in the managed
create's finally. The desktop create already used one holder for the same guarantee.
The holder now threads down through the create args, so the git create arms it at the point
it consumes a prepared checkout and nothing below has to handle the failure case. The thunk
already re-checks the pool before arming, so a single fire point in the outermost finally
covers every failure after the consume. Behavior is unchanged; both flipped failure-path
tests still assert exactly one fire, and each fails without the production change.
|
||
|
|
a7db6c336b |
perf(git): skip the sparse probe for worktree listings that never read it (#18050)
Three main-process call sites list a repo's worktrees to read `worktree.path` and nothing else, but went through the annotated listing, so each one paid a sparse-checkout probe per worktree and cached the result nobody consumed: - `registered-worktree-roots-cache.ts` rebuilds the filesystem-auth authorized roots. `invalidateAuthorizedRootsCache()` fires on every worktree create and remove, plus repo add/clone/settings changes, so this reruns constantly. - `filesystem-source-control-ai-targets.ts` checks whether a local repo owns a worktree path. - `hosted-review.ts` verifies a worktree belongs to the repo before granting access. The probe is an `fs.stat` of the per-worktree `info/sparse-checkout` plus, when that file is non-empty, a git config read. On a WSL-hosted repo both cross 9p. #17859 cached it and #17932 keyed that cache on the distro, which fixed a wrong answer but also meant the distro-less callers above populate a second entry per worktree — probed cold, revalidated on their own five-minute loop, and read by nobody. Worktree create/remove clears the sparse cache and dirties the roots cache together, so both variants go cold at once and the discarded half is re-probed in full on the next auth check. `listRepoWorktreeGraph` routes those callers to `listWorktreeGraph`, which already existed as the annotation-free listing (#17655). Doing only that would have cost a second `git worktree list`. The scan cache keys in-flight scans on a `kind`, and graph and lenient were separate kinds, so a roots rebuild overlapping a sidebar refresh would spawn its own subprocess where the two previously coalesced. That is a real regression on macOS, Linux and native Windows, where `getLocalProjectWorktreeGitOptions` returns `{}` and both callers land on the identical key; on WSL they already differ by distro and never shared. So the annotated listing is now the graph listing plus annotation, rather than a parallel scan of its own: `listWorktrees` awaits `listWorktreeGraph` and annotates the rows it returns. Both soften a Git failure to `[]`, so they can share one listing; strict keeps its own because it must be able to reject. The two kinds ran Git twice before and now run it once, so the overlap case gets strictly faster instead of paying for the opt-out. An annotated scan holds two in-flight entries now (its own, plus the graph listing it shares). Keeping its own entry matters: `detectSparseCheckoutCached` dedupes revalidation but not the initial fill, so two concurrent badge readers sharing only the graph scan would both probe. Per-platform delta: - macOS/Linux: fewer probes on the three call sites; one `git worktree list` instead of two when a graph and an annotated scan overlap. - native Windows, no WSL: same, and the saved subprocess is the expensive half. - Windows + WSL: the largest win. The discarded probes were 9p round-trips re-paid cold after every worktree create/remove. - SSH/relay: none. `listRepoWorktreeGraph` returns through the same provider branch as `listRepoWorktrees` before reaching local Git. - folder workspaces: none. Both return the same synthetic folder worktree. Not in this change: - The badge listing itself. It still probes, still annotates, and still keys on the distro exactly as #17932 left it. - The remaining `listRepoWorktrees` callers. They read `isSparse`, or feed rows to something that does. |
||
|
|
8ac1c6e2ac |
perf(git): bound ref and worktree scans (#17655)
* perf(git): bound ref and worktree scans * fix(repo-search): clamp oversized ref limits * fix(worktree): keep strict worktree listing unshared The shared-scan re-export flipped every `listWorktreesStrict` caller from an isolated subprocess to the coalesced scan. `git worktree prune` in the removal recovery path does not bump the scan generation, so a post-prune verification could join a pre-prune scan, see the stale row, and report a successful removal as a stale registration. The same gap defeats the post-archive-hook rechecks that exist to catch an external Git client locking the row. Restore the unshared export and make coalescing opt-in via `listWorktreesSharedStrict`, which existing callers already use deliberately. * fix(git): separate a proven absent ref from a failed probe `show-ref --verify --quiet` exits 1 for a missing ref, but so does `wsl.exe` when its own launch fails, so reading any exit 1 as absence collapsed `unverifiable` into `exited`. A genuine miss prints nothing while a wrapper failure always explains itself, so require empty stderr alongside the exit code; a runner that reports no stderr at all keeps its exit-code contract. That same signal removes a spawn regression: `show-ref` is a direct-git read under WSL, and the runner retried any numeric exit through the user's interactive login shell. The replaced `for-each-ref` exited 0 on a miss, so absence never retried; every absent probe now would. Treat a quiet exit 1 as Git control flow and skip the fallback. Also narrow the hosted-review suffix fallback: the replaced `refs/remotes/*/<base>` could not cross a slash, but `show-ref -- <base>` matches at any depth, so `origin/feature/main` answered a query for `main` and submitted a review against a base the provider rejects. Refresh the real-binary compatibility contract to the shipped excludes, and assert exact probe concurrency rather than an upper bound so a regression to serial probing fails. |
||
|
|
3af2c665c0 |
fix(cli): name PowerShell when it strips quotes from JSON flags (#17351)
* fix(cli): name PowerShell when it strips quotes from JSON flags Windows PowerShell 5.1 does not escape inner quotes when building a native command line, so `--options '["a","b"]'` reaches orca.exe as `--options [a,b]`. The value is correct when printed and damaged by the time argv is parsed, so the resulting "invalid JSON" error blamed the user's input rather than the shell. #16743 recovered this for `--deps`, which is safe only because generated task IDs have a fixed 12-hex grammar. The same mangling hits `--options`, `--payload` and `--result`, and those are NOT safely recoverable: `["1","2"]` and `[1,2]` arrive at argv identically, so a general repair would silently turn strings into numbers. Detect instead. `getOptionalJsonFlag` rejects the damaged shape up front with an error that names the shell and shows the workaround. It fires only when the value is bracketed, quote-free, fails JSON.parse, AND consists entirely of bare tokens that quoting would rescue, so valid JSON is untouched. Also share the generated-id contract: `task-deps-flag` hardcoded /^task_[0-9a-f]{12}$/i, which silently diverges if `generateId`'s byte count changes. It now calls `isGeneratedId`, with a test pinning the two together. Verified on a Windows host. Measured argv, which the new test pins as a fixture: PS_VALUE=["task_b2a580db74d8","task_c3b691ec85e9"] ARGV=["--deps","[task_b2a580db74d8,task_c3b691ec85e9]"] Before: Invalid --options: must be a JSON array of strings After: --options arrived as [a,b], which is not valid JSON. Windows PowerShell 5.1 strips the inner quotes ... * fix(cli): scope JSON-flag detection to genuinely JSON flags Review found the detector wired to two flags that are not JSON: - `orchestration ask --options` is documented `<csv>` and the runtime splits it on commas, so `--options [a,b]` was a legitimate value being rejected. - `task-update --result` is stored verbatim and reused as dispatch failure text; existing tests pass free text, so a bracketed `[ok]` was being rejected. Both revert to `getOptionalStringFlag`. Only `gate-create --options` (`<json_array>`) and `send --payload` (`<json>`) are JSON-parsed and keep it. Three further review fixes: - Objects now require a `key:value` pair per entry. `{a,b}` and `{a:b,c}` were reported as quote-stripped although quoting them cannot produce valid JSON. - The raw value is no longer echoed. A `--payload` can carry secrets and this message reaches `--json` output; the flag name and guidance are enough. - The message hedges the shell attribution. Detection inspects only the value's shape, so it also fires when a macOS/Linux user forgets to quote, where PowerShell is not involved. Verified against a Windows host, all six cases: both JSON flags fire on the mangled shape and pass valid JSON through to the runtime; both non-JSON flags now reach the runtime again; and the secret in `{token:hunter2}` appears zero times in the error output. |
||
|
|
3457acb647 |
fix(memory): hydrate retained PTYs before diagnostics (#17308)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
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. |