Commit Graph
16 Commits
Author SHA1 Message Date
Neil a8f1a2d98c fix(startup): drop the other-cased PATH key from the Windows probe env
Caught by running the suite on a real Windows machine, not a mocked
platform. The spread of process.env is a plain, case-sensitive object,
while Windows resolves env names case-insensitively. Writing the captured
`Path` back onto it left the seeded value still live under `PATH`, so the
probe shell could read either one — the exact duplicate-key hazard the
win32 branch was supposed to prevent.

Drop any other-cased variant of the key before writing.
2026-08-24 19:21:52 -07:00
Neil ccd246a613 fix(startup): snapshot the launch PATH at module load, log probe failures
Three loose ends from the review, folded in rather than deferred.

The probe's clean PATH was handed over by an explicit recordLaunchPath call
from the seeding site, so the invariant lived across three files and a
refactor that moved the seed call would silently re-pin nvm. Snapshot PATH
during module init instead: that runs while the import graph is evaluated,
strictly before any statement in main's body, so it cannot observe the
seeds and there is no call ordering left to break. All seven importers are
static, so no lazy import can defeat it. A test asserts the probe ignores
later process.env mutation, and fails if the live read is reintroduced.

A failed startup probe leaves the seeded newest-nvm dir in front and said
nothing, so the population whose rc files blow the 5s budget hit the
original symptom with no diagnosable trace. Log the failureReason.

The probe is an interactive login shell, so rc files that exec into a
multiplexer or start a heavy prompt can outrun that budget with no way to
opt out. Set ORCA_SHELL_PATH_PROBE=1 so they can take a fast path.
2026-08-24 19:17:30 -07:00
Neil 335a3ded4f fix(startup): give win32 the same probe insulation, keyed by Path
The previous commit exempted win32 on the stated grounds that no Windows
seed pins a node version. That is wrong: getVersionManagerDirectories
calls getNvmVersionDirectories on every platform, so a Git Bash user whose
nvm uses the POSIX ~/.nvm/versions/node layout gets the newest version dir
seeded on Windows too, and the -ilc Git Bash probe inherits it.

Record the PATH key alongside the value and overwrite that entry in place,
so Windows never carries both `Path` and `PATH` — which was the only real
reason to skip win32.
2026-08-24 18:58:27 -07:00
Neil ac4690b248 test(startup): pin the platform in the probe-env test
shellProbeEnv short-circuits on win32, so the POSIX-only assertion failed
for anyone running the suite on Windows. Matches the convention in
hydrate-shell-path.windows.test.ts.

Also narrows the win32 exemption comment: WindowsShellPathOwnership
snapshots its baseline after the seeds land, so it does not unwind them.
The exemption holds because Windows keys PATH as `Path` and no Windows
seed pins a node version.
2026-08-24 18:38:15 -07:00
Neil 8703969ca9 fix(startup): stop the PATH seed pinning nvm to its newest install
patchPackagedProcessPath prepends the newest nvm version dir to
process.env.PATH, then hydrateShellPath probes the login shell with that
same env. nvm's startup `use` honors whatever node is already on PATH
instead of the user's `default` alias, so the probe returns a PATH pinned
to the newest install and every terminal pane inherits it.

A user whose newest nvm node is a bare install then loses every global CLI
(codex, claude, gemini, vercel...) inside Orca while they still resolve in
Ghostty/Terminal, which start from the bare GUI PATH and fall through to
`default`.

Probe with the PATH the process launched with. Windows already gets this
through WindowsShellPathOwnership.
2026-08-24 15:41:41 -07:00
OrcaWin c96ded8dfd fix(startup): restore Windows PATH before shell changes (#13792) 2026-08-11 11:50:21 -07:00
OrcaWin 75650936f4 fix(source-control): hydrate Windows shell profile PATH (#13418) 2026-08-09 18:42:15 -07:00
NeilandOrca aab112933e Revert "fix(memory): bound OOM-prone accumulators (#10179)" (#10255)
Co-authored-by: Orca <help@stably.ai>
2026-07-23 18:35:31 -07:00
Neil 8f40ddf328 fix(memory): bound OOM-prone accumulators (#10179) 2026-07-23 06:22:56 -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
Neil 1a22e2d05c UX/copy tweaks (#5142)
* UX/copy tweaks

* UX/copy tweaks
2026-06-10 19:53:03 -07:00
Jinwoo HongandOrca 6d7d25f784 Fix packaged shell PATH order (#5125)
Co-authored-by: Orca <help@stably.ai>
2026-06-10 14:03:55 -07:00
Jinwoo Hong 5f6b454c3a perf(windows): fix 60s startup ACL walk and OpenCode streaming freeze, with benchmark harnesses (#5124) 2026-06-10 16:41:22 -04:00
Neil d0aa82864b fix: clean up shell path timeout listeners (#3756) 2026-05-30 09:01:02 -07:00
Brennan BensonandOrca 98b15aeabc feat(telemetry): instrument on_path:false triage on onboarding_agent_picked (#1674)
* feat(telemetry): instrument on_path:false triage on onboarding_agent_picked

Adds path_source and path_failure_reason to onboarding_agent_picked so the
~30% on_path:false rate on dashboard 1562016 can be split between shell
hydration failures and genuinely-not-on-PATH cases before picking a fix.
See docs/agent-on-path-detection.md.

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

* fix(telemetry): close PathSource compile-time-sync hole

Add `_PathSourceSync` guard mirroring `_PathFailureReasonSync` so adding
a new `PathSource` value to the alias without updating the schema (or
vice versa) fails the build. Without it, drift would silently drop
`onboarding_agent_picked` at the strict validator. Also replace stale
line-number references in docs/agent-on-path-detection.md with named
function/handler references that survive future edits.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 15:47:14 -07:00
Neil 9d56108e89 fix(agents): detect all user-installed CLIs by hydrating PATH from login shell (#843)
* fix(agents): detect opencode/pi CLIs installed under ~/.opencode/bin and ~/.vite-plus/bin

Packaged Electron inherits a minimal PATH without shell rc files, so
agent install-script fallback dirs stay invisible to `which` probes —
the Agents settings page then shows OpenCode/Pi as "Not installed"
even when the user can run them from Terminal.

Add ~/bin, ~/.opencode/bin, and ~/.vite-plus/bin to the packaged PATH
augmentation so preflight detection matches shell behavior.

Fixes #829

* feat(agents): hydrate PATH from user's login shell + Agents Refresh button

Packaged Electron inherits a minimal launchd PATH that misses whatever
the user's shell rc files append — ~/.opencode/bin, ~/.cargo/bin, nvm
shims, pyenv, custom tool dirs. The preceding commit hardcoded two known
install locations; this replaces that whack-a-mole pattern with a
generic approach.

On packaged startup (non-Windows), spawn `${SHELL} -ilc 'echo $PATH'`
with a 5s timeout, parse the delimited PATH, and prepend any new
segments to process.env.PATH. The result is cached for the app session
so we pay the shell-init cost at most once.

Surface a Refresh button in Settings > Agents that forces a re-probe
and re-detects installed agents — handy right after installing a new
CLI, no restart needed.

Live-verified that a `zsh -ilc` spawn with a minimal launchd-style env
still resolves the user's full PATH (32+ segments including the
rc-appended dirs).

* refactor(hydrate-shell-path): simplify dedup with Set + Set.difference

Set preserves insertion order, so PATH first-match-wins semantics are
preserved without manual tracking. Set.prototype.difference (Node 22+)
expresses the new-segments calculation in mergePathSegments as the
set-difference operation it always was.
2026-04-19 14:36:30 -07:00