Commit Graph
29 Commits
Author SHA1 Message Date
Neil a730becd7a fix(automation): keep explicit background launches off screen (#18898) 2026-09-05 16:12:52 -07:00
Neil 2e30187560 feat(dev): sweep the backlog of idle dev Electron bundles (#17803)
* fix(dev): make reclaim report real sizes on Windows and keep setuid intact

Two bugs found by running the reclaim script on real Linux and Windows hosts.

The size report shelled out to `du`, which does not exist on Windows, so every
worktree measured 0 bytes and the script reported nothing reclaimable on the
platform with the largest dist (374MB). Walk the tree in Node instead.

makeTreeReadOnly chmod'd files to a flat 0o555, which clears setuid. On Linux
that would silently strip the bit from chrome-sandbox if a developer had run
the usual `sudo chown root && chmod 4755` workaround -- and under hardlink
sharing it would strip it from every worktree and the cache at once. Clear the
write bits and nothing else.

Measured after the fix: 7.30 GiB across 23 worktrees on one Windows host and
18.31 GiB across 56 on another, both previously reported as 0.

* feat(dev): sweep the backlog of idle dev Electron bundles

out/electron-dev holds one ~275MB patched Electron.app per branch title x
Electron version. The dev runner already prunes them, but only inside the
worktree it is starting and only when that worktree holds more than one bundle
-- and a worktree almost always holds exactly one, so the sweep returns early
every time and nothing ever reclaims another worktree's bundle.

pnpm reclaim:dev-bundles sweeps across every worktree of the repo. Bundles are
pure build output that pnpm dev rebuilds on demand, and rebuilding is cheap now
that the Electron dist is shared.

Reuses the runner's own staleness rules, so a bundle a live process is running
from, or one whose build is still in flight, is never removed. Refuses to run
at all if the process table cannot be read, rather than guessing.

Measured: 120 bundles, 32.2 GiB, on one machine.

Also guards both reclaim scripts behind a direct-invocation check; importing
one for tests previously ran a full sweep at import time.
2026-08-31 22:18:50 -07:00
Neil fe0f2f9be7 perf(dev): share one Electron dist per repo instead of per worktree (#17664)
* perf(dev): clone one Electron dist per repo instead of per worktree

Every worktree extracted its own ~295MB node_modules/electron/dist, measured
at 69GB across 241 worktrees on one machine.

Extract once per repository into <git-common-dir>/orca-cache/electron, then
APFS-clone it into each worktree: copy-on-write, so the second worktree
allocates ~0 bytes and still gets a real, private, writable directory.

Hangs off install-electron-package-binary.mjs, inside the transaction it
already uses to swap dist. Every cache path returns a boolean and false means
"install normally", so non-APFS, cross-volume, corrupt entry, no Git, folder
workspace and CI all keep today's behavior. No symlinks, no lifecycle changes.

out/electron-dev's per-branch Electron.app copy clones too, via the same helper.

Refs #13709

* perf(dev): share the Electron dist on Linux and Windows too

Extends the shared dist cache beyond macOS APFS. Three mechanisms, strongest
isolation first:

  macOS APFS    cp -c              private copy-on-write
  Linux btrfs   cp --reflink       private copy-on-write
  ext4 / NTFS   hardlink + 0555    shared inodes, forced read-only

Reflinks cover btrfs/XFS/bcachefs/ZFS but not ext4, and Windows block cloning
is ReFS-only, so most Linux and effectively all Windows developers need
hardlinks to get any saving at all. Extracted dist is 327MB on linux-x64 and
374MB on win32-x64, both larger than macOS.

Hardlinks share inodes, so a write through one worktree would rewrite every
sibling and the cache. Nothing in this repo writes inside dist -- every
mutation replaces the directory via rename -- but Electron's own install.js
extracts over an existing dist with O_TRUNC, and is reachable through
`pnpm rebuild electron`. Publishing the entry read-only turns that from silent
cross-worktree corruption into EPERM. Directories stay writable so the install
transaction's renames and unlinks still work.

out/electron-dev's per-branch Electron.app is patched and codesigned after it
is copied, so it uses copyPrivateTree, which never hardlinks.

Refs #13709

* test(dev): keep shared-dist tests honest across ext4 and NTFS

Verified on real hardware: Ubuntu 24.04/ext4 (no reflink support, so the
hardlink tier is the only thing that helps there) and Windows/NTFS.

Three tests faked platform: 'darwin' while invoking the real mechanism, so
they failed on Linux where /bin/cp -c does not exist. Mechanism selection is
now asserted with injected stubs; real filesystem behavior is asserted against
whatever the host actually supports.

Windows maps chmod onto the read-only attribute alone, so a directory never
reports 0o755 and a read-only file reports 0o444. Mode-bit assertions that
encoded POSIX semantics are now behavioral (the tree stays removable), and the
executable-bit assertion is POSIX-only -- confirmed on NTFS that a read-only
hardlinked .exe still runs.

* fix(dev): stop a losing publisher from discarding a good cache entry

Greptile caught a TOCTOU in the shared Electron dist cache. Quarantining an
invalid entry happened before sharing the replacement tree, which takes
seconds -- long enough for a sibling worktree to publish a good entry that this
one would then rename away. If the follow-up publish also failed, the cache was
left empty and every worktree re-downloaded.

Stage first, then re-validate immediately before the destructive rename, so an
entry that became good during the share is kept. On a failed swap, restore the
quarantined entry instead of leaving no entry at all: a stale entry still beats
an empty cache, because the next publisher re-validates and replaces it. An
entry that cannot be validated is never displaced, matching the pre-staging rule.

Also covers the Electron upgrade path end to end: a version bump gets its own
cache entry and leaves the previous one for worktrees still on the old branch.

* feat(dev): add a script to share existing worktrees' Electron dists

An install only shares when Electron is (re)installed, and rebuild-native-deps
returns early when the package is already usable -- so a worktree that already
has a working dist never reaches the sharing path and keeps its own copy until
the next Electron upgrade.

pnpm reclaim:electron-dists reports what it would share; --apply does it.
Each worktree is converted behind a rename, so an interrupted run leaves a
working dist either way, and any worktree that fails is left untouched.

Measured on one machine: 677 worktrees, ~195 GiB reclaimable.

* fix(dev): keep the reclaim script's error formatting type-safe
2026-08-31 20:35:54 -07:00
Neil 5ea9daba97 fix(window): keep automated Electron launches out of the foreground (#17347) 2026-08-29 23:55:00 -07:00
Neil a3da91b10a fix(dev): stop caching unsigned bundles and reclaim stale dev copies (#15247) 2026-08-18 13:08:04 -07:00
Neil c40b0ab96b fix(dev): stop macOS Keychain password prompts on pnpm dev (#15183) 2026-08-17 22:34:04 -07:00
Neil 9f3a912c1e fix(terminal): type Option-composed ASCII instead of reporting it as a chord (#14743)
* fix(terminal): preserve Option-composed ASCII input

* fix(terminal): preserve Option keyboard protocol semantics

* fix(terminal): complete Option keyboard event encoding

* fix(terminal): harden Option input encoding

* fix(terminal): close keyboard protocol fallback gaps

* test(terminal): prove Option-composed ASCII reaches the pty end to end

The Option-compose fix had unit coverage only. This drives a live Electron
pane whose kitty flags are armed by the application's own CSI > 1 u and
asserts the bytes at the pty boundary: composed `@` and Shift-layer `\`
arrive as text, configured Option-as-Alt still reports the layout-resolved
chord, and a non-ASCII glyph still reaches the app as its alt hotkey.
Restoring the pre-fix policy fails exactly the two composed-text scenarios.

Also records the ASCII rule's rationale where the rule lives, not only in a
test comment.

* refactor(terminal): drop the unread Option layers from the layout snapshot

The native helper computed an Option and Option+Shift character for every
key, shipped both over IPC, validated them in the parser and cached them in
the renderer — but no production caller ever asked for them. Only the base
and Shift layers are read, and Shift is the one the web layout map cannot
supply, which is why the helper exists at all.

Removing them halves the helper's UCKeyTranslate work per key and drops the
option parameter that six signatures were threading through for nobody.
2026-08-16 12:49:02 -07:00
NeilandBrennan Benson a8126a0a92 fix(macos): explain the TCC prompts, and surface Full Disk Access only to users macOS is prompting (#9756) (#9910)
* fix(macos): add a Full Disk Access nudge to reduce recurring TCC prompts (#9756)

macOS shows the "Orca wants to access other apps' data"
(kTCCServiceSystemPolicyAppData) prompt and it can keep reappearing. The
reappearing loop is not a fixable app bug: it is TCC identity churn — an
unsigned local rebuild mints a new code identity each build, so macOS treats
each as a new app — and Orca's other-app reads are already gated behind opt-in
settings or explicit user actions.

The durable remedy for the population we can help (release users) is Full Disk
Access, a superset macOS grant that stops these prompts for a stable identity.
Surface it with an ambient, dismissable sidebar card that reuses the existing
developer-permissions IPC. macOS-only; probes FDA status at most once per
renderer session (the probe itself reads protected data, so it must not repeat
on focus/remount); "Open System Settings" opens the Full Disk Access pane;
permanent localStorage dismissal.

* fix(macos): stop the FDA nudge promising macOS will stop asking

The card said Full Disk Access makes "macOS stop asking", but the grant
covers this app while terminals are spawned by the detached PTY daemon
(daemon-init.ts forks execPath with ELECTRON_RUN_AS_NODE + detached:true,
reparented to launchd), which macOS treats as its own TCC identity. A user
who followed the card would grant FDA and still be prompted from terminals.
Scope the claim to reducing prompts and name the terminal caveat.

* fix(macos): drop stale focus refreshes in the FDA nudge

refreshFullDiskAccessStatus() applied whichever getStatus() round-trip
resolved last. Rapid blur/focus puts several in flight, so an earlier
pre-grant 'unknown' landing after a newer 'granted' un-hid the card and
also wrote 'unknown' into the module-level session cache, re-nagging a
user who already has Full Disk Access for the rest of the session. The
adjacent FullDiskAccessSetupPrompt already guards this with a refresh
sequence; mirror it here.

Also unmount React roots in afterEach: clearing document.body left them
mounted, leaking each test's window focus listener into later tests.

* test(macos): unmount the StrictMode FDA nudge root between tests

The afterEach unmount added in 5a0f717 only covers roots created through
renderNudge(). The StrictMode probe test builds its own root, so it was
never unmounted and its component stayed live for the rest of the file.
Today that component has no window focus listener, so nothing breaks; add
a CTA click to it and the same contamination 5a0f717 fixed comes back —
the two tests after it see extra getStatus() calls and fail. Register the
root so the fix covers every mount site.

* fix(macos): attribute the FDA prompts to agent activity, not Orca's own reads

The card said the prompts happen "when this copy of Orca reads protected app
data", but Orca's own reads are small and gated; #9756's trigger is agent
find/grep sweeps into ~/Library/Containers, which macOS bills to Orca because
Orca is the responsible process for every terminal child. Blaming Orca reads
as an accusation and hid why FDA works at all — the grant attaches to Orca
rather than to each churning child binary.

Name agents as the trigger, keep the "reduce" hedge and the terminal caveat,
and drop the "this copy of Orca" dev-build hedge that cost a clause. Assert
the causation wording so it can't silently regress.

* fix(macos): explain the TCC prompts on the settings row, drop the sidebar card

The sidebar nudge added in 344d466b was premised on FDA being reachable
"only inside onboarding". It isn't: Settings > macOS Permissions has had a
full-disk-access row all along (searchable), the Setup Guide hosts the same
prompt from both a settings pane and a re-openable modal, and the sidebar
already links to that modal via the "Onboarding checklist" entry. The card
added a fifth affordance to the same sidebar that already had the fourth,
so it bought prominence rather than access - shown to every macOS user
without FDA, most of whom never hit #9756.

Keep the part that was actually new. The settings row still described the
prompts as something projects and worktrees trigger, which is the same
misattribution the card carried: the reads come from the agents Orca runs,
and macOS names Orca only because it is the responsible process for every
terminal child. It also never mentioned that the grant has to cover Orca
Helper, or that the preserved daemon keeps stale TCC state until restart.

Non-English catalogs get the English string as a placeholder; the bootstrap
translators key their cache on the English value, so a changed string is
re-translated on the next run.

* feat(macos): nudge Full Disk Access only after macOS repeatedly prompts

The FDA hint is only worth showing to users macOS is actually prompting.
tccd emits one AUTHREQ_PROMPTING line per consent dialog it displays,
carrying the service and both identities, so a narrow log-stream predicate
detects the real thing without correlating across lines or guessing whether
a dialog appeared. Verified against a captured dialog: the predicate matched
1 line out of 1436 TCC lines in ~28s, because routine preflight checks - the
overwhelming majority of TCC traffic - do not emit it.

Count dialogs where Orca is the responsible process, persist across launches,
and tell the renderer on the third one. The event separates the accessing
binary from the responsible app, which is the crux of #9756, so the toast can
name the tool that triggered it rather than blaming Orca generically. One
toast per user, with a permanent opt-out; it deep-links to the FDA row in
Settings > macOS Permissions rather than restating the guidance.

macOS-only: the watcher no-ops elsewhere, the web client stubs the API, and
the child is killed on before-quit since log stream ignores a closed stdout.

* test(macos): pin the platform so the TCC watcher tests exercise the darwin path

start() is darwin-gated, so on Linux CI it no-opped and the stream/kill
assertions passed vacuously against a watcher that never spawned. Pin
process.platform per the existing convention (shared/secure-file.test.ts),
and cover the gate itself with an explicit non-darwin case.

* fix(macos): start the TCC watcher from app bootstrap, not the window wiring

attachMainWindowServices is called directly by its own unit test, so wiring
initTccPromptNotice there made `vitest src/main/window/` spawn real `log stream`
children that outlived the run - two orphaned watchers were left behind by a
single test session. Only the IPC handler registration stays there; the spawn
moves to the real app bootstrap in index.ts, which tests never execute.

Verified: running the suite that leaked now leaves the watcher count unchanged.

* fix(macos): clarify repeated permission notice

* fix(macos): keep TCC notice lifecycle safe

* fix(macos): retain pending TCC notice delivery

* fix(macos): acknowledge TCC notice delivery

* fix(macos): release failed TCC notice claims

* fix(macos): retry transient TCC notice display

* fix(macos): contain TCC notice IPC failures

* fix(macos): harden TCC notice renderer lifecycle

* fix(macos): contain TCC notice dismissal failures

* test(macos): satisfy promise executor lint

* fix(macos): detect helper-attributed TCC prompts

* fix(macos): align TCC watcher lifecycle and helper identity

* perf(macos): defer TCC log reader until first paint

* fix(macos): recover deferred TCC watcher startup

* fix(macos): recover TCC watcher from deferred quit

* fix(macos): localize recurring file access notice

* fix(macos): preserve TCC watcher and localized guidance

* fix(macos): avoid duplicate TCC watcher recovery

* fix(macos): wait for locale before TCC notice

* perf(macos): isolate TCC notice subscriptions

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-28 15:34:52 -07:00
OrcaWin cd05f2ff93 Implement robust orchestration primitives and connected-server workers (#9925) 2026-07-27 12:31:37 -07:00
NeilandOrca 25ea2bbfd1 onboarding: seamless macOS notification permission step with live state detection (#7684)
* 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>
2026-07-08 22:21:40 -07:00
Neil ce687221d3 lint(unicorn): enable prefer-number-properties, prefer-array-find, prefer-array-index-of (#7516)
Enable three unicorn rules — one correctness, two performance — and fix every
existing violation repo-wide so the rules pass as errors.

prefer-number-properties (76 sites)
- parseInt/parseFloat/NaN -> Number.* : safe aliases (autofixed).
- isNaN -> Number.isNaN (12 sites, hand-converted): global isNaN coerces its
  argument, Number.isNaN does not. Verified every call site already passes a
  number (Number.parseInt results, number-typed fields, Date.getTime()), so the
  conversion is behavior-preserving today and guards against a future non-numeric
  argument silently coercing.

prefer-array-find (26 sites)
- .filter(pred)[0] -> .find(pred); .filter(pred).at(-1) / .pop() -> .findLast(pred).
  Drops the intermediate array and short-circuits.

prefer-array-index-of (5 sites)
- .findIndex(x => x === v) -> .indexOf(v).

Verified: typecheck (node/cli/web) clean, 53 affected suites pass (1679 tests),
oxlint clean repo-wide. mobile/ uses findLast safely (already ships ES2023
.toReversed()); config scripts and e2e helpers run on Node 24.
2026-07-05 23:56:37 -07:00
Neil f9e18910ae chore(lint): adopt unicorn/prefer-import-meta-properties (error) (#6847)
Migrate fileURLToPath(import.meta.url) / dirname(...) boilerplate to the
native import.meta.dirname / import.meta.filename, then enable the rule
at error so new code stays on the native form.

The oxlint autofix rewrites the expression but leaves the now-unused
node:url / node:path imports behind (which the already-enabled
no-unused-vars=error would then flag), so this commit also removes those
34 orphaned imports — trimming the named import where other names are
still used, deleting the line where it was the sole import.

Scope is build scripts + Node-env tests only (config/scripts, tools/
benchmarks, *.test.{ts,mjs}, vitest configs); zero shipped runtime code.
The native properties are exact equivalents (Node >= 20.11; repo is on
24), so behavior is unchanged.

Verified: oxlint 0 errors tree-wide (root + mobile), oxfmt clean,
typecheck (node+cli+web) + mobile tsc pass, root vitest 22825 passed /
0 failed, mobile vitest 1018 passed. Exercised the rewritten scripts
directly: build:relay (6 targets), ensure-native-runtime,
verify-macos-entitlements all run correctly with import.meta.dirname.
2026-06-29 23:37:30 -07:00
Jinwoo HongandOrca 7ea359bd60 Add Claude Agent Teams native pane launcher (#4892)
* Add Claude Agent Teams native pane launcher

Co-authored-by: Orca <help@stably.ai>

* Fix Agent Teams CI coverage checks

Co-authored-by: Orca <help@stably.ai>

* Fix Claude Agent Teams split direction mapping

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-08 16:11:32 -04:00
Jinjing 60e47944cd Revert "Reduce macOS dev instance identity prompts" (#4721) 2026-06-05 14:07:28 -07:00
Jinjing 39e633c136 fix: address review findings (#4704) 2026-06-05 10:39:18 -07:00
Neil ddbb6a1e7d Update oxlint and oxfmt 2026-05-30 13:09:17 -07:00
Jinjing ac10c4075f Show sleeping workspaces by default (#2514)
- Add a narrow SSH relay RPC for refreshing remote-tracking refs without
  reopening generic fetch execution
- Resolve SSH connection context from composite worktree IDs during startup
  before worktree discovery completes
- Make the sleeping workspace filter negative-form and reset to the new visible
  default
- Tolerate transient xterm scroll restoration failures during layout
- Restore macOS Electron framework symlinks after copying the dev app
2026-05-21 02:12:22 -07:00
Neil 8b77dffec2 Fix macOS notification settings recovery
Open the current app's macOS notification settings entry and stop reporting test notification success until Electron confirms the native notification was shown.
2026-05-20 22:39:18 -07:00
Jinjing e0104372da Squashed commits (#2485)
- Fix workspace space cache and git status cleanup checks

- Treat browser tabs as workspace delete blockers

- Move deletion readiness into shared presentation logic so tests cover it
- Preserve explicit empty git status entries for clean worktrees

- Add package manager cache cleanup to space manager

- Detect npm, pnpm, Yarn, and Bun caches from lockfiles during scans
- Add explicit cleanup IPC for safe and aggressive cache actions
- Support local, SSH, and Windows command execution paths safely
- Tighten workspace deletion decisions with git, editor, agent, and terminal state
2026-05-20 22:09:35 -07:00
Jinjing a1f9e16ccb Rebuild stale macOS dev Electron app copies (#2479)
- Detect missing Chromium framework resources before reusing the copied app
- Prevent interrupted copies from leaving `pn dev` with a blank Electron window
2026-05-20 20:16:56 -07:00
Jinwoo HongandOrca 8a4d558c1d Skip initial dev web client build (#2273)
Co-authored-by: Orca <help@stably.ai>
2026-05-18 14:30:36 -07:00
Jinwoo HongandOrca 4b7c9b7213 Improve remote client runtime parity (#1975)
Co-authored-by: Orca <help@stably.ai>
2026-05-17 22:24:38 -07:00
Neil c017229149 Simplify dev Dock instance naming (#2111) 2026-05-16 14:36:46 -07:00
Neil 2ead67c650 Label macOS dev Dock instances by branch (#2068)
* fix: label macOS dev Dock instances

* fix: keep dev badge visible in Dock labels

* chore: clean up dev identity plumbing

* feat: add stable-name dev command
2026-05-15 22:46:13 -07:00
Jinwoo Hong 618f39d179 Add web runtime client support 2026-05-15 05:44:25 -04:00
Brennan BensonandOrca c0801b9aef chore(dev): auto-expose a CDP port from pn dev (#1511)
Co-authored-by: Orca <help@stably.ai>
2026-05-06 14:14:51 -07:00
Jinwoo HongandOrca c9391e203f feat(orchestration): add inter-agent orchestration system (#1188)
Co-authored-by: Orca <help@stably.ai>
2026-04-28 12:21:31 -07:00
Jinwoo Hong 1ea2a6d768 fix: strip ELECTRON_RUN_AS_NODE from dev script environment (#769) 2026-04-17 13:14:40 -07:00
Neil 8d3f640e67 Fix macOS dev Electron shutdown on Ctrl+C (#435) 2026-04-09 23:50:23 -07:00