From 43431ded34d415d277be68442fc12214adff2ebd Mon Sep 17 00:00:00 2001 From: "Bing.Z" Date: Wed, 7 Oct 2026 17:29:34 +0800 Subject: [PATCH] fix(cli): accept Orca agent ids in skills install --agent A typed --agent value that is an Orca agent id (claude) now maps onto the skills CLI key (claude-code) through the existing agent-key table, the same way detected agents already do. Unknown values still pass through for the skills CLI to reject. trae stays trae because it is also the skills CLI's own TRAE key; the detected-agent mapping to trae-cn is unchanged. Fixes #20831 --- src/cli/handlers/skills.ts | 8 +++++++- src/cli/skills.test.ts | 7 ++++--- src/shared/skills-cli-agent-keys.test.ts | 14 ++++++++++++++ src/shared/skills-cli-agent-keys.ts | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/cli/handlers/skills.ts b/src/cli/handlers/skills.ts index 325262a42f5..cbd4a3a0590 100644 --- a/src/cli/handlers/skills.ts +++ b/src/cli/handlers/skills.ts @@ -17,7 +17,11 @@ import { UnsafeWindowsBatchArgumentsError, WINDOWS_BATCH_UNSAFE_CHARACTERS_LABEL } from '../../shared/windows-batch-spawn' -import { isUsableSkillsCliAgentKey, toSkillsCliAgentKeys } from '../../shared/skills-cli-agent-keys' +import { + isUsableSkillsCliAgentKey, + toRequestedSkillsCliAgentKey, + toSkillsCliAgentKeys +} from '../../shared/skills-cli-agent-keys' import { buildAgentFeatureSkillInstallArgs, buildAgentFeatureSkillUpdateArgs @@ -143,6 +147,8 @@ function resolveInstallAgentKeys(flags: Map): string[] .split(',') .map((entry) => entry.trim()) .filter(Boolean) + // Why: dedupe after mapping so `claude,claude-code` yields one target. + .map(toRequestedSkillsCliAgentKey) ) ] // Why: a value like "," parses to nothing. Falling through to detection would diff --git a/src/cli/skills.test.ts b/src/cli/skills.test.ts index 19b26037d92..77b8f5112f2 100644 --- a/src/cli/skills.test.ts +++ b/src/cli/skills.test.ts @@ -778,7 +778,7 @@ describe('orca skills CLI', () => { vi.spyOn(process.stderr, 'write').mockImplementation(() => true) const resultPromise = main( - ['skills', 'install', '--skill', 'alpha', '--agent', 'codex, claude-code ,codex'], + ['skills', 'install', '--skill', 'alpha', '--agent', 'codex, claude-code ,codex,claude,trae'], '/tmp/repo' ) await vi.waitFor(() => expect(spawnMock).toHaveBeenCalled()) @@ -787,8 +787,9 @@ describe('orca skills CLI', () => { const argv = spawnMock.mock.calls[0]?.[1] ?? [] const agents = argv.filter((_: string, i: number) => argv[i - 1] === '--agent') - // Why: trimmed and de-duplicated, and detection is not consulted at all. - expect(agents).toEqual(['codex', 'claude-code']) + // Why: trimmed and de-duplicated, and detection is not consulted at all. Orca's + // `claude` becomes `claude-code`; `trae` is the CLI's own key, so it is kept. + expect(agents).toEqual(['codex', 'claude-code', 'trae']) expect(detectCommandsMock).not.toHaveBeenCalled() }) diff --git a/src/shared/skills-cli-agent-keys.test.ts b/src/shared/skills-cli-agent-keys.test.ts index 02bdd8b52df..84c8b582064 100644 --- a/src/shared/skills-cli-agent-keys.test.ts +++ b/src/shared/skills-cli-agent-keys.test.ts @@ -4,6 +4,7 @@ import { SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT, isUsableSkillsCliAgentKey, SKILLS_CLI_UNIVERSAL_AGENT_KEY, + toRequestedSkillsCliAgentKey, toSkillsCliAgentKeys } from './skills-cli-agent-keys' @@ -134,4 +135,17 @@ describe('skills CLI agent keys', () => { expect(toSkillsCliAgentKeys(['omp'])).toEqual(['universal']) expect(toSkillsCliAgentKeys([])).toEqual(['universal']) }) + + it('maps a typed Orca agent id unless the skills CLI already owns that key', () => { + for (const [agent, key] of Object.entries(SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT)) { + // Why: an id that is itself a valid skills key (only `trae`) keeps the CLI's meaning. + const expected = key === null || SKILLS_CLI_VALID_AGENT_KEYS.has(agent) ? agent : key + expect(toRequestedSkillsCliAgentKey(agent), agent).toBe(expected) + } + expect(toRequestedSkillsCliAgentKey('claude')).toBe('claude-code') + expect(toRequestedSkillsCliAgentKey('trae')).toBe('trae') + for (const passthrough of ['claude-code', 'universal', '*', 'Claude', 'inference-sh']) { + expect(toRequestedSkillsCliAgentKey(passthrough), passthrough).toBe(passthrough) + } + }) }) diff --git a/src/shared/skills-cli-agent-keys.ts b/src/shared/skills-cli-agent-keys.ts index 2db871a0284..a76cc650b0b 100644 --- a/src/shared/skills-cli-agent-keys.ts +++ b/src/shared/skills-cli-agent-keys.ts @@ -1,4 +1,5 @@ import type { TuiAgent } from './tui-agent' +import { isTuiAgent } from './tui-agent-config' /** * The community `skills` CLI's own `--agent` key for each agent Orca detects. @@ -93,3 +94,20 @@ export function toSkillsCliAgentKeys(detectedAgents: readonly TuiAgent[]): strin } return [...keys].sort() } + +// Why: `trae` is also the skills CLI's own key for TRAE international, so a typed +// `trae` keeps that meaning rather than becoming the detected-agent target `trae-cn`. +const SKILLS_CLI_KEYS_SHADOWING_TUI_AGENTS: ReadonlySet = new Set(['trae']) + +/** + * Map a user-typed `--agent` value onto its skills key when it is an Orca agent id. + * + * Why: users type the id Orca accepts everywhere else (`claude`), which the skills CLI + * rejects. Values Orca cannot map pass through for the CLI to judge, as before. + */ +export function toRequestedSkillsCliAgentKey(value: string): string { + if (!isTuiAgent(value) || SKILLS_CLI_KEYS_SHADOWING_TUI_AGENTS.has(value)) { + return value + } + return SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT[value] ?? value +}