pi-toggle-skills 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/skill-discovery.ts +18 -7
- package/src/skill-selector.ts +1 -1
package/package.json
CHANGED
package/src/skill-discovery.ts
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
} from "./index.js";
|
|
15
15
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import matter from "gray-matter";
|
|
17
|
-
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
17
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync, realpathSync } from "node:fs";
|
|
18
|
+
import { homedir } from "node:os";
|
|
18
19
|
import { join, basename, dirname } from "node:path";
|
|
19
20
|
|
|
20
21
|
// Skill directories to scan (in priority order, matching pi's discovery)
|
|
@@ -24,7 +25,7 @@ function getGlobalPiSkillDirs(): string[] {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
function getGlobalAgentsSkillDirs(): string[] {
|
|
27
|
-
return [join(
|
|
28
|
+
return [join(homedir(), ".agents", "skills")];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
function getProjectSkillDirs(cwd: string): string[] {
|
|
@@ -51,11 +52,14 @@ function getAllSkillDirs(cwd: string): SkillDir[] {
|
|
|
51
52
|
for (const path of getProjectSkillDirs(cwd)) {
|
|
52
53
|
dirs.push({ path, source: "project-pi" });
|
|
53
54
|
}
|
|
54
|
-
// Deduplicate by path
|
|
55
|
+
// Deduplicate by resolved (real) path so that symlinked directories
|
|
56
|
+
// (e.g. ~/.agents/skills → ~/.pi/agent/skills) are not scanned twice.
|
|
55
57
|
const seen = new Set<string>();
|
|
56
58
|
return dirs.filter((d) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
let resolved = d.path;
|
|
60
|
+
try { resolved = realpathSync(d.path); } catch { /* path doesn't exist yet */ }
|
|
61
|
+
if (seen.has(resolved)) return false;
|
|
62
|
+
seen.add(resolved);
|
|
59
63
|
return true;
|
|
60
64
|
});
|
|
61
65
|
}
|
|
@@ -171,11 +175,18 @@ function loadSkillFromFile(filePath: string): ToggleSkill | null {
|
|
|
171
175
|
// Skills without description are not loaded by pi — skip them
|
|
172
176
|
if (!description || description.trim() === "") return null;
|
|
173
177
|
|
|
178
|
+
// Resolve symlinks so that the same physical SKILL.md reached via
|
|
179
|
+
// different alias paths (e.g. ~/.agents/skills/x vs ~/.pi/agent/skills/x)
|
|
180
|
+
// gets the same filePath and is correctly deduplicated.
|
|
181
|
+
let realFilePath = filePath;
|
|
182
|
+
try { realFilePath = realpathSync(filePath); } catch { /* keep as-is */ }
|
|
183
|
+
const realBaseDir = dirname(realFilePath);
|
|
184
|
+
|
|
174
185
|
return {
|
|
175
186
|
name,
|
|
176
187
|
description,
|
|
177
|
-
filePath,
|
|
178
|
-
baseDir:
|
|
188
|
+
filePath: realFilePath,
|
|
189
|
+
baseDir: realBaseDir,
|
|
179
190
|
disabled: isDisabled(frontmatter),
|
|
180
191
|
};
|
|
181
192
|
} catch {
|
package/src/skill-selector.ts
CHANGED
|
@@ -297,7 +297,7 @@ export class ToggleSkillSelectorComponent implements Component {
|
|
|
297
297
|
? this.theme.fg("accent", item.name)
|
|
298
298
|
: item.name;
|
|
299
299
|
const status = item.disabled
|
|
300
|
-
? this.theme.fg("
|
|
300
|
+
? this.theme.fg("dim", " ✗")
|
|
301
301
|
: this.theme.fg("success", " ✓");
|
|
302
302
|
|
|
303
303
|
this.listContainer.addChild(
|