agentpacks 1.7.5 → 1.7.8

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 (133) hide show
  1. package/README.md +69 -742
  2. package/dist/api.d.ts +15 -15
  3. package/dist/api.js +2706 -2706
  4. package/dist/cli/export-cmd.js +364 -364
  5. package/dist/cli/generate.js +1409 -1409
  6. package/dist/cli/import-cmd.js +249 -249
  7. package/dist/cli/info.js +31 -31
  8. package/dist/cli/init.js +6 -6
  9. package/dist/cli/install.js +141 -141
  10. package/dist/cli/login.js +31 -31
  11. package/dist/cli/models-explain.js +514 -514
  12. package/dist/cli/pack/create.js +6 -6
  13. package/dist/cli/pack/enable.js +2 -2
  14. package/dist/cli/pack/list.js +362 -362
  15. package/dist/cli/pack/validate.js +119 -119
  16. package/dist/cli/publish.js +42 -42
  17. package/dist/cli/search.js +31 -31
  18. package/dist/core/config.js +3 -3
  19. package/dist/core/feature-merger.d.ts +5 -5
  20. package/dist/core/feature-merger.js +4 -4
  21. package/dist/core/index.d.ts +4 -4
  22. package/dist/core/index.js +633 -633
  23. package/dist/core/lockfile.js +1 -1
  24. package/dist/core/metarepo.js +3 -3
  25. package/dist/core/pack-loader.d.ts +6 -6
  26. package/dist/core/pack-loader.js +362 -362
  27. package/dist/core/profile-resolver.d.ts +1 -1
  28. package/dist/exporters/cursor-plugin.d.ts +12 -0
  29. package/dist/exporters/cursor-plugin.js +46 -46
  30. package/dist/exporters/index.d.ts +1 -1
  31. package/dist/exporters/index.js +46 -46
  32. package/dist/features/agents.js +4 -4
  33. package/dist/features/commands.js +4 -4
  34. package/dist/features/hooks.js +4 -4
  35. package/dist/features/index.d.ts +8 -8
  36. package/dist/features/index.js +350 -350
  37. package/dist/features/mcp.js +4 -4
  38. package/dist/features/models.js +4 -4
  39. package/dist/features/plugins.js +5 -5
  40. package/dist/features/rules.js +4 -4
  41. package/dist/features/skills.js +5 -5
  42. package/dist/importers/claude-code.js +6 -6
  43. package/dist/importers/cursor.js +7 -7
  44. package/dist/importers/opencode.js +7 -7
  45. package/dist/importers/rulesync.js +7 -7
  46. package/dist/index.js +2674 -2674
  47. package/dist/node/api.js +2706 -2706
  48. package/dist/node/cli/export-cmd.js +364 -364
  49. package/dist/node/cli/generate.js +1409 -1409
  50. package/dist/node/cli/import-cmd.js +249 -249
  51. package/dist/node/cli/info.js +31 -31
  52. package/dist/node/cli/init.js +6 -6
  53. package/dist/node/cli/install.js +141 -141
  54. package/dist/node/cli/login.js +31 -31
  55. package/dist/node/cli/models-explain.js +514 -514
  56. package/dist/node/cli/pack/create.js +6 -6
  57. package/dist/node/cli/pack/enable.js +2 -2
  58. package/dist/node/cli/pack/list.js +362 -362
  59. package/dist/node/cli/pack/validate.js +119 -119
  60. package/dist/node/cli/publish.js +42 -42
  61. package/dist/node/cli/search.js +31 -31
  62. package/dist/node/core/config.js +3 -3
  63. package/dist/node/core/feature-merger.js +4 -4
  64. package/dist/node/core/index.js +633 -633
  65. package/dist/node/core/lockfile.js +1 -1
  66. package/dist/node/core/metarepo.js +3 -3
  67. package/dist/node/core/pack-loader.js +362 -362
  68. package/dist/node/exporters/cursor-plugin.js +46 -46
  69. package/dist/node/exporters/index.js +46 -46
  70. package/dist/node/features/agents.js +4 -4
  71. package/dist/node/features/commands.js +4 -4
  72. package/dist/node/features/hooks.js +4 -4
  73. package/dist/node/features/index.js +350 -350
  74. package/dist/node/features/mcp.js +4 -4
  75. package/dist/node/features/models.js +4 -4
  76. package/dist/node/features/plugins.js +5 -5
  77. package/dist/node/features/rules.js +4 -4
  78. package/dist/node/features/skills.js +5 -5
  79. package/dist/node/importers/claude-code.js +6 -6
  80. package/dist/node/importers/cursor.js +7 -7
  81. package/dist/node/importers/opencode.js +7 -7
  82. package/dist/node/importers/rulesync.js +7 -7
  83. package/dist/node/index.js +2674 -2674
  84. package/dist/node/sources/git.js +2 -2
  85. package/dist/node/sources/index.js +138 -138
  86. package/dist/node/sources/local.js +1 -1
  87. package/dist/node/sources/npm.js +3 -3
  88. package/dist/node/sources/registry.js +35 -35
  89. package/dist/node/targets/additional-targets.js +43 -43
  90. package/dist/node/targets/agents-md.js +4 -4
  91. package/dist/node/targets/claude-code.js +86 -86
  92. package/dist/node/targets/codex-cli.js +6 -6
  93. package/dist/node/targets/copilot.js +46 -46
  94. package/dist/node/targets/cursor.js +68 -68
  95. package/dist/node/targets/gemini-cli.js +25 -25
  96. package/dist/node/targets/generic-md-target.js +43 -43
  97. package/dist/node/targets/index.js +911 -911
  98. package/dist/node/targets/mistral-vibe.js +46 -46
  99. package/dist/node/targets/opencode.js +68 -68
  100. package/dist/node/targets/registry.js +911 -911
  101. package/dist/node/utils/credentials.js +2 -2
  102. package/dist/node/utils/filesystem.js +4 -4
  103. package/dist/node/utils/global.js +1 -1
  104. package/dist/node/utils/tarball.js +2 -2
  105. package/dist/sources/git.js +2 -2
  106. package/dist/sources/index.d.ts +6 -6
  107. package/dist/sources/index.js +138 -138
  108. package/dist/sources/local.js +1 -1
  109. package/dist/sources/npm.d.ts +3 -0
  110. package/dist/sources/npm.js +3 -3
  111. package/dist/sources/registry.js +35 -35
  112. package/dist/targets/additional-targets.js +43 -43
  113. package/dist/targets/agents-md.js +4 -4
  114. package/dist/targets/claude-code.js +86 -86
  115. package/dist/targets/codex-cli.js +6 -6
  116. package/dist/targets/copilot.js +46 -46
  117. package/dist/targets/cursor.js +68 -68
  118. package/dist/targets/gemini-cli.js +25 -25
  119. package/dist/targets/generic-md-target.js +43 -43
  120. package/dist/targets/index.d.ts +6 -6
  121. package/dist/targets/index.js +911 -911
  122. package/dist/targets/mistral-vibe.js +46 -46
  123. package/dist/targets/opencode.js +68 -68
  124. package/dist/targets/registry.js +911 -911
  125. package/dist/utils/credentials.js +2 -2
  126. package/dist/utils/filesystem.js +4 -4
  127. package/dist/utils/global.d.ts +3 -0
  128. package/dist/utils/global.js +1 -1
  129. package/dist/utils/tarball.js +2 -2
  130. package/package.json +5 -5
  131. package/templates/pack/models.json +36 -36
  132. package/templates/pack/pack.json +8 -8
  133. package/templates/workspace/agentpacks.jsonc +24 -24
@@ -5,13 +5,13 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  import {
6
6
  existsSync,
7
7
  mkdirSync,
8
- readFileSync,
9
- writeFileSync,
10
8
  readdirSync,
9
+ readFileSync,
11
10
  rmSync,
12
- statSync
11
+ statSync,
12
+ writeFileSync
13
13
  } from "fs";
14
- import { dirname, relative, join } from "path";
14
+ import { dirname, join, relative } from "path";
15
15
  var GENERATED_HEADER_MD = "<!-- Generated by agentpacks. DO NOT EDIT. -->";
16
16
  var GENERATED_HEADER_JSON = "// Generated by agentpacks. DO NOT EDIT.";
17
17
  var GENERATED_HEADER_JS = "// Generated by agentpacks. DO NOT EDIT.";
@@ -111,6 +111,175 @@ function getHeader(type) {
111
111
  }
112
112
  }
113
113
 
114
+ // src/features/models.ts
115
+ import { join as join2 } from "path";
116
+ import { z } from "zod";
117
+ var SECRET_PATTERNS = [
118
+ /["']api[_-]?key["']\s*:/i,
119
+ /["']apiKey["']\s*:/i,
120
+ /["']secret["']\s*:/i,
121
+ /["']password["']\s*:/i,
122
+ /["'](?:auth_token|access_token|bearer_token)["']\s*:/i,
123
+ /["']private[_-]?key["']\s*:/i,
124
+ /-----BEGIN\s+(RSA|EC|DSA|OPENSSH|PGP)\s+PRIVATE\s+KEY-----/,
125
+ /sk-[a-zA-Z0-9]{20,}/,
126
+ /Bearer\s+[a-zA-Z0-9._-]{20,}/
127
+ ];
128
+ var AgentModelSchema = z.object({
129
+ model: z.string(),
130
+ temperature: z.number().min(0).max(2).optional(),
131
+ top_p: z.number().min(0).max(1).optional()
132
+ });
133
+ var ModelProfileSchema = z.object({
134
+ extends: z.string().optional(),
135
+ description: z.string().optional(),
136
+ default: z.string().optional(),
137
+ small: z.string().optional(),
138
+ agents: z.record(z.string(), AgentModelSchema).optional()
139
+ });
140
+ var RoutingConditionSchema = z.object({
141
+ complexity: z.enum(["low", "medium", "high", "critical"]).optional().describe("Task complexity level"),
142
+ urgency: z.enum(["low", "normal", "high"]).optional().describe("Time sensitivity"),
143
+ budget: z.enum(["minimal", "standard", "premium"]).optional().describe("Cost/token budget tier"),
144
+ contextWindowNeed: z.enum(["small", "medium", "large", "max"]).optional().describe("Required context window size"),
145
+ toolUseIntensity: z.enum(["none", "light", "heavy"]).optional().describe("Expected tool/function calling intensity")
146
+ });
147
+ var RoutingRuleSchema = z.object({
148
+ when: z.record(z.string(), z.string()),
149
+ use: z.string(),
150
+ description: z.string().optional(),
151
+ priority: z.number().optional()
152
+ });
153
+ var ProviderModelSchema = z.object({
154
+ options: z.record(z.string(), z.unknown()).optional(),
155
+ variants: z.record(z.string(), z.record(z.string(), z.unknown())).optional()
156
+ });
157
+ var ProviderConfigSchema = z.object({
158
+ options: z.record(z.string(), z.unknown()).optional(),
159
+ models: z.record(z.string(), ProviderModelSchema).optional()
160
+ });
161
+ var ModelsSchema = z.object({
162
+ default: z.string().optional(),
163
+ small: z.string().optional(),
164
+ agents: z.record(z.string(), AgentModelSchema).optional(),
165
+ profiles: z.record(z.string(), ModelProfileSchema).optional(),
166
+ providers: z.record(z.string(), ProviderConfigSchema).optional(),
167
+ routing: z.array(RoutingRuleSchema).optional(),
168
+ overrides: z.record(z.string(), z.object({
169
+ default: z.string().optional(),
170
+ small: z.string().optional(),
171
+ agents: z.record(z.string(), AgentModelSchema).optional()
172
+ })).optional()
173
+ });
174
+ function parseModels(packDir, packName) {
175
+ const modelsPath = join2(packDir, "models.json");
176
+ const raw = readJsonOrNull(modelsPath);
177
+ if (!raw)
178
+ return null;
179
+ const parsed = ModelsSchema.parse(raw);
180
+ return {
181
+ packName,
182
+ sourcePath: modelsPath,
183
+ config: parsed
184
+ };
185
+ }
186
+ function mergeModelsConfigs(configs) {
187
+ const warnings = [];
188
+ const result = {};
189
+ for (const entry of configs) {
190
+ const { config, packName } = entry;
191
+ if (config.default !== undefined && result.default === undefined) {
192
+ result.default = config.default;
193
+ } else if (config.default !== undefined && result.default !== undefined) {
194
+ warnings.push(`Models "default" from pack "${packName}" skipped (already defined).`);
195
+ }
196
+ if (config.small !== undefined && result.small === undefined) {
197
+ result.small = config.small;
198
+ } else if (config.small !== undefined && result.small !== undefined) {
199
+ warnings.push(`Models "small" from pack "${packName}" skipped (already defined).`);
200
+ }
201
+ if (config.agents) {
202
+ if (!result.agents)
203
+ result.agents = {};
204
+ for (const [name, assignment] of Object.entries(config.agents)) {
205
+ if (name in result.agents) {
206
+ warnings.push(`Models agent "${name}" from pack "${packName}" skipped (already defined).`);
207
+ continue;
208
+ }
209
+ result.agents[name] = assignment;
210
+ }
211
+ }
212
+ if (config.profiles) {
213
+ if (!result.profiles)
214
+ result.profiles = {};
215
+ for (const [name, profile] of Object.entries(config.profiles)) {
216
+ if (name in result.profiles) {
217
+ warnings.push(`Models profile "${name}" from pack "${packName}" skipped (already defined).`);
218
+ continue;
219
+ }
220
+ result.profiles[name] = profile;
221
+ }
222
+ }
223
+ if (config.providers) {
224
+ if (!result.providers)
225
+ result.providers = {};
226
+ for (const [providerName, providerConfig] of Object.entries(config.providers)) {
227
+ if (!(providerName in result.providers)) {
228
+ result.providers[providerName] = providerConfig;
229
+ } else {
230
+ const existing = result.providers[providerName];
231
+ if (!existing) {
232
+ result.providers[providerName] = providerConfig;
233
+ continue;
234
+ }
235
+ if (providerConfig.options) {
236
+ existing.options = {
237
+ ...providerConfig.options,
238
+ ...existing.options
239
+ };
240
+ }
241
+ if (providerConfig.models) {
242
+ if (!existing.models)
243
+ existing.models = {};
244
+ for (const [modelName, modelConfig] of Object.entries(providerConfig.models)) {
245
+ if (!(modelName in existing.models)) {
246
+ existing.models[modelName] = modelConfig;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ }
252
+ }
253
+ if (config.routing) {
254
+ if (!result.routing)
255
+ result.routing = [];
256
+ result.routing.push(...config.routing);
257
+ }
258
+ if (config.overrides) {
259
+ if (!result.overrides)
260
+ result.overrides = {};
261
+ for (const [targetId, override] of Object.entries(config.overrides)) {
262
+ if (targetId in result.overrides) {
263
+ warnings.push(`Models override for target "${targetId}" from pack "${packName}" skipped (already defined).`);
264
+ continue;
265
+ }
266
+ result.overrides[targetId] = override;
267
+ }
268
+ }
269
+ }
270
+ return { config: result, warnings };
271
+ }
272
+ function scanModelsForSecrets(config) {
273
+ const warnings = [];
274
+ const json = JSON.stringify(config);
275
+ for (const pattern of SECRET_PATTERNS) {
276
+ if (pattern.test(json)) {
277
+ warnings.push(`Potential secret detected in models.json matching pattern: ${pattern.source}`);
278
+ }
279
+ }
280
+ return warnings;
281
+ }
282
+
114
283
  // src/utils/frontmatter.ts
115
284
  import matter from "gray-matter";
116
285
  function parseFrontmatter(source) {
@@ -129,38 +298,32 @@ function serializeFrontmatter(data, content) {
129
298
  return matter.stringify(content, filtered);
130
299
  }
131
300
 
132
- // src/features/rules.ts
301
+ // src/features/agents.ts
133
302
  import { readFileSync as readFileSync2 } from "fs";
134
303
  import { basename } from "path";
135
- function parseRules(rulesDir, packName) {
136
- const files = listFiles(rulesDir, { extension: ".md" });
137
- return files.map((filepath) => parseRuleFile(filepath, packName));
304
+ function parseAgents(agentsDir, packName) {
305
+ const files = listFiles(agentsDir, { extension: ".md" });
306
+ return files.map((filepath) => parseAgentFile(filepath, packName));
138
307
  }
139
- function parseRuleFile(filepath, packName) {
308
+ function parseAgentFile(filepath, packName) {
140
309
  const raw = readFileSync2(filepath, "utf-8");
141
310
  const { data, content } = parseFrontmatter(raw);
142
311
  return {
143
- name: basename(filepath, ".md"),
312
+ name: data.name ?? basename(filepath, ".md"),
144
313
  sourcePath: filepath,
145
314
  packName,
146
315
  meta: data,
147
316
  content
148
317
  };
149
318
  }
150
- function ruleMatchesTarget(rule, targetId) {
151
- const { targets } = rule.meta;
319
+ function agentMatchesTarget(agent, targetId) {
320
+ const { targets } = agent.meta;
152
321
  if (!targets || targets === "*")
153
322
  return true;
154
323
  if (Array.isArray(targets) && targets.includes("*"))
155
324
  return true;
156
325
  return Array.isArray(targets) && targets.includes(targetId);
157
326
  }
158
- function getRootRules(rules) {
159
- return rules.filter((r) => r.meta.root === true);
160
- }
161
- function getDetailRules(rules) {
162
- return rules.filter((r) => r.meta.root !== true);
163
- }
164
327
 
165
328
  // src/features/commands.ts
166
329
  import { readFileSync as readFileSync3 } from "fs";
@@ -189,54 +352,187 @@ function commandMatchesTarget(cmd, targetId) {
189
352
  return Array.isArray(targets) && targets.includes(targetId);
190
353
  }
191
354
 
192
- // src/features/agents.ts
193
- import { readFileSync as readFileSync4 } from "fs";
194
- import { basename as basename3 } from "path";
195
- function parseAgents(agentsDir, packName) {
196
- const files = listFiles(agentsDir, { extension: ".md" });
197
- return files.map((filepath) => parseAgentFile(filepath, packName));
198
- }
199
- function parseAgentFile(filepath, packName) {
200
- const raw = readFileSync4(filepath, "utf-8");
201
- const { data, content } = parseFrontmatter(raw);
355
+ // src/features/hooks.ts
356
+ import { join as join3 } from "path";
357
+ var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
358
+ function parseHooks(packDir, packName) {
359
+ const hooksPath = join3(packDir, "hooks", "hooks.json");
360
+ const raw = readJsonOrNull(hooksPath);
361
+ if (!raw)
362
+ return null;
363
+ const shared = raw.hooks ?? {};
364
+ const targetOverrides = {};
365
+ for (const key of TARGET_OVERRIDE_KEYS) {
366
+ const override = raw[key];
367
+ if (override && typeof override === "object" && "hooks" in override && override.hooks) {
368
+ targetOverrides[key] = override.hooks;
369
+ }
370
+ }
202
371
  return {
203
- name: data.name ?? basename3(filepath, ".md"),
204
- sourcePath: filepath,
205
372
  packName,
206
- meta: data,
207
- content
373
+ sourcePath: hooksPath,
374
+ version: raw.version,
375
+ shared,
376
+ targetOverrides
208
377
  };
209
378
  }
210
- function agentMatchesTarget(agent, targetId) {
211
- const { targets } = agent.meta;
212
- if (!targets || targets === "*")
213
- return true;
214
- if (Array.isArray(targets) && targets.includes("*"))
215
- return true;
216
- return Array.isArray(targets) && targets.includes(targetId);
379
+ function resolveHooksForTarget(hooks, targetId) {
380
+ const merged = {};
381
+ for (const [event, entries] of Object.entries(hooks.shared)) {
382
+ merged[event] = [...entries];
383
+ }
384
+ const overrides = hooks.targetOverrides[targetId];
385
+ if (overrides) {
386
+ for (const [event, entries] of Object.entries(overrides)) {
387
+ merged[event] = [...merged[event] ?? [], ...entries];
388
+ }
389
+ }
390
+ return merged;
217
391
  }
218
392
 
219
- // src/features/skills.ts
220
- import { readFileSync as readFileSync5, existsSync as existsSync2 } from "fs";
221
- import { basename as basename4, join as join2 } from "path";
222
- var SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
223
- var SKILL_NAME_MAX_LENGTH = 64;
224
- function parseSkills(skillsDir, packName) {
225
- const dirs = listDirs(skillsDir);
226
- const skills = [];
227
- for (const dir of dirs) {
228
- const skillMd = join2(dir, "SKILL.md");
229
- if (existsSync2(skillMd)) {
230
- skills.push(parseSkillFile(skillMd, dir, packName));
393
+ // src/features/ignore.ts
394
+ import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
395
+ import { join as join4 } from "path";
396
+ var IGNORE_FILES = ["ignore", ".aiignore"];
397
+ function parseIgnore(packDir, packName) {
398
+ for (const filename of IGNORE_FILES) {
399
+ const filepath = join4(packDir, filename);
400
+ if (existsSync2(filepath)) {
401
+ const raw = readFileSync4(filepath, "utf-8");
402
+ const patterns = parseIgnoreContent(raw);
403
+ return {
404
+ packName,
405
+ sourcePath: filepath,
406
+ patterns
407
+ };
408
+ }
409
+ }
410
+ return null;
411
+ }
412
+ function parseIgnoreContent(content) {
413
+ return content.split(`
414
+ `).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
415
+ }
416
+ function mergeIgnorePatterns(configs) {
417
+ const seen = new Set;
418
+ const result = [];
419
+ for (const config of configs) {
420
+ for (const pattern of config.patterns) {
421
+ if (!seen.has(pattern)) {
422
+ seen.add(pattern);
423
+ result.push(pattern);
424
+ }
425
+ }
426
+ }
427
+ return result;
428
+ }
429
+
430
+ // src/features/mcp.ts
431
+ import { join as join5 } from "path";
432
+ function parseMcp(packDir, packName) {
433
+ const mcpPath = join5(packDir, "mcp.json");
434
+ const raw = readJsonOrNull(mcpPath);
435
+ if (!raw?.mcpServers)
436
+ return null;
437
+ return {
438
+ packName,
439
+ sourcePath: mcpPath,
440
+ servers: raw.mcpServers
441
+ };
442
+ }
443
+ function mergeMcpConfigs(configs) {
444
+ const servers = {};
445
+ const warnings = [];
446
+ for (const config of configs) {
447
+ for (const [name, entry] of Object.entries(config.servers)) {
448
+ if (name in servers) {
449
+ warnings.push(`MCP server "${name}" from pack "${config.packName}" skipped (already defined).`);
450
+ continue;
451
+ }
452
+ servers[name] = entry;
453
+ }
454
+ }
455
+ return { servers, warnings };
456
+ }
457
+
458
+ // src/features/plugins.ts
459
+ import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
460
+ import { basename as basename3, join as join6 } from "path";
461
+ function parsePlugins(packDir, packName) {
462
+ const pluginsDir = join6(packDir, "plugins");
463
+ if (!existsSync3(pluginsDir))
464
+ return [];
465
+ const tsFiles = listFiles(pluginsDir, { extension: ".ts" });
466
+ const jsFiles = listFiles(pluginsDir, { extension: ".js" });
467
+ const allFiles = [...tsFiles, ...jsFiles];
468
+ return allFiles.map((filepath) => parsePluginFile(filepath, packName));
469
+ }
470
+ function parsePluginFile(filepath, packName) {
471
+ const content = readFileSync5(filepath, "utf-8");
472
+ const ext = filepath.endsWith(".ts") ? "ts" : "js";
473
+ return {
474
+ name: basename3(filepath, `.${ext}`),
475
+ sourcePath: filepath,
476
+ packName,
477
+ content,
478
+ extension: ext
479
+ };
480
+ }
481
+
482
+ // src/features/rules.ts
483
+ import { readFileSync as readFileSync6 } from "fs";
484
+ import { basename as basename4 } from "path";
485
+ function parseRules(rulesDir, packName) {
486
+ const files = listFiles(rulesDir, { extension: ".md" });
487
+ return files.map((filepath) => parseRuleFile(filepath, packName));
488
+ }
489
+ function parseRuleFile(filepath, packName) {
490
+ const raw = readFileSync6(filepath, "utf-8");
491
+ const { data, content } = parseFrontmatter(raw);
492
+ return {
493
+ name: basename4(filepath, ".md"),
494
+ sourcePath: filepath,
495
+ packName,
496
+ meta: data,
497
+ content
498
+ };
499
+ }
500
+ function ruleMatchesTarget(rule, targetId) {
501
+ const { targets } = rule.meta;
502
+ if (!targets || targets === "*")
503
+ return true;
504
+ if (Array.isArray(targets) && targets.includes("*"))
505
+ return true;
506
+ return Array.isArray(targets) && targets.includes(targetId);
507
+ }
508
+ function getRootRules(rules) {
509
+ return rules.filter((r) => r.meta.root === true);
510
+ }
511
+ function getDetailRules(rules) {
512
+ return rules.filter((r) => r.meta.root !== true);
513
+ }
514
+
515
+ // src/features/skills.ts
516
+ import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
517
+ import { basename as basename5, join as join7 } from "path";
518
+ var SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
519
+ var SKILL_NAME_MAX_LENGTH = 64;
520
+ function parseSkills(skillsDir, packName) {
521
+ const dirs = listDirs(skillsDir);
522
+ const skills = [];
523
+ for (const dir of dirs) {
524
+ const skillMd = join7(dir, "SKILL.md");
525
+ if (existsSync4(skillMd)) {
526
+ skills.push(parseSkillFile(skillMd, dir, packName));
231
527
  }
232
528
  }
233
529
  return skills;
234
530
  }
235
531
  function parseSkillFile(filepath, skillDir, packName) {
236
- const raw = readFileSync5(filepath, "utf-8");
532
+ const raw = readFileSync7(filepath, "utf-8");
237
533
  const { data, content } = parseFrontmatter(raw);
238
534
  return {
239
- name: data.name ?? basename4(skillDir),
535
+ name: data.name ?? basename5(skillDir),
240
536
  sourcePath: filepath,
241
537
  sourceDir: skillDir,
242
538
  packName,
@@ -272,7 +568,7 @@ function normalizeImportedSkillMarkdown(source, skillName) {
272
568
  }
273
569
  function validateAgentSkillsFrontmatter(skill) {
274
570
  const errors = [];
275
- const dirName = basename4(skill.sourceDir);
571
+ const dirName = basename5(skill.sourceDir);
276
572
  const declaredName = skill.meta.name;
277
573
  if (typeof declaredName !== "string" || declaredName.trim().length === 0) {
278
574
  errors.push('Missing required frontmatter field "name".');
@@ -305,302 +601,6 @@ function skillMatchesTarget(skill, targetId) {
305
601
  return true;
306
602
  return Array.isArray(targets) && targets.includes(targetId);
307
603
  }
308
-
309
- // src/features/hooks.ts
310
- import { join as join3 } from "path";
311
- var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
312
- function parseHooks(packDir, packName) {
313
- const hooksPath = join3(packDir, "hooks", "hooks.json");
314
- const raw = readJsonOrNull(hooksPath);
315
- if (!raw)
316
- return null;
317
- const shared = raw.hooks ?? {};
318
- const targetOverrides = {};
319
- for (const key of TARGET_OVERRIDE_KEYS) {
320
- const override = raw[key];
321
- if (override && typeof override === "object" && "hooks" in override && override.hooks) {
322
- targetOverrides[key] = override.hooks;
323
- }
324
- }
325
- return {
326
- packName,
327
- sourcePath: hooksPath,
328
- version: raw.version,
329
- shared,
330
- targetOverrides
331
- };
332
- }
333
- function resolveHooksForTarget(hooks, targetId) {
334
- const merged = {};
335
- for (const [event, entries] of Object.entries(hooks.shared)) {
336
- merged[event] = [...entries];
337
- }
338
- const overrides = hooks.targetOverrides[targetId];
339
- if (overrides) {
340
- for (const [event, entries] of Object.entries(overrides)) {
341
- merged[event] = [...merged[event] ?? [], ...entries];
342
- }
343
- }
344
- return merged;
345
- }
346
-
347
- // src/features/plugins.ts
348
- import { readFileSync as readFileSync6, existsSync as existsSync3 } from "fs";
349
- import { basename as basename5, join as join4 } from "path";
350
- function parsePlugins(packDir, packName) {
351
- const pluginsDir = join4(packDir, "plugins");
352
- if (!existsSync3(pluginsDir))
353
- return [];
354
- const tsFiles = listFiles(pluginsDir, { extension: ".ts" });
355
- const jsFiles = listFiles(pluginsDir, { extension: ".js" });
356
- const allFiles = [...tsFiles, ...jsFiles];
357
- return allFiles.map((filepath) => parsePluginFile(filepath, packName));
358
- }
359
- function parsePluginFile(filepath, packName) {
360
- const content = readFileSync6(filepath, "utf-8");
361
- const ext = filepath.endsWith(".ts") ? "ts" : "js";
362
- return {
363
- name: basename5(filepath, `.${ext}`),
364
- sourcePath: filepath,
365
- packName,
366
- content,
367
- extension: ext
368
- };
369
- }
370
-
371
- // src/features/mcp.ts
372
- import { join as join5 } from "path";
373
- function parseMcp(packDir, packName) {
374
- const mcpPath = join5(packDir, "mcp.json");
375
- const raw = readJsonOrNull(mcpPath);
376
- if (!raw?.mcpServers)
377
- return null;
378
- return {
379
- packName,
380
- sourcePath: mcpPath,
381
- servers: raw.mcpServers
382
- };
383
- }
384
- function mergeMcpConfigs(configs) {
385
- const servers = {};
386
- const warnings = [];
387
- for (const config of configs) {
388
- for (const [name, entry] of Object.entries(config.servers)) {
389
- if (name in servers) {
390
- warnings.push(`MCP server "${name}" from pack "${config.packName}" skipped (already defined).`);
391
- continue;
392
- }
393
- servers[name] = entry;
394
- }
395
- }
396
- return { servers, warnings };
397
- }
398
-
399
- // src/features/ignore.ts
400
- import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
401
- import { join as join6 } from "path";
402
- var IGNORE_FILES = ["ignore", ".aiignore"];
403
- function parseIgnore(packDir, packName) {
404
- for (const filename of IGNORE_FILES) {
405
- const filepath = join6(packDir, filename);
406
- if (existsSync4(filepath)) {
407
- const raw = readFileSync7(filepath, "utf-8");
408
- const patterns = parseIgnoreContent(raw);
409
- return {
410
- packName,
411
- sourcePath: filepath,
412
- patterns
413
- };
414
- }
415
- }
416
- return null;
417
- }
418
- function parseIgnoreContent(content) {
419
- return content.split(`
420
- `).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
421
- }
422
- function mergeIgnorePatterns(configs) {
423
- const seen = new Set;
424
- const result = [];
425
- for (const config of configs) {
426
- for (const pattern of config.patterns) {
427
- if (!seen.has(pattern)) {
428
- seen.add(pattern);
429
- result.push(pattern);
430
- }
431
- }
432
- }
433
- return result;
434
- }
435
-
436
- // src/features/models.ts
437
- import { join as join7 } from "path";
438
- import { z } from "zod";
439
- var SECRET_PATTERNS = [
440
- /["']api[_-]?key["']\s*:/i,
441
- /["']apiKey["']\s*:/i,
442
- /["']secret["']\s*:/i,
443
- /["']password["']\s*:/i,
444
- /["'](?:auth_token|access_token|bearer_token)["']\s*:/i,
445
- /["']private[_-]?key["']\s*:/i,
446
- /-----BEGIN\s+(RSA|EC|DSA|OPENSSH|PGP)\s+PRIVATE\s+KEY-----/,
447
- /sk-[a-zA-Z0-9]{20,}/,
448
- /Bearer\s+[a-zA-Z0-9._-]{20,}/
449
- ];
450
- var AgentModelSchema = z.object({
451
- model: z.string(),
452
- temperature: z.number().min(0).max(2).optional(),
453
- top_p: z.number().min(0).max(1).optional()
454
- });
455
- var ModelProfileSchema = z.object({
456
- extends: z.string().optional(),
457
- description: z.string().optional(),
458
- default: z.string().optional(),
459
- small: z.string().optional(),
460
- agents: z.record(z.string(), AgentModelSchema).optional()
461
- });
462
- var RoutingConditionSchema = z.object({
463
- complexity: z.enum(["low", "medium", "high", "critical"]).optional().describe("Task complexity level"),
464
- urgency: z.enum(["low", "normal", "high"]).optional().describe("Time sensitivity"),
465
- budget: z.enum(["minimal", "standard", "premium"]).optional().describe("Cost/token budget tier"),
466
- contextWindowNeed: z.enum(["small", "medium", "large", "max"]).optional().describe("Required context window size"),
467
- toolUseIntensity: z.enum(["none", "light", "heavy"]).optional().describe("Expected tool/function calling intensity")
468
- });
469
- var RoutingRuleSchema = z.object({
470
- when: z.record(z.string(), z.string()),
471
- use: z.string(),
472
- description: z.string().optional(),
473
- priority: z.number().optional()
474
- });
475
- var ProviderModelSchema = z.object({
476
- options: z.record(z.string(), z.unknown()).optional(),
477
- variants: z.record(z.string(), z.record(z.string(), z.unknown())).optional()
478
- });
479
- var ProviderConfigSchema = z.object({
480
- options: z.record(z.string(), z.unknown()).optional(),
481
- models: z.record(z.string(), ProviderModelSchema).optional()
482
- });
483
- var ModelsSchema = z.object({
484
- default: z.string().optional(),
485
- small: z.string().optional(),
486
- agents: z.record(z.string(), AgentModelSchema).optional(),
487
- profiles: z.record(z.string(), ModelProfileSchema).optional(),
488
- providers: z.record(z.string(), ProviderConfigSchema).optional(),
489
- routing: z.array(RoutingRuleSchema).optional(),
490
- overrides: z.record(z.string(), z.object({
491
- default: z.string().optional(),
492
- small: z.string().optional(),
493
- agents: z.record(z.string(), AgentModelSchema).optional()
494
- })).optional()
495
- });
496
- function parseModels(packDir, packName) {
497
- const modelsPath = join7(packDir, "models.json");
498
- const raw = readJsonOrNull(modelsPath);
499
- if (!raw)
500
- return null;
501
- const parsed = ModelsSchema.parse(raw);
502
- return {
503
- packName,
504
- sourcePath: modelsPath,
505
- config: parsed
506
- };
507
- }
508
- function mergeModelsConfigs(configs) {
509
- const warnings = [];
510
- const result = {};
511
- for (const entry of configs) {
512
- const { config, packName } = entry;
513
- if (config.default !== undefined && result.default === undefined) {
514
- result.default = config.default;
515
- } else if (config.default !== undefined && result.default !== undefined) {
516
- warnings.push(`Models "default" from pack "${packName}" skipped (already defined).`);
517
- }
518
- if (config.small !== undefined && result.small === undefined) {
519
- result.small = config.small;
520
- } else if (config.small !== undefined && result.small !== undefined) {
521
- warnings.push(`Models "small" from pack "${packName}" skipped (already defined).`);
522
- }
523
- if (config.agents) {
524
- if (!result.agents)
525
- result.agents = {};
526
- for (const [name, assignment] of Object.entries(config.agents)) {
527
- if (name in result.agents) {
528
- warnings.push(`Models agent "${name}" from pack "${packName}" skipped (already defined).`);
529
- continue;
530
- }
531
- result.agents[name] = assignment;
532
- }
533
- }
534
- if (config.profiles) {
535
- if (!result.profiles)
536
- result.profiles = {};
537
- for (const [name, profile] of Object.entries(config.profiles)) {
538
- if (name in result.profiles) {
539
- warnings.push(`Models profile "${name}" from pack "${packName}" skipped (already defined).`);
540
- continue;
541
- }
542
- result.profiles[name] = profile;
543
- }
544
- }
545
- if (config.providers) {
546
- if (!result.providers)
547
- result.providers = {};
548
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
549
- if (!(providerName in result.providers)) {
550
- result.providers[providerName] = providerConfig;
551
- } else {
552
- const existing = result.providers[providerName];
553
- if (!existing) {
554
- result.providers[providerName] = providerConfig;
555
- continue;
556
- }
557
- if (providerConfig.options) {
558
- existing.options = {
559
- ...providerConfig.options,
560
- ...existing.options
561
- };
562
- }
563
- if (providerConfig.models) {
564
- if (!existing.models)
565
- existing.models = {};
566
- for (const [modelName, modelConfig] of Object.entries(providerConfig.models)) {
567
- if (!(modelName in existing.models)) {
568
- existing.models[modelName] = modelConfig;
569
- }
570
- }
571
- }
572
- }
573
- }
574
- }
575
- if (config.routing) {
576
- if (!result.routing)
577
- result.routing = [];
578
- result.routing.push(...config.routing);
579
- }
580
- if (config.overrides) {
581
- if (!result.overrides)
582
- result.overrides = {};
583
- for (const [targetId, override] of Object.entries(config.overrides)) {
584
- if (targetId in result.overrides) {
585
- warnings.push(`Models override for target "${targetId}" from pack "${packName}" skipped (already defined).`);
586
- continue;
587
- }
588
- result.overrides[targetId] = override;
589
- }
590
- }
591
- }
592
- return { config: result, warnings };
593
- }
594
- function scanModelsForSecrets(config) {
595
- const warnings = [];
596
- const json = JSON.stringify(config);
597
- for (const pattern of SECRET_PATTERNS) {
598
- if (pattern.test(json)) {
599
- warnings.push(`Potential secret detected in models.json matching pattern: ${pattern.source}`);
600
- }
601
- }
602
- return warnings;
603
- }
604
604
  export {
605
605
  validateAgentSkillsFrontmatter,
606
606
  skillMatchesTarget,