Commit Graph
194 Commits
Author SHA1 Message Date
3f9dbba47b fix(build): skip spawn-helper check on Linux to avoid spurious node-pty rebuilds (#7762)
* fix(build): skip spawn-helper check on Linux to avoid spurious node-pty rebuilds

getPatchedNodePtyRebuildReason() unconditionally checked for
build/Release/spawn-helper, but spawn-helper is a macOS-only node-pty
build target. On Linux, node-gyp never generates it, so missingArtifact
was always non-null, causing unnecessary source rebuilds every time.

Fixes #7760

* test(build): cover platform-specific node-pty artifacts

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-10 01:17:55 -07:00
f238952be2 Agent status over WSL: guest-resident hook relay + WSL-side hook installers (STA-1515) (#7903)
* docs: full design + context for agent status over WSL (STA-1515)

Why hooks don't work on Windows+WSL (loopback transport gap + WSL-side
installation gap), per-client transport map, the OMP-only fixes that
shipped (7642/7641) and why they don't generalize, the recommended
guest-resident relay over wsl.exe stdio mirroring the SSH relay plus
WSL-side hook installers, alternatives considered, validation facts and
gotchas from the 2026-07-08 Windows rig run, and acceptance criteria.

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

* feat(agent-hooks): agent status over WSL — guest relay + WSL-side hook installers (STA-1515)

Agent hooks have never worked from inside WSL: under default NAT
networking, WSL's 127.0.0.1 is its own loopback, so every hook POST to
the Windows listener dies silently, and hook configs were only ever
written to the Windows home where WSL agents never see them.

Transport: a hooks-only guest relay (src/relay/wsl-agent-hook-relay.ts)
runs inside the distro, binds WSL loopback on the very port the clients
were already given (host-issued token; EADDRINUSE falls back to :0 with
endpoint-file re-coordination, which also covers mirrored networking),
and forwards parsed envelopes over its own wsl.exe stdio into
agentHookServer.ingestRemote — the same shape as the SSH relay. It exits
when stdin closes so a freed Windows port can never be forwarded into a
dead guest listener.

Installation: the unchanged SSH remote hook installers run against an
SFTP-shaped adapter whose primitives are home-scoped fs RPCs served by
the relay, so all 14 managed agents' hooks land in the WSL home over the
already-open channel with zero per-file wsl.exe spawns.

Lifecycle: per-distro manager ensured from buildPtyHostEnv on every WSL
PTY spawn (covers post-restart daemon reattach re-spawns), stale-bundle
reinstall via exit 42, no-node-43 cooldown, bounded retry for wsl.exe
'Catastrophic failure (E_UNEXPECTED)', breadcrumbed failures.

Zero per-client transport changes; listener stays Windows-loopback-only.

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

* fix(agent-hooks): WSL relay link-death recovery + Codex runtime-home hook install (STA-1515)

Follow-ups from the first Windows-rig validation of PR #7903:

Link death: a mux protocol error or keepalive timeout could kill the
host<->guest link while the guest relay stayed alive returning 204s —
the manager stayed 'running' and every later envelope blackholed
silently (the exact observed signature: Claude hooks POST 204, store
never populates). wsl-hook-relay-link.ts now guarantees exactly-once
death handling from either signal (mux dispose OR child exit); the
manager breadcrumbs it, kills the child, and self-restarts after a
short cooldown since a live agent session produces no new PTY spawns
to re-trigger ensure. ORCA_WSL_HOOK_RELAY_DEBUG=1 traces each received
envelope pre-ingest. A live integration test pins the full host chain:
the real esbuild bundle over real child stdio through the real manager
into a real AgentHookServer.ingestRemote, exact Claude POST shape.

Codex: Orca launches WSL Codex with CODEX_HOME redirected to the
managed runtime home (~/.local/share/orca/codex-runtime-home/home), so
hooks installed to ~/.codex were never read. installRemote now accepts
an explicit codex home (flat layout), threaded from the relay manager;
the config.toml trust write is deferred while the file doesn't exist
(the launch path seeds it only-if-absent — creating it first would
cancel the seed), and the manager re-runs the byte-equality-idempotent
installers on later ensures (30s throttle) to upsert trust once the
seed lands.

Also: WSL test suites now run on Windows dev hosts (fs-backed suites
skip with rig coverage noted; manager suite uses a fixed POSIX home).

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

* fix(agent-hooks): renderer ownership gate treats wsl:* connection ids as local (STA-1515)

Round-2 rig finding: with the link fixed, WSL hook envelopes reached
ingestRemote and the durable cache, but useIpcEvents.applyAgentStatus
drops any status whose stamped connectionId differs from the owning
repo's — 'wsl:<distro>' !== null for a local repo, so every WSL-relayed
status died before setAgentStatus and notifications.

wsl:* ids are transport provenance, not ownership: the gate now
normalizes them to local via isWslHookRelayConnectionId (shared
contract, also used by the relay link when stamping), while still
rejecting WSL-stamped events against SSH-owned repos. Provenance stays
stamped — it is what made this drop diagnosable.

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

* fix(agent-hooks): adversarial-review hardening for the WSL hook relay (STA-1515)

Four independent review lenses over the branch; all confirmed findings
fixed before the next rig round:

Endpoint identity (4/4 reviewers): the guest endpoint dir was keyed by
the EPHEMERAL Windows hook port, so a daemon-surviving agent kept
sourcing the dead port-P1 file after an Orca restart — breaking the
restart-resume acceptance criterion and regressing shipped OMP
recovery. Now keyed by a restart-stable instance key (hash of the
Windows endpoint file path, crossed via ORCA_WSL_HOOK_INSTANCE): the
restarted instance's relay rewrites the SAME file, which is exactly
what re-coordinates survivors.

Restart policy: every failure arms the restart timer (one failed
relaunch no longer ends self-recovery), and the timer probes
wsl --list --running first — wsl -d BOOTS a stopped distro, so
recovery must never resurrect a VM the user shut down; stopped-distro
state is dropped instead. Failure counters reset only after 2min of
stable uptime, so connect-then-die loops escalate to the 10-min cap
instead of cycling every 10s. Timer policy extracted to
wsl-hook-relay-recovery.ts with direct tests.

Also: version-namespaced guest install dir (dev+prod instances no
longer reinstall over each other; PID-suffixed tmp files), 30s install
timeout (a wedged wsl.exe could pin the state machine at 'starting'
forever), per-candidate node version probing (apt node 12 on PATH no
longer masks nvm node 20 into a false no-node cooldown), WSL_UTF8=1 +
NUL-stripped stderr (catastrophic-failure matcher survives UTF-16LE),
ordered post-sentinel chunk handoff, port-fallback breadcrumb via the
home handshake, bad home reply now fails the connect, missing-bundle
warn-once, case-normalized distro keys, disposeAll wired to will-quit,
one-shot 60s reinstall timer for single-spawn Codex trust catch-up,
escaped + contract-derived spawn command.

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

* docs: record round-3 rig validation status for agent status over WSL (STA-1515)

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

* fix(agent-hooks): round-4 adversarial-review fixes for the WSL hook relay (STA-1515)

- dropState identity race: recovery re-checks state identity after the
  distro-running probe await, and the manager's dropState only deletes the
  exact state it was armed for — an ensure() landing mid-probe can no longer
  have its fresh relay orphaned outside the map.
- Distro-running probe fails CLOSED: a probe error no longer reports
  'running', so recovery can never wsl-d-boot a distro the user shut down.
- Relay spawns use --exec: bypasses the distro's default login shell
  (fish/nushell chsh) and passes argv verbatim, dropping the $-escape shim;
  same form as the Codex WSL login spawn.
- Post-sentinel chunk handoff rides a microtask so an envelope in the
  trailing bytes can no longer dispatch before the link's notification
  handler is registered.
- Guest relay mirrors the SSH relay's uncaughtException/unhandledRejection
  posture.
- Replay cache capped at 256 panes with recency eviction (the WSL relay has
  no per-pane teardown signal); meta map kept in lockstep.
- Launch script derives the stale-exit code from the shared contract
  constant; one-shot reinstall timer refuses to arm after dispose.
- New oracles: sentinel unit suite, fs-bridge scoping suite, fixed-token
  403/204, EADDRINUSE endpoint-file rewrite, cache-cap eviction, and the
  recovery/manager race regressions (verified to fail with fixes reverted).
- Doc: round-4 review section + revised curl.exe stance (kept as the
  no-node fallback — Codex is a native binary; fresh distros ship no node).

* docs: record round-4 pinned rig validation for agent status over WSL (STA-1515)

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 00:19:45 -07:00
Jinjing 69befad13e Harden layout validation, watcher lifecycle, and connection robustness (#7924)
* 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.
2026-07-09 16:09:09 -07:00
Jinjing ee823b766c Move notification status helper to Contents/MacOS (#7931)
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.
2026-07-09 03:07:05 -07:00
Jinwoo Hong da0f03fc2a Sign Windows inner binaries during release (fail-open two-request SignPath flow) (#7866) 2026-07-09 01:29:10 -04: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
Jinwoo Hong 20832ef36f ci(daemon): fail builds, packaging, and CI when the terminal daemon cannot start — and stop failing silently (#7849) 2026-07-08 19:46:14 -04:00
Jinwoo Hong dfc12f2cf6 fix(watcher): isolate @parcel/watcher in a forked process so native crashes can't kill the app (#7547) (#7757) 2026-07-07 22:10:22 -04:00
bea9b38544 Fix OMP worktree title identity flicker
* Fix OMP worktree title identity flicker

* Add headless fresh pairing server script

* Harden fresh pairing server script startup

* Default fresh pairing server to reachable address

* review: harden OMP tab identity validation

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

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-07 13:51:25 -07:00
NeilandOrca f311307560 Add max-lines ratchet CI gate to block new line-limit bypasses (#7608)
oxlint already fails any file over max-lines that is not suppressed, so the
only way to grow past the budget is to add an eslint/oxlint-disable max-lines
comment or a per-file max-lines bump in mobile/.oxlintrc.json. This adds a CI
gate that freezes the current set of suppressions (config/max-lines-baseline.txt,
355 grandfathered entries) and fails the build when a NEW one appears — with a
loud, actionable message pointing at 'split the file'. Existing oversized files
are untouched; the baseline may only shrink (pnpm check:max-lines-ratchet --prune).

Wired into the root lint script and as a dedicated pr.yml step. Unit-tested
(15 cases) and verified against all three failure paths + clean-tree pass.

Co-authored-by: Orca <help@stably.ai>
2026-07-06 17:12:27 -07:00
Jinjing 3dd3cc9f68 Clarify Orca orchestration tool boundary and sidebar lineage (#7522)
* Clarify Orca orchestration tool boundary and sidebar lineage

Add a "Tool Boundary" section to the orchestration skill, requiring
explicit Orca runtime state instead of generic subagent tools or
chat-only parallel workers. Also add tests to verify the tool boundary
and clarify sidebar lineage for same-worktree workers.

* Clarify worktree lineage guidance and parent-child boundaries

Update orchestration guidance and tests to clarify when to use child versus
top-level worktree lineages, and when to prefer same-worktree workers.

* Require stating the desired Orca lineage before creating a worktree from
  an active feature branch.
* Limit child worktrees to conceptually stacked or dependent tasks.
* Prefer same-worktree workers unless isolated checkouts are explicitly
  needed and do not require uncommitted changes.
2026-07-06 00:05:49 -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
Jinjing c97d3a4977 Replace post-worker_done polling with idle behavior (#7509)
- Instruct workers to stop and idle or exit immediately after sending
  `worker_done`, rather than running a 10-minute polling loop.
- Distinguish instructions based on worker kind: prompt-returning
  agents should remain idle for re-engagement, while bare-shell
  workers should exit.
- Prevent infinite polling overhead since the coordinator re-engages
  workers via fresh terminal input instead of inbox polling.
2026-07-05 23:10:20 -07:00
Jinwoo Hong 6a4b89785c revert: back out the Windows terminal update-survival chain (#7421→#7499) (#7505)
* Revert "Preload the daemon windowsHide shim via --require; wrap promisify custom (#7499)"

This reverts commit 8f396badaf.

* Revert "Hide console windows for children of the node.exe-hosted daemon (#7486)"

This reverts commit f0fdd3a716.

* Revert "fix(daemon): relocate daemon host image out of the install-dir kill zone (#7473)"

This reverts commit f4faafa987.

* Revert "fix(pty): keep runtime dirs a surviving daemon still uses (#7463)"

This reverts commit 3cd23a13a1.

* Revert "Relocate node-pty ConPTY runtime outside the Windows install dir (fixes update-time terminal loss) (#7421)"

This reverts commit 509c41e2bf.
2026-07-05 22:50:48 -07:00
f4faafa987 fix(daemon): relocate daemon host image out of the install-dir kill zone (#7473)
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
2026-07-05 19:52:06 -07:00
Bevis a3e34b66b8 fix(pet): stop i18n from corrupting CSS keyframes
Keep PetOverlay runtime keyframes out of localization so translated locales cannot invalidate sprite or bob animations.\n\nAlso adds regression coverage for translated-locale keyframe CSS and removes the stale generated locale entries.
2026-07-04 14:43:57 -07:00
Neil bec4392d87 cleanup(main): defer serve-sim materialization, dedupe reload flags, guard gate validators (#7321)
Quality pass on main-process/build PRs merged 2026-07-03:

- ios-emulator-backend: resolve the serve-sim executable via a lazily-cached getter
  instead of eagerly in the constructor. The bridge is built before the main window
  is shown, so the one-time recursive copy + xattr subprocess (first launch after each
  version bump) no longer blocks macOS startup for a feature that may go unused (#7174).
- index: collapse the two near-identical `{webContentsId, until}` reload flags
  (expectedRendererReload / recoveryReloadInFlight) into one `createWebContentsTimedFlag`
  primitive; behavior preserved, including consume-on-read for the recovery reload (#7290).
- check-reliability-gates: coerce gate.commands/testFiles/platforms/providers with an
  `asArray` helper before `.includes`, so a hand-edited manifest with a missing/mistyped
  field reports a validation failure instead of throwing an uncaught TypeError; extract
  `hasCompleteRedGreenEvidence` for the duplicated status check (#7295).
- claude-pty: derive FABLE_WEEKLY_LABEL_RE from WEEKLY_RE.source so a future weekly-
  wording change stays in one place and can't reopen the parsing gap it just closed.
- macos-tcc-login-shell: trim the 30-line flag-by-flag JSDoc to the two non-obvious whys
  (TCC identity, env(1) SHELL re-assertion) per the repo comment guidance (#7003).

Typecheck, oxlint, oxfmt, `check:reliability-gates`, and touched unit suites all pass.
2026-07-03 22:32:11 -07:00
Jinjing b2fcbdbc73 fix: bound release notes by published releases (#7311) 2026-07-03 20:53:16 -07:00
5b5ce6cef8 Harden reliability gate policy and register merged terminal regression tests as gates (#7295)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: brennanb2025 <delta-eng@stably.ai>
2026-07-03 19:58:07 -07:00
Brennan BensonandOrca 1282f5c2da Add reliability gate manifest (#7001)
Co-authored-by: Orca <help@stably.ai>
2026-07-03 19:26:00 -07:00
Alexander 99d61b13b2 Bound generated release notes by previous tag (#5649)
Fixes #5579. Pass previous_tag_name to GitHub generate-notes so draft-release notes stop accumulating across releases; omit it safely on first release. Adds tag parse/compare + paginated tag fetch and regression tests.
2026-07-03 14:22:47 -07:00
Brennan Benson 087ad66aa2 Revert "Ship serve-sim camera dylib as data and materialize it at runtime" (#7172) 2026-07-02 18:46:00 -07:00
Brennan BensonandOrca f44cb3059b Ship serve-sim camera dylib as data and materialize it at runtime (#7168)
Co-authored-by: Orca <help@stably.ai>
2026-07-02 18:24:23 -07:00
Brennan Benson d6fb8e04f9 Revert "Notarize serve-sim camera dylibs in macOS releases" (#7165) 2026-07-02 18:05:50 -07:00
Brennan BensonandOrca ee8bdf1aac Notarize serve-sim camera dylibs in macOS releases (#7077)
Co-authored-by: Orca <help@stably.ai>
2026-07-02 16:42:56 -07:00
Jinwoo Hong 2ce9314acb Improve Windows terminal performance: retain WebGL contexts, warm first ConPTY (#7085) 2026-07-02 18:41:23 -04:00
Brennan BensonandNeil 49a8e80526 Temporarily bypass Windows inner signature gate (#7137)
Co-authored-by: Neil <neil@stably.ai>
2026-07-02 12:34:35 -07:00
Brennan BensonandNeil d2d3e90c96 Fix Windows inner signature PowerShell path (#7136)
Co-authored-by: Neil <neil@stably.ai>
2026-07-02 12:11:58 -07:00
Brennan BensonandNeil fc17c57b6b Fix Windows SignPath PSGallery preflight (#7135)
* Verify Windows app executable signing

* Isolate Windows signing verifier tests

* Handle direct Windows installer extraction

* Fix SignPath PowerShell gallery preflight

---------

Co-authored-by: Neil <neil@stably.ai>
2026-07-02 11:42:44 -07:00
Brennan BensonandNeil 85cec26773 Prevent unsigned Windows app releases (#6806)
* Verify Windows app executable signing

* Isolate Windows signing verifier tests

* Handle direct Windows installer extraction

---------

Co-authored-by: Neil <neil@stably.ai>
2026-07-02 10:54:19 -07:00
Brennan BensonandOrca df6e5d56a7 Test arm64 ConPTY payload packaging (#6970)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 18:22:08 -07:00
Brennan BensonandOrca 22db5b78d6 Fix Windows bundled ConPTY packaging (#6968)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 18:05:38 -07:00
Neil 7cfae28115 ci: isolate Blacksmith mac release build (#6962) 2026-06-30 16:36:59 -07:00
Brennan BensonandOrca 9408cadb80 ci: keep release workflow GitHub-hosted for SignPath (#6946)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 14:58:43 -07:00
Brennan BensonandOrca 16de859fdf ci: isolate mac release build from SignPath matrix (#6937)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 13:55:48 -07:00
Brennan BensonandOrca 22e9c4f4bb ci: pin Windows release runner to VS 2022 (#6932)
Co-authored-by: Orca <help@stably.ai>
2026-06-30 13:21:32 -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
NeilandOrca 46646d7ff1 chore(lint): upgrade oxlint to 1.71 + enable 7 new rules (autofixed backlog) (#6841)
* chore(lint): upgrade oxlint to 1.71 and enable 7 new rules

Upgrade oxlint 1.67.0 -> 1.71.0 (1.72 was blocked by the repo's 3-day
minimum-release-age supply-chain guard; nothing here needs it). The
bump is a no-op on the existing config.

Enable 3 error rules (backlog autofixed to zero in this commit) and
4 warn rules (surface signal without gating CI):

error (autofixed, behavior-preserving):
- unicorn/prefer-node-protocol        (~1531 sites: bare builtin -> node:)
- typescript/no-import-type-side-effects (~36: all-inline-type -> import type)
- unicorn/no-array-reverse            (19: copy-then-reverse -> toReversed)

warn (real signal, current fires are test-only/correct):
- unicorn/no-array-fill-with-reference-type  (aliasing footgun guard)
- typescript/no-unsafe-function-type         (bans bare Function type)
- unicorn/prefer-array-flat-map              (map().flat() -> flatMap())
- unicorn/prefer-regexp-test                 (.match() in bool ctx -> .test())

mobile/.oxlintrc.json extends root, so it inherits all 7; the autofix
ran from root and covered mobile/ too.

Verification (all green): oxlint 0 errors (root+mobile+aux configs),
oxfmt clean, typecheck (node+cli+web), vitest 22795 passed / 0 failed,
builds (electron-vite + web + cli) succeed. node: rewrites confirmed to
skip embedded SSH/CLI string payloads (AST-only); all toReversed sites
verified to operate on fresh copies or write-once locals.

* chore(lint): bump mobile oxlint to 1.71 so inherited rules parse

mobile/ is a standalone pnpm project pinning its own oxlint@1.67, which
lacks unicorn/no-array-fill-with-reference-type (needs >=1.70). Since
mobile/.oxlintrc.json extends the root config, mobile CI's 'cd mobile &&
oxlint' failed to parse the new rule. Bump mobile to match root (1.71).

Verified in mobile/: oxlint 0 errors, oxfmt --check clean, tsc --noEmit
pass, vitest 978 passed / 0 failed.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:38:29 -07:00
Miguel Echávarri cd03928e94 fix(i18n): correct Spanish "PR" mistranslated as "relaciones públicas" (#6749)
Machine translation rendered the abbreviation "PR" (pull request) as "relaciones públicas" (public relations) across 32 Spanish UI strings — e.g. "Reabrir relaciones públicas" (Reopen PR), "Crear relaciones públicas" (Create PR), "Abrir cheques de relaciones públicas" (Open PR checks).

Adds the missing `es` rule to LOCALE_PHRASE_FIXES. Because "relaciones públicas" is a real Spanish phrase (unlike the CJK-only ko/zh patterns 홍보/公关), the rule guards on the actual `PR`/`PRs` token via a new optional `whenEnMatches` RegExp guard in applyPhraseFixes, so it never fires on unrelated English that merely contains a "pr" substring (approve, preview, press). `whenEnMatches` is backward compatible — existing `whenEnIncludes` rules are unchanged.

Regenerates the 32 affected es.json leaves. Adds a vitest spec covering the rewrites and a negative case proving the token guard ignores genuine "public relations" strings.
2026-06-29 11:56:26 -07:00
NeilandOrca 9f94ccdb8f perf(emulator): prune serve-sim dedupe keys on worktree forget (#6708)
Co-authored-by: Orca <help@stably.ai>
2026-06-28 23:41:14 -07:00
NeilandOrca c96d8e3b5a perf(emulator): return MJPEG frames as views instead of per-frame copies (#6707)
Co-authored-by: Orca <help@stably.ai>
2026-06-28 23:40:55 -07:00
mehmet turac 19eeacfad3 fix: pin CLI build output to CommonJS (#6656) 2026-06-28 22:58:27 -07:00
NeilandOrca ad87bb0123 perf(editor): skip markdown TOC parse while the panel is closed (#6695)
The rich markdown editor rebuilt the entire Table-of-Contents outline on
every content change by running a full-document remark parse
(buildMarkdownTableOfContents), then discarded the result whenever the TOC
panel was closed — which is the default state. The parse is driven by the
300ms-debounced serialize path, so it fired ~3x/sec during sustained typing,
with cost scaling linearly with document size.

Gate the memo on showTableOfContents so the parse only runs when the panel is
actually open. Including showTableOfContents in the deps rebuilds the outline
the moment the panel opens, so there is no stale TOC.

Benchmark (config/scripts/markdown-toc-parse-benchmark.mjs), per content
change while typing:
  175 KiB doc / 200 headings -> ~65 ms median  (13.2 s cumulative over a
                                                 ~1 min typing burst)
  351 KiB doc / 400 headings -> ~138 ms median (27.8 s cumulative)
With the fix this drops to ~0 ms while the panel is closed.

Adds a unit test proving the parse is skipped (and a stable empty-array
reference returned) while closed, and still runs when open.

Co-authored-by: Orca <help@stably.ai>
2026-06-28 21:19:10 -07:00
NeilandOrca 5db5b23257 perf(renderer): drop per-tick matchMedia alloc + purge hibernation epoch map (#6696)
Co-authored-by: Orca <help@stably.ai>
2026-06-28 21:16:02 -07:00
Jinjing 2edfad0fc6 Clarify full handoff routing guidance (#6687) 2026-06-28 19:51:14 -07:00
Neil 0976f9427c fix(linux): disable GPU sandbox to stop terminal input freeze on Wayland (#5319) 2026-06-28 19:43:18 -07:00
Brennan BensonandOrca e58a5e9e17 Simplify Appearance settings (#6459)
Co-authored-by: Orca <help@stably.ai>
2026-06-28 11:50:29 -07:00
Brennan Bensonandbrennanb2025 74d564a67e fix(windows): trim macOS safe-area inset so app icon fills the canvas (#6548)
The Windows ICO was rasterized straight from the untrimmed 1024px macOS
render, inheriting Icon Composer's transparent safe-area inset (glyph only
~83% of the canvas). Windows scales the largest ICO frame down for the
taskbar/"Open with" list without compensating, so the icon looked visibly
small next to native apps.

Add config/scripts/trim-windows-icon-source.mjs (pngjs-based): trims the
transparent inset, re-squares with a small 2% margin, and emits a filled
multi-size ICO (~96% fill). Regenerate resources/build/icon.ico from it and
update generate.sh to delegate to the script so the committed binary stays
in sync regardless of whether ImageMagick is installed.

Fixes #5357

Co-authored-by: brennanb2025 <brennanb2025@users.noreply.github.com>
2026-06-28 00:30:24 -07:00
Brennan BensonandOrca c6299f8b85 Improve Windows release signing reliability (#6292)
Co-authored-by: Orca <help@stably.ai>
2026-06-24 14:24:42 -07:00
Brennan BensonandOrca 4ac1e960d4 Harden Orca CLI skill security guidance (#6131)
Co-authored-by: Orca <help@stably.ai>
2026-06-24 13:55:53 -07:00