@jaggerxtrm/pi-extensions 0.8.1 → 0.9.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.
@@ -3,37 +3,63 @@ import { SubprocessRunner } from "../../src/core";
3
3
  import * as path from "node:path";
4
4
  import * as fs from "node:fs";
5
5
 
6
- const SERVICE_REGISTRY_FILES = [
7
- "service-registry.json",
8
- path.join(".claude", "skills", "service-registry.json"),
9
- ];
6
+ // service-skills v2: the canonical machinery skill is `service-skills`; per-service
7
+ // skills + the registry live under the per-repo umbrella in .xtrm packs.
8
+ const MACHINERY_SKILL = "service-skills";
10
9
 
11
10
  const GLOBAL_SKILL_ROOTS = [
12
11
  path.join(process.env.HOME || "", ".agents", "skills"),
13
12
  path.join(process.env.HOME || "", ".claude", "skills"),
14
13
  ];
15
14
 
15
+ function listPackDirs(cwd: string): string[] {
16
+ const packsRoot = path.join(cwd, ".xtrm", "skills", "user", "packs");
17
+ try {
18
+ return fs
19
+ .readdirSync(packsRoot, { withFileTypes: true })
20
+ .filter((e) => e.isDirectory())
21
+ .map((e) => path.join(packsRoot, e.name))
22
+ .sort();
23
+ } catch {
24
+ return [];
25
+ }
26
+ }
27
+
16
28
  export default function (pi: ExtensionAPI) {
17
29
  const getCwd = (ctx: any) => ctx.cwd || process.cwd();
18
30
 
31
+ // Precedence mirrors bootstrap.get_registry_path: canonical .xtrm umbrella wins,
32
+ // then flat pack-root, then legacy repo-root / .claude (never let stale shadow).
19
33
  const resolveRegistryPath = (cwd: string): string | null => {
20
- for (const rel of SERVICE_REGISTRY_FILES) {
34
+ const packDirs = listPackDirs(cwd);
35
+ for (const pack of packDirs) {
36
+ const umbrella = path.join(pack, "service-skills", "service-registry.json");
37
+ if (fs.existsSync(umbrella)) return umbrella;
38
+ }
39
+ for (const pack of packDirs) {
40
+ const flat = path.join(pack, "service-registry.json");
41
+ if (fs.existsSync(flat)) return flat;
42
+ }
43
+ for (const rel of ["service-registry.json", path.join(".claude", "skills", "service-registry.json")]) {
21
44
  const candidate = path.join(cwd, rel);
22
45
  if (fs.existsSync(candidate)) return candidate;
23
46
  }
24
47
  return null;
25
48
  };
26
49
 
27
- const resolveSkillScript = (cwd: string, skillName: string, scriptName: string): string | null => {
28
- const localPath = path.join(cwd, ".claude", "skills", skillName, "scripts", scriptName);
29
- if (fs.existsSync(localPath)) return localPath;
30
-
50
+ const resolveSkillScript = (cwd: string, scriptName: string): string | null => {
51
+ const candidates = [
52
+ path.join(cwd, ".claude", "skills", MACHINERY_SKILL, "scripts", scriptName),
53
+ path.join(cwd, ".xtrm", "skills", "default", MACHINERY_SKILL, "scripts", scriptName),
54
+ ];
55
+ for (const candidate of candidates) {
56
+ if (fs.existsSync(candidate)) return candidate;
57
+ }
31
58
  for (const root of GLOBAL_SKILL_ROOTS) {
32
59
  if (!root) continue;
33
- const candidate = path.join(root, skillName, "scripts", scriptName);
60
+ const candidate = path.join(root, MACHINERY_SKILL, "scripts", scriptName);
34
61
  if (fs.existsSync(candidate)) return candidate;
35
62
  }
36
-
37
63
  return null;
38
64
  };
39
65
 
@@ -43,7 +69,7 @@ export default function (pi: ExtensionAPI) {
43
69
  const registryPath = resolveRegistryPath(cwd);
44
70
  if (!registryPath) return undefined;
45
71
 
46
- const catalogerPath = resolveSkillScript(cwd, "using-service-skills", "cataloger.py");
72
+ const catalogerPath = resolveSkillScript(cwd, "cataloger.py");
47
73
  if (!catalogerPath) return undefined;
48
74
 
49
75
  const result = await SubprocessRunner.run("python3", [catalogerPath], {
@@ -77,7 +103,7 @@ export default function (pi: ExtensionAPI) {
77
103
  const registryPath = resolveRegistryPath(cwd);
78
104
  if (!registryPath) return undefined;
79
105
 
80
- const driftDetectorPath = resolveSkillScript(cwd, "updating-service-skills", "drift_detector.py");
106
+ const driftDetectorPath = resolveSkillScript(cwd, "drift_detector.py");
81
107
  if (!driftDetectorPath) return undefined;
82
108
 
83
109
  const hookInput = JSON.stringify({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaggerxtrm/pi-extensions",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Unified Pi extension entrypoint for xtrm-managed extensions",
5
5
  "type": "module",
6
6
  "publishConfig": {