Repository navigation
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>
…tablyai#10000) The workspace-options filter row used the Workflow icon while the Automations nav item and page use CalendarClock. Match them so the filter clearly maps to automation-created workspaces.
… a remote runtime is active (stablyai#6628) * fix(worktrees): refresh local worktrees in the sidebar while a remote runtime is active When a remote runtime is active, a local `worktrees:changed` event for an unbound repo was dropped by the renderer guard in useIpcEvents. Worktrees created outside Orca for that repo (e.g. `orca worktree create` from a CLI or automation flow) therefore stayed invisible in the sidebar until an app restart, even though their sessions were already running. The guard existed because an unbound repo's list fetch routes to the active runtime (settingsForKnownRepoOwner's unbound fall-through), so refreshing with local worktree ids could query — and purge against — the remote host. Instead of dropping the event, pin the refresh to the local host (forceLocalOwner): fetch the worktree list against the local owner and merge additively. The merge is host-scoped and the deletion-purge is skipped on this path, so it only ever adds local-host worktrees and never overwrites the active runtime's worktree state. A genuinely-removed local worktree is reclaimed by the next unguarded full refresh. * test(e2e): regression — CLI-created worktree visible while a remote runtime is active Drives the real `orca worktree create` path: the CLI RuntimeClient calls `worktree.create` over the app's socket, registering a managed worktree and firing the `worktrees:changed` IPC the renderer listens for. Stages a remote runtime as active by injecting `activeRuntimeEnvironmentId` into the renderer store, so no real remote host is needed. Fails on the prior behavior (the worktree never appears while a runtime is active) and passes with this fix. * fix(worktrees): pin local lineage refresh during runtime activity Co-authored-by: Orca <help@stably.ai> * review: trim comments to house style, normalize queue coalescing to booleans * review: sweep rename-grace expiry before early returns in worktrees:changed handler * review: document accepted workspace-space gap, drop imprecise 'additive' wording * fix(worktrees): route duplicate local repo events locally * fix(worktrees): tag local worktree events at origin, gate purge skip on runtime overlap * test: pin origin-based forceLocalOwner with a no-runtime local event assertion --------- Co-authored-by: brennanb2025 <brennankbenson@gmail.com> Co-authored-by: Orca <help@stably.ai> Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
…tablyai#9996) * feat(agent-status): show question glyph for needs-you state everywhere Replace the amber attention dot with the dashboard's MessageCircleQuestion chat glyph for the waiting/permission "needs you" state across all surfaces: the agent dashboard cards, in-app dashboard rows, the sidebar's Agent Dashboard quick-indicator counts, the worktree-level status dot, and the shared agent-row/terminal-tab indicators. On the dashboard card the header glyph is suppressed when a question summary pill is present so "needs you" reads once, not twice. * test(agent-status): assert amber question glyph, not amber dot The needs-you unification replaced the amber dot with the amber MessageCircleQuestion glyph, so update the remaining state assertions in DashboardAgentRow, WorktreeCardStatusSlot, and TerminalTabLeadingIcon to match (lucide-message-circle-question + text-amber-500). * test(agent-status): cover needs-you glyph surfaces
…ablyai#9883) * perf(web): pause runtime heartbeat while hidden Co-authored-by: Orca <help@stably.ai> * fix(web): preserve inbound-liveness baseline across a hidden heartbeat re-arm The visible re-arm rebaselined lastInboundFrameAt=now, so a socket that went silent while the window was hidden looked freshly-heard-from and its death was masked for another full idle window (~25s). Move the fresh-connect baseline into startHeartbeat (the real 'we just connected' moment) and have the visible re-arm only reset the tick clock + clear an in-flight probe, preserving lastInboundFrameAt so the next visible tick probes a stale connection promptly and closes if unanswered. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
…nected (stablyai#9885) * perf(runtime): idle websocket heartbeat without clients Co-authored-by: Orca <help@stably.ai> * fix(runtime): probe immediately when the WS heartbeat arms Arming the heartbeat on the first accepted connection started a fresh interval, so the first liveness ping was a full interval (~15s) out — a socket that died right after connecting went unprobed for that window. Run one sweep synchronously in start() so the first ping goes out at arm time; the seeded socket is pinged (never reaped on the arm sweep) and reaped on the next tick only if it never pongs. Tests updated for the earlier first probe. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
…blyai#9888) * perf(mobile): coalesce overlapping home requests Co-authored-by: Orca <help@stably.ai> * fix(mobile): queue a trailing follow-up for triggers during an in-flight read Single-flight returned the in-flight promise to any trigger that arrived mid-read, so a distinct refresh requested while a slow read was on the wire was silently answered by the older response and never re-read the latest state (UI could stay one refresh cycle stale). Coalesce mid-flight triggers into exactly one trailing follow-up (latest params win) whose fresh result is delivered to those callers. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
…ingle-flight (stablyai#9892) * fix(mobile): gate dictation setup polling Co-authored-by: Orca <help@stably.ai> * fix(mobile): fence a stale dictation refresh against a newer setPolling intent An in-flight setup read resolving 'keep polling' after an explicit setPolling(false) wrote polling=true and rescheduled, resurrecting a poll the caller had just stopped. Snapshot a pollingRevision when each read starts and only apply its result if no explicit setPolling superseded it mid-flight — so a late true can't restart a stopped poll (nor a late false cancel a restart). Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
…ablyai#10007) * Enable accessibility tree (`ax`) command on iOS emulator sessions Fetch the accessibility tree from serve-sim's /ax endpoint, which requires an active session but provides the same UI snapshot capability as Android's uiautomator output. Derive the endpoint from the stream URL when not explicitly provided by the helper, and route through the bridge to pass session context to the backend. * Add ax command routing and backend integration tests Tests verify accessibility tree routes through EmulatorBridge, Android backend ignores iOS-specific ax URLs, and ax endpoints are derived from serve-sim stream URLs.
…rant lane (stablyai#10001) * feat(telemetry): classify codex trust-grant fallbacks and attribute grant lane * fix(telemetry): tighten codex trust-grant classification
Allow the existing "Open in" entries to launch a configured VS Code
launcher against an SSH-backed worktree via Remote-SSH:
code --remote ssh-remote+<authority> <remote-path>
- Split the blanket SSH/runtime block into a capability model: file
managers and non-VS Code launchers stay local-only (disabled with
"Local only" metadata); a recognized VS Code command is enabled and
forwarded with connectionId over a typed object IPC.
- Main process stays authoritative: rejects active/owned runtimes,
resolves the SshTarget from the persisted Store, derives the authority
(config alias, or username@host on port 22, or ssh-alias-required on a
non-default port), validates POSIX/Windows absolute remote paths without
local stat/normalize, and rejects non-VS Code and compound commands
before spawn.
- Authority and remote path are passed as separate argv; getSpawnArgsForWindows
remains the cmd/bat shim boundary and fails closed on metacharacters.
- Same capability rules across the worktree menu, Explorer overflow, and
the source-control entry context menu.
Refs STA-2386
Closes stablyai#9999
…ar (stablyai#8047) * fix(rate-limits): use session cookies for OpenCode Go * fix(rate-limits): harden OpenCode session setup --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: OrcaWin <alpha-eng@stably.ai>
…ablyai#9475) * fix(codex): promote [tui] settings so they survive the managed-home remirror Codex TUI preferences (/statusline, theme, terminal title) are written into the [tui] table of the managed runtime config.toml, but the write-back promotion allowlist only covered four top-level scalars — so the next mirror pass rewrote the runtime config from ~/.codex and silently discarded them. Extend promotion to the [tui] keys the Codex TUI persists (status_line, status_line_use_colors, terminal_title, theme), keyed as structured tui.* paths so the same three-way merge (runtime vs baseline vs ~/.codex) applies: in-Codex changes promote into ~/.codex before the mirror, and outside edits to ~/.codex still win over stale runtime values. The byte-preserving upsert moves to codex-config-settings-upsert.ts (max-lines) and learns [tui] placement: replace an existing bare or dotted key in place, insert into the first [tui] body, insert dotted beside existing dotted tui.* keys, or create one [tui] table at EOF — never defining tui twice, including when the system config holds an inline tui = {...} table. * Add codex-config-settings-upsert to the CLI tsconfig file list * fix(codex): keep tui upserts out of array tables * fix(codex): handle quoted tui config paths during promotion * fix(codex): harden tui promotion writes
… c5d87873) (stablyai#10024) Co-authored-by: Orca <help@stably.ai>
Coalesce identical and sub-pixel fallback overlay measurements so ResizeObserver and xterm fit cannot sustain a render feedback loop, while preserving precise committed geometry. Adds regression coverage for stable measurements, sub-pixel jitter across integer boundaries, and genuine resizes.
…s 7f93d89c, 362b566d) (stablyai#10028)
…+ add glibc/libstdc++ packaging gate (stablyai#9902) (stablyai#10019) * fix(linux): restore Ubuntu 20.04 launch by pinning node-pty glibc symbols (stablyai#9902) The bundled node-pty pty.node is compiled from source in release CI on ubuntu-latest (glibc 2.39). glibc's 2.32-2.34 libpthread/libutil merge relocated openpty/forkpty (GLIBC_2.34) and pthread_sigmask (GLIBC_2.32) into libc under new symbol versions, so the from-source build bound to versions absent on Ubuntu 20.04 (glibc 2.31). The main process imports node-pty at startup, so the app crashed on launch. pty.node is the sole blocker (Electron needs GLIBC_2.25; other native modules <= 2.17). - Patch node-pty: a .symver shim pins the 3 symbols to their pre-merge version (GLIBC_2.2.5 x64 / GLIBC_2.17 arm64), and Linux-only ldflags force libutil.so.1/libpthread.so.0 back into DT_NEEDED. Guarded to Linux; macOS/Windows untouched. - Add a packaging gate (verify-linux-glibc-floor.cjs, afterPack): reads each bundled native binary's objdump -p version needs and fails the Linux build if any strong GLIBC_/GLIBCXX_/CXXABI_ node exceeds stock Ubuntu 20.04 (glibc 2.31 / GLIBCXX_3.4.28 / CXXABI_1.3.12). Catches GLIBC_ABI_DT_RELR, rejects GLIBC_PRIVATE, skips weak needs, fail-closed. - Docs + tests; the lazy sherpa-onnx speech prebuilt (GLIBCXX_3.4.29, never loaded at launch) is a documented libstdc++-floor exemption. * fix(linux): assert DT_NEEDED provider deps in the glibc-floor gate Harden the packaging gate (flagged in adversarial re-eval): the version-floor check alone can false-pass if the patch's forced `-l:libutil.so.1` ever silently drops — the pinned openpty@GLIBC_2.2.5 still resolves from libc's compat alias at build time, but fails to load on Ubuntu 20.04 where openpty/forkpty live only in libutil. The gate now also asserts that any binary importing openpty/forkpty keeps libutil.so.1 in DT_NEEDED. Validated on a real symver-pinned .so with libutil dropped (now fails) vs. present (passes). Documents the recommended real-host smoke-test follow-up.
Update desktop experimental settings, mobile settings/onboarding, i18n (en/zh/ja/ko/es), and user-visible error strings. Keep internal APIs and identifiers as nativeChat.
Anchor: GH PR was mistranslated as 生长激素受体 (growth hormone receptor). Also restore CLI/product literals (--model sonnet, pnpm install, SCSS, Ghostty, Hermes, Kagi, orca.yaml, /goal, origin) and fix high-confidence sense errors (Move, Memory, Stage, State, cursor Bar/Block, etc.). First slice of stablyai#9574 — not a full catalog audit.
CodeRabbit: automation still used /目标; bulk Stage prefix used 阶段.
Owner
Author
|
Upstream stablyai#10048 merged on stablyai/orca — closing portfolio mirror. |
innocarpe
pushed a commit
that referenced
this pull request
Oct 1, 2026
stablyai#23968) * test: retire native-chat and sidebar cases their fixtures or predicates neutralize Semantic sweep of renderer sidebar, right-sidebar and native-chat. 10 cases removed across 6 files; one test-only production re-export removed. Two new shapes here, both of which make a case unable to fail: A fixture that neutralizes its own variation. `NativeChatNoticeRow`'s `old-reader compatibility` table had six rows, but the test's own `oldStatusSchema.omit({tone, presentation})` strips the metadata being varied, so all six render the identical body `{kind:'status', text:'…'}`. Its schema-acceptance half is owned case-for-case at `agent-session-journal-schemas.test.ts:310-318`. A fixture that makes the distinction its name claims impossible. "Counts a new turn from its stamp, not a row held open by background work" set `turnStartedAt` and `mainAgent.stateStartedAt` to the same `now - 5_000`, so it could not tell the two links apart; `native-chat-terminal-turn.test.ts:75` owns the real version. Also removed: two cases varying `stateHistory`, which no native-chat production file reads (`NativeChatHookTurnEntry` omits it); the `agent-session` row of a transport table whose guard is `valueSource === 'dispatched' && transport === 'catalog'`, so under `reported` the transport is never consulted — the `catalog` row stays as the only test of the non-dispatched arm; `openclaude` from an `it.each` where the only agent test on that path is `args.agent === 'codex'`, so both agents take the identical arm. Production change: `NativeChatMessageList.tsx` no longer re-exports `ProviderFrameRow`. That export existed only for `NativeChatMessageList.provider-frame.test.tsx`; both production callers (`NativeChatNoticeRow.tsx:9`, `NativeChatMessageRow.tsx:24`) already import it from `NativeChatTranscriptChrome` directly, so the test now does too. Kept where the call site differs though the assertions match: a dispatched-pill tooltip case and a transport-hedge case hit `NativeChatSessionOptionPickers.tsx:278` (model pill) versus `:302` (options pill). Kept as live branches: the `lifecycle === null || lifecycle === 'published'` disjuncts, the four distinct wirings in `native-chat-reader-scroll-input.ts:33-46`, and a ring case that is the only one reaching the module's own keydown listener, because the sibling's click path already runs `dropPendingHover`. * test: delete the assembler/id-merge differential, which cannot fail Reverses my own restore of `native-chat-assembler-merge-parity.test.ts`. I kept it believing it was a live cross-implementation differential oracle; it is not. `native-chat-session-assembler.ts:233` documents the gate: the `turnKey` fallback "only merges a candidate against an existing message of a DIFFERENT source (#10)". The test passes `sources: { transcript }` — a single source — so that fallback is gated off, the assembler reduces to id-dedup-and-append, and it equals the mobile id-only merge by construction. The assertion is identity === identity. Both contracts it nominally covered are owned directly, by tests asserting concrete values rather than comparing two implementations that degenerate to the same operation: identical same-source prompts surviving at `native-chat-session-assembler.test.ts:328` and `:354` (both citing #10), and id-append order at `mobile/src/session/mobile-native-chat-merge.test.ts:18`. The lesson generalizes: a differential is only worth keeping if the two implementations can actually diverge on the fixture used. Check that the fixture reaches the code that differs.
innocarpe
pushed a commit
that referenced
this pull request
Oct 21, 2026
…win projections stay on their host (review-5 #2 #9 #11) (stablyai#30890) * fix(renderer): host writes route only through the strict owner, and twin projections stay on their host (review-5 #2 #9 #11) A selected ssh: host that two paired servers proxy now resolves ambiguous at the one selected-host resolver, so no caller can fall back to this app's own SSH connection. File Explorer and SSH mutation expectations derive the full {endpoint, place} pair from resolveOwner, so a server folder's nested SSH target stays the write's host. A local lineage write projects onto its own host's rows only. The id-only store-write ratchet now also covers persistence repo-row lookups by id alone (review-5 #10's shape). * fix(ratchet): the id-only lookup scan also sees optional chaining and destructured ids * fix(renderer): an unstamped folder keeps reading its host from its repos; editor focus fallback left for a follow-up * docs(renderer): the File Explorer owner comment names its folder fallback
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
Description User-facing (Simplified Chinese): Several UI strings that were machine-translated into nonsense or the wrong sense are corrected. The anchor bug is Edit worktree detail → GH PR showing 生长激素受体 (“growth hormone receptor”) instead of
GH PR. **TechnNote
innocarpe/orcamainuntil the upstream PR is merged.