Conversation
There was a problem hiding this comment.
ℹ️ No critical issues — minor suggestions inline.
Reviewed changes
One sentence: this adds ZCode (Z.ai's zcode CLI) as a managed TUI agent, and I spot-checked the load-bearing external contracts against github.com/zai-org/ZCode rather than trusting the PR description.
- Hook install (
src/main/zcode/) — writes~/.zcode/cli/config.jsonwithhooks.enabled: trueand the 7hooks.events.<Event>entries, editing the file text in place so user hooks/key order survive; plus local/SSH command wrappers andgetStatuswith apartialstate whenhooks.enabledis off. - Event normalization — routes
/hook/zcodethrough the Claude-compatible vendor path (normalizeZCodeEvent, sharedextractClaudeToolFields), mappingPermissionRequest/AskUserQuestiontowaitingandStop/PostToolUseFailureback to working/done. - Readiness and launch — synthetic title (
ZCode ready/ZCode - action required) because ZCode emits no OSC title and repaints forever, plus azcode-composer-promptdraft-paste signal;stdin-after-startprompt transport,expectedProcess: 'zcode-cli',--mode yolo, resume viazcode --resume, skills root~/.zcode/skills. - Registration sweep and refactors — catalog/i18n/mobile/telemetry/skills/resume-capability entries, the handshake-covered exclusions (no session-option catalog, no usage/AI-Vault), and three max-lines splits (
agent-command-line-entrypoint.ts,skill-discovery-classification.ts,remote-hook-service-registry-coverage.test.ts). - Verification — all ZCode and all-agent census suites pass locally. Upstream confirms
CLI_PROCESS_NAME = 'zcode-cli', package@zcode/cliwith bindist/zcode.cjs,--resume/--mode yolo/-p/--target, the exact 7HookEventNames, theenabled: falsedefault, and the Claude alias set (createCompatibleHookStdin) including the temptranscript_paththat makes the resume design correct.
ℹ️ Remote install coverage does not match the testing claim
The body says SSH install is "covered by remote-hook-service-installers.test.ts", but that suite has no ZCode block — no call to zcodeHookService.installRemote anywhere. The only automated remote exercise is the aggregate smoke in managed-hook-local-filesystem.test.ts, which asserts a non-error result and an executable script but never inspects the remote config.json. A ZCode block mirroring the Muse/Copilot cases (assert hooks.enabled, the event set, and user-hook preservation over SFTP) would close the gap that the PR itself flags as the least-tested axis.
Technical details
# ZCode remote config is only smoke-tested
## Affected sites
- `src/main/agent-hooks/remote-hook-service-installers.test.ts` — per-agent remote blocks exist
for claude/openclaude/codex/gemini/antigravity/amp/cursor/command-code/grok/copilot/devin/
droid/kimi/hermes/muse, but none for `zcode`.
- `src/main/zcode/hook-service.ts` `installRemote` — writes the POSIX script and the remote
`config.json` via `writeHooksJsonRemote`; unverified by a targeted test.
- `src/main/agent-hooks/managed-hook-local-filesystem.test.ts:37` — aggregate install over
`REMOTE_MANAGED_HOOK_INSTALLER_AGENTS` includes zcode, but only asserts length/state/mode.
## Required outcome
- A test that runs `zcodeHookService.installRemote(createManagedHookLocalFilesystem(), home)`
against a pre-seeded remote `~/.zcode/cli/config.json` and asserts: `hooks.enabled === true`,
all `ZCODE_HOOK_EVENTS` present, the managed command points at `zcode-hook.sh`, and a user's
own hook entry is preserved.
## Open questions for the human
- Is the aggregate smoke considered sufficient, or should remote get the same per-agent
assertion depth as Muse/Copilot?DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe pull request adds ZCode as a supported CLI agent. It adds launch configuration, process recognition, session resume, terminal readiness detection, managed local and remote hooks, and hook event normalization. It also adds ZCode skill discovery and installation support, agent catalog and icon entries, translations, and documentation. Shared interpreter command-line parsing moves into a new module. Priority: ➖ Normal Merge Risk: 🔵 Low · up to If ZCode exits before showing its composer, the pending task text may be inserted into the surviving shell prompt. This is a bounded edge case, but should be fixed or explicitly accepted before relying on the integration. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: 5f633f70-11cf-47ba-9865-11da022f7097
⛔ Files ignored due to path filters (1)
src/shared/agent-icons/zcode.pngis excluded by!**/*.png
📒 Files selected for processing (68)
README.mdconfig/tsconfig.cli.jsondocs/readme/README.es.mddocs/readme/README.fr.mddocs/readme/README.ja.mddocs/readme/README.ko.mddocs/readme/README.pt.mddocs/readme/README.zh-CN.mddocs/site/content/docs/agents/supported.mdxmobile/src/components/mobile-agent-icon-assets.tsmobile/src/tasks/mobile-tui-agents.tssrc/cli/specs/orchestration-worker-specs.tssrc/main/agent-hooks/installer-utils-remote.tssrc/main/agent-hooks/installer-utils.tssrc/main/agent-hooks/managed-agent-hook-registry.tssrc/main/agent-hooks/managed-hook-command-contract.test.tssrc/main/agent-hooks/remote-hook-service-installers.test.tssrc/main/agent-hooks/remote-hook-service-registry-coverage.test.tssrc/main/agent-hooks/remote-managed-hook-installers.tssrc/main/agent-hooks/server-retired-pane-new-turn.test.tssrc/main/runtime/__fixtures__/zcode-composer-ready.meta.jsonsrc/main/runtime/__fixtures__/zcode-composer-ready.txtsrc/main/runtime/zcode-readiness-transcript.test.tssrc/main/skills/skill-discovery-classification.tssrc/main/skills/skill-discovery-concurrency.test.tssrc/main/skills/skill-discovery-sources.tssrc/main/zcode/hook-config-json.tssrc/main/zcode/hook-service.test.tssrc/main/zcode/hook-service.tssrc/main/zcode/hook-settings.tssrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/fr.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/lib/agent-catalog.tsxsrc/renderer/src/lib/agent-favicon-assets.tssrc/renderer/src/lib/agent-status.tssrc/renderer/src/runtime/agent-resume-host-authority-capability.test.tssrc/renderer/src/runtime/agent-resume-host-authority-capability.tssrc/shared/agent-command-line-entrypoint.tssrc/shared/agent-headless-command.tssrc/shared/agent-hook-listener/provider-dispatch.tssrc/shared/agent-hook-listener/provider-event-routing.tssrc/shared/agent-hook-listener/providers/zcode-events.test.tssrc/shared/agent-hook-listener/providers/zcode-events.tssrc/shared/agent-hook-listener/source-routing.tssrc/shared/agent-hook-relay.tssrc/shared/agent-hook-types.tssrc/shared/agent-kind.tssrc/shared/agent-name-token-match.tssrc/shared/agent-process-recognition.tssrc/shared/agent-session-resume.tssrc/shared/agent-type-label.tssrc/shared/draft-paste-ready-scanner.tssrc/shared/protocol-version.tssrc/shared/skill-install-providers.tssrc/shared/skills-cli-agent-keys.tssrc/shared/synthetic-agent-title.tssrc/shared/telemetry-property-schemas.tssrc/shared/tui-agent-config.tssrc/shared/tui-agent-display-names.tssrc/shared/tui-agent-permissions.tssrc/shared/tui-agent-selection.tssrc/shared/tui-agent.tssrc/shared/zcode-headless-command.tssrc/shared/zcode-orchestration-contract.test.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.
| // Why: ZCode animates its ASCII banner forever, so the quiet window never settles on | ||
| // its own — but keep it armed as the floor for a build that renders inline and never | ||
| // switches to the alternate screen, where the marker anchor would never arm. | ||
| quietAnchor: DECSET_BRACKETED_PASTE |
There was a problem hiding this comment.
🎯 Functional Correctness | 🛡️ Detected with Advanced Tier | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '1,200p' src/shared/draft-paste-ready-scanner.ts
rg -n 'quietTimer|QUIET_MS|sendStartupDraftPaste|armQuietTimer|\\r|submit' src/renderer/src/components/terminal-pane/pty-connection/pane-serializer-settle.ts src/main/runtime/runtime-worktree-startup-readiness.tsRepository: stablyai/orca
Length of output: 11817
Check process ownership before ZCode quiet-fallback delivery. DECSET_BRACKETED_PASTE arms sawQuietAnchor, but DECRST_ALT_SCREEN revokes only the marker anchor. If ZCode exits before ╭ appears, the quiet timer can deliver the pending draft to the shell. The draft uses bracketed paste and does not include an Enter keystroke, so this can insert stray text into the shell prompt but does not directly execute the command. Apply the foreground-process check in both quiet-fallback consumers.
Check process ownership before fallback delivery
--- a/src/renderer/src/components/terminal-pane/pty-connection/pane-serializer-settle.ts
+++ b/src/renderer/src/components/terminal-pane/pty-connection/pane-serializer-settle.ts
@@
startupDraftQuietTimer = setTimeout(() => {
startupDraftQuietTimer = null
- sendStartupDraftPaste()
+ void deliverStartupDraftIfAgentOwnsPty()
}, STARTUP_DRAFT_PASTE_QUIET_MS)--- a/src/main/runtime/runtime-worktree-startup-readiness.ts
+++ b/src/main/runtime/runtime-worktree-startup-readiness.ts
@@
- quietTimer = setTimeout(() => finish(ptyId), BRACKETED_PASTE_QUIET_MS)
+ quietTimer = setTimeout(() => {
+ if (agent !== 'zcode') {
+ finish(ptyId)
+ return
+ }
+ void host.getForegroundProcess(ptyId).then(
+ (foregroundProcess) => {
+ if (
+ isExpectedAgentProcess(
+ foregroundProcess,
+ TUI_AGENT_CONFIG.zcode.expectedProcess
+ )
+ ) {
+ finish(ptyId)
+ }
+ },
+ () => {}
+ )
+ }, BRACKETED_PASTE_QUIET_MS)50b0dde to
a776066
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: be65510b-a27b-4ab4-9214-4a0cee27f9c5
📒 Files selected for processing (4)
src/main/zcode/hook-config-json.tssrc/main/zcode/hook-service.tssrc/main/zcode/hook-settings.tssrc/shared/agent-hook-listener/providers/zcode-events.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.
There was a problem hiding this comment.
ℹ️ One new commit since the last review — a behavior-preserving refactor with no new issues. Not approving only because a prior inline thread is still unresolved.
Reviewed changes
This run reviewed the single commit added since the prior Pullfrog review (3bf87309dd, "reuse shared helpers and cut the harness down"): four production files, no test changes, ~55 net lines removed.
- Config serialization —
hook-config-json.tsgained a localeditJsonPathhelper and reads the event map through the sharedreadZCodeEventMap; the comment was corrected to note ZCode's loader is a strictJSON.parse. - Hook status —
hook-service.tscollapsed the error/partial construction intozcodeHookError+ early returns, and managed-entry detection now uses the sharedhookDefinitionHasManagedCommand, which aligns status with whatremoveManagedCommandsactually removes. - Settings surface —
hook-settings.tsdropped the unusedZCodeHookEventtype andgetZCodeConfigDir, made the command matcher module-private, and gavereadManagedZCodeHookEventsa script-file-name parameter. - Event normalization —
zcode-events.tsextracted the per-event state mapping intoreadZCodeTurn;sessionBoundaryandinterruptedare now passed unconditionally, whichnormalizeAgentStatusPayloadstill collapses toundefinedoutside a cleandone.
I ran pnpm tc:node (clean) and the ZCode + hook suites (153 passed, 3 skipped).
The only reason this isn't an approval is the still-open thread at src/shared/agent-hook-listener/provider-event-routing.ts:39 (the ZCode isNewTurnEvent comment contradicts its SessionStart || UserPromptSubmit return); 3bf87309dd does not touch that file, so it remains outstanding.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
|
Review fixes pushed in Fixed — Fixed — Fixed — ZCode listed twice in the README (@coderabbitai). Confirmed it's one Not changing — quiet-fallback process ownership (@coderabbitai, On remote-install coverage (@pullfrog). Fair — my testing note said SSH is "covered by construction and by the shared contract tests", and
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This run reviewed the single commit added since the prior Pullfrog review (e758f5542e, "address review — keep unmanaged event keys, correct comment, de-dupe README"): four files, +26/−5.
- Unmanaged event keys survive removal —
removeZCodeManagedHooksnow short-circuits when an event's cleaned list is unchanged, so a user's unrelated"Notification": []is no longer deleted as collateral whenever a managed hook elsewhere forces a write. A regression test pins it. isNewTurnEventcomment corrected — the ZCode case now documents theSessionStart || UserPromptSubmitshape the expression actually implements, matching Codex/Claude.- README de-dupe — dropped the duplicate favicon ZCode badge, keeping the local-icon entry the link checker validates.
The prior inline thread at src/shared/agent-hook-listener/provider-event-routing.ts:39 is resolved. I ran pnpm test src/main/zcode/hook-service.test.ts (9 passed) and confirmed the new test fails under the pre-fix removal logic, so it is real coverage rather than a tautology.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed the single commit added since the prior Pullfrog review (e758f5542e): four files — a data-integrity fix in ZCode hook removal with its regression test, a comment correction, and a README de-duplication.
- Unmanaged hook keys now survive removal —
removeZCodeManagedHooksskips any event whose definition list is unchanged byremoveManagedCommands, so a user's unrelated"Notification": []is no longer deleted as collateral when Orca removes a managed hook elsewhere.src/main/zcode/hook-settings.ts:158. - Regression test verified against the bug — installs then removes with a pre-seeded
Notification: [], asserting the empty key survives while all seven managed events are dropped. I re-ran it against the pre-fix logic and confirmed it fails withexpected undefined to deeply equal [], then passes on the fixed code.src/main/zcode/hook-service.test.ts:129. - Comment now matches its return — the ZCode
isNewTurnEventcomment states the Codex/Claude shape (SessionStartlands the idle boundary,UserPromptSubmitis the turn boundary), consistent with theSessionStart || UserPromptSubmitexpression.src/shared/agent-hook-listener/provider-event-routing.ts:39. - README de-duplicated — the duplicate favicon ZCode entry is gone; the local-icon entry the link checker validates is retained.
The prior open Pullfrog thread on provider-event-routing.ts is addressed and resolved. pnpm test over the ZCode hook-service and event suites passes (20 tests).
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 Minor · Check process ownership before quiet-timer delivery · tui-agent-config.ts:318-330
src/shared/tui-agent-config.ts:318-330
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCheck process ownership before quiet-timer delivery
When ZCode exits before the
zcode-composer-promptquiet timer fires, the timer callssendStartupDraftPaste()without checking the foreground process. This can write the pending bracketed paste to the shell PTY. Use the existing ownership check at this renderer delivery boundary.Suggested fix
- sendStartupDraftPaste() + void deliverStartupDraftIfAgentOwnsPty()
🟡 Minor · Check foreground ownership before the main worktree draft paste. · tui-agent-config.ts:318-330
src/shared/tui-agent-config.ts:318-330
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCheck foreground ownership before the main worktree draft paste.
When ZCode resolves
zcode-composer-promptand exits before the callback runs,pasteWorktreeStartupDraftWhenReady()writes the bracketed draft without checking the current foreground process. The draft can therefore be pasted into the shell after ZCode exits. It remains unsubmitted; this path does not execute it.Check ownership immediately before
host.write():Suggested fix
- .then((ptyId) => { + .then(async (ptyId) => { if (!ptyId) { console.warn('[worktree-create] agent did not become ready for draft paste') return } + const foregroundProcess = await host.getForegroundProcess(ptyId) + if ( + !isExpectedAgentProcess( + foregroundProcess, + TUI_AGENT_CONFIG[draft.agent].expectedProcess + ) + ) { + return + } host.write(ptyId, `${BRACKETED_PASTE_BEGIN}${draft.content}${BRACKETED_PASTE_END}`) })
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: 1e9e23fe-0901-4f41-93fc-487c70d523ff
📒 Files selected for processing (4)
README.mdsrc/main/zcode/hook-service.test.tssrc/main/zcode/hook-settings.tssrc/shared/agent-hook-listener/provider-event-routing.ts
💤 Files with no reviewable changes (1)
- README.md
🚧 Files skipped from review as they are similar to previous changes (3)
- src/shared/agent-hook-listener/provider-event-routing.ts
- src/main/zcode/hook-settings.ts
- src/main/zcode/hook-service.test.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
git status --short
git show --stat --oneline e758f554 -- | head -70
ast-grep outline src/main/zcode/hook-settings.ts --items all --match 'removeZCodeManagedHooks|applyZCodeManagedHooks'
ast-grep outline src/main/zcode/hook-service.test.ts --items all --match 'remove|Notification'
ast-grep outline src/shared/draft-paste-ready-scanner.ts --items all --match 'createDraftPasteReadyScanner'
ast-grep outline src/shared/agent-hook-listener/provider-event-routing.ts --items all --match 'isNewTurnEvent'
rg -n -C2 'Notification|removeZCodeManagedHooks|sawQuietAnchor|DECRST_ALT_SCREEN|grok-composer-prompt|zcode-composer-prompt|UserPromptSubmit|SessionStart' src/main/zcode/hook-settings.ts src/main/zcode/hook-service.test.ts src/shared/draft-paste-ready-scanner.ts src/shared/agent-hook-listener/provider-event-routing.ts
rg -n 'ZCode|Muse|zcode.z.ai|agent-icons/zcode.png' README.md | head -45Length of output: 14460 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '105,183p' src/main/zcode/hook-settings.ts
sed -n '95,154p' src/main/zcode/hook-service.test.ts
sed -n '30,92p' src/shared/draft-paste-ready-scanner.ts
sed -n '140,182p' src/shared/draft-paste-ready-scanner.ts
sed -n '224,280p' src/shared/draft-paste-ready-scanner.ts
git show e758f554 -- src/main/zcode/hook-settings.ts src/main/zcode/hook-service.test.ts src/shared/agent-hook-listener/provider-event-routing.ts README.md | head -195Length of output: 18068
I agree that the quiet-fallback concern also applies to Grok. I will leave that concern open for a separate change covering both agents. Would you like me to open a follow-up issue? Your distinction between SFTP test coverage and validation on a real SSH host is accurate. ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! You are interacting with an AI system. |
ZCode harness is ready to test — installable builds belowPR #22464 adds ZCode as a first-class Orca agent. Before it's approved and merged I'd like confirmation from people who actually use ZCode that it behaves on real machines — mine is macOS-only, and the hook install touches your real ZCode config. Once a couple of you confirm it works, we'll approve and merge. Install (easiest path)Adhoc dev build: https://github.com/stablyai/orca-adhoc/releases/tag/v1.4.210-adhoc.20260923230858
macOS is signed and notarized, so it installs normally. Windows is unsigned — SmartScreen will warn; choose More info → Run anyway. This is an unmerged branch build and is auto-deleted after a retention window. If you'd rather not install an unvetted build, check out You need ZCode's CLI on your PATH ( What to check
Where I most need help
Please report back on #22464 with your OS, ZCode version ( Notes on scopeUsage/rate-limit tracking (#21757, #18506) is not in this PR — it's a follow-up. Good news there: now that ZCode is open source, it turns out it records usage locally in Credit to the earlier attempts this builds on: #13965 / #10654 (@guanbear, @innocarpe) reached the same hook-install conclusion independently, and #21756 (@sunganhao8-lgtm) the same registration surface. cc @JWu527 @sunganhao8-lgtm @ArtemBozhenko @guanbear @innocarpe @penghuizhang @blacktoast @christh @Codemaster64 @jerrdasur @justforyoudear @kevinjkinder @liuhaoxh @megastruktur @verylovestars @aspectrr @damarro3 @lucianweber @AmethystLiang @brennanb2025 |
|
| Run | Failing test(s) | Count |
|---|---|---|
| 1 | scan cache per repo; caller-terminal lineage | expected 3, got 5 |
| 2 | valid orchestration lineage; cwd lineage fallback | — |
| 3 | scan cache per repo | expected 3, got 4 |
Different tests, different counts, same file. A deterministic break would fail the same test with the same number every time.
Independently checked:
orca-runtime.test.tspasses locally on this branch: 1299 passed, 1 skipped.- This branch touches no runtime lineage or scan-cache code. The only
src/main/runtime/entries in the diff are my own transcript fixture and my own readiness test. - Shard 8/8 currently passes on other open PRs (e.g. feat(orchestration): let a structured chat run orchestration as itself #22568), so the shard is not broken for everyone — consistent with a load-dependent leak rather than an outage.
I'd rather not paper over it here: loosening the assertion would throw away a real invariant (scanning repo A twice and repo B once is what proves per-repo TTL expiry without sibling coupling). The fix belongs in #22567. Once that lands I'll rebase and this shard should go green without any change to ZCode code.
Everything else on this PR is green: 29 passing, including typecheck, static analysis, the mobile bundle, package (macOS + Windows), cross-version wire compatibility, and the SSH terminal/hooks e2e.
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
… 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.
The mobile agent picker now bundles ZCode's icon, which the session route reaches through the shared picker. Measured: the only module the closure gains is `src/shared/agent-icons/zcode.png`, the same single local input Muse's icon added.
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.
…nt, 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.
e758f55 to
e26b5ba
Compare
Rebased past #22567 — CI is fully green (31/31)
Three conflicts came up in the rebase, all resolved in this PR's favour rather than by taking either side blindly:
Verification on the rebased branch: The adhoc build linked above was cut from the pre-rebase commit; it is unaffected by the rebase (README, a test pin, and locale merges only — no ZCode behaviour changed), so it is still the right build to test against. Testing notes are unchanged: #22464 (comment) Still waiting on a live-session confirmation before merge — everything automated is green, but nobody has yet run a real ZCode turn with an actual Z.ai account, and Windows/Linux/SSH remain untested on real hardware. |
|
Confirmed a live session on macOS Apple Silicon with a real BigModel / Z.ai Coding Plan account. Environment
What worked
CLI caveat for other testers
That blocked Orca until I switched PATH to community I did not deeply exercise questions/approvals, send-to-agent, or Thanks for the adhoc builds and the checklist. |
|
Happy to help with more live testing (questions/approvals, send-to-agent, resume) if useful before merge — and I’d also be glad to contribute code to Orca going forward when there’s a good fit. |
…sion 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
|
@JWu527 — thank you, this is exactly the confirmation the PR was missing. A live turn on a real Coding Plan account is the one thing I couldn't produce myself, and hooks landing correctly ( Your The docs page now has a "ZCode: pick a CLI that ships the TUI" section with the exact error, why it's misleading, and a Worth noting for the record: your Yes please to the follow-up pass, if you have the time — questions/approvals, send-to-agent, and
Any of the three working is useful; any of them not working is more useful. And yes — contributions very welcome. The two follow-ups already scoped out of this PR are a local usage provider reading |
|
@JWu527 your Orca watches a freshly launched ZCode pane's first output and, when it sees that exact failure, replaces the bare stack trace with an explanation — that Orca's hooks are fine, that this Two things I found while building it that are worth knowing:
The rule keys on the failure, not the success. Matching #22730 is stacked on this PR since it needs Still useful if you have time: questions/approvals, send-to-agent, and |

ELI5
ZCode is Z.ai's coding agent. Until now Orca could only run it as a plain terminal command: no status dot, no "it's asking you something" badge, no notification when it finished, and it couldn't be used as a supervised worker. This teaches Orca how to talk to ZCode properly, so a ZCode pane behaves like a Claude or Codex pane.
What Changed
Before:
zcodewas not an agent Orca knew. You could type it into a blank terminal, and that was it — the sidebar showed a nameless terminal, the tab never said what ZCode was doing, nothing told you when it needed you, andworker-start --agent zcodewas not a thing.After: ZCode is in the agent picker with its own icon. Launching it installs Orca's managed hooks into ZCode's own config, and from then on the pane reports itself: working while it runs, "action required" when it asks a question or wants to approve a command, "ready" when it finishes — with the usual attention badge and completion notification. Prompts can be sent to it, sessions resume, and it can run as a supervised worker.
The mechanism is ZCode's lifecycle hooks. Z.ai open-sourced
zai-org/ZCoderecently, so this is written against the real source (agent CLI0.16.9) rather than guessed at. Six things came out of reading it that changed the implementation:hook_event_name,session_id,tool_name,tool_input,transcript_path,last_assistant_message) next to its own camelCase fields — deliberately, per its own comment. So ZCode routes through Orca's existing Claude-compatible vendor path and only needs its own identity, not a new parser.hooks.enableddefaults tofalse. This is the actual cause of the long-standing "ZCode never fires configured hooks" report (zai-org/feedback#32, quoted in Feature: Add ZCode (Z.ai / GLM-5.2) as a first-class supported agent #10564). Registering the events is not enough; the installer sets the flag, andgetStatus()reportspartialif it is ever turned back off.PermissionRequestonly fires with the approval card already on screen, racing the user's answer — never for an auto-approved call. That makes it trustworthy proof the pane is blocked, unlike the equivalent event on some other agents.AskUserQuestionwith Claude'squestions/optionsshape, so Orca's existing question card renders it with no new UI.zcode-cli. The expected foreground process cannot be the launch command, ordispatch --injectrefuses the pane withno_agent_detected.Also included: local + SSH + Windows hook installers, session resume (
--resume), skills discovery, the agent-picker/mobile/README/docs registration, and a captured PTY transcript with tests pinned to it.Three files crossed their
max-lineslimit, so each is split along a real seam rather than suppressed: 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.Why
#10564 (8 reactions) asks for this, and there are five prior attempts (#21756, #13965, #16227, #16228, #14556). They were all written before Z.ai open-sourced the CLI, which left two things unresolved that this PR can now settle with evidence:
zcodewas an unofficial third-party client being labelled as Z.ai's. That is no longer the situation:apps/zcode-cli/packages/cli/package.jsonin Z.ai's own repo declares"bin": { "zcode": ... }. This PR is built and tested against that first-party binary.Alternatives considered:
--model/--mode. ZCode's CLI has no--modelflag, and Orca's option-launch path applies nothing until a model id is chosen. A catalog would have accepted--modeland silently dropped it. Took opencode's position instead: no catalog, soworker-start --modelis refused with a clear message and ZCode launches with the model from its own config.Linked Issue
Refs #10564
Visual Proof
All captured against the real ZCode CLI 0.16.9, built from
zai-org/ZCode, running inside Orca from this branch. Status transitions were driven by posting ZCode's actual hook payloads to Orca's live hook endpoint, through the installedzcode-hook.sh.1. ZCode in the agent picker, with its own icon
2. Real ZCode running in an Orca pane — note Orca's ZCode agent panel on the right (version, status, subagents, MCP, modified files, todos), and the composer titled
Yolo, which is the--mode yolopermission default being applied.3. Status: working —
UserPromptSubmitlands the prompt and a spinner on the sidebar row.4. Question status —
AskUserQuestionflips the pane to waiting; the tab reads "ZCode - action required" (Orca's synthesized title) and the sidebar shows the attention badge.5. Approval / blocked —
PermissionRequestshows "Needs permission" with the exact command awaiting approval (Bash: rm -rf build/ && pnpm install --force).6. Completion + notification —
Stopflips the tab to "ZCode ready" with the unread-completion indicator and a green check on the sidebar row.7. Send to agent — a prompt typed into Orca's terminal input is delivered into the live ZCode pane (
stdin-after-start, gated on the composer signal).8. Auto-setup actually wrote ZCode's config. After launch, the real
~/.zcode/cli/config.jsoncontained:9. The hook transport, end to end. Running the installed
zcode-hook.shwith a ZCode payload on stdin against a listener:Testing
pnpm tcclean.pnpm testover the affected trees: 11,908 passed, 1 expected fail, 179 skipped.pnpm run check:code-quality:changedpasses with 0 findings.New tests:
src/main/zcode/hook-service.test.ts— install/idempotency/removal against a temp$HOME, preserving the user's own hooks and key order,hooks.enabledhandling, thepartialstate when it is disabled, and that the result is still strict-JSON parseable (ZCode's loader isJSON.parse, not JSONC).src/shared/agent-hook-listener/providers/zcode-events.test.ts— every lifecycle event → status, including the question card'sinteractivePrompt, interruptedStop, and that events are attributed tozcodeand never toclaude.src/main/runtime/zcode-readiness-transcript.test.ts— pinned to the committed transcript: no OSC title, no quiescence after the composer mounts, the composer draft signal fires at the mount, and the synthetic title settles readiness.src/shared/zcode-orchestration-contract.test.ts— dispatchable process name, no catalog, stdin prompt transport, prompt kept out of the launch command.Transcript recorded with
config/scripts/capture-agent-pty-transcript.mjsperdocs/reference/agent-pty-transcript-capture.md; scrub check clean; tail truncated at a byte-exact escape boundary with the reason recorded in the sidecar.Platforms: manually tested on macOS. Linux and Windows are covered by construction and by the shared contract tests (Windows
.cmdwrapper and POSIX.shboth asserted inmanaged-hook-command-contract.test.ts); SSH install is covered byremote-hook-service-installers.test.ts, and both remain untested on real Linux/Windows/SSH hosts — worth a look from someone with those.AI Disclosure
Implemented with Claude (Opus 5) via Claude Code, working from the
zai-org/ZCodesource.Review
Deliberately not in this PR, both because they are separate subsystems and because Muse shipped them the same way (harness first, then #22379):
~/.zcode/cli/db/db.sqlite, in amodel_usagetable withstarted_at,provider_id,model_id, input/output/reasoning/cache token columns and an index on(started_at, provider_id, model_id). I confirmed 93 real rows on a machine with ZCode installed. That means a local usage provider is possible, which sidesteps the objection in Usage/rate-limit tracking for ZCode (Z.ai GLM Coding Plan)? #21757 about shipping a fetcher against an undocumented internal billing endpoint. That is the path I would take, as a follow-up.session/message/parttables in an OpenCode-shaped schema, so it should reuse the existing OpenCode SQLite scanner rather than a new parser.Prior art credit: #13965 / #10654 (@guanbear, @innocarpe) reached the same
~/.zcode/cli/config.jsonhook-install conclusion independently, and #21756 (@sunganhao8-lgtm) the same registration surface.Agent skill upstream boundary
Notes
hooks.enabledalone on removal, since the user may be running hooks of their own.~/.zcode/cliishomedir()-relative on every platform in ZCode's own resolver (no APPDATA/XDG branch), so the path needs no per-OS special case. Windows gets the.cmdwrapper, SSH the POSIX.sh.installRemotewrites over SFTP through Orca's shared atomic writer and is covered by the remote installer ratchet.RUNTIME_CAPABILITIESso older hosts negotiate it rather than receiving an unknown field.Checklist
pnpm typecheck,pnpm test, changed-code quality gate pass locally