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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-toggle-skills",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Toggle skill visibility in pi's system prompt — flip disable-model-invocation on skills via an interactive TUI",
5
5
  "type": "module",
6
6
  "author": "Tom X Nguyen",
@@ -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(getAgentDir(), "..", "agents", "skills")];
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
- if (seen.has(d.path)) return false;
58
- seen.add(d.path);
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: skillDir,
188
+ filePath: realFilePath,
189
+ baseDir: realBaseDir,
179
190
  disabled: isDisabled(frontmatter),
180
191
  };
181
192
  } catch {
@@ -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("warning", " ✗")
300
+ ? this.theme.fg("dim", " ✗")
301
301
  : this.theme.fg("success", " ✓");
302
302
 
303
303
  this.listContainer.addChild(