From 1ee385498240a4f0be872a0bbc645d93c2f9af6c Mon Sep 17 00:00:00 2001 From: bercianor Date: Sat, 20 Jun 2026 19:59:54 +0200 Subject: [PATCH] feat: add codex to agent list in install-skills command --- gradle.properties | 2 +- .../command/InstallSkillsCommand.java | 2 +- .../skills/SkillsInstallationTarget.java | 10 ++++++++++ .../SkillsInstallationTargetResolver.java | 8 ++++++-- .../command/InstallSkillsCommandTest.java | 20 ++++++++++++++++++- .../SkillsInstallationTargetResolverTest.java | 16 +++++++++++++++ .../skills/SkillsInstallationTargetTest.java | 16 +++++++++++++++ 7 files changed, 69 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index fa79a43..c40a8f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=io.flamingock -version=1.2.1 +version=1.2.2 diff --git a/src/main/java/io/flamingock/cli/executor/command/InstallSkillsCommand.java b/src/main/java/io/flamingock/cli/executor/command/InstallSkillsCommand.java index 79e57f7..2835cc4 100644 --- a/src/main/java/io/flamingock/cli/executor/command/InstallSkillsCommand.java +++ b/src/main/java/io/flamingock/cli/executor/command/InstallSkillsCommand.java @@ -41,7 +41,7 @@ public class InstallSkillsCommand implements Callable { private boolean global; @Option(names = {"-a", "--agent"}, - description = "Target AI assistant: claude, github, cursor, opencode, gemini, windsurf, pi") + description = "Target AI assistant: claude, codex, github, cursor, opencode, gemini, windsurf, pi") private String agent; private final SkillsInstallationTargetResolver targetResolver; diff --git a/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTarget.java b/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTarget.java index 7cca7c5..12e36bb 100644 --- a/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTarget.java +++ b/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTarget.java @@ -61,6 +61,16 @@ public static SkillsInstallationTarget claude(Path destinationSkillsDir) { return new SkillsInstallationTarget("local:claude", destinationSkillsDir); } + /** + * Creates an agent-specific installation target for the codex assistant. + * + * @param destinationSkillsDir codex destination directory + * @return codex installation target + */ + public static SkillsInstallationTarget codex(Path destinationSkillsDir) { + return new SkillsInstallationTarget("local:codex", destinationSkillsDir); + } + /** * Creates an agent-specific installation target for the github assistant. * diff --git a/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolver.java b/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolver.java index c01bdf3..3b61c32 100644 --- a/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolver.java +++ b/src/main/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolver.java @@ -62,7 +62,7 @@ public List resolveTargets(Path workingDirectory, bool * * @param workingDirectory current command working directory * @param global whether global mode was requested - * @param agent target AI assistant identifier (claude, github, cursor, opencode, gemini, windsurf, pi) + * @param agent target AI assistant identifier (claude, codex, github, cursor, opencode, gemini, windsurf, pi) * @return resolved installation targets */ public List resolveTargets(Path workingDirectory, boolean global, String agent) { @@ -80,6 +80,10 @@ public List resolveTargets(Path workingDirectory, bool Path destination = directoryResolver.resolveDirectory(workingDirectory, CLAUDE_PATH); yield List.of(SkillsInstallationTarget.claude(destination)); } + case "codex" -> { + Path destination = directoryResolver.resolveDirectory(workingDirectory, LOCAL_SKILLS_PATH); + yield List.of(SkillsInstallationTarget.codex(destination)); + } case "github" -> { Path destination = directoryResolver.resolveDirectory(workingDirectory, GITHUB_PATH); yield List.of(SkillsInstallationTarget.github(destination)); @@ -105,7 +109,7 @@ public List resolveTargets(Path workingDirectory, bool yield List.of(SkillsInstallationTarget.pi(destination)); } default -> throw new IllegalStateException( - "Unsupported agent: '" + agent + "'. Supported values: claude, github, cursor, opencode, gemini, windsurf, pi."); + "Unsupported agent: '" + agent + "'. Supported values: claude, codex, github, cursor, opencode, gemini, windsurf, pi."); }; } } diff --git a/src/test/java/io/flamingock/cli/executor/command/InstallSkillsCommandTest.java b/src/test/java/io/flamingock/cli/executor/command/InstallSkillsCommandTest.java index a088a29..e5f6a8b 100644 --- a/src/test/java/io/flamingock/cli/executor/command/InstallSkillsCommandTest.java +++ b/src/test/java/io/flamingock/cli/executor/command/InstallSkillsCommandTest.java @@ -61,7 +61,7 @@ void call_defaultAgentPassesNullToResolver() { @Test void call_withInvalidAgentAgentsReturnsExitCodeOne() { FailingTargetResolver targetResolver = new FailingTargetResolver( - new IllegalStateException("Unsupported agent: 'agents'. Supported values: claude, github, cursor, opencode, gemini, windsurf, pi.") + new IllegalStateException("Unsupported agent: 'agents'. Supported values: claude, codex, github, cursor, opencode, gemini, windsurf, pi.") ); RecordingPipeline pipeline = new RecordingPipeline(new SkillsInstallationResult(List.of(), List.of())); InstallSkillsCommand command = new InstallSkillsCommand(targetResolver, pipeline, tempDir); @@ -81,6 +81,7 @@ void call_withInvalidAgentAgentsReturnsExitCodeOne() { String stderr = errContent.toString(StandardCharsets.UTF_8); assertTrue(stderr.contains("agents")); assertTrue(stderr.contains("claude")); + assertTrue(stderr.contains("codex")); assertTrue(stderr.contains("github")); assertTrue(stderr.contains("cursor")); assertTrue(stderr.contains("opencode")); @@ -106,6 +107,23 @@ void call_withAgentClaudePassesClaudeToResolver() { assertEquals("claude", targetResolver.agent); } + @Test + void call_withAgentCodexPassesCodexToResolver() { + SkillsInstallationTarget resolvedTarget = SkillsInstallationTarget.codex(tempDir.resolve(".agents/skills")); + RecordingTargetResolver targetResolver = new RecordingTargetResolver(List.of(resolvedTarget)); + RecordingPipeline pipeline = new RecordingPipeline(new SkillsInstallationResult( + List.of(resolvedTarget), + List.of("flamingock-core") + )); + InstallSkillsCommand command = new InstallSkillsCommand(targetResolver, pipeline, tempDir); + + int exitCode = new CommandLine(command).execute("-a", "codex"); + + assertEquals(0, exitCode); + assertTrue(targetResolver.called); + assertEquals("codex", targetResolver.agent); + } + @Test void call_withAgentGithubPassesGithubToResolver() { SkillsInstallationTarget resolvedTarget = SkillsInstallationTarget.github(tempDir.resolve(".github/skills")); diff --git a/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolverTest.java b/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolverTest.java index 704f629..6d3687a 100644 --- a/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolverTest.java +++ b/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetResolverTest.java @@ -72,6 +72,7 @@ void resolveTargets_agentsAgentThrowsWithSupportedValues() { String message = exception.getMessage(); assertTrue(message.contains("agents")); assertTrue(message.contains("claude")); + assertTrue(message.contains("codex")); assertTrue(message.contains("github")); assertTrue(message.contains("cursor")); assertTrue(message.contains("opencode")); @@ -93,6 +94,20 @@ void resolveTargets_claudeAgentResolvesToClaudePath() { assertTrue(directoryResolver.called); } + @Test + void resolveTargets_codexAgentResolvesToAgentsPath() { + RecordingDirectoryResolver directoryResolver = new RecordingDirectoryResolver(tempDir.resolve(".agents/skills")); + SkillsInstallationTargetResolver resolver = new SkillsInstallationTargetResolver(directoryResolver); + + List targets = resolver.resolveTargets(tempDir, false, "codex"); + + assertEquals(1, targets.size()); + assertEquals("local:codex", targets.get(0).identifier()); + assertEquals(tempDir.resolve(".agents/skills"), targets.get(0).destinationSkillsDir()); + assertArrayEquals(new String[]{".agents", "skills"}, directoryResolver.segments); + assertTrue(directoryResolver.called); + } + @Test void resolveTargets_geminiAgentResolvesToGeminiPath() { RecordingDirectoryResolver directoryResolver = new RecordingDirectoryResolver(tempDir.resolve(".gemini/skills")); @@ -184,6 +199,7 @@ void resolveTargets_invalidAgentThrowsWithSupportedValues() { String message = exception.getMessage(); assertTrue(message.contains("foo")); assertTrue(message.contains("claude")); + assertTrue(message.contains("codex")); assertTrue(message.contains("github")); assertTrue(message.contains("cursor")); assertTrue(message.contains("opencode")); diff --git a/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetTest.java b/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetTest.java index 1d9f885..6264539 100644 --- a/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetTest.java +++ b/src/test/java/io/flamingock/cli/executor/skills/SkillsInstallationTargetTest.java @@ -55,6 +55,22 @@ void claudeFactoryCreatesTargetWithClaudeIdentifier() { assertEquals(dest, target.destinationSkillsDir()); } + @Test + void codexFactoryCreatesTargetWithCodexIdentifier() { + Path dest = Path.of("/some/path/.agents/skills"); + SkillsInstallationTarget target = SkillsInstallationTarget.codex(dest); + + assertEquals("local:codex", target.identifier()); + assertEquals(dest, target.destinationSkillsDir()); + } + + @Test + void codexFactoryRejectsNullPath() { + assertThrows(NullPointerException.class, + () -> SkillsInstallationTarget.codex(null), + "destinationSkillsDir must not be null"); + } + @Test void githubFactoryCreatesTargetWithGithubIdentifier() { Path dest = Path.of("/some/path/.github/skills");