From bf6457e4887dd203bbab01cb992296819d620e28 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Fri, 6 Nov 2026 02:34:41 +0100 Subject: [PATCH] fix: accept omp and copilot in the per-mode command overrides (release review) RemoteCommandOverridesSchema is .strict() and stopped at deepseek, so the API refused a commands.omp or commands.copilot override although both modes can run remotely and in a container (RemoteCommandMode, DockerCommandMode) and the launch builders honour the key. The docs call the override the way out for a login shell the stock launch cannot run, which was not true for those two modes. The test walks the CLI registry, so the next CLI cannot miss the schema the same way. Co-Authored-By: Claude Opus 5.5 --- src/web/schemas.ts | 2 ++ test/remote-hosts.test.ts | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/web/schemas.ts b/src/web/schemas.ts index 10ef069a..b24fce25 100644 --- a/src/web/schemas.ts +++ b/src/web/schemas.ts @@ -867,6 +867,8 @@ const RemoteCommandOverridesSchema = z pi: z.string().min(1).max(300).optional(), grok: z.string().min(1).max(300).optional(), deepseek: z.string().min(1).max(300).optional(), + omp: z.string().min(1).max(300).optional(), + copilot: z.string().min(1).max(300).optional(), }) .strict() .optional(); diff --git a/test/remote-hosts.test.ts b/test/remote-hosts.test.ts index 8606d5d1..5e091b8e 100644 --- a/test/remote-hosts.test.ts +++ b/test/remote-hosts.test.ts @@ -2,6 +2,7 @@ import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, describe, expect, it } from 'vitest'; +import { listClis } from '../src/config/cli-registry/registry.js'; import { defaultRemoteCommandForMode, readRemoteCases, @@ -13,7 +14,7 @@ import { writeRemoteCases, writeRemoteHosts, } from '../src/remote-hosts.js'; -import { RemoteHostSchema } from '../src/web/schemas.js'; +import { DockerHostSchema, RemoteHostSchema } from '../src/web/schemas.js'; describe('remote-hosts domain', () => { let dir: string | null = null; @@ -126,6 +127,27 @@ describe('remote-hosts domain', () => { }); }); + describe('per-mode command overrides', () => { + const modes = ['shell', ...listClis().map((cli) => cli.id)]; + + // `.strict()` refuses an unknown key, so a mode missing here cannot take an override, and + // `commands.*` is the documented way out for a login shell the stock launch cannot run. + it.each(modes)('accepts a %s override on a remote host and a docker host', (mode) => { + const commands = { [mode]: 'exec my-agent' }; + const remote = { id: 'h', label: 'H', host: '10.0.0.1', username: 'u', commands }; + const docker = { id: 'h', label: 'H', image: 'codeman/agent:base', commands }; + expect(RemoteHostSchema.safeParse(remote).success).toBe(true); + expect(DockerHostSchema.safeParse(docker).success).toBe(true); + }); + + it('still refuses a key that is no mode', () => { + const commands = { nope: 'exec my-agent' }; + expect(RemoteHostSchema.safeParse({ id: 'h', label: 'H', host: '10.0.0.1', username: 'u', commands }).success).toBe( + false + ); + }); + }); + describe('rehydrateRemoteHostFields', () => { const persisted = { hostId: 'hufflepuff',