@xynogen/pix-skills 0.1.1 → 0.2.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +26 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-skills",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Pi extension — agent skill loader (skill tool + skills bundle)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import { existsSync, readdirSync, readFileSync } from "node:fs";
13
+ import { homedir } from "node:os";
13
14
  import { join, resolve } from "node:path";
14
15
  import { fileURLToPath } from "node:url";
15
16
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
@@ -18,12 +19,17 @@ import { Type } from "typebox";
18
19
 
19
20
  // ─── Skill resolution ─────────────────────────────────────────────────────────
20
21
 
21
- /** Absolute path to this package's skills/ directory. */
22
+ /** Absolute path to this package's bundled skills/ directory. */
22
23
  function skillsRoot(): string {
23
24
  const here = fileURLToPath(new URL(".", import.meta.url));
24
25
  return resolve(here, "..", "skills");
25
26
  }
26
27
 
28
+ /** Absolute path to the user-level skills directory (~/.pi/agent/skills). */
29
+ function userSkillsRoot(): string {
30
+ return join(homedir(), ".pi", "agent", "skills");
31
+ }
32
+
27
33
  interface SkillEntry {
28
34
  name: string;
29
35
  /** Absolute path to the SKILL.md or flat .md file. */
@@ -31,13 +37,12 @@ interface SkillEntry {
31
37
  }
32
38
 
33
39
  /**
34
- * Discover all skills from the package's skills/ directory.
40
+ * Scan a single skills root directory.
35
41
  * Supports two layouts:
36
42
  * - flat: skills/commit.md
37
43
  * - subdir: skills/commit/SKILL.md
38
44
  */
39
- function discoverSkills(): SkillEntry[] {
40
- const root = skillsRoot();
45
+ function scanSkillsDir(root: string): SkillEntry[] {
41
46
  if (!existsSync(root)) return [];
42
47
 
43
48
  const entries: SkillEntry[] = [];
@@ -56,7 +61,23 @@ function discoverSkills(): SkillEntry[] {
56
61
  }
57
62
  }
58
63
 
59
- return entries.sort((a, b) => a.name.localeCompare(b.name));
64
+ return entries;
65
+ }
66
+
67
+ /**
68
+ * Discover all skills from bundled skills/ AND ~/.pi/agent/skills/.
69
+ * Bundled skills take precedence on name collision.
70
+ * Results sorted alphabetically by name.
71
+ */
72
+ function discoverSkills(): SkillEntry[] {
73
+ const bundled = scanSkillsDir(skillsRoot());
74
+ const user = scanSkillsDir(userSkillsRoot());
75
+
76
+ // Merge: bundled wins on collision
77
+ const seen = new Set(bundled.map((s) => s.name));
78
+ const merged = [...bundled, ...user.filter((s) => !seen.has(s.name))];
79
+
80
+ return merged.sort((a, b) => a.name.localeCompare(b.name));
60
81
  }
61
82
 
62
83
  /** Extract the `description` from YAML frontmatter, or null. */