Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Works with **any CLI agent** — if it runs in a terminal, it runs in Orca.
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="docs/assets/droid-logo.svg" alt="Droid logo" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Kilocode logo" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Kimi logo" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="ZCode logo" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Kiro logo" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Mistral Vibe logo" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Qwen Code logo" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
2 changes: 2 additions & 0 deletions config/tsconfig.cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
"../src/main/kimi/hook-service.ts",
"../src/main/kimi/kimi-hook-config-toml.ts",
"../src/main/openclaude/hook-service.ts",
"../src/main/zcode/hook-service.ts",
"../src/main/zcode/zcode-hook-config.ts",
"../src/main/rolling-file-backup.ts",
"../src/main/startup/hydrate-shell-path.ts",
"../src/main/startup/windows-shell-path-ownership.ts",
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ Funciona con **cualquier agente CLI** — si corre en una terminal, corre en Orc
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Droid logo" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Kilocode logo" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Kimi logo" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="ZCode logo" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Kiro logo" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Mistral Vibe logo" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Qwen Code logo" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ Fonctionne avec **n'importe quel agent CLI** — s'il tourne dans un terminal, i
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Logo Droid" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Logo Kilocode" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Logo Kimi" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="Logo ZCode" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Logo Kiro" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Logo Mistral Vibe" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Logo Qwen Code" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ PR、Issue、プロジェクトボードをアプリ内で閲覧 — 任意の
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Droid logo" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Kilocode logo" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Kimi logo" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="ZCode logo" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Kiro logo" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Mistral Vibe logo" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Qwen Code logo" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ diff의 어느 줄에든 코멘트를 남기고 에이전트에게 바로 보내
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Droid logo" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Kilocode logo" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Kimi logo" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="ZCode logo" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Kiro logo" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Mistral Vibe logo" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Qwen Code logo" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Funciona com **qualquer agente CLI** — se roda em um terminal, roda no Orca.
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Logotipo do Droid" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Logotipo do Kilocode" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Logotipo do Kimi" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/en/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="Logotipo do ZCode" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Logotipo do Kiro" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Logotipo do Mistral Vibe" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Logotipo do Qwen Code" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
1 change: 1 addition & 0 deletions docs/readme/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ VS Code 的编辑器,处处自动保存 — 把文件或图片直接拖入智
<a href="https://docs.factory.ai/cli/getting-started/quickstart"><kbd><img src="../assets/droid-logo.svg" alt="Droid logo" width="16" valign="middle" /> Droid</kbd></a> &nbsp;
<a href="https://kilo.ai/docs/cli"><kbd><img src="https://raw.githubusercontent.com/Kilo-Org/kilocode/main/packages/kilo-vscode/assets/icons/kilo-light.svg" alt="Kilocode logo" width="16" valign="middle" /> Kilocode</kbd></a> &nbsp;
<a href="https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html"><kbd><img src="https://www.google.com/s2/favicons?domain=moonshot.cn&sz=64" alt="Kimi logo" width="16" valign="middle" /> Kimi</kbd></a> &nbsp;
<a href="https://zcode.z.ai/cn/docs/welcome"><kbd><img src="https://www.google.com/s2/favicons?domain=z.ai&sz=64" alt="ZCode logo" width="16" valign="middle" /> ZCode</kbd></a> &nbsp;
<a href="https://kiro.dev/docs/cli/"><kbd><img src="https://www.google.com/s2/favicons?domain=kiro.dev&sz=64" alt="Kiro logo" width="16" valign="middle" /> Kiro</kbd></a> &nbsp;
<a href="https://github.com/mistralai/mistral-vibe"><kbd><img src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="Mistral Vibe logo" width="16" valign="middle" /> Mistral Vibe</kbd></a> &nbsp;
<a href="https://github.com/QwenLM/qwen-code"><kbd><img src="https://www.google.com/s2/favicons?domain=qwenlm.github.io&sz=64" alt="Qwen Code logo" width="16" valign="middle" /> Qwen Code</kbd></a> &nbsp;
Expand Down
3 changes: 2 additions & 1 deletion mobile/src/tasks/mobile-tui-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export const MOBILE_TUI_AGENT_FAVICON_DOMAINS: Partial<Record<TuiAgent, string>>
rovo: 'atlassian.com',
hermes: 'nousresearch.com',
devin: 'devin.ai',
openclaw: 'openclaw.ai'
openclaw: 'openclaw.ai',
zcode: 'z.ai'
}

export const isMobileTuiAgent: (value: unknown) => value is TuiAgent = isTuiAgent
Expand Down
13 changes: 9 additions & 4 deletions src/main/agent-hooks/managed-agent-hook-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { grokHookService } from '../grok/hook-service'
import { hermesHookService } from '../hermes/hook-service'
import { kimiHookService } from '../kimi/hook-service'
import { openClaudeHookService } from '../openclaude/hook-service'
import { zcodeHookService } from '../zcode/hook-service'

// Why (#16441): Codex's installer awaits a codex app-server trust-grant session
// instead of blocking the main thread on spawnSync. Widening the tuple keeps the
Expand Down Expand Up @@ -50,7 +51,8 @@ export const MANAGED_AGENT_HOOK_INSTALLERS: readonly ManagedAgentHookInstaller[]
['copilot', () => copilotHookService.install()],
['hermes', () => hermesHookService.install()],
['devin', () => devinHookService.install()],
['kimi', () => kimiHookService.install()]
['kimi', () => kimiHookService.install()],
['zcode', () => zcodeHookService.install()]
]

// Why: covers the shared launcher/statusline scripts under ~/.orca/agent-hooks — the files a
Expand All @@ -71,7 +73,8 @@ export const MANAGED_AGENT_HOOK_SCRIPT_REFRESHERS: readonly ManagedAgentHookScri
['grok', () => grokHookService.refreshManagedScripts()],
['copilot', () => copilotHookService.refreshManagedScripts()],
['devin', () => devinHookService.refreshManagedScripts()],
['kimi', () => kimiHookService.refreshManagedScripts()]
['kimi', () => kimiHookService.refreshManagedScripts()],
['zcode', () => zcodeHookService.refreshManagedScripts()]
]

export const MANAGED_AGENT_HOOK_REMOVERS: readonly ManagedAgentHookRemover[] = [
Expand All @@ -88,7 +91,8 @@ export const MANAGED_AGENT_HOOK_REMOVERS: readonly ManagedAgentHookRemover[] = [
['copilot', () => copilotHookService.remove()],
['hermes', () => hermesHookService.remove()],
['devin', () => devinHookService.remove()],
['kimi', () => kimiHookService.remove()]
['kimi', () => kimiHookService.remove()],
['zcode', () => zcodeHookService.remove()]
]

export const MANAGED_AGENT_HOOK_ASYNC_REMOVERS: readonly ManagedAgentHookAsyncRemover[] = [
Expand All @@ -109,5 +113,6 @@ export const MANAGED_AGENT_HOOK_STATUS_READERS: readonly ManagedAgentHookStatusR
['copilot', () => copilotHookService.getStatus()],
['hermes', () => hermesHookService.getStatus()],
['devin', () => devinHookService.getStatus()],
['kimi', () => kimiHookService.getStatus()]
['kimi', () => kimiHookService.getStatus()],
['zcode', () => zcodeHookService.getStatus()]
]
6 changes: 3 additions & 3 deletions src/main/agent-hooks/managed-hook-local-filesystem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ describe('managed-hook local filesystem', () => {
const cold = await installRemoteManagedAgentHooks(filesystem, home, options)
const warm = await installRemoteManagedAgentHooks(filesystem, home, options)

expect(cold).toHaveLength(14)
expect(cold).toHaveLength(15)
expect(cold.filter((result) => result.state === 'error')).toEqual([])
expect(warm).toHaveLength(14)
expect(warm).toHaveLength(15)
expect(warm.filter((result) => result.state === 'error')).toEqual([])
const files = await listFiles(home)
expect(files.filter((path) => path.endsWith('.tmp'))).toEqual([])
Expand All @@ -71,7 +71,7 @@ describe('managed-hook local filesystem', () => {
agents: REMOTE_MANAGED_HOOK_INSTALLER_AGENTS
})

expect(results).toHaveLength(14)
expect(results).toHaveLength(15)
expect(results.find((result) => result.agent === 'claude')?.state).toBe('error')
expect(results.find((result) => result.agent === 'openclaude')?.state).toBe('installed')
expect(results.find((result) => result.agent === 'kimi')?.state).toBe('installed')
Expand Down
8 changes: 7 additions & 1 deletion src/main/agent-hooks/remote-hook-service-installers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { CopilotHookService, copilotHookService } from '../copilot/hook-service'
import { HermesHookService, hermesHookService } from '../hermes/hook-service'
import { DevinHookService, devinHookService } from '../devin/hook-service'
import { KimiHookService, kimiHookService } from '../kimi/hook-service'
import { ZcodeHookService, zcodeHookService } from '../zcode/hook-service'
import { openClaudeHookService } from '../openclaude/hook-service'
import { MANAGED_AGENT_HOOK_INSTALLERS } from './managed-agent-hook-controls'
import {
Expand Down Expand Up @@ -189,6 +190,10 @@ describe('remote hook service installers', () => {
{
path: '/home/dev/.orca/agent-hooks/droid-hook.sh',
install: (sftp: SFTPWrapper) => new DroidHookService().installRemote(sftp, '/home/dev')
},
{
path: '/home/dev/.orca/agent-hooks/zcode-hook.sh',
install: (sftp: SFTPWrapper) => new ZcodeHookService().installRemote(sftp, '/home/dev')
}
]

Expand Down Expand Up @@ -709,7 +714,8 @@ describe('remote hook service installers', () => {
['copilot', copilotHookService],
['hermes', hermesHookService],
['devin', devinHookService],
['kimi', kimiHookService]
['kimi', kimiHookService],
['zcode', zcodeHookService]
])

// Guard against a service silently missing from the map above as new agents land.
Expand Down
4 changes: 3 additions & 1 deletion src/main/agent-hooks/remote-managed-hook-installers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { grokHookService } from '../grok/hook-service'
import { hermesHookService } from '../hermes/hook-service'
import { kimiHookService } from '../kimi/hook-service'
import { openClaudeHookService } from '../openclaude/hook-service'
import { zcodeHookService } from '../zcode/hook-service'

export type RemoteManagedHookInstallOptions = {
/** Explicit CODEX_HOME dir for redirected runtimes (for example WSL's managed runtime home). */
Expand Down Expand Up @@ -72,7 +73,8 @@ const REMOTE_MANAGED_HOOK_INSTALLERS: readonly RemoteManagedHookInstaller[] = [
['droid', (sftp, remoteHome) => droidHookService.installRemote(sftp, remoteHome)],
['hermes', (sftp, remoteHome) => hermesHookService.installRemote(sftp, remoteHome)],
['devin', (sftp, remoteHome) => devinHookService.installRemote(sftp, remoteHome)],
['kimi', (sftp, remoteHome) => kimiHookService.installRemote(sftp, remoteHome)]
['kimi', (sftp, remoteHome) => kimiHookService.installRemote(sftp, remoteHome)],
['zcode', (sftp, remoteHome) => zcodeHookService.installRemote(sftp, remoteHome)]
]

/** Agents wired into the remote (SSH) hook installer. Exported so an invariant
Expand Down
1 change: 1 addition & 0 deletions src/main/agent-hooks/server-retired-pane-new-turn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const NEW_TURN_EVENT: Record<AgentHookSource, string | null> = {
copilot: 'sessionStart',
hermes: 'pre_llm_call',
devin: 'UserPromptSubmit',
zcode: 'UserPromptSubmit',
opencode: 'SessionStart',
opencode2: 'SessionStart',
'mimo-code': null,
Expand Down
16 changes: 16 additions & 0 deletions src/main/ipc/agent-hooks-zcode-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { AgentHookInstallStatus } from '../../shared/agent-hook-types'
import { zcodeHookService } from '../zcode/hook-service'

export function getZcodeHookStatus(): AgentHookInstallStatus {
try {
return zcodeHookService.getStatus()
} catch (error) {
return {
agent: 'zcode',
state: 'error',
configPath: '',
managedHooksPresent: false,
detail: error instanceof Error ? error.message : String(error)
}
}
}
41 changes: 41 additions & 0 deletions src/main/ssh/ssh-relay-session-managed-hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,45 @@ describe('SshRelaySession managed hooks', () => {
})
)
})

it('retries without ZCode when an older relay rejects the expanded allowlist', async () => {
let installAttempts = 0
muxRequestMock.mockImplementation(async (method: string) => {
if (method === 'preflight.detectAgents') {
return { agents: ['codex', 'zcode'] }
}
if (method === AGENT_HOOK_INSTALL_MANAGED_HOOKS_METHOD) {
installAttempts += 1
if (installAttempts === 1) {
throw new Error('remote request failed: invalid_managed_hook_agents')
}
return { installers: 1, errors: 0 }
}
return { ok: true }
})
const { mockStore, mockPortForward, getMainWindow } = createMockDeps()
const connection = {
sftp: vi.fn(),
getHostKeyFingerprint: vi.fn(() => 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
} as unknown as SshConnection
const session = new SshRelaySession('target-1', getMainWindow, mockStore, mockPortForward)

await session.establish(connection)
await vi.waitFor(() => expect(installAttempts).toBe(2))

const installCalls = muxRequestMock.mock.calls.filter(
([method]) => method === AGENT_HOOK_INSTALL_MANAGED_HOOKS_METHOD
)
expect(installCalls.map(([, params]) => params)).toEqual([
{
hostKeyFingerprint: 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
agents: ['codex', 'zcode']
},
{
hostKeyFingerprint: 'SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
agents: ['codex']
}
])
expect(registerSshPtyProvider).toHaveBeenCalled()
})
})
Loading