Skip to content

Commit d050a3f

Browse files
committed
fix: isolate configured skill loading
1 parent 9916746 commit d050a3f

4 files changed

Lines changed: 33 additions & 20 deletions

File tree

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ WEB_NO_PROXY=
4949
# Optional tool integrations. Enable only when configured intentionally.
5050
BROWSER_ENABLED=false
5151
MCP_ENABLED=false
52-
MCP_CONFIG_PATH=mcp-servers.json
52+
MCP_CONFIG_PATH=~/.husky/config/mcp-servers.json
5353

5454
# SkillHub community skill search
5555
SKILLHUB_API_KEY=

infra/src/main/java/io/github/huskyagent/infra/skill/SkillLoader.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,13 @@ public SkillLoader(SkillManager skillManager, HuskyDataPaths dataPaths) {
6060
public void load() {
6161
skillDirMap.clear();
6262
List<Skill> skills = new ArrayList<>();
63-
Path userHome = Path.of(System.getProperty("user.home"));
64-
Path projectDir = Path.of(System.getProperty("user.dir"));
65-
66-
scanSkillDir(resolveBuiltinSkillDir(), "builtin", skills);
67-
scanSkillDir(userHome.resolve(".claude").resolve("skills"), "global-claude", skills);
68-
scanSkillDir(userHome.resolve(".husky").resolve("skills"), "global-husky", skills);
69-
scanSkillDir(projectDir.resolve(".claude").resolve("skills"), "project-claude", skills);
63+
scanSkillDir(resolveBuiltinSkillDir(), "builtin", skills);
7064
for (Path managedRoot : scanSkillRoots()) {
7165
scanSkillDir(managedRoot, "managed-husky", skills);
7266
}
7367

7468
skillManager.setSkills(skills);
75-
log.info("Loaded {} skills (builtin + global + project)", skills.size());
69+
log.info("Loaded {} skills (builtin + configured)", skills.size());
7670
}
7771

7872
private void scanSkillDir(Path dir, String source, List<Skill> skills) {
@@ -285,15 +279,8 @@ void setBuiltinDirForTesting(String builtinDir) {
285279
}
286280

287281
public Set<Path> getWatchedRoots() {
288-
Path userHome = Path.of(System.getProperty("user.home"));
289-
Path projectDir = Path.of(System.getProperty("user.dir"));
290282
return Stream.concat(
291-
Stream.of(
292-
resolveSkillDir(builtinDir),
293-
userHome.resolve(".claude").resolve("skills"),
294-
userHome.resolve(".husky").resolve("skills"),
295-
projectDir.resolve(".claude").resolve("skills")
296-
),
283+
Stream.of(resolveSkillDir(builtinDir)),
297284
scanSkillRoots().stream()
298285
)
299286
.map(Path::toAbsolutePath)

infra/src/test/java/io/github/huskyagent/infra/skill/SkillLoaderTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,33 @@ void patchAllowsConfiguredManagedDirBeyondSkillDir() throws IOException {
124124
assertEquals("patched", skillManager.getSkill("global").content());
125125
}
126126

127+
@Test
128+
void loadUsesConfiguredSkillRootsOnly() throws IOException {
129+
Path fixedGlobal = tempDir.resolve("home/.husky/skills");
130+
Path fixedClaude = tempDir.resolve("home/.claude/skills");
131+
Path fixedProject = tempDir.resolve("project/.claude/skills");
132+
String oldUserHome = System.getProperty("user.home");
133+
String oldUserDir = System.getProperty("user.dir");
134+
try {
135+
System.setProperty("user.home", tempDir.resolve("home").toString());
136+
System.setProperty("user.dir", tempDir.resolve("project").toString());
137+
createSkill(fixedGlobal, "global_husky", "global");
138+
createSkill(fixedClaude, "global_claude", "global");
139+
createSkill(fixedProject, "project_claude", "project");
140+
createManagedSkill("configured", List.of());
141+
142+
loader.load();
143+
144+
assertNotNull(skillManager.getSkill("configured"));
145+
assertNull(skillManager.getSkill("global_husky"));
146+
assertNull(skillManager.getSkill("global_claude"));
147+
assertNull(skillManager.getSkill("project_claude"));
148+
} finally {
149+
System.setProperty("user.home", oldUserHome);
150+
System.setProperty("user.dir", oldUserDir);
151+
}
152+
}
153+
127154
@Test
128155
void managedSkillRootsDefaultToSkillDir() {
129156
assertEquals(List.of(managedSkills.toAbsolutePath().normalize()), loader.managedSkillRoots());

service/src/main/resources/application.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,9 @@ auth:
395395
# Skill configuration
396396
skill:
397397
builtin-dir: builtin-skills
398-
# write target for install/create — also scanned as highest-priority source
399-
# auto-scanned (lower priority): ~/.claude/skills, ~/.husky/skills, .claude/skills
398+
# write target for install/create; also scanned for installed or user-authored skills
400399
dir: ${husky.data.dir}/skills
401-
# skill_manage patch/delete is restricted to skills loaded from these configured writable roots.
400+
# skill_manage patch/delete is restricted to skills loaded from these configured writable roots; these roots are also scanned.
402401
managed-dirs: ${SKILL_MANAGED_DIRS:${skill.dir}}
403402
disabled: []
404403

0 commit comments

Comments
 (0)