Repository navigation
[upstream #24308] fix(runtime): clear a stale agent wait when the tail is a settled ready prompt - #280
Open
innocarpe wants to merge 8632 commits into
Open
[upstream #24308] fix(runtime): clear a stale agent wait when the tail is a settled ready prompt#280innocarpe wants to merge 8632 commits into
innocarpe wants to merge 8632 commits into
Conversation
innocarpe
force-pushed
the
fix-24187-stale-agent-wait
branch
from
October 1, 2026 09:52
780ac74 to
cf6ad0b
Compare
Closed
7 of 9 tasks
Owner
Author
Sync update (
|
innocarpe
force-pushed
the
fix-24187-stale-agent-wait
branch
2 times, most recently
from
October 4, 2026 15:36
433ce82 to
3c6eef1
Compare
…estart (stablyai#31196) * fix(editor): name a server's file by its owned id from the first open, so it no longer reloads after a restart * refactor(mirror): a server file's mirror id no longer needs the bare-path collision lookup * fix(editor): conflict review reuses an open server file under its owned id instead of opening a second copy * fix(editor): conflict review overview shows an open server file's unsaved edits under its owned id * fix(editor): route conflict files by their workspace owner only; keep the overview lookup a plain read * test(mirror): the browser-placement replay test names its server file by the owned id
…yai#29821) Matrix the lane over distro families. Debian 12 and Fedora 41 rootfs are exported from their container images (systemd off only, since the images ship no systemd). The lane test now makes the systemd distro optional and writes its login-env export to the file a login bash actually reads (~/.bash_profile on Fedora and Arch), which made new distros fail for the wrong reason. Co-authored-by: Claude <noreply@anthropic.com>
…ut (A1, dark) (stablyai#31187) * wip(layout): applyDefaultTabs command in the layout model (dark) * wip(layout): applyDefaultTabs takes the window's proposed ids; main refuses a taken one * wip(layout): main closes or keeps an exited split pane by the window's rule (dark) * wip(layout): a create or split sent again after its close is refused (dark) * wip: typed test doubles * wip(layout): main writes a worktree's default tabs in one command and starts them, window or none (dark; twin e) * wip(layout): main writes a worktree's default tabs in one command and starts them, window or none (dark; twin e) * wip(layout): main provisions setup and default tabs even when the agent fails to start; no window takes over (dark) * wip(layout): pane start status in frames; a failed start keeps its pane; a terminal close stands after a failed write (dark) * wip: lint fixes (max-lines, test throws) * test(layout): a terminal close stands after a real failed profile write; switch off still refuses * fix(layout): checked types in the close-failure rule and its tests * fix(layout): a failed start keeps its pane whatever failed; default tabs start once; a tab's last pane keeps its card (dark) * test(layout): the agent's kept pane counts as the workspace's terminal; main starts it whatever failed * fix(layout): the switch-off create path gains no await * fix(layout): a failed start never writes back a pane the user closed (dark) * fix(layout): a failed start's pane goes through main's create rules, so a closed tab stays closed (dark) * test(layout): D1a's switch-on close tests assert the intent main receives (both builds) * test(layout): the close fixture answers main's command without naming the method * fix(layout): a re-created pane binds as designed; the id-only ratchet reads a shared import (dark) * fix(layout): a pane's start status may sit on a pane still bound to its old terminal (dark) * fix(layout): a pane's start status ends when its pane binds again by any path (dark) * test(layout): same-id restore ends a status; a replayed split brings back a closed pane by design * test(layout): terminal reply fixtures captured from the window-owned build, and main's switch-on proofs * wip(layout): main's terminal surface index feeds the runtime graph (dark) * wip(layout): main's panes stand in for the window's terminal list (dark) * test(layout): the window sends main-listed panes as mount facts (dark) * test(layout): surface proofs use public runtime calls * chore: lint * feat(layout): close by handle closes in main's layout; the close-time relist goes (dark) * feat(layout): main's binding outranks a caller's pane claim on the terminal record (dark) * test(layout): window-list tests stay on the rollback build; switch-on mount-fact cases (dark) * wip(layout): main's terminal index reads E1's shared projection and follows its operation ends (dark) * refactor(layout): the main-surfaces host lives beside the session-tabs readers, keeping the graph file under its line cap (dark) * fix(layout): main's panes skip the window-era membership fence, follow workspace routing, and list a terminal when it registers; window close only hands the graph back (dark) * refactor(runtime): explicit-close PTY stops move unchanged to their own module, for the file's line cap * test(layout): the cold-restore table runs in a layout-owner build too: one push per registration * test(layout): the parked and automation pane tests assert the same window report in both builds (mount facts with the switch on) * chore: one layout-owner switch import after the restack on D1a * feat(layout): main's terminal.list rows carry the host's verdict; a pane with a status is never live (dark) * chore(layout): fit main's surfaces under the lint gates after the D1a restack * feat(layout): every pane status D1a publishes keeps a row from reading live; remote host answers pass through (dark) * feat(layout): a drag-out moves main's own binding and refuses the home copy's last pane; the window's terminal claim is not consulted (L127, dark) * fix(layout): a tab close by a starting pane's handle stops the tab's terminals; a starting pane is never exited on the inventory alone; terminal.list lists every saved pane main owns; the pane claim lookup leaves the output path (dark) * fix(terminal): keep shipped exit and default-tab behaviour with the layout switch on An exited pane closes through the legacy retirement unless the keep rule holds; the default tab's title and color still reach the window and the phone's live tabs. * fix(terminal): one id guard for every pane write; keep panes on an unvouched -1 Main's taken and closed-id guard now runs where every pane write goes, so a runtime create replayed after its tab closed is refused before it spawns. An exit code nothing vouches for keeps the pane, as the window does; a kept pane sends the phone no retirement. Converts the switch-on tests that asserted the deleted window hand-off and title bridge. * fix(terminal): keep the closed-tab guard on every pane write, held-id checks on client commands A paired host starts each pane of a client's tab as a create under the tab's id, so a held tab id is refused only for a client's own layout command. * fix(terminal): a provider-reported -1 keeps the pane, as the window does Only a requested stop or a host-confirmed death closes a pane on a negative exit code. Pins that the closed-tab guard never fires in the shipped build. * chore(terminal): satisfy the exhaustive-switch and test typing checks * test(terminal): give the replay test's live process a cwd * fix(layout): main's index reads routing only for a workspace two partitions hold, the fence reads ownership once, a legacy pane keeps its claim; switch-on tests assert main's answers after a window closes (dark) * refactor(runtime): a worktree stop's terminal collection moves unchanged to its own module, for the file's line cap * fix(layout): main's index routes every workspace as the layout stream does, re-reading routing only on a write or a terminal registration; a worktree stop names every terminal main binds; a starting pane is unverifiable (dark) * feat(layout): every pane status main publishes keeps a row from reading live; a resuming pane is unverifiable like a starting one (dark) --------- Co-authored-by: E2E Test <e2e@test.local>
…ai#31230) * feat(speech): set the OpenAI dictation key on a headless host (orca speech openai-key) Cloud dictation needs an OpenAI key on the host that transcribes, and desktop Settings was the only way to save one. A headless orca serve or managed server had none. speech.openAiKey.{status,set,clear} save it through the host's existing key store and secret sealing; the CLI reads the key from stdin so it never lands in shell history. * fix(cli): name the update when an older server lacks the speech key methods; one key length cap; PowerShell example (Opus review)
…nd WSL hosts (stablyai#31235) * fix(orcad): replace a stale terminal daemon once it drains on Linux and WSL hosts A daemon forked by an older orcad (before stablyai#31135, at umask 077) kept serving new terminals after an upgrade if it was busy at startup, because the runtime stale-bundle recycle was macOS-only. orcad now opts in on every platform; the replacement still waits for exactly zero live sessions and treats an unverifiable count as keep. * test(daemon): pin the restart recycle test to linux; tighten wording
…ad of running on a guessed host (stablyai#31234) * fix(automations): a legacy automation on a twin project refuses instead of running on a guessed host * fix(automations): capture a legacy run target before the dispatch snapshot, only where it keeps the folder * fix(automations): re-read a legacy record after capture even when another run captured it first
…tablyai#30937) * feat(native-chat): Codex chats list and run the skills Codex loaded A Codex chat's skill list now comes from Codex itself (`skills/list`), live while the chat runs and refreshed when Codex says its skills changed, and from a short-lived Codex check while the chat is at rest. Plugin skills keep Codex's `plugin:skill` names, disabled skills drop out, and each skill file is its own row. A skill picked from the list reaches Codex as that exact skill, beside the unchanged `$name` text, on hosts that take it. * test(native-chat): account for Codex's skill list call; send without a trailing argument * fix: align skill probes with chat launches and preserve picked mentions * fix: distinguish skill choices in phone accessibility labels * fix: clear picked skill files when queued text changes * fix(native-chat): refresh resting commands when launch settings change * fix: keep WSL agent refresh on its execution host * fix: preserve skill selection at read and send boundaries * fix: narrow agent identity for selected skill notice * fix: use checked agent predicate for skill notice label * test: retain locale in composer translation mocks
…afterwards (phase 1a) (stablyai#31251) * refactor(editor): make the editor buffer record the source of truth for tab buffer state Writers of the six buffer fields read and write the record, with the OpenFile fields written as a mirror in the same store update. The store middleware no longer copies tab values into the record; it only keeps records keyed by open tabs (seeded from the tab on create, dropped on close) and, in dev and test builds, asserts every mirror field equals its record. Host-mirrored web tabs adopt the host's published values explicitly in the session sync patch. Co-Authored-By: Claude <noreply@anthropic.com> * refactor(editor): check the buffer invariant in e2e builds and tidy the record helpers Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): give session-sync fixtures the now-required editorBuffers Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…ost that returned the item (stablyai#31252) * fix(github): a twin project's PR cards, rows and dialogs act on the host that returned the item * fix(github): key twin rows by host so cache sync keeps each copy; a lone row ignores the stamp
…scan budget (stablyai#31139) (stablyai#31226) All hosts gave every Orca server a 3 s scan, including the managed servers Orca reaches through an SSH tunnel, which now serve every SSH host. A healthy SSH host walking a large home timed out and showed up empty. The saved environment's connectionDependency now picks the 15 s budget for tunnelled servers; direct LAN/Tailscale servers keep 3 s. Reported, with the proposed approach, by @quzard in stablyai#31139.
…laude read them (stablyai#31204) Co-authored-by: Paweł Kotowski <p.kotowski89@gmail.com>
… test-only editor-state guard (stablyai#31250) * refactor(editor): drop isWholeEditorState and the diff-signature re-export; bound superseded restore re-reads - Remove isWholeEditorState; its callers take the real AppState. Tests that mocked partial stores now build full states from createTestStore. - Import getDiskBaselineSignature from shared/disk-baseline-signature directly and delete the re-export from diff-content-signature.ts. - Restored-tab conflict scan: count superseded re-reads toward MAX_VERIFY_ATTEMPTS, so a read slower than the re-verify interval gives up with the conflict banner instead of looping forever. Adds a regression test. Co-Authored-By: Claude <noreply@anthropic.com> * fix(editor): keep the last read at the superseded re-read cap instead of giving up A matching read at the cap cleared nothing and showed a false changed-on-disk banner; it now resolves like any read. Only read failures give up. Co-Authored-By: Claude <noreply@anthropic.com> * fix(editor): back off on superseded restore re-reads instead of capping them A superseded read may predate the newer check, so it never resolves the verification, even at the attempt cap. Overlapping checks now delay the next fresh read (bounded, one timer per tab) and keep verification pending; only failed reads count toward giving up. Co-Authored-By: Claude <noreply@anthropic.com> * test(editor): address the restored tab by its owned id in the overlapping-check tests After stablyai#31196 a server's tab is no longer keyed by its path, so these tests flagged a tab that does not exist and no read was ever issued. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…ading all of them every 30s (stablyai#31253) * perf(worktrees): gate the 30s git-common reconciliation sweep on each entry's dir signature The native-watch reconciliation forced an ungated stat of every leaf of every worktree admin entry each tick (~7 stats/entry). It now uses the entry-dir signature gate plus the two leaves git writes in place (gitdir, logs/HEAD), runs the ungated sweep every 10 ticks (~5 min), and falls back to sweeping every tick if a sweep ever finds a change the dir signature missed. Co-Authored-By: Claude <noreply@anthropic.com> * fix(worktrees): only distrust the reconciliation dir gate on a confirmed, repeated miss Detect a missed change on any entry rescan, including ones the in-place leaf probes trigger, not just full sweeps. Re-stat the admin dir after the leaf rescan so a rename racing the scan isn't counted, ignore transient missing leaves, and require misses on two separate ticks before sweeping every tick. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…eal path in Workspace scope (stablyai#31244) * fix(ai-vault): keep sessions recorded under a symlinked workspace's real path in Workspace scope (stablyai#31139) A workspace registered through a symlink (~/work/api -> /data/src/api, or macOS /var -> /private/var) lost every session whose agent recorded the resolved cwd: scope matching compared strings, and those rows also counted against the out-of-scope depth cap. The host that owns the files (the desktop for local scans, orcad for SSH and server hosts) now resolves each scope path's real path, scans both spellings, and gives matching sessions optional matching-only cwdAliases in the registered spelling. Workspace scope, the depth cap and project attribution read cwd plus aliases; resume still uses the recorded cwd. Older hosts send no aliases and older clients strip the field. Reported, with the proposed approach, by @quzard in stablyai#31139. * fix(ai-vault): rank aliased attribution by closest root; never resolve recorded cwds Review feedback: a longer-spelled parent link could take a nested project's session, and resolving every out-of-scope cwd could stall a listing on a hung network mount or raise macOS privacy prompts.
innocarpe
force-pushed
the
fix-24187-stale-agent-wait
branch
from
October 21, 2026 23:37
606ba0c to
bd3c6eb
Compare
A reused file reader carries a note composer into another document, and a late submission closes the new composer. Give document state and callbacks a keyed lifetime.
…stablyai#31690) A focus read started before Enable can finish afterward and switch notifications back off. Fence reads against permission and preference mutations.
…blyai#31692) Saving an endpoint after the user leaves can pop a second screen. Retire navigation ownership while allowing the endpoint save and client refresh to finish.
* Use one model catalog per execution scope * Accept a missing session record in host scope * Merge duplicate launch-resolution import * Fix catalog typecheck errors * Align catalog tests with the one-list design * Type the integration fixture's send without a cast * Give the discovery test complete runtime dependencies * Fix model catalog completion and scoped configured display * Preserve model catalog authority across released clients * Fix mobile first-frame catalog fixture narrowing * Keep startup catalog persistence with one completion owner * fix: preserve chat selections across CLI model updates A newer CLI can omit a model that an existing chat still runs. Keep that chat's selected model and effort instead of replacing them from the available list. Discover one model list per host, account, launch command and folder, refreshing after two minutes. Keep current values and the running model's exact effort choices with its chat. Show only the known effort when Claude supplies no matching menu. Preserve older paired-client delivery and configured launch arguments. Make Codex use independent discovery and retain the established ACP and Pi paths. Tracked in STA-10947. * fix: keep the Pi options read within its file limit after main's growth Tracked in STA-10947. * fix: import the option snapshot's shared module once Tracked in STA-10947. * fix: keep Grok and Pi model menus and fast controls across restarts Restore the established ACP and Pi catalog route: newer listed models and qualified startup defaults stay visible, and genuine retained effort menus survive later reads. Keep exact-child Fast and Speed controls. Update the phone option contracts and the remaining stale expectations to the selection rules. Tracked in STA-10947. * fix: share each workspace's model list and keep live Grok and Pi menus New chats read their workspace's own model list through the one shared request for that workspace, so a second chat in the same folder starts on the model and effort the agent actually runs there, and a slow first answer can no longer overwrite a newer list. A running Grok, OpenCode or Pi chat keeps its live model menu when an older shared list arrives later. Update the tests that still expected the replaced behavior. Tracked in STA-10947. * fix: keep separate agent and chat model lists for Grok, OpenCode and Pi A brand-new Claude chat now offers the selected model's effort levels before the first message, as it did before. Grok, OpenCode, omp and Pi again keep the list read from the installed agent apart from the list a running chat reports, and each newer list replaces only its own source. So a chat shows the model the agent is actually running with that model's own effort menu, and an effort change can no longer act on an older model's menu. Saved model lists on WSL are readable again without starting the agent. Tracked in STA-10947. * fix: keep desktop catalog storage out of the phone's type graph and show Grok's late model answer The phone app's type check no longer pulls in desktop-only catalog storage. The model-list code no longer reaches the saved-catalog file through a type import. When a Grok model change times out and Grok later confirms the model, the chat shows the model Grok actually runs. Tracked in STA-10947. * Remove unrelated merge formatter and package manager churn * Clarify independent catalog ownership and refresh contracts * Declare picker demand callback as an effect dependency * Complete mobile catalog surface and catalog merge types * Complete catalog contract fixtures for current host types * fix: preserve catalog source contracts and account fallback * test: inject independent Codex discovery transport * test: remove accidental client fixture assertion * test: qualify the saved account fallback read * fix(chat): preserve catalog evidence and current child controls * Fix catalog CI types and mobile option readiness * Reconcile session controls after inventory changes * Fix catalog import and deferred test resolver types * Keep model capability observations separate from picker views * Use installed model choices for chat options * Fix model catalog test fixture contracts * Restore model option compatibility and stable settlement * Return a catalog reply in provisional launch fixture * Compose unreported live model defaults in the host * Preserve explicit replacement model on recovery send * fix(chat): use stable scoped catalogs on local desktop * test(chat): preserve generic catalog runner type * fix: scope catalogs to configured environment and keep saved reads passive * fix: satisfy catalog regression and controller CI checks
…along the address bar on desktop and mobile (stablyai#31597)
…ablyai#31686) * refactor(linear): group issue-context owners and use direct imports * test(linear): mock concrete current-context owner in WSL move suite
…ablyai#31727) stablyai#31656 left BrowserAddressBar.tsx one counted line over max-lines, which fails Lint for every PR. The six copies of clear-a-timeout-ref become one helper.
…over Home (native part ships with the next app build) (stablyai#31305) * fix(mobile): the home screen's New Workspace opens the create sheet again The native host-list route dropped the home screen's action=newWorktree when it built the page's route, so the page opened as a plain list. The route now forwards it, and the page names it back once applied so a reload does not reopen the sheet. Reaches phones only with the next native build. * test(mobile): drop the New Workspace tests that only re-check types and a null guard * fix(mobile): Home's New Workspace opens the create sheet over Home Replaces the action=newWorktree route hand-off. The quick action picks a host (as Tasks does), then mounts the host's create sheet on Home; a create opens the new workspace's session marked as just created. The sheet controller becomes a plain visible/onClose component, and the host screen's route-action state, the action route param and its builder are deleted. * fix(mobile): Home's create sheet seeds only proven worktree rows Home's cold-start seed is a pathless resume row that the name suggester cannot read, so the sheet now seeds from proven rows and is keyed by host. The host screen gets one setter for the sheet's visibility and its ref. * test(mobile): name the Home new-workspace test after the screen it renders * proto(mobile): Home's New Workspace opens a native drawer hosting the page's create form Home pushes /new-workspace/<host>, a react-native-screens formSheet over Home whose content is MobileWebShellScreen for the page route /h/<host>/new-workspace. The page renders the shared Create Workspace form with its drawers inline, so the form and its pickers fill the native drawer. The shell's loading, download and failure states render inside the drawer. Prototype only. * proto(mobile): the New Workspace drawer is the host screen's own sheet over a transparent modal The native route is a transparentModal hosting the shell over Home; the page route renders the host screen's NewWorktreeModal on a transparent page, so the drawer is the same component. While the page loads, the shell shows a placeholder of that sheet (scrim, grabber, spinner or download bar), and the page's sheet opens in place without its slide. A host that cannot serve the page (old desktop, blocked, failed) opens the host list instead of a wall in a drawer. * feat(mobile): Home's New Workspace opens the page's create drawer over a dimmed Home A transparent native overlay route hosts the host picker and then the page's /h/[hostId]/new-workspace route, which renders the same NewWorktreeModal as the host screen's +. The native scrim matches the drawer backdrop and the page's first drawer opens already dimmed, so Home stays dimmed throughout. Old desktops without the route fall back to the host list. * fix(mobile): one loading layer for Home's New Workspace overlay The overlay route owns a single tappable loading layer (spinner, or the download on a small card) that stays mounted from the pick until the page paints, so the fade and spinner no longer restart per shell state. The shell reports its load and shows the host list for anything it cannot open; the picker hands the pick over at once and keeps sliding away. The page's first drawer takes the dimmed backdrop once, and a gate's overlay pending view no longer stacks a second scrim over a mounted stack. Native /h/[hostId]/new-workspace redirects to the overlay. Drops the unused session-route params, the clipboard grant, and pass-through tests. * feat(mobile): New Workspace loads in a short drawer over an undimmed Home While the page loads, the overlay shows one short native drawer in the shared drawer chrome with a spinner or the download, and nothing dims Home: a tap above it, a drag down or Back cancels. The page's real drawer then slides up with its own backdrop exactly as on the host screen's +. Drops the native scrim, the loading card and the already-dimmed backdrop handoff; the overlay's WebView stays invisible until the page paints, since a fresh one draws opaque. * feat(mobile): the New Workspace loading drawer dims Home like any drawer The short loading drawer opens with the shared drawer backdrop and show duration, and a tap on that backdrop, a drag down or Back cancels. It stays in the screen's own window (a native Modal over the loading WebView stalls the page) and goes in the frame the page paints: the shell reports its load from a layout effect so the WebView shows and the drawer leaves together. * fix(mobile): the page's first paint waits for a drawer opening with it A drawer opening as its page screen mounts holds that screen's first-paint report until its open animation ends, through a hold on the existing report rather than a new bridge message. The New Workspace overlay's loading drawer now stays until the create drawer is up, so a cold open no longer shows Home undimmed between the two. * refactor(mobile): the New Workspace overlay owns its exits; the loading drawer fades out The shell no longer imports the feature: an overlay is a shell with onOverlayLoad, which reports `unavailable` for what it cannot show, and the overlay route opens the host list for every exit. HostProtocolGate takes one transparentWhilePending flag. The loading drawer's drag handler follows a stable cancel, and on paint the drawer fades out eased in, as the shell's page cover does, because the WebView takes a frame or two to show the page after it is revealed; removing it outright left Home undimmed for those frames. * Revert "fix(mobile): the page's first paint waits for a drawer opening with it" This reverts commit be0913b. * fix(mobile): Home's host picker leaves when there is no desktop to pick An unreadable host catalog, or offered desktops that are all gone, left the picker invisible inside the transparent overlay, holding a screen over Home with nothing to dismiss it. The catalog read now resolves to no hosts on failure, and an empty pick list goes back to Home. * fix(mobile): Home's create drawer names SSH hosts as the host screen does The page drawer opened from Home passed no host labels, so a project on an SSH host showed its run target by raw host id. Reading the SSH target summaries and display overrides moves into one function that both the host screen's metadata fetch and the page drawer call.
…ablyai#31687) * fix(security): update Node runtimes for October security releases * fix(ci): compare normalized web file inventory without ordering artifacts
innocarpe
force-pushed
the
fix-24187-stale-agent-wait
branch
from
October 22, 2026 00:08
bd3c6eb to
9c7c13b
Compare
…lyai#31702) * fix(mobile): invalidate chat file search on authority migration Modern search caches and late replies survive authority migration on the same client object. Own cache, capability decision and inventory by logical generation. * test(mobile): record retired file-search requests after reset * refactor(browser): simplify address bar callbacks within lint limit * style(browser): keep client-hosted pane within line limit * fix(i18n): retire obsolete Portuguese default zoom entries
* fix(mobile): show commit comparison failures with retry Comparison refusals, transport errors and malformed payloads appear as No file changes. Decode accepted data, preserve loaded files on failed refresh, and offer Retry. * test(mobile): record commit comparison errors and retry affordance * refactor(browser): simplify address bar callbacks within lint limit * style(browser): keep client-hosted pane within line limit * fix(i18n): retire obsolete Portuguese default zoom entries
* Extract image clipboard copying into shared utility * Await image reads before reporting clipboard copy success
Pass the selected repository to New Workspace agent detection through the host-authoritative runtime resolver, including WSL paths and Windows project preferences. Preserve old-client request shape, SSH routing, and strict ownership/refusal behavior. This merge credits @welldoingk’s original WSL agent-detection investigation and community PR stablyai#20101, adapted to the current host-resolved contract. Co-authored-by: welldoingk <thkwon96@gmail.com> Fixes stablyai#20060
…yai#31709) * fix(mobile): own commit generation by workspace and admit once AI commit generation crosses workspace transitions and admits duplicate calls before a render. Retire the active run on scope changes and use synchronous admission. * fix(mobile): retire commit generations only after scope commits
… state (stablyai#31711) Concurrent close replies filter captured terminal arrays and resurrect an already closed terminal. Reconcile the current collection synchronously and respect newer selection and metadata.
…dy prompt A blocked stamp stayed after the dialog left, so a later send to an idle Codex composer was still refused. Clear it only when the tail is a settled ready prompt, and keep it while the tail is empty, inconclusive, or blocked.
…lear The deferred check still clears a leaf that shares the PTY tail, and that path is now tested without another output chunk. A null stamp no longer pays for the ready-prompt scan. Co-authored-by: Cursor <cursoragent@cursor.com>
innocarpe
force-pushed
the
fix-24187-stale-agent-wait
branch
from
October 22, 2026 00:30
9c7c13b to
07d1f42
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upstream: stablyai#24308
ELI5
Orca used an old permission prompt from terminal history even after the live Codex screen was ready. It now checks the current screen when the runtime has a complete, up-to-date screen model.
What Changed
Why
A retained tail can contain a prompt that has already left the visible screen. Clearing the timestamp alone cannot change the send decision because that decision reads the blocked text first. Checking a synchronized current screen fixes that stale refusal while keeping the existing fail-closed tail fallback when the screen cannot be trusted.
Linked Issue
Fixes stablyai#24187
Visual Proof
N/A — no UI layout changes; this changes which terminal screen evidence the send guard reads.
Testing
Ran on macOS:
node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/runtime/orca-runtime-tail-wait-memo.test.ts src/main/runtime/terminal-wait-detection.test.ts src/main/runtime/agent-prompt-submission-runtime.test.tsResult: 3 test files passed, 78 tests passed. This did not include a manual live Codex pane check.
AI Disclosure
Codex (OpenAI GPT-6) assisted with this follow-up.
Review
The send guard and terminal status query now use the same current-screen-first evidence. The screen is trusted only when the headless model's output sequence matches the PTY output sequence; otherwise the existing retained-tail check remains in force.
Agent skill upstream boundary
Notes
The screen reader uses the current whole-screen headless model. Provider-preferred or stale models fall back to the existing tail checks. Cross-platform, SSH, and mobile environments were not exercised locally; CI is still awaiting maintainer approval.
Checklist
pnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (CI is awaiting maintainer approval)