Skip to content
Merged
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
group=io.flamingock
version=1.2.1
version=1.2.2
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class InstallSkillsCommand implements Callable<Integer> {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ public static SkillsInstallationTarget claude(Path destinationSkillsDir) {
return new SkillsInstallationTarget("local:claude", destinationSkillsDir);
}

/**
* Creates an agent-specific installation target for the <code>codex</code> 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 <code>github</code> assistant.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public List<SkillsInstallationTarget> 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<SkillsInstallationTarget> resolveTargets(Path workingDirectory, boolean global, String agent) {
Expand All @@ -80,6 +80,10 @@ public List<SkillsInstallationTarget> 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));
Expand All @@ -105,7 +109,7 @@ public List<SkillsInstallationTarget> 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.");
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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"));
Expand All @@ -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"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand All @@ -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<SkillsInstallationTarget> 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"));
Expand Down Expand Up @@ -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"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading