[upstream #10187] feat(automations): host selector for remote environment automations - #42
Closed
innocarpe wants to merge 209 commits into
Closed
[upstream #10187] feat(automations): host selector for remote environment automations#42innocarpe wants to merge 209 commits into
innocarpe wants to merge 209 commits into
Conversation
…p-free (stablyai#9881) Co-authored-by: Orca <help@stably.ai>
…idebar rows (stablyai#9850) * fix(agent-status): keep Claude in-process teammates visible as idle sidebar rows Claude Code 2.1.21x runs named Agent-tool agents as turn-based in-process teammates: SubagentStop and TeammateIdle fire at every TURN end while the teammate stays alive awaiting mail (verified live on 2.1.217). Treating those events as finish signals deleted the child row seconds after each burst, so the sidebar showed no subagents for most of a teammate's life. Root-cause fix: the roster now tracks a working/idle state per child. - One-shot children (hyphen-free ids) keep remove-on-stop: their SubagentStop is a true finish. - Teammate-shaped rows park as idle on SubagentStop/TeammateIdle and revive to working via the next SubagentStart (same lifecycle id, first-observed startedAt preserved). - Idle rows never gate the pane 'working' (stablyai#8825's done-gate rule). - Only TeammateIdle-confirmed idle rows survive a complete lead-Stop fold; a stopped workflow lane wearing a teammate-shaped id is reaped there (or immediately, once a fold tagged it listedAsSubagentTask), so the pre-stablyai#8825 idle pile cannot rebuild. - At the wire cap, the oldest idle row is evicted to admit a working spawn; working children are never displaced. - Hydrate keeps pruning idle snapshots: idle-teammate liveness cannot be proven across a restart, and a live teammate re-earns its row. * fix(agent-status): restore inventory-confirmed workflow lanes
* feat(skills): land remaining hybrid stubs * fix(build): exclude skill stub sources from packages
…gration (stablyai#9798) Opening the Quick Commands sheet right after connecting over relay races the relay->direct cutover, which rejects the in-flight one-shot settings.getTerminalQuickCommands with LogicalClientCutoverError while connState stays 'connected'. The sheet then strands on "RPC interrupted by connection migration" with an empty list until closed and reopened. The read is side-effect-free, so replay it on cutover (capped at 5, cancelled if the sheet closes or the client is replaced). Same failure class and pattern as stablyai#9794 (capability probe) and stablyai#9796 (terminal create).
…rch terms (stablyai#9967) The Language setting's native word (语言 / 언어 / 言語 / Idioma) only reached settings search via the localized title in that word's own UI locale — so a Chinese speaker on the default English UI could not find it by typing 语言. Always-index the native word for 'language' in every supported language (plus the previously-omitted Spanish native name Español), so speakers can locate and switch to their language from any starting locale. Native words are locale-invariant constants, so they are plain keyword literals with reviewed localization-coverage allowlist entries. Co-authored-by: Orca <help@stably.ai>
stablyai#9861) * fix(agent-status): map codex request_user_input questions to waiting Codex 0.145 asks user questions via the auto-allowed request_user_input tool (experimental default_mode_request_user_input): PreToolUse fires while blocked on the answer with no Stop, so Orca showed the pane as working/idle instead of Needs You. Map that PreToolUse to waiting (mirrors grok's ask_user_question), exempt question waits from the codex yolo auto-approval suppressor, and deliver native-chat answers to the digit-commit selector by option number (typed labels are ignored and Enter commits the highlighted first option). Older codex versions emit no such event and are unchanged. * fix(native-chat): preserve codex question answer semantics
…n mobile (stablyai#9801) * fix(mobile): persist per-device tab selection so worktree return restores the last open tab A phone's tab selection lived only in the host's in-memory ClientSessionTabSelectionStore. Any host restart wiped it, and the per-device projection then fell back to deterministic topology, so returning to a worktree on mobile always landed on the first tab instead of the tab last opened on the phone. Persist the per-device selections in the Store (keyed deviceId -> worktreeId), hydrate them when the runtime constructs, and guard projection so an early empty snapshot after restart cannot wipe a hydrated selection before tabs arrive. Selections are pruned with the worktree/repo and on device revoke, and malformed persisted payloads degrade to empty instead of throwing. * fix(mobile): harden persisted tab selection cleanup * fix(mobile): preserve tab selection across worktree rename
…ed (stablyai#9780) * feat(mobile): mount ProtocolBlockScreen when protocol compat is blocked ProtocolBlockScreen existed since PR stablyai#1440 but was never mounted: on a 'blocked' compat verdict the only output was a console.warn, so a future MIN_COMPATIBLE_RUNTIME_CLIENT_VERSION bump would have silently shown a broken host UI instead of the update screen. Add HostProtocolGate — a choke point in app/h/_layout.tsx above every /h/[hostId] route — that consumes useHostStatusGates and replaces the blocked host's entire UI (sidebar + detail stack) with ProtocolBlockScreen. The host list and other hosts stay usable; the screen's own 'Back to hosts' escape hatch routes to '/'. Both block reasons render their respective CTAs (mobile-too-old → App Store, desktop-too-old → GitHub Releases). Compat logic stays in the src/shared mirror contract — no fork. * fix(mobile): fence incompatible host routes efficiently * fix(mobile): route Android updates to releases
* feat(source-control): show current branch in header * fix(source-control): keep header focused on branch * fix(source-control): compact detached head identity * fix(source-control): make branch identity keyboard accessible * fix(source-control): keep create review in checks
…erer OOM (stablyai#9872) (stablyai#9936) The live `agentStatusByPaneKey` map had no size cap. `setAgentStatus` rewrites it with a full spread copy on every status ping and keeps rows until a pane/tab teardown event removes them; a missed teardown (agent killed without a Stop hook, pane/tab closed while its status lingered) orphans a row forever. On long multi-agent sessions orphaned heavy rows accumulate without bound, and because each ping spread-copies the whole map, once it is ~1.9 GB one ping transiently doubles it past the 3586 MB old-space limit -> renderer crash (exit -36861). Cap the live map at MAX_LIVE_AGENT_STATUSES=500, shedding only rows whose pane is provably gone (a mounted tab's rooted layout no longer lists the leaf) or long idle, and never an open pane's row (any state, incl. needs-input waiting/blocked). Rootless/empty-snapshot, not-yet-hydrated, and no-renderer-tab (orchestration worker) rows are unprovable: kept while a fresh agent could own them, shed only past the stale window or by a hard-cap fallback that guarantees the bound. Eviction bumps the status/sort epochs so the retention sync snapshots disappeared done rows. Cost is one Object.keys length check on the reducer's already-O(n) spread under the cap; the layout walk + sweeps run only on the rare over-cap ping. Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ablyai#9782) * feat(mobile-pairing): surface unpaired-device auth failures instead of silent 4001 loops Desktop: when a phone repeatedly fails direct-transport E2EE auth with a token missing from the device registry (pre-v1.4.106 pairing-path bug left desktops that regenerated their registry rejecting paired phones forever), throttle to one notification per session and show an actionable toast pointing at Settings -> Mobile to re-pair. Mobile: map a bare 4001 close onto the existing auth retry budget (the encrypted e2ee_error is undecryptable when the desktop keypair changed, so the close code is the only surviving signal) instead of looping the generic reconnect forever, and make the auth-failed verdict say 'Pairing invalid - re-pair with your desktop' instead of a bare 'Auth failed'. * fix(mobile-pairing): handle stale keys and startup notification races * fix(mobile-pairing): isolate auth notification failures * fix(mobile-pairing): keep recovery alert actionable
* perf(mobile): gate host polling on foreground The mobile host screen ran two 3s polls (routed + embedded), each firing worktree.ps AND repo.list, with no foreground/background gate — so a connected phone kept pinging every 3s (worktree.ps is a full multi-repo process scan) plus a radio wakeup, including brief background windows while the socket stays parked. Consolidate both into one startHostWorktreeRefresh lifecycle and AppState-gate the interval so BOTH polls stop while backgrounded and refresh immediately on foreground return. worktree.ps keeps its 3s cadence while foregrounded (it carries live agent status/preview/unread that no push event replaces). repo.list stays on the interval as an AppState-gated, self-throttling (REPO_METADATA_REFRESH_MS=60s) convergence safety-net — desktop Settings repo edits notify only the renderer, not the runtime clientEvents stream, so it can't be made purely event-driven without going stale — and additionally gets a reposChanged/worktreesChanged fast-path and reconnect-replay refetch. Verified in a deps-installed mobile checkout: full mobile suite 2232 pass, typecheck, oxlint (within the frozen max-lines budget), and oxfmt --check all clean. Co-authored-by: Orca <help@stably.ai> * chore(mobile): drop stale fetchRepoMetadata dep from the reconnect effect Address CodeRabbit nitpick: the reconnect effect no longer calls fetchRepoMetadata (that refetch moved into startHostWorktreeRefresh), so it shouldn't remain in the effect's dependency array. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
stablyai#9979) * fix(mobile): keep quick-commands button steady while capabilities load The tab-row quick-commands button only rendered once the capability probe resolved true, so it popped in after the row was already visible (and vanished during reconnect re-probes). Render it whenever support is not confirmed absent and disable it until the probe settles — pre-quick-commands hosts strip agentPrompt, so the action (not the button) must wait for confirmation. Confirmed-unsupported hosts still hide it entirely. * fix(mobile): explain unsupported quick commands on tap instead of hiding Per feedback on the disabled/hidden states: the button now always renders and stays tappable. Tapping against a desktop that confirmed no support shows "Desktop update required for quick commands" (mirroring the browser streaming copy); tapping while the capability probe is still resolving says to try again in a moment. The sheet still opens only once support is confirmed, since pre-quick-commands hosts strip agentPrompt. * docs(pr): add QA screenshots for quick-commands button states * test(mobile): lock quick-commands button stability Add a focused source-contract test for the always-mounted tab action and confirmed-support sheet gate. Keep the non-obvious safety comment concise, and remove PR screenshots now hosted as GitHub user attachments. * test(mobile): structurally guard quick-command action mount
…9843) react-markdown's <Markdown> has no internal memoization: it rebuilds the whole unified remark->rehype->highlight->katex processor and re-parses the document on every render. MarkdownPreview re-renders on internal state that does not affect the rendered output — most visibly, every keystroke in Find (query/match-index state) — so a large doc re-ran the full parse + syntax-highlight + KaTeX pass per keypress, making Find laggy. Hoist the two fully-static plugin arrays to module scope (a fresh array identity per render would defeat the memo) and render the body through a React.memo'd MarkdownBody keyed on content + components. The pipeline now re-runs only when the rendered content or the components map actually changes; Find/review-pulse/copied- note re-renders skip it. The components map was already memoized, so its identity is stable across those re-renders. Behavior unchanged: 106 existing MarkdownPreview tests pass. Co-authored-by: Orca <help@stably.ai>
…i#9842) The iOS MJPEG and Android scrcpy device streams are gated only on the pane being the active tab (isActive, PR stablyai#7382). When the emulator tab is frontmost but the whole Orca window is hidden/minimized/occluded/display-asleep, the full-fps pipeline keeps running: main-process socket read + JPEG/H.264 decode + IPC + renderer decode. Renderer background-throttling (stablyai#9395) cannot stop it because the pipeline is IPC-push driven from main. Gate showStream additionally on window visibility via a new occlusion-safe hook that honors the terminal stale-visibility latch (so a display-sleep occlusion wedge can't freeze the emulator on a black frame) and delays the visible->hidden park by 500ms so a quick Cmd+Tab round-trip doesn't renegotiate the device stream. Co-authored-by: Orca <help@stably.ai>
…#9995) Zone.js patches the global Promise with a non-native thenable. When a bare `new Promise(...)` crosses the Electron executeJavaScript boundary, it's serialized as-is, losing { page, target } and exposing __zone_symbol__* fields instead. Wrap in an async IIFE to return a native promise that Electron always unwraps correctly.
…blyai#9985) Production crash diagnostics measured ~128 `git worktree list` execs/min (9,400 in one 80-minute session, ~16% of wall-clock in git subprocesses): the resolved-worktree scan fans out over every registered repo on a 30s cache TTL, and most registered repos on the affected installs were agent-CLI scratch repos (~/.codex-tmp capsules, vendor imports, skill checkouts) that need no freshness. Classify agent-scratch repo roots with a curated shared matcher and stamp their scan-cache entries with a 5-minute TTL instead of 30s. Orca-driven mutations still bypass the TTL via the per-repo generation bump, so only passive pickup of external changes slows for scratch repos. Expected steady-state reduction on the measured install: ~82% fewer git spawns.
…7936) (stablyai#9826) * fix(daemon): retire macOS daemons whose login session died (stablyai#7936) A daemon that survives a full macOS logout is unsalvageable: its PAM context can no longer host login(1) spawns (every new PTY becomes a 'Login incorrect' prompt zombie) and its Mach bootstrap namespace has lost the system DNS resolver, so terminals it hosts have no egress. Today it also keeps the stablyai#9301 preflight's cached 'accepted' verdict, so it keeps wrapping spawns in login(1) forever; only a manual daemon restart recovers. GUI-spawned daemons now watch for login-session death from the inside: a fresh cache-bypassing PAM probe (triggered by PTY-exit bursts, fresh client hellos, and a slow periodic timer) must conclusively reject three consecutive times AND the in-process system resolver must be degraded; then the daemon exits crash-style so session meta stays unclean and the replacement daemon cold-restores scrollback. A conclusive rejection also flips the spawn-wrapper cache off immediately. Headless serve/SSH daemons never get the watch (they must survive their spawning session ending), and a session that never conclusively accepted login(1) never arms it — a PAM anomaly alone can't kill a healthy daemon (fast user switching keeps accepting, so switched-away sessions are preserved). * test(daemon): e2e seam to drive login-session death oracles from a verdict file A dead macOS login session cannot be fabricated without root (PAM owns audit-session teardown), so live lifecycle QA drives the death watch's probe and resolver oracles from ORCA_E2E_LOGIN_SESSION_PROBE_FILE: 'alive' → accepted/healthy, 'dead' → rejected/unhealthy, anything else inconclusive — with compressed watch timing. Mirrors the existing ORCA_E2E_DAEMON_INIT_DELAY_MS seam; inert unless the env var is set. * fix(daemon): close the hang-shaped gap in login-session death detection The conclusive-PAM-verdict trigger had one blind failure shape: login(1) hanging at the prompt past the probe bound (killed → inconclusive forever → the watch never fires). Three changes close it: - The death-watch probe gets its own 4s bound (the 500ms preflight bound exists for spawn-path latency, which doesn't apply off-path), so a slow-but-answering PAM stack isn't misread as a hang. - An inconclusive pipe probe escalates to a PTY-hosted probe via script(1) — a dead session's PAM stack may only misbehave under a real tty (the pipe-vs-PTY fidelity limit the preflight documents). - A streak of timeout-killed probes (which a live session never produces) is a second retirement trigger, at a higher threshold (5) and still gated on the degraded resolver, logged with a distinct cause so field logs discriminate the two paths. Every dead-session behavior — fast reject, prompt-then-EOF, or hang — now fires retirement; all inconclusive states still fail toward preserving the daemon. * fix(daemon): keep login-session retirement conclusive * fix(daemon): stop login watch before clean shutdown * fix(daemon): make login-session PTY probe reliable * fix(daemon): close login-session watch races * fix(daemon): ignore health probes for login watch activity
…ai#9980) * test(e2e): verify Claude is prefilled with issue URL on start Regression test for stablyai#6613: when starting a workspace from a newly created GitHub issue, ensure the issue URL is passed to Claude via `--prefill` and `--dangerously-skip-permissions` flags. This prevents context loss after issue creation. * test(e2e): fix GitHub-issue-start prefill test flakiness - Reorder mock API handlers to ensure `/labels` and `/assignees` paths match before the specific issue endpoint - Replace regex heading matcher with exact string for more reliable assertions - Refactor terminal content polling to capture text once and reuse in subsequent assertions
* fix(terminal): defer remote output ACKs until parse * test(terminal): document synchronous credit claims --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…-name field mid-composition (stablyai#9517) RepoSettingsDraftInput holds unconfirmed IME text in local draft state and only persists on compositionend (so the async store echo cannot cancel the composition). If the user types a Hangul syllable and immediately navigates back out of project settings while it is still composing, no compositionend fires — the last syllable stays in the draft and never reaches the store, so the project's display name loses its final character. Users have to click back into the field or press Enter (both force compositionend) to make it stick. Flush the visible draft on blur and on unmount, guarded by lastPersistedRef so it is a no-op when a keystroke or compositionend already persisted that value. The flush closure is published from an effect (post-commit) so a discarded concurrent render cannot leave the cleanup pointing at uncommitted draft state. Adds blur / unmount / no-double-persist / no-op regression tests to the component's existing suite. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
…tablyai#9900) * fix(terminal): make Ctrl+V paste work in the HTTP web client navigator.clipboard only exists in secure contexts, so the web client served over plain HTTP (e.g. a LAN address) read an empty clipboard and Ctrl+V silently did nothing: the keydown handler preventDefault-ed the chord and suppressed the native paste event whose clipboardData is the only clipboard access available there. When the async clipboard reader is unavailable in the web client, let the chord's native paste event fire and feed its clipboardData text through the existing paste pipeline (size limits, bracketed-paste handling and error toasts included). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RTjQWLg4wy1CgmcZKmGAuN * fix: address review finding (bug-bash takeover) Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> Co-authored-by: Orca <help@stably.ai>
…yai#9922) `git sparse-checkout disable` restores the full working tree and sets core.sparseCheckout=false, but deliberately leaves <gitdir>/info/sparse-checkout in place so the checkout can be re-enabled with the same patterns. detectSparseCheckout treated the mere presence of that pattern file as "sparse", so a fully-populated worktree kept showing the sparse badge and the misleading "Partial checkout. Files outside these paths are not on disk." tooltip. Gate the fast-path fs.stat behind a config read that confirms core.sparseCheckout is actually enabled (shared repo config or per-worktree config.worktree, honoring git's precedence). The config read runs only when a non-empty pattern file exists, so it does not reintroduce the per-poll subprocess fan-out PR stablyai#1290 removed, and it reads git's config files directly (no subprocess). Adds a real-git regression test (enable -> disable leaves file -> not sparse) and unit tests for the git-config boolean parser.
…locales (stablyai#9935) The theme picker count row concatenates "Showing {count}" directly with the " of {{value0}}" fragment. The ko/ja/zh translations dropped the fragment's leading separator, so the shown and total counts fused (e.g. Korean rendered "표시 중 3030 중" instead of "표시 중 30/30"). Restore a slash separator for the total-count fragment and the leading space for the search-match fragment in ko/ja/zh, in both the runtime catalogs and the key-override sources so catalog regeneration keeps the repaired values. Add a regression test covering both fragments. 🤖 Generated with Claude Code
…ry (stablyai#10090) During scrollToIndex/reveal, rangeStartIndex can advance before TanStack mounts the candidate Project row. Returning that unmounted index made a Project sticky paint over the Host card in multi-host views. Prefer a previous mounted sticky (or none for the group tier) until geometry exists. Closes stablyai#10088
* fix(win): taskkill agent PTY descendant trees on stop Windows agent teardown previously degraded to shell-only kill because descendant snapshot is POSIX-only. Orphaned claude/codex/MCP children kept worktree cwd handles open and blocked worktree remove. Use taskkill /T /F on the PTY root in killWithDescendantSweep (daemon + local agent shutdown) so the ConPTY tree is cleared before teardown. Fixes stablyai#10004 * fix(win): bound taskkill with timeout and windowsHide Prevent a wedged taskkill from delaying killRoot, and hide the console flash during agent PTY tree teardown (CodeRabbit on stablyai#10100).
…lyai#10073) The claude/codex/openCode usage store slices read `scanState.enabled` directly off `window.api.<provider>Usage.getScanState()`. In the web client that usage IPC is not bridged, so the preload fallback proxy resolves those calls to `undefined`, and enabling usage tracking from Settings -> Stats & Usage throws `TypeError: Cannot read properties of undefined (reading 'enabled')` (reproduced live against `orca serve` v1.4.150; present on main too). Guard the getScanState()/setEnabled() seams in all three slices so an absent scan state degrades to a graceful no-op instead of crashing. Desktop behavior is unchanged (a real ScanState is always truthy). Adds a regression test that stubs the web-client fallback (every call -> undefined) and asserts fetch*/enable* no-op without throwing for all three providers. Co-authored-by: ECO2G Migration <cmeia.ai02@cmeia.co.kr>
…gent (stablyai#8469) The New Workspace flow built a bare launch command client-side and sent it as `startupCommand`, so the host ran it verbatim and never applied the default launch args. The first Claude session therefore started in manual mode, while opening another Claude via the "+" tab (which sends the agent id and lets the host resolve args) started with `--dangerously-skip-permissions`. Send `startupAgent` from every client-built create path (blank, reuse-branch, and new-branch) so the host resolves the launch command, args, env, and host-shell quoting through the same path the "+" new-tab and CLI use. The work-item path already delegated via `startupDraft`. Custom `agentDefaultArgs` are now honored on all paths. Adds a shared `agentLaunchCreateFields` helper and removes the now-unused client-side command map, which had also drifted from the canonical launch commands for continue, hermes, command-code, kiro, and mistral-vibe. Claude-Session: https://claude.ai/code/session_014iufZnQwPD2obYuvdahjaE Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
…lyai#10035) createPtySubprocess asserted assertSafeAgentStartupCwd on the raw opts.cwd before applying opts.cwd || getDefaultCwd(). An omitted cwd was treated as root-like and threw even though the post-fallback home default is safe — while LocalPtyProvider already gates the effective cwd after fallback. Compute requestedCwd first, then gate. Update the daemon unit test to assert omitted-cwd agent launch uses the safe default (stablyai#9578).
…t clipped (stablyai#10056) * fix(window): reflow on macOS occlusion-reveal so the bottom bar is not clipped Fixes STA-2383. On macOS the window is background-throttled while hidden; on occlusion-uncover only 'focus' fires and its handler runs webContents.invalidate() (the setSize jiggle is skipped to avoid SIGWINCH-ing terminals). invalidate() repaints but does not reflow, so the app-shell h-dvh root keeps a stale dynamic-viewport height and the StatusBar is clipped below the viewport ('no bottom bar'); a manual resize restores it. Fix: renderer relays a genuine hidden->visible reveal (visibilitychange) to main via new ui.notifyWindowRevealed IPC; main runs the same proven forceRepaint. Occlusion-gated (no per-Cmd+Tab SIGWINCH regression), darwin-scoped, sender-guarded, cleaned up on close. Test plan: vitest createMainWindow + web-preload-api green. Recommend on-device macOS occlusion QA before merge. * fix(window): preserve user resizes during reveal repaint
stablyai#10057) * test(session): guard against workspace-reopen tab fork-bomb (STA-1111) Relates to STA-1111 (already fixed on main by stablyai#6945). The runaway-tab-on-reopen bug was fixed by stablyai#6945 (activeOrQueuedResumeClaimsProviderSession dedup guard) hours before the ticket was filed. Verified: disabling that guard makes tab count climb 1->2->3->4 across reopens; restoring it holds at 1. This adds a revert-sensitive regression test covering the created-agent and sleeping-resume reopen paths so it cannot regress. Test plan: 2 new tests pass; fail if the stablyai#6945 guard is removed. * test(session): isolate automatic resume replay coverage * test(session): assert resumed tab identity stays stable
…ablyai#10334) Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
* Normalize branch prefixes and flag invalid ones in settings A custom branch prefix ending in a slash (e.g. "team/") produced a double-slashed branch name like "team//feature" that git rejects, and the raw check-ref-format error gave no hint that the prefix caused it. - Normalize the configured prefix (trim whitespace, strip leading/ trailing and duplicate slashes) in the shared branch-name builder so the common trailing-slash case just works, for local and SSH worktrees. - Validate the prefix on the worktree-create path (computeValidatedBranchName) so a genuinely invalid prefix fails fast with a clear "update it in Settings -> Git" message instead of an opaque git error. - Add a live BranchPrefixFeedback under the Branch Prefix setting: previews the resulting branch name, warns on invalid characters, and notes when a prefix collapses to none. - Keep the background first-work rename on the non-throwing builder since the prefix is already validated at create time. * Keep caret in place when editing the branch prefix The custom branch prefix input was directly controlled by settings, but updateSettings persists through an async IPC round-trip, so the value updated a tick late and React re-assigned it, snapping the caret to the end on mid-string edits. Drive the input from a local draft and only adopt genuine external settings changes so the caret stays put (and fast typing survives slow SSH round-trips). Co-authored-by: Cursor <cursoragent@cursor.com> * Return ReactNode from BranchPrefixFeedback JSX.Element needlessly excludes null/string/number returns; ReactNode keeps the component's return type from over-constraining future changes. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(terminal): reveal Markdown links at target lines * fix(terminal): scope line reveals to opened tabs --------- Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
…tablyai#10325) An image send whose text+Enter RPC ended 'unknown' (ack loss / path cutover) collapsed to accepted=true, so the terminal was never marked stale. When the Enter truly never landed, the already-pasted image path sat on the input line and glued onto the next plain-text message. Propagate the send outcome through handleNativeChatSendWithOutcome and mark the terminal input stale on any non-accepted outcome; the next send heals with Ctrl+U (a no-op when the message did land). Chips still clear on 'unknown' to avoid a double-send on retry.
innocarpe
force-pushed
the
fix/automations-environment-selector
branch
2 times, most recently
from
July 24, 2026 08:42
981653f to
01d36b3
Compare
…ablyai#10351) Move link-tooltip chrome into terminal.css so offsets cannot drift via inline styles, and square the bottom-left corner so the hover preview sits flush against the pane edge (Ghostty-style).
The Automations page listed only through the global active runtime focus, so connected remote environments with automations stayed invisible. Add a Local + connected-runtime selector on the page and prefer that selection when listing, without changing the global active runtime. Closes stablyai#9964
Bare "environment:" must not override the global list fallback. Fall through to getAutomationListTarget instead. Addresses CodeRabbit review on stablyai#10187.
innocarpe
force-pushed
the
fix/automations-environment-selector
branch
from
July 24, 2026 08:59
394765e to
5ce2c7e
Compare
2 tasks
Owner
Author
Sync update (
|
CodeRabbit: temporary pending navigation overwrote the explicit host choice.
Owner
Author
|
Upstream stablyai#10187 closed without merge — closing portfolio mirror. |
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
Summary
Summary - Add a host selector on the Automations page (Local + each connected runtime environment). - Prefer the page’s explicit host when listing automations/runs, so remote automations are visible without changing the global active runtime. - Pending run navigation stil
Note
innocarpe/orcamainuntil the upstream PR is merged.