* fix(agent-hooks): register forward-slash Windows hook paths for Grok, Devin, ZCode and Antigravity
These four agents registered their native-Windows status hook as a bare
backslash path. A Git Bash hook host strips the backslashes, the command exits
127, and no status event reaches Orca. Use the same direct forward-slash form
Claude, Codex and Muse already register, keeping the cmd-safe gate and the
encoded PowerShell fallback. Existing backslash entries still match the
managed-command matcher, so the next install replaces them and keeps user hooks.
* perf(hooks): register direct .cmd hooks for Gemini, DSH, Kiro, Droid and Command Code on Windows
On a cmd-safe profile path these agents now register the managed .cmd path
itself instead of a `powershell.exe -EncodedCommand` launcher, so each hook
event no longer pays a second PowerShell start-up on top of the runner's own
shell. Profiles the bare path cannot carry (spaces, non-ASCII, UNC) keep the
encoded launcher. Same pattern as Claude (#18875) and Muse (#26755).
Refs #20913
* test(agent-hooks): expect forward-slash Antigravity hooks after the Unicode upgrade
ASCII profiles now register the direct forward-slash wrapper path, so the
upgrade-delivery test expects that form and also runs it through Git Bash.
Unicode profiles keep the encoded launcher.
* test(agent-hooks): assert the registered hook lives under the mocked home
Pins that the os mock reaches the agents' node:os imports, so the host test
never installs into the real profile.
* refactor(hooks): one Windows batch-hook helper and one payload-delivery table
- Add wrapWindowsBatchHookCommand (bare .cmd path, encoded launcher
otherwise) and use it for Muse, Gemini, DSH, Kiro, Droid and Command Code.
- Fold the five agents into windows-hook-payload-delivery.test.ts as rows
run under each vendor's shell, from a plain and a spaced profile, with a
stale encoded registration seeded per row; drop the separate runner suite
and its CI list entries.
- Replace the Windows-only per-agent registration tests with ones that stub
process.platform, so they run on every CI OS.
- Fix stale launcher, helper and DSH comments.
Refs #20913
* refactor(agent-hooks): register Grok, Devin, ZCode and Antigravity through wrapWindowsBatchHookCommand
Use the shared batch-hook helper from #27717 instead of an inline direct-or-cmd
fallback. A UNC home is cmd-safe but has no drive letter; the old fallback
registered it as a bare backslash path that Git Bash cannot start, while the
helper sends it to the encoded launcher.
wrapWindowsCmdHookCommand has no production callers left, so it is removed and
its tests point at the helper. Grok, Devin and ZCode join the Windows payload
delivery table with a legacy backslash entry to sweep, replacing the separate
host test, and the Antigravity migration test now runs on every platform.
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
* fix(serve): report secrets unavailable instead of hanging on an unreachable macOS keychain
* fix(serve): classify keychain probe by exit code, skip under a mock keychain, ratchet direct safeStorage imports
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
A restored plaintext envelope can match the rejected replacement byte for
byte. Do not delete that file, since it is the previous key rather than a
new secret.
A failed plaintext replacement can publish the new key before file
restriction is confirmed. If restoring the previous key fails before it
replaces that file, delete only the rejected envelope so a completed
restore is left intact.
Extract subprocess execution and process contracts into @orca/process-host with explicit public entry points, independent checks, and one Node 18 compatible CommonJS runtime. Migrate application consumers and integrate package builds, dependency selection, import enforcement, and runtime resource staging.
Preserve daemon startup ownership and profile isolation, and qualify development rebuild recovery and concurrent output publication. Remove unnecessary aliases, test forwarding exports, and a duplicate output scan.
Validation: full typechecks, changed-code quality, package and artifact checks, native Windows builds/types plus 306 runtime tests, and independent native reviews.
Matched full E2E controls on original main and unchanged reviewed head both pass all 17 applicable tests (nine skips). Earlier intermittent E2E failures are documented in the PR; no assertions were weakened. The final combined-tree audit preserves both branches with no import-boundary violations.
* feat(zcode): explain a ZCode build that has no terminal UI
ZCode ships one agent runtime behind two front ends. The desktop app bundles it
without `@zcode/tui`, because it draws its own window in Electron. Put that
bundle on PATH as `zcode` and it answers `--version`, runs `-p` headlessly, and
passes `zcode doctor` — so Orca detects it, launches it, and installs hooks
against it, all successfully. Only the interactive session fails, leaving a bare
Node stack trace in the pane that reads as a broken Orca integration.
Watch a freshly launched ZCode pane's first output and replace that with an
explanation: Orca's hooks are fine, this `zcode` just cannot open a session,
install one that ships the TUI.
The rule keys on Node's own module-resolution error rather than on the healthy
build's "TUI requires an interactive terminal." message, because ZCode localizes
the latter (`TUI 需要交互式终端。` in zh-CN) and matching it would miss every
non-English user. Node's error is not translated and names the package.
Scoped so it costs a healthy pane nothing: it runs only for a pane Orca launched
as `zcode`, and only over the first 8 KiB, because a module-resolution failure
happens before the runtime renders anything.
Evidence: `src/main/runtime/__fixtures__/zcode-missing-tui.txt`, a recorded PTY
capture of the desktop bundle refusing to start, per
docs/reference/agent-pty-transcript-capture.md.
Reported-by: JWu527
* refactor(zcode): ask the CLI if it can open a session instead of watching for the failure
The stream watcher this replaces never fired. Before/after screenshots were
identical and instrumentation showed the hook never ran, so the sidecar was
both misplaced and racing a failure that lands ~440ms after spawn.
Replace it with a direct question, answered once per run and cached.
Reading zai-org/ZCode shows why running it is the only way to ask, and why the
answer is unambiguous. `--version` and `doctor` are byte-identical in shape
between a build that has the terminal UI and one that does not, because the TUI
is only ever touched on the `tui` command path. There, `runTuiCommand` calls
`loadTuiRuntime()` before anything else, and `runTui` checks for a TTY only
after that module is already loaded. So with stdin at EOF:
- no TUI -> fails in the loader -> Node's module-resolution error
- has TUI -> loads, then declines -> "TUI requires an interactive terminal."
The module error is therefore present exactly when the terminal UI is absent.
All three shipping shapes land correctly: an npm/node-bundle install resolves
`@zcode/tui` as a real package (esbuild marks it external, so it is never
inlined), a SEA build always carries it as embedded assets, and the desktop
app's bundled runtime carries neither.
Verified against both real builds on this machine rather than a mock: the
desktop bundle answers `missing-tui`, a CLI built from source answers
`interactive`, and a command that does not exist answers `unknown` — the probe
fails open so an unrelated spawn failure never accuses a working CLI.
* feat(zcode): warn at launch when the installed zcode cannot open a session
Wires the capability probe to the one place a ZCode launch is first known:
terminal tab creation, which runs before the pane connects, so the explanation
reaches the screen alongside the failure rather than after it.
- main exposes the cached probe over `preflight:zcodeInteractiveCapability`,
beside the other "what can the installed CLIs do" answers
- the web preload stub answers `unknown`, because a paired client has no
business deciding anything about the host's CLI install
- the renderer notice is advisory: a probe that cannot run never blocks a launch
Verified in the running app against the real desktop bundle: creating a ZCode
workspace now shows "This ZCode build has no terminal UI" next to the stack
trace, where before the trace stood alone.
* feat(agents): add first-class ZCode harness
Add ZCode (Z.ai's `zcode` CLI) as a supervised Orca agent: managed lifecycle
hooks on local, SSH and Windows hosts; status, question and approval reporting;
synthetic status titles; session resume; orchestration worker launch options;
and desktop + mobile agent-picker registration.
Written against the newly open-sourced `zai-org/ZCode` (agent CLI 0.16.9), not
against a remembered screen:
- ZCode's hook runner writes a Claude-compatible stdin alias set, so it routes
through the existing Claude-compatible vendor path while keeping its own
identity in the sidebar.
- `PermissionRequest` fires only once the approval card is on screen and racing
the user's answer, so it is proof the pane is blocked, not an auto-approval.
- ZCode's clarification tool is literally `AskUserQuestion` with Claude's
questions/options shape, so Orca's question card renders it unchanged.
- ZCode's `hooks.enabled` defaults to false, which is why configured hooks were
reported as never firing; the installer sets it.
- ZCode renames its own process to `zcode-cli`, so the expected foreground
process cannot be the launch command or dispatch refuses the pane.
- ZCode emits no OSC title in any state and repaints its ASCII banner forever,
so readiness comes from Orca's synthetic hook title and launch drafts wait on
the composer box rather than on a quiet render window.
Three files crossed their max-lines limit, so each is split along a real seam:
command-line entrypoint parsing out of agent process recognition, skill
classification out of skill root discovery, and registry coverage out of the
remote hook installer tests.
Refs #10564
* fix(zcode): drop the session-option catalog and pin the orchestration contract
ZCode's CLI exposes no `--model` flag at all, and the session-option launch path
refuses to apply any option until a model id is chosen. A catalog therefore could
not deliver `--mode` per worker, and would have accepted `--model` only to drop
it silently. Take opencode's position instead: no catalog, so `worker-start
--model` is refused with a clear message and ZCode launches with the model from
its own config. `--mode` stays reachable through agent args, which is also how
the yolo default is applied.
Add a contract test covering the parts that make ZCode a usable worker:
dispatchable foreground process, stdin prompt delivery, the prompt staying out
of the launch command, and the composer-gated draft paste.
* refactor(zcode): reuse shared helpers and cut the harness down
No behaviour change; every ZCode test still passes.
- Use installer-utils' own `hookDefinitionHasManagedCommand` instead of
re-walking a hook definition by hand, which also drops a local string reader.
- Share one `readZCodeEventMap` instead of keeping the same narrowing in both
hook-settings and hook-config-json.
- Collapse five identical error returns into one `zcodeHookError` builder, and
return early from the status branches instead of assigning through `let`.
- Split the event-to-status decision out of `normalizeZCodeEvent` into a pure
`readZCodeTurn`, so the normalizer reads as decide-then-build and stops
computing the tool name for events that never look at it.
- Take a script file name in `readManagedZCodeHookEvents` like its siblings,
which removes a `Parameters<typeof …>` indirection at the call site.
- Drop the unused `ZCodeHookEvent` export and inline a single-use path helper.
- Correct a stale comment: ZCode's loader is a strict `JSON.parse`, so the
in-place edit preserves key order and indentation, not comments.
* fix(zcode): address review — keep unmanaged event keys, correct comment, de-dupe README
- `removeZCodeManagedHooks` deleted any event key whose list ended up empty, so an
unrelated `"Notification": []` the user wrote was removed as collateral whenever a
managed hook elsewhere made the write happen. Only touch an event Orca actually
owned something in; covered by a new regression test.
- The `isNewTurnEvent` comment claimed UserPromptSubmit was ZCode's only turn
boundary while the expression below it also returned true for SessionStart. Say
what the code does: SessionStart lands the idle boundary, UserPromptSubmit is the
turn boundary (the Codex/Claude shape).
- ZCode appeared twice in the README's single agent-badge block; keep the
local-icon entry the link checker validates and drop the favicon duplicate.
* docs(zcode): call out that the desktop bundle's CLI cannot open a session
From live testing on #22464: pointing `zcode` at the desktop app's bundled
`glm/zcode.cjs` installs Orca's hooks fine but then fails with
`Cannot find package '@zcode/tui'`, so the pane never opens a session. The
symptom reads as a broken harness when the CLI simply has no TUI. Say which
build to use and how to check before reporting a problem.
Reported-by: JWu527