mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
* perf(claude): run the Windows Claude hook as a native orca-hook.exe
Each Claude hook event on Windows started cmd.exe (plus the user's cmd
AutoRun) and then curl.exe on top of the agent's own shell. A small signed
Rust binary now does the same synchronous POST in one process, under Git
Bash, PowerShell and direct CreateProcess alike.
- native/windows-agent-hook: std-only crate, same contract as the .cmd hook
(prints {}, env guards before stdin, endpoint re-read, 0.5s/1.5s caps,
waits for the listener reply, always exit 0). Its installed file name
selects the agent profile, so the registration stays a bare path.
- Packaged as resources/bin/orca-hook.exe (SignPath signs it with the other
inner PEs); afterPack fails on a missing or wrong-machine binary.
- Claude install copies it verbatim to ~/.orca/agent-hooks/claude-hook.exe
(temp + rename, running copy moved aside) and registers it; it falls back
to the .cmd hook when the bundle is missing, unsigned or cannot be copied.
Only Claude opts in, via windowsNativeHookExecutable.
- The managed-command matcher sweeps .exe entries alongside .cmd/.ps1/.sh.
- The CLI launcher and hook builds share windows-rust-executable-build.mjs,
which now also checks the PE machine.
Refs #20913
* fix(build): publish native Windows binaries atomically so parallel builds cannot collide
The Windows CI lane runs every orca-hook.exe suite in one vitest
invocation, each building through build-windows-agent-hook.mjs. The build
copied straight onto native/windows-agent-hook/.build/orca-hook.exe, and
CopyFile opens its destination unshared, so a second build (or a scanner
still holding the fresh image) failed with EBUSY.
- windows-rust-executable-build.mjs skips the publish when the output
already has the built bytes, otherwise stages a per-process temp file and
renames it over the output, retrying briefly while another handle holds it.
- The test fixture hands each suite a private copy of the build output, so
no suite reads or starts the shared file while another build replaces it.
Refs #20913
* refactor(claude): simplify the native Windows hook to one Claude binary
Review follow-up on the native hook (#20913): the same behaviour with less
machinery.
- The binary is built, shipped and installed as claude-hook.exe, so the
installed name matches its PE OriginalFilename. It is Claude-only, so the
file-name profile table and the per-agent opt-in flag are gone; the
registration is gated by the existing Claude-only usesWindowsEntry check.
- Install and refresh reuse writeManagedScript / refreshManagedScriptIfPresent
(now accepting bytes): temp file, rename, skip when identical. A copy whose
hook is still running cannot be replaced; install then registers the .cmd
hook and refresh keeps the old build until a later start, instead of the
rename-aside and *.retired sweep.
- The install-time Authenticode-presence check is dropped. Release CI now
requires resources\bin\claude-hook.exe to be signed (release-cut and the
signing rehearsal), next to resources\bin\orca.exe.
- getStatus counts either Windows form through findManagedEventHookForms in
hook-settings.ts, replacing managed-event-hook-status.ts.
- Rust: plain Claude constants, one endpoint-file lookup (last assignment
wins, as under `call`), one request write and a deadline-bounded drain.
Guard order and form encoding are unchanged.
- Build: PR CI builds the hook once before the Windows tests, so the suites
only read it; the launcher publish goes back to copyFileSync and the retry
loop and its test are gone. The PE-machine check lives only in afterPack.
Cargo.lock joins both crates' build fingerprints, and the launcher's alias
exports are removed.
Refs #20913
* test(ci): run the managed hook stdin-lifecycle suite in the Windows lane
Its claude-hook.exe case (and the other Windows-only cases) are gated per
test, so the lane-registration guard did not require the file and it ran
only on Linux, where those cases skip. Register it in both Windows lists.
Refs #20913
* feat(agent-hooks): ship the native hook as orca-agent-hook.exe <agent>
The native Windows hook (#20913) becomes one general binary that stays
Claude-only in behaviour.
- Named orca-agent-hook.exe everywhere: build output, PE OriginalFilename
and InternalName, resources\bin, the afterPack check, the installed copy
in ~/.orca/agent-hooks, and the release signed-target lists.
- It takes the agent as its first argument and Claude registers
`<path> claude`. The CLAUDE_JOB_DIR exit and the Grok/Devin drain belong
to that agent; an unknown or missing agent answers {} without reading
stdin. The managed-command matcher owns `orca-agent-hook.exe claude` and
still owns the old claude-hook.exe entry, so installs migrate; install
deletes a leftover claude-hook.exe when nothing runs it.
- A copy still running from the previous build no longer forces the .cmd
fallback. Identical bytes are not rewritten; otherwise the temp file is
renamed over the target, and when Windows refuses because the image is
mapped, the running copy is renamed to orca-agent-hook.exe.old first.
Install deletes a stale .old; only when that copy is also still running
does the install fall back to .cmd. writeManagedScript and
refreshManagedScriptIfPresent take the aside path, sharing one helper.
Refs #20913
* fix(agent-hooks): roll back a failed aside rename and keep an installed hook exe
Design-review follow-up on the native hook (#20913).
- If the running copy was moved to orca-agent-hook.exe.old but the new
file then could not take its name, the copy is renamed back before the
error is rethrown, so settings.json never points at a missing exe. The
rename helper now owns the `.old` name, next to the comment that
explains it; a mocked-fs unit test covers both the sync and async paths.
- A failed write, or a build with no bundled exe, keeps registering a copy
that is already installed (every build knows `claude`), so a dev checkout
and an installed build no longer flip settings.json between forms.
- The claude-hook.exe migration is gone: no release ever shipped that
name, so the legacy sweep, the `.exe` matcher needle and their test are
removed.
Refs #20913
* fix(agent-hooks): derive the native hook's agent with win32 path rules
getWindowsNativeHookAgent took the host's basename of the managed script
path, so on a POSIX host (Linux CI) a Windows path was not split and the
registered command became `orca-agent-hook.exe C:\...\claude`. It now takes
the path and applies path.win32.basename itself. The install destination
and the `.old` aside stay on host paths: they name files the host opens.
Refs #20913
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
205 lines
9.4 KiB
YAML
205 lines
9.4 KiB
YAML
name: Computer-use e2e
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- '.github/workflows/computer-e2e.yml'
|
|
- 'config/electron-builder.config.cjs'
|
|
- 'config/scripts/build-computer-macos.mjs'
|
|
- 'config/scripts/build-native-for-platform.mjs'
|
|
- 'config/scripts/build-native-for-platform.test.mjs'
|
|
- 'config/scripts/pnpm-cli-invocation.mjs'
|
|
- 'config/scripts/build-windows-cli-launcher.mjs'
|
|
- 'config/scripts/windows-rust-executable-build.mjs'
|
|
- 'config/scripts/build-windows-cli-launcher.test.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-benchmark.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-group-recovery.test.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-metrics.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-processes.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-processes.test.mjs'
|
|
- 'config/scripts/macos-computer-helper-owner-loss-trial-cleanup.mjs'
|
|
- 'config/scripts/computer-use-smoke.mjs'
|
|
- 'config/scripts/computer-use-smoke.test.mjs'
|
|
- 'config/scripts/daemon-boot-smoke.mjs'
|
|
- 'config/scripts/daemon-endpoint-handover-smoke.mjs'
|
|
- 'config/scripts/windows-daemon-workspace-close-repro.mjs'
|
|
- 'config/scripts/verify-computer-native.mjs'
|
|
# Why: the native-smoke job boots the built terminal daemon under plain
|
|
# Node, so any change to the daemon bundle graph or the main build must
|
|
# re-run it (the v1.4.129-rc.1 daemon outage shipped with green CI).
|
|
- 'electron.vite.config.ts'
|
|
- 'config/build-plugins/**'
|
|
- 'src/main/daemon/**'
|
|
- '!src/main/daemon/**/*.test.ts'
|
|
- '!src/main/daemon/daemon-init-dependency-mocks.ts'
|
|
- '!src/main/daemon/daemon-init-test-harness.ts'
|
|
- '!src/main/daemon/daemon-init-fresh-import.ts'
|
|
- '!src/main/daemon/daemon-init-mock-types.ts'
|
|
- 'src/main/providers/local-pty-provider.ts'
|
|
- 'src/main/providers/windows-shell-args.ts'
|
|
- 'src/main/providers/windows-shell-preflight-runtime.windows.test.ts'
|
|
- 'native/computer-use-macos/**'
|
|
- 'native/computer-use-linux/**'
|
|
- 'native/computer-use-windows/**'
|
|
- 'native/windows-cli-launcher/**'
|
|
- 'skills/computer-use/SKILL.md'
|
|
- 'src/cli/**'
|
|
- 'src/main/computer/**'
|
|
- 'src/main/runtime/rpc/dispatcher.ts'
|
|
- 'src/main/runtime/rpc/errors.ts'
|
|
- 'src/main/runtime/rpc/methods/computer*.ts'
|
|
- 'src/shared/computer-use-*.ts'
|
|
- 'tests/e2e/computer-linux.e2e.ts'
|
|
- 'tests/e2e/computer-windows.e2e.ts'
|
|
- 'tests/e2e/computer-windows-store.e2e.ts'
|
|
- 'tests/e2e/helpers/computer-cli-driver.ts'
|
|
- 'tests/e2e/helpers/computer-driver.ts'
|
|
- 'tests/e2e/vitest.config.ts'
|
|
workflow_dispatch:
|
|
schedule:
|
|
- cron: '0 6 * * *'
|
|
|
|
concurrency:
|
|
group: computer-e2e-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
|
|
jobs:
|
|
native-smoke:
|
|
if: github.event_name == 'pull_request'
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-22.04, windows-latest]
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
- if: runner.os == 'Linux'
|
|
run: sudo apt-get update && sudo apt-get install -y python3 python3-gi gir1.2-atspi-2.0 at-spi2-core
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
native-runtime: node
|
|
# Why: without --config, bare vitest ignores config/vitest.config.ts (there
|
|
# is no root config) and falls back to the 5s default timeout with no
|
|
# Windows worker cap, so the real csc.exe launcher-compile tests time out
|
|
# on hosted Windows. Use the shared config so this job matches pnpm test.
|
|
- run: >-
|
|
pnpm vitest run --config config/vitest.config.ts
|
|
config/scripts/macos-computer-helper-owner-loss-group-recovery.test.mjs
|
|
config/scripts/macos-computer-helper-owner-loss-processes.test.mjs
|
|
config/scripts/computer-use-smoke.test.mjs
|
|
src/main/computer/computer-provider-lifecycle.test.ts
|
|
src/main/computer/computer-provider-unavailable-message.test.ts
|
|
src/main/computer/sidecar-client.test.ts
|
|
src/main/computer/macos-native-provider-client.test.ts
|
|
src/main/computer/macos-native-provider-socket.test.ts
|
|
src/main/computer/macos-computer-use-permissions.test.ts
|
|
src/main/computer/macos-computer-use-permission-status.test.ts
|
|
src/main/providers/windows-shell-preflight-runtime.windows.test.ts
|
|
src/main/computer/desktop-script-provider-client.test.ts
|
|
src/main/computer/desktop-script-provider-cache.test.ts
|
|
src/main/computer/desktop-script-provider-actions.test.ts
|
|
src/main/computer/desktop-script-provider-cache-lifecycle.test.ts
|
|
src/main/computer/desktop-script-provider-errors.test.ts
|
|
src/main/computer/desktop-script-provider-action-errors.test.ts
|
|
src/shared/computer-use-error-recovery.test.ts
|
|
src/shared/computer-use-key-spec.test.ts
|
|
src/cli/format.test.ts
|
|
src/cli/handlers/computer.test.ts
|
|
src/cli/handlers/computer-action-routing.test.ts
|
|
src/cli/handlers/computer-action-validation.test.ts
|
|
src/cli/handlers/computer-state-formatting.test.ts
|
|
src/cli/index.test.ts
|
|
src/main/runtime/rpc/dispatcher-computer-errors.test.ts
|
|
src/main/runtime/rpc/errors.test.ts
|
|
src/main/runtime/rpc/methods/computer.test.ts
|
|
src/main/runtime/rpc/methods/computer-actions.test.ts
|
|
src/cli/runtime/envelope-schema.test.ts
|
|
src/shared/remote-runtime-client.test.ts
|
|
- run: pnpm verify:computer-native
|
|
- run: pnpm build:cli
|
|
- run: pnpm run build:electron-vite:parallel
|
|
# Why: boot the BUILT daemon-entry under plain Node the way production
|
|
# forks it. v1.4.129-rc.1 shipped a daemon that exited at module load
|
|
# (leaked electron require) while every other check passed; this fails
|
|
# the PR when the built daemon cannot start on ubuntu-22.04 / windows.
|
|
- name: Daemon boot smoke
|
|
run: node config/scripts/daemon-boot-smoke.mjs
|
|
# Why: a daemon that lost its endpoint name used to delete the replacement's
|
|
# socket on exit, stranding a live daemon that hosts PTYs nothing can reach.
|
|
# Only two real processes racing the same endpoint reproduce it.
|
|
- name: Daemon endpoint handover smoke
|
|
run: node config/scripts/daemon-endpoint-handover-smoke.mjs
|
|
# Why: workspace removal overlaps graceful renderer teardown with the
|
|
# forced main-process sweep; exercise that exact pair against real ConPTY.
|
|
- name: Windows daemon workspace-close repro
|
|
if: runner.os == 'Windows'
|
|
run: node config/scripts/windows-daemon-workspace-close-repro.mjs
|
|
# Hosted macOS runners cannot receive persistent Accessibility/Screen Recording
|
|
# grants. Keep the real native build/owner-loss checks on every trigger instead.
|
|
mac-native-owner-smoke:
|
|
runs-on: macos-15
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
native-runtime: electron
|
|
- name: Owner-loss benchmark process cleanup
|
|
run: >-
|
|
pnpm vitest run
|
|
config/scripts/macos-computer-helper-owner-loss-group-recovery.test.mjs
|
|
config/scripts/macos-computer-helper-owner-loss-processes.test.mjs
|
|
# Why: the parallel launcher's cancellation tests are darwin-only and no
|
|
# other PR job runs on macOS.
|
|
- name: Parallel native build launcher cancellation
|
|
run: >-
|
|
pnpm vitest run --config config/vitest.config.ts
|
|
config/scripts/build-native-for-platform.test.mjs
|
|
- name: Authenticated helper owner-loss smoke
|
|
run: pnpm bench:macos-computer-helper-owner-loss --expect reaped --trials 1
|
|
- name: Swift tests and signed universal helper verification
|
|
run: pnpm verify:computer-native
|
|
|
|
linux:
|
|
if: github.event_name != 'pull_request'
|
|
runs-on: ubuntu-22.04
|
|
env:
|
|
ORCA_COMPUTER_E2E: '1'
|
|
ACCESSIBILITY_ENABLED: '1'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
- run: sudo apt-get update && sudo apt-get install -y build-essential python3 python3-gi gir1.2-atspi-2.0 gedit at-spi2-core xvfb xclip xdotool
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
native-runtime: electron
|
|
- run: pnpm verify:computer-native
|
|
- run: pnpm build:cli
|
|
- run: pnpm run build:electron-vite:parallel
|
|
- run: xvfb-run --auto-servernum dbus-run-session -- pnpm test:e2e:computer --reporter=verbose tests/e2e/computer-linux.e2e.ts
|
|
|
|
windows:
|
|
if: github.event_name != 'pull_request'
|
|
runs-on: windows-latest
|
|
env:
|
|
ORCA_COMPUTER_E2E: '1'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
native-runtime: electron
|
|
- run: pnpm verify:computer-native
|
|
- run: pnpm build:cli
|
|
- run: pnpm run build:electron-vite:parallel
|
|
- run: pnpm test:e2e:computer --reporter=verbose tests/e2e/computer-windows.e2e.ts tests/e2e/computer-windows-store.e2e.ts
|