@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,43 @@
1
+ import { z } from "zod/v4";
2
+ /**
3
+ * Source specifier patterns (inferred from value):
4
+ * owner/repo -- GitHub
5
+ * owner/repo@ref -- GitHub pinned
6
+ * git:https://... -- non-GitHub git
7
+ * path:../relative -- local filesystem
8
+ */
9
+ const GIT_URL_VALID = /^git:(https:\/\/|git:\/\/|ssh:\/\/|git@|file:\/\/|\/)/;
10
+ const skillSourceSchema = z.string().check(z.refine((s) => {
11
+ if (s.startsWith("git:")) {
12
+ // Require a valid protocol scheme or absolute path to prevent argument injection
13
+ return GIT_URL_VALID.test(s);
14
+ }
15
+ if (s.startsWith("path:"))
16
+ return true;
17
+ // owner/repo or owner/repo@ref
18
+ const base = s.includes("@") ? s.slice(0, s.indexOf("@")) : s;
19
+ const parts = base.split("/");
20
+ return parts.length === 2 && parts.every((p) => p.length > 0 && !p.startsWith("-"));
21
+ }, "Must be owner/repo, owner/repo@ref, git:<url> (with https/git/ssh protocol), or path:<relative>"));
22
+ /** Skill names must be safe for use in file paths: alphanumeric, dots, hyphens, underscores. */
23
+ const skillNameSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/, "Skill names must start with alphanumeric and contain only [a-zA-Z0-9._-]");
24
+ const skillDependencySchema = z.object({
25
+ name: skillNameSchema,
26
+ source: skillSourceSchema,
27
+ ref: z.string().optional(),
28
+ path: z.string().optional(),
29
+ });
30
+ const symlinksConfigSchema = z.object({
31
+ targets: z.array(z.string()).default([]),
32
+ });
33
+ const projectConfigSchema = z.object({
34
+ name: z.string().optional(),
35
+ });
36
+ export const agentsConfigSchema = z.object({
37
+ version: z.literal(1),
38
+ gitignore: z.boolean().default(true),
39
+ project: projectConfigSchema.optional(),
40
+ symlinks: symlinksConfigSchema.optional(),
41
+ skills: z.array(skillDependencySchema).default([]),
42
+ });
43
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,uDAAuD,CAAC;AAE9E,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CACxC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;IACb,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,iFAAiF;QACjF,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,+BAA+B;IAC/B,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACtF,CAAC,EAAE,iGAAiG,CAAC,CACtG,CAAC;AAIF,gGAAgG;AAChG,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CACtC,8BAA8B,EAC9B,0EAA0E,CAC3E,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,eAAe;IACrB,MAAM,EAAE,iBAAiB;IACzB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAIH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAIH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACpC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE;IACvC,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACnD,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schema.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.test.d.ts","sourceRoot":"","sources":["../../src/config/schema.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,138 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { agentsConfigSchema } from "./schema.js";
3
+ describe("agentsConfigSchema", () => {
4
+ it("parses a minimal valid config", () => {
5
+ const result = agentsConfigSchema.safeParse({ version: 1 });
6
+ expect(result.success).toBe(true);
7
+ if (result.success) {
8
+ expect(result.data.version).toBe(1);
9
+ expect(result.data.gitignore).toBe(true);
10
+ expect(result.data.skills).toEqual([]);
11
+ }
12
+ });
13
+ it("defaults gitignore to true when absent", () => {
14
+ const result = agentsConfigSchema.safeParse({ version: 1 });
15
+ expect(result.success).toBe(true);
16
+ if (result.success) {
17
+ expect(result.data.gitignore).toBe(true);
18
+ }
19
+ });
20
+ it("parses gitignore = true", () => {
21
+ const result = agentsConfigSchema.safeParse({ version: 1, gitignore: true });
22
+ expect(result.success).toBe(true);
23
+ if (result.success) {
24
+ expect(result.data.gitignore).toBe(true);
25
+ }
26
+ });
27
+ it("parses gitignore = false", () => {
28
+ const result = agentsConfigSchema.safeParse({ version: 1, gitignore: false });
29
+ expect(result.success).toBe(true);
30
+ if (result.success) {
31
+ expect(result.data.gitignore).toBe(false);
32
+ }
33
+ });
34
+ it("parses a full config with all fields", () => {
35
+ const result = agentsConfigSchema.safeParse({
36
+ version: 1,
37
+ project: { name: "test-project" },
38
+ symlinks: { targets: [".claude", ".cursor"] },
39
+ skills: [
40
+ {
41
+ name: "pdf-processing",
42
+ source: "anthropics/skills",
43
+ ref: "v1.0.0",
44
+ },
45
+ {
46
+ name: "my-skill",
47
+ source: "path:../shared/my-skill",
48
+ },
49
+ ],
50
+ });
51
+ expect(result.success).toBe(true);
52
+ if (result.success) {
53
+ expect(result.data.project?.name).toBe("test-project");
54
+ expect(result.data.symlinks?.targets).toEqual([".claude", ".cursor"]);
55
+ expect(result.data.skills).toHaveLength(2);
56
+ }
57
+ });
58
+ it("rejects invalid version", () => {
59
+ expect(agentsConfigSchema.safeParse({ version: 2 }).success).toBe(false);
60
+ });
61
+ it("rejects missing version", () => {
62
+ expect(agentsConfigSchema.safeParse({}).success).toBe(false);
63
+ });
64
+ describe("source specifiers", () => {
65
+ const parseSkill = (source) => agentsConfigSchema.safeParse({
66
+ version: 1,
67
+ skills: [{ name: "test", source }],
68
+ });
69
+ it("accepts owner/repo", () => {
70
+ expect(parseSkill("anthropics/skills").success).toBe(true);
71
+ });
72
+ it("accepts owner/repo@ref", () => {
73
+ expect(parseSkill("anthropics/skills@v1.0.0").success).toBe(true);
74
+ });
75
+ it("accepts owner/repo@sha", () => {
76
+ expect(parseSkill("anthropics/skills@abc123").success).toBe(true);
77
+ });
78
+ it("accepts git: source with https", () => {
79
+ expect(parseSkill("git:https://example.com/repo.git").success).toBe(true);
80
+ });
81
+ it("accepts git: source with ssh", () => {
82
+ expect(parseSkill("git:ssh://git@example.com/repo.git").success).toBe(true);
83
+ });
84
+ it("accepts git: source with git@", () => {
85
+ expect(parseSkill("git:git@github.com:owner/repo.git").success).toBe(true);
86
+ });
87
+ it("accepts git: source with absolute path", () => {
88
+ expect(parseSkill("git:/tmp/local-repo").success).toBe(true);
89
+ });
90
+ it("rejects git: source without protocol", () => {
91
+ expect(parseSkill("git:--upload-pack=evil").success).toBe(false);
92
+ });
93
+ it("rejects git: source with bare relative path", () => {
94
+ expect(parseSkill("git:relative/path").success).toBe(false);
95
+ });
96
+ it("accepts path: source", () => {
97
+ expect(parseSkill("path:../relative/dir").success).toBe(true);
98
+ });
99
+ it("rejects bare name without slash", () => {
100
+ expect(parseSkill("just-a-name").success).toBe(false);
101
+ });
102
+ it("rejects owner starting with dash", () => {
103
+ expect(parseSkill("-bad/repo").success).toBe(false);
104
+ });
105
+ it("rejects repo starting with dash", () => {
106
+ expect(parseSkill("owner/-bad").success).toBe(false);
107
+ });
108
+ it("rejects three-part path (not a valid format)", () => {
109
+ expect(parseSkill("a/b/c").success).toBe(false);
110
+ });
111
+ });
112
+ describe("skill name validation", () => {
113
+ const parseWithName = (name) => agentsConfigSchema.safeParse({
114
+ version: 1,
115
+ skills: [{ name, source: "owner/repo" }],
116
+ });
117
+ it("accepts valid skill names", () => {
118
+ expect(parseWithName("pdf-processing").success).toBe(true);
119
+ expect(parseWithName("my_skill").success).toBe(true);
120
+ expect(parseWithName("skill.v2").success).toBe(true);
121
+ expect(parseWithName("find-bugs").success).toBe(true);
122
+ });
123
+ it("rejects path traversal in skill names", () => {
124
+ expect(parseWithName("../../etc/passwd").success).toBe(false);
125
+ expect(parseWithName("../evil").success).toBe(false);
126
+ });
127
+ it("rejects skill names with slashes", () => {
128
+ expect(parseWithName("foo/bar").success).toBe(false);
129
+ });
130
+ it("rejects skill names starting with dot", () => {
131
+ expect(parseWithName(".hidden").success).toBe(false);
132
+ });
133
+ it("rejects skill names starting with hyphen", () => {
134
+ expect(parseWithName("-bad").success).toBe(false);
135
+ });
136
+ });
137
+ });
138
+ //# sourceMappingURL=schema.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/config/schema.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SkillDependency } from "./schema.js";
2
+ /**
3
+ * Add a skill entry to agents.toml.
4
+ * Appends a [[skills]] block at the end of the file.
5
+ * Uses smol-toml's stringify for proper TOML escaping.
6
+ */
7
+ export declare function addSkillToConfig(filePath: string, name: string, dep: Omit<SkillDependency, "name">): Promise<void>;
8
+ /**
9
+ * Remove a skill entry from agents.toml.
10
+ * Removes the [[skills]] block whose name field matches.
11
+ */
12
+ export declare function removeSkillFromConfig(filePath: string, name: string): Promise<void>;
13
+ /**
14
+ * Generate a minimal agents.toml scaffold.
15
+ */
16
+ export declare function generateDefaultConfig(): string;
17
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/config/writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAGf;AAyCD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C"}
@@ -0,0 +1,71 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { stringify } from "smol-toml";
3
+ /**
4
+ * Add a skill entry to agents.toml.
5
+ * Appends a [[skills]] block at the end of the file.
6
+ * Uses smol-toml's stringify for proper TOML escaping.
7
+ */
8
+ export async function addSkillToConfig(filePath, name, dep) {
9
+ const content = await readFile(filePath, "utf-8");
10
+ // Build a partial TOML object and stringify it for proper escaping
11
+ const entry = { name, source: dep.source };
12
+ if (dep.ref)
13
+ entry["ref"] = dep.ref;
14
+ if (dep.path)
15
+ entry["path"] = dep.path;
16
+ const section = stringify({ skills: [entry] });
17
+ const newContent = content.trimEnd() + "\n\n" + section.trimEnd() + "\n";
18
+ await writeFile(filePath, newContent, "utf-8");
19
+ }
20
+ /**
21
+ * Remove a skill entry from agents.toml.
22
+ * Removes the [[skills]] block whose name field matches.
23
+ */
24
+ export async function removeSkillFromConfig(filePath, name) {
25
+ const content = await readFile(filePath, "utf-8");
26
+ await writeFile(filePath, removeBlockByName(content, name), "utf-8");
27
+ }
28
+ function removeBlockByName(content, name) {
29
+ const lines = content.split("\n");
30
+ const result = [];
31
+ let i = 0;
32
+ while (i < lines.length) {
33
+ if (lines[i].trim() === "[[skills]]") {
34
+ // Collect the entire block (header + key-value lines)
35
+ const blockLines = [lines[i]];
36
+ i++;
37
+ while (i < lines.length && lines[i].trim() !== "" && !lines[i].trim().startsWith("[")) {
38
+ blockLines.push(lines[i]);
39
+ i++;
40
+ }
41
+ // Check if this block's name matches
42
+ const nameLine = blockLines.find((l) => l.trim().startsWith("name"));
43
+ const match = nameLine?.match(/^name\s*=\s*"([^"]+)"/);
44
+ if (match && match[1] === name) {
45
+ // Remove blank lines before the block
46
+ while (result.length > 0 && result[result.length - 1]?.trim() === "") {
47
+ result.pop();
48
+ }
49
+ // Skip this block
50
+ continue;
51
+ }
52
+ // Not the target — keep the block
53
+ result.push(...blockLines);
54
+ continue;
55
+ }
56
+ result.push(lines[i]);
57
+ i++;
58
+ }
59
+ return result.join("\n");
60
+ }
61
+ /**
62
+ * Generate a minimal agents.toml scaffold.
63
+ */
64
+ export function generateDefaultConfig() {
65
+ return `version = 1
66
+ # Check skills into git so collaborators get them without running 'dotagents install'.
67
+ # Set to true (or remove) to gitignore managed skills instead.
68
+ gitignore = false
69
+ `;
70
+ }
71
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/config/writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=writer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.test.d.ts","sourceRoot":"","sources":["../../src/config/writer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,103 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtemp, writeFile, readFile, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { addSkillToConfig, removeSkillFromConfig, generateDefaultConfig, } from "./writer.js";
6
+ import { loadConfig } from "./loader.js";
7
+ describe("writer", () => {
8
+ let dir;
9
+ let configPath;
10
+ beforeEach(async () => {
11
+ dir = await mkdtemp(join(tmpdir(), "dotagents-test-"));
12
+ configPath = join(dir, "agents.toml");
13
+ await writeFile(configPath, generateDefaultConfig());
14
+ });
15
+ afterEach(async () => {
16
+ await rm(dir, { recursive: true });
17
+ });
18
+ describe("generateDefaultConfig", () => {
19
+ it("produces valid TOML that parses", async () => {
20
+ const config = await loadConfig(configPath);
21
+ expect(config.version).toBe(1);
22
+ expect(config.skills).toEqual([]);
23
+ });
24
+ it("sets gitignore to false by default", async () => {
25
+ const config = await loadConfig(configPath);
26
+ expect(config.gitignore).toBe(false);
27
+ });
28
+ it("contains gitignore = false in output", () => {
29
+ const content = generateDefaultConfig();
30
+ expect(content).toContain("gitignore = false");
31
+ });
32
+ });
33
+ describe("addSkillToConfig", () => {
34
+ it("adds a skill with source only", async () => {
35
+ await addSkillToConfig(configPath, "pdf", {
36
+ source: "anthropics/skills",
37
+ });
38
+ const config = await loadConfig(configPath);
39
+ const pdf = config.skills.find((s) => s.name === "pdf");
40
+ expect(pdf?.source).toBe("anthropics/skills");
41
+ });
42
+ it("adds a skill with source and ref", async () => {
43
+ await addSkillToConfig(configPath, "pdf", {
44
+ source: "anthropics/skills",
45
+ ref: "v1.0.0",
46
+ });
47
+ const config = await loadConfig(configPath);
48
+ const pdf = config.skills.find((s) => s.name === "pdf");
49
+ expect(pdf?.ref).toBe("v1.0.0");
50
+ });
51
+ it("adds a skill with source, ref, and path", async () => {
52
+ await addSkillToConfig(configPath, "review", {
53
+ source: "git:https://example.com/repo.git",
54
+ ref: "main",
55
+ path: "skills/review",
56
+ });
57
+ const config = await loadConfig(configPath);
58
+ const review = config.skills.find((s) => s.name === "review");
59
+ expect(review?.source).toBe("git:https://example.com/repo.git");
60
+ expect(review?.path).toBe("skills/review");
61
+ });
62
+ it("adds multiple skills", async () => {
63
+ await addSkillToConfig(configPath, "a", {
64
+ source: "org/repo-a",
65
+ });
66
+ await addSkillToConfig(configPath, "b", {
67
+ source: "org/repo-b",
68
+ });
69
+ const config = await loadConfig(configPath);
70
+ expect(config.skills).toHaveLength(2);
71
+ });
72
+ });
73
+ describe("removeSkillFromConfig", () => {
74
+ it("removes an existing skill", async () => {
75
+ await addSkillToConfig(configPath, "pdf", {
76
+ source: "anthropics/skills",
77
+ ref: "v1.0.0",
78
+ });
79
+ await removeSkillFromConfig(configPath, "pdf");
80
+ const config = await loadConfig(configPath);
81
+ expect(config.skills.find((s) => s.name === "pdf")).toBeUndefined();
82
+ });
83
+ it("preserves other skills when removing one", async () => {
84
+ await addSkillToConfig(configPath, "a", {
85
+ source: "org/repo-a",
86
+ });
87
+ await addSkillToConfig(configPath, "b", {
88
+ source: "org/repo-b",
89
+ });
90
+ await removeSkillFromConfig(configPath, "a");
91
+ const config = await loadConfig(configPath);
92
+ expect(config.skills.find((s) => s.name === "a")).toBeUndefined();
93
+ expect(config.skills.find((s) => s.name === "b")?.source).toBe("org/repo-b");
94
+ });
95
+ it("is a no-op for non-existent skill", async () => {
96
+ const before = await readFile(configPath, "utf-8");
97
+ await removeSkillFromConfig(configPath, "nope");
98
+ const after = await readFile(configPath, "utf-8");
99
+ expect(after).toBe(before);
100
+ });
101
+ });
102
+ });
103
+ //# sourceMappingURL=writer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.test.js","sourceRoot":"","sources":["../../src/config/writer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IACtB,IAAI,GAAW,CAAC;IAChB,IAAI,UAAkB,CAAC;IAEvB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;QACvD,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QACtC,MAAM,SAAS,CAAC,UAAU,EAAE,qBAAqB,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;YACxC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE;gBACxC,MAAM,EAAE,mBAAmB;aAC5B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;YACxD,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE;gBACxC,MAAM,EAAE,mBAAmB;gBAC3B,GAAG,EAAE,QAAQ;aACd,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;YACxD,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE;gBAC3C,MAAM,EAAE,kCAAkC;gBAC1C,GAAG,EAAE,MAAM;gBACX,IAAI,EAAE,eAAe;aACtB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YAC9D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YAChE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;gBACtC,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YACH,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;gBACtC,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE;gBACxC,MAAM,EAAE,mBAAmB;gBAC3B,GAAG,EAAE,QAAQ;aACd,CAAC,CAAC;YACH,MAAM,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAE/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;gBACtC,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YACH,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;gBACtC,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YACH,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;YAClE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,qBAAqB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { writeAgentsGitignore, removeAgentsGitignore, updateAgentsGitignore } from "./writer.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gitignore/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { writeAgentsGitignore, removeAgentsGitignore, updateAgentsGitignore } from "./writer.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gitignore/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generate .agents/.gitignore listing managed skill directories.
3
+ * Skills with path: sources are also gitignored since they're installed by dotagents.
4
+ */
5
+ export declare function writeAgentsGitignore(agentsDir: string, managedSkillNames: string[]): Promise<void>;
6
+ /**
7
+ * Remove .agents/.gitignore if it exists.
8
+ */
9
+ export declare function removeAgentsGitignore(agentsDir: string): Promise<void>;
10
+ /**
11
+ * Create or remove .agents/.gitignore based on the gitignore config option.
12
+ * When gitignore is true, generates the gitignore listing managed skills.
13
+ * When gitignore is false, removes the gitignore file if it exists.
14
+ */
15
+ export declare function updateAgentsGitignore(agentsDir: string, gitignore: boolean, managedSkillNames: string[]): Promise<void>;
16
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/gitignore/writer.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -0,0 +1,40 @@
1
+ import { rm, writeFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ const HEADER = `# Auto-generated by dotagents. Do not edit.
5
+ # Managed skills (installed by dotagents)`;
6
+ /**
7
+ * Generate .agents/.gitignore listing managed skill directories.
8
+ * Skills with path: sources are also gitignored since they're installed by dotagents.
9
+ */
10
+ export async function writeAgentsGitignore(agentsDir, managedSkillNames) {
11
+ const lines = [HEADER];
12
+ for (const name of managedSkillNames.sort()) {
13
+ lines.push(`/skills/${name}/`);
14
+ }
15
+ lines.push(""); // trailing newline
16
+ await writeFile(join(agentsDir, ".gitignore"), lines.join("\n"), "utf-8");
17
+ }
18
+ /**
19
+ * Remove .agents/.gitignore if it exists.
20
+ */
21
+ export async function removeAgentsGitignore(agentsDir) {
22
+ const gitignorePath = join(agentsDir, ".gitignore");
23
+ if (existsSync(gitignorePath)) {
24
+ await rm(gitignorePath);
25
+ }
26
+ }
27
+ /**
28
+ * Create or remove .agents/.gitignore based on the gitignore config option.
29
+ * When gitignore is true, generates the gitignore listing managed skills.
30
+ * When gitignore is false, removes the gitignore file if it exists.
31
+ */
32
+ export async function updateAgentsGitignore(agentsDir, gitignore, managedSkillNames) {
33
+ if (gitignore) {
34
+ await writeAgentsGitignore(agentsDir, managedSkillNames);
35
+ }
36
+ else {
37
+ await removeAgentsGitignore(agentsDir);
38
+ }
39
+ }
40
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/gitignore/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,MAAM,GAAG;0CAC2B,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,iBAA2B;IAE3B,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC;IACjC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB;IAEnC,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,SAAiB;IAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,MAAM,EAAE,CAAC,aAAa,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAiB,EACjB,SAAkB,EAClB,iBAA2B;IAE3B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,oBAAoB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,MAAM,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=writer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.test.d.ts","sourceRoot":"","sources":["../../src/gitignore/writer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,99 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtemp, readFile, rm, mkdir, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { existsSync } from "node:fs";
6
+ import { writeAgentsGitignore, removeAgentsGitignore, updateAgentsGitignore } from "./writer.js";
7
+ describe("writeAgentsGitignore", () => {
8
+ let dir;
9
+ beforeEach(async () => {
10
+ dir = await mkdtemp(join(tmpdir(), "dotagents-test-"));
11
+ await mkdir(join(dir, ".agents"), { recursive: true });
12
+ });
13
+ afterEach(async () => {
14
+ await rm(dir, { recursive: true });
15
+ });
16
+ it("writes header with no managed skills", async () => {
17
+ const agentsDir = join(dir, ".agents");
18
+ await writeAgentsGitignore(agentsDir, []);
19
+ const content = await readFile(join(agentsDir, ".gitignore"), "utf-8");
20
+ expect(content).toContain("Auto-generated by dotagents");
21
+ expect(content.split("\n").filter((l) => l.startsWith("/skills/"))).toHaveLength(0);
22
+ });
23
+ it("lists managed skill directories", async () => {
24
+ const agentsDir = join(dir, ".agents");
25
+ await writeAgentsGitignore(agentsDir, ["pdf", "find-bugs", "code-review"]);
26
+ const content = await readFile(join(agentsDir, ".gitignore"), "utf-8");
27
+ expect(content).toContain("/skills/code-review/");
28
+ expect(content).toContain("/skills/find-bugs/");
29
+ expect(content).toContain("/skills/pdf/");
30
+ });
31
+ it("sorts skill names alphabetically", async () => {
32
+ const agentsDir = join(dir, ".agents");
33
+ await writeAgentsGitignore(agentsDir, ["zebra", "alpha", "middle"]);
34
+ const content = await readFile(join(agentsDir, ".gitignore"), "utf-8");
35
+ const lines = content.split("\n").filter((l) => l.startsWith("/skills/"));
36
+ expect(lines).toEqual([
37
+ "/skills/alpha/",
38
+ "/skills/middle/",
39
+ "/skills/zebra/",
40
+ ]);
41
+ });
42
+ it("overwrites existing gitignore", async () => {
43
+ const agentsDir = join(dir, ".agents");
44
+ await writeAgentsGitignore(agentsDir, ["old-skill"]);
45
+ await writeAgentsGitignore(agentsDir, ["new-skill"]);
46
+ const content = await readFile(join(agentsDir, ".gitignore"), "utf-8");
47
+ expect(content).not.toContain("old-skill");
48
+ expect(content).toContain("new-skill");
49
+ });
50
+ });
51
+ describe("removeAgentsGitignore", () => {
52
+ let dir;
53
+ beforeEach(async () => {
54
+ dir = await mkdtemp(join(tmpdir(), "dotagents-test-"));
55
+ await mkdir(join(dir, ".agents"), { recursive: true });
56
+ });
57
+ afterEach(async () => {
58
+ await rm(dir, { recursive: true });
59
+ });
60
+ it("removes existing .gitignore", async () => {
61
+ const agentsDir = join(dir, ".agents");
62
+ await writeFile(join(agentsDir, ".gitignore"), "some content");
63
+ await removeAgentsGitignore(agentsDir);
64
+ expect(existsSync(join(agentsDir, ".gitignore"))).toBe(false);
65
+ });
66
+ it("is a no-op when .gitignore does not exist", async () => {
67
+ const agentsDir = join(dir, ".agents");
68
+ await removeAgentsGitignore(agentsDir);
69
+ expect(existsSync(join(agentsDir, ".gitignore"))).toBe(false);
70
+ });
71
+ });
72
+ describe("updateAgentsGitignore", () => {
73
+ let dir;
74
+ beforeEach(async () => {
75
+ dir = await mkdtemp(join(tmpdir(), "dotagents-test-"));
76
+ await mkdir(join(dir, ".agents"), { recursive: true });
77
+ });
78
+ afterEach(async () => {
79
+ await rm(dir, { recursive: true });
80
+ });
81
+ it("creates .gitignore when gitignore is true", async () => {
82
+ const agentsDir = join(dir, ".agents");
83
+ await updateAgentsGitignore(agentsDir, true, ["my-skill"]);
84
+ const content = await readFile(join(agentsDir, ".gitignore"), "utf-8");
85
+ expect(content).toContain("/skills/my-skill/");
86
+ });
87
+ it("removes .gitignore when gitignore is false", async () => {
88
+ const agentsDir = join(dir, ".agents");
89
+ await writeFile(join(agentsDir, ".gitignore"), "existing content");
90
+ await updateAgentsGitignore(agentsDir, false, ["my-skill"]);
91
+ expect(existsSync(join(agentsDir, ".gitignore"))).toBe(false);
92
+ });
93
+ it("does not create .gitignore when gitignore is false", async () => {
94
+ const agentsDir = join(dir, ".agents");
95
+ await updateAgentsGitignore(agentsDir, false, ["my-skill"]);
96
+ expect(existsSync(join(agentsDir, ".gitignore"))).toBe(false);
97
+ });
98
+ });
99
+ //# sourceMappingURL=writer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.test.js","sourceRoot":"","sources":["../../src/gitignore/writer.test.ts"],"names":[],"mappings":"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"}