fix(jcode): register in main's remote-installer guard, drop our duplicate

Rebasing onto 853 commits of main surfaced two things the earlier branch
had hidden.

main already owns a guard for the issue-#7253 bug class
(`remote-hook-service-registry-coverage.test.ts`). This branch had added a
second, near-identical one — a parallel implementation of a test that
already existed, which is what AGENTS.md's reuse rule is about. Deleted
ours and registered jcode in main's, which is the one that has kept pace
with every agent added since.

Also fixes a missing separator in the mobile icon map. `pnpm tc` does not
cover `mobile/`, so only the session-route closure suite caught it.

Co-authored-by: czzczz <chanzrz_zbf@foxmail.com>
This commit is contained in:
Neil
2026-10-03 01:49:40 -07:00
committed by Neil
co-authored by czzczz
parent 154b2fdab8
commit 84d246b9f0
6 changed files with 10 additions and 73 deletions
@@ -46,6 +46,6 @@ export const MOBILE_AGENT_ICON_ASSETS: Partial<Record<TuiAgent, ImageSourcePropT
muse: require('../../../src/shared/agent-icons/muse.png'),
dsh: require('../../../src/shared/agent-icons/dsh.png'),
zcode: require('../../../src/shared/agent-icons/zcode.png'),
openclaw: require('../../../src/shared/agent-icons/openclaw.png')
openclaw: require('../../../src/shared/agent-icons/openclaw.png'),
jcode: require('../../../src/shared/agent-icons/jcode.png')
}
@@ -1,68 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
vi.mock('electron', () => ({
app: {
getPath: () => '/tmp/orca-user-data'
}
}))
import { claudeHookService } from '../claude/hook-service'
import { openClaudeHookService } from '../openclaude/hook-service'
import { codexHookService } from '../codex/hook-service'
import { geminiHookService } from '../gemini/hook-service'
import { antigravityHookService } from '../antigravity/hook-service'
import { ampHookService } from '../amp/hook-service'
import { cursorHookService } from '../cursor/hook-service'
import { droidHookService } from '../droid/hook-service'
import { commandCodeHookService } from '../command-code/hook-service'
import { grokHookService } from '../grok/hook-service'
import { copilotHookService } from '../copilot/hook-service'
import { hermesHookService } from '../hermes/hook-service'
import { devinHookService } from '../devin/hook-service'
import { kimiHookService } from '../kimi/hook-service'
import { museHookService } from '../muse/hook-service'
import { jcodeHookService } from '../jcode/hook-service'
import { MANAGED_AGENT_HOOK_INSTALLERS } from './managed-agent-hook-controls'
import { REMOTE_MANAGED_HOOK_INSTALLER_AGENTS } from './remote-managed-hook-installers'
// Why: Droid (and Copilot) each shipped a working installRemote but were never
// registered in REMOTE_MANAGED_HOOK_INSTALLERS, so their status silently never
// appeared over SSH (issue #7253). Guard the whole bug class, not one agent:
// every locally-managed hook service that implements installRemote MUST be
// wired into the remote installer.
describe('remote hook installer registry guard', () => {
it('registers every managed agent that implements installRemote in the remote installer (issue #7253)', () => {
const servicesByAgent = new Map<string, { installRemote?: unknown }>([
['claude', claudeHookService],
['openclaude', openClaudeHookService],
['codex', codexHookService],
['gemini', geminiHookService],
['antigravity', antigravityHookService],
['amp', ampHookService],
['cursor', cursorHookService],
['droid', droidHookService],
['command-code', commandCodeHookService],
['grok', grokHookService],
['copilot', copilotHookService],
['hermes', hermesHookService],
['devin', devinHookService],
['kimi', kimiHookService],
['muse', museHookService],
['jcode', jcodeHookService]
])
// Guard against a service silently missing from the map above as new agents land.
for (const [agent] of MANAGED_AGENT_HOOK_INSTALLERS) {
expect(servicesByAgent.has(agent)).toBe(true)
}
const registered = new Set<string>(REMOTE_MANAGED_HOOK_INSTALLER_AGENTS)
const missing: string[] = []
for (const [agent, service] of servicesByAgent) {
if (typeof service.installRemote === 'function' && !registered.has(agent)) {
missing.push(agent)
}
}
expect(missing).toEqual([])
})
})
@@ -26,6 +26,7 @@ import { openClaudeHookService } from '../openclaude/hook-service'
import { qwenCodeHookService } from '../qwen-code/hook-service'
import { qoderCnHookService, qoderHookService } from '../qoder/hook-service'
import { zcodeHookService } from '../zcode/hook-service'
import { jcodeHookService } from '../jcode/hook-service'
import { MANAGED_AGENT_HOOK_INSTALLERS } from './managed-agent-hook-controls'
import { REMOTE_MANAGED_HOOK_INSTALLER_AGENTS } from './remote-managed-hook-installers'
@@ -59,7 +60,8 @@ describe('remote hook service registry coverage', () => {
['qwen-code', qwenCodeHookService],
['codebuddy', codebuddyHookService],
['zcode', zcodeHookService],
['dsh', dshHookService]
['dsh', dshHookService],
['jcode', jcodeHookService]
])
// Guard against a service silently missing from the map above as new agents land.
+2 -1
View File
@@ -6,7 +6,8 @@ import { dirname, join } from 'node:path'
const { homedirMock } = vi.hoisted(() => ({ homedirMock: vi.fn<() => string>() }))
vi.mock('os', async () => {
const actual = await vi.importActual<typeof import('os')>('os') // eslint-disable-line @typescript-eslint/consistent-type-imports -- vi.importActual requires inline import()
// oxlint-disable-next-line typescript/consistent-type-imports -- vi.importActual needs the inline import() to type the real module
const actual = await vi.importActual<typeof import('os')>('os')
return { ...actual, homedir: homedirMock }
})
+2 -1
View File
@@ -8,7 +8,8 @@ const { homedirMock } = vi.hoisted(() => ({
}))
vi.mock('os', async () => {
const actual = await vi.importActual<typeof import('os')>('os') // eslint-disable-line @typescript-eslint/consistent-type-imports -- vi.importActual requires inline import()
// oxlint-disable-next-line typescript/consistent-type-imports -- vi.importActual needs the inline import() to type the real module
const actual = await vi.importActual<typeof import('os')>('os')
return { ...actual, homedir: homedirMock }
})
+2 -1
View File
@@ -8,7 +8,8 @@ const { homedirMock } = vi.hoisted(() => ({
}))
vi.mock('os', async () => {
const actual = await vi.importActual<typeof import('os')>('os') // eslint-disable-line @typescript-eslint/consistent-type-imports -- vi.importActual requires inline import()
// oxlint-disable-next-line typescript/consistent-type-imports -- vi.importActual needs the inline import() to type the real module
const actual = await vi.importActual<typeof import('os')>('os')
return { ...actual, homedir: homedirMock }
})