Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ public static boolean saveSkills(Path baseDir, List<AgentSkill> skills, boolean
return false;
}

int size = skills.size();
int saveCount = 0;
try {
for (AgentSkill skill : skills) {
String skillName = skill.getName();
Expand All @@ -182,7 +184,7 @@ public static boolean saveSkills(Path baseDir, List<AgentSkill> skills, boolean
if (!force) {
logger.info(
"Skill directory already exists and force=false: {}", skillName);
return false;
continue; // Skip to the next skill if force=false
} else {
logger.info("Overwriting existing skill directory: {}", skillName);
deleteDirectory(skillDir);
Expand Down Expand Up @@ -215,10 +217,15 @@ public static boolean saveSkills(Path baseDir, List<AgentSkill> skills, boolean
}
}

saveCount++;
logger.info("Successfully saved skill: {}", skillName);
}
boolean allSaved = (size == saveCount);
if (!allSaved) {
logger.warn("Not all skills were saved. Saved {} of {}", saveCount, size);
}

return true;
return allSaved;
} catch (IOException e) {
logger.error("Failed to save skills", e);
throw new RuntimeException("Failed to save skills", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,72 @@ void testSaveSkills_ExistingSkill_ForceDisabled() {
assertEquals("Test Skill", loaded.getDescription());
}

@Test
@DisplayName(
"Should save zero skills and leave file contents unchanged when all exist and force is"
+ " false")
void testSaveSkills_AllExistingSkills_ForceDisabled_NoSkillsSaved() throws IOException {
String originalTestSkill =
Files.readString(
skillsBaseDir.resolve("test-skill/SKILL.md"), StandardCharsets.UTF_8);
String originalAnotherSkill =
Files.readString(
skillsBaseDir.resolve("another-skill/SKILL.md"), StandardCharsets.UTF_8);

AgentSkill skill1 = new AgentSkill("test-skill", "Updated Test", "Updated content 1", null);
AgentSkill skill2 =
new AgentSkill("another-skill", "Updated Another", "Updated content 2", null);

boolean result =
SkillFileSystemHelper.saveSkills(skillsBaseDir, List.of(skill1, skill2), false);

// 0 out of 2 saved — no coverage at all
assertFalse(result);
assertEquals(
originalTestSkill,
Files.readString(
skillsBaseDir.resolve("test-skill/SKILL.md"), StandardCharsets.UTF_8),
"test-skill SKILL.md must not be modified");
assertEquals(
originalAnotherSkill,
Files.readString(
skillsBaseDir.resolve("another-skill/SKILL.md"), StandardCharsets.UTF_8),
"another-skill SKILL.md must not be modified");
}

@Test
@DisplayName("Should save new skills while leaving existing ones unchanged when force is false")
void testSaveSkills_MixedSkills_ForceDisabled_NewSavedExistingUnchanged() throws IOException {
String originalContent =
Files.readString(
skillsBaseDir.resolve("test-skill/SKILL.md"), StandardCharsets.UTF_8);

AgentSkill existingSkill =
new AgentSkill("test-skill", "Updated Description", "Updated content", null);
AgentSkill newSkill = new AgentSkill("brand-new-skill", "Brand New", "New content", null);

boolean result =
SkillFileSystemHelper.saveSkills(
skillsBaseDir, List.of(existingSkill, newSkill), false);

// 1 out of 2 saved — not all saved
assertFalse(result);

// existing skill must not be modified
assertEquals(
originalContent,
Files.readString(
skillsBaseDir.resolve("test-skill/SKILL.md"), StandardCharsets.UTF_8),
"test-skill SKILL.md must not be modified");

// new skill must be saved correctly
AgentSkill loaded =
SkillFileSystemHelper.loadSkill(skillsBaseDir, "brand-new-skill", "source");
assertEquals("brand-new-skill", loaded.getName());
assertEquals("Brand New", loaded.getDescription());
assertEquals("New content", loaded.getSkillContent());
}

@Test
@DisplayName("Should overwrite when skill exists and force is true")
void testSaveSkills_ExistingSkill_ForceEnabled() {
Expand Down
Loading