@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.
Files changed (202) hide show
  1. package/README.md +96 -0
  2. package/dist/cli/commands/add.d.ts +12 -0
  3. package/dist/cli/commands/add.d.ts.map +1 -0
  4. package/dist/cli/commands/add.js +127 -0
  5. package/dist/cli/commands/add.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +10 -0
  7. package/dist/cli/commands/init.d.ts.map +1 -0
  8. package/dist/cli/commands/init.js +81 -0
  9. package/dist/cli/commands/init.js.map +1 -0
  10. package/dist/cli/commands/init.test.d.ts +2 -0
  11. package/dist/cli/commands/init.test.d.ts.map +1 -0
  12. package/dist/cli/commands/init.test.js +71 -0
  13. package/dist/cli/commands/init.test.js.map +1 -0
  14. package/dist/cli/commands/install.d.ts +15 -0
  15. package/dist/cli/commands/install.d.ts.map +1 -0
  16. package/dist/cli/commands/install.js +139 -0
  17. package/dist/cli/commands/install.js.map +1 -0
  18. package/dist/cli/commands/install.test.d.ts +2 -0
  19. package/dist/cli/commands/install.test.d.ts.map +1 -0
  20. package/dist/cli/commands/install.test.js +94 -0
  21. package/dist/cli/commands/install.test.js.map +1 -0
  22. package/dist/cli/commands/list.d.ts +13 -0
  23. package/dist/cli/commands/list.d.ts.map +1 -0
  24. package/dist/cli/commands/list.js +82 -0
  25. package/dist/cli/commands/list.js.map +1 -0
  26. package/dist/cli/commands/list.test.d.ts +2 -0
  27. package/dist/cli/commands/list.test.d.ts.map +1 -0
  28. package/dist/cli/commands/list.test.js +96 -0
  29. package/dist/cli/commands/list.test.js.map +1 -0
  30. package/dist/cli/commands/remove.d.ts +10 -0
  31. package/dist/cli/commands/remove.d.ts.map +1 -0
  32. package/dist/cli/commands/remove.js +68 -0
  33. package/dist/cli/commands/remove.js.map +1 -0
  34. package/dist/cli/commands/sync.d.ts +16 -0
  35. package/dist/cli/commands/sync.d.ts.map +1 -0
  36. package/dist/cli/commands/sync.js +108 -0
  37. package/dist/cli/commands/sync.js.map +1 -0
  38. package/dist/cli/commands/sync.test.d.ts +2 -0
  39. package/dist/cli/commands/sync.test.d.ts.map +1 -0
  40. package/dist/cli/commands/sync.test.js +100 -0
  41. package/dist/cli/commands/sync.test.js.map +1 -0
  42. package/dist/cli/commands/update.d.ts +15 -0
  43. package/dist/cli/commands/update.d.ts.map +1 -0
  44. package/dist/cli/commands/update.js +113 -0
  45. package/dist/cli/commands/update.js.map +1 -0
  46. package/dist/cli/commands/update.test.d.ts +2 -0
  47. package/dist/cli/commands/update.test.d.ts.map +1 -0
  48. package/dist/cli/commands/update.test.js +90 -0
  49. package/dist/cli/commands/update.test.js.map +1 -0
  50. package/dist/cli/index.d.ts +2 -0
  51. package/dist/cli/index.d.ts.map +1 -0
  52. package/dist/cli/index.js +49 -0
  53. package/dist/cli/index.js.map +1 -0
  54. package/dist/config/index.d.ts +5 -0
  55. package/dist/config/index.d.ts.map +1 -0
  56. package/dist/config/index.js +4 -0
  57. package/dist/config/index.js.map +1 -0
  58. package/dist/config/loader.d.ts +6 -0
  59. package/dist/config/loader.d.ts.map +1 -0
  60. package/dist/config/loader.js +35 -0
  61. package/dist/config/loader.js.map +1 -0
  62. package/dist/config/loader.test.d.ts +2 -0
  63. package/dist/config/loader.test.d.ts.map +1 -0
  64. package/dist/config/loader.test.js +60 -0
  65. package/dist/config/loader.test.js.map +1 -0
  66. package/dist/config/schema.d.ts +37 -0
  67. package/dist/config/schema.d.ts.map +1 -0
  68. package/dist/config/schema.js +43 -0
  69. package/dist/config/schema.js.map +1 -0
  70. package/dist/config/schema.test.d.ts +2 -0
  71. package/dist/config/schema.test.d.ts.map +1 -0
  72. package/dist/config/schema.test.js +138 -0
  73. package/dist/config/schema.test.js.map +1 -0
  74. package/dist/config/writer.d.ts +17 -0
  75. package/dist/config/writer.d.ts.map +1 -0
  76. package/dist/config/writer.js +71 -0
  77. package/dist/config/writer.js.map +1 -0
  78. package/dist/config/writer.test.d.ts +2 -0
  79. package/dist/config/writer.test.d.ts.map +1 -0
  80. package/dist/config/writer.test.js +103 -0
  81. package/dist/config/writer.test.js.map +1 -0
  82. package/dist/gitignore/index.d.ts +2 -0
  83. package/dist/gitignore/index.d.ts.map +1 -0
  84. package/dist/gitignore/index.js +2 -0
  85. package/dist/gitignore/index.js.map +1 -0
  86. package/dist/gitignore/writer.d.ts +16 -0
  87. package/dist/gitignore/writer.d.ts.map +1 -0
  88. package/dist/gitignore/writer.js +40 -0
  89. package/dist/gitignore/writer.js.map +1 -0
  90. package/dist/gitignore/writer.test.d.ts +2 -0
  91. package/dist/gitignore/writer.test.d.ts.map +1 -0
  92. package/dist/gitignore/writer.test.js +99 -0
  93. package/dist/gitignore/writer.test.js.map +1 -0
  94. package/dist/index.d.ts +12 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +8 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/lockfile/index.d.ts +5 -0
  99. package/dist/lockfile/index.d.ts.map +1 -0
  100. package/dist/lockfile/index.js +4 -0
  101. package/dist/lockfile/index.js.map +1 -0
  102. package/dist/lockfile/loader.d.ts +10 -0
  103. package/dist/lockfile/loader.d.ts.map +1 -0
  104. package/dist/lockfile/loader.js +36 -0
  105. package/dist/lockfile/loader.js.map +1 -0
  106. package/dist/lockfile/schema.d.ts +42 -0
  107. package/dist/lockfile/schema.d.ts.map +1 -0
  108. package/dist/lockfile/schema.js +25 -0
  109. package/dist/lockfile/schema.js.map +1 -0
  110. package/dist/lockfile/schema.test.d.ts +2 -0
  111. package/dist/lockfile/schema.test.d.ts.map +1 -0
  112. package/dist/lockfile/schema.test.js +60 -0
  113. package/dist/lockfile/schema.test.js.map +1 -0
  114. package/dist/lockfile/writer.d.ts +7 -0
  115. package/dist/lockfile/writer.d.ts.map +1 -0
  116. package/dist/lockfile/writer.js +17 -0
  117. package/dist/lockfile/writer.js.map +1 -0
  118. package/dist/lockfile/writer.test.d.ts +2 -0
  119. package/dist/lockfile/writer.test.d.ts.map +1 -0
  120. package/dist/lockfile/writer.test.js +73 -0
  121. package/dist/lockfile/writer.test.js.map +1 -0
  122. package/dist/skills/discovery.d.ts +17 -0
  123. package/dist/skills/discovery.d.ts.map +1 -0
  124. package/dist/skills/discovery.js +156 -0
  125. package/dist/skills/discovery.js.map +1 -0
  126. package/dist/skills/discovery.test.d.ts +2 -0
  127. package/dist/skills/discovery.test.d.ts.map +1 -0
  128. package/dist/skills/discovery.test.js +110 -0
  129. package/dist/skills/discovery.test.js.map +1 -0
  130. package/dist/skills/index.d.ts +7 -0
  131. package/dist/skills/index.d.ts.map +1 -0
  132. package/dist/skills/index.js +4 -0
  133. package/dist/skills/index.js.map +1 -0
  134. package/dist/skills/loader.d.ts +14 -0
  135. package/dist/skills/loader.d.ts.map +1 -0
  136. package/dist/skills/loader.js +57 -0
  137. package/dist/skills/loader.js.map +1 -0
  138. package/dist/skills/loader.test.d.ts +2 -0
  139. package/dist/skills/loader.test.d.ts.map +1 -0
  140. package/dist/skills/loader.test.js +69 -0
  141. package/dist/skills/loader.test.js.map +1 -0
  142. package/dist/skills/resolver.d.ts +46 -0
  143. package/dist/skills/resolver.d.ts.map +1 -0
  144. package/dist/skills/resolver.integration.test.d.ts +2 -0
  145. package/dist/skills/resolver.integration.test.d.ts.map +1 -0
  146. package/dist/skills/resolver.integration.test.js +106 -0
  147. package/dist/skills/resolver.integration.test.js.map +1 -0
  148. package/dist/skills/resolver.js +82 -0
  149. package/dist/skills/resolver.js.map +1 -0
  150. package/dist/skills/resolver.test.d.ts +2 -0
  151. package/dist/skills/resolver.test.d.ts.map +1 -0
  152. package/dist/skills/resolver.test.js +36 -0
  153. package/dist/skills/resolver.test.js.map +1 -0
  154. package/dist/sources/cache.d.ts +23 -0
  155. package/dist/sources/cache.d.ts.map +1 -0
  156. package/dist/sources/cache.js +61 -0
  157. package/dist/sources/cache.js.map +1 -0
  158. package/dist/sources/git.d.ts +25 -0
  159. package/dist/sources/git.d.ts.map +1 -0
  160. package/dist/sources/git.js +72 -0
  161. package/dist/sources/git.js.map +1 -0
  162. package/dist/sources/index.d.ts +5 -0
  163. package/dist/sources/index.d.ts.map +1 -0
  164. package/dist/sources/index.js +4 -0
  165. package/dist/sources/index.js.map +1 -0
  166. package/dist/sources/local.d.ts +9 -0
  167. package/dist/sources/local.d.ts.map +1 -0
  168. package/dist/sources/local.js +32 -0
  169. package/dist/sources/local.js.map +1 -0
  170. package/dist/symlinks/index.d.ts +2 -0
  171. package/dist/symlinks/index.d.ts.map +1 -0
  172. package/dist/symlinks/index.js +2 -0
  173. package/dist/symlinks/index.js.map +1 -0
  174. package/dist/symlinks/manager.d.ts +20 -0
  175. package/dist/symlinks/manager.d.ts.map +1 -0
  176. package/dist/symlinks/manager.js +103 -0
  177. package/dist/symlinks/manager.js.map +1 -0
  178. package/dist/symlinks/manager.test.d.ts +2 -0
  179. package/dist/symlinks/manager.test.d.ts.map +1 -0
  180. package/dist/symlinks/manager.test.js +94 -0
  181. package/dist/symlinks/manager.test.js.map +1 -0
  182. package/dist/utils/exec.d.ts +16 -0
  183. package/dist/utils/exec.d.ts.map +1 -0
  184. package/dist/utils/exec.js +37 -0
  185. package/dist/utils/exec.js.map +1 -0
  186. package/dist/utils/fs.d.ts +6 -0
  187. package/dist/utils/fs.d.ts.map +1 -0
  188. package/dist/utils/fs.js +10 -0
  189. package/dist/utils/fs.js.map +1 -0
  190. package/dist/utils/hash.d.ts +16 -0
  191. package/dist/utils/hash.d.ts.map +1 -0
  192. package/dist/utils/hash.js +50 -0
  193. package/dist/utils/hash.js.map +1 -0
  194. package/dist/utils/hash.test.d.ts +2 -0
  195. package/dist/utils/hash.test.d.ts.map +1 -0
  196. package/dist/utils/hash.test.js +61 -0
  197. package/dist/utils/hash.test.js.map +1 -0
  198. package/dist/utils/index.d.ts +4 -0
  199. package/dist/utils/index.d.ts.map +1 -0
  200. package/dist/utils/index.js +4 -0
  201. package/dist/utils/index.js.map +1 -0
  202. 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,4 @@
1
+ export { loadSkillMd, SkillLoadError } from "./loader.js";
2
+ export { discoverSkill, discoverAllSkills } from "./discovery.js";
3
+ export { resolveSkill, parseSource, ResolveError } from "./resolver.js";
4
+ //# sourceMappingURL=index.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=loader.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolver.integration.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolver.test.d.ts.map
@@ -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"}