mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
8262fb147fe3b854449c19ca2a74bbe62d33b1b9
688
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d5803bdbc4 |
feat(ssh): host-stamped remote foreground identity (#18078)
* docs: add SSH agent identity implementation plan * feat(ssh): host-stamped remote foreground identity * fix(runtime): preserve unfenced inspect call shape * perf(ssh): traverse foreground descendants linearly * fix(ssh): bound retired PTY evidence records * test(ssh): cover retired incarnation retention * fix(ssh): make remote process inspection total * Split SSH identity build hot spots * Fix process table snapshot module split * test(ssh): update process inspection expectations * docs: drop the SSH identity plan from the PR The design doc does not belong in the product repo; it stays out of the shipped tree while the implementation carries its own comments. --------- Co-authored-by: Merge Sim <sim@local> |
||
|
|
6cd477a2f1 |
test(e2e): un-rot the SSH freeze repro and probe two failure modes nothing covered (#17940)
Test-only. No production code. ## The freeze repro was rotted in three ways, not one #16764 tracks four stale call sites. There were three separate problems: 1. **Stale call sites** — `execInTerminal` gained a `ptyId` and `splitActiveTerminalPane` gained a direction. (`startDockerSshRelayTarget`'s missing `testInfo` was the third; #18257 has since landed it on main.) 2. **It connected before session restore settled**, so the seeded tab never bound to a remote PTY and the terminal sat on "Connecting…" forever. 3. **It could never have passed, even once.** It waited for a one-shot `READY:` line through a 4000-char terminal window while its own 2 KB-every-8 ms flood buries that line within ~16 ms. Readiness is now keyed on the repeating `BG:` flood marker, which is strictly stronger — it proves the pane is streaming rather than merely started. It now runs end to end and prints a measurement instead of dying on a call site: ``` [freeze-repro R2] hiddenFloodMaxLagMs 2.1 bulkOpenMaxLagMs 41.5 interactionProbeMs 53.6 softFreeze false hardFreeze false ``` **It is still not CI-gateable, and the exclusion comment now says so.** The same spec on the same commit measured `bulkOpen 2575.6ms / interaction 3464.2ms` on a GitHub ubuntu runner against a 2500 ms soft budget — a ~60x spread on the number the budget reads, with the relay still streaming. That is the budget failing, not the product. The earlier draft of this comment claimed "repaired and passing", which was true only of the host it was measured on; gating this needs a host-relative oracle, not a bigger constant. ## New: a half-open link is judged, not wedged The fixture image has no `iptables` and the container has no `NET_ADMIN`, so `docker pause` is used instead — a harder case, because the container's TCP stack keeps ACKing: no FIN, no RST, and the socket looks perfectly healthy. Only an application-level probe can detect it. ``` [half-open] {"verdict":"reconnecting","verdictMs":25135,"budgetMs":90000} ``` Nothing in the suite covered the failure mode behind the "SSH hangs until I restart Orca" reports. ## New: resource accumulation measured on the remote host 6 terminals, then 5 reconnect cycles, counted on the container itself: ``` open: pts 1->6 (exactly 1/terminal), relay fds 25->30 (exactly 1/terminal) reconnect: pts flat at 6, relay procs flat at 1, node procs flat at 3 ``` `leakedMasterFdCount` is now **asserted**, not merely recorded. It counts PTY master fds held by non-relay processes: without `FD_CLOEXEC` a master is inherited by every later child, so terminal k adds k of them — the triangular signature measured as 15 across 5 terminals before the fix. #17914 patched the app and daemon and #17920 shipped the same patch to the relay host, and both are now on main, so the correct value is 0 and the probe holds it there: ``` baseline leakedMasterFdCount 0 6 terminals leakedMasterFdCount 0 (holders: only relay.js, n=6) reconnects leakedMasterFdCount 0 across all 5 cycles ``` Any growth here means the relay's node-pty rebuild did not take on that host, which is exactly what a remote-host probe exists to catch — and it is the half of #17914's claim that no unit test can reach. ## Routing Both new probes are claimed by `run-ssh-docker-e2e.mjs` (a Docker-gated spec no runner names self-skips everywhere and still reports green) **and** by the `ssh-terminal-source` route in `pr-e2e-source-routing.mjs`, so they run when the relay and SSH code they guard changes rather than only on a scheduled lane. |
||
|
|
074a2366bf |
test(e2e): pass testInfo to startDockerSshRelayTarget in the freeze repro (#18257)
The spec called startDockerSshRelayTarget() with no argument while the helper signature is (testInfo: TestInfo) and dereferences testInfo.workerIndex, so it threw before any Orca code ran and took the Docker SSH lane red on every PR. Fixes #16764 |
||
|
|
4ff96df2b5 |
Auto e2e tests autofix scheduled ci 1h run 32 20260902T0700 (#18227)
* Fix flaky e2e tests with improved locators and synchronization Add explicit waits, use more robust element selectors, and simplify test setup to reduce race conditions. Replace file-based fixtures with programmatic browser creation, use parent-scoped locators for menu interactions, and poll for stable state before assertions. * Add E2E failure triage report for run 33564563164 - Reconciles 14 failed tests against job logs and trace artifacts - Categorizes failures: 8 product bugs, 2 flaky tests, 4 test updates - Documents test-maintenance fixes and diagnostic findings - Files 8 Linear issues with owners and fresh recurrence evidence - Provides next actions for product owners and repository maintenance * rm artifact notes * Refactor browser creation E2E test to use UI interactions - Click through menu instead of manipulating internal store state - Use Playwright's locator and toBeVisible() assertion patterns * Record E2E browser creation pageId before barrier check Move createdPageId assignment before the barrier arm/fire checks. This ensures the pageId is recorded unconditionally when tracking is enabled, allowing tests to distinguish between creations rejected before the host attempt vs those that failed after creation. * Remove browser page reclamation assertion from restart test Simplifies test by removing page ID tracking and poll checking if pages persist after paired runtime restart. |
||
|
|
c2fce80289 |
Fix agent dashboard setting configure (#18245)
* Make agents activity always-on; toggle via bell icon - Remove optional showAgentsSidebar setting - Replace sidebar view-toggle with bell-button for activity access - Agents activity now always accessible in sidebar - Preserve migration flag for introduction to existing users - Remove visibility inference utilities * Simplify sidebar when agents view active: hide workspace options, add to - Hide workspace options menu and add project button when agents view is active, reducing UI clutter in that mode - Add tooltip to the activity bell button for better discoverability - Localize sidebar search field text - Move search and filter toggles to local state in SidebarAgentsList, removing unused callbacks from thread list components - Manage search input focus properly when opening |
||
|
|
e3de6b2ce8 |
Add automation runs dashboard with pagination and filtering (#18226)
* Add automation runs dashboard with pagination and filtering Adds a new Runs view in the Automations page that lets users browse all runs across automations with status/host filtering, search, and pagination support. Includes virtualized table rendering for efficient handling of large run histories and summary cards showing 24h/7d success/failure counts. * Fix missing dependencies in useCallback hooks and imports Missing dependencies in useCallback can cause stale closure bugs. This adds missing state setters to dependency arrays and consolidates type imports for consistency. * Use keyset pagination for stable automation runs pages Pagination now uses createdAt:id boundaries instead of offsets, so new runs arriving between pages don't shift the window. Maintains backwards compatibility with legacy offset cursors. Move pagination to shared module, fix outcome counting for future-dated runs, and improve hook state tracking on authority re-pairing or target changes. * Extract automation run details to top-level page view Moves run display from detail pane to dedicated page, establishing three-level navigation (Automations → Runs → Run Details) and simplifying the detail pane component. * Fix pagination stability when automation runs share createdAt - Define a stable total order with createdAt and id tiebreaker to prevent runs tied on createdAt from being dropped when the boundary run is pruned between page requests - Retain cursor on failed pagination so pages remain retryable - Update ownerNotice type to AutomationActionNotice * Extract automations list panel and worktree map logic Split AutomationsPageSurface into smaller, focused modules for better maintainability and reusability. Move list panel UI rendering to AutomationsPageListPanel component and worktree map selection logic to a standalone utility function. * Add i18n strings for automation runs dashboard Adds localized strings for the automation runs dashboard view, including search, filtering by host and status, run counts for 24h/7d windows, and empty state messaging across all supported languages. * fix missing translation * fix missing translation |
||
|
|
b00ec20731 |
perf(startup): stop an unreachable SSH host from gating local terminal restore (#18164)
* perf(startup): stop an unreachable SSH host from gating local terminal restore An asleep or unreachable SSH target held the terminal-restoration gate for the full 15s reconnect timeout, so no terminal restored — local ones included. Startup now awaits only the target that owns the active workspace's tabs and lets the rest connect in the background, folded into the existing deferred path that reattaches their PTYs on tab focus. Also splits the renderer's git-environment fence out of the first-window PTY services barrier: worktree hydration needs shell-PATH generation and the managed WSL CLI registration, not a daemon PTY spawn or a hook-server bind. Terminal restoration still fences on the first-window services via app:prepareTerminalStartupRestoration. Measured with tests/tools/benchmarks/startup-time-bench.mjs (382 restored tabs, 28k-file profile, medians of 3): unreachable SSH host: 17.27s -> 1.34s to renderer-startup-hydration-done all-local: 1.98s -> 1.33s * fix(startup): restore the startup-ordering oracle and keep a connected background SSH target undeferred app-startup-routing.test.ts pinned the old step names, so the two ordering cases went vacuous-then-red when the barrier split. Repoint them at the steps that now carry the same fences: 'git-environment-barrier-await' (shell PATH + managed WSL, the fence host Git needs) before hydration worktrees, and 'prepare-terminal-startup-restoration' (which awaits firstWindowStartupServicesReady in main) before terminal reconnect. Both still fail against main's hydration source. Also: the timed-out-eager rewrite of the deferred list re-added background targets that had already connected, undoing removeDeferredSshReconnectTarget and sending fresh panes on a reachable host down the cold-restore path. |
||
|
|
ae1dab40d6 |
Sta 6308 add copy session id option to terminal tab context menu (#18070)
* Move Copy Session ID from tab to terminal pane context menu - Relocates session ID copy to the exact pane that owns it, not the tab's active pane - Adds support for durable sleeping agent sessions as fallback for cleared live status - Generalizes copy-rejection guards to handle any identity type, not just pane IDs - Updates e2e test to verify pane-specific session ID copying * Gate session ID liveness by shell foreground state Once OSC 133;D proves a pane is back at the shell, don't return the session ID even if a durable record survived the exit. This prevents treating exited sessions as still active when the user is typing at the prompt. * Update hook order parity test for session-ID projection hook The pane session-ID projection adds a render hook to TerminalPane. Update the expected hook count from 229 to 230 and the corresponding SHA256 hash. |
||
|
|
61e010079f |
New agent dashboard (#18222)
* more obvious toggle
* more obvious toggle
* feat(activity): redesign thread rows and add child agent filtering
- Emphasize task title and last activity in row layout over metadata
- Add child agent toggle; hide orchestration workers by default
- Support collapsible groups and ungrouped view mode
- Improve orchestration worker message handling to surface replies
- Add sidebar search and filter controls for agent activity
* periodic checkin
* feat(activity): add "Clear completed" action and performance improvement
- Add "Clear completed" action for activity threads with undo window; clears completed and interrupted rows from view, persists across restart
- Virtualize activity thread list to render only viewport-bounded rows
- Cache activity thread search text to prevent recomputation on every keystroke
- Cache dashboard bucket counts per-worktree for selective invalidation on unrelated changes
- Use useDeferredValue for activity search filtering to keep input responsive
- Make compact mode the default display for activity threads
- Add activity-cleared-at persisted state tracking (per-pane cutoff timestamps)
* improve style
* minor change
* feat(activity): add persisted host and project filters to agents view
Agents scope filters are deliberately separate from workspace-nav filters so a monitoring surface never inherits workspace context silently. Filters survive restarts and always display an active-filter chips row with hidden count, making filtering visible and reversible.
* Graduate Agents view from experimental, refine activity handling
- Agents Dashboard moves from experimental to standard feature with showAgentsSidebar setting controlling visibility
- Add identity-checked cache eviction (dropPersisted IPC) to prevent newer runs from being evicted when UI clears older status, fixing clear-completed safety
- Extract ActivityThreadHoverCardSummary and ActivityThreadListToolbar components for better organization and reusability
- Implement mark-thread-read as separate action from select with clickable bell icon
- Add hasActivityThreadWorkspace helper for checking workspace availability across hosts (SSH/runtime targets)
- Preserve scope filter array identity during hydration for memo optimization
- Track manually-unread turns in auto-ack to prevent re-acknowledgement
- Clean up activity cleared-at cutoffs on pane retirement
- Remove activity-thread-hover-card max-lines lint override (code refactored below threshold)
* Refactor agent cache identity to use timing fields only
- Simplify AgentStatusCacheIdentity: keep only paneKey, receivedAt, stateStartedAt
- This fixes silent no-ops where renderer-enriched fields diverged from main's cache
- Add worktree-jump-navigation for navigating activity to workspaces
- Add manual mark-unread protection separate from auto-ack
- Optimize activity owner resolution with per-build memoization
- Optimize detected worktree lookup with indexed search
* Remove sticky header, add scroll position persistence
Replace the floating sticky header overlay with scroll position memory via
a ref. This preserves the user's scroll location when switching between
threads or remounting the agents list, improving UX without requiring
React state.
* Implement sticky group headers in activity thread list
Keep group headers visible at the top while scrolling when threads are grouped. Headers stick to the viewport while their section is in view, then unstick as the next header approaches.
* add blue flash
* update settings appearnce
* Extracted activity acknowledgement/clearance actions from the oversized UI slice.
- Removed dead sidebar search/menu props and the unused search ref.
- Removed the unnecessary sidebar visibility bitmask.
- Replaced hardcoded sidebar toggle colors with design-system tokens.
- Removed duplicate “mark all read / clear completed” controls in the sidebar.
- Preserved manual-unread state correctly across pane retire, transfer, and drop.
- Made clear-completed cutoffs monotonic so clock skew cannot resurrect old activity.
- Fixed blank workspace names in hover cards with the existing fallback helper.
- Added missing localization entries and stabilized hydrated filter array identity.
- Updated misleading Agents setting copy to describe both sidebar surfaces.
* add onboarding guide for the new agents panel
* Add activity clearance tracking and synced agent view settings
Agent view filters and presentation settings now sync across paired clients.
Preserves per-pane activity clearance cutoffs in persistent state. Improves
activity thread row accessibility with proper ARIA roles, and preserves
terminal host ownership after pane teardown via retained terminal handle.
* rm html
* Graduate Agents from experimental and improve activity visibility
- Migrate `showAgentsSidebar` setting from legacy experimental flags; default new profiles to the agents sidebar
- Replace scoped-thread filtering with visible-thread filtering so bulk actions (mark all read, clear completed) only affect rendered rows
- Rewrite child agent classification as a set of visible pane keys to fix orphan promotion and parent-cycle handling
- Improve activity cleared-at cutoff lifecycle: preserve on row dismissal (pane may still be live) but clear on pane removal
- Add pagehide flush for pending clear-completed evictions so quit/reload cannot replay cleared activity
- Polish agents sidebar: unread count badge, expand button, onboarding intro for migrated/new users
- Extract shared time-ago formatting to a library module
- Fix scroll restoration to defer until content can contain the saved offset
- Improve stable message hold for compact agent rows using state instead of refs
- Add worktree filter-visibility check to distinguish collapsed-but-unfiltered from filtered-hidden
* Graduate Agents from experimental and improve activity visibility
- Remove the deprecated full-page Agents view; fix settings navigation fallback
- Refactor bulk action bindings and separate mark-all-read from visible threads
- Preserve sidebar collapse state across remounts; fix child-agent badge filtering
- Add safety window for scroll-restore and improve worktree host-qualified filtering
* Graduate Agents from experimental and add manual unread tracking
- Move Agents sidebar from experimental settings to standard feature with intro flow
- Add persistent manual unread turn tracking for activity feed
- Consolidate workspace activation through activateAndRevealWorkspace dispatcher
- Improve sidebar view toggle with radio semantics and arrow-key navigation
* Graduate Agents sidebar and separate dashboard experiment
The Agents tab now has its own `showAgentsSidebar` setting (defaults on) independent from the dashboard popout experiment. Activity unread counting is simplified to count all events uniformly without mode-specific filtering. Dashboard visibility is now controlled solely by `experimentalAgentDashboardPopout`, with its own UI in the Experimental settings pane. Migration path updated: only `experimentalActivity=true` graduates to the sidebar; the dashboard experiment remains separate.
* Add agent-session tab support to activity tracking
Build activity event contexts from structured agent-session tabs and
worktree-attributed status entries. When activating a thread, try
agent-session tab activation before falling back to terminal pane.
* • The workspace sidebar tab is now a static Spaces
label—no grouping-based “Projects” label or hidden
width-reservation span.
* Show unread count badge and prioritize attention-needing agent threads
Activity group order now surfaces threads needing attention (blocked,
waiting, interrupted) before working/done so they're never buried. The
Agents tab shows an unread count badge while viewing Spaces, since the
open Agents list already highlights unread rows.
Also improves UX text ("Hide Agents" vs "Maybe later"), accessibility
with proper ARIA labels, and handles edge cases: preserves read state
for retained panes on SSH reconnect and handles deleted worktrees
gracefully in navigation.
* Batch agent-status evictions and optimize activity pane rebuilds
- Add dropPersistedStatusEntries batch API; consolidate evictions into one persist
- Implement fallback timeout in clear-completed for unseen toast callbacks
- Project only activity-relevant tabs; memoize terminal tab derivations
- Stabilize activity virtualizer key to prevent unnecessary item measurements
* Remove unread count badge from Agents sidebar tab
Simplify useActivityUnreadCount by removing the enabled parameter and
conditional logic, as the badge is no longer displayed in the UI.
* Deduplicate activity unread counts across source overlaps
Live pane status is the primary source; retained and migration entries
serve as fallback caches that may briefly overlap it during lifecycle
transitions. Count each pane only once by tracking seen keys, prioritizing
the live status as the canonical source.
Also fix monitoring state display: it's a distinct agent state, not a
tool-running row state, so exclude it from tool preview checks.
* Update activity pane tests to remove unread badge assertions
- Remove ActivityPaneVisibility type and readActivityPaneVisibility() helper
- Update agentsSidebarButton selector to match badge-less state
- Simplify assertions to check pane focus instead of visibility isolation
- Remove test for unread badge acknowledgement flow
* Fix activity pane workspace resolution and localization handling
- Thread defaultHostId through activity operations for correct host resolution
- Add language-aware caching for standalone terminal names with cache invalidation
- Fix scroll restoration bounds calculation for tall viewports
- Add focus management to sidebar radio group keyboard navigation
- Refresh localized sidebar content on language changes
- Preserve activity state across heartbeats to prevent history loss
- Improve host-id strictness in worktree jump navigation
* Preserve activity view when settings fetch fails
A failed window.api.settings.get() leaves settings null, which was
incorrectly treated as opt-out. Add the missing null check so the
activity-view gate only applies when settings are available.
Includes tests for this scenario and related edge cases in keyboard
navigation, worktree jumping, and session state handling.
|
||
|
|
6062edf296 |
test: simplify remote pane link routing to server-hosted placement (#18219)
Remote-pane links are now explicitly server-hosted regardless of generic client-hosted preference. Remove client-hosted placement verification, placement-switching test acts, and related type definitions. Focus the test on verifying the core invariant: links stay server-hosted on their owning runtime. |
||
|
|
f737f3499f |
fix(relay): stream an oversized fs.listFiles reply instead of refusing it (#17954)
Opening Orca's own checkout over SSH cannot list its files in one response frame. 22,617 tracked paths average 58 characters, so the 20,001-row page the client asks for serializes to 1,223,415 bytes — past `DISPATCHER_CONTROL_QUEUE_MAX_BYTES`, so `sendResponse` demotes it to the `legacy-response` lane, where an unrelated producer backlog can refuse it as an opaque `ResponseOverCapacity`. Break-even is around 49 characters of average path; any `packages/<name>/src/...` monorepo is over the line. Picking a ceiling to refuse at does not fix that, it just moves where it shows up and refuses listings that would have been delivered. `__streamResponse` already exists for exactly this on the git methods, and it is its own negotiation in both directions: an old client never sends it and gets the plain array on the legacy-response lane as before, and an old relay ignores it and answers plainly, which the client detects by the sentinel marker being absent. So fs.listFiles opts into it — no new method, no new opcode, nothing to advertise — and the size of a listing stops being a correctness question. The response-stream registry becomes one per relay, shared by FsHandler and GitHandler. A second registry is not an option and the header of git-response-stream.ts says why: a client keys reassembly on `streamId` alone, so two would hand out the same id and cross-feed chunks, and only the handler that registers `git.responseAck` can credit the window a pump parks on. Also declares `maxResults` on the runtime-RPC `files.listAll` and forwards it. The mechanism "the client names its cap, so a full page reads as truncation" was wired only on the Electron IPC hop; web and mobile were saved incidentally by `remoteFileContentBudget` defaulting the cap inside `listRuntimeFiles`. A new optional field is additive in both directions (wire rule 1). The new Docker-gated spec is claimed by run-ssh-docker-e2e.mjs. The sharded e2e lanes set no ORCA_E2E_SSH_DOCKER, so a Docker-gated spec that no runner names self-skips everywhere and still reports green — pr-e2e-gate-contract enforces that. Closes #12547 |
||
|
|
32e4c6be4a |
Auto-focus editor when opening new markdown file (#18071)
* feat(markdown-preview): autofocus editor when opening new markdown file Users should be able to start typing immediately after creating a markdown file without an extra click. * add e2e tests * add e2e tests |
||
|
|
0dbe9d0504 |
test(ssh): dockerized relay fault injection with verdict assertions (#18017)
* test(ssh): add a dockerized SSH fault-injection lane with four fault shapes The existing SSH reconnect specs all reconnect by calling ssh.disconnect() then ssh.connect() - a clean cycle the client knows is coming. Nothing covered the faults the reconnect machinery exists for. Four shapes, each documented with why it is not the others: killing sshd's per-connection forks (transport dies, relay survives), `docker pause` (silence with TCP still established), SIGKILLing every relay.js (the only fault where `exited` is the correct verdict), and a 48MB flood with nobody attached. The relay-kill case is the one that makes the rest meaningful: every other case asserts the session survived, which only means something if a genuinely dead session is distinguishable. It is the only case where replacing the pane is correct, so it pins the boundary in docs/reference/ssh-execution-boundary.md rather than just testing reconnection. The `docker pause` case pins the other side of that boundary: after 30s of silence from a healthy host the pane keeps its PTY and its scrollback, because loss of contact is never evidence of death. No network-blackhole fault: reconnecting the fixture does not restore its published port mapping, so that fault is not reversible on this container and would strand the worker it ran on. * test(ssh): fixme the flood case pending #18018 It fails in CI on its first real run: the pane keeps its PTY and repaints, but a command run after the flood produces no output within the poll budget. Same shape as #18018 and not caused by this spec. The three verdict assertions around it stay enforced. |
||
|
|
0352c239c2 |
Add Copy Session ID menu item to terminal tabs (#18039)
* Add Copy Session ID menu item to terminal tabs
Adds a menu item to copy the active pane's agent session ID when available.
The item only appears when the session is still live and has reported an ID.
* Add Copy Session ID i18n strings and e2e test
- Add localized strings for Session ID context menu item
- Add e2e test coverage for copying session ID from terminal tabs
- Fix dev build permissions when copying private Electron app bundles
* Drop the Electron dev-bundle fix from this branch
It landed on main as
|
||
|
|
f8a3f2c7c0 |
test(e2e): do not treat a destroyed renderer as a relaunched runtime (#17785)
* test(e2e): do not treat a destroyed renderer as a relaunched runtime waitForRelaunchedRuntime polled refreshAuthorityRuntimeId with expect.not.stringMatching(previousId). Playwright treats null as a non-match, so an Execution-context-destroyed miss ended the wait as if the client had already reconnected. Poll until a non-null id that differs from the pre-restart process. * test(e2e): wrap cookie-survival restart evaluates as pending misses The cookie spec still opened a post-restart page with a raw evaluate poll. A recycled renderer then timed out as "never materialized". Use the shared fixture helpers so destroyed-context is a miss, not a fail. * test(e2e): leave cookie-survival on its own wait for this PR The relaunch-wait fix made the cookie spec's post-restart echo render time out in CI. Keep that spec out of this change so the destroyed- context wait can land on the helpers restart-survival actually uses. |
||
|
|
a5796ec8eb |
refactor(runtime): split OrcaRuntimeService and compatibility tests (#17605)
* refactor(runtime): split OrcaRuntimeService into focused modules
* test(runtime): cover admission tiers and strict worktree reconciliation
* fix(runtime): preserve owner and structured session visibility
* fix(runtime): port post-extraction compatibility fixes
* fix(runtime): preserve skill-share cancellation barrier
* test(runtime): update identity inventory after extraction
* fix(runtime): preserve hook transport environment cleanup
* fix(runtime): consolidate idle probe imports
* test(runtime): retire split file process allowlist entry
* fix(runtime): route child process types through shared boundary
* test(runtime): preserve worktree host metadata precedence
* fix(runtime): update extracted test seams
* fix(runtime): gate the split's ts-nocheck set and restore the stop-confirmed contract
Audit follow-ups for the OrcaRuntimeService split:
- Freeze the 171 @ts-nocheck files behind a ratchet so no new file can disable
type checking. The split's linear mixin chain cannot express forward
references yet, so the existing suppressions are grandfathered; the baseline
may only shrink.
- Drop the stray @ts-nocheck at the end of orca-runtime-get-status.ts. It sat
after the first statement, where TypeScript ignores it, so the module was
already checked.
- Restore `retireRejectedPty(ptyId, stopConfirmed: boolean)` as a required
argument. The split widened it to optional and patched the resulting error
with `stopConfirmed === true`; an omitted argument would have silently taken
the unverified-stop path instead of failing to compile.
- Guard that every orca-runtime-tests fragment is imported by the compatibility
entrypoint. The fragments are .spec.ts, which no Vitest include glob matches,
so one left out of the list would silently stop running.
* fix(runtime): restore four behaviors the OrcaRuntimeService split dropped
Audit findings against the refactor's true base (
|
||
|
|
1efd4e1a97 | test(e2e): seed source control diff before opening panel (#17784) | ||
|
|
f116d2ca2a |
test(ci): retry Windows teardown EPERM and restart evaluate misses (#17780)
Restart-survival polls treated a recycled renderer as a hard failure. Wrap those evaluates so "Execution context was destroyed" is a pending miss. Windows package-lane teardowns after a force-kill used rmSync with force:true only, which does not absorb EPERM; put them on the shared maxRetries:8 policy. |
||
|
|
eff317939a |
fix(terminal): mount one surface per workspace id in the workbench (STA-4846) (#17432)
* fix(terminal): mount one surface per workspace id in the workbench (STA-4846) * test(terminal): pin the workbench projection against under-selecting Losing a surface unmounts live terminals, which is worse than the duplicate mount STA-4846 fixes, so cover every catalog shape that reaches the workbench: local-only rows that name no host, an unqualified row colliding with a host-qualified one, two SSH hosts on one id, folder rows across three hosts, folder ids alongside git worktree ids, and a whole-catalog assertion that the emitted id set equals the distinct input id set. Also pin the `useAllWorktrees` -> `useWorktreeMap` swap: both read the same WeakMap-cached snapshot, so the zustand compare is unchanged. Harden the folder tie-break to require the row to name its own host. `getCatalogOwnerHostId` defaults an unstamped row to `local`, which would let a row that never named a host win the `local` tie and mount another host's path; it now keeps first-wins instead of guessing. * fix(terminal): surface the unresolvable folder-surface collision When two hosts publish the same folder-workspace id and the active workspace's host cannot be resolved, the projection drops one row's folderPath first-wins. That path is the PTY cwd for any tab without a startupCwd, so the drop was silent. Warn on it, and pin the two tie-break branches the unit tests missed: a colliding row that is not the active workspace, and the same collision with the rows in swapped order (a host reconnect re-appends its rows, flipping which row is first mid-session). * test(e2e): ride out Playwright's spurious main-process evaluate rejection `e2e / changed e2e specs` failed on `pr11346-selected-runtime-add.spec.ts` with "Execution context was destroyed, most likely because of a navigation" from the paired client's first `app.evaluate` — the isolated-HOME assert that runs one millisecond after `electron.launch()` resolves, which is before the app is `ready`. Nothing navigates there: Playwright raises that message for any main-process CDP failure that is neither a JS error nor a closed session, and `ElectronApplication.evaluate` is unreliable on Electron 27+ (microsoft/playwright#33737). Reproduced locally, and a plain re-run of the same commit went green. Extract the retry `installTerminalPtyWriteSpy` already carried for this exact message into `retryTransientMainEvaluate`, and use it for the launch-time home read in all three launchers. The read is idempotent and a real boundary escape still throws on the first successful read. Also forward the paired client's process logs before the assert instead of after: this failure reached CI with none of the client's own output, because forwarding had not started yet. * test(e2e): wait on the owning group before asserting a Cmd-J browser tab is active `changed e2e specs` then failed at the remote browser-page step: the store poll had already seen `activeBrowserTabId` land on the mirrored workspace, but `[data-tab-id=...][data-active="true"]` never appeared. `data-active` on a `BrowserTab` is the strip's active tab, which comes from the owning group's `activeTabId` — not from `activeBrowserTabId` — so the DOM assert was racing an activation the poll never waited for. The simulator rows in the same spec already poll the group; the two browser-page rows did not. Poll the same triple for them, so a genuinely stuck group fails with the ids it ended on instead of a bare "element(s) not found". |
||
|
|
c558d7e083 |
Activate terminal splits before inherited CWD resolution (#17601)
* perf(terminal): activate splits before cwd resolution * test(terminal): prove split focus before cwd publish * fix(terminal): release stale split cwd fence * test(terminal): add visible split activation latency benchmark * docs(reliability): clarify split benchmark provenance * fix: preserve deferred split handoffs across remounts * fix: fence late deferred split closes * docs(reliability): record exact split benchmark runs * test(reliability): fail benchmark on artifact write errors * test(reliability): attribute split activation phases * docs(reliability): record schema-v2 split benchmark * refactor(terminal): collapse duplicated split-handoff and write-queue paths - Drop the discardDeferredSplitPaneHandoff alias for its identical clear twin. - Fold the deferred-cwd resolve/reject settle handlers into one applier. - Extract settlePaneCwdDeferredSpawn for the repeated read-clear-write pattern. - Share one head-index FIFO primitive between the ordinary and reply queues. * fix(terminal): stop retaining a promise reaction per acknowledged write Racing every accepted write against one queue-lifetime cancel promise kept a reaction record alive until that promise settled: 200k acknowledged writes retained 88.6MB, now 0.1MB. Give each in-flight write its own cancel, and split the shared FIFO primitive into its own module. Also sanitize the split-latency benchmark report at its single serialization point so shared artifacts no longer carry the machine-local repo path or unbounded cleanup error text. * fix(terminal): settle deferred split input when the spawn is abandoned An abandoned deferred spawn returns before transport.connect(), so nothing drained the pre-connect buffer: sendInputAccepted's promise never settled and a paste into that pane hung forever. Clear the buffer on the abandon fence. Also re-derive the pre-connect retention cap from the clipboard-paste ceiling rather than the 16MB single-write ceiling; it is held twice per pane across up to 64 deferred splits, so 5.59M code units guarded the wrong thing. * fix(terminal): release the deferred cwd fence on a rejected reattach A daemon createOrAttach can turn an apparent fresh spawn into a reattach; when that reattach is refused the spawn ends with deferredSplitSpawn/pendingCwd still set, permanently arming the pre-bind detach refusal. The release no-ops when a PTY did bind, so it only fires where the fence would otherwise leak. The stale-generation return above is deliberately left alone: a newer connect already owns the pane there, and the fence is not generation-scoped. |
||
|
|
bbbb59e18c | test: cover quick commands, catalog links, and long discard dialogs (#17489) | ||
|
|
d5d3c4898a |
perf(diff): defer large diffs until user loads them (#17521)
* perf(diff): defer large diffs until user loads them Rendering very large diffs would freeze the UI. Diffs exceeding MAX_AUTOMATIC_DIFF_CHANGED_LINES now show a prompt allowing users to load them on demand instead of automatically rendering. * perf(diff): defer large diffs until user loads them Diffs with >10,000 changed lines are now deferred and only rendered when the user explicitly clicks "Load diff" in a prompt. This improves initial render performance for large file changes while maintaining full access when needed. * perf(diff): defer large diffs until user loads them Prevents UI freeze when opening files with very large diffs by deferring render until the user explicitly loads them. * fix(diff-view): defer loading large untracked files and refactor fallbac Split on-demand load decision logic to distinguish tracked vs untracked files — large untracked files now properly defer loading while untracked images remain automatic. Extract fallback height computation into a dedicated function to centralize the logic for render-limited and in-flight-loading states, reducing code duplication and clarifying when to use bounded fallback heights. * fix(diff-view): defer loading large SVG files SVG renders as source text in the diff view rather than a preview, so should defer like other text files. Also fix Windows e2e test cleanup by using post-Electron shutdown. |
||
|
|
fbe94ceff6 |
fix: close readiness gaps found by merged-change audit (#17159)
* fix(ssh): fence stale kills and retired pane replay * fix(ssh): support cancellable interactive authentication * fix(ssh): await remote catalog before snapshot adoption * fix(pty): contain Windows ConPTY input failures * fix(power): avoid redundant macOS display blocking * perf(editor): narrow markdown override subscriptions * fix(quick-open): close directory handles after reads * refactor(linux): remove unused proc socket scanner * fix(usage): apply flat Sonnet 4.6 pricing * ci: prime Node next native test cache * docs(skills): resolve snapshot cleanup data path * fix(ssh): recover install locks after host reboot * test(ssh): recognize boot-aware install locks * test(ssh): prove previous-boot lock recovery live * test(wire): pin pre-metadata release coverage * fix(terminal): preserve remote tab ownership through recovery races * test(runtime): fence replaced terminal handles in agent guard * fix(ssh): preserve remote snapshot authority across polls * fix(pty): contain late ConPTY output EPIPE * test(pty): register Windows exit watcher before kill * fix: close SSH and tab readiness race gaps * fix(tabs): retain headless order and placeholder titles * fix(build): avoid parallel electron-vite config race * test(windows): avoid MSYS temp path rewriting * test(windows): avoid killing exited PTY * fix(pty): avoid late ConPTY input teardown race * fix(terminal): sync reconnect error ownership after commit * fix(runtime): use canonical worktree identity comparison * test(ssh): assert complete cold-hydration baseline * test(windows): invoke quoted retention fixture via PowerShell * test(windows): read ConPTY grid through mode con * fix(terminal): publish PTY replacements atomically * fix(terminal): infer stale identity on reattach * fix(terminal): fence stale pane PTY callbacks * fix(terminal): fence stale pane binds after rebind * fix(terminal): reject stale pane transport callbacks * fix(terminal): fence mirrored reattach spawn callbacks * fix(terminal): replace stale pane PTYs on remount * fix(ci): size the Windows launcher-compile test budget from measurement `native-smoke (windows-latest)` fails ~4.5% of runs on `preserves a multiline argument through the compiled remote launcher` with "Test timed out in 15000ms" — on unrelated PRs, for reasons that have nothing to do with them. Across 176 sampled attempts it is the only red that job produced, and it hit seven different PRs in two days: #16900, #16904, #16915, #16955 (twice), #16979, #17014, #17085. The test is six process creations: powershell.exe forks csc.exe, then the freshly compiled orca.exe forks node.exe, twice. Hosted Windows runners periodically slow process creation down, and this test amplifies that far harder than anything else in the job. Comparing the 80 attempts where it ran under 3s against the 12 where it ran over 12s, its own median goes 2198ms -> 15917ms (7.2x) while the same file's powershell-only test moves 556 -> 686ms (1.2x), the cmd.exe and Git Bash process tests in the neighbouring file move 1.4x, and the other 35 files put together move 1.5x. Measured across those 176 attempts: 1881ms to 35438ms, p50 4264ms, correlation +0.881 with the job's total Vitest duration. 8 of 176 (4.5%) exceeded the 15s cap; 2 of 176 (1.1%) also exceeded the shared 30s testTimeout, so deleting the override and inheriting the config is not enough on its own. 60s clears all 176 with 1.7x headroom on the worst. This is slow, not hung. Every body here is synchronous spawnSync, so Vitest cannot interrupt one — the timer fires only after the body returns and the reported duration is real elapsed time. That is why a failure reads `× ... 22464ms` under `Test timed out in 15000ms`. The work finished; the stopwatch was short. Seven reruns at one identical head measured 2053 / 4680 / 5551 / 8732 / 13506 / 14868 / 21937ms — the last of those would have been red on code that had not changed. The 15s came from #8897, which raised this test off Vitest's built-in 5s default because the job then ran bare `pnpm vitest run`. #8909 landed 3h27m later and pointed the job at config/vitest.config.ts, which is the real fix for that. The constant stayed behind and has been the binding budget ever since. * fix(terminal): fence stale remount reattach ownership * fix(terminal): reconcile mounted pane identity after replacement * fix(terminal): fence stale reattach fallback ownership * fix(terminal): fence deferred SSH reattach ownership * fix(terminal): fence stale split pane ownership callbacks * fix(terminal): keep stale spawns from consuming startup --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> |
||
|
|
46fa1a98d0 | fix(browser): show reload loading feedback (#17635) | ||
|
|
3060cf73b9 |
fix(tasks): restore scroll position when reopening GitHub item details (#17524)
Track scroll-restore generation to invalidate stale callbacks that were resetting the scroll position to 0 when reopening a detail page. Prevent restoration while a detail page is open. Update automation test to use runtime.call RPC instead of removed preload CRUD method. Hide browser import hint in E2E profile to prevent overlay from intercepting test setup clicks. |
||
|
|
0d8785b916 |
Prevent stale search commits from timer race conditions (#17495)
Validate scheduled values match current state before executing idle timeout callbacks. Use useLayoutEffect to synchronously update refs, preventing outdated searches when rapid keystrokes overwrite timers. |
||
|
|
f7d8d7f77a |
test(e2e): make the cold-hydration spec verify its own captured snapshot (#17031)
`adds no tab when the host workspace snapshot stalls across a relaunch` replays the bytes it reads off the relay, but only ever waited for the snapshot FILE to exist -- never for it to carry the tabs the test had just seeded. A capture that missed the baseline produced a failure that reads as a product regression and is not one: an empty `session.tabsByWorktreePath` places nothing, so it reports nothing unplaced, so `remote-workspace-snapshot-apply.ts` marks the target hydrated and `hydrateTabsSession` replaces the worktree's tabs with none. That is exactly the observed `baseline=3 duringStall=3 afterHydration=0`, and it is correct behaviour for a host snapshot that genuinely holds no tabs. Assert the precondition where it belongs -- on the capture, before the relaunch that consumes it -- so an empty or unparseable fixture names itself instead of surfacing later as a tab count the product appears to have lost. No assertion is weakened: `afterHydration` still has to equal the baseline, and no retry, sleep, or timeout was added. |
||
|
|
e84042572c |
Upgrade xterm to 6.1.0-beta.303 and generate addon patches
* Upgrade xterm to 6.1.0-beta.303 and generate the addon patches
Takes the current xterm beta line: xterm 287 -> 303, addon-webgl 286 -> 299,
addon-serialize 287 -> 300, headless 302, the remaining addons -> 300, and the
same set on mobile. All four packages stamp upstream commit d3e32b3.
The reasons are upstream #6042/#6043/#6055 (a shared glyph atlas no longer
garbles sibling panes on a page merge, clear, or sampler-budget overflow) and
Note that core 303 is not image-addon-only over 302: it carries the buffer perf
work, including the new BufferLineStringCache.
addon-webgl and addon-serialize move into the patch generator
--------------------------------------------------------------
Both were hand-edited minified bundles, which is what the Known Gaps section of
docs/reference/xterm-patch-regeneration.md described. Both reproduce byte for
byte from the pinned commit, so they are now manifest entries generated from a
source patch like @xterm/xterm already was. Their sourcemaps now move with their
bundles; before this they shipped maps whose offsets did not match the code
beside them.
The webgl patch shrinks from a 1.06 MB hand-edited bundle to a 6.6 KB source
patch, because upstream took the invalidation half Orca had backported. What is
left is only what upstream still lacks: the fragment-shader else branch for a
v_texpage past the sampler budget, the clearTexture guard that no-ops once a
merged page holds index 0, spending the merge retry budget before beginFrame
latches the version it saw, and Orca's font-weight probe.
The serialize source patch is byte-for-byte the same fixes as before; upstream
changed nothing in that addon between 287 and 300.
Generator fixes, each of which failed silently
----------------------------------------------
- `--relative` was appended after the `--` separator in CHECKOUT_DIFF_FLAGS, so
git read it as a pathspec and kept repo-root-relative paths, dropping every
source hunk from an addon's patch.
- `git apply` run from a package subdirectory still resolves patch paths from
the repo root, skips every hunk and exits 0. It now runs from the root with
`--directory=<packageDir>`, and a source patch that leaves the checkout
unchanged is a hard failure rather than an empty patch.
- An addon's own `tsgo -p .` has empty files/include and only project
references, so it emits nothing and the addon webpack then fails on a missing
./out/. The root build now runs first.
- versionStampFile is optional; publish.js stamps an addon's package.json, which
overlayBuildOutput never patches.
- On a version bump the lockfile has no entry under the new key yet, so --write
reports the gap instead of aborting mid-run. --check still fails on it.
Adding the two addons pushed the generator and the Electron packaging contract
test over max-lines, so the patch-text helpers move to xterm-patch-text.mjs
(pure text: no checkout, no build) and the vendored-xterm assertions move out of
the packaging contract into xterm-webgl-runtime-contract.test.mjs.
Tests
-----
Four tests asserted upstream bugs that are now fixed, not Orca behaviour:
- xterm-user-scrolling-contract pinned headless and core by version string.
Upstream bumps each package only when its own output changes, so headless 302
and core 303 are the same source. It now asserts they share a commit.
- Five CSI 3 J assertions expected a reader stranded at the top after an erase.
Upstream #6081 clears isUserScrolling there, so the erase releases them to the
bottom instead. Orca's pin still lands them correctly, because its parser
handler observes the erase before xterm's own handler runs.
- The IME transaction test hard-coded the xterm version; it now reads the
installed package, since the point is that bundle, map and version agree.
- The Electron runtime contract asserted Orca's old clearModelGeneration. Shared
atlas invalidation is upstream's now, so it asserts pageLayoutVersion on the
resolved dependency, plus the Orca-only hunks on the patch.
Verified: 66,008 unit tests, mobile's 3,863, the four WebGL atlas e2e specs, and
`regenerate-xterm-patches.mjs --check` in sync on all three packages.
Left alone deliberately: resetAllTerminalWebglAtlases still fans out globally
even though clearTexture now self-heals siblings, and upstream #6068
(WebglAddon.dispose leaks the GL context) is still open.
* Drop the two unused WebGL atlas fan-out exports
resetAllTerminalWebglAtlases and presentAllTerminalPanesWithoutAtlasClear have
no callers, and had none at
|
||
|
|
3ab9766e38 |
perf(worktree): prepare checkouts while the composer is open
Squashed merge of PR #17290. |
||
|
|
fd52e942bd | fix(tasks): keep the remembered GitHub scroll offset instead of clobbering it (STA-5949) (#17433) | ||
|
|
6677ae4e5e | test: correct 8 stale specs surfaced by the test-detected-bugs sweep (#17434) | ||
|
|
70df6f0224 |
fix(terminal): mask the agent composer's dim placeholder during a preedit (#17377)
Split out of #17170, which now carries only the xterm composition-overlay work. Codex and Claude draw an all-dim, full-row ghost placeholder. The opaque preedit overlay reproduces the committed row tail it covers, so without this the ghost is repeated to the right of the composing syllable instead of staying masked. The binding keys off the `.xterm-composition-remainder` class that #17170 adds and hides it through CSS while a composition owns a structurally verified placeholder row — bold prompt glyph plus a dimmed model footer below a blank gap for Codex, a frame line above the prompt for Claude. Arbitrary dim output, shell lookalikes, and any row carrying typed text keep their tail visible. readTerminalCursorLineContext moves from src/main/daemon to src/shared because the renderer now needs the same reader the daemon uses; the move is import-only. Depends on #17170. |
||
|
|
7f822a73e3 |
fix(terminal): render the IME caret and give the candidate anchor one owner (#17170)
* fix(terminal): render IME caret without placeholder overlap * fix(terminal): preserve dim mid-line composition tails * fix(terminal): keep IME caret visible at row edge * fix(terminal): harden IME overlay lifecycle and layout * test(terminal): type final-cell layout mock * fix(terminal): keep final-cell IME anchor on-screen * fix(terminal): bind IME masking to composer ownership * fix(terminal): bound IME placeholder session ownership * fix(terminal): track latest IME placeholder session * test(terminal): share IME session event fixture * fix(terminal): keep both writers of the IME candidate anchor in agreement `textarea.style.left` has two writers: xterm's patched CompositionHelper and Orca's terminal-ime-candidate-anchor.ts. The anchor module listens on terminal.element, so within a composition event it writes after xterm's textarea listener and reverted the final-column clamp the patch had just applied. Moving the clamp into the anchor module and dropping the patch hunk does not fix it, and the rendered e2e caught that: CoreBrowserTerminal.ts:444 drives updateCompositionElements from onRender as well, so xterm re-asserts the textarea position on every repaint, with no composition event for that module to hear. The anchor survived only when no render happened to follow — measured as a flake at the final column, 1561.28px against a 1557px screen edge, the fully unclamped value. So both writers now compute the same clamp. The patch keeps it, because it is the writer on the render path and already holds cursorLeft, maxWidth and the preedit bounds. The anchor module applies the same one, so its composition-event write no longer reverts the correction in the window before the next render. Both halves are individually necessary and both are mutation-tested. Also restores _getRowRemainderText's expression from main: translateToString(true, x, line.length) and translateToString(false, x, getTrimmedLength()) are the same call, since upstream does endCol = min(endCol, getTrimmedLength()) under trimRight. Adds the two missing tests — one installing both anchor writers in a single rig, one driving a render under an open composition — plus disposal cleanup and clamp-bound coverage, and moves the Codex/Claude placeholder mask to a follow-up PR. |
||
|
|
7b467bd0a6 |
ci: gate PRs on a real input method, and prove the lane engaged one (#17365)
* ci: gate PRs on a real input method, and prove the lane engaged one No job on the PR gate has ever run a real input method. pr.yml and e2e.yml are ubuntu-latest with CDP `Input.imeSetComposition`, which is a synthetic composition; the only job that drives ibus-hangul through xdotool is terminal-ime-e2e.yml, and it is schedule + dispatch only. A PR could turn the real-IME path red and merge green. Route IME source to that lane from pr.yml through the existing pr-e2e-source-routing mechanism, so it runs on IME-touching PRs and nothing else. The lane stays out of verify.needs — advisory, like `e2e` — because its reliability is known only from nightly main runs. Deliberately no continue-on-error: that reports green and hides the signal. The harness fails open in ways that all look like success: Playwright reports a skipped test as a pass, so an unset ORCA_E2E_NATIVE_IBUS_HANGUL, a renamed test, or a session with no engine all exit 0 having exercised nothing. The specs now append an engagement receipt only after observing real composition events, and the runner requires one per expected test before the lane may report success. Also drop the native spec from changed-e2e: it was already routed there by its own filename, where it self-skips for want of an ibus session and reported that skip as coverage. * ci: let the real-IME step report even when the synthetic step failed |
||
|
|
2259e06ff6 |
fix(tests): match showInactive() in paired-client-window-reveal spec (#17362)
PR #17347 switched the reveal helper from window.show() to window.showInactive() and updated the thrown message, but left the unit test's regex/title matching the old show() wording — failing deterministically in CI (which builds against current main) while passing on any stale checkout that predates #17347. |
||
|
|
09429768c5 | test(cross-version-wire): compare published fields per frame (#17301) | ||
|
|
252dbd60ea |
fix(terminal): restore lossy initial remote snapshots (#17113)
* fix(terminal): restore lossy initial remote snapshots * test(terminal): strengthen lossy snapshot causal oracle |
||
|
|
ae0f3675a1 |
fix(remote): focus host-delegated split panes (#16886)
* fix(remote): focus host-delegated split panes Return the authoritative leaf identity from terminal.split, record viewer-local focus intent behind the captured pairing revision, and replay the mirrored layout before focusing the exact pane. Preserve old-host fallback and prevent delayed split responses from stealing focus after the viewer moves away. Add deterministic runtime, renderer, concurrency, compatibility, and headed paired-Electron coverage for Cmd+D, header splits, and immediate PTY input routing. Fixes #16510 * fix(remote): preserve split focus across tab groups Resolve the initiating source tab and leaf from the remote PTY, while keeping the viewer's current focus as a separate anti-steal baseline. This lets context-menu/header splits from non-focused group tabs focus their result without allowing delayed responses to override a later navigation. * test(remote): drive split focus with key events * test(remote): use the platform split shortcut * fix(remote): fence concurrent split focus intent * fix(remote): harden split focus ordering * fix(remote): preserve split focus after runtime refactor * fix(remote): fence stale split focus gestures * test(remote): keep split focus regression within line budget |
||
|
|
5ea9daba97 | fix(window): keep automated Electron launches out of the foreground (#17347) | ||
|
|
f572ba34bc | feat(browser): address-bar convergence — previews and browser tabs convert in place (STA-5681) (#16998) | ||
|
|
73ff003147 |
test(e2e): cover session upgrade and Windows terminal recovery (#17289)
* coverage report * rm test coverage * test(e2e): cover session upgrade and Windows terminal recovery * fix stub |
||
|
|
c6641152f1 |
Split relay dispatcher layers (#17174)
* Split speech session lifecycle * Split terminal output scheduler pipeline * Split mobile browser pane modules * Prune resolved max-lines suppressions * Split pane tree equalization logic * Extract mobile troubleshoot screen styles * Split external automation manager * Split main window service attachments * Split hosted review creation checks * Split automation dispatch event handling * Split settings navigation metadata * Split daemon initialization lifecycle * Split GitLab item dialog * Split relay dispatcher layers * Fix F3-speech for #17123 * Fix F1-cycle for #17131 * Fix F4-navtest for #17157 * Fix F2-allowlist for #17161 |
||
|
|
2214d29f15 |
fix(browser): close guest-owned split tab (#17281)
* fix(browser): close guest-owned split tab * fix: check sourceId before toggling floating panel on close The empty-panel toggle is the ambient fallback only. Guest-initiated closes (with sourceId) target the main workspace and should not toggle the panel. * test(browser-split-shortcuts): remove terminal-mirrors close test and un Removes test case that verified Cmd+W closes guest-owned browser splits when active-tab mirrors point to a terminal, along with the helper function and unused fixture properties that only that test required. |
||
|
|
2dfaa676d8 | chore: update oxlint and oxfmt (#17150) | ||
|
|
b17f60d744 | build: upgrade to pnpm 12 (#17156) | ||
|
|
11d8673112 |
test(cross-version-wire): derive skew expectations from the baseline under test (#17178)
* test(cross-version-wire): derive skew expectations from the baseline under test The cross-version wire job pairs current code against whichever release tag is newest, so a hand-written "the old side does not have X" assertion expires by itself: v1.4.192 was the first tag containing the SnapshotStart `terminalOwner` field, and cutting it turned the new-client/old-server pairing red on unrelated pull requests with no code change anywhere. Read what each build publishes from that build. Each host is now paired against a client of its own version to produce a reference, and the skewed pairings are compared against that reference, so the expectation is whatever the release actually shipped. The same class of assertion in the agent-session suite — "the old build advertises no structured capability and registers no structured method" — becomes "each build's advertisement agrees with what it registers", and the "client too old to know this capability" is derived by removing the capability from the baseline's own list. The guard is unchanged in strength: a field the old host still publishes may not be dropped, skew may not change what a host puts on the wire, and a new pairing asserts the oracle still stalls when a peer cannot decode an opcode the other side sends. * test(cross-version-wire): exercise release structured methods * test(cross-version-wire): load the registered method manifest * test(cross-version-wire): assert execution, not registration, on both host gates The release-shaped checkout gate accepted any reply that was not method_not_found, so a registered-but-throwing handler passed it. The capability gate asserted a shared host spy had been called at all, so the second method mapped to that spy could stop reaching the host unnoticed. * test(cross-version): make the release-shaped skew cover the whole agent-session manifest The release-shaped checkout is the only place the "registered means usable" claim is executable today — the baseline release registers none of these methods — and it was exercising one of sixteen. A handler registered and returning an execution error passed the suite. - Declare each method's result in the manifest, so "answered" is the contract rather than "did not say method_not_found". - Give each build a seam to install a host into its own module slot; a release checkout has its own copy, so the working tree's host was never this dispatcher's, and every host-backed method answered structured_agent_session_unsupported — the capability gate's own words. - Run one execution contract over both skews instead of two divergent loops. - Pair the AI Vault never-called spy with a positive control; renaming the runtime method it watches left it green. --------- Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local> |
||
|
|
92ab618a11 |
Repair scheduled computer-use CI (#17122)
* Repair scheduled computer-use CI * Make Calculator E2E Windows-version neutral * Handle classic Calculator accessibility panes * Update Calculator E2E source contract |
||
|
|
fd9125ea8c |
feat(native-chat): Codex structured native chat restructure (#16729)
* feat(native-chat): port structured Codex sessions from restructure-recovery Rebuilds the desktop structured native-chat implementation from brennanb2025/native-chat-restructure-recovery (tip 4e31c08db3) on top of current main as a single commit, scoped to the local Codex path. Ported: - Structured agent-session core: durable record store + single-writer lease, canonical journal, agent-session wire host/attach/eviction/subscribers, `agentSession.*` RPC surface (registered via ALL_RPC_METHODS; host-side mobile allowlist included for wire compat), pty write gate, transcript additions, and the Codex app-server adapter/launch resolution. - Renderer: NativeChatStructuredSession view/composer stack, structured launch path with the single-flight guard, local structured session tabs sync, activation gate + structured inventory (read-only `agentSession.handoffStatus` probe), agent-session tabs in the tab strip, AI-vault structured session activation, and the settings pane with the parent Experimental Chat UI toggle plus the nested "Use updated structured native chat" toggle. New sessions require both flags, agent codex, no prompt, and a local non-WSL, non-Windows-host execution host (structured-native-chat-availability). - Fixes 72c013cea6 (verified Codex launch recovery), 8ddbaf5e3d (defer native terminal view switching affordances), and 4e31c08db3 (release the launch gate after a visibility retry) with their regression tests, including the third-launch-after-retry guard case. - Cross-version agent-session wire test + CI lane, packaging entries (proper-lockfile, agent-tooling asar excludes), and the wire-compat doc section. Deliberately not ported: mobile/ changes, the Claude structured runtime (only the claude-transcript-branch-proof and claude-structured-owner-identity leaf modules remain, backing the kept TUI-recovery arms), the terminal↔chat adoption/handoff flow (`agentSession.adoptTerminal`/`requestHandoff`, the handoff request engine, TUI adoption machinery, orca-runtime adoption methods), renderer switching affordances and their dead leftovers, the hook/subagent-status refactor cluster, and unrelated branch changes. The crash-during-acquisition recovery path (restart handoff adjudication, restore/reverse re-acquire, lease schema handoff keys) is kept because every plain direct launch depends on it; a trimmed handoff coordinator exposes only status/restore/close. Branch edits that targeted files main has since split (ipc/pty.ts, worktrees.ts, rpc/methods/terminal.ts, useIpcEvents, pty-connection, store/slices/terminals.ts, runtime-types, web preload) were re-applied to the split modules, preserving main's newer logic (Windows CIM fallback, browser tab close rework, cold-restore resume flow, dispatcher threading). Known seam: the mobile clipboard image-provenance CONSUMER gate ships (agentSession.send refuses unproven mobile image refs with agent_session_image_untrusted) but the producer hunk in rpc/methods/clipboard.ts stays with the unported mobile cluster, so mobile image sends into structured chat fail closed until that side ports. * fix(native-chat): trust only authenticated local image uploads * fix(build): preserve Windows process-tree patch application * test(windows): include process creation time in addon fixture * fix(build): run windows-process-tree node-gyp from the physical package dir gyp expands the node-addon-api dependency by probing node, whose cwd resolves to the package's physical directory in the store, so the emitted target is a store-relative ../../../../node-addon-api@... hop. gyp then resolves that hop against the rebuild cwd; from the node_modules symlink/junction it escapes the store and configure fails with "node_addon_api.gyp not found" (run 32999886072). Rebuild from realpath(package dir) so both bases agree, matching how the package manager itself runs native install scripts. The regression test replays gyp's expansion+resolution against the planned cwd and fails without the fix. * fix(native-chat): keep chat tabs visible through terminal closes and empty-worktree launches Two proven blockers in the native Codex tab contract: closeTerminalTab pre-empted the canonical unified close. With one terminal left it deactivated the worktree on a terminal/editor/browser-only check, blanking a workspace that still held a renderable agent-session tab; with two or more it pre-picked a successor from terminal entities only, re-stamping the group active before closeUnifiedTab's MRU/neighbor repair could land on the chat tab. Successor choice now defers to the unified contract whenever the terminal has a unified row, and deactivation is gated on the unified renderable count (matching leaveWorktreeIfEmpty), with the legacy pre-pick kept only for terminals without a unified row. A structured session created on an empty worktree was published into the host's headless group while preserveLocalLayout froze the local layout, leaving the tab in store but permanently off screen. A preserveLocalLayout owner now always takes client-owned placement — repairing a rendered leaf whose group record is missing, or materializing a rendered group on a truly empty worktree — and applies the client-derived layout repair while still rejecting host-authored layout. Regression tests drive the real store through closeTerminalTab (git worktree and folder workspace) and the real snapshot applier for the empty-worktree adoption states; all fail without the fixes. * fix(native-chat): close stale turns and retry rejected sends * fix(native-chat): retire hosted rows on structured tab activation * fix(native-chat): preserve rpc defaults across main merge * chore: format remote wire compatibility guide * test(native-chat): cover retry after unconfirmed send * fix(native-chat): reload outbox on session switch * docs(settings): disclose structured chat platform limits * fix(native-chat): await Codex launch-home preparation * fix(codex): align child-process allowlist with async trust bridge * test(identity): update inventory for tab surface refactor * fix(windows): preserve process-tree CRLF patch sources * fix(native-chat): anchor an unmatched chat echo where it was sent (#16117) * fix(native-chat): anchor an unmatched chat echo where it was sent The reported symptom was old user messages replaying below every new turn, so the conversation read as scrambled. The cause was not that the echo failed to match a transcript row. Claude consumes a mid-turn send through a `queued_command` attachment and writes no `type:"user"` record for it, so some echoes can never match, and no amount of matching will change that. The cause was WHERE an unmatched echo rendered: buildMobileNativeChatTransientData appended every pending item after the entire transcript, so it re-read below each turn that landed afterwards. Render each echo directly after the transcript row it was sent against, using the baseline the send already captures. An unmatched echo is then at worst a duplicate in the right position rather than a scrambled one, and it stays visible. Echoes sharing an anchor keep send order; a send with no baseline, or one whose anchor folding dropped, still falls back to the tail. Deliberately NOT fixed by deleting the echo. Inferring from send ordering that an echo can never match, then removing it, loses the user's own text for a message the agent did receive, and it cannot fire in the common case anyway - measured drain groups are 1,017 of size 1 against 55 larger. It also escalates an existing gap: the count pass has no baseline-tail guard, unlike the glue pass, while `messages` is a 40-row window that head-trims, resets on reconnect and grows at the front on loadEarlier, so a false landing there would license deleting a DIFFERENT outstanding message. That count-pass gap is real and left for a separate change; anchoring makes its worst case a duplicate in place rather than a scrambled conversation. * fix(native-chat): preserve folded echo anchors * fix(native-chat): preserve forward-folded echo anchors * fix(native-chat): keep leading folded echoes in place * fix(workspace-cleanup): show git status for every row (#16690) * fix(native-chat): refuse structured chat on every Windows execution path canUseStructuredNativeChat only refused win32 when a project runtime resolved, so folder-workspace keys (and other keys with no project runtime) failed open into structured chat on Windows. Fail closed on win32 unconditionally after the host check, matching the settings copy: local macOS/Linux only; Windows/WSL/SSH stay on terminal chat. * fix(native-chat): restore runtime refusals behind the win32 gate |
||
|
|
774ce22e84 |
fix(e2e): drop the pi-title spec's stale private connect fork (#17017)
`ssh-pi-compatible-agent-title.spec.ts` kept a private `connectDockerRemote`
that predates #11003. Commit
|
||
|
|
c4b39295c1 |
style: format codebase (#16935)
* style: format codebase * style: format codebase * refactor: extract skill install dialog footer and content Extract footer and content sections from SkillInstallDialog and SkillInstallManagementDialog into separate components for improved maintainability and clarity of component responsibilities. |