Reconcile presence-gated Codex launch prep with main's #7969 WSL runtime-home
status-hook install:
- WSL runtime-home installs (installForRuntimeHome/refreshRuntimeUserHooksForRuntimeHome)
run unconditionally and synchronously — never presence-gated, since the
Windows-side PATH probe cannot see a codex CLI living inside the WSL distro
(gating it would regress #7969).
- Non-WSL launches keep the presence gate plus the always-run #7896 approval
promotion from this branch's review fixes.
- Keep both new tsconfig.cli entries and the added imports (getDefaultWslDistro,
codexLaunchNeedsDirectApprovalPromotion).
- Launch-prep no longer drops #7896 approval promotion when the presence
gate skips the managed install (false-'missing' PATH probe or relative
command override). Promotion now runs on every Codex launch; only the
managed-config write stays presence-gated. Guarded by a new predicate test.
- Remove the now-dead duplicated installer loop + errorStatus from
install-telemetry (production uses the CLI-safe copy in controls); keep the
electron-coupled recorder there and test it directly. Add fail-open loop
coverage to controls where the loop actually lives.
- Relay Windows presence reports 'unknown' (honest) instead of a false
'missing'; drop the unused 'unsupported_remote_platform' skip reason.
* fix(preflight): resolve WSL/SSH agent paths past shell aliases
LeanCTX and similar tools wrap claude/codex as interactive shell aliases.
command -v then returns alias text, which fails absolute-path detection and
hides installed agents (#7816).
Prefer bash type -P, then zsh type -p, then command -v for dash/sh fallback
in WSL agent discovery, WSL isCommandOnPath, and remote relay probes.
* fix(preflight): harden alias-safe PATH lookup chain
Require non-empty results between type -P, type -p, and command -v so bash
type -p empty success cannot skip later lookups.
* fix(preflight): resolve agent executables directly from PATH
---------
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
- Restore per-launch Codex hook upkeep on the interactive PTY launch path via a
shared maintainCodexLaunchHooks() helper (fire-and-forget from the sync spawn
path, awaited from commit-message prep). This keeps #7896's runtime /hooks
approval promotion + user-hook refresh running on every Codex launch, which the
presence-gating refactor had dropped from the interactive path. Enabled installs
stay presence-gated.
- Relay CLI presence: report 'unknown' for a relative (non-absolute, non-home)
override path instead of probing it against the relay process CWD, mirroring the
local detector's guard. Adds a regression test.
- Repoint the agent-hooks.cli-presence-gating reliability gate at the split-out
ssh-relay-session-agent-hook-presence.test.ts where those assertions now live.
* Improve workspace cleanup list
Co-authored-by: Orca <help@stably.ai>
* Address workspace cleanup review feedback
Co-authored-by: Orca <help@stably.ai>
* Fix workspace cleanup perf findings
Co-authored-by: Orca <help@stably.ai>
* Avoid stale cleanup progress cache
Co-authored-by: Orca <help@stably.ai>
* Complete workspace cleanup perf fixes
Co-authored-by: Orca <help@stably.ai>
* Fix worktree list option forwarding
Co-authored-by: Orca <help@stably.ai>
* Address workspace cleanup review nits
Co-authored-by: Orca <help@stably.ai>
* Fix workspace cleanup removal review findings
- Fail a queued removal that now needs a force the user never approved
(confirm-time approvedCandidates snapshot compared in preflight)
- Reword the 120s removal timeout to say removal continues in background
- Wire suppressPreservedBranchToast into cleanup removals
- Stop statting a repo after the first activity metadata timeout
- Document the WSL 9P best-effort stat gap; drop unused locale key
Co-authored-by: Orca <help@stably.ai>
* Split workspace-cleanup slice test to satisfy max-lines
Rebasing onto latest main pushed the combined store-slice test over the
800-line cap. Extract shared fixtures into a test harness and split the
suite into scan-progress and removal-preflight files instead of adding a
forbidden max-lines suppression.
---------
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* Harden layout validation, watcher lifecycle, and connection robustness
- Throw instead of silently skipping when the packaged daemon-entry is
missing, preventing layout regressions from passing build checks.
- Terminate idle parcel-watcher processes to reclaim native handles and
avoid crash-prone native node module teardowns on shutdown.
- Bind the persisted WS fallback port first to prevent orphaning active
mobile pairings when the preferred port becomes free again.
- Cap concurrent disk reads for restored dirty tab verification at three
to prevent startup connection bottlenecks on remote SSH workspaces.
* Queue file IDs instead of snapshots in restored conflict scans
This avoids using stale file snapshots (e.g., outdated disk signatures)
if a tab is saved, closed, or re-baselined while waiting in the queue
behind the concurrency limit. The live state is now fetched from the
store and validated immediately before initiating the disk read.
- Update the issue #7253 remote-installer coverage test to the manifest +
presence-gated installRemoteManagedAgentHooks signature (droid/copilot now
install remotely only with positive CLI presence, preserving the #7253 fix).
- Split the remote managed-hook presence gating tests out of
ssh-relay-session.test.ts into a focused sibling file so both stay under the
800-line oxlint max-lines limit without any suppression.
- Report agents omitted from the remote presence map as
remote_presence_unavailable instead of cli_not_found; only a positive
'missing' probe means the CLI is absent.
- Re-check shouldContinue after the SFTP open await in
installManagedHooksOnRemote so a disposed/replaced session cannot
mutate remote agent config.
- Treat relative (non-home, non-absolute) command overrides as unknown
presence instead of probing them against the main process CWD.
Co-authored-by: Orca <help@stably.ai>
On macOS 26, UNUserNotificationCenter aborts when executables are run
from Contents/Resources because bundleProxyForCurrentProcess returns
nil.
Moving the orca-notification-status helper to Contents/MacOS next to
the main Electron executable ensures proper bundle resolution and
avoids immediate crashes.
* auth v1
* fable review
* lint
* Account menu with org membership management
Default UX is a compact account menu (sign in, organization selection, sign
out) that renders only when cloud auth is configured; adds an organization
members dialog (invite, role, remove) gated on server-side role checks. The
multi-profile switcher UI is preserved behind ORCA_MULTI_PROFILE_UI=1.
Co-authored-by: Orca <help@stably.ai>
* Gate the optional account sign-in UI to dev builds
The account switcher stays hidden in packaged builds while the feature is
in progress. Dev builds still show it when the client env vars are set, and
a dev-only Settings > Dev Tools > Orca Cloud section mirrors it.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* feat(onboarding): state-aware macOS notification permission step
The Set up notifications step showed a one-size-fits-all 'Open Mac
Settings' button that simultaneously fired the macOS permission prompt
and opened System Settings — two competing system UIs, with System
Settings unnecessary for the common fresh-install case.
Electron exposes no API to read macOS notification authorization, but
scheduling outcomes do reveal it: a silent probe notification's 'show'
event means permission is granted, 'failed' means delivery is blocked.
A new notifications:probeDelivery IPC runs that probe (cached via
passive delivery evidence and a persisted confirmation flag), and the
onboarding card now renders the real state:
- fresh install: the probe itself pops the native Allow dialog the
moment the step opens; the card flips to 'Notifications are enabled'
automatically when the user clicks Allow (silent 2.5s re-probes)
- blocked: amber card with an Open System Settings deep-link, which
also self-heals once the user flips the toggle
- granted: green confirmation card
The test-notification button now feeds the same card instead of the
ambiguous 'if no banner appeared…' toast during onboarding.
Co-authored-by: Orca <help@stably.ai>
* fix: don't log expected probe rejections while polling for permission
Co-authored-by: Orca <help@stably.ai>
* fix: amber warning styling + single stable dev bundle id for notifications
- Blocked card now uses the app's shipped amber idiom (tinted surface with
amber title/body) instead of white-on-amber-wash, which read muddy in
dark mode; macOS permission card split into its own module to stay under
the max-lines budget.
- Dev instances previously minted a unique macOS bundle id per
branch x Electron version, registering a new Notification Settings entry
every time ('Orca: <branch>' rows piling up forever) and pointing the
settings deep-link at ids System Settings can't resolve. All dev
instances now share com.stablyai.orca.dev: one Notification Center
entry, one permission grant covering every dev build.
Co-authored-by: Orca <help@stably.ai>
* fix: tighten macOS permission card copy
Body copy was one long sentence; now a single short instruction with
'Updates automatically.' as a separate dimmer line. Also repairs locale
catalog parity for keys introduced by commits rebased into this branch.
Co-authored-by: Orca <help@stably.ai>
* fix: drop 'Updates automatically.' line; ad-hoc sign dev app copies
The extra line read as confusing filler — the cards now carry one short
instruction each.
Dev Electron copies had broken code signatures (the Info.plist identity
edits invalidate the ad-hoc seal), which macOS punishes by refusing
Notification Center registration outright: every dev notification failed
with UNErrorDomain error 1, the app never appeared in System Settings >
Notifications, and the settings deep-link had nothing to land on. The dev
runner now ad-hoc re-signs the copied bundle after the plist edits
(bundleLayoutVersion bumped so stale unsigned copies are recreated).
Verified end-to-end: runner-built copy passes codesign --verify --deep,
probe delivery returns delivered, the onboarding card flips green in dev,
and the deep link opens the dev app's own notifications pane.
Co-authored-by: Orca <help@stably.ai>
* fix: drop confusing copy line; session-only permission evidence
Removes the 'Updates automatically.' line from both permission cards.
Also drops the persisted notificationDeliveryConfirmed flag: OS-level
permission changes between sessions, and a stale positive rendered a
false green card. Delivery evidence is now session-scoped only.
Documented detection ceiling (verified empirically on macOS 26): while
the permission dialog is unanswered — and when notifications are toggled
off in System Settings after being authorized — macOS accepts requests
and silently swallows them, with no public API (Notification Center
delivered-history and legacy ncprefs both included) able to distinguish
that from real delivery. 'failed' remains definitive for unsigned builds
and dialog-level denials.
Co-authored-by: Orca <help@stably.ai>
* feat: real macOS notification permission readout via native helper
Electron has no API for UNUserNotificationCenter authorization, and every
observable fallback lies: scheduling succeeds (and getHistory lists the
notification) even while macOS silently swallows display because the
permission dialog is unanswered or notifications were toggled off in
System Settings. The onboarding card therefore showed 'enabled' after the
user disabled notifications.
Adds native/notification-status-macos: a tiny Swift binary that prints
the app's real authorization status. It runs from inside the app bundle
(NSBundle resolves the bundle by walking up from the executable) and
embeds the app's CFBundleIdentifier in a __TEXT,__info_plist section so
every codesign --force pass — electron-builder's signing or the dev
runner's ad-hoc deep sign — derives the identifier macOS keys
notification records to. Spawning it from the app returns authorized /
denied / not-determined exactly matching System Settings.
notifications:probeDelivery now prefers this readout (authoritative,
silent), firing at most one dialog-trigger probe per session while the
decision is pending, and falls back to the previous delivery-probe
heuristics when the helper is unavailable. The card polls the readout
silently in every state, so toggling Allow notifications in System
Settings flips the card within a poll — both directions, verified live.
Test notifications also consult the readout so 'delivered' is no longer
claimed for swallowed notifications.
Packaged builds ship the helper via extraResources and sign it in
afterPack like the computer-use helper; dev copies compile it on demand
(swiftc, non-fatal when missing) with the shared dev bundle id.
Co-authored-by: Orca <help@stably.ai>
* feat: in-app fallback for swallowed notifications + permission card in Settings
- Dispatch now consults the authorization readout before creating a
native notification: when macOS would silently swallow it (denied or
prompt unanswered) it returns reason 'blocked-by-system' instead of
piling invisible notifications into Notification Center. The terminal
notification path surfaces that as a once-per-session in-app toast
with an Open System Settings action. Mobile fan-out is unaffected.
- Settings > Notifications now shows the same live permission card as
onboarding (moved to components/notifications/), polling the readout
so System Settings changes reflect within seconds, and the test
button updates it inline.
- Test sends that are blocked at the OS level now show the
settings-pointing failure toast instead of a generic error.
Co-authored-by: Orca <help@stably.ai>
* fix: hide macOS permission card while Orca notifications are disabled
A green 'Notifications are enabled' card next to a disabled Enable
Notifications toggle read as a contradiction — the card now renders (and
the readout polls) only while Orca's own notifications setting is on.
Also single-flights the authorization helper so simultaneous agent
completions share one readout process.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): clear leaked mouse-reporting modes on pane reattach
A TUI that enables mouse tracking (?1000/1002/1003 + SGR 1006/1016) and
dies uncleanly never emits the disable sequence, so the daemon's snapshot
records the mode and buildRehydrateSequences re-arms it on every reattach.
POST_REPLAY_REATTACH_RESET cleared cursor/focus/kitty state but not mouse
modes, so a plain shell in the reattached pane echoed every pointer-motion
report (`<35;col;rowM`) as literal text.
Add RESET_MOUSE_REPORTING (?9l ?1000l ?1002l ?1003l ?1006l ?1016l) to both
POST_REPLAY_REATTACH_RESET and POST_REPLAY_MODE_RESET. Live agent panes keep
mouse modes via POST_REPLAY_LIVE_AGENT_REATTACH_RESET, so agent scroll is
unaffected.
Verified against the real daemon serializer + real xterm: the old reset
leaves mouseTrackingMode armed, the new reset returns it to 'none'.
* test: add regression tests for terminal mouse mode leak on reattach
- Add an E2E test to verify that a warm reattach disarms mouse modes
left armed by an uncleanly exited TUI.
- Add a test fixture that writes the mouse tracking enable sequence
without a matching disable sequence.
- Ensure the reattached pane disarms mouse tracking and that actual
mouse movement produces no reports.
* Add types to isMouseReport in terminal reattach leak test
Explicitly annotate parameter and return types for the isMouseReport
helper function inside the page.evaluate block.
* Refactor mouse-mode leak E2E test to use shell printf and live pane
Eliminate the external Node.js fixture file and streamline the E2E test
by using a POSIX printf shell builtin to arm the mouse tracking modes.
Additionally, verify the leak precondition by inspecting the active pane's
live terminal state (mouseTrackingMode) rather than querying internal
daemon buffer snapshots via window.api.pty.getMainBufferSnapshot.
Identify Claude sessions with no saved conversation turns but possessing
recoverable signals such as queued prompts or subagent transcripts.
This displays them in the sidebar with a "Not saved" badge instead of
filtering them out as empty, and provides detailed notices to recover
them via logs while disabling standard resume actions.
Additionally, extract Gemini session parsing logic into a separate
module and support counting sibling subagent transcripts across local
and remote SSH session scans.
Show a small amber dot on the floating-workspace launcher (both the
floating-button and status-bar triggers) whenever any floating-workspace tab
still has an unacknowledged terminal bell or agent completion, and a
composited amber dot on the Windows tray icon when the window is
minimized/hidden. Both clear through the existing show-until-interact paths —
engaging with or closing the offending tab drops the dot with no stale unread
state left behind.
The launcher dot derives from the existing per-tab/per-pane unread maps via a
new selectFloatingWorkspaceHasUnread selector (primitive boolean, empty-
workspace early return, no bespoke state). The tray dot rides the notification
dispatch and clears on window show/restore.
* fix(mobile): normalize Grok rotating OSC titles at the main observation boundary
Desktop already collapses Grok Build's rotating working frames via the
renderer's normalizeTerminalTitle, but the main process stored raw OSC
titles, so mobile session tabs (fed from pty.lastOscTitle) still saw a
distinct title every spinner frame and re-touched snapshots each time.
Apply normalizeTerminalTitle once where main records an observed OSC
title, before the prevTitle comparison that gates session-tab and
mobile-snapshot touches, and normalize hydration-seeded titles the same
way so the first live frame after a seed compares equal. Agent status
stays detected from the raw title, mirroring the renderer tracker.
Covers remoted/SSH PTYs too since they surface through the same main
observation path.
Co-authored-by: Orca <help@stably.ai>
* Fix Grok and Pi terminal title normalization and status detection
- Require a strict "spinner - phrase - grok" pattern for Grok working
titles to prevent false positives on other agent tasks ending in
"- grok" (such as Claude or Codex).
- Treat collapsed "Pi" and "OMP" synthetic titles as idle by default
to prevent them from reverting to neutral status after normalization.
- Prevent duplicate mobile session tab updates during Grok status
frame rotations by ensuring they normalize to a stable title.
---------
Co-authored-by: Orca <help@stably.ai>
* feat(source-control): add Fix push failure with AI for pre-push hooks
Detect pre-push hook failures separately from auth/transport errors so
push toasts and inline messages no longer suggest checking repo access.
Mirror the commit-failure recovery flow with a fixPushFailure action,
summary panel, details dialog, and agent launch recipe in Settings.
Fixes#6497
* feat(source-control): add push failure AI recovery
Co-authored-by: dalveytech-vincent <vincent@dalveytech.com>
---------
Co-authored-by: dalveytech-vincent <vincent@dalveytech.com>
After #7750 removed the containment guard, the residual #7239 failure mode
is a persisted/inherited startupCwd whose directory no longer exists: every
spawn dies with the provider's missing-directory error. Fresh local renderer
spawns now opt in (cwdFallback: 'worktree') to recover at the workspace root
with a generic in-terminal notice; reattach, SSH, remote-runtime, runtime/API
and mobile callers keep exact cwd semantics, and existing directories —
including outside the worktree (#7685) — spawn as requested.
Co-authored-by: Orca <help@stably.ai>
The relay CLI shim on SSH remotes rejected every orchestration/mutation
command with 'Unsupported SSH Orca CLI command' because the host handled
relay CLI requests with a hand-rolled allowlist of five read-only-ish
commands. The host now runs the real bundled orca CLI entry (same entry
as the local shell command, via ELECTRON_RUN_AS_NODE) as a captured
subprocess, so remote invocations get the full command surface by
construction. Remote cwd is carried via ORCA_CLI_CWD so cwd-based
selectors (--worktree active) resolve against the caller's remote
directory; only Orca terminal-context env vars cross the bridge.
Host-interactive commands (serve, claude-teams, agent-teams-tmux) get a
targeted error, and the legacy in-process switch remains as a fallback
when the host CLI entry cannot be launched. Relay-side request timeouts
are raised to fit mutation and long-poll (--wait/--timeout-ms) commands,
and stdin forwarding now covers *-stdin payload flags.
Fixes#7716
Co-authored-by: Orca <help@stably.ai>
* fix(ssh): guard mux dead-link detector against sleep/App Nap timer pauses
After system sleep or App Nap timer throttling, the first post-wake
timeout-check tick saw pre-pause keepalives as >20s stale and killed a
healthy link (false 'Connection timed out (no ack received)' ->
dispose('connection_lost') -> reconnect overlay churn). Track the last
tick time; when a tick gap far exceeds the interval, reset staleness
tracking, probe with a fresh keepalive, and let the next full window
make an honest liveness determination. A genuinely dead link is still
detected within ~25s after wake.
Also adds probeLiveness(timeoutMs): a keepalive round-trip primitive
that resolves true on the first frame of any kind, used by the resume
path to distinguish surviving links from dead ones.
Refs #7773
Co-authored-by: Orca <help@stably.ai>
* fix(ssh): probe relay liveness on system resume instead of unconditional reconnect
powerMonitor 'resume' previously called connectionManager.reconnect()
for every active target, guaranteeing a teardown + reconnect overlay on
every wake even when the connection survived sleep. Now each session's
relay link is probed (keepalive round-trip, 5s timeout, one retry for
slow post-wake network); only targets whose probe fails are reconnected.
Dead-after-sleep connections still reconnect promptly. The 'suspend'
grace-time handling is unchanged.
Refs #7773
Co-authored-by: Orca <help@stably.ai>
* feat(relay): prefix relay.log diagnostic lines with ISO timestamps
The remote relay.log had no timestamps, which blocked correlating
reconnect flaps with user activity and sleep/wake windows while
diagnosing #7773. Daemon-mode diagnostic lines now carry an ISO
timestamp prefix ('<ISO> [relay] ...', grep-stable). Connect-mode and
orca-cli passthrough stderr is untouched since it goes back to the
app/user terminal and is parsed (handshake-mismatch detection).
The relay bundle is content-hashed at build time, so the versioned
install picks up the new relay automatically on next deploy.
Refs #7773
Co-authored-by: Orca <help@stably.ai>
* fix(ssh): re-check session identity before post-probe resume reconnect
The resume probe can take ~10s; if the user disconnected the target or the
session/connection was replaced during that window, reconnecting would
resurrect an intentionally torn-down connection (CodeRabbit).
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* Sweep all persisted carriers of a removed SSH target id on re-adoption
reassignSshTargetId re-pointed repos and worktree metas but left the old
target id embedded in persisted session pty ids (ssh:<id>@@pty-N in tabs,
layouts, remoteSessionIdsByTabId), the startup reconnect list
(activeConnectionIdsAtShutdown, replayed via ssh.connect at boot — the
exact 'SSH target not found' in STA-1468), sleeping-agent resume records,
provisioned project host setups, sidebar host-scope arrays, and relay pty
leases. Any survivor resurfaces later as a failing connect or reattach.
New ssh-target-id-migration module re-points every carrier in one pass,
wired into reassignSshTargetId with per-carrier unit and store-level
round-trip tests.
Co-authored-by: Orca <help@stably.ai>
* Bridge SSH connection state to paired remote clients
The SSH surface was desktop-only: ssh:state-changed went to the host's
own BrowserWindow and the web client's ssh API was a no-op stub, so a
paired client's reconnect overlay never learned the host connected and
its target labels stayed empty (STA-1468 — overlay stuck on 'please
connect' over a live terminal).
- New sshStateChanged runtime client event, emitted from broadcastSshState
through OrcaRuntimeService onto the existing clientEvents stream.
- New ssh.listTargets / ssh.listRemovedTargetLabels RPC methods next to
the previously unused ssh.getState / ssh.connect.
- Web preload now routes listTargets / listRemovedTargetLabels / getState
/ connect to the paired host's runtime RPC instead of stubbing them.
- useIpcEvents applies sshStateChanged on paired web clients through the
same guarded path as desktop ssh.onStateChanged; desktop clients ignore
the event since a foreign runtime's targets would pollute their local
SSH store.
Co-authored-by: Orca <help@stably.ai>
* Harden the SSH reconnect overlay against stale or unknown target state
- Only present the destructive 'SSH host removed' state on positive
evidence (a removal tombstone label, or a hydrated non-empty target
list lacking the id). A client whose SSH state never hydrated has an
empty labels map for every id and must not offer workspace removal.
- After a failed Connect, resync target metadata so a stale overlay
converges to the ghost/re-adopted state instead of offering the same
failing Connect forever (the repeated 'SSH target not found' toast
loop in STA-1468).
Co-authored-by: Orca <help@stably.ai>
* Address CodeRabbit review on #7767
- Re-key workspaceSessionsByHostId partitions stored under a removed SSH
host id during re-adoption (no writer keys partitions by ssh host today,
but the schema tolerates it — re-key instead of stranding; live partition
wins when both keys exist).
- Track SSH target-list hydration explicitly (sshTargetsHydrated) instead
of inferring it from a non-empty label map, so a legitimately empty
target list still counts as removal evidence and a never-hydrated client
still never offers destructive removal.
- Apply the refreshed target list before the best-effort removed-labels
fetch in the overlay resync, so a labels failure can't discard it.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* fix(main): detect CJK input source via cfprefsd on macOS 15
macOS 15's `plutil -extract <key> json` aborts with "invalid object in
plist for destination format" on the AppleSelectedInputSources array even
though it is all strings, so the selected-input-source probe threw and fell
back to the keyboard layout id (com.apple.keylayout.US). That disabled
forwardAsciiPunctuation, so third-party IMEs (Sogou, Doubao) sent half-width
,.? to the PTY instead of full-width ,。? in terminal panes and agent chat.
Apple's built-in IME happened not to trip the plutil bug.
Read the live prefs via `defaults export` (cfprefsd) and extract as xml1
before converting the clean subtree to JSON, dodging both the plutil json
bug and the stale on-disk plist. The parser and CJK term list are unchanged.
* fix(main): reap CJK input-source probe process group on timeout
Run the macOS input-source probe via detached spawn and SIGKILL the whole
process group on timeout so a wedged cfprefsd can't orphan the defaults/plutil
pipeline stages (the probe re-runs on every window focus-in). Pin absolute
/usr/bin paths, guard the stdout stream, and cover the non-zero-exit, spawn-
failure, and timeout fallbacks in tests.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: su'qiang <nslogname@MacBook-Pro.local>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* fix(runtime): keep same-path imports host-qualified (#7018)
* review: harden runtime repo host match against SSH-repo hijack
An unstamped repo with a connectionId is an SSH repo (resolves to
ssh:<id>), so a same-path runtime import must not adopt it into a
runtime/local host. Match/adopt an unstamped repo only when it has no
connectionId, mirroring the existing local-IPC dedup guard
(src/main/ipc/repos.ts). Adds a regression test that fails without the
guard (SSH repo hijacked into runtime host).
Co-authored-by: Orca <help@stably.ai>
* review: only runtime hosts backfill an unstamped repo
A legacy unstamped repo is indistinguishable from a genuine local repo
(both have null executionHostId and connectionId). Restrict the adoption
branch to runtime incoming hosts so a local/ssh import at a colliding
path can never re-attribute a real local project to the wrong host.
Runtime is the only host that lost its identity to the pre-#7018
path-only import and needs the backfill. Adds a regression test.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>