* fix(agent-hooks): refresh existing shared hook scripts when the CLI is no longer detected
A CLI that falls off PATH (moved npm prefix, relocated shim) keeps its user-wide
config invoking Orca's launcher script under ~/.orca/agent-hooks, but the
presence gate skips install() with no removal — freezing the script at whatever
Orca generated last. Anyone in that state kept the pre-#11568 more.com-leaking
.cmd forever, because no launcher script is ever deleted and Windows startup
deliberately skips shell PATH hydration.
Reconcile before gating: every existing shared launcher/statusline script is
rewritten to the current template on each install pass. Creating scripts stays
behind the presence gate — an existing file is proof of a prior install; a
missing one means the gate did its job. Amp and Hermes are deliberately absent:
they write provider-native plugin code with its own install lifecycle, not
shared launchers.
- refreshManagedScriptIfPresent() in installer-utils (no-op unless the file exists)
- refreshManagedScripts() on the 11 launcher-writing services (openclaude via
the shared Claude class)
- reconcile pass in installManagedAgentHooks before presence detection,
filtered by the agents option, best-effort per agent
- coverage gate: a launcher written to ~/.orca/agent-hooks without a matching
refresher entry fails the suite, in both directions
* perf(agent-hooks): refresh launchers off the main thread
* test(agent-hooks): keep refresh mode assertion POSIX-only
Collapse multi-line explanatory comment blocks into single-line "why" statements
per AGENTS.md ("Document the Why, Briefly"): drop restatements of the code and
mechanism narration; keep the non-obvious reason, external refs, and directives.
Comments-only — verified no code changed via a Babel/esbuild comment-strip
token-equality gate against origin/main; typecheck and oxlint clean.
Area: main — git, source-control, providers & integrations. 40 files changed, 1432 insertions(+), 4473 deletions(-).
Co-authored-by: Orca <help@stably.ai>
Codex, Antigravity, and Devin launch their agent-hook `command` as a program
(argv[0]), not through cmd.exe. PR #8430 changed wrapWindowsCmdHookCommand to
emit an `if exist "path\." (drain) else if exist "path" (call "path") else
(drain)` compound whose argv[0] is the cmd builtin `if` — unspawnable — so every
Codex/Antigravity/Devin hook (SessionStart, UserPromptSubmit, Stop, ...) failed
with "hook exited with code 1" on Windows starting in v1.4.138.
Revert the cmd-safe fast path to the bare, directly-spawnable .cmd path (the
proven pre-#8430 form). A cmd-builtin drain and direct-spawnability are mutually
exclusive, and nesting cmd.exe /d /c breaks large-payload draining; the
missing-script stdin drain stays on the encoded-PowerShell fallback (used for
spaced/non-ASCII paths). Upgrades self-heal on first launch: startup install()
unconditionally rewrites the command and Codex trust entry, sweeping the old
compound form.
Add a platform-independent regression guard (launcher must resolve to a real
file, never a cmd-builtin fragment), update the lifecycle test + docs, and fix a
stale Devin comment.
* Fix hook scripts to drain stdin before any early-exit path
Generated agent hook scripts and missing-script launchers could exit
successfully before consuming the payload written to their stdin,
leaving the writer with a broken pipe (EPIPE/ERROR_BROKEN_PIPE) once
the reader closed early. Capture stdin (or drain it via a shared
epilogue/fast-path guard) before any whole-script success exit across
all POSIX, batch, PowerShell, and Git Bash launcher variants, and add
a cross-agent lifecycle test suite plus a live Electron verification
script to guard the contract going forward.
* Harden hook scripts against unreadable managed scripts and add a Claude/
- Extend the POSIX launcher guard to also require `[ -r ]`, not just `-f`/`-x`,
so an executable-but-unreadable managed script still drains stdin instead of
erroring or silently misbehaving.
- Add a verifier case (`verifyClaudeDevinSkip`) that spins up a local HTTP
server and confirms the Claude hook never forwards a request that Devin
already imported, catching accidental double-forwarding.
- Update installer-utils tests and stdin-lifecycle docs to match the new
readable-file guard and the added verification case.
* Fix hook-launcher verification to derive script paths from the installed
Extract the quoted path from the launcher's `if [ -f '...'` clause instead of
reconstructing it via join(home, ...), so missing/failing-script test cases
can't silently fall through to the real script if the install layout changes.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
The POSIX agent-hook script for every curl-based agent inlined the full
event payload via `curl --data-urlencode "payload=${payload}"`. Tool
output can be tens of KB, so the resulting process command line could be
multi-KB — which endpoint security tools (e.g. Microsoft Defender for
Endpoint) flag as an oversized/suspicious command line. That produced a
false-positive detection on Orca's own loopback (127.0.0.1) telemetry POST.
Stream the payload to an mktemp file and post it with
`--data-urlencode "payload@$payload_file"` instead. The urlencoded body on
the wire is byte-identical, so the agent-hook receiver is unchanged; the
payload simply never appears on a process command line. `trap ... EXIT`
removes the temp file on every exit path. Small bounded metadata fields
(paneKey/tabId/worktreeId/env/version) stay inline.
Applied to all curl-based agents: claude, codex, command-code, copilot,
cursor, droid, gemini, grok, antigravity. (amp/hermes/opencode post via
the HTTP request body and were never affected.) The Windows post-command
shares the same latent pattern and is flagged as follow-up.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
* 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>
Speed up Windows CLI launch by delivering short startup commands through shell args, falling back to stdin for oversized commands, and moving Codex historical session bridging into an incremental background task. Includes review fixes for Windows symlink and WSL test reliability.
* Revert "fix(terminal): add proportional scroll fallback for sidebar resize" (#937)
* fix(sidebar): smoothly animate off-screen worktree reveal on click (#1302)
Clicking a worktree card whose row lies outside the sidebar viewport
caused an instant jump when scrolling it into view. Switching
`scrollToIndex` to `behavior: 'smooth'` turns that minimum-distance
scroll into an animated slide while keeping `align: 'auto'` so visible
cards still no-op (no re-centering).
Co-authored-by: Orca <help@stably.ai>
* Avoid local scrollback serialization on shutdown (#1821)
* Fix PR refresh coordinator test arguments (#2545)
* release: v1.4.31
* release: v1.4.31
* release: v1.4.31
* release: v1.4.31
* release: v1.4.31
* release: v1.4.31
* release: v1.4.31
* release: v1.4.36-rc.6
* release: v1.4.36-rc.6
* release: v1.4.36-rc.6
* ci: gate release-cut to the canonical repo so it skips forks (#4815)
The cut job checks out main, bumps package.json's version, and
fast-forwards main. On a fork with Actions enabled, the scheduled RC
cut runs against the fork's main and diverges it on the version line
every slot, so that contributor's PRs back to upstream conflict on
package.json even when their change never touches it.
Gate the job to github.repository == 'stablyai/orca' so it (and the
jobs that depend on it) no-op on forks. Canonical scheduled and manual
cuts are unaffected.
* feat(hooks): install Devin managed status hooks
* feat(devin): address hook review, resume, and UI polish
- Parse Devin config.json as JSONC; warn on read_config_from overlap
- Windows hook command uses forward slashes; APPDATA fallback
- Add devin to sleeping-agent resume and UI registries (plan 003/004)
- Add hook-service and hook-config-json tests
Closes follow-up for plans 002–004 on feat/add-devin-agent.
* feat(devin): scan ATIF transcripts for AI Vault
Register devin in AI_VAULT_AGENTS, discover ~/.local/share/devin/cli/transcripts
(or DEVIN_HOME), parse ATIF JSON sessions, and build devin --resume commands.
* docs(devin): clarify stdin-after-start vs bracketed paste
* fix(devin): use JSONC for remote install, add partial+APPDATA tests
- installRemote: replace readHooksJsonRemote (JSON.parse) with
readTextFileRemote + parseJsonc for JSONC compatibility on SSH
- Add partial status test (some hooks missing → state:'partial')
- Add Windows APPDATA config path test with fallback
* fix(devin): address CodeRabbit review — sessionId fallback, parseJsonc errors, comment, i18n
* Fix Devin integration edge cases
Co-authored-by: Orca <help@stably.ai>
* Package Devin JSONC parser dependency
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Trevin Chow <trevin@trevinchow.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>