agentpacks 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 (172) hide show
  1. package/dist/api.d.ts +32 -0
  2. package/dist/api.js +2852 -0
  3. package/dist/cli/export-cmd.d.ts +12 -0
  4. package/dist/cli/export-cmd.js +786 -0
  5. package/dist/cli/generate.d.ts +13 -0
  6. package/dist/cli/generate.js +2018 -0
  7. package/dist/cli/import-cmd.d.ts +9 -0
  8. package/dist/cli/import-cmd.js +691 -0
  9. package/dist/cli/init.d.ts +5 -0
  10. package/dist/cli/init.js +214 -0
  11. package/dist/cli/install.d.ts +11 -0
  12. package/dist/cli/install.js +610 -0
  13. package/dist/cli/pack/create.d.ts +4 -0
  14. package/dist/cli/pack/create.js +175 -0
  15. package/dist/cli/pack/enable.d.ts +8 -0
  16. package/dist/cli/pack/enable.js +96 -0
  17. package/dist/cli/pack/list.d.ts +4 -0
  18. package/dist/cli/pack/list.js +699 -0
  19. package/dist/cli/pack/validate.d.ts +4 -0
  20. package/dist/cli/pack/validate.js +364 -0
  21. package/dist/core/config.d.ts +77 -0
  22. package/dist/core/config.js +181 -0
  23. package/dist/core/dependency-resolver.d.ts +38 -0
  24. package/dist/core/dependency-resolver.js +151 -0
  25. package/dist/core/feature-merger.d.ts +61 -0
  26. package/dist/core/feature-merger.js +139 -0
  27. package/dist/core/index.d.ts +5 -0
  28. package/dist/core/index.js +924 -0
  29. package/dist/core/lockfile.d.ts +50 -0
  30. package/dist/core/lockfile.js +72 -0
  31. package/dist/core/metarepo.d.ts +26 -0
  32. package/dist/core/metarepo.js +218 -0
  33. package/dist/core/pack-loader.d.ts +61 -0
  34. package/dist/core/pack-loader.js +646 -0
  35. package/dist/exporters/cursor-plugin.d.ts +29 -0
  36. package/dist/exporters/cursor-plugin.js +258 -0
  37. package/dist/exporters/index.d.ts +1 -0
  38. package/dist/exporters/index.js +258 -0
  39. package/dist/features/agents.d.ts +48 -0
  40. package/dist/features/agents.js +190 -0
  41. package/dist/features/commands.d.ts +33 -0
  42. package/dist/features/commands.js +190 -0
  43. package/dist/features/hooks.d.ts +33 -0
  44. package/dist/features/hooks.js +182 -0
  45. package/dist/features/ignore.d.ts +21 -0
  46. package/dist/features/ignore.js +72 -0
  47. package/dist/features/index.d.ts +8 -0
  48. package/dist/features/index.js +426 -0
  49. package/dist/features/mcp.d.ts +34 -0
  50. package/dist/features/mcp.js +172 -0
  51. package/dist/features/plugins.d.ts +23 -0
  52. package/dist/features/plugins.js +168 -0
  53. package/dist/features/rules.d.ts +53 -0
  54. package/dist/features/rules.js +198 -0
  55. package/dist/features/skills.d.ts +42 -0
  56. package/dist/features/skills.js +198 -0
  57. package/dist/importers/claude-code.d.ts +5 -0
  58. package/dist/importers/claude-code.js +224 -0
  59. package/dist/importers/cursor.d.ts +5 -0
  60. package/dist/importers/cursor.js +288 -0
  61. package/dist/importers/opencode.d.ts +5 -0
  62. package/dist/importers/opencode.js +261 -0
  63. package/dist/importers/rulesync.d.ts +14 -0
  64. package/dist/importers/rulesync.js +280 -0
  65. package/dist/index.d.ts +2 -0
  66. package/dist/index.js +3464 -0
  67. package/dist/node/api.js +2852 -0
  68. package/dist/node/cli/export-cmd.js +786 -0
  69. package/dist/node/cli/generate.js +2018 -0
  70. package/dist/node/cli/import-cmd.js +691 -0
  71. package/dist/node/cli/init.js +214 -0
  72. package/dist/node/cli/install.js +610 -0
  73. package/dist/node/cli/pack/create.js +175 -0
  74. package/dist/node/cli/pack/enable.js +96 -0
  75. package/dist/node/cli/pack/list.js +699 -0
  76. package/dist/node/cli/pack/validate.js +364 -0
  77. package/dist/node/core/config.js +181 -0
  78. package/dist/node/core/dependency-resolver.js +151 -0
  79. package/dist/node/core/feature-merger.js +139 -0
  80. package/dist/node/core/index.js +924 -0
  81. package/dist/node/core/lockfile.js +72 -0
  82. package/dist/node/core/metarepo.js +218 -0
  83. package/dist/node/core/pack-loader.js +646 -0
  84. package/dist/node/exporters/cursor-plugin.js +258 -0
  85. package/dist/node/exporters/index.js +258 -0
  86. package/dist/node/features/agents.js +190 -0
  87. package/dist/node/features/commands.js +190 -0
  88. package/dist/node/features/hooks.js +182 -0
  89. package/dist/node/features/ignore.js +72 -0
  90. package/dist/node/features/index.js +426 -0
  91. package/dist/node/features/mcp.js +172 -0
  92. package/dist/node/features/plugins.js +168 -0
  93. package/dist/node/features/rules.js +198 -0
  94. package/dist/node/features/skills.js +198 -0
  95. package/dist/node/importers/claude-code.js +224 -0
  96. package/dist/node/importers/cursor.js +288 -0
  97. package/dist/node/importers/opencode.js +261 -0
  98. package/dist/node/importers/rulesync.js +280 -0
  99. package/dist/node/index.js +3464 -0
  100. package/dist/node/sources/git-ref.js +79 -0
  101. package/dist/node/sources/git.js +245 -0
  102. package/dist/node/sources/index.js +416 -0
  103. package/dist/node/sources/local.js +52 -0
  104. package/dist/node/sources/npm-ref.js +84 -0
  105. package/dist/node/sources/npm.js +211 -0
  106. package/dist/node/targets/additional-targets.js +428 -0
  107. package/dist/node/targets/agents-md.js +239 -0
  108. package/dist/node/targets/base-target.js +51 -0
  109. package/dist/node/targets/claude-code.js +490 -0
  110. package/dist/node/targets/codex-cli.js +297 -0
  111. package/dist/node/targets/copilot.js +390 -0
  112. package/dist/node/targets/cursor.js +441 -0
  113. package/dist/node/targets/gemini-cli.js +352 -0
  114. package/dist/node/targets/generic-md-target.js +319 -0
  115. package/dist/node/targets/index.js +1351 -0
  116. package/dist/node/targets/opencode.js +556 -0
  117. package/dist/node/targets/registry.js +1343 -0
  118. package/dist/node/utils/diff.js +144 -0
  119. package/dist/node/utils/filesystem.js +152 -0
  120. package/dist/node/utils/frontmatter.js +52 -0
  121. package/dist/node/utils/global.js +81 -0
  122. package/dist/node/utils/markdown.js +62 -0
  123. package/dist/sources/git-ref.d.ts +27 -0
  124. package/dist/sources/git-ref.js +79 -0
  125. package/dist/sources/git.d.ts +29 -0
  126. package/dist/sources/git.js +245 -0
  127. package/dist/sources/index.d.ts +5 -0
  128. package/dist/sources/index.js +416 -0
  129. package/dist/sources/local.d.ts +8 -0
  130. package/dist/sources/local.js +52 -0
  131. package/dist/sources/npm-ref.d.ts +30 -0
  132. package/dist/sources/npm-ref.js +84 -0
  133. package/dist/sources/npm.d.ts +20 -0
  134. package/dist/sources/npm.js +211 -0
  135. package/dist/targets/additional-targets.d.ts +65 -0
  136. package/dist/targets/additional-targets.js +428 -0
  137. package/dist/targets/agents-md.d.ts +13 -0
  138. package/dist/targets/agents-md.js +239 -0
  139. package/dist/targets/base-target.d.ts +61 -0
  140. package/dist/targets/base-target.js +51 -0
  141. package/dist/targets/claude-code.d.ts +13 -0
  142. package/dist/targets/claude-code.js +490 -0
  143. package/dist/targets/codex-cli.d.ts +12 -0
  144. package/dist/targets/codex-cli.js +297 -0
  145. package/dist/targets/copilot.d.ts +12 -0
  146. package/dist/targets/copilot.js +390 -0
  147. package/dist/targets/cursor.d.ts +13 -0
  148. package/dist/targets/cursor.js +441 -0
  149. package/dist/targets/gemini-cli.d.ts +12 -0
  150. package/dist/targets/gemini-cli.js +352 -0
  151. package/dist/targets/generic-md-target.d.ts +25 -0
  152. package/dist/targets/generic-md-target.js +319 -0
  153. package/dist/targets/index.d.ts +9 -0
  154. package/dist/targets/index.js +1351 -0
  155. package/dist/targets/opencode.d.ts +13 -0
  156. package/dist/targets/opencode.js +556 -0
  157. package/dist/targets/registry.d.ts +17 -0
  158. package/dist/targets/registry.js +1343 -0
  159. package/dist/utils/diff.d.ts +13 -0
  160. package/dist/utils/diff.js +144 -0
  161. package/dist/utils/filesystem.d.ts +49 -0
  162. package/dist/utils/filesystem.js +152 -0
  163. package/dist/utils/frontmatter.d.ts +19 -0
  164. package/dist/utils/frontmatter.js +52 -0
  165. package/dist/utils/global.d.ts +17 -0
  166. package/dist/utils/global.js +81 -0
  167. package/dist/utils/markdown.d.ts +20 -0
  168. package/dist/utils/markdown.js +62 -0
  169. package/package.json +808 -0
  170. package/templates/pack/pack.json +10 -0
  171. package/templates/pack/rules/overview.md +22 -0
  172. package/templates/workspace/agentpacks.jsonc +34 -0
package/dist/index.js ADDED
@@ -0,0 +1,3464 @@
1
+ #!/usr/bin/env node
2
+ // @bun
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
8
+ var __toCommonJS = (from) => {
9
+ var entry = __moduleCache.get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function")
14
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ }));
18
+ __moduleCache.set(from, entry);
19
+ return entry;
20
+ };
21
+ var __export = (target, all) => {
22
+ for (var name in all)
23
+ __defProp(target, name, {
24
+ get: all[name],
25
+ enumerable: true,
26
+ configurable: true,
27
+ set: (newValue) => all[name] = () => newValue
28
+ });
29
+ };
30
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
31
+ var __require = import.meta.require;
32
+
33
+ // src/core/config.ts
34
+ var exports_config = {};
35
+ __export(exports_config, {
36
+ resolveTargets: () => resolveTargets,
37
+ resolveFeatures: () => resolveFeatures,
38
+ loadWorkspaceConfig: () => loadWorkspaceConfig,
39
+ loadPackManifest: () => loadPackManifest,
40
+ WorkspaceConfigSchema: () => WorkspaceConfigSchema,
41
+ TARGET_IDS: () => TARGET_IDS,
42
+ REPO_MODES: () => REPO_MODES,
43
+ PackManifestSchema: () => PackManifestSchema,
44
+ FEATURE_IDS: () => FEATURE_IDS
45
+ });
46
+ import { z } from "zod";
47
+ import { readFileSync, existsSync } from "fs";
48
+ import { resolve } from "path";
49
+ import { parse as parseJsonc } from "jsonc-parser";
50
+ function loadWorkspaceConfig(projectRoot) {
51
+ for (const filename of CONFIG_FILES) {
52
+ const filepath = resolve(projectRoot, filename);
53
+ if (existsSync(filepath)) {
54
+ const raw = readFileSync(filepath, "utf-8");
55
+ const parsed = parseJsonc(raw);
56
+ return WorkspaceConfigSchema.parse(parsed);
57
+ }
58
+ }
59
+ return WorkspaceConfigSchema.parse({});
60
+ }
61
+ function loadPackManifest(packDir) {
62
+ const filepath = resolve(packDir, "pack.json");
63
+ if (!existsSync(filepath)) {
64
+ const dirName = packDir.split("/").pop() ?? "unknown";
65
+ return PackManifestSchema.parse({ name: dirName });
66
+ }
67
+ const raw = readFileSync(filepath, "utf-8");
68
+ const parsed = JSON.parse(raw);
69
+ return PackManifestSchema.parse(parsed);
70
+ }
71
+ function resolveFeatures(config, targetId) {
72
+ const { features } = config;
73
+ if (features === "*") {
74
+ return [...FEATURE_IDS];
75
+ }
76
+ if (Array.isArray(features)) {
77
+ if (features.includes("*"))
78
+ return [...FEATURE_IDS];
79
+ return features.filter((f) => FEATURE_IDS.includes(f));
80
+ }
81
+ const targetFeatures = features[targetId];
82
+ if (!targetFeatures)
83
+ return [];
84
+ if (targetFeatures === "*")
85
+ return [...FEATURE_IDS];
86
+ if (Array.isArray(targetFeatures) && targetFeatures.includes("*"))
87
+ return [...FEATURE_IDS];
88
+ return targetFeatures.filter((f) => FEATURE_IDS.includes(f));
89
+ }
90
+ function resolveTargets(config) {
91
+ if (config.targets === "*")
92
+ return [...TARGET_IDS];
93
+ return config.targets;
94
+ }
95
+ var TARGET_IDS, FEATURE_IDS, REPO_MODES, PackManifestSchema, FeaturesSchema, WorkspaceConfigSchema, CONFIG_FILES;
96
+ var init_config = __esm(() => {
97
+ TARGET_IDS = [
98
+ "opencode",
99
+ "cursor",
100
+ "claudecode",
101
+ "codexcli",
102
+ "geminicli",
103
+ "copilot",
104
+ "agentsmd",
105
+ "cline",
106
+ "kilo",
107
+ "roo",
108
+ "qwencode",
109
+ "kiro",
110
+ "factorydroid",
111
+ "antigravity",
112
+ "junie",
113
+ "augmentcode",
114
+ "windsurf",
115
+ "warp",
116
+ "replit",
117
+ "zed"
118
+ ];
119
+ FEATURE_IDS = [
120
+ "rules",
121
+ "commands",
122
+ "agents",
123
+ "skills",
124
+ "hooks",
125
+ "plugins",
126
+ "mcp",
127
+ "ignore"
128
+ ];
129
+ REPO_MODES = ["repo", "monorepo", "metarepo"];
130
+ PackManifestSchema = z.object({
131
+ name: z.string().min(1),
132
+ version: z.string().default("1.0.0"),
133
+ description: z.string().default(""),
134
+ author: z.union([
135
+ z.string(),
136
+ z.object({ name: z.string(), email: z.string().optional() })
137
+ ]).optional(),
138
+ tags: z.array(z.string()).default([]),
139
+ dependencies: z.array(z.string()).default([]),
140
+ conflicts: z.array(z.string()).default([]),
141
+ targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
142
+ features: z.union([z.literal("*"), z.array(z.string())]).default("*")
143
+ });
144
+ FeaturesSchema = z.union([
145
+ z.literal("*"),
146
+ z.array(z.string()),
147
+ z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]))
148
+ ]);
149
+ WorkspaceConfigSchema = z.object({
150
+ $schema: z.string().optional(),
151
+ packs: z.array(z.string()).default(["./packs/default"]),
152
+ disabled: z.array(z.string()).default([]),
153
+ targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
154
+ features: FeaturesSchema.default("*"),
155
+ mode: z.enum(REPO_MODES).default("repo"),
156
+ baseDirs: z.array(z.string()).default(["."]),
157
+ global: z.boolean().default(false),
158
+ delete: z.boolean().default(true),
159
+ verbose: z.boolean().default(false),
160
+ silent: z.boolean().default(false),
161
+ overrides: z.record(z.string(), z.record(z.string(), z.string())).default({}),
162
+ sources: z.array(z.object({
163
+ source: z.string(),
164
+ packs: z.array(z.string()).optional(),
165
+ skills: z.array(z.string()).optional()
166
+ })).default([])
167
+ });
168
+ CONFIG_FILES = ["agentpacks.local.jsonc", "agentpacks.jsonc"];
169
+ });
170
+
171
+ // src/utils/filesystem.ts
172
+ import {
173
+ existsSync as existsSync2,
174
+ mkdirSync,
175
+ readFileSync as readFileSync2,
176
+ writeFileSync,
177
+ readdirSync,
178
+ statSync
179
+ } from "fs";
180
+ import { dirname, relative, join } from "path";
181
+ import { removeSync } from "fs-extra";
182
+ var GENERATED_HEADER_MD = "<!-- Generated by agentpacks. DO NOT EDIT. -->";
183
+ var GENERATED_HEADER_JSON = "// Generated by agentpacks. DO NOT EDIT.";
184
+ var GENERATED_HEADER_JS = "// Generated by agentpacks. DO NOT EDIT.";
185
+ function writeGeneratedFile(filepath, content, options = {}) {
186
+ const { header = true, type } = options;
187
+ const ext = type ?? inferFileType(filepath);
188
+ ensureDir(dirname(filepath));
189
+ let output = content;
190
+ if (header) {
191
+ const headerComment = getHeader(ext);
192
+ if (headerComment) {
193
+ output = `${headerComment}
194
+ ${content}`;
195
+ }
196
+ }
197
+ writeFileSync(filepath, output, "utf-8");
198
+ }
199
+ function writeGeneratedJson(filepath, data, options = {}) {
200
+ const json = JSON.stringify(data, null, 2);
201
+ writeGeneratedFile(filepath, json + `
202
+ `, { ...options, type: "json" });
203
+ }
204
+ function readFileOrNull(filepath) {
205
+ if (!existsSync2(filepath))
206
+ return null;
207
+ return readFileSync2(filepath, "utf-8");
208
+ }
209
+ function readJsonOrNull(filepath) {
210
+ const content = readFileOrNull(filepath);
211
+ if (content === null)
212
+ return null;
213
+ return JSON.parse(content);
214
+ }
215
+ function ensureDir(dirPath) {
216
+ if (!existsSync2(dirPath)) {
217
+ mkdirSync(dirPath, { recursive: true });
218
+ }
219
+ }
220
+ function removeIfExists(targetPath) {
221
+ if (existsSync2(targetPath)) {
222
+ removeSync(targetPath);
223
+ }
224
+ }
225
+ function listFiles(dirPath, options = {}) {
226
+ const { extension, recursive = false } = options;
227
+ if (!existsSync2(dirPath))
228
+ return [];
229
+ const results = [];
230
+ const entries = readdirSync(dirPath);
231
+ for (const entry of entries) {
232
+ const fullPath = join(dirPath, entry);
233
+ const stat = statSync(fullPath);
234
+ if (stat.isDirectory() && recursive) {
235
+ results.push(...listFiles(fullPath, options));
236
+ } else if (stat.isFile()) {
237
+ if (!extension || entry.endsWith(extension)) {
238
+ results.push(fullPath);
239
+ }
240
+ }
241
+ }
242
+ return results;
243
+ }
244
+ function listDirs(dirPath) {
245
+ if (!existsSync2(dirPath))
246
+ return [];
247
+ return readdirSync(dirPath).map((entry) => join(dirPath, entry)).filter((fullPath) => statSync(fullPath).isDirectory());
248
+ }
249
+ function relPath(projectRoot, filepath) {
250
+ return relative(projectRoot, filepath);
251
+ }
252
+ function isGeneratedFile(filepath) {
253
+ const content = readFileOrNull(filepath);
254
+ if (!content)
255
+ return false;
256
+ return content.startsWith(GENERATED_HEADER_MD) || content.startsWith(GENERATED_HEADER_JSON) || content.startsWith(GENERATED_HEADER_JS);
257
+ }
258
+ function inferFileType(filepath) {
259
+ if (filepath.endsWith(".json") || filepath.endsWith(".jsonc"))
260
+ return "json";
261
+ if (filepath.endsWith(".ts") || filepath.endsWith(".mts"))
262
+ return "ts";
263
+ if (filepath.endsWith(".js") || filepath.endsWith(".mjs"))
264
+ return "js";
265
+ return "md";
266
+ }
267
+ function getHeader(type) {
268
+ switch (type) {
269
+ case "md":
270
+ return GENERATED_HEADER_MD;
271
+ case "json":
272
+ return GENERATED_HEADER_JSON;
273
+ case "js":
274
+ case "ts":
275
+ return GENERATED_HEADER_JS;
276
+ default:
277
+ return null;
278
+ }
279
+ }
280
+
281
+ // src/utils/frontmatter.ts
282
+ import matter from "gray-matter";
283
+ function parseFrontmatter(source) {
284
+ const { data, content } = matter(source);
285
+ return {
286
+ data,
287
+ content: content.trim(),
288
+ raw: source
289
+ };
290
+ }
291
+ function serializeFrontmatter(data, content) {
292
+ const filtered = Object.fromEntries(Object.entries(data).filter(([, v]) => v !== undefined));
293
+ if (Object.keys(filtered).length === 0) {
294
+ return content;
295
+ }
296
+ return matter.stringify(content, filtered);
297
+ }
298
+
299
+ // src/features/rules.ts
300
+ import { readFileSync as readFileSync3 } from "fs";
301
+ import { basename } from "path";
302
+ function parseRules(rulesDir, packName) {
303
+ const files = listFiles(rulesDir, { extension: ".md" });
304
+ return files.map((filepath) => parseRuleFile(filepath, packName));
305
+ }
306
+ function parseRuleFile(filepath, packName) {
307
+ const raw = readFileSync3(filepath, "utf-8");
308
+ const { data, content } = parseFrontmatter(raw);
309
+ return {
310
+ name: basename(filepath, ".md"),
311
+ sourcePath: filepath,
312
+ packName,
313
+ meta: data,
314
+ content
315
+ };
316
+ }
317
+ function ruleMatchesTarget(rule, targetId) {
318
+ const { targets } = rule.meta;
319
+ if (!targets || targets === "*")
320
+ return true;
321
+ if (Array.isArray(targets) && targets.includes("*"))
322
+ return true;
323
+ return Array.isArray(targets) && targets.includes(targetId);
324
+ }
325
+ function getRootRules(rules) {
326
+ return rules.filter((r) => r.meta.root === true);
327
+ }
328
+ function getDetailRules(rules) {
329
+ return rules.filter((r) => r.meta.root !== true);
330
+ }
331
+
332
+ // src/features/commands.ts
333
+ import { readFileSync as readFileSync4 } from "fs";
334
+ import { basename as basename2 } from "path";
335
+ function parseCommands(commandsDir, packName) {
336
+ const files = listFiles(commandsDir, { extension: ".md" });
337
+ return files.map((filepath) => parseCommandFile(filepath, packName));
338
+ }
339
+ function parseCommandFile(filepath, packName) {
340
+ const raw = readFileSync4(filepath, "utf-8");
341
+ const { data, content } = parseFrontmatter(raw);
342
+ return {
343
+ name: basename2(filepath, ".md"),
344
+ sourcePath: filepath,
345
+ packName,
346
+ meta: data,
347
+ content
348
+ };
349
+ }
350
+ function commandMatchesTarget(cmd, targetId) {
351
+ const { targets } = cmd.meta;
352
+ if (!targets || targets === "*")
353
+ return true;
354
+ if (Array.isArray(targets) && targets.includes("*"))
355
+ return true;
356
+ return Array.isArray(targets) && targets.includes(targetId);
357
+ }
358
+
359
+ // src/features/agents.ts
360
+ import { readFileSync as readFileSync5 } from "fs";
361
+ import { basename as basename3 } from "path";
362
+ function parseAgents(agentsDir, packName) {
363
+ const files = listFiles(agentsDir, { extension: ".md" });
364
+ return files.map((filepath) => parseAgentFile(filepath, packName));
365
+ }
366
+ function parseAgentFile(filepath, packName) {
367
+ const raw = readFileSync5(filepath, "utf-8");
368
+ const { data, content } = parseFrontmatter(raw);
369
+ return {
370
+ name: data.name ?? basename3(filepath, ".md"),
371
+ sourcePath: filepath,
372
+ packName,
373
+ meta: data,
374
+ content
375
+ };
376
+ }
377
+ function agentMatchesTarget(agent, targetId) {
378
+ const { targets } = agent.meta;
379
+ if (!targets || targets === "*")
380
+ return true;
381
+ if (Array.isArray(targets) && targets.includes("*"))
382
+ return true;
383
+ return Array.isArray(targets) && targets.includes(targetId);
384
+ }
385
+
386
+ // src/features/skills.ts
387
+ import { readFileSync as readFileSync6, existsSync as existsSync3 } from "fs";
388
+ import { basename as basename4, join as join2 } from "path";
389
+ function parseSkills(skillsDir, packName) {
390
+ const dirs = listDirs(skillsDir);
391
+ const skills = [];
392
+ for (const dir of dirs) {
393
+ const skillMd = join2(dir, "SKILL.md");
394
+ if (existsSync3(skillMd)) {
395
+ skills.push(parseSkillFile(skillMd, dir, packName));
396
+ }
397
+ }
398
+ return skills;
399
+ }
400
+ function parseSkillFile(filepath, skillDir, packName) {
401
+ const raw = readFileSync6(filepath, "utf-8");
402
+ const { data, content } = parseFrontmatter(raw);
403
+ return {
404
+ name: data.name ?? basename4(skillDir),
405
+ sourcePath: filepath,
406
+ sourceDir: skillDir,
407
+ packName,
408
+ meta: data,
409
+ content
410
+ };
411
+ }
412
+ function skillMatchesTarget(skill, targetId) {
413
+ const { targets } = skill.meta;
414
+ if (!targets || targets === "*")
415
+ return true;
416
+ if (Array.isArray(targets) && targets.includes("*"))
417
+ return true;
418
+ return Array.isArray(targets) && targets.includes(targetId);
419
+ }
420
+
421
+ // src/features/hooks.ts
422
+ import { join as join3 } from "path";
423
+ var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
424
+ function parseHooks(packDir, packName) {
425
+ const hooksPath = join3(packDir, "hooks", "hooks.json");
426
+ const raw = readJsonOrNull(hooksPath);
427
+ if (!raw)
428
+ return null;
429
+ const shared = raw.hooks ?? {};
430
+ const targetOverrides = {};
431
+ for (const key of TARGET_OVERRIDE_KEYS) {
432
+ const override = raw[key];
433
+ if (override && typeof override === "object" && "hooks" in override && override.hooks) {
434
+ targetOverrides[key] = override.hooks;
435
+ }
436
+ }
437
+ return {
438
+ packName,
439
+ sourcePath: hooksPath,
440
+ version: raw.version,
441
+ shared,
442
+ targetOverrides
443
+ };
444
+ }
445
+ function resolveHooksForTarget(hooks, targetId) {
446
+ const merged = {};
447
+ for (const [event, entries] of Object.entries(hooks.shared)) {
448
+ merged[event] = [...entries];
449
+ }
450
+ const overrides = hooks.targetOverrides[targetId];
451
+ if (overrides) {
452
+ for (const [event, entries] of Object.entries(overrides)) {
453
+ merged[event] = [...merged[event] ?? [], ...entries];
454
+ }
455
+ }
456
+ return merged;
457
+ }
458
+
459
+ // src/features/plugins.ts
460
+ import { readFileSync as readFileSync7, existsSync as existsSync4 } from "fs";
461
+ import { basename as basename5, join as join4 } from "path";
462
+ function parsePlugins(packDir, packName) {
463
+ const pluginsDir = join4(packDir, "plugins");
464
+ if (!existsSync4(pluginsDir))
465
+ return [];
466
+ const tsFiles = listFiles(pluginsDir, { extension: ".ts" });
467
+ const jsFiles = listFiles(pluginsDir, { extension: ".js" });
468
+ const allFiles = [...tsFiles, ...jsFiles];
469
+ return allFiles.map((filepath) => parsePluginFile(filepath, packName));
470
+ }
471
+ function parsePluginFile(filepath, packName) {
472
+ const content = readFileSync7(filepath, "utf-8");
473
+ const ext = filepath.endsWith(".ts") ? "ts" : "js";
474
+ return {
475
+ name: basename5(filepath, `.${ext}`),
476
+ sourcePath: filepath,
477
+ packName,
478
+ content,
479
+ extension: ext
480
+ };
481
+ }
482
+
483
+ // src/features/mcp.ts
484
+ import { join as join5 } from "path";
485
+ function parseMcp(packDir, packName) {
486
+ const mcpPath = join5(packDir, "mcp.json");
487
+ const raw = readJsonOrNull(mcpPath);
488
+ if (!raw?.mcpServers)
489
+ return null;
490
+ return {
491
+ packName,
492
+ sourcePath: mcpPath,
493
+ servers: raw.mcpServers
494
+ };
495
+ }
496
+ function mergeMcpConfigs(configs) {
497
+ const servers = {};
498
+ const warnings = [];
499
+ for (const config of configs) {
500
+ for (const [name, entry] of Object.entries(config.servers)) {
501
+ if (name in servers) {
502
+ warnings.push(`MCP server "${name}" from pack "${config.packName}" skipped (already defined).`);
503
+ continue;
504
+ }
505
+ servers[name] = entry;
506
+ }
507
+ }
508
+ return { servers, warnings };
509
+ }
510
+
511
+ // src/features/ignore.ts
512
+ import { existsSync as existsSync5, readFileSync as readFileSync8 } from "fs";
513
+ import { join as join6 } from "path";
514
+ var IGNORE_FILES = ["ignore", ".aiignore"];
515
+ function parseIgnore(packDir, packName) {
516
+ for (const filename of IGNORE_FILES) {
517
+ const filepath = join6(packDir, filename);
518
+ if (existsSync5(filepath)) {
519
+ const raw = readFileSync8(filepath, "utf-8");
520
+ const patterns = parseIgnoreContent(raw);
521
+ return {
522
+ packName,
523
+ sourcePath: filepath,
524
+ patterns
525
+ };
526
+ }
527
+ }
528
+ return null;
529
+ }
530
+ function parseIgnoreContent(content) {
531
+ return content.split(`
532
+ `).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
533
+ }
534
+ function mergeIgnorePatterns(configs) {
535
+ const seen = new Set;
536
+ const result = [];
537
+ for (const config of configs) {
538
+ for (const pattern of config.patterns) {
539
+ if (!seen.has(pattern)) {
540
+ seen.add(pattern);
541
+ result.push(pattern);
542
+ }
543
+ }
544
+ }
545
+ return result;
546
+ }
547
+
548
+ // src/core/pack-loader.ts
549
+ init_config();
550
+ import { existsSync as existsSync6 } from "fs";
551
+ import { resolve as resolve3, isAbsolute } from "path";
552
+ class PackLoader {
553
+ projectRoot;
554
+ config;
555
+ constructor(projectRoot, config) {
556
+ this.projectRoot = projectRoot;
557
+ this.config = config;
558
+ }
559
+ loadAll() {
560
+ const warnings = [];
561
+ const packs = [];
562
+ const disabledSet = new Set(this.config.disabled);
563
+ for (const packRef of this.config.packs) {
564
+ const packDir = this.resolvePackPath(packRef);
565
+ if (!packDir) {
566
+ warnings.push(`Pack "${packRef}" could not be resolved. Skipping.`);
567
+ continue;
568
+ }
569
+ if (!existsSync6(packDir)) {
570
+ warnings.push(`Pack directory "${packDir}" does not exist. Skipping.`);
571
+ continue;
572
+ }
573
+ const manifest = loadPackManifest(packDir);
574
+ if (disabledSet.has(manifest.name) || disabledSet.has(packRef)) {
575
+ continue;
576
+ }
577
+ const loaded = this.loadPack(packDir, manifest);
578
+ packs.push(loaded);
579
+ }
580
+ return { packs, warnings };
581
+ }
582
+ loadPack(packDir, manifest) {
583
+ const name = manifest.name;
584
+ const rulesDir = resolve3(packDir, "rules");
585
+ const commandsDir = resolve3(packDir, "commands");
586
+ const agentsDir = resolve3(packDir, "agents");
587
+ const skillsDir = resolve3(packDir, "skills");
588
+ return {
589
+ manifest,
590
+ directory: packDir,
591
+ rules: existsSync6(rulesDir) ? parseRules(rulesDir, name) : [],
592
+ commands: existsSync6(commandsDir) ? parseCommands(commandsDir, name) : [],
593
+ agents: existsSync6(agentsDir) ? parseAgents(agentsDir, name) : [],
594
+ skills: existsSync6(skillsDir) ? parseSkills(skillsDir, name) : [],
595
+ hooks: parseHooks(packDir, name),
596
+ plugins: parsePlugins(packDir, name),
597
+ mcp: parseMcp(packDir, name),
598
+ ignore: parseIgnore(packDir, name)
599
+ };
600
+ }
601
+ loadForBaseDir(baseDir) {
602
+ const baseDirRoot = resolve3(this.projectRoot, baseDir);
603
+ const localConfigPath = resolve3(baseDirRoot, "agentpacks.jsonc");
604
+ if (!existsSync6(localConfigPath)) {
605
+ return { packs: [], warnings: [] };
606
+ }
607
+ const { loadWorkspaceConfig: loadWorkspaceConfig2 } = (init_config(), __toCommonJS(exports_config));
608
+ const localConfig = loadWorkspaceConfig2(baseDirRoot);
609
+ const loader = new PackLoader(baseDirRoot, localConfig);
610
+ return loader.loadAll();
611
+ }
612
+ resolveCuratedPack(packRef) {
613
+ const curatedDir = resolve3(this.projectRoot, ".agentpacks", ".curated");
614
+ let packName = packRef;
615
+ if (packName.startsWith("npm:"))
616
+ packName = packName.slice(4);
617
+ if (packName.startsWith("github:"))
618
+ packName = packName.slice(7);
619
+ if (packName.startsWith("@"))
620
+ packName = packName.slice(1);
621
+ if (packName.includes("/")) {
622
+ const parts = packName.split("/");
623
+ packName = packName.includes("@") ? parts.join("-") : parts[parts.length - 1] ?? packName;
624
+ }
625
+ packName = packName.split("@")[0].split(":")[0];
626
+ const resolved = resolve3(curatedDir, packName);
627
+ return existsSync6(resolved) ? resolved : null;
628
+ }
629
+ resolvePackPath(packRef) {
630
+ if (packRef.startsWith("./") || packRef.startsWith("../")) {
631
+ return resolve3(this.projectRoot, packRef);
632
+ }
633
+ if (isAbsolute(packRef)) {
634
+ return packRef;
635
+ }
636
+ if (packRef.startsWith("@") || packRef.startsWith("npm:") || !packRef.includes("/")) {
637
+ return this.resolveCuratedPack(packRef);
638
+ }
639
+ if (packRef.startsWith("github:") || packRef.includes("/")) {
640
+ return this.resolveCuratedPack(packRef);
641
+ }
642
+ return resolve3(this.projectRoot, packRef);
643
+ }
644
+ }
645
+
646
+ // src/core/feature-merger.ts
647
+ class FeatureMerger {
648
+ packs;
649
+ warnings = [];
650
+ constructor(packs) {
651
+ this.packs = packs;
652
+ }
653
+ merge() {
654
+ this.warnings = [];
655
+ const features = {
656
+ rules: this.mergeRules(),
657
+ commands: this.mergeByName("commands"),
658
+ agents: this.mergeByName("agents"),
659
+ skills: this.mergeByName("skills"),
660
+ hooks: this.mergeHooks(),
661
+ plugins: this.mergePlugins(),
662
+ mcpServers: this.mergeMcp(),
663
+ ignorePatterns: this.mergeIgnore()
664
+ };
665
+ return { features, warnings: this.warnings };
666
+ }
667
+ mergeRules() {
668
+ const seen = new Map;
669
+ const result = [];
670
+ for (const pack of this.packs) {
671
+ for (const rule of pack.rules) {
672
+ const existing = seen.get(rule.name);
673
+ if (existing) {
674
+ this.warnings.push(`Rule "${rule.name}" from pack "${rule.packName}" skipped (already defined by "${existing}").`);
675
+ continue;
676
+ }
677
+ seen.set(rule.name, rule.packName);
678
+ result.push(rule);
679
+ }
680
+ }
681
+ return result;
682
+ }
683
+ mergeByName(featureKey) {
684
+ const seen = new Map;
685
+ const result = [];
686
+ for (const pack of this.packs) {
687
+ const items = pack[featureKey];
688
+ for (const item of items) {
689
+ const existing = seen.get(item.name);
690
+ if (existing) {
691
+ this.warnings.push(`${featureKey.slice(0, -1)} "${item.name}" from pack "${item.packName}" skipped (already defined by "${existing}").`);
692
+ continue;
693
+ }
694
+ seen.set(item.name, item.packName);
695
+ result.push(item);
696
+ }
697
+ }
698
+ return result;
699
+ }
700
+ mergeHooks() {
701
+ return this.packs.map((p) => p.hooks).filter((h) => h !== null);
702
+ }
703
+ mergePlugins() {
704
+ const seen = new Map;
705
+ const result = [];
706
+ for (const pack of this.packs) {
707
+ for (const plugin of pack.plugins) {
708
+ const key = `${plugin.name}.${plugin.extension}`;
709
+ const existing = seen.get(key);
710
+ if (existing) {
711
+ this.warnings.push(`Plugin "${key}" from pack "${plugin.packName}" skipped (already defined by "${existing}").`);
712
+ continue;
713
+ }
714
+ seen.set(key, plugin.packName);
715
+ result.push(plugin);
716
+ }
717
+ }
718
+ return result;
719
+ }
720
+ mergeMcp() {
721
+ const servers = {};
722
+ for (const pack of this.packs) {
723
+ if (!pack.mcp)
724
+ continue;
725
+ for (const [name, entry] of Object.entries(pack.mcp.servers)) {
726
+ if (name in servers) {
727
+ this.warnings.push(`MCP server "${name}" from pack "${pack.manifest.name}" skipped (already defined).`);
728
+ continue;
729
+ }
730
+ servers[name] = entry;
731
+ }
732
+ }
733
+ return servers;
734
+ }
735
+ mergeIgnore() {
736
+ const seen = new Set;
737
+ const result = [];
738
+ for (const pack of this.packs) {
739
+ if (!pack.ignore)
740
+ continue;
741
+ for (const pattern of pack.ignore.patterns) {
742
+ if (!seen.has(pattern)) {
743
+ seen.add(pattern);
744
+ result.push(pattern);
745
+ }
746
+ }
747
+ }
748
+ return result;
749
+ }
750
+ }
751
+
752
+ // src/core/lockfile.ts
753
+ import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "fs";
754
+ import { resolve as resolve4 } from "path";
755
+ import { createHash } from "crypto";
756
+ var LOCKFILE_VERSION = 1;
757
+ var LOCKFILE_NAME = "agentpacks.lock";
758
+ function loadLockfile(projectRoot) {
759
+ const filepath = resolve4(projectRoot, LOCKFILE_NAME);
760
+ if (!existsSync7(filepath)) {
761
+ return { lockfileVersion: LOCKFILE_VERSION, sources: {} };
762
+ }
763
+ const raw = readFileSync9(filepath, "utf-8");
764
+ return JSON.parse(raw);
765
+ }
766
+ function saveLockfile(projectRoot, lockfile) {
767
+ const filepath = resolve4(projectRoot, LOCKFILE_NAME);
768
+ writeFileSync2(filepath, JSON.stringify(lockfile, null, 2) + `
769
+ `);
770
+ }
771
+ function getLockedSource(lockfile, sourceKey) {
772
+ return lockfile.sources[sourceKey];
773
+ }
774
+ function setLockedSource(lockfile, sourceKey, entry) {
775
+ lockfile.sources[sourceKey] = entry;
776
+ }
777
+ function computeIntegrity(content) {
778
+ const hash = createHash("sha256").update(content).digest("hex");
779
+ return `sha256-${hash}`;
780
+ }
781
+ function isLockfileFrozenValid(lockfile, sourceKeys) {
782
+ const missing = sourceKeys.filter((key) => !(key in lockfile.sources));
783
+ return { valid: missing.length === 0, missing };
784
+ }
785
+
786
+ // src/sources/local.ts
787
+ import { existsSync as existsSync8 } from "fs";
788
+ import { resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
789
+ function resolveLocalPack(packRef, projectRoot) {
790
+ let resolved;
791
+ if (isAbsolute2(packRef)) {
792
+ resolved = packRef;
793
+ } else {
794
+ resolved = resolve5(projectRoot, packRef);
795
+ }
796
+ if (!existsSync8(resolved))
797
+ return null;
798
+ return resolved;
799
+ }
800
+ function isLocalPackRef(packRef) {
801
+ return packRef.startsWith("./") || packRef.startsWith("../") || isAbsolute2(packRef);
802
+ }
803
+
804
+ // src/sources/git-ref.ts
805
+ function parseGitSourceRef(source) {
806
+ let s = source;
807
+ if (s.startsWith("github:")) {
808
+ s = s.slice(7);
809
+ }
810
+ let path = "";
811
+ const atIdx = s.indexOf("@");
812
+ const colonIdx = s.indexOf(":", atIdx > -1 ? atIdx : 0);
813
+ if (colonIdx > -1) {
814
+ path = s.slice(colonIdx + 1);
815
+ s = s.slice(0, colonIdx);
816
+ }
817
+ let ref = "main";
818
+ if (atIdx > -1) {
819
+ ref = s.slice(atIdx + 1);
820
+ s = s.slice(0, atIdx);
821
+ }
822
+ const parts = s.split("/");
823
+ if (parts.length < 2) {
824
+ throw new Error(`Invalid git source reference: "${source}". Expected owner/repo format.`);
825
+ }
826
+ return {
827
+ owner: parts[0],
828
+ repo: parts[1],
829
+ ref,
830
+ path: path || ""
831
+ };
832
+ }
833
+ function isGitPackRef(packRef) {
834
+ if (packRef.startsWith("github:"))
835
+ return true;
836
+ if (packRef.startsWith("./") || packRef.startsWith("../") || packRef.startsWith("/")) {
837
+ return false;
838
+ }
839
+ if (packRef.startsWith("@") || packRef.startsWith("npm:"))
840
+ return false;
841
+ const parts = packRef.split("/");
842
+ return parts.length === 2 && !packRef.includes("node_modules");
843
+ }
844
+ function gitSourceKey(parsed) {
845
+ return `${parsed.owner}/${parsed.repo}`;
846
+ }
847
+
848
+ // src/sources/npm-ref.ts
849
+ function parseNpmSourceRef(source) {
850
+ let s = source;
851
+ if (s.startsWith("npm:")) {
852
+ s = s.slice(4);
853
+ }
854
+ let path = "";
855
+ const pathColonIdx = findPathColon(s);
856
+ if (pathColonIdx > -1) {
857
+ path = s.slice(pathColonIdx + 1);
858
+ s = s.slice(0, pathColonIdx);
859
+ }
860
+ let version = "latest";
861
+ const versionAtIdx = findVersionAt(s);
862
+ if (versionAtIdx > -1) {
863
+ version = s.slice(versionAtIdx + 1);
864
+ s = s.slice(0, versionAtIdx);
865
+ }
866
+ if (!s) {
867
+ throw new Error(`Invalid npm source reference: "${source}". Expected package name.`);
868
+ }
869
+ return { packageName: s, version, path };
870
+ }
871
+ function findPathColon(s) {
872
+ const startAfter = s.startsWith("@") ? s.indexOf("/") + 1 : 0;
873
+ const vAt = findVersionAt(s);
874
+ const searchFrom = vAt > -1 ? vAt : startAfter;
875
+ return s.indexOf(":", searchFrom);
876
+ }
877
+ function findVersionAt(s) {
878
+ if (s.startsWith("@")) {
879
+ const slashIdx = s.indexOf("/");
880
+ if (slashIdx === -1)
881
+ return -1;
882
+ return s.indexOf("@", slashIdx + 1);
883
+ }
884
+ return s.indexOf("@");
885
+ }
886
+ function isNpmPackRef(packRef) {
887
+ if (packRef.startsWith("npm:"))
888
+ return true;
889
+ if (packRef.startsWith("@") && packRef.includes("/"))
890
+ return true;
891
+ return false;
892
+ }
893
+ function npmSourceKey(parsed) {
894
+ return `npm:${parsed.packageName}`;
895
+ }
896
+
897
+ // src/sources/git.ts
898
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
899
+ import { resolve as resolve6, join as join7 } from "path";
900
+ var GITHUB_API = "https://api.github.com";
901
+ function githubHeaders(token) {
902
+ const h = {
903
+ Accept: "application/vnd.github.v3+json",
904
+ "User-Agent": "agentpacks"
905
+ };
906
+ if (token)
907
+ h.Authorization = `token ${token}`;
908
+ return h;
909
+ }
910
+ async function resolveGitRef(parsed, token) {
911
+ const base = `${GITHUB_API}/repos/${parsed.owner}/${parsed.repo}/git/ref`;
912
+ const res = await fetch(`${base}/heads/${parsed.ref}`, {
913
+ headers: githubHeaders(token)
914
+ });
915
+ if (!res.ok) {
916
+ const tagRes = await fetch(`${base}/tags/${parsed.ref}`, {
917
+ headers: githubHeaders(token)
918
+ });
919
+ if (!tagRes.ok) {
920
+ throw new Error(`Could not resolve ref "${parsed.ref}" for ${parsed.owner}/${parsed.repo}: ${res.status}`);
921
+ }
922
+ const tagData = await tagRes.json();
923
+ return tagData.object.sha;
924
+ }
925
+ const data = await res.json();
926
+ return data.object.sha;
927
+ }
928
+ async function fetchGitDirectory(parsed, sha, subpath, token) {
929
+ const path = parsed.path ? `${parsed.path}/${subpath}` : subpath;
930
+ const url = `${GITHUB_API}/repos/${parsed.owner}/${parsed.repo}/contents/${path}?ref=${sha}`;
931
+ const res = await fetch(url, { headers: githubHeaders(token) });
932
+ if (!res.ok)
933
+ return [];
934
+ return await res.json();
935
+ }
936
+ async function fetchGitFile(downloadUrl, token) {
937
+ const headers = { "User-Agent": "agentpacks" };
938
+ if (token)
939
+ headers.Authorization = `token ${token}`;
940
+ const res = await fetch(downloadUrl, { headers });
941
+ if (!res.ok) {
942
+ throw new Error(`Failed to fetch ${downloadUrl}: ${res.status}`);
943
+ }
944
+ return res.text();
945
+ }
946
+ async function fetchAndWriteSubdir(parsed, sha, remotePath, localDir, installed, token) {
947
+ mkdirSync2(localDir, { recursive: true });
948
+ const entries = await fetchGitDirectory(parsed, sha, remotePath, token);
949
+ for (const entry of entries) {
950
+ if (entry.type === "file" && entry.download_url) {
951
+ const content = await fetchGitFile(entry.download_url, token);
952
+ const filepath = join7(localDir, entry.name);
953
+ writeFileSync3(filepath, content);
954
+ installed.push(filepath);
955
+ } else if (entry.type === "dir") {
956
+ await fetchAndWriteSubdir(parsed, sha, `${remotePath}/${entry.name}`, join7(localDir, entry.name), installed, token);
957
+ }
958
+ }
959
+ }
960
+ async function installGitSource(projectRoot, source, lockfile, options = {}) {
961
+ const parsed = parseGitSourceRef(source);
962
+ const sourceKey = gitSourceKey(parsed);
963
+ const installed = [];
964
+ const warnings = [];
965
+ let resolvedSha;
966
+ const locked = getLockedSource(lockfile, sourceKey);
967
+ if (options.frozen && !locked) {
968
+ throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
969
+ }
970
+ if (locked && !options.update) {
971
+ resolvedSha = locked.resolvedRef;
972
+ } else {
973
+ resolvedSha = await resolveGitRef(parsed, options.token);
974
+ }
975
+ const basePath = parsed.path || "packs";
976
+ const entries = await fetchGitDirectory(parsed, resolvedSha, basePath, options.token);
977
+ const curatedDir = resolve6(projectRoot, ".agentpacks", ".curated");
978
+ mkdirSync2(curatedDir, { recursive: true });
979
+ const newLockEntry = {
980
+ requestedRef: parsed.ref,
981
+ resolvedRef: resolvedSha,
982
+ resolvedAt: new Date().toISOString(),
983
+ skills: {},
984
+ packs: {}
985
+ };
986
+ const packDirs = entries.filter((e) => e.type === "dir");
987
+ for (const packEntry of packDirs) {
988
+ const packName = packEntry.name;
989
+ const packOutDir = resolve6(curatedDir, packName);
990
+ const packFiles = await fetchGitDirectory(parsed, resolvedSha, `${basePath}/${packName}`, options.token);
991
+ mkdirSync2(packOutDir, { recursive: true });
992
+ for (const file of packFiles) {
993
+ if (file.type === "file" && file.download_url) {
994
+ const content = await fetchGitFile(file.download_url, options.token);
995
+ writeFileSync3(join7(packOutDir, file.name), content);
996
+ installed.push(join7(packOutDir, file.name));
997
+ if (newLockEntry.packs) {
998
+ newLockEntry.packs[packName] = {
999
+ integrity: computeIntegrity(content)
1000
+ };
1001
+ }
1002
+ } else if (file.type === "dir") {
1003
+ await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${packName}/${file.name}`, join7(packOutDir, file.name), installed, options.token);
1004
+ }
1005
+ }
1006
+ }
1007
+ if (packDirs.length === 0) {
1008
+ const fileEntries = entries.filter((e) => e.type === "file");
1009
+ if (fileEntries.length > 0) {
1010
+ const packName = parsed.path.split("/").pop() ?? parsed.repo;
1011
+ const packOutDir = resolve6(curatedDir, packName);
1012
+ mkdirSync2(packOutDir, { recursive: true });
1013
+ for (const file of entries) {
1014
+ if (file.type === "file" && file.download_url) {
1015
+ const content = await fetchGitFile(file.download_url, options.token);
1016
+ writeFileSync3(join7(packOutDir, file.name), content);
1017
+ installed.push(join7(packOutDir, file.name));
1018
+ } else if (file.type === "dir") {
1019
+ await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${file.name}`, join7(packOutDir, file.name), installed, options.token);
1020
+ }
1021
+ }
1022
+ }
1023
+ }
1024
+ setLockedSource(lockfile, sourceKey, newLockEntry);
1025
+ return { installed, warnings };
1026
+ }
1027
+
1028
+ // src/sources/npm.ts
1029
+ import { mkdirSync as mkdirSync3, existsSync as existsSync9 } from "fs";
1030
+ import { resolve as resolve7, join as join8 } from "path";
1031
+ import { execSync } from "child_process";
1032
+ var NPM_REGISTRY = "https://registry.npmjs.org";
1033
+ async function resolveNpmVersion(parsed) {
1034
+ const url = `${NPM_REGISTRY}/${encodeURIComponent(parsed.packageName)}/${parsed.version}`;
1035
+ const res = await fetch(url, {
1036
+ headers: { Accept: "application/json" }
1037
+ });
1038
+ if (!res.ok) {
1039
+ throw new Error(`Could not resolve npm package "${parsed.packageName}@${parsed.version}": ${res.status}`);
1040
+ }
1041
+ const data = await res.json();
1042
+ return { version: data.version, tarball: data.dist.tarball };
1043
+ }
1044
+ async function installNpmSource(projectRoot, source, lockfile, options = {}) {
1045
+ const parsed = parseNpmSourceRef(source);
1046
+ const sourceKey = npmSourceKey(parsed);
1047
+ const installed = [];
1048
+ const warnings = [];
1049
+ const locked = getLockedSource(lockfile, sourceKey);
1050
+ if (options.frozen && !locked) {
1051
+ throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
1052
+ }
1053
+ let resolvedVersion;
1054
+ let tarballUrl;
1055
+ if (locked && !options.update) {
1056
+ resolvedVersion = locked.resolvedRef;
1057
+ tarballUrl = "";
1058
+ } else {
1059
+ const resolved = await resolveNpmVersion(parsed);
1060
+ resolvedVersion = resolved.version;
1061
+ tarballUrl = resolved.tarball;
1062
+ }
1063
+ const curatedDir = resolve7(projectRoot, ".agentpacks", ".curated");
1064
+ mkdirSync3(curatedDir, { recursive: true });
1065
+ const packDir = extractNpmPack(parsed, resolvedVersion, curatedDir, installed, warnings);
1066
+ const newEntry = {
1067
+ requestedRef: parsed.version,
1068
+ resolvedRef: resolvedVersion,
1069
+ resolvedAt: new Date().toISOString(),
1070
+ skills: {},
1071
+ packs: {}
1072
+ };
1073
+ setLockedSource(lockfile, sourceKey, newEntry);
1074
+ return { installed, warnings };
1075
+ }
1076
+ function extractNpmPack(parsed, version, curatedDir, installed, warnings) {
1077
+ const pkgSpec = `${parsed.packageName}@${version}`;
1078
+ const packName = parsed.packageName.replace(/^@/, "").replace(/\//g, "-");
1079
+ const packOutDir = resolve7(curatedDir, packName);
1080
+ try {
1081
+ const tmpDir = resolve7(curatedDir, ".tmp-npm");
1082
+ mkdirSync3(tmpDir, { recursive: true });
1083
+ execSync(`npm pack ${pkgSpec} --pack-destination "${tmpDir}"`, {
1084
+ stdio: "pipe",
1085
+ timeout: 30000
1086
+ });
1087
+ const tgzFiles = __require("fs").readdirSync(tmpDir).filter((f) => f.endsWith(".tgz"));
1088
+ if (tgzFiles.length === 0) {
1089
+ warnings.push(`No tarball found for ${pkgSpec}`);
1090
+ return packOutDir;
1091
+ }
1092
+ const tgzPath = join8(tmpDir, tgzFiles[0]);
1093
+ mkdirSync3(packOutDir, { recursive: true });
1094
+ execSync(`tar xzf "${tgzPath}" -C "${packOutDir}" --strip-components=1`, {
1095
+ stdio: "pipe",
1096
+ timeout: 15000
1097
+ });
1098
+ execSync(`rm -rf "${tmpDir}"`, { stdio: "pipe" });
1099
+ const subpath = parsed.path || "";
1100
+ const targetDir = subpath ? join8(packOutDir, subpath) : packOutDir;
1101
+ if (existsSync9(targetDir)) {
1102
+ collectFiles(targetDir, installed);
1103
+ }
1104
+ } catch (err) {
1105
+ warnings.push(`Failed to extract npm pack ${pkgSpec}: ${err instanceof Error ? err.message : String(err)}`);
1106
+ }
1107
+ return packOutDir;
1108
+ }
1109
+ function collectFiles(dir, out) {
1110
+ const fs = __require("fs");
1111
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
1112
+ for (const entry of entries) {
1113
+ const full = join8(dir, entry.name);
1114
+ if (entry.isDirectory()) {
1115
+ collectFiles(full, out);
1116
+ } else {
1117
+ out.push(full);
1118
+ }
1119
+ }
1120
+ }
1121
+
1122
+ // src/targets/base-target.ts
1123
+ class BaseTarget {
1124
+ supportsFeature(feature) {
1125
+ return this.supportedFeatures.includes(feature);
1126
+ }
1127
+ getEffectiveFeatures(enabledFeatures) {
1128
+ return enabledFeatures.filter((f) => this.supportsFeature(f));
1129
+ }
1130
+ createResult(filesWritten = [], filesDeleted = [], warnings = []) {
1131
+ return {
1132
+ targetId: this.id,
1133
+ filesWritten,
1134
+ filesDeleted,
1135
+ warnings
1136
+ };
1137
+ }
1138
+ }
1139
+
1140
+ // src/utils/markdown.ts
1141
+ function stripGeneratedHeader(content) {
1142
+ return content.replace(/^<!-- Generated by agentpacks.*-->\n/, "").replace(/^\/\/ Generated by agentpacks.*\n/, "");
1143
+ }
1144
+ function packNameToIdentifier(packName) {
1145
+ return packName.split(/[-_.]/).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
1146
+ }
1147
+ function extractFirstHeading(content) {
1148
+ const match = content.match(/^#{1,6}\s+(.+)$/m);
1149
+ return match?.[1]?.trim() ?? null;
1150
+ }
1151
+ function combineMarkdown(sections, separator = `
1152
+
1153
+ ---
1154
+
1155
+ `) {
1156
+ return sections.filter(Boolean).join(separator);
1157
+ }
1158
+ function wrapSection(heading, content, level = 2) {
1159
+ const prefix = "#".repeat(level);
1160
+ return `${prefix} ${heading}
1161
+
1162
+ ${content}`;
1163
+ }
1164
+
1165
+ // src/targets/opencode.ts
1166
+ import { resolve as resolve8, join as join9 } from "path";
1167
+ var TARGET_ID = "opencode";
1168
+
1169
+ class OpenCodeTarget extends BaseTarget {
1170
+ id = TARGET_ID;
1171
+ name = "OpenCode";
1172
+ supportedFeatures = [
1173
+ "rules",
1174
+ "commands",
1175
+ "agents",
1176
+ "skills",
1177
+ "hooks",
1178
+ "plugins",
1179
+ "mcp",
1180
+ "ignore"
1181
+ ];
1182
+ generate(options) {
1183
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1184
+ const root = resolve8(projectRoot, baseDir);
1185
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1186
+ const filesWritten = [];
1187
+ const filesDeleted = [];
1188
+ const warnings = [];
1189
+ const opencodeDir = resolve8(root, ".opencode");
1190
+ if (effective.includes("agents")) {
1191
+ const agentDir = resolve8(opencodeDir, "agent");
1192
+ if (deleteExisting) {
1193
+ removeIfExists(agentDir);
1194
+ filesDeleted.push(agentDir);
1195
+ }
1196
+ ensureDir(agentDir);
1197
+ const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID));
1198
+ for (const agent of agents) {
1199
+ const filepath = join9(agentDir, `${agent.name}.md`);
1200
+ writeGeneratedFile(filepath, agent.content);
1201
+ filesWritten.push(filepath);
1202
+ }
1203
+ }
1204
+ if (effective.includes("skills")) {
1205
+ const skillDir = resolve8(opencodeDir, "skill");
1206
+ if (deleteExisting) {
1207
+ removeIfExists(skillDir);
1208
+ filesDeleted.push(skillDir);
1209
+ }
1210
+ ensureDir(skillDir);
1211
+ const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID));
1212
+ for (const skill of skills) {
1213
+ const skillSubDir = join9(skillDir, skill.name);
1214
+ ensureDir(skillSubDir);
1215
+ const filepath = join9(skillSubDir, "SKILL.md");
1216
+ writeGeneratedFile(filepath, skill.content);
1217
+ filesWritten.push(filepath);
1218
+ }
1219
+ }
1220
+ if (effective.includes("commands")) {
1221
+ const cmdDir = resolve8(opencodeDir, "command");
1222
+ if (deleteExisting) {
1223
+ removeIfExists(cmdDir);
1224
+ filesDeleted.push(cmdDir);
1225
+ }
1226
+ ensureDir(cmdDir);
1227
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID));
1228
+ for (const cmd of commands) {
1229
+ const filepath = join9(cmdDir, `${cmd.name}.md`);
1230
+ writeGeneratedFile(filepath, cmd.content);
1231
+ filesWritten.push(filepath);
1232
+ }
1233
+ }
1234
+ if (effective.includes("hooks") || effective.includes("plugins")) {
1235
+ const pluginsDir = resolve8(opencodeDir, "plugins");
1236
+ ensureDir(pluginsDir);
1237
+ if (effective.includes("hooks")) {
1238
+ for (const hookSet of features.hooks) {
1239
+ const events = resolveHooksForTarget(hookSet, TARGET_ID);
1240
+ if (Object.keys(events).length > 0) {
1241
+ const filepath = join9(pluginsDir, `agentpacks-${hookSet.packName}.ts`);
1242
+ const content = generateOpenCodeHookPlugin(hookSet.packName, events);
1243
+ writeGeneratedFile(filepath, content, { type: "ts" });
1244
+ filesWritten.push(filepath);
1245
+ }
1246
+ }
1247
+ }
1248
+ if (effective.includes("plugins")) {
1249
+ for (const plugin of features.plugins) {
1250
+ const filepath = join9(pluginsDir, `agentpacks-${plugin.packName}-${plugin.name}.${plugin.extension}`);
1251
+ writeGeneratedFile(filepath, plugin.content, {
1252
+ type: plugin.extension
1253
+ });
1254
+ filesWritten.push(filepath);
1255
+ }
1256
+ }
1257
+ }
1258
+ if (effective.includes("mcp")) {
1259
+ const mcpEntries = Object.entries(features.mcpServers);
1260
+ if (mcpEntries.length > 0) {
1261
+ const opencodeConfig = buildOpenCodeMcp(features.mcpServers);
1262
+ const filepath = resolve8(root, "opencode.json");
1263
+ writeGeneratedJson(filepath, opencodeConfig, { header: false });
1264
+ filesWritten.push(filepath);
1265
+ }
1266
+ }
1267
+ if (effective.includes("rules")) {
1268
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID));
1269
+ const rootRules = getRootRules(rules);
1270
+ const detailRules = getDetailRules(rules);
1271
+ if (detailRules.length > 0) {
1272
+ const memoriesDir = resolve8(opencodeDir, "memories");
1273
+ if (deleteExisting) {
1274
+ removeIfExists(memoriesDir);
1275
+ filesDeleted.push(memoriesDir);
1276
+ }
1277
+ ensureDir(memoriesDir);
1278
+ for (const rule of detailRules) {
1279
+ const filepath = join9(memoriesDir, `${rule.name}.md`);
1280
+ writeGeneratedFile(filepath, rule.content);
1281
+ filesWritten.push(filepath);
1282
+ }
1283
+ }
1284
+ }
1285
+ return this.createResult(filesWritten, filesDeleted, warnings);
1286
+ }
1287
+ }
1288
+ function buildOpenCodeMcp(servers) {
1289
+ const mcp = {};
1290
+ for (const [name, entry] of Object.entries(servers)) {
1291
+ if (entry.url) {
1292
+ mcp[name] = {
1293
+ type: "remote",
1294
+ url: entry.url,
1295
+ enabled: true,
1296
+ ...entry.headers && Object.keys(entry.headers).length > 0 ? { headers: entry.headers } : {}
1297
+ };
1298
+ } else if (entry.command) {
1299
+ const cmd = entry.args ? [entry.command, ...entry.args] : [entry.command];
1300
+ mcp[name] = {
1301
+ type: "local",
1302
+ command: cmd,
1303
+ enabled: true,
1304
+ ...entry.env && Object.keys(entry.env).length > 0 ? { environment: entry.env } : {}
1305
+ };
1306
+ }
1307
+ }
1308
+ return {
1309
+ $schema: "https://opencode.ai/config.json",
1310
+ mcp
1311
+ };
1312
+ }
1313
+ function generateOpenCodeHookPlugin(packName, events) {
1314
+ const identifier = packNameToIdentifier(packName);
1315
+ const hookMap = mapHookEvents(events);
1316
+ const hookEntries = Object.entries(hookMap).map(([event, handlers]) => {
1317
+ const body = handlers.map((h) => {
1318
+ const matcherGuard = h.matcher ? `if (!/(?:${h.matcher})/.test(String(input?.tool ?? ""))) return;
1319
+ ` : "";
1320
+ return ` ${matcherGuard}await $\`${h.command}\`;`;
1321
+ }).join(`
1322
+ `);
1323
+ return ` "${event}": async (input, output) => {
1324
+ ${body}
1325
+ },`;
1326
+ }).join(`
1327
+ `);
1328
+ return `import type { Plugin } from "@opencode-ai/plugin";
1329
+
1330
+ export const ${identifier}Plugin: Plugin = async ({ project, client, $, directory, worktree }) => {
1331
+ return {
1332
+ ${hookEntries}
1333
+ };
1334
+ };
1335
+ `;
1336
+ }
1337
+ function mapHookEvents(events) {
1338
+ const mapped = {};
1339
+ const eventMapping = {
1340
+ sessionStart: "session.created",
1341
+ postToolUse: "tool.execute.after",
1342
+ preToolUse: "tool.execute.before",
1343
+ stop: "session.idle",
1344
+ afterFileEdit: "file.edited",
1345
+ afterShellExecution: "command.executed"
1346
+ };
1347
+ for (const [event, handlers] of Object.entries(events)) {
1348
+ const opencodeEvent = eventMapping[event] ?? event;
1349
+ if (!mapped[opencodeEvent]) {
1350
+ mapped[opencodeEvent] = [];
1351
+ }
1352
+ mapped[opencodeEvent].push(...handlers.filter((h) => h.command));
1353
+ }
1354
+ return mapped;
1355
+ }
1356
+
1357
+ // src/targets/cursor.ts
1358
+ import { resolve as resolve9, join as join10 } from "path";
1359
+ var TARGET_ID2 = "cursor";
1360
+
1361
+ class CursorTarget extends BaseTarget {
1362
+ id = TARGET_ID2;
1363
+ name = "Cursor";
1364
+ supportedFeatures = [
1365
+ "rules",
1366
+ "commands",
1367
+ "agents",
1368
+ "skills",
1369
+ "hooks",
1370
+ "mcp",
1371
+ "ignore"
1372
+ ];
1373
+ generate(options) {
1374
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1375
+ const root = resolve9(projectRoot, baseDir);
1376
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1377
+ const filesWritten = [];
1378
+ const filesDeleted = [];
1379
+ const warnings = [];
1380
+ const cursorDir = resolve9(root, ".cursor");
1381
+ if (effective.includes("rules")) {
1382
+ const rulesDir = resolve9(cursorDir, "rules");
1383
+ if (deleteExisting) {
1384
+ removeIfExists(rulesDir);
1385
+ filesDeleted.push(rulesDir);
1386
+ }
1387
+ ensureDir(rulesDir);
1388
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID2));
1389
+ for (const rule of rules) {
1390
+ const cursorMeta = rule.meta.cursor ?? {};
1391
+ const frontmatter = {
1392
+ description: cursorMeta.description ?? rule.meta.description ?? "",
1393
+ alwaysApply: cursorMeta.alwaysApply ?? rule.meta.root ?? false
1394
+ };
1395
+ const globs = cursorMeta.globs ?? rule.meta.globs;
1396
+ if (globs) {
1397
+ frontmatter.globs = globs;
1398
+ }
1399
+ const filepath = join10(rulesDir, `${rule.name}.mdc`);
1400
+ const content = serializeFrontmatter(frontmatter, rule.content);
1401
+ writeGeneratedFile(filepath, content);
1402
+ filesWritten.push(filepath);
1403
+ }
1404
+ }
1405
+ if (effective.includes("agents")) {
1406
+ const agentsDir = resolve9(cursorDir, "agents");
1407
+ if (deleteExisting) {
1408
+ removeIfExists(agentsDir);
1409
+ filesDeleted.push(agentsDir);
1410
+ }
1411
+ ensureDir(agentsDir);
1412
+ const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID2));
1413
+ for (const agent of agents) {
1414
+ const frontmatter = {
1415
+ name: agent.name,
1416
+ description: agent.meta.description ?? ""
1417
+ };
1418
+ const filepath = join10(agentsDir, `${agent.name}.md`);
1419
+ const content = serializeFrontmatter(frontmatter, agent.content);
1420
+ writeGeneratedFile(filepath, content);
1421
+ filesWritten.push(filepath);
1422
+ }
1423
+ }
1424
+ if (effective.includes("skills")) {
1425
+ const skillsDir = resolve9(cursorDir, "skills");
1426
+ if (deleteExisting) {
1427
+ removeIfExists(skillsDir);
1428
+ filesDeleted.push(skillsDir);
1429
+ }
1430
+ ensureDir(skillsDir);
1431
+ const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID2));
1432
+ for (const skill of skills) {
1433
+ const skillSubDir = join10(skillsDir, skill.name);
1434
+ ensureDir(skillSubDir);
1435
+ const frontmatter = {
1436
+ name: skill.name,
1437
+ description: skill.meta.description ?? ""
1438
+ };
1439
+ const filepath = join10(skillSubDir, "SKILL.md");
1440
+ const content = serializeFrontmatter(frontmatter, skill.content);
1441
+ writeGeneratedFile(filepath, content);
1442
+ filesWritten.push(filepath);
1443
+ }
1444
+ }
1445
+ if (effective.includes("commands")) {
1446
+ const commandsDir = resolve9(cursorDir, "commands");
1447
+ if (deleteExisting) {
1448
+ removeIfExists(commandsDir);
1449
+ filesDeleted.push(commandsDir);
1450
+ }
1451
+ ensureDir(commandsDir);
1452
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID2));
1453
+ for (const cmd of commands) {
1454
+ const filepath = join10(commandsDir, `${cmd.name}.md`);
1455
+ writeGeneratedFile(filepath, cmd.content);
1456
+ filesWritten.push(filepath);
1457
+ }
1458
+ }
1459
+ if (effective.includes("mcp")) {
1460
+ const mcpEntries = Object.entries(features.mcpServers);
1461
+ if (mcpEntries.length > 0) {
1462
+ const mcpConfig = buildCursorMcp(features.mcpServers);
1463
+ const filepath = resolve9(cursorDir, "mcp.json");
1464
+ writeGeneratedJson(filepath, mcpConfig, { header: false });
1465
+ filesWritten.push(filepath);
1466
+ }
1467
+ }
1468
+ if (effective.includes("ignore")) {
1469
+ if (features.ignorePatterns.length > 0) {
1470
+ const filepath = resolve9(root, ".cursorignore");
1471
+ const content = features.ignorePatterns.join(`
1472
+ `) + `
1473
+ `;
1474
+ writeGeneratedFile(filepath, content);
1475
+ filesWritten.push(filepath);
1476
+ }
1477
+ }
1478
+ return this.createResult(filesWritten, filesDeleted, warnings);
1479
+ }
1480
+ }
1481
+ function buildCursorMcp(servers) {
1482
+ const mcpServers = {};
1483
+ for (const [name, entry] of Object.entries(servers)) {
1484
+ if (entry.url) {
1485
+ mcpServers[name] = { url: entry.url };
1486
+ } else if (entry.command) {
1487
+ mcpServers[name] = {
1488
+ command: entry.command,
1489
+ ...entry.args ? { args: entry.args } : {},
1490
+ ...entry.env ? { env: entry.env } : {}
1491
+ };
1492
+ }
1493
+ }
1494
+ return { mcpServers };
1495
+ }
1496
+
1497
+ // src/targets/claude-code.ts
1498
+ import { resolve as resolve10, join as join11 } from "path";
1499
+ var TARGET_ID3 = "claudecode";
1500
+
1501
+ class ClaudeCodeTarget extends BaseTarget {
1502
+ id = TARGET_ID3;
1503
+ name = "Claude Code";
1504
+ supportedFeatures = [
1505
+ "rules",
1506
+ "commands",
1507
+ "agents",
1508
+ "skills",
1509
+ "hooks",
1510
+ "mcp",
1511
+ "ignore"
1512
+ ];
1513
+ generate(options) {
1514
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1515
+ const root = resolve10(projectRoot, baseDir);
1516
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1517
+ const filesWritten = [];
1518
+ const filesDeleted = [];
1519
+ const warnings = [];
1520
+ const claudeDir = resolve10(root, ".claude");
1521
+ if (effective.includes("rules")) {
1522
+ const rulesDir = resolve10(claudeDir, "rules");
1523
+ if (deleteExisting) {
1524
+ removeIfExists(rulesDir);
1525
+ filesDeleted.push(rulesDir);
1526
+ }
1527
+ ensureDir(rulesDir);
1528
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID3));
1529
+ const rootRules = getRootRules(rules);
1530
+ const detailRules = getDetailRules(rules);
1531
+ if (rootRules.length > 0) {
1532
+ const claudeMd = rootRules.map((r) => r.content).join(`
1533
+
1534
+ `);
1535
+ const filepath = resolve10(claudeDir, "CLAUDE.md");
1536
+ writeGeneratedFile(filepath, claudeMd);
1537
+ filesWritten.push(filepath);
1538
+ }
1539
+ for (const rule of detailRules) {
1540
+ const filepath = join11(rulesDir, `${rule.name}.md`);
1541
+ writeGeneratedFile(filepath, rule.content);
1542
+ filesWritten.push(filepath);
1543
+ }
1544
+ }
1545
+ if (effective.includes("agents")) {
1546
+ const agentsDir = resolve10(claudeDir, "agents");
1547
+ if (deleteExisting) {
1548
+ removeIfExists(agentsDir);
1549
+ filesDeleted.push(agentsDir);
1550
+ }
1551
+ ensureDir(agentsDir);
1552
+ const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID3));
1553
+ for (const agent of agents) {
1554
+ const filepath = join11(agentsDir, `${agent.name}.md`);
1555
+ writeGeneratedFile(filepath, agent.content);
1556
+ filesWritten.push(filepath);
1557
+ }
1558
+ }
1559
+ if (effective.includes("skills")) {
1560
+ const skillsDir = resolve10(claudeDir, "skills");
1561
+ if (deleteExisting) {
1562
+ removeIfExists(skillsDir);
1563
+ filesDeleted.push(skillsDir);
1564
+ }
1565
+ ensureDir(skillsDir);
1566
+ const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID3));
1567
+ for (const skill of skills) {
1568
+ const skillSubDir = join11(skillsDir, skill.name);
1569
+ ensureDir(skillSubDir);
1570
+ const filepath = join11(skillSubDir, "SKILL.md");
1571
+ writeGeneratedFile(filepath, skill.content);
1572
+ filesWritten.push(filepath);
1573
+ }
1574
+ }
1575
+ if (effective.includes("commands")) {
1576
+ const commandsDir = resolve10(claudeDir, "commands");
1577
+ if (deleteExisting) {
1578
+ removeIfExists(commandsDir);
1579
+ filesDeleted.push(commandsDir);
1580
+ }
1581
+ ensureDir(commandsDir);
1582
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID3));
1583
+ for (const cmd of commands) {
1584
+ const filepath = join11(commandsDir, `${cmd.name}.md`);
1585
+ writeGeneratedFile(filepath, cmd.content);
1586
+ filesWritten.push(filepath);
1587
+ }
1588
+ }
1589
+ if (effective.includes("hooks") || effective.includes("mcp") || effective.includes("ignore")) {
1590
+ const settings = buildClaudeSettings(options, effective);
1591
+ if (Object.keys(settings).length > 0) {
1592
+ const filepath = resolve10(claudeDir, "settings.json");
1593
+ const existing = readJsonOrNull(filepath) ?? {};
1594
+ const merged = { ...existing, ...settings };
1595
+ writeGeneratedJson(filepath, merged, { header: false });
1596
+ filesWritten.push(filepath);
1597
+ }
1598
+ }
1599
+ return this.createResult(filesWritten, filesDeleted, warnings);
1600
+ }
1601
+ }
1602
+ function buildClaudeSettings(options, effective) {
1603
+ const settings = {};
1604
+ if (effective.includes("hooks")) {
1605
+ const allHookEntries = {};
1606
+ for (const hookSet of options.features.hooks) {
1607
+ const events = resolveHooksForTarget(hookSet, TARGET_ID3);
1608
+ for (const [event, entries] of Object.entries(events)) {
1609
+ const pascalEvent = toPascalCase(event);
1610
+ if (!allHookEntries[pascalEvent]) {
1611
+ allHookEntries[pascalEvent] = [];
1612
+ }
1613
+ allHookEntries[pascalEvent].push(...entries.map((e) => ({
1614
+ type: e.type ?? "command",
1615
+ ...e.matcher ? { matcher: e.matcher } : {},
1616
+ command: e.command
1617
+ })));
1618
+ }
1619
+ }
1620
+ if (Object.keys(allHookEntries).length > 0) {
1621
+ settings.hooks = allHookEntries;
1622
+ }
1623
+ }
1624
+ if (effective.includes("mcp")) {
1625
+ const mcpEntries = Object.entries(options.features.mcpServers);
1626
+ if (mcpEntries.length > 0) {
1627
+ const mcpServers = {};
1628
+ for (const [name, entry] of mcpEntries) {
1629
+ if (entry.url) {
1630
+ mcpServers[name] = { url: entry.url };
1631
+ } else if (entry.command) {
1632
+ mcpServers[name] = {
1633
+ command: entry.command,
1634
+ ...entry.args ? { args: entry.args } : {},
1635
+ ...entry.env ? { env: entry.env } : {}
1636
+ };
1637
+ }
1638
+ }
1639
+ settings.mcpServers = mcpServers;
1640
+ }
1641
+ }
1642
+ return settings;
1643
+ }
1644
+ function toPascalCase(str) {
1645
+ return str.charAt(0).toUpperCase() + str.slice(1);
1646
+ }
1647
+
1648
+ // src/targets/codex-cli.ts
1649
+ import { resolve as resolve11, join as join12 } from "path";
1650
+ var TARGET_ID4 = "codexcli";
1651
+
1652
+ class CodexCliTarget extends BaseTarget {
1653
+ id = TARGET_ID4;
1654
+ name = "Codex CLI";
1655
+ supportedFeatures = ["rules", "skills", "mcp", "hooks"];
1656
+ generate(options) {
1657
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1658
+ const root = resolve11(projectRoot, baseDir);
1659
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1660
+ const filesWritten = [];
1661
+ const filesDeleted = [];
1662
+ const warnings = [];
1663
+ const codexDir = resolve11(root, ".codex");
1664
+ if (effective.includes("rules")) {
1665
+ const memoriesDir = resolve11(codexDir, "memories");
1666
+ if (deleteExisting) {
1667
+ removeIfExists(memoriesDir);
1668
+ filesDeleted.push(memoriesDir);
1669
+ }
1670
+ ensureDir(memoriesDir);
1671
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID4));
1672
+ for (const rule of rules) {
1673
+ const filepath = join12(memoriesDir, `${rule.name}.md`);
1674
+ writeGeneratedFile(filepath, rule.content);
1675
+ filesWritten.push(filepath);
1676
+ }
1677
+ }
1678
+ if (effective.includes("skills")) {
1679
+ const skillsDir = resolve11(codexDir, "skills");
1680
+ if (deleteExisting) {
1681
+ removeIfExists(skillsDir);
1682
+ filesDeleted.push(skillsDir);
1683
+ }
1684
+ ensureDir(skillsDir);
1685
+ const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID4));
1686
+ for (const skill of skills) {
1687
+ const skillSubDir = join12(skillsDir, skill.name);
1688
+ ensureDir(skillSubDir);
1689
+ const filepath = join12(skillSubDir, "SKILL.md");
1690
+ writeGeneratedFile(filepath, skill.content);
1691
+ filesWritten.push(filepath);
1692
+ }
1693
+ }
1694
+ return this.createResult(filesWritten, filesDeleted, warnings);
1695
+ }
1696
+ }
1697
+
1698
+ // src/targets/gemini-cli.ts
1699
+ import { resolve as resolve12, join as join13 } from "path";
1700
+ var TARGET_ID5 = "geminicli";
1701
+
1702
+ class GeminiCliTarget extends BaseTarget {
1703
+ id = TARGET_ID5;
1704
+ name = "Gemini CLI";
1705
+ supportedFeatures = [
1706
+ "rules",
1707
+ "commands",
1708
+ "mcp",
1709
+ "ignore",
1710
+ "skills",
1711
+ "hooks"
1712
+ ];
1713
+ generate(options) {
1714
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1715
+ const root = resolve12(projectRoot, baseDir);
1716
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1717
+ const filesWritten = [];
1718
+ const filesDeleted = [];
1719
+ const warnings = [];
1720
+ const geminiDir = resolve12(root, ".gemini");
1721
+ if (effective.includes("rules")) {
1722
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID5));
1723
+ const rootRules = getRootRules(rules);
1724
+ const detailRules = getDetailRules(rules);
1725
+ if (rootRules.length > 0) {
1726
+ const geminiMd = rootRules.map((r) => r.content).join(`
1727
+
1728
+ `);
1729
+ const filepath = resolve12(root, "GEMINI.md");
1730
+ writeGeneratedFile(filepath, geminiMd);
1731
+ filesWritten.push(filepath);
1732
+ }
1733
+ if (detailRules.length > 0) {
1734
+ const memoriesDir = resolve12(geminiDir, "memories");
1735
+ if (deleteExisting) {
1736
+ removeIfExists(memoriesDir);
1737
+ filesDeleted.push(memoriesDir);
1738
+ }
1739
+ ensureDir(memoriesDir);
1740
+ for (const rule of detailRules) {
1741
+ const filepath = join13(memoriesDir, `${rule.name}.md`);
1742
+ writeGeneratedFile(filepath, rule.content);
1743
+ filesWritten.push(filepath);
1744
+ }
1745
+ }
1746
+ }
1747
+ if (effective.includes("commands")) {
1748
+ const commandsDir = resolve12(geminiDir, "commands");
1749
+ if (deleteExisting) {
1750
+ removeIfExists(commandsDir);
1751
+ filesDeleted.push(commandsDir);
1752
+ }
1753
+ ensureDir(commandsDir);
1754
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID5));
1755
+ for (const cmd of commands) {
1756
+ const toml = buildGeminiCommand(cmd.name, cmd.meta.description ?? "", cmd.content);
1757
+ const filepath = join13(commandsDir, `${cmd.name}.toml`);
1758
+ writeGeneratedFile(filepath, toml, { type: "md" });
1759
+ filesWritten.push(filepath);
1760
+ }
1761
+ }
1762
+ if (effective.includes("mcp")) {
1763
+ const mcpEntries = Object.entries(features.mcpServers);
1764
+ if (mcpEntries.length > 0) {
1765
+ const settings = buildGeminiSettings(features.mcpServers);
1766
+ const filepath = resolve12(geminiDir, "settings.json");
1767
+ writeGeneratedJson(filepath, settings, { header: false });
1768
+ filesWritten.push(filepath);
1769
+ }
1770
+ }
1771
+ if (effective.includes("ignore")) {
1772
+ if (features.ignorePatterns.length > 0) {
1773
+ const filepath = resolve12(root, ".geminiignore");
1774
+ const content = features.ignorePatterns.join(`
1775
+ `) + `
1776
+ `;
1777
+ writeGeneratedFile(filepath, content);
1778
+ filesWritten.push(filepath);
1779
+ }
1780
+ }
1781
+ return this.createResult(filesWritten, filesDeleted, warnings);
1782
+ }
1783
+ }
1784
+ function buildGeminiCommand(name, description, content) {
1785
+ return `[command]
1786
+ name = "${name}"
1787
+ description = "${description}"
1788
+
1789
+ [prompt]
1790
+ content = """
1791
+ ${content}
1792
+ """
1793
+ `;
1794
+ }
1795
+ function buildGeminiSettings(servers) {
1796
+ const mcpServers = {};
1797
+ for (const [name, entry] of Object.entries(servers)) {
1798
+ if (entry.command) {
1799
+ mcpServers[name] = {
1800
+ command: entry.command,
1801
+ ...entry.args ? { args: entry.args } : {},
1802
+ ...entry.env ? { env: entry.env } : {}
1803
+ };
1804
+ } else if (entry.url) {
1805
+ mcpServers[name] = { url: entry.url };
1806
+ }
1807
+ }
1808
+ return { mcpServers };
1809
+ }
1810
+
1811
+ // src/targets/copilot.ts
1812
+ import { resolve as resolve13, join as join14 } from "path";
1813
+ var TARGET_ID6 = "copilot";
1814
+
1815
+ class CopilotTarget extends BaseTarget {
1816
+ id = TARGET_ID6;
1817
+ name = "GitHub Copilot";
1818
+ supportedFeatures = [
1819
+ "rules",
1820
+ "commands",
1821
+ "agents",
1822
+ "skills",
1823
+ "mcp",
1824
+ "ignore"
1825
+ ];
1826
+ generate(options) {
1827
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1828
+ const root = resolve13(projectRoot, baseDir);
1829
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1830
+ const filesWritten = [];
1831
+ const filesDeleted = [];
1832
+ const warnings = [];
1833
+ const githubDir = resolve13(root, ".github");
1834
+ if (effective.includes("rules")) {
1835
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID6));
1836
+ if (rules.length > 0) {
1837
+ const combinedContent = rules.map((r) => r.content).join(`
1838
+
1839
+ ---
1840
+
1841
+ `);
1842
+ const filepath = resolve13(githubDir, "copilot-instructions.md");
1843
+ ensureDir(githubDir);
1844
+ writeGeneratedFile(filepath, combinedContent);
1845
+ filesWritten.push(filepath);
1846
+ }
1847
+ }
1848
+ if (effective.includes("agents")) {
1849
+ const copilotDir = resolve13(githubDir, "copilot");
1850
+ const agentsDir = resolve13(copilotDir, "agents");
1851
+ if (deleteExisting) {
1852
+ removeIfExists(agentsDir);
1853
+ filesDeleted.push(agentsDir);
1854
+ }
1855
+ ensureDir(agentsDir);
1856
+ const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID6));
1857
+ for (const agent of agents) {
1858
+ const filepath = join14(agentsDir, `${agent.name}.md`);
1859
+ writeGeneratedFile(filepath, agent.content);
1860
+ filesWritten.push(filepath);
1861
+ }
1862
+ }
1863
+ if (effective.includes("skills")) {
1864
+ const copilotDir = resolve13(githubDir, "copilot");
1865
+ const skillsDir = resolve13(copilotDir, "skills");
1866
+ if (deleteExisting) {
1867
+ removeIfExists(skillsDir);
1868
+ filesDeleted.push(skillsDir);
1869
+ }
1870
+ ensureDir(skillsDir);
1871
+ const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID6));
1872
+ for (const skill of skills) {
1873
+ const skillSubDir = join14(skillsDir, skill.name);
1874
+ ensureDir(skillSubDir);
1875
+ const filepath = join14(skillSubDir, "SKILL.md");
1876
+ writeGeneratedFile(filepath, skill.content);
1877
+ filesWritten.push(filepath);
1878
+ }
1879
+ }
1880
+ if (effective.includes("commands")) {
1881
+ const copilotDir = resolve13(githubDir, "copilot");
1882
+ const commandsDir = resolve13(copilotDir, "commands");
1883
+ if (deleteExisting) {
1884
+ removeIfExists(commandsDir);
1885
+ filesDeleted.push(commandsDir);
1886
+ }
1887
+ ensureDir(commandsDir);
1888
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID6));
1889
+ for (const cmd of commands) {
1890
+ const filepath = join14(commandsDir, `${cmd.name}.md`);
1891
+ writeGeneratedFile(filepath, cmd.content);
1892
+ filesWritten.push(filepath);
1893
+ }
1894
+ }
1895
+ if (effective.includes("ignore")) {}
1896
+ return this.createResult(filesWritten, filesDeleted, warnings);
1897
+ }
1898
+ }
1899
+
1900
+ // src/targets/agents-md.ts
1901
+ import { resolve as resolve14 } from "path";
1902
+ class AgentsMdTarget extends BaseTarget {
1903
+ id = "agentsmd";
1904
+ name = "AGENTS.md";
1905
+ supportedFeatures = ["rules"];
1906
+ generate(options) {
1907
+ const { projectRoot, baseDir, features } = options;
1908
+ const root = resolve14(projectRoot, baseDir);
1909
+ const filesWritten = [];
1910
+ const warnings = [];
1911
+ const rootRules = getRootRules(features.rules);
1912
+ if (rootRules.length === 0) {
1913
+ warnings.push("No root rules found. AGENTS.md will not be generated.");
1914
+ return this.createResult(filesWritten, [], warnings);
1915
+ }
1916
+ const sections = rootRules.map((r) => r.content);
1917
+ const content = sections.join(`
1918
+
1919
+ `);
1920
+ const filepath = resolve14(root, "AGENTS.md");
1921
+ writeGeneratedFile(filepath, content);
1922
+ filesWritten.push(filepath);
1923
+ return this.createResult(filesWritten, [], warnings);
1924
+ }
1925
+ }
1926
+
1927
+ // src/targets/generic-md-target.ts
1928
+ import { resolve as resolve15, join as join15 } from "path";
1929
+ function createGenericMdTarget(config) {
1930
+ return new GenericMdTarget(config);
1931
+ }
1932
+
1933
+ class GenericMdTarget extends BaseTarget {
1934
+ id;
1935
+ name;
1936
+ supportedFeatures;
1937
+ config;
1938
+ constructor(config) {
1939
+ super();
1940
+ this.id = config.id;
1941
+ this.name = config.name;
1942
+ this.supportedFeatures = config.supportedFeatures;
1943
+ this.config = config;
1944
+ }
1945
+ generate(options) {
1946
+ const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
1947
+ const root = resolve15(projectRoot, baseDir);
1948
+ const effective = this.getEffectiveFeatures(enabledFeatures);
1949
+ const filesWritten = [];
1950
+ const filesDeleted = [];
1951
+ const warnings = [];
1952
+ const configDir = resolve15(root, this.config.configDir);
1953
+ const rulesSubDir = this.config.rulesDir ?? "rules";
1954
+ const ext = this.config.ruleExtension ?? ".md";
1955
+ if (effective.includes("rules")) {
1956
+ const rulesDir = resolve15(configDir, rulesSubDir);
1957
+ if (deleteExisting) {
1958
+ removeIfExists(rulesDir);
1959
+ filesDeleted.push(rulesDir);
1960
+ }
1961
+ ensureDir(rulesDir);
1962
+ const rules = features.rules.filter((r) => ruleMatchesTarget(r, this.id));
1963
+ for (const rule of rules) {
1964
+ const filepath = join15(rulesDir, `${rule.name}${ext}`);
1965
+ writeGeneratedFile(filepath, rule.content);
1966
+ filesWritten.push(filepath);
1967
+ }
1968
+ }
1969
+ if (effective.includes("commands")) {
1970
+ const commandsDir = resolve15(configDir, "commands");
1971
+ if (deleteExisting) {
1972
+ removeIfExists(commandsDir);
1973
+ filesDeleted.push(commandsDir);
1974
+ }
1975
+ ensureDir(commandsDir);
1976
+ const commands = features.commands.filter((c) => commandMatchesTarget(c, this.id));
1977
+ for (const cmd of commands) {
1978
+ const filepath = join15(commandsDir, `${cmd.name}.md`);
1979
+ writeGeneratedFile(filepath, cmd.content);
1980
+ filesWritten.push(filepath);
1981
+ }
1982
+ }
1983
+ if (effective.includes("mcp")) {
1984
+ const mcpEntries = Object.entries(features.mcpServers);
1985
+ if (mcpEntries.length > 0) {
1986
+ const mcpDir = this.config.mcpInConfigDir ? configDir : root;
1987
+ const filepath = resolve15(mcpDir, "mcp.json");
1988
+ writeGeneratedJson(filepath, { mcpServers: features.mcpServers }, {
1989
+ header: false
1990
+ });
1991
+ filesWritten.push(filepath);
1992
+ }
1993
+ }
1994
+ if (effective.includes("ignore") && this.config.ignoreFile) {
1995
+ if (features.ignorePatterns.length > 0) {
1996
+ const filepath = resolve15(root, this.config.ignoreFile);
1997
+ writeGeneratedFile(filepath, features.ignorePatterns.join(`
1998
+ `) + `
1999
+ `);
2000
+ filesWritten.push(filepath);
2001
+ }
2002
+ }
2003
+ return this.createResult(filesWritten, filesDeleted, warnings);
2004
+ }
2005
+ }
2006
+
2007
+ // src/targets/additional-targets.ts
2008
+ var ClineTarget = createGenericMdTarget({
2009
+ id: "cline",
2010
+ name: "Cline",
2011
+ configDir: ".cline",
2012
+ supportedFeatures: ["rules", "commands", "mcp", "ignore"],
2013
+ ignoreFile: ".clineignore",
2014
+ mcpInConfigDir: true
2015
+ });
2016
+ var KiloTarget = createGenericMdTarget({
2017
+ id: "kilo",
2018
+ name: "Kilo Code",
2019
+ configDir: ".kilo",
2020
+ supportedFeatures: ["rules", "commands", "mcp", "ignore"],
2021
+ ignoreFile: ".kiloignore",
2022
+ mcpInConfigDir: true
2023
+ });
2024
+ var RooTarget = createGenericMdTarget({
2025
+ id: "roo",
2026
+ name: "Roo Code",
2027
+ configDir: ".roo",
2028
+ supportedFeatures: ["rules", "commands", "mcp", "ignore"],
2029
+ ignoreFile: ".rooignore",
2030
+ mcpInConfigDir: true
2031
+ });
2032
+ var QwenCodeTarget = createGenericMdTarget({
2033
+ id: "qwencode",
2034
+ name: "Qwen Code",
2035
+ configDir: ".qwencode",
2036
+ supportedFeatures: ["rules", "mcp", "ignore"],
2037
+ ignoreFile: ".qwencodeignore",
2038
+ mcpInConfigDir: true
2039
+ });
2040
+ var KiroTarget = createGenericMdTarget({
2041
+ id: "kiro",
2042
+ name: "Kiro",
2043
+ configDir: ".kiro",
2044
+ supportedFeatures: ["rules", "mcp"],
2045
+ mcpInConfigDir: true
2046
+ });
2047
+ var FactoryDroidTarget = createGenericMdTarget({
2048
+ id: "factorydroid",
2049
+ name: "Factory Droid",
2050
+ configDir: ".factorydroid",
2051
+ supportedFeatures: ["rules", "mcp"],
2052
+ mcpInConfigDir: true
2053
+ });
2054
+ var AntiGravityTarget = createGenericMdTarget({
2055
+ id: "antigravity",
2056
+ name: "AntiGravity",
2057
+ configDir: ".antigravity",
2058
+ supportedFeatures: ["rules", "mcp"],
2059
+ mcpInConfigDir: true
2060
+ });
2061
+ var JunieTarget = createGenericMdTarget({
2062
+ id: "junie",
2063
+ name: "Junie",
2064
+ configDir: ".junie",
2065
+ supportedFeatures: ["rules", "mcp"],
2066
+ mcpInConfigDir: true
2067
+ });
2068
+ var AugmentCodeTarget = createGenericMdTarget({
2069
+ id: "augmentcode",
2070
+ name: "Augment Code",
2071
+ configDir: ".augmentcode",
2072
+ supportedFeatures: ["rules", "mcp"],
2073
+ mcpInConfigDir: true
2074
+ });
2075
+ var WindsurfTarget = createGenericMdTarget({
2076
+ id: "windsurf",
2077
+ name: "Windsurf",
2078
+ configDir: ".windsurf",
2079
+ supportedFeatures: ["rules", "mcp", "ignore"],
2080
+ ignoreFile: ".windsurfignore",
2081
+ mcpInConfigDir: true
2082
+ });
2083
+ var WarpTarget = createGenericMdTarget({
2084
+ id: "warp",
2085
+ name: "Warp",
2086
+ configDir: ".warp",
2087
+ supportedFeatures: ["rules"]
2088
+ });
2089
+ var ReplitTarget = createGenericMdTarget({
2090
+ id: "replit",
2091
+ name: "Replit Agent",
2092
+ configDir: ".replit",
2093
+ supportedFeatures: ["rules", "mcp"],
2094
+ mcpInConfigDir: true
2095
+ });
2096
+ var ZedTarget = createGenericMdTarget({
2097
+ id: "zed",
2098
+ name: "Zed",
2099
+ configDir: ".zed",
2100
+ supportedFeatures: ["rules", "mcp"],
2101
+ mcpInConfigDir: true
2102
+ });
2103
+
2104
+ // src/targets/registry.ts
2105
+ var TARGETS = [
2106
+ new OpenCodeTarget,
2107
+ new CursorTarget,
2108
+ new ClaudeCodeTarget,
2109
+ new CodexCliTarget,
2110
+ new GeminiCliTarget,
2111
+ new CopilotTarget,
2112
+ new AgentsMdTarget,
2113
+ ClineTarget,
2114
+ KiloTarget,
2115
+ RooTarget,
2116
+ QwenCodeTarget,
2117
+ KiroTarget,
2118
+ FactoryDroidTarget,
2119
+ AntiGravityTarget,
2120
+ JunieTarget,
2121
+ AugmentCodeTarget,
2122
+ WindsurfTarget,
2123
+ WarpTarget,
2124
+ ReplitTarget,
2125
+ ZedTarget
2126
+ ];
2127
+ var targetMap = new Map(TARGETS.map((t) => [t.id, t]));
2128
+ function getTarget(id) {
2129
+ return targetMap.get(id);
2130
+ }
2131
+ function getAllTargets() {
2132
+ return [...TARGETS];
2133
+ }
2134
+ function getTargets(ids) {
2135
+ return ids.map((id) => targetMap.get(id)).filter((t) => t !== undefined);
2136
+ }
2137
+ function listTargetIds() {
2138
+ return TARGETS.map((t) => t.id);
2139
+ }
2140
+
2141
+ // src/exporters/cursor-plugin.ts
2142
+ import { resolve as resolve16, join as join16 } from "path";
2143
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
2144
+ function exportCursorPlugin(pack, outputDir) {
2145
+ const filesWritten = [];
2146
+ const pluginDir = resolve16(outputDir, pack.manifest.name);
2147
+ mkdirSync4(pluginDir, { recursive: true });
2148
+ const manifest = {
2149
+ name: pack.manifest.name,
2150
+ version: pack.manifest.version,
2151
+ description: pack.manifest.description
2152
+ };
2153
+ if (pack.manifest.author) {
2154
+ manifest.author = typeof pack.manifest.author === "string" ? pack.manifest.author : pack.manifest.author.name;
2155
+ }
2156
+ if (pack.manifest.tags.length > 0) {
2157
+ manifest.tags = pack.manifest.tags;
2158
+ }
2159
+ if (pack.rules.length > 0) {
2160
+ const rulesDir = join16(pluginDir, "rules");
2161
+ ensureDir(rulesDir);
2162
+ manifest.rules = [];
2163
+ for (const rule of pack.rules) {
2164
+ const cursorMeta = rule.meta.cursor ?? {};
2165
+ const fm = {
2166
+ description: cursorMeta.description ?? rule.meta.description ?? "",
2167
+ alwaysApply: cursorMeta.alwaysApply ?? rule.meta.root ?? false
2168
+ };
2169
+ const globs = cursorMeta.globs ?? rule.meta.globs;
2170
+ if (globs)
2171
+ fm.globs = globs;
2172
+ const filename = `${rule.name}.mdc`;
2173
+ const filepath = join16(rulesDir, filename);
2174
+ writeFileSync5(filepath, serializeFrontmatter(fm, rule.content));
2175
+ filesWritten.push(filepath);
2176
+ manifest.rules.push(filename);
2177
+ }
2178
+ }
2179
+ if (pack.agents.length > 0) {
2180
+ const agentsDir = join16(pluginDir, "agents");
2181
+ ensureDir(agentsDir);
2182
+ manifest.agents = [];
2183
+ for (const agent of pack.agents) {
2184
+ const fm = {
2185
+ name: agent.name,
2186
+ description: agent.meta.description ?? ""
2187
+ };
2188
+ const filename = `${agent.name}.md`;
2189
+ const filepath = join16(agentsDir, filename);
2190
+ writeFileSync5(filepath, serializeFrontmatter(fm, agent.content));
2191
+ filesWritten.push(filepath);
2192
+ manifest.agents.push(filename);
2193
+ }
2194
+ }
2195
+ if (pack.skills.length > 0) {
2196
+ const skillsDir = join16(pluginDir, "skills");
2197
+ ensureDir(skillsDir);
2198
+ manifest.skills = [];
2199
+ for (const skill of pack.skills) {
2200
+ const skillSubDir = join16(skillsDir, skill.name);
2201
+ ensureDir(skillSubDir);
2202
+ const fm = {
2203
+ name: skill.name,
2204
+ description: skill.meta.description ?? ""
2205
+ };
2206
+ const filepath = join16(skillSubDir, "SKILL.md");
2207
+ writeFileSync5(filepath, serializeFrontmatter(fm, skill.content));
2208
+ filesWritten.push(filepath);
2209
+ manifest.skills.push(skill.name);
2210
+ }
2211
+ }
2212
+ if (pack.commands.length > 0) {
2213
+ const commandsDir = join16(pluginDir, "commands");
2214
+ ensureDir(commandsDir);
2215
+ manifest.commands = [];
2216
+ for (const cmd of pack.commands) {
2217
+ const filename = `${cmd.name}.md`;
2218
+ const filepath = join16(commandsDir, filename);
2219
+ writeFileSync5(filepath, cmd.content);
2220
+ filesWritten.push(filepath);
2221
+ manifest.commands.push(filename);
2222
+ }
2223
+ }
2224
+ if (pack.mcp && Object.keys(pack.mcp.servers).length > 0) {
2225
+ manifest.mcp = true;
2226
+ const filepath = join16(pluginDir, "mcp.json");
2227
+ writeFileSync5(filepath, JSON.stringify({ mcpServers: pack.mcp.servers }, null, 2) + `
2228
+ `);
2229
+ filesWritten.push(filepath);
2230
+ }
2231
+ const manifestPath = join16(pluginDir, "manifest.json");
2232
+ writeFileSync5(manifestPath, JSON.stringify(manifest, null, 2) + `
2233
+ `);
2234
+ filesWritten.push(manifestPath);
2235
+ return { outputDir: pluginDir, filesWritten, manifest };
2236
+ }
2237
+
2238
+ // src/importers/rulesync.ts
2239
+ import { existsSync as existsSync10, readFileSync as readFileSync10, copyFileSync, writeFileSync as writeFileSync6 } from "fs";
2240
+ import { resolve as resolve17, join as join17, basename as basename6 } from "path";
2241
+ import { parse as parseJsonc2 } from "jsonc-parser";
2242
+ function importFromRulesync(projectRoot, outputPackDir) {
2243
+ const rulesyncDir = resolve17(projectRoot, ".rulesync");
2244
+ const warnings = [];
2245
+ const filesImported = [];
2246
+ if (!existsSync10(rulesyncDir)) {
2247
+ return {
2248
+ packDir: "",
2249
+ filesImported: [],
2250
+ warnings: ["No .rulesync/ directory found."],
2251
+ configGenerated: false
2252
+ };
2253
+ }
2254
+ const packDir = outputPackDir ?? resolve17(projectRoot, "packs", "default");
2255
+ ensureDir(packDir);
2256
+ const rulesDir = resolve17(rulesyncDir, "rules");
2257
+ if (existsSync10(rulesDir)) {
2258
+ const outRulesDir = resolve17(packDir, "rules");
2259
+ ensureDir(outRulesDir);
2260
+ const files = listFiles(rulesDir, { extension: ".md" });
2261
+ for (const file of files) {
2262
+ const dest = join17(outRulesDir, basename6(file));
2263
+ copyFileSync(file, dest);
2264
+ filesImported.push(dest);
2265
+ }
2266
+ }
2267
+ const commandsDir = resolve17(rulesyncDir, "commands");
2268
+ if (existsSync10(commandsDir)) {
2269
+ const outCommandsDir = resolve17(packDir, "commands");
2270
+ ensureDir(outCommandsDir);
2271
+ const files = listFiles(commandsDir, { extension: ".md" });
2272
+ for (const file of files) {
2273
+ const dest = join17(outCommandsDir, basename6(file));
2274
+ copyFileSync(file, dest);
2275
+ filesImported.push(dest);
2276
+ }
2277
+ }
2278
+ const subagentsDir = resolve17(rulesyncDir, "subagents");
2279
+ if (existsSync10(subagentsDir)) {
2280
+ const outAgentsDir = resolve17(packDir, "agents");
2281
+ ensureDir(outAgentsDir);
2282
+ const files = listFiles(subagentsDir, { extension: ".md" });
2283
+ for (const file of files) {
2284
+ const dest = join17(outAgentsDir, basename6(file));
2285
+ copyFileSync(file, dest);
2286
+ filesImported.push(dest);
2287
+ }
2288
+ }
2289
+ const skillsDir = resolve17(rulesyncDir, "skills");
2290
+ if (existsSync10(skillsDir)) {
2291
+ const outSkillsDir = resolve17(packDir, "skills");
2292
+ ensureDir(outSkillsDir);
2293
+ const skillDirs = listDirs(skillsDir);
2294
+ for (const skillDir of skillDirs) {
2295
+ const skillName = basename6(skillDir);
2296
+ if (skillName.startsWith("."))
2297
+ continue;
2298
+ const skillMd = join17(skillDir, "SKILL.md");
2299
+ if (existsSync10(skillMd)) {
2300
+ const outSkillDir = join17(outSkillsDir, skillName);
2301
+ ensureDir(outSkillDir);
2302
+ copyFileSync(skillMd, join17(outSkillDir, "SKILL.md"));
2303
+ filesImported.push(join17(outSkillDir, "SKILL.md"));
2304
+ }
2305
+ }
2306
+ }
2307
+ const hooksJson = resolve17(rulesyncDir, "hooks.json");
2308
+ if (existsSync10(hooksJson)) {
2309
+ const outHooksDir = resolve17(packDir, "hooks");
2310
+ ensureDir(outHooksDir);
2311
+ copyFileSync(hooksJson, join17(outHooksDir, "hooks.json"));
2312
+ filesImported.push(join17(outHooksDir, "hooks.json"));
2313
+ }
2314
+ const mcpJson = resolve17(rulesyncDir, "mcp.json");
2315
+ if (existsSync10(mcpJson)) {
2316
+ copyFileSync(mcpJson, join17(packDir, "mcp.json"));
2317
+ filesImported.push(join17(packDir, "mcp.json"));
2318
+ }
2319
+ const aiIgnore = resolve17(rulesyncDir, ".aiignore");
2320
+ const rulesyncIgnore = resolve17(projectRoot, ".rulesyncignore");
2321
+ if (existsSync10(aiIgnore)) {
2322
+ copyFileSync(aiIgnore, join17(packDir, "ignore"));
2323
+ filesImported.push(join17(packDir, "ignore"));
2324
+ } else if (existsSync10(rulesyncIgnore)) {
2325
+ copyFileSync(rulesyncIgnore, join17(packDir, "ignore"));
2326
+ filesImported.push(join17(packDir, "ignore"));
2327
+ }
2328
+ const packJson = {
2329
+ name: "default",
2330
+ version: "1.0.0",
2331
+ description: "Imported from rulesync",
2332
+ tags: ["imported", "rulesync"],
2333
+ dependencies: [],
2334
+ conflicts: [],
2335
+ targets: "*",
2336
+ features: "*"
2337
+ };
2338
+ writeFileSync6(join17(packDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
2339
+ `);
2340
+ filesImported.push(join17(packDir, "pack.json"));
2341
+ let configGenerated = false;
2342
+ const rulesyncConfig = resolve17(projectRoot, "rulesync.jsonc");
2343
+ if (existsSync10(rulesyncConfig)) {
2344
+ const agentpacksConfig = convertRulesyncConfig(rulesyncConfig, packDir, projectRoot);
2345
+ const configPath = resolve17(projectRoot, "agentpacks.jsonc");
2346
+ writeFileSync6(configPath, agentpacksConfig);
2347
+ configGenerated = true;
2348
+ }
2349
+ return { packDir, filesImported, warnings, configGenerated };
2350
+ }
2351
+ function convertRulesyncConfig(rulesyncPath, packDir, projectRoot) {
2352
+ const raw = readFileSync10(rulesyncPath, "utf-8");
2353
+ const parsed = parseJsonc2(raw);
2354
+ const targets = parsed.targets ?? ["opencode", "cursor", "claudecode"];
2355
+ const features = parsed.features ?? ["*"];
2356
+ const baseDirs = parsed.baseDirs ?? ["."];
2357
+ const global = parsed.global ?? false;
2358
+ const deleteVal = parsed.delete ?? true;
2359
+ const relPackDir = "./" + join17("packs", "default");
2360
+ const config = {
2361
+ $schema: "https://unpkg.com/agentpacks/schema.json",
2362
+ packs: [relPackDir],
2363
+ disabled: [],
2364
+ targets,
2365
+ features,
2366
+ mode: baseDirs.length > 1 ? "monorepo" : "repo",
2367
+ baseDirs,
2368
+ global,
2369
+ delete: deleteVal
2370
+ };
2371
+ return JSON.stringify(config, null, 2) + `
2372
+ `;
2373
+ }
2374
+
2375
+ // src/importers/cursor.ts
2376
+ import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync7, copyFileSync as copyFileSync2 } from "fs";
2377
+ import { resolve as resolve18, join as join18, basename as basename7 } from "path";
2378
+ function importFromCursor(projectRoot, outputPackDir) {
2379
+ const cursorDir = resolve18(projectRoot, ".cursor");
2380
+ const warnings = [];
2381
+ const filesImported = [];
2382
+ if (!existsSync11(cursorDir)) {
2383
+ return {
2384
+ packDir: "",
2385
+ filesImported: [],
2386
+ warnings: ["No .cursor/ directory found."],
2387
+ configGenerated: false
2388
+ };
2389
+ }
2390
+ const packDir = outputPackDir ?? resolve18(projectRoot, "packs", "cursor-import");
2391
+ ensureDir(packDir);
2392
+ const rulesDir = resolve18(cursorDir, "rules");
2393
+ if (existsSync11(rulesDir)) {
2394
+ const outRulesDir = resolve18(packDir, "rules");
2395
+ ensureDir(outRulesDir);
2396
+ const files = listFiles(rulesDir, { extension: ".mdc" });
2397
+ for (const file of files) {
2398
+ const raw = readFileSync11(file, "utf-8");
2399
+ const { data, content } = parseFrontmatter(raw);
2400
+ const meta = {};
2401
+ if (data.description)
2402
+ meta.description = data.description;
2403
+ if (data.alwaysApply)
2404
+ meta.root = true;
2405
+ if (data.globs)
2406
+ meta.globs = data.globs;
2407
+ meta.cursor = { ...data };
2408
+ const mdContent = buildAgentpacksRule(meta, content);
2409
+ const name = basename7(file, ".mdc");
2410
+ const dest = join18(outRulesDir, `${name}.md`);
2411
+ writeFileSync7(dest, mdContent);
2412
+ filesImported.push(dest);
2413
+ }
2414
+ const mdFiles = listFiles(rulesDir, { extension: ".md" });
2415
+ for (const file of mdFiles) {
2416
+ const dest = join18(outRulesDir, basename7(file));
2417
+ copyFileSync2(file, dest);
2418
+ filesImported.push(dest);
2419
+ }
2420
+ }
2421
+ const agentsDir = resolve18(cursorDir, "agents");
2422
+ if (existsSync11(agentsDir)) {
2423
+ const outDir = resolve18(packDir, "agents");
2424
+ ensureDir(outDir);
2425
+ const files = listFiles(agentsDir, { extension: ".md" });
2426
+ for (const file of files) {
2427
+ const dest = join18(outDir, basename7(file));
2428
+ copyFileSync2(file, dest);
2429
+ filesImported.push(dest);
2430
+ }
2431
+ }
2432
+ const skillsDir = resolve18(cursorDir, "skills");
2433
+ if (existsSync11(skillsDir)) {
2434
+ const outDir = resolve18(packDir, "skills");
2435
+ ensureDir(outDir);
2436
+ const dirs = listDirs(skillsDir);
2437
+ for (const dir of dirs) {
2438
+ const name = basename7(dir);
2439
+ const skillMd = join18(dir, "SKILL.md");
2440
+ if (existsSync11(skillMd)) {
2441
+ const outSkillDir = join18(outDir, name);
2442
+ ensureDir(outSkillDir);
2443
+ copyFileSync2(skillMd, join18(outSkillDir, "SKILL.md"));
2444
+ filesImported.push(join18(outSkillDir, "SKILL.md"));
2445
+ }
2446
+ }
2447
+ }
2448
+ const commandsDir = resolve18(cursorDir, "commands");
2449
+ if (existsSync11(commandsDir)) {
2450
+ const outDir = resolve18(packDir, "commands");
2451
+ ensureDir(outDir);
2452
+ const files = listFiles(commandsDir, { extension: ".md" });
2453
+ for (const file of files) {
2454
+ const dest = join18(outDir, basename7(file));
2455
+ copyFileSync2(file, dest);
2456
+ filesImported.push(dest);
2457
+ }
2458
+ }
2459
+ const mcpJson = resolve18(cursorDir, "mcp.json");
2460
+ if (existsSync11(mcpJson)) {
2461
+ copyFileSync2(mcpJson, join18(packDir, "mcp.json"));
2462
+ filesImported.push(join18(packDir, "mcp.json"));
2463
+ }
2464
+ const cursorIgnore = resolve18(projectRoot, ".cursorignore");
2465
+ if (existsSync11(cursorIgnore)) {
2466
+ copyFileSync2(cursorIgnore, join18(packDir, "ignore"));
2467
+ filesImported.push(join18(packDir, "ignore"));
2468
+ }
2469
+ writePackJson(packDir, "cursor-import", filesImported);
2470
+ return { packDir, filesImported, warnings, configGenerated: false };
2471
+ }
2472
+ function buildAgentpacksRule(meta, content) {
2473
+ const lines = ["---"];
2474
+ for (const [k, v] of Object.entries(meta)) {
2475
+ if (typeof v === "object") {
2476
+ lines.push(`${k}: ${JSON.stringify(v)}`);
2477
+ } else {
2478
+ lines.push(`${k}: ${v}`);
2479
+ }
2480
+ }
2481
+ lines.push("---", "", content);
2482
+ return lines.join(`
2483
+ `);
2484
+ }
2485
+ function writePackJson(packDir, name, filesImported) {
2486
+ const packJson = {
2487
+ name,
2488
+ version: "1.0.0",
2489
+ description: `Imported from Cursor`,
2490
+ tags: ["imported", "cursor"],
2491
+ dependencies: [],
2492
+ conflicts: [],
2493
+ targets: "*",
2494
+ features: "*"
2495
+ };
2496
+ const dest = join18(packDir, "pack.json");
2497
+ writeFileSync7(dest, JSON.stringify(packJson, null, 2) + `
2498
+ `);
2499
+ filesImported.push(dest);
2500
+ }
2501
+
2502
+ // src/importers/claude-code.ts
2503
+ import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync8, copyFileSync as copyFileSync3 } from "fs";
2504
+ import { resolve as resolve19, join as join19, basename as basename8 } from "path";
2505
+ function importFromClaudeCode(projectRoot, outputPackDir) {
2506
+ const warnings = [];
2507
+ const filesImported = [];
2508
+ const claudeDir = resolve19(projectRoot, ".claude");
2509
+ const hasClaudeMd = existsSync12(resolve19(projectRoot, "CLAUDE.md"));
2510
+ const hasClaudeDir = existsSync12(claudeDir);
2511
+ if (!hasClaudeMd && !hasClaudeDir) {
2512
+ return {
2513
+ packDir: "",
2514
+ filesImported: [],
2515
+ warnings: ["No CLAUDE.md or .claude/ directory found."],
2516
+ configGenerated: false
2517
+ };
2518
+ }
2519
+ const packDir = outputPackDir ?? resolve19(projectRoot, "packs", "claude-import");
2520
+ ensureDir(packDir);
2521
+ const rulesDir = resolve19(packDir, "rules");
2522
+ ensureDir(rulesDir);
2523
+ if (hasClaudeMd) {
2524
+ const raw = readFileSync12(resolve19(projectRoot, "CLAUDE.md"), "utf-8");
2525
+ const ruleContent = [
2526
+ "---",
2527
+ "root: true",
2528
+ 'description: "Root Claude Code rules"',
2529
+ "---",
2530
+ "",
2531
+ raw
2532
+ ].join(`
2533
+ `);
2534
+ const dest = join19(rulesDir, "claude-root.md");
2535
+ writeFileSync8(dest, ruleContent);
2536
+ filesImported.push(dest);
2537
+ }
2538
+ if (hasClaudeDir) {
2539
+ const claudeRulesDir = resolve19(claudeDir, "rules");
2540
+ if (existsSync12(claudeRulesDir)) {
2541
+ const files = listFiles(claudeRulesDir, { extension: ".md" });
2542
+ for (const file of files) {
2543
+ const dest = join19(rulesDir, basename8(file));
2544
+ copyFileSync3(file, dest);
2545
+ filesImported.push(dest);
2546
+ }
2547
+ }
2548
+ const settingsPath = resolve19(claudeDir, "settings.json");
2549
+ if (existsSync12(settingsPath)) {
2550
+ try {
2551
+ const raw = readFileSync12(settingsPath, "utf-8");
2552
+ const settings = JSON.parse(raw);
2553
+ const mcpServers = settings.mcpServers ?? settings.mcp_servers;
2554
+ if (mcpServers && typeof mcpServers === "object") {
2555
+ const mcpConfig = { servers: mcpServers };
2556
+ const dest = join19(packDir, "mcp.json");
2557
+ writeFileSync8(dest, JSON.stringify(mcpConfig, null, 2) + `
2558
+ `);
2559
+ filesImported.push(dest);
2560
+ }
2561
+ } catch {
2562
+ warnings.push("Failed to parse .claude/settings.json");
2563
+ }
2564
+ }
2565
+ }
2566
+ const packJson = {
2567
+ name: "claude-import",
2568
+ version: "1.0.0",
2569
+ description: "Imported from Claude Code",
2570
+ tags: ["imported", "claude-code"],
2571
+ dependencies: [],
2572
+ conflicts: [],
2573
+ targets: "*",
2574
+ features: "*"
2575
+ };
2576
+ const packJsonPath = join19(packDir, "pack.json");
2577
+ writeFileSync8(packJsonPath, JSON.stringify(packJson, null, 2) + `
2578
+ `);
2579
+ filesImported.push(packJsonPath);
2580
+ return { packDir, filesImported, warnings, configGenerated: false };
2581
+ }
2582
+
2583
+ // src/importers/opencode.ts
2584
+ import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync9, copyFileSync as copyFileSync4 } from "fs";
2585
+ import { resolve as resolve20, join as join20, basename as basename9 } from "path";
2586
+ function importFromOpenCode(projectRoot, outputPackDir) {
2587
+ const warnings = [];
2588
+ const filesImported = [];
2589
+ const ocDir = resolve20(projectRoot, ".opencode");
2590
+ if (!existsSync13(ocDir)) {
2591
+ return {
2592
+ packDir: "",
2593
+ filesImported: [],
2594
+ warnings: ["No .opencode/ directory found."],
2595
+ configGenerated: false
2596
+ };
2597
+ }
2598
+ const packDir = outputPackDir ?? resolve20(projectRoot, "packs", "opencode-import");
2599
+ ensureDir(packDir);
2600
+ importDirMd(resolve20(ocDir, "rules"), resolve20(packDir, "rules"), filesImported);
2601
+ importDirMd(resolve20(ocDir, "commands"), resolve20(packDir, "commands"), filesImported);
2602
+ importDirMd(resolve20(ocDir, "agents"), resolve20(packDir, "agents"), filesImported);
2603
+ const skillDir = resolve20(ocDir, "skill");
2604
+ if (existsSync13(skillDir)) {
2605
+ const outSkillDir = resolve20(packDir, "skills");
2606
+ ensureDir(outSkillDir);
2607
+ const dirs = listDirs(skillDir);
2608
+ for (const dir of dirs) {
2609
+ const name = basename9(dir);
2610
+ if (name.startsWith("."))
2611
+ continue;
2612
+ const skillMd = join20(dir, "SKILL.md");
2613
+ if (existsSync13(skillMd)) {
2614
+ const outDir = join20(outSkillDir, name);
2615
+ ensureDir(outDir);
2616
+ copyFileSync4(skillMd, join20(outDir, "SKILL.md"));
2617
+ filesImported.push(join20(outDir, "SKILL.md"));
2618
+ }
2619
+ }
2620
+ }
2621
+ const pluginsDir = resolve20(ocDir, "plugins");
2622
+ if (existsSync13(pluginsDir)) {
2623
+ const outPluginsDir = resolve20(packDir, "plugins");
2624
+ ensureDir(outPluginsDir);
2625
+ const files = listFiles(pluginsDir);
2626
+ for (const file of files) {
2627
+ if (file.endsWith(".ts") || file.endsWith(".js")) {
2628
+ const dest2 = join20(outPluginsDir, basename9(file));
2629
+ copyFileSync4(file, dest2);
2630
+ filesImported.push(dest2);
2631
+ }
2632
+ }
2633
+ }
2634
+ const agentsMd = resolve20(projectRoot, "AGENTS.md");
2635
+ if (existsSync13(agentsMd)) {
2636
+ const outRulesDir = resolve20(packDir, "rules");
2637
+ ensureDir(outRulesDir);
2638
+ const raw = readFileSync13(agentsMd, "utf-8");
2639
+ const ruleContent = [
2640
+ "---",
2641
+ "root: true",
2642
+ 'description: "AGENTS.md root rules"',
2643
+ "---",
2644
+ "",
2645
+ raw
2646
+ ].join(`
2647
+ `);
2648
+ const dest2 = join20(outRulesDir, "agents-md-root.md");
2649
+ writeFileSync9(dest2, ruleContent);
2650
+ filesImported.push(dest2);
2651
+ }
2652
+ const ocJson = resolve20(projectRoot, "opencode.json");
2653
+ if (existsSync13(ocJson)) {
2654
+ try {
2655
+ const raw = readFileSync13(ocJson, "utf-8");
2656
+ const config = JSON.parse(raw);
2657
+ const mcpObj = config.mcp;
2658
+ if (mcpObj) {
2659
+ const dest2 = join20(packDir, "mcp.json");
2660
+ writeFileSync9(dest2, JSON.stringify({ servers: mcpObj }, null, 2) + `
2661
+ `);
2662
+ filesImported.push(dest2);
2663
+ }
2664
+ } catch {
2665
+ warnings.push("Failed to parse opencode.json");
2666
+ }
2667
+ }
2668
+ const ocIgnore = resolve20(projectRoot, ".opencodeignore");
2669
+ if (existsSync13(ocIgnore)) {
2670
+ copyFileSync4(ocIgnore, join20(packDir, "ignore"));
2671
+ filesImported.push(join20(packDir, "ignore"));
2672
+ }
2673
+ const packJson = {
2674
+ name: "opencode-import",
2675
+ version: "1.0.0",
2676
+ description: "Imported from OpenCode",
2677
+ tags: ["imported", "opencode"],
2678
+ dependencies: [],
2679
+ conflicts: [],
2680
+ targets: "*",
2681
+ features: "*"
2682
+ };
2683
+ const dest = join20(packDir, "pack.json");
2684
+ writeFileSync9(dest, JSON.stringify(packJson, null, 2) + `
2685
+ `);
2686
+ filesImported.push(dest);
2687
+ return { packDir, filesImported, warnings, configGenerated: false };
2688
+ }
2689
+ function importDirMd(srcDir, outDir, filesImported) {
2690
+ if (!existsSync13(srcDir))
2691
+ return;
2692
+ ensureDir(outDir);
2693
+ const files = listFiles(srcDir, { extension: ".md" });
2694
+ for (const file of files) {
2695
+ const dest = join20(outDir, basename9(file));
2696
+ copyFileSync4(file, dest);
2697
+ filesImported.push(dest);
2698
+ }
2699
+ }
2700
+
2701
+ // src/cli/export-cmd.ts
2702
+ init_config();
2703
+ import { resolve as resolve21 } from "path";
2704
+ import chalk from "chalk";
2705
+ function runExport(projectRoot, options) {
2706
+ const config = loadWorkspaceConfig(projectRoot);
2707
+ const verbose = options.verbose ?? config.verbose;
2708
+ const loader = new PackLoader(projectRoot, config);
2709
+ const { packs, warnings: loadWarnings } = loader.loadAll();
2710
+ for (const w of loadWarnings) {
2711
+ console.log(chalk.yellow(` warn: ${w}`));
2712
+ }
2713
+ if (packs.length === 0) {
2714
+ console.log(chalk.red("No packs loaded. Nothing to export."));
2715
+ return;
2716
+ }
2717
+ const packsToExport = options.pack ? packs.filter((p) => p.manifest.name === options.pack) : packs;
2718
+ if (packsToExport.length === 0) {
2719
+ console.log(chalk.red(`Pack "${options.pack}" not found.`));
2720
+ return;
2721
+ }
2722
+ const outputDir = resolve21(projectRoot, options.output ?? "dist/cursor-plugins");
2723
+ switch (options.format) {
2724
+ case "cursor-plugin": {
2725
+ let totalFiles = 0;
2726
+ for (const pack of packsToExport) {
2727
+ if (verbose) {
2728
+ console.log(chalk.dim(` Exporting ${pack.manifest.name}...`));
2729
+ }
2730
+ const result = exportCursorPlugin(pack, outputDir);
2731
+ totalFiles += result.filesWritten.length;
2732
+ if (verbose) {
2733
+ console.log(chalk.dim(` ${result.filesWritten.length} file(s) written`));
2734
+ }
2735
+ }
2736
+ console.log(chalk.green(`Exported ${packsToExport.length} pack(s) as Cursor plugins (${totalFiles} files) to ${outputDir}`));
2737
+ break;
2738
+ }
2739
+ default:
2740
+ console.log(chalk.red(`Unknown export format: "${options.format}". Supported: cursor-plugin`));
2741
+ }
2742
+ }
2743
+
2744
+ // src/utils/diff.ts
2745
+ import { existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
2746
+ function diffFile(filepath, newContent) {
2747
+ if (!existsSync14(filepath)) {
2748
+ return {
2749
+ filepath,
2750
+ status: "added",
2751
+ diffLines: formatAddedDiff(filepath, newContent)
2752
+ };
2753
+ }
2754
+ const existing = readFileSync14(filepath, "utf-8");
2755
+ if (existing === newContent) {
2756
+ return { filepath, status: "unchanged", diffLines: [] };
2757
+ }
2758
+ return {
2759
+ filepath,
2760
+ status: "modified",
2761
+ diffLines: computeUnifiedDiff(filepath, existing, newContent)
2762
+ };
2763
+ }
2764
+ function formatAddedDiff(filepath, content) {
2765
+ const lines = [
2766
+ `--- /dev/null`,
2767
+ `+++ ${filepath}`,
2768
+ `@@ -0,0 +1,${content.split(`
2769
+ `).length} @@`
2770
+ ];
2771
+ for (const line of content.split(`
2772
+ `)) {
2773
+ lines.push(`+${line}`);
2774
+ }
2775
+ return lines;
2776
+ }
2777
+ function computeUnifiedDiff(filepath, oldContent, newContent) {
2778
+ const oldLines = oldContent.split(`
2779
+ `);
2780
+ const newLines = newContent.split(`
2781
+ `);
2782
+ const result = [`--- ${filepath}`, `+++ ${filepath}`];
2783
+ const hunks = findHunks(oldLines, newLines);
2784
+ for (const hunk of hunks) {
2785
+ result.push(`@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`);
2786
+ for (const line of hunk.lines) {
2787
+ result.push(line);
2788
+ }
2789
+ }
2790
+ return result;
2791
+ }
2792
+ function findHunks(oldLines, newLines) {
2793
+ const CONTEXT = 3;
2794
+ const changes = [];
2795
+ let oi = 0;
2796
+ let ni = 0;
2797
+ while (oi < oldLines.length || ni < newLines.length) {
2798
+ if (oi < oldLines.length && ni < newLines.length && oldLines[oi] === newLines[ni]) {
2799
+ changes.push({ type: " ", line: oldLines[oi], oldIdx: oi, newIdx: ni });
2800
+ oi++;
2801
+ ni++;
2802
+ } else if (ni < newLines.length && (oi >= oldLines.length || !newLines.slice(ni).includes(oldLines[oi]))) {
2803
+ changes.push({ type: "+", line: newLines[ni], oldIdx: oi, newIdx: ni });
2804
+ ni++;
2805
+ } else {
2806
+ changes.push({ type: "-", line: oldLines[oi], oldIdx: oi, newIdx: oi });
2807
+ oi++;
2808
+ }
2809
+ }
2810
+ const hunks = [];
2811
+ let currentHunk = null;
2812
+ let unchangedCount = 0;
2813
+ for (const change of changes) {
2814
+ if (change.type === " ") {
2815
+ unchangedCount++;
2816
+ if (currentHunk && unchangedCount <= CONTEXT) {
2817
+ currentHunk.lines.push(` ${change.line}`);
2818
+ currentHunk.oldCount++;
2819
+ currentHunk.newCount++;
2820
+ } else if (currentHunk && unchangedCount > CONTEXT * 2) {
2821
+ hunks.push(currentHunk);
2822
+ currentHunk = null;
2823
+ }
2824
+ } else {
2825
+ if (!currentHunk) {
2826
+ const contextStart = Math.max(0, changes.indexOf(change) - CONTEXT);
2827
+ currentHunk = {
2828
+ oldStart: change.oldIdx - Math.min(CONTEXT, changes.indexOf(change) - contextStart),
2829
+ oldCount: 0,
2830
+ newStart: change.newIdx - Math.min(CONTEXT, changes.indexOf(change) - contextStart),
2831
+ newCount: 0,
2832
+ lines: []
2833
+ };
2834
+ for (let i = contextStart;i < changes.indexOf(change); i++) {
2835
+ if (changes[i].type === " ") {
2836
+ currentHunk.lines.push(` ${changes[i].line}`);
2837
+ currentHunk.oldCount++;
2838
+ currentHunk.newCount++;
2839
+ }
2840
+ }
2841
+ }
2842
+ unchangedCount = 0;
2843
+ currentHunk.lines.push(`${change.type}${change.line}`);
2844
+ if (change.type === "-")
2845
+ currentHunk.oldCount++;
2846
+ if (change.type === "+")
2847
+ currentHunk.newCount++;
2848
+ }
2849
+ }
2850
+ if (currentHunk)
2851
+ hunks.push(currentHunk);
2852
+ return hunks;
2853
+ }
2854
+
2855
+ // src/cli/generate.ts
2856
+ init_config();
2857
+ import { existsSync as existsSync15, readFileSync as readFileSync15 } from "fs";
2858
+ import chalk2 from "chalk";
2859
+ function runGenerate(projectRoot, options) {
2860
+ const config = loadWorkspaceConfig(projectRoot);
2861
+ if (options.targets) {
2862
+ const targetList = options.targets === "*" ? "*" : options.targets.split(",");
2863
+ config.targets = targetList;
2864
+ }
2865
+ if (options.features) {
2866
+ const featureList = options.features === "*" ? "*" : options.features.split(",");
2867
+ config.features = featureList;
2868
+ }
2869
+ if (options.verbose !== undefined) {
2870
+ config.verbose = options.verbose;
2871
+ }
2872
+ const verbose = config.verbose;
2873
+ if (verbose)
2874
+ console.log(chalk2.dim("Loading packs..."));
2875
+ const loader = new PackLoader(projectRoot, config);
2876
+ const { packs, warnings: loadWarnings } = loader.loadAll();
2877
+ for (const w of loadWarnings) {
2878
+ console.log(chalk2.yellow(` warn: ${w}`));
2879
+ }
2880
+ if (packs.length === 0) {
2881
+ console.log(chalk2.red("No packs loaded. Nothing to generate."));
2882
+ console.log(chalk2.dim("Run 'agentpacks init' to create a default pack."));
2883
+ return;
2884
+ }
2885
+ if (verbose) {
2886
+ console.log(chalk2.dim(` Loaded ${packs.length} pack(s): ${packs.map((p) => p.manifest.name).join(", ")}`));
2887
+ }
2888
+ if (verbose)
2889
+ console.log(chalk2.dim("Merging features..."));
2890
+ const merger = new FeatureMerger(packs);
2891
+ const { features, warnings: mergeWarnings } = merger.merge();
2892
+ for (const w of mergeWarnings) {
2893
+ console.log(chalk2.yellow(` warn: ${w}`));
2894
+ }
2895
+ const targetIds = resolveTargets(config);
2896
+ if (!targetIds.includes("agentsmd")) {
2897
+ targetIds.push("agentsmd");
2898
+ }
2899
+ const targets = getTargets(targetIds);
2900
+ if (targets.length === 0) {
2901
+ console.log(chalk2.red("No valid targets found."));
2902
+ return;
2903
+ }
2904
+ const allResults = [];
2905
+ const diffEntries = [];
2906
+ for (const baseDir of config.baseDirs) {
2907
+ for (const target of targets) {
2908
+ const enabledFeatures = resolveFeatures(config, target.id);
2909
+ const effectiveFeatures = enabledFeatures.filter((f) => target.supportsFeature(f));
2910
+ if (effectiveFeatures.length === 0 && target.id !== "agentsmd") {
2911
+ if (verbose) {
2912
+ console.log(chalk2.dim(` Skipping ${target.name} (no enabled features)`));
2913
+ }
2914
+ continue;
2915
+ }
2916
+ if (options.dryRun && !options.diff) {
2917
+ console.log(chalk2.cyan(` [dry-run] Would generate ${target.name} in ${baseDir}`));
2918
+ continue;
2919
+ }
2920
+ const generateOptions = {
2921
+ projectRoot,
2922
+ baseDir,
2923
+ features,
2924
+ enabledFeatures,
2925
+ deleteExisting: options.diff ? false : config.delete,
2926
+ global: config.global,
2927
+ verbose: config.verbose
2928
+ };
2929
+ const preSnapshot = new Map;
2930
+ try {
2931
+ const result = target.generate(generateOptions);
2932
+ allResults.push(result);
2933
+ if (options.diff) {
2934
+ for (const filepath of result.filesWritten) {
2935
+ const newContent = existsSync15(filepath) ? readFileSync15(filepath, "utf-8") : "";
2936
+ const entry = diffFile(filepath, newContent);
2937
+ if (entry.status !== "unchanged") {
2938
+ diffEntries.push(entry);
2939
+ }
2940
+ }
2941
+ }
2942
+ for (const w of result.warnings) {
2943
+ console.log(chalk2.yellow(` warn [${target.name}]: ${w}`));
2944
+ }
2945
+ if (verbose && result.filesWritten.length > 0) {
2946
+ console.log(chalk2.dim(` ${target.name}: wrote ${result.filesWritten.length} file(s)`));
2947
+ }
2948
+ } catch (err) {
2949
+ const message = err instanceof Error ? err.message : String(err);
2950
+ console.log(chalk2.red(` error [${target.name}]: ${message}`));
2951
+ }
2952
+ }
2953
+ }
2954
+ if (options.diff && diffEntries.length > 0) {
2955
+ const added = diffEntries.filter((e) => e.status === "added").length;
2956
+ const modified = diffEntries.filter((e) => e.status === "modified").length;
2957
+ console.log(chalk2.bold(`
2958
+ Diff: ${added} added, ${modified} modified
2959
+ `));
2960
+ for (const entry of diffEntries) {
2961
+ const label = entry.status === "added" ? chalk2.green("[+] " + entry.filepath) : chalk2.yellow("[M] " + entry.filepath);
2962
+ console.log(label);
2963
+ if (verbose) {
2964
+ for (const line of entry.diffLines.slice(0, 50)) {
2965
+ if (line.startsWith("+") && !line.startsWith("+++")) {
2966
+ console.log(chalk2.green(line));
2967
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
2968
+ console.log(chalk2.red(line));
2969
+ } else {
2970
+ console.log(chalk2.dim(line));
2971
+ }
2972
+ }
2973
+ if (entry.diffLines.length > 50) {
2974
+ console.log(chalk2.dim(` ... ${entry.diffLines.length - 50} more lines`));
2975
+ }
2976
+ }
2977
+ }
2978
+ console.log();
2979
+ } else if (options.diff) {
2980
+ console.log(chalk2.dim("No changes detected."));
2981
+ }
2982
+ if (!options.dryRun) {
2983
+ const totalWritten = allResults.reduce((sum, r) => sum + r.filesWritten.length, 0);
2984
+ const totalDeleted = allResults.reduce((sum, r) => sum + r.filesDeleted.length, 0);
2985
+ const targetNames = allResults.map((r) => r.targetId);
2986
+ const uniqueTargets = [...new Set(targetNames)];
2987
+ console.log(chalk2.green(`Generated ${totalWritten} file(s) for ${uniqueTargets.length} target(s)` + (totalDeleted > 0 ? ` (cleaned ${totalDeleted} dir(s))` : "")));
2988
+ }
2989
+ }
2990
+
2991
+ // src/cli/import-cmd.ts
2992
+ import chalk3 from "chalk";
2993
+ function runImport(projectRoot, options) {
2994
+ const { from, output } = options;
2995
+ switch (from) {
2996
+ case "rulesync": {
2997
+ console.log(chalk3.dim("Importing from .rulesync/ ..."));
2998
+ const result = importFromRulesync(projectRoot, output);
2999
+ if (result.warnings.length > 0) {
3000
+ for (const w of result.warnings) {
3001
+ console.log(chalk3.yellow(` warn: ${w}`));
3002
+ }
3003
+ return;
3004
+ }
3005
+ console.log(chalk3.green(`Imported ${result.filesImported.length} file(s) to ${result.packDir}`));
3006
+ if (result.configGenerated) {
3007
+ console.log(chalk3.green("Generated agentpacks.jsonc from rulesync.jsonc"));
3008
+ }
3009
+ console.log(chalk3.cyan(`
3010
+ Next steps:`), `
3011
+ 1. Review the imported pack at`, chalk3.bold(result.packDir), `
3012
+ 2. Run`, chalk3.bold("agentpacks generate"), "to generate tool configs");
3013
+ break;
3014
+ }
3015
+ case "cursor": {
3016
+ console.log(chalk3.dim("Importing from .cursor/ ..."));
3017
+ const cursorResult = importFromCursor(projectRoot, output);
3018
+ printImportResult(cursorResult, "Cursor");
3019
+ break;
3020
+ }
3021
+ case "claude":
3022
+ case "claudecode":
3023
+ case "claude-code": {
3024
+ console.log(chalk3.dim("Importing from Claude Code..."));
3025
+ const claudeResult = importFromClaudeCode(projectRoot, output);
3026
+ printImportResult(claudeResult, "Claude Code");
3027
+ break;
3028
+ }
3029
+ case "opencode": {
3030
+ console.log(chalk3.dim("Importing from .opencode/ ..."));
3031
+ const ocResult = importFromOpenCode(projectRoot, output);
3032
+ printImportResult(ocResult, "OpenCode");
3033
+ break;
3034
+ }
3035
+ default:
3036
+ console.log(chalk3.red(`Unknown import source: "${from}"`));
3037
+ console.log(chalk3.dim("Supported sources: rulesync, cursor, claude-code, opencode"));
3038
+ break;
3039
+ }
3040
+ }
3041
+ function printImportResult(result, sourceName) {
3042
+ if (result.warnings.length > 0 && result.filesImported.length === 0) {
3043
+ for (const w of result.warnings) {
3044
+ console.log(chalk3.yellow(` warn: ${w}`));
3045
+ }
3046
+ return;
3047
+ }
3048
+ for (const w of result.warnings) {
3049
+ console.log(chalk3.yellow(` warn: ${w}`));
3050
+ }
3051
+ console.log(chalk3.green(`Imported ${result.filesImported.length} file(s) from ${sourceName} to ${result.packDir}`));
3052
+ console.log(chalk3.cyan(`
3053
+ Next steps:`), `
3054
+ 1. Review the imported pack at`, chalk3.bold(result.packDir), `
3055
+ 2. Run`, chalk3.bold("agentpacks generate"), "to generate tool configs");
3056
+ }
3057
+
3058
+ // src/cli/init.ts
3059
+ import { existsSync as existsSync16, copyFileSync as copyFileSync5, writeFileSync as writeFileSync10 } from "fs";
3060
+ import { resolve as resolve22, join as join21 } from "path";
3061
+ import chalk4 from "chalk";
3062
+ function runInit(projectRoot) {
3063
+ const configPath = resolve22(projectRoot, "agentpacks.jsonc");
3064
+ const packsDir = resolve22(projectRoot, "packs", "default");
3065
+ if (existsSync16(configPath)) {
3066
+ console.log(chalk4.yellow("agentpacks.jsonc already exists. Skipping config creation."));
3067
+ } else {
3068
+ const templateDir = resolve22(import.meta.dirname, "..", "..", "templates");
3069
+ const templateConfig = resolve22(templateDir, "workspace", "agentpacks.jsonc");
3070
+ if (existsSync16(templateConfig)) {
3071
+ copyFileSync5(templateConfig, configPath);
3072
+ } else {
3073
+ const config = {
3074
+ $schema: "https://unpkg.com/agentpacks/schema.json",
3075
+ packs: ["./packs/default"],
3076
+ disabled: [],
3077
+ targets: [
3078
+ "opencode",
3079
+ "cursor",
3080
+ "claudecode",
3081
+ "geminicli",
3082
+ "codexcli",
3083
+ "copilot"
3084
+ ],
3085
+ features: ["*"],
3086
+ mode: "repo",
3087
+ baseDirs: ["."],
3088
+ global: false,
3089
+ delete: true
3090
+ };
3091
+ writeFileSync10(configPath, JSON.stringify(config, null, 2) + `
3092
+ `);
3093
+ }
3094
+ console.log(chalk4.green("Created agentpacks.jsonc"));
3095
+ }
3096
+ if (existsSync16(packsDir)) {
3097
+ console.log(chalk4.yellow("packs/default/ already exists. Skipping pack scaffold."));
3098
+ } else {
3099
+ ensureDir(packsDir);
3100
+ ensureDir(join21(packsDir, "rules"));
3101
+ ensureDir(join21(packsDir, "commands"));
3102
+ ensureDir(join21(packsDir, "agents"));
3103
+ ensureDir(join21(packsDir, "skills"));
3104
+ const packJson = {
3105
+ name: "default",
3106
+ version: "1.0.0",
3107
+ description: "Default project pack",
3108
+ tags: [],
3109
+ dependencies: [],
3110
+ conflicts: [],
3111
+ targets: "*",
3112
+ features: "*"
3113
+ };
3114
+ writeFileSync10(join21(packsDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
3115
+ `);
3116
+ const templateRule = resolve22(import.meta.dirname, "..", "..", "templates", "pack", "rules", "overview.md");
3117
+ if (existsSync16(templateRule)) {
3118
+ copyFileSync5(templateRule, join21(packsDir, "rules", "overview.md"));
3119
+ }
3120
+ console.log(chalk4.green("Created packs/default/ with scaffold"));
3121
+ }
3122
+ console.log(chalk4.cyan(`
3123
+ Next steps:`), `
3124
+ 1. Edit packs/default/rules/overview.md with your project guidelines`, `
3125
+ 2. Run`, chalk4.bold("agentpacks generate"), "to generate tool configs", `
3126
+ 3. Or run`, chalk4.bold("agentpacks import --from rulesync"), "to migrate from rulesync");
3127
+ }
3128
+
3129
+ // src/cli/install.ts
3130
+ init_config();
3131
+ import chalk5 from "chalk";
3132
+ async function runInstall(projectRoot, options) {
3133
+ const config = loadWorkspaceConfig(projectRoot);
3134
+ const lockfile = loadLockfile(projectRoot);
3135
+ const verbose = options.verbose ?? config.verbose;
3136
+ const remotePacks = config.packs.filter((ref) => isGitPackRef(ref) || isNpmPackRef(ref));
3137
+ const localPacks = config.packs.filter((ref) => isLocalPackRef(ref));
3138
+ if (remotePacks.length === 0) {
3139
+ console.log(chalk5.dim("No remote packs to install. All packs are local."));
3140
+ return;
3141
+ }
3142
+ if (verbose) {
3143
+ console.log(chalk5.dim(`Found ${remotePacks.length} remote pack(s) to install`));
3144
+ console.log(chalk5.dim(` (${localPacks.length} local pack(s) skipped)`));
3145
+ }
3146
+ if (options.frozen) {
3147
+ const sourceKeys = remotePacks.map((ref) => ref);
3148
+ const frozenCheck = isLockfileFrozenValid(lockfile, sourceKeys);
3149
+ if (!frozenCheck.valid) {
3150
+ console.log(chalk5.red(`Frozen install failed. Missing lockfile entries: ${frozenCheck.missing.join(", ")}`));
3151
+ process.exit(1);
3152
+ }
3153
+ }
3154
+ let totalInstalled = 0;
3155
+ const allWarnings = [];
3156
+ for (const packRef of remotePacks) {
3157
+ if (verbose) {
3158
+ console.log(chalk5.dim(` Installing ${packRef}...`));
3159
+ }
3160
+ try {
3161
+ let result;
3162
+ if (isGitPackRef(packRef)) {
3163
+ const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN ?? undefined;
3164
+ result = await installGitSource(projectRoot, packRef, lockfile, {
3165
+ update: options.update,
3166
+ frozen: options.frozen,
3167
+ token
3168
+ });
3169
+ } else if (isNpmPackRef(packRef)) {
3170
+ result = await installNpmSource(projectRoot, packRef, lockfile, {
3171
+ update: options.update,
3172
+ frozen: options.frozen
3173
+ });
3174
+ } else {
3175
+ continue;
3176
+ }
3177
+ totalInstalled += result.installed.length;
3178
+ allWarnings.push(...result.warnings);
3179
+ if (verbose && result.installed.length > 0) {
3180
+ console.log(chalk5.dim(` ${result.installed.length} file(s) installed`));
3181
+ }
3182
+ } catch (err) {
3183
+ const msg = err instanceof Error ? err.message : String(err);
3184
+ console.log(chalk5.red(` error [${packRef}]: ${msg}`));
3185
+ allWarnings.push(`Failed to install ${packRef}: ${msg}`);
3186
+ }
3187
+ }
3188
+ for (const w of allWarnings) {
3189
+ console.log(chalk5.yellow(` warn: ${w}`));
3190
+ }
3191
+ saveLockfile(projectRoot, lockfile);
3192
+ console.log(chalk5.green(`Installed ${totalInstalled} file(s) from ${remotePacks.length} source(s)`));
3193
+ if (verbose) {
3194
+ console.log(chalk5.dim("Lockfile updated: agentpacks.lock"));
3195
+ }
3196
+ }
3197
+
3198
+ // src/cli/pack/create.ts
3199
+ import { existsSync as existsSync17, writeFileSync as writeFileSync11 } from "fs";
3200
+ import { resolve as resolve23, join as join22 } from "path";
3201
+ import chalk6 from "chalk";
3202
+ function runPackCreate(projectRoot, name) {
3203
+ const packDir = resolve23(projectRoot, "packs", name);
3204
+ if (existsSync17(packDir)) {
3205
+ console.log(chalk6.red(`Pack "${name}" already exists at packs/${name}/`));
3206
+ return;
3207
+ }
3208
+ ensureDir(packDir);
3209
+ ensureDir(join22(packDir, "rules"));
3210
+ ensureDir(join22(packDir, "commands"));
3211
+ ensureDir(join22(packDir, "agents"));
3212
+ ensureDir(join22(packDir, "skills"));
3213
+ const packJson = {
3214
+ name,
3215
+ version: "1.0.0",
3216
+ description: "",
3217
+ tags: [],
3218
+ dependencies: [],
3219
+ conflicts: [],
3220
+ targets: "*",
3221
+ features: "*"
3222
+ };
3223
+ writeFileSync11(join22(packDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
3224
+ `);
3225
+ console.log(chalk6.green(`Created pack "${name}" at packs/${name}/`));
3226
+ console.log(chalk6.dim(" Add rules, commands, agents, skills, hooks, plugins, mcp.json, or ignore files."));
3227
+ console.log(chalk6.dim(` Then add "${join22("./packs", name)}" to packs[] in agentpacks.jsonc.`));
3228
+ }
3229
+
3230
+ // src/cli/pack/enable.ts
3231
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync12, existsSync as existsSync18 } from "fs";
3232
+ import { resolve as resolve24 } from "path";
3233
+ import chalk7 from "chalk";
3234
+ var CONFIG_FILENAME = "agentpacks.jsonc";
3235
+ function readConfigRaw(projectRoot) {
3236
+ const filepath = resolve24(projectRoot, CONFIG_FILENAME);
3237
+ if (!existsSync18(filepath)) {
3238
+ throw new Error(`No ${CONFIG_FILENAME} found. Run 'agentpacks init' first.`);
3239
+ }
3240
+ return readFileSync16(filepath, "utf-8");
3241
+ }
3242
+ function parseDisabledFromRaw(raw) {
3243
+ const regex = /"disabled"\s*:\s*\[([^\]]*)\]/;
3244
+ const match = regex.exec(raw);
3245
+ if (!match)
3246
+ return { list: [], match: null };
3247
+ const inner = match[1].trim();
3248
+ if (!inner)
3249
+ return { list: [], match };
3250
+ const list = inner.split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
3251
+ return { list, match };
3252
+ }
3253
+ function writeDisabled(raw, newList, match) {
3254
+ const formatted = newList.length === 0 ? '"disabled": []' : `"disabled": [${newList.map((n) => `"${n}"`).join(", ")}]`;
3255
+ if (!match) {
3256
+ return raw.replace(/("packs"\s*:\s*\[[^\]]*\],?)/, `$1
3257
+
3258
+ // Packs to disable (override)
3259
+ ${formatted},`);
3260
+ }
3261
+ return raw.slice(0, match.index) + formatted + raw.slice(match.index + match[0].length);
3262
+ }
3263
+ function runPackDisable(projectRoot, packName) {
3264
+ const raw = readConfigRaw(projectRoot);
3265
+ const { list, match } = parseDisabledFromRaw(raw);
3266
+ if (list.includes(packName)) {
3267
+ console.log(chalk7.dim(`Pack "${packName}" is already disabled.`));
3268
+ return;
3269
+ }
3270
+ list.push(packName);
3271
+ const updated = writeDisabled(raw, list, match);
3272
+ const filepath = resolve24(projectRoot, CONFIG_FILENAME);
3273
+ writeFileSync12(filepath, updated);
3274
+ console.log(chalk7.green(`Disabled pack "${packName}".`));
3275
+ console.log(chalk7.dim("Run 'agentpacks generate' to regenerate configs."));
3276
+ }
3277
+ function runPackEnable(projectRoot, packName) {
3278
+ const raw = readConfigRaw(projectRoot);
3279
+ const { list, match } = parseDisabledFromRaw(raw);
3280
+ if (!list.includes(packName)) {
3281
+ console.log(chalk7.dim(`Pack "${packName}" is not disabled.`));
3282
+ return;
3283
+ }
3284
+ const newList = list.filter((n) => n !== packName);
3285
+ const updated = writeDisabled(raw, newList, match);
3286
+ const filepath = resolve24(projectRoot, CONFIG_FILENAME);
3287
+ writeFileSync12(filepath, updated);
3288
+ console.log(chalk7.green(`Enabled pack "${packName}".`));
3289
+ console.log(chalk7.dim("Run 'agentpacks generate' to regenerate configs."));
3290
+ }
3291
+
3292
+ // src/cli/pack/list.ts
3293
+ init_config();
3294
+ import chalk8 from "chalk";
3295
+ function runPackList(projectRoot) {
3296
+ const config = loadWorkspaceConfig(projectRoot);
3297
+ const loader = new PackLoader(projectRoot, config);
3298
+ const { packs, warnings } = loader.loadAll();
3299
+ const disabledSet = new Set(config.disabled);
3300
+ for (const w of warnings) {
3301
+ console.log(chalk8.yellow(` warn: ${w}`));
3302
+ }
3303
+ if (packs.length === 0 && config.packs.length === 0) {
3304
+ console.log(chalk8.dim("No packs configured. Run 'agentpacks init' to get started."));
3305
+ return;
3306
+ }
3307
+ console.log(chalk8.bold(`Active packs:
3308
+ `));
3309
+ for (const pack of packs) {
3310
+ const m = pack.manifest;
3311
+ const features = [];
3312
+ if (pack.rules.length > 0)
3313
+ features.push(`${pack.rules.length} rules`);
3314
+ if (pack.commands.length > 0)
3315
+ features.push(`${pack.commands.length} commands`);
3316
+ if (pack.agents.length > 0)
3317
+ features.push(`${pack.agents.length} agents`);
3318
+ if (pack.skills.length > 0)
3319
+ features.push(`${pack.skills.length} skills`);
3320
+ if (pack.hooks)
3321
+ features.push("hooks");
3322
+ if (pack.plugins.length > 0)
3323
+ features.push(`${pack.plugins.length} plugins`);
3324
+ if (pack.mcp)
3325
+ features.push(`${Object.keys(pack.mcp.servers).length} MCP servers`);
3326
+ if (pack.ignore)
3327
+ features.push("ignore");
3328
+ const status = disabledSet.has(m.name) ? chalk8.red("[disabled]") : chalk8.green("[active]");
3329
+ console.log(` ${status} ${chalk8.bold(m.name)} v${m.version}`);
3330
+ if (m.description) {
3331
+ console.log(` ${chalk8.dim(m.description)}`);
3332
+ }
3333
+ if (features.length > 0) {
3334
+ console.log(` ${chalk8.dim(features.join(", "))}`);
3335
+ }
3336
+ console.log();
3337
+ }
3338
+ for (const ref of config.disabled) {
3339
+ if (!packs.some((p) => p.manifest.name === ref)) {
3340
+ console.log(` ${chalk8.red("[disabled]")} ${chalk8.dim(ref)}`);
3341
+ }
3342
+ }
3343
+ }
3344
+
3345
+ // src/cli/pack/validate.ts
3346
+ init_config();
3347
+ import { existsSync as existsSync19 } from "fs";
3348
+ import { resolve as resolve25, join as join23 } from "path";
3349
+ import chalk9 from "chalk";
3350
+ function runPackValidate(projectRoot) {
3351
+ const config = loadWorkspaceConfig(projectRoot);
3352
+ let hasErrors = false;
3353
+ for (const packRef of config.packs) {
3354
+ const packDir = resolvePackDir(projectRoot, packRef);
3355
+ console.log(chalk9.bold(`
3356
+ Validating pack: ${packRef}`));
3357
+ if (!packDir || !existsSync19(packDir)) {
3358
+ console.log(chalk9.red(` ERROR: Pack directory not found: ${packRef}`));
3359
+ hasErrors = true;
3360
+ continue;
3361
+ }
3362
+ const packJsonPath = resolve25(packDir, "pack.json");
3363
+ if (!existsSync19(packJsonPath)) {
3364
+ console.log(chalk9.yellow(" warn: No pack.json found. Name will be inferred from directory."));
3365
+ } else {
3366
+ try {
3367
+ loadPackManifest(packDir);
3368
+ console.log(chalk9.green(" pack.json: valid"));
3369
+ } catch (err) {
3370
+ const message = err instanceof Error ? err.message : String(err);
3371
+ console.log(chalk9.red(` ERROR pack.json: ${message}`));
3372
+ hasErrors = true;
3373
+ }
3374
+ }
3375
+ const subdirs = ["rules", "commands", "agents", "skills"];
3376
+ for (const sub of subdirs) {
3377
+ const subDir = join23(packDir, sub);
3378
+ if (existsSync19(subDir)) {
3379
+ if (sub === "skills") {
3380
+ const skillDirs = listDirs(subDir);
3381
+ for (const skillDir of skillDirs) {
3382
+ const skillMd = join23(skillDir, "SKILL.md");
3383
+ if (!existsSync19(skillMd)) {
3384
+ console.log(chalk9.yellow(` warn: skills/${skillDir.split("/").pop()} missing SKILL.md`));
3385
+ }
3386
+ }
3387
+ console.log(chalk9.green(` ${sub}/: ${skillDirs.length} skill(s)`));
3388
+ } else {
3389
+ const files = listFiles(subDir, { extension: ".md" });
3390
+ console.log(chalk9.green(` ${sub}/: ${files.length} file(s)`));
3391
+ }
3392
+ }
3393
+ }
3394
+ const optionalFiles = ["mcp.json", "ignore", ".aiignore"];
3395
+ for (const file of optionalFiles) {
3396
+ if (existsSync19(join23(packDir, file))) {
3397
+ console.log(chalk9.green(` ${file}: present`));
3398
+ }
3399
+ }
3400
+ const hooksJson = join23(packDir, "hooks", "hooks.json");
3401
+ if (existsSync19(hooksJson)) {
3402
+ console.log(chalk9.green(" hooks/hooks.json: present"));
3403
+ }
3404
+ const pluginsDir = join23(packDir, "plugins");
3405
+ if (existsSync19(pluginsDir)) {
3406
+ const pluginFiles = [
3407
+ ...listFiles(pluginsDir, { extension: ".ts" }),
3408
+ ...listFiles(pluginsDir, { extension: ".js" })
3409
+ ];
3410
+ console.log(chalk9.green(` plugins/: ${pluginFiles.length} file(s)`));
3411
+ }
3412
+ }
3413
+ console.log();
3414
+ if (hasErrors) {
3415
+ console.log(chalk9.red("Validation failed with errors."));
3416
+ process.exit(1);
3417
+ } else {
3418
+ console.log(chalk9.green("All packs valid."));
3419
+ }
3420
+ }
3421
+ function resolvePackDir(projectRoot, packRef) {
3422
+ if (packRef.startsWith("./") || packRef.startsWith("../")) {
3423
+ return resolve25(projectRoot, packRef);
3424
+ }
3425
+ return resolve25(projectRoot, packRef);
3426
+ }
3427
+
3428
+ // src/index.ts
3429
+ import { Command } from "commander";
3430
+ import { resolve as resolve26 } from "path";
3431
+ var program = new Command;
3432
+ program.name("agentpacks").description("Composable AI agent configuration manager. Pack-based rules, commands, skills, hooks, and MCP sync across OpenCode, Cursor, Claude Code, Codex, Gemini, Copilot, and more.").version("0.1.0");
3433
+ program.command("init").description("Initialize agentpacks in the current project").action(() => {
3434
+ runInit(resolve26("."));
3435
+ });
3436
+ program.command("generate").description("Generate tool configs from active packs").option("-t, --targets <targets>", "Comma-separated target IDs or '*' for all").option("-f, --features <features>", "Comma-separated feature IDs or '*' for all").option("--dry-run", "Preview changes without writing files").option("--diff", "Show diff of what would change").option("-v, --verbose", "Enable verbose logging").action((options) => {
3437
+ runGenerate(resolve26("."), options);
3438
+ });
3439
+ program.command("install").description("Install remote packs (git, npm) into local cache").option("--update", "Re-resolve all refs (ignore lockfile)").option("--frozen", "Fail if lockfile is missing or incomplete").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
3440
+ await runInstall(resolve26("."), options);
3441
+ });
3442
+ program.command("export").description("Export packs to target-native format (e.g. Cursor plugin)").requiredOption("--format <format>", "Export format (cursor-plugin)").option("-o, --output <dir>", "Output directory").option("--pack <name>", "Export a specific pack only").option("-v, --verbose", "Enable verbose logging").action((options) => {
3443
+ runExport(resolve26("."), options);
3444
+ });
3445
+ program.command("import").description("Import from existing tool configurations").requiredOption("--from <source>", "Import source (rulesync)").option("-o, --output <dir>", "Output pack directory").action((options) => {
3446
+ runImport(resolve26("."), options);
3447
+ });
3448
+ var packCmd = program.command("pack").description("Manage packs");
3449
+ packCmd.command("create <name>").description("Create a new pack scaffold").action((name) => {
3450
+ runPackCreate(resolve26("."), name);
3451
+ });
3452
+ packCmd.command("list").description("List all configured packs and their status").action(() => {
3453
+ runPackList(resolve26("."));
3454
+ });
3455
+ packCmd.command("validate").description("Validate all configured packs").action(() => {
3456
+ runPackValidate(resolve26("."));
3457
+ });
3458
+ packCmd.command("enable <name>").description("Enable a previously disabled pack").action((name) => {
3459
+ runPackEnable(resolve26("."), name);
3460
+ });
3461
+ packCmd.command("disable <name>").description("Disable a pack without removing it").action((name) => {
3462
+ runPackDisable(resolve26("."), name);
3463
+ });
3464
+ program.parse();