@sentry/dotagents 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.
- package/README.md +96 -0
- package/dist/cli/commands/add.d.ts +12 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +127 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/init.d.ts +10 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +81 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/init.test.d.ts +2 -0
- package/dist/cli/commands/init.test.d.ts.map +1 -0
- package/dist/cli/commands/init.test.js +71 -0
- package/dist/cli/commands/init.test.js.map +1 -0
- package/dist/cli/commands/install.d.ts +15 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +139 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/install.test.d.ts +2 -0
- package/dist/cli/commands/install.test.d.ts.map +1 -0
- package/dist/cli/commands/install.test.js +94 -0
- package/dist/cli/commands/install.test.js.map +1 -0
- package/dist/cli/commands/list.d.ts +13 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +82 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/list.test.d.ts +2 -0
- package/dist/cli/commands/list.test.d.ts.map +1 -0
- package/dist/cli/commands/list.test.js +96 -0
- package/dist/cli/commands/list.test.js.map +1 -0
- package/dist/cli/commands/remove.d.ts +10 -0
- package/dist/cli/commands/remove.d.ts.map +1 -0
- package/dist/cli/commands/remove.js +68 -0
- package/dist/cli/commands/remove.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +16 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +108 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/sync.test.d.ts +2 -0
- package/dist/cli/commands/sync.test.d.ts.map +1 -0
- package/dist/cli/commands/sync.test.js +100 -0
- package/dist/cli/commands/sync.test.js.map +1 -0
- package/dist/cli/commands/update.d.ts +15 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +113 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/commands/update.test.d.ts +2 -0
- package/dist/cli/commands/update.test.d.ts.map +1 -0
- package/dist/cli/commands/update.test.js +90 -0
- package/dist/cli/commands/update.test.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +49 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +6 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +35 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/loader.test.d.ts +2 -0
- package/dist/config/loader.test.d.ts.map +1 -0
- package/dist/config/loader.test.js +60 -0
- package/dist/config/loader.test.js.map +1 -0
- package/dist/config/schema.d.ts +37 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +43 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/schema.test.d.ts +2 -0
- package/dist/config/schema.test.d.ts.map +1 -0
- package/dist/config/schema.test.js +138 -0
- package/dist/config/schema.test.js.map +1 -0
- package/dist/config/writer.d.ts +17 -0
- package/dist/config/writer.d.ts.map +1 -0
- package/dist/config/writer.js +71 -0
- package/dist/config/writer.js.map +1 -0
- package/dist/config/writer.test.d.ts +2 -0
- package/dist/config/writer.test.d.ts.map +1 -0
- package/dist/config/writer.test.js +103 -0
- package/dist/config/writer.test.js.map +1 -0
- package/dist/gitignore/index.d.ts +2 -0
- package/dist/gitignore/index.d.ts.map +1 -0
- package/dist/gitignore/index.js +2 -0
- package/dist/gitignore/index.js.map +1 -0
- package/dist/gitignore/writer.d.ts +16 -0
- package/dist/gitignore/writer.d.ts.map +1 -0
- package/dist/gitignore/writer.js +40 -0
- package/dist/gitignore/writer.js.map +1 -0
- package/dist/gitignore/writer.test.d.ts +2 -0
- package/dist/gitignore/writer.test.d.ts.map +1 -0
- package/dist/gitignore/writer.test.js +99 -0
- package/dist/gitignore/writer.test.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lockfile/index.d.ts +5 -0
- package/dist/lockfile/index.d.ts.map +1 -0
- package/dist/lockfile/index.js +4 -0
- package/dist/lockfile/index.js.map +1 -0
- package/dist/lockfile/loader.d.ts +10 -0
- package/dist/lockfile/loader.d.ts.map +1 -0
- package/dist/lockfile/loader.js +36 -0
- package/dist/lockfile/loader.js.map +1 -0
- package/dist/lockfile/schema.d.ts +42 -0
- package/dist/lockfile/schema.d.ts.map +1 -0
- package/dist/lockfile/schema.js +25 -0
- package/dist/lockfile/schema.js.map +1 -0
- package/dist/lockfile/schema.test.d.ts +2 -0
- package/dist/lockfile/schema.test.d.ts.map +1 -0
- package/dist/lockfile/schema.test.js +60 -0
- package/dist/lockfile/schema.test.js.map +1 -0
- package/dist/lockfile/writer.d.ts +7 -0
- package/dist/lockfile/writer.d.ts.map +1 -0
- package/dist/lockfile/writer.js +17 -0
- package/dist/lockfile/writer.js.map +1 -0
- package/dist/lockfile/writer.test.d.ts +2 -0
- package/dist/lockfile/writer.test.d.ts.map +1 -0
- package/dist/lockfile/writer.test.js +73 -0
- package/dist/lockfile/writer.test.js.map +1 -0
- package/dist/skills/discovery.d.ts +17 -0
- package/dist/skills/discovery.d.ts.map +1 -0
- package/dist/skills/discovery.js +156 -0
- package/dist/skills/discovery.js.map +1 -0
- package/dist/skills/discovery.test.d.ts +2 -0
- package/dist/skills/discovery.test.d.ts.map +1 -0
- package/dist/skills/discovery.test.js +110 -0
- package/dist/skills/discovery.test.js.map +1 -0
- package/dist/skills/index.d.ts +7 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +4 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +14 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +57 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/loader.test.d.ts +2 -0
- package/dist/skills/loader.test.d.ts.map +1 -0
- package/dist/skills/loader.test.js +69 -0
- package/dist/skills/loader.test.js.map +1 -0
- package/dist/skills/resolver.d.ts +46 -0
- package/dist/skills/resolver.d.ts.map +1 -0
- package/dist/skills/resolver.integration.test.d.ts +2 -0
- package/dist/skills/resolver.integration.test.d.ts.map +1 -0
- package/dist/skills/resolver.integration.test.js +106 -0
- package/dist/skills/resolver.integration.test.js.map +1 -0
- package/dist/skills/resolver.js +82 -0
- package/dist/skills/resolver.js.map +1 -0
- package/dist/skills/resolver.test.d.ts +2 -0
- package/dist/skills/resolver.test.d.ts.map +1 -0
- package/dist/skills/resolver.test.js +36 -0
- package/dist/skills/resolver.test.js.map +1 -0
- package/dist/sources/cache.d.ts +23 -0
- package/dist/sources/cache.d.ts.map +1 -0
- package/dist/sources/cache.js +61 -0
- package/dist/sources/cache.js.map +1 -0
- package/dist/sources/git.d.ts +25 -0
- package/dist/sources/git.d.ts.map +1 -0
- package/dist/sources/git.js +72 -0
- package/dist/sources/git.js.map +1 -0
- package/dist/sources/index.d.ts +5 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +4 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/local.d.ts +9 -0
- package/dist/sources/local.d.ts.map +1 -0
- package/dist/sources/local.js +32 -0
- package/dist/sources/local.js.map +1 -0
- package/dist/symlinks/index.d.ts +2 -0
- package/dist/symlinks/index.d.ts.map +1 -0
- package/dist/symlinks/index.js +2 -0
- package/dist/symlinks/index.js.map +1 -0
- package/dist/symlinks/manager.d.ts +20 -0
- package/dist/symlinks/manager.d.ts.map +1 -0
- package/dist/symlinks/manager.js +103 -0
- package/dist/symlinks/manager.js.map +1 -0
- package/dist/symlinks/manager.test.d.ts +2 -0
- package/dist/symlinks/manager.test.d.ts.map +1 -0
- package/dist/symlinks/manager.test.js +94 -0
- package/dist/symlinks/manager.test.js.map +1 -0
- package/dist/utils/exec.d.ts +16 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +37 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/fs.d.ts +6 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +10 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/hash.d.ts +16 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +50 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/hash.test.d.ts +2 -0
- package/dist/utils/hash.test.d.ts.map +1 -0
- package/dist/utils/hash.test.js +61 -0
- package/dist/utils/hash.test.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, writeFile, mkdir, rm } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { discoverSkill, discoverAllSkills } from "./discovery.js";
|
|
6
|
+
const SKILL_MD = (name) => `---
|
|
7
|
+
name: ${name}
|
|
8
|
+
description: Test skill ${name}
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# ${name}
|
|
12
|
+
`;
|
|
13
|
+
describe("discoverSkill", () => {
|
|
14
|
+
let repoDir;
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
repoDir = await mkdtemp(join(tmpdir(), "dotagents-discover-"));
|
|
17
|
+
});
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
await rm(repoDir, { recursive: true });
|
|
20
|
+
});
|
|
21
|
+
it("finds skill at root level (<name>/SKILL.md)", async () => {
|
|
22
|
+
await mkdir(join(repoDir, "pdf"), { recursive: true });
|
|
23
|
+
await writeFile(join(repoDir, "pdf", "SKILL.md"), SKILL_MD("pdf"));
|
|
24
|
+
const result = await discoverSkill(repoDir, "pdf");
|
|
25
|
+
expect(result).not.toBeNull();
|
|
26
|
+
expect(result.path).toBe("pdf");
|
|
27
|
+
expect(result.meta.name).toBe("pdf");
|
|
28
|
+
});
|
|
29
|
+
it("finds skill in skills/ directory", async () => {
|
|
30
|
+
await mkdir(join(repoDir, "skills", "review"), { recursive: true });
|
|
31
|
+
await writeFile(join(repoDir, "skills", "review", "SKILL.md"), SKILL_MD("review"));
|
|
32
|
+
const result = await discoverSkill(repoDir, "review");
|
|
33
|
+
expect(result).not.toBeNull();
|
|
34
|
+
expect(result.path).toBe("skills/review");
|
|
35
|
+
});
|
|
36
|
+
it("finds skill in .agents/skills/ directory", async () => {
|
|
37
|
+
await mkdir(join(repoDir, ".agents", "skills", "lint"), { recursive: true });
|
|
38
|
+
await writeFile(join(repoDir, ".agents", "skills", "lint", "SKILL.md"), SKILL_MD("lint"));
|
|
39
|
+
const result = await discoverSkill(repoDir, "lint");
|
|
40
|
+
expect(result).not.toBeNull();
|
|
41
|
+
expect(result.path).toBe(".agents/skills/lint");
|
|
42
|
+
});
|
|
43
|
+
it("finds skill in .claude/skills/ directory", async () => {
|
|
44
|
+
await mkdir(join(repoDir, ".claude", "skills", "commit"), {
|
|
45
|
+
recursive: true,
|
|
46
|
+
});
|
|
47
|
+
await writeFile(join(repoDir, ".claude", "skills", "commit", "SKILL.md"), SKILL_MD("commit"));
|
|
48
|
+
const result = await discoverSkill(repoDir, "commit");
|
|
49
|
+
expect(result).not.toBeNull();
|
|
50
|
+
expect(result.path).toBe(".claude/skills/commit");
|
|
51
|
+
});
|
|
52
|
+
it("prefers root-level over skills/ directory", async () => {
|
|
53
|
+
await mkdir(join(repoDir, "pdf"), { recursive: true });
|
|
54
|
+
await writeFile(join(repoDir, "pdf", "SKILL.md"), SKILL_MD("pdf"));
|
|
55
|
+
await mkdir(join(repoDir, "skills", "pdf"), { recursive: true });
|
|
56
|
+
await writeFile(join(repoDir, "skills", "pdf", "SKILL.md"), SKILL_MD("pdf"));
|
|
57
|
+
const result = await discoverSkill(repoDir, "pdf");
|
|
58
|
+
expect(result.path).toBe("pdf");
|
|
59
|
+
});
|
|
60
|
+
it("returns null when skill not found", async () => {
|
|
61
|
+
const result = await discoverSkill(repoDir, "nonexistent");
|
|
62
|
+
expect(result).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("discoverAllSkills", () => {
|
|
66
|
+
let repoDir;
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
repoDir = await mkdtemp(join(tmpdir(), "dotagents-discover-"));
|
|
69
|
+
});
|
|
70
|
+
afterEach(async () => {
|
|
71
|
+
await rm(repoDir, { recursive: true });
|
|
72
|
+
});
|
|
73
|
+
it("discovers skills across multiple directories", async () => {
|
|
74
|
+
// Root-level skill
|
|
75
|
+
await mkdir(join(repoDir, "pdf"), { recursive: true });
|
|
76
|
+
await writeFile(join(repoDir, "pdf", "SKILL.md"), SKILL_MD("pdf"));
|
|
77
|
+
// skills/ skill
|
|
78
|
+
await mkdir(join(repoDir, "skills", "review"), { recursive: true });
|
|
79
|
+
await writeFile(join(repoDir, "skills", "review", "SKILL.md"), SKILL_MD("review"));
|
|
80
|
+
const results = await discoverAllSkills(repoDir);
|
|
81
|
+
expect(results).toHaveLength(2);
|
|
82
|
+
const names = results.map((r) => r.meta.name).sort();
|
|
83
|
+
expect(names).toEqual(["pdf", "review"]);
|
|
84
|
+
});
|
|
85
|
+
it("returns empty array for repo with no skills", async () => {
|
|
86
|
+
const results = await discoverAllSkills(repoDir);
|
|
87
|
+
expect(results).toHaveLength(0);
|
|
88
|
+
});
|
|
89
|
+
it("skips directories without SKILL.md", async () => {
|
|
90
|
+
await mkdir(join(repoDir, "not-a-skill"), { recursive: true });
|
|
91
|
+
await writeFile(join(repoDir, "not-a-skill", "README.md"), "# Not a skill");
|
|
92
|
+
const results = await discoverAllSkills(repoDir);
|
|
93
|
+
expect(results).toHaveLength(0);
|
|
94
|
+
});
|
|
95
|
+
it("discovers skills in marketplace format", async () => {
|
|
96
|
+
// .claude-plugin must exist (marker for marketplace repos)
|
|
97
|
+
await mkdir(join(repoDir, ".claude-plugin"), { recursive: true });
|
|
98
|
+
// plugins/<plugin>/skills/<skill>/SKILL.md
|
|
99
|
+
await mkdir(join(repoDir, "plugins", "my-plugin", "skills", "find-bugs"), { recursive: true });
|
|
100
|
+
await writeFile(join(repoDir, "plugins", "my-plugin", "skills", "find-bugs", "SKILL.md"), SKILL_MD("find-bugs"));
|
|
101
|
+
await mkdir(join(repoDir, "plugins", "my-plugin", "skills", "code-review"), { recursive: true });
|
|
102
|
+
await writeFile(join(repoDir, "plugins", "my-plugin", "skills", "code-review", "SKILL.md"), SKILL_MD("code-review"));
|
|
103
|
+
const results = await discoverAllSkills(repoDir);
|
|
104
|
+
expect(results).toHaveLength(2);
|
|
105
|
+
const names = results.map((r) => r.meta.name).sort();
|
|
106
|
+
expect(names).toEqual(["code-review", "find-bugs"]);
|
|
107
|
+
expect(results.find((r) => r.meta.name === "find-bugs").path).toBe("plugins/my-plugin/skills/find-bugs");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=discovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../src/skills/discovery.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { loadSkillMd, SkillLoadError } from "./loader.js";
|
|
2
|
+
export type { SkillMeta } from "./loader.js";
|
|
3
|
+
export { discoverSkill, discoverAllSkills } from "./discovery.js";
|
|
4
|
+
export type { DiscoveredSkill } from "./discovery.js";
|
|
5
|
+
export { resolveSkill, parseSource, ResolveError } from "./resolver.js";
|
|
6
|
+
export type { ResolvedSkill, ResolvedGitSkill, ResolvedLocalSkill } from "./resolver.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class SkillLoadError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export interface SkillMeta {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parse a SKILL.md file and extract YAML frontmatter.
|
|
11
|
+
* Returns the parsed metadata (name, description, plus any extra fields).
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadSkillMd(filePath: string): Promise<SkillMeta>;
|
|
14
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"AAEA,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID;;;GAGG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAuBtE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
export class SkillLoadError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "SkillLoadError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
9
|
+
/**
|
|
10
|
+
* Parse a SKILL.md file and extract YAML frontmatter.
|
|
11
|
+
* Returns the parsed metadata (name, description, plus any extra fields).
|
|
12
|
+
*/
|
|
13
|
+
export async function loadSkillMd(filePath) {
|
|
14
|
+
let content;
|
|
15
|
+
try {
|
|
16
|
+
content = await readFile(filePath, "utf-8");
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
throw new SkillLoadError(`SKILL.md not found: ${filePath}`);
|
|
20
|
+
}
|
|
21
|
+
const match = FRONTMATTER_RE.exec(content);
|
|
22
|
+
if (!match?.[1]) {
|
|
23
|
+
throw new SkillLoadError(`No YAML frontmatter in ${filePath}`);
|
|
24
|
+
}
|
|
25
|
+
const meta = parseSimpleYaml(match[1]);
|
|
26
|
+
if (typeof meta["name"] !== "string" || !meta["name"]) {
|
|
27
|
+
throw new SkillLoadError(`Missing 'name' in SKILL.md frontmatter: ${filePath}`);
|
|
28
|
+
}
|
|
29
|
+
if (typeof meta["description"] !== "string" || !meta["description"]) {
|
|
30
|
+
throw new SkillLoadError(`Missing 'description' in SKILL.md frontmatter: ${filePath}`);
|
|
31
|
+
}
|
|
32
|
+
return meta;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Minimal YAML parser for flat key: value frontmatter.
|
|
36
|
+
* We avoid a full YAML dependency — SKILL.md frontmatter is simple key-value pairs.
|
|
37
|
+
*/
|
|
38
|
+
function parseSimpleYaml(yaml) {
|
|
39
|
+
const result = {};
|
|
40
|
+
for (const line of yaml.split("\n")) {
|
|
41
|
+
const trimmed = line.trim();
|
|
42
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
43
|
+
continue;
|
|
44
|
+
const colonIdx = trimmed.indexOf(":");
|
|
45
|
+
if (colonIdx === -1)
|
|
46
|
+
continue;
|
|
47
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
48
|
+
let value = trimmed.slice(colonIdx + 1).trim();
|
|
49
|
+
// Strip surrounding quotes
|
|
50
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
51
|
+
value = value.slice(1, -1);
|
|
52
|
+
}
|
|
53
|
+
result[key] = value;
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAQD,MAAM,cAAc,GAAG,6BAA6B,CAAC;AAErD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,cAAc,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,cAAc,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvC,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,cAAc,CAAC,2CAA2C,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,cAAc,CAAC,kDAAkD,QAAQ,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,IAAiB,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAS;QAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,2BAA2B;QAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrG,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.d.ts","sourceRoot":"","sources":["../../src/skills/loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, writeFile, rm } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { loadSkillMd, SkillLoadError } from "./loader.js";
|
|
6
|
+
describe("loadSkillMd", () => {
|
|
7
|
+
let dir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
dir = await mkdtemp(join(tmpdir(), "dotagents-skill-"));
|
|
10
|
+
});
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await rm(dir, { recursive: true });
|
|
13
|
+
});
|
|
14
|
+
it("parses valid SKILL.md with frontmatter", async () => {
|
|
15
|
+
const skillMd = join(dir, "SKILL.md");
|
|
16
|
+
await writeFile(skillMd, `---
|
|
17
|
+
name: pdf-processing
|
|
18
|
+
description: Extract and process PDF documents
|
|
19
|
+
license: MIT
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# PDF Processing
|
|
23
|
+
|
|
24
|
+
This skill handles PDF files.
|
|
25
|
+
`);
|
|
26
|
+
const meta = await loadSkillMd(skillMd);
|
|
27
|
+
expect(meta.name).toBe("pdf-processing");
|
|
28
|
+
expect(meta.description).toBe("Extract and process PDF documents");
|
|
29
|
+
expect(meta["license"]).toBe("MIT");
|
|
30
|
+
});
|
|
31
|
+
it("handles quoted values", async () => {
|
|
32
|
+
const skillMd = join(dir, "SKILL.md");
|
|
33
|
+
await writeFile(skillMd, `---
|
|
34
|
+
name: "my-skill"
|
|
35
|
+
description: 'A skill with quoted values'
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
Content.
|
|
39
|
+
`);
|
|
40
|
+
const meta = await loadSkillMd(skillMd);
|
|
41
|
+
expect(meta.name).toBe("my-skill");
|
|
42
|
+
expect(meta.description).toBe("A skill with quoted values");
|
|
43
|
+
});
|
|
44
|
+
it("throws SkillLoadError for missing file", async () => {
|
|
45
|
+
await expect(loadSkillMd(join(dir, "nope.md"))).rejects.toThrow(SkillLoadError);
|
|
46
|
+
});
|
|
47
|
+
it("throws SkillLoadError for missing frontmatter", async () => {
|
|
48
|
+
const skillMd = join(dir, "SKILL.md");
|
|
49
|
+
await writeFile(skillMd, "# No frontmatter here\n");
|
|
50
|
+
await expect(loadSkillMd(skillMd)).rejects.toThrow(SkillLoadError);
|
|
51
|
+
});
|
|
52
|
+
it("throws SkillLoadError for missing name", async () => {
|
|
53
|
+
const skillMd = join(dir, "SKILL.md");
|
|
54
|
+
await writeFile(skillMd, `---
|
|
55
|
+
description: No name field
|
|
56
|
+
---
|
|
57
|
+
`);
|
|
58
|
+
await expect(loadSkillMd(skillMd)).rejects.toThrow(SkillLoadError);
|
|
59
|
+
});
|
|
60
|
+
it("throws SkillLoadError for missing description", async () => {
|
|
61
|
+
const skillMd = join(dir, "SKILL.md");
|
|
62
|
+
await writeFile(skillMd, `---
|
|
63
|
+
name: my-skill
|
|
64
|
+
---
|
|
65
|
+
`);
|
|
66
|
+
await expect(loadSkillMd(skillMd)).rejects.toThrow(SkillLoadError);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../src/skills/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SkillDependency } from "../config/schema.js";
|
|
2
|
+
export declare class ResolveError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export interface ResolvedGitSkill {
|
|
6
|
+
type: "git";
|
|
7
|
+
/** Original source string */
|
|
8
|
+
source: string;
|
|
9
|
+
/** Resolved git clone URL */
|
|
10
|
+
resolvedUrl: string;
|
|
11
|
+
/** Path within the repo to the skill directory */
|
|
12
|
+
resolvedPath: string;
|
|
13
|
+
/** Ref that was resolved */
|
|
14
|
+
resolvedRef?: string;
|
|
15
|
+
/** Full 40-char commit SHA */
|
|
16
|
+
commit: string;
|
|
17
|
+
/** Absolute path to the cached skill directory */
|
|
18
|
+
skillDir: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ResolvedLocalSkill {
|
|
21
|
+
type: "local";
|
|
22
|
+
source: string;
|
|
23
|
+
/** Absolute path to the skill directory */
|
|
24
|
+
skillDir: string;
|
|
25
|
+
}
|
|
26
|
+
export type ResolvedSkill = ResolvedGitSkill | ResolvedLocalSkill;
|
|
27
|
+
/**
|
|
28
|
+
* Parse a source string into its components.
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseSource(source: string): {
|
|
31
|
+
type: "github" | "git" | "local";
|
|
32
|
+
url?: string;
|
|
33
|
+
owner?: string;
|
|
34
|
+
repo?: string;
|
|
35
|
+
ref?: string;
|
|
36
|
+
path?: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a skill dependency to a concrete directory on disk.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveSkill(skillName: string, dep: Pick<SkillDependency, "source" | "ref" | "path">, opts?: {
|
|
42
|
+
projectRoot?: string;
|
|
43
|
+
/** Locked commit from agents.lock — skip resolution, use this exact commit */
|
|
44
|
+
lockedCommit?: string;
|
|
45
|
+
}): Promise<ResolvedSkill>;
|
|
46
|
+
//# sourceMappingURL=resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/skills/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM3D,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,KAAK,CAAC;IACZ,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAElE;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3C,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAsBA;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC,EACrD,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACA,OAAO,CAAC,aAAa,CAAC,CAsDxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.integration.test.d.ts","sourceRoot":"","sources":["../../src/skills/resolver.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { resolveSkill } from "./resolver.js";
|
|
6
|
+
import { exec } from "../utils/exec.js";
|
|
7
|
+
/**
|
|
8
|
+
* Integration tests that use real git operations.
|
|
9
|
+
* These create local git repos to test the full resolve pipeline.
|
|
10
|
+
*/
|
|
11
|
+
describe("resolveSkill integration", () => {
|
|
12
|
+
let tmpDir;
|
|
13
|
+
let stateDir;
|
|
14
|
+
let projectRoot;
|
|
15
|
+
let repoDir;
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
tmpDir = await mkdtemp(join(tmpdir(), "dotagents-resolve-"));
|
|
18
|
+
stateDir = join(tmpDir, "state");
|
|
19
|
+
projectRoot = join(tmpDir, "project");
|
|
20
|
+
repoDir = join(tmpDir, "repo");
|
|
21
|
+
await mkdir(stateDir, { recursive: true });
|
|
22
|
+
await mkdir(projectRoot, { recursive: true });
|
|
23
|
+
// Point cache to temp dir
|
|
24
|
+
process.env["DOTAGENTS_STATE_DIR"] = stateDir;
|
|
25
|
+
// Create a local git repo that looks like a skill repository
|
|
26
|
+
await mkdir(repoDir, { recursive: true });
|
|
27
|
+
await exec("git", ["init"], { cwd: repoDir });
|
|
28
|
+
await exec("git", ["config", "user.email", "test@test.com"], { cwd: repoDir });
|
|
29
|
+
await exec("git", ["config", "user.name", "Test"], { cwd: repoDir });
|
|
30
|
+
// Create a skill at the root level
|
|
31
|
+
await mkdir(join(repoDir, "pdf"), { recursive: true });
|
|
32
|
+
await writeFile(join(repoDir, "pdf", "SKILL.md"), `---
|
|
33
|
+
name: pdf
|
|
34
|
+
description: PDF processing skill
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# PDF Processing
|
|
38
|
+
`);
|
|
39
|
+
// Create a skill in skills/ directory
|
|
40
|
+
await mkdir(join(repoDir, "skills", "review"), { recursive: true });
|
|
41
|
+
await writeFile(join(repoDir, "skills", "review", "SKILL.md"), `---
|
|
42
|
+
name: review
|
|
43
|
+
description: Code review skill
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Review
|
|
47
|
+
`);
|
|
48
|
+
await exec("git", ["add", "."], { cwd: repoDir });
|
|
49
|
+
await exec("git", ["commit", "-m", "initial"], { cwd: repoDir });
|
|
50
|
+
});
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
delete process.env["DOTAGENTS_STATE_DIR"];
|
|
53
|
+
await rm(tmpDir, { recursive: true });
|
|
54
|
+
});
|
|
55
|
+
it("resolves a local path: source", async () => {
|
|
56
|
+
// Create skill inside project root
|
|
57
|
+
const skillDir = join(projectRoot, "local-skills", "my-skill");
|
|
58
|
+
await mkdir(skillDir, { recursive: true });
|
|
59
|
+
await writeFile(join(skillDir, "SKILL.md"), `---
|
|
60
|
+
name: my-skill
|
|
61
|
+
description: A local skill
|
|
62
|
+
---
|
|
63
|
+
`);
|
|
64
|
+
const result = await resolveSkill("my-skill", { source: "path:local-skills/my-skill" }, { projectRoot });
|
|
65
|
+
expect(result.type).toBe("local");
|
|
66
|
+
expect(result.skillDir).toBe(skillDir);
|
|
67
|
+
});
|
|
68
|
+
it("resolves a git: source with skill discovery", async () => {
|
|
69
|
+
const result = await resolveSkill("pdf", { source: `git:${repoDir}` }, { projectRoot });
|
|
70
|
+
expect(result.type).toBe("git");
|
|
71
|
+
if (result.type === "git") {
|
|
72
|
+
expect(result.resolvedUrl).toBe(repoDir);
|
|
73
|
+
expect(result.resolvedPath).toBe("pdf");
|
|
74
|
+
expect(result.commit).toMatch(/^[a-f0-9]{40}$/);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it("resolves a git: source for skill in skills/ directory", async () => {
|
|
78
|
+
const result = await resolveSkill("review", { source: `git:${repoDir}` }, { projectRoot });
|
|
79
|
+
expect(result.type).toBe("git");
|
|
80
|
+
if (result.type === "git") {
|
|
81
|
+
expect(result.resolvedPath).toBe("skills/review");
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
it("resolves with explicit path override", async () => {
|
|
85
|
+
const result = await resolveSkill("pdf", { source: `git:${repoDir}`, path: "pdf" }, { projectRoot });
|
|
86
|
+
expect(result.type).toBe("git");
|
|
87
|
+
if (result.type === "git") {
|
|
88
|
+
expect(result.resolvedPath).toBe("pdf");
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it("throws ResolveError when skill not found in repo", async () => {
|
|
92
|
+
await expect(resolveSkill("nonexistent", { source: `git:${repoDir}` }, { projectRoot })).rejects.toThrow(/not found/);
|
|
93
|
+
});
|
|
94
|
+
it("caches repos and reuses them", async () => {
|
|
95
|
+
// First resolve — clones
|
|
96
|
+
const result1 = await resolveSkill("pdf", { source: `git:${repoDir}` }, { projectRoot });
|
|
97
|
+
// Second resolve — should reuse cache (same commit)
|
|
98
|
+
const result2 = await resolveSkill("review", { source: `git:${repoDir}` }, { projectRoot });
|
|
99
|
+
expect(result1.type).toBe("git");
|
|
100
|
+
expect(result2.type).toBe("git");
|
|
101
|
+
if (result1.type === "git" && result2.type === "git") {
|
|
102
|
+
expect(result1.commit).toBe(result2.commit);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=resolver.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.integration.test.js","sourceRoot":"","sources":["../../src/skills/resolver.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ensureCached } from "../sources/cache.js";
|
|
2
|
+
import { resolveLocalSource } from "../sources/local.js";
|
|
3
|
+
import { discoverSkill } from "./discovery.js";
|
|
4
|
+
export class ResolveError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "ResolveError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse a source string into its components.
|
|
12
|
+
*/
|
|
13
|
+
export function parseSource(source) {
|
|
14
|
+
if (source.startsWith("path:")) {
|
|
15
|
+
return { type: "local", path: source.slice(5) };
|
|
16
|
+
}
|
|
17
|
+
if (source.startsWith("git:")) {
|
|
18
|
+
return { type: "git", url: source.slice(4) };
|
|
19
|
+
}
|
|
20
|
+
// owner/repo or owner/repo@ref
|
|
21
|
+
const atIdx = source.indexOf("@");
|
|
22
|
+
const base = atIdx !== -1 ? source.slice(0, atIdx) : source;
|
|
23
|
+
const ref = atIdx !== -1 ? source.slice(atIdx + 1) : undefined;
|
|
24
|
+
const [owner, repo] = base.split("/");
|
|
25
|
+
return {
|
|
26
|
+
type: "github",
|
|
27
|
+
owner,
|
|
28
|
+
repo,
|
|
29
|
+
ref,
|
|
30
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a skill dependency to a concrete directory on disk.
|
|
35
|
+
*/
|
|
36
|
+
export async function resolveSkill(skillName, dep, opts) {
|
|
37
|
+
const parsed = parseSource(dep.source);
|
|
38
|
+
if (parsed.type === "local") {
|
|
39
|
+
const projectRoot = opts?.projectRoot || process.cwd();
|
|
40
|
+
const skillDir = await resolveLocalSource(projectRoot, parsed.path);
|
|
41
|
+
return { type: "local", source: dep.source, skillDir };
|
|
42
|
+
}
|
|
43
|
+
// Git source (GitHub or generic git)
|
|
44
|
+
const url = parsed.url;
|
|
45
|
+
const ref = dep.ref ?? parsed.ref;
|
|
46
|
+
const cacheKey = parsed.type === "github"
|
|
47
|
+
? `${parsed.owner}/${parsed.repo}`
|
|
48
|
+
: url.replace(/^https?:\/\//, "").replace(/\.git$/, "");
|
|
49
|
+
const cached = await ensureCached({
|
|
50
|
+
url,
|
|
51
|
+
cacheKey,
|
|
52
|
+
ref,
|
|
53
|
+
pinnedCommit: opts?.lockedCommit,
|
|
54
|
+
});
|
|
55
|
+
// Discover the skill within the repo
|
|
56
|
+
let discovered;
|
|
57
|
+
if (dep.path) {
|
|
58
|
+
// Explicit path override — load directly
|
|
59
|
+
const { loadSkillMd } = await import("./loader.js");
|
|
60
|
+
const { join } = await import("node:path");
|
|
61
|
+
const meta = await loadSkillMd(join(cached.repoDir, dep.path, "SKILL.md"));
|
|
62
|
+
discovered = { path: dep.path, meta };
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
discovered = await discoverSkill(cached.repoDir, skillName);
|
|
66
|
+
}
|
|
67
|
+
if (!discovered) {
|
|
68
|
+
throw new ResolveError(`Skill "${skillName}" not found in ${dep.source}. ` +
|
|
69
|
+
`Tried conventional directories. Use the 'path' field to specify the location explicitly.`);
|
|
70
|
+
}
|
|
71
|
+
const { join } = await import("node:path");
|
|
72
|
+
return {
|
|
73
|
+
type: "git",
|
|
74
|
+
source: dep.source,
|
|
75
|
+
resolvedUrl: url,
|
|
76
|
+
resolvedPath: discovered.path,
|
|
77
|
+
resolvedRef: ref,
|
|
78
|
+
commit: cached.commit,
|
|
79
|
+
skillDir: join(cached.repoDir, discovered.path),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/skills/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.test.d.ts","sourceRoot":"","sources":["../../src/skills/resolver.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { parseSource } from "./resolver.js";
|
|
3
|
+
describe("parseSource", () => {
|
|
4
|
+
it("parses owner/repo as github", () => {
|
|
5
|
+
const result = parseSource("anthropics/skills");
|
|
6
|
+
expect(result.type).toBe("github");
|
|
7
|
+
expect(result.owner).toBe("anthropics");
|
|
8
|
+
expect(result.repo).toBe("skills");
|
|
9
|
+
expect(result.url).toBe("https://github.com/anthropics/skills.git");
|
|
10
|
+
expect(result.ref).toBeUndefined();
|
|
11
|
+
});
|
|
12
|
+
it("parses owner/repo@ref as github with ref", () => {
|
|
13
|
+
const result = parseSource("getsentry/sentry-skills@v1.0.0");
|
|
14
|
+
expect(result.type).toBe("github");
|
|
15
|
+
expect(result.owner).toBe("getsentry");
|
|
16
|
+
expect(result.repo).toBe("sentry-skills");
|
|
17
|
+
expect(result.ref).toBe("v1.0.0");
|
|
18
|
+
expect(result.url).toBe("https://github.com/getsentry/sentry-skills.git");
|
|
19
|
+
});
|
|
20
|
+
it("parses owner/repo@sha as github with sha ref", () => {
|
|
21
|
+
const result = parseSource("anthropics/skills@abc123");
|
|
22
|
+
expect(result.type).toBe("github");
|
|
23
|
+
expect(result.ref).toBe("abc123");
|
|
24
|
+
});
|
|
25
|
+
it("parses git: prefix as generic git", () => {
|
|
26
|
+
const result = parseSource("git:https://git.corp.example.com/team/skills.git");
|
|
27
|
+
expect(result.type).toBe("git");
|
|
28
|
+
expect(result.url).toBe("https://git.corp.example.com/team/skills.git");
|
|
29
|
+
});
|
|
30
|
+
it("parses path: prefix as local", () => {
|
|
31
|
+
const result = parseSource("path:../shared/my-skill");
|
|
32
|
+
expect(result.type).toBe("local");
|
|
33
|
+
expect(result.path).toBe("../shared/my-skill");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=resolver.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.test.js","sourceRoot":"","sources":["../../src/skills/resolver.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,MAAM,GAAG,WAAW,CAAC,mBAAmB,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,WAAW,CAAC,gCAAgC,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CACrB,gDAAgD,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,WAAW,CAAC,0BAA0B,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,kDAAkD,CAAC,CAAC;QAC/E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|