@skillkit/core 1.7.6 → 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.
package/dist/index.js CHANGED
@@ -17,7 +17,22 @@ var AgentType = z.enum([
17
17
  "roo",
18
18
  "trae",
19
19
  "windsurf",
20
- "universal"
20
+ "universal",
21
+ "cline",
22
+ "codebuddy",
23
+ "commandcode",
24
+ "continue",
25
+ "crush",
26
+ "factory",
27
+ "mcpjam",
28
+ "mux",
29
+ "neovate",
30
+ "openhands",
31
+ "pi",
32
+ "qoder",
33
+ "qwen",
34
+ "vercel",
35
+ "zencoder"
21
36
  ]);
22
37
  var GitProvider = z.enum(["github", "gitlab", "bitbucket", "local"]);
23
38
  var SkillFrontmatter = z.object({
@@ -233,6 +248,127 @@ var AGENT_CONFIG = {
233
248
  configFormat: "xml",
234
249
  usesFrontmatter: true,
235
250
  supportsAutoDiscovery: true
251
+ },
252
+ // Cline
253
+ cline: {
254
+ skillsDir: ".cline/skills",
255
+ configFile: "AGENTS.md",
256
+ configFormat: "xml",
257
+ usesFrontmatter: true,
258
+ supportsAutoDiscovery: true
259
+ },
260
+ // Codebuddy
261
+ codebuddy: {
262
+ skillsDir: ".codebuddy/skills",
263
+ configFile: "AGENTS.md",
264
+ configFormat: "xml",
265
+ usesFrontmatter: true,
266
+ supportsAutoDiscovery: true
267
+ },
268
+ // Commandcode
269
+ commandcode: {
270
+ skillsDir: ".commandcode/skills",
271
+ configFile: "AGENTS.md",
272
+ configFormat: "xml",
273
+ usesFrontmatter: true,
274
+ supportsAutoDiscovery: true
275
+ },
276
+ // Continue
277
+ continue: {
278
+ skillsDir: ".continue/skills",
279
+ configFile: "AGENTS.md",
280
+ globalSkillsDir: "~/.continue/skills",
281
+ configFormat: "xml",
282
+ usesFrontmatter: true,
283
+ supportsAutoDiscovery: true
284
+ },
285
+ // Crush
286
+ crush: {
287
+ skillsDir: ".crush/skills",
288
+ configFile: "AGENTS.md",
289
+ configFormat: "xml",
290
+ usesFrontmatter: true,
291
+ supportsAutoDiscovery: true
292
+ },
293
+ // Factory
294
+ factory: {
295
+ skillsDir: ".factory/skills",
296
+ configFile: "AGENTS.md",
297
+ configFormat: "xml",
298
+ usesFrontmatter: true,
299
+ supportsAutoDiscovery: true
300
+ },
301
+ // MCPJam
302
+ mcpjam: {
303
+ skillsDir: ".mcpjam/skills",
304
+ configFile: "AGENTS.md",
305
+ configFormat: "xml",
306
+ usesFrontmatter: true,
307
+ supportsAutoDiscovery: true
308
+ },
309
+ // Mux
310
+ mux: {
311
+ skillsDir: ".mux/skills",
312
+ configFile: "AGENTS.md",
313
+ configFormat: "xml",
314
+ usesFrontmatter: true,
315
+ supportsAutoDiscovery: true
316
+ },
317
+ // Neovate
318
+ neovate: {
319
+ skillsDir: ".neovate/skills",
320
+ configFile: "AGENTS.md",
321
+ configFormat: "xml",
322
+ usesFrontmatter: true,
323
+ supportsAutoDiscovery: true
324
+ },
325
+ // OpenHands
326
+ openhands: {
327
+ skillsDir: ".openhands/skills",
328
+ configFile: "AGENTS.md",
329
+ configFormat: "xml",
330
+ usesFrontmatter: true,
331
+ supportsAutoDiscovery: true
332
+ },
333
+ // Pi
334
+ pi: {
335
+ skillsDir: ".pi/skills",
336
+ configFile: "AGENTS.md",
337
+ configFormat: "xml",
338
+ usesFrontmatter: true,
339
+ supportsAutoDiscovery: true
340
+ },
341
+ // Qoder
342
+ qoder: {
343
+ skillsDir: ".qoder/skills",
344
+ configFile: "AGENTS.md",
345
+ configFormat: "xml",
346
+ usesFrontmatter: true,
347
+ supportsAutoDiscovery: true
348
+ },
349
+ // Qwen
350
+ qwen: {
351
+ skillsDir: ".qwen/skills",
352
+ configFile: "AGENTS.md",
353
+ configFormat: "xml",
354
+ usesFrontmatter: true,
355
+ supportsAutoDiscovery: true
356
+ },
357
+ // Vercel
358
+ vercel: {
359
+ skillsDir: ".vercel/skills",
360
+ configFile: "AGENTS.md",
361
+ configFormat: "xml",
362
+ usesFrontmatter: true,
363
+ supportsAutoDiscovery: true
364
+ },
365
+ // Zencoder
366
+ zencoder: {
367
+ skillsDir: ".zencoder/skills",
368
+ configFile: "AGENTS.md",
369
+ configFormat: "xml",
370
+ usesFrontmatter: true,
371
+ supportsAutoDiscovery: true
236
372
  }
237
373
  };
238
374
  function getAgentDirectoryConfig(agent) {
@@ -271,10 +407,20 @@ var SKILL_DISCOVERY_PATHS = [
271
407
  "skills/.curated",
272
408
  "skills/.experimental",
273
409
  "skills/.system",
410
+ "agents",
274
411
  ".agents/skills",
275
412
  ".agent/skills",
413
+ ".amp/skills",
414
+ ".antigravity/skills",
276
415
  ".claude/skills",
416
+ ".cline/skills",
417
+ ".clawdbot/skills",
418
+ ".codebuddy/skills",
277
419
  ".codex/skills",
420
+ ".commandcode/skills",
421
+ ".continue/skills",
422
+ ".copilot/skills",
423
+ ".crush/skills",
278
424
  ".cursor/skills",
279
425
  ".factory/skills",
280
426
  ".gemini/skills",
@@ -282,13 +428,19 @@ var SKILL_DISCOVERY_PATHS = [
282
428
  ".goose/skills",
283
429
  ".kilocode/skills",
284
430
  ".kiro/skills",
431
+ ".mcpjam/skills",
432
+ ".mux/skills",
433
+ ".neovate/skills",
285
434
  ".opencode/skills",
435
+ ".openhands/skills",
436
+ ".pi/skills",
437
+ ".qoder/skills",
438
+ ".qwen/skills",
286
439
  ".roo/skills",
287
440
  ".trae/skills",
441
+ ".vercel/skills",
288
442
  ".windsurf/skills",
289
- ".clawdbot/skills",
290
- ".antigravity/skills",
291
- ".copilot/skills"
443
+ ".zencoder/skills"
292
444
  ];
293
445
  function discoverSkillsInDir(dir) {
294
446
  const skills = [];
@@ -297,11 +449,17 @@ function discoverSkillsInDir(dir) {
297
449
  }
298
450
  const entries = readdirSync(dir, { withFileTypes: true });
299
451
  for (const entry of entries) {
300
- if (!entry.isDirectory()) continue;
301
- const skillPath = join(dir, entry.name);
302
- const skillMdPath = join(skillPath, "SKILL.md");
303
- if (existsSync(skillMdPath)) {
304
- const skill = parseSkill(skillPath);
452
+ if (entry.isDirectory()) {
453
+ const skillPath = join(dir, entry.name);
454
+ const skillMdPath = join(skillPath, "SKILL.md");
455
+ if (existsSync(skillMdPath)) {
456
+ const skill = parseSkill(skillPath);
457
+ if (skill) {
458
+ skills.push(skill);
459
+ }
460
+ }
461
+ } else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "README.md") {
462
+ const skill = parseStandaloneSkill(join(dir, entry.name));
305
463
  if (skill) {
306
464
  skills.push(skill);
307
465
  }
@@ -309,6 +467,32 @@ function discoverSkillsInDir(dir) {
309
467
  }
310
468
  return skills;
311
469
  }
470
+ function parseStandaloneSkill(filePath, location = "project") {
471
+ if (!existsSync(filePath)) {
472
+ return null;
473
+ }
474
+ try {
475
+ const content = readFileSync(filePath, "utf-8");
476
+ const frontmatter = extractFrontmatter(content);
477
+ if (!frontmatter) {
478
+ return null;
479
+ }
480
+ const name = frontmatter.name || basename(filePath, ".md");
481
+ const description = frontmatter.description || "No description available";
482
+ if (!name || name.length === 0) {
483
+ return null;
484
+ }
485
+ return {
486
+ name,
487
+ description,
488
+ path: filePath,
489
+ location,
490
+ enabled: true
491
+ };
492
+ } catch {
493
+ return null;
494
+ }
495
+ }
312
496
  function discoverSkillsRecursive(dir, seen, maxDepth = 5, currentDepth = 0) {
313
497
  const skills = [];
314
498
  if (currentDepth >= maxDepth || !existsSync(dir)) {
@@ -320,18 +504,25 @@ function discoverSkillsRecursive(dir, seen, maxDepth = 5, currentDepth = 0) {
320
504
  if (entry.name === "node_modules" || entry.name === ".git") {
321
505
  continue;
322
506
  }
323
- if (!entry.isDirectory()) continue;
324
507
  const entryPath = join(dir, entry.name);
325
- const skillMdPath = join(entryPath, "SKILL.md");
326
- if (existsSync(skillMdPath)) {
327
- const skill = parseSkill(entryPath);
508
+ if (entry.isDirectory()) {
509
+ const skillMdPath = join(entryPath, "SKILL.md");
510
+ if (existsSync(skillMdPath)) {
511
+ const skill = parseSkill(entryPath);
512
+ if (skill && !seen.has(skill.name)) {
513
+ seen.add(skill.name);
514
+ skills.push(skill);
515
+ }
516
+ } else {
517
+ const subSkills = discoverSkillsRecursive(entryPath, seen, maxDepth, currentDepth + 1);
518
+ skills.push(...subSkills);
519
+ }
520
+ } else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "README.md") {
521
+ const skill = parseStandaloneSkill(entryPath);
328
522
  if (skill && !seen.has(skill.name)) {
329
523
  seen.add(skill.name);
330
524
  skills.push(skill);
331
525
  }
332
- } else {
333
- const subSkills = discoverSkillsRecursive(entryPath, seen, maxDepth, currentDepth + 1);
334
- skills.push(...subSkills);
335
526
  }
336
527
  }
337
528
  } catch {
@@ -446,7 +637,7 @@ function loadMetadata(skillPath) {
446
637
  }
447
638
  }
448
639
  function readSkillContent(skillPath) {
449
- const skillMdPath = join(skillPath, "SKILL.md");
640
+ const skillMdPath = skillPath.endsWith(".md") ? skillPath : join(skillPath, "SKILL.md");
450
641
  if (!existsSync(skillMdPath)) {
451
642
  return null;
452
643
  }
@@ -486,8 +677,9 @@ function findAllSkills(searchDirs) {
486
677
  function validateSkill(skillPath) {
487
678
  const errors = [];
488
679
  const warnings = [];
489
- const dirName = basename(skillPath);
490
- const skillMdPath = join(skillPath, "SKILL.md");
680
+ const isStandalone = skillPath.endsWith(".md");
681
+ const dirName = isStandalone ? basename(skillPath, ".md") : basename(skillPath);
682
+ const skillMdPath = isStandalone ? skillPath : join(skillPath, "SKILL.md");
491
683
  if (!existsSync(skillMdPath)) {
492
684
  errors.push("Missing SKILL.md file");
493
685
  return { valid: false, errors };
@@ -1033,7 +1225,22 @@ var AGENT_FORMAT_MAP = {
1033
1225
  "universal": "skill-md",
1034
1226
  "cursor": "cursor-mdc",
1035
1227
  "windsurf": "markdown-rules",
1036
- "github-copilot": "markdown-rules"
1228
+ "github-copilot": "markdown-rules",
1229
+ "cline": "skill-md",
1230
+ "codebuddy": "skill-md",
1231
+ "commandcode": "skill-md",
1232
+ "continue": "skill-md",
1233
+ "crush": "skill-md",
1234
+ "factory": "skill-md",
1235
+ "mcpjam": "skill-md",
1236
+ "mux": "skill-md",
1237
+ "neovate": "skill-md",
1238
+ "openhands": "skill-md",
1239
+ "pi": "skill-md",
1240
+ "qoder": "skill-md",
1241
+ "qwen": "skill-md",
1242
+ "vercel": "skill-md",
1243
+ "zencoder": "skill-md"
1037
1244
  };
1038
1245
  var TranslatableSkillFrontmatter = z2.object({
1039
1246
  name: z2.string(),
@@ -15094,6 +15301,111 @@ var AGENT_FORMATS = {
15094
15301
  directory: "commands",
15095
15302
  supportsSlashCommands: true,
15096
15303
  supportsCommandFiles: true
15304
+ },
15305
+ cline: {
15306
+ agent: "cline",
15307
+ extension: ".md",
15308
+ directory: ".cline/commands",
15309
+ supportsSlashCommands: true,
15310
+ supportsCommandFiles: true
15311
+ },
15312
+ codebuddy: {
15313
+ agent: "codebuddy",
15314
+ extension: ".md",
15315
+ directory: ".codebuddy/commands",
15316
+ supportsSlashCommands: true,
15317
+ supportsCommandFiles: true
15318
+ },
15319
+ commandcode: {
15320
+ agent: "commandcode",
15321
+ extension: ".md",
15322
+ directory: ".commandcode/commands",
15323
+ supportsSlashCommands: true,
15324
+ supportsCommandFiles: true
15325
+ },
15326
+ continue: {
15327
+ agent: "continue",
15328
+ extension: ".md",
15329
+ directory: ".continue/commands",
15330
+ supportsSlashCommands: true,
15331
+ supportsCommandFiles: true
15332
+ },
15333
+ crush: {
15334
+ agent: "crush",
15335
+ extension: ".md",
15336
+ directory: ".crush/commands",
15337
+ supportsSlashCommands: true,
15338
+ supportsCommandFiles: true
15339
+ },
15340
+ factory: {
15341
+ agent: "factory",
15342
+ extension: ".md",
15343
+ directory: ".factory/commands",
15344
+ supportsSlashCommands: true,
15345
+ supportsCommandFiles: true
15346
+ },
15347
+ mcpjam: {
15348
+ agent: "mcpjam",
15349
+ extension: ".md",
15350
+ directory: ".mcpjam/commands",
15351
+ supportsSlashCommands: true,
15352
+ supportsCommandFiles: true
15353
+ },
15354
+ mux: {
15355
+ agent: "mux",
15356
+ extension: ".md",
15357
+ directory: ".mux/commands",
15358
+ supportsSlashCommands: true,
15359
+ supportsCommandFiles: true
15360
+ },
15361
+ neovate: {
15362
+ agent: "neovate",
15363
+ extension: ".md",
15364
+ directory: ".neovate/commands",
15365
+ supportsSlashCommands: true,
15366
+ supportsCommandFiles: true
15367
+ },
15368
+ openhands: {
15369
+ agent: "openhands",
15370
+ extension: ".md",
15371
+ directory: ".openhands/commands",
15372
+ supportsSlashCommands: true,
15373
+ supportsCommandFiles: true
15374
+ },
15375
+ pi: {
15376
+ agent: "pi",
15377
+ extension: ".md",
15378
+ directory: ".pi/commands",
15379
+ supportsSlashCommands: true,
15380
+ supportsCommandFiles: true
15381
+ },
15382
+ qoder: {
15383
+ agent: "qoder",
15384
+ extension: ".md",
15385
+ directory: ".qoder/commands",
15386
+ supportsSlashCommands: true,
15387
+ supportsCommandFiles: true
15388
+ },
15389
+ qwen: {
15390
+ agent: "qwen",
15391
+ extension: ".md",
15392
+ directory: ".qwen/commands",
15393
+ supportsSlashCommands: true,
15394
+ supportsCommandFiles: true
15395
+ },
15396
+ vercel: {
15397
+ agent: "vercel",
15398
+ extension: ".md",
15399
+ directory: ".vercel/commands",
15400
+ supportsSlashCommands: true,
15401
+ supportsCommandFiles: true
15402
+ },
15403
+ zencoder: {
15404
+ agent: "zencoder",
15405
+ extension: ".md",
15406
+ directory: ".zencoder/commands",
15407
+ supportsSlashCommands: true,
15408
+ supportsCommandFiles: true
15097
15409
  }
15098
15410
  };
15099
15411
  var CommandGenerator = class {
@@ -16086,7 +16398,7 @@ var AGENT_DISCOVERY_PATHS = {
16086
16398
  "antigravity": [".antigravity/agents"],
16087
16399
  "amp": [".amp/agents"],
16088
16400
  "clawdbot": [".clawdbot/agents", "agents"],
16089
- "droid": [".factory/agents"],
16401
+ "droid": [".droid/agents"],
16090
16402
  "github-copilot": [".github/agents", ".github/instructions", ".github/custom-agents"],
16091
16403
  "goose": [".goose/agents"],
16092
16404
  "kilo": [".kilocode/agents", ".kilocode/modes"],
@@ -16094,22 +16406,41 @@ var AGENT_DISCOVERY_PATHS = {
16094
16406
  "roo": [".roo/agents", ".roo/modes"],
16095
16407
  "trae": [".trae/agents", ".trae/agent"],
16096
16408
  "windsurf": [".windsurf/agents", ".windsurf/workflows"],
16097
- "universal": ["agents", ".agents"]
16409
+ "universal": ["agents", ".agents"],
16410
+ "cline": [".cline/agents"],
16411
+ "codebuddy": [".codebuddy/agents"],
16412
+ "commandcode": [".commandcode/agents"],
16413
+ "continue": [".continue/agents"],
16414
+ "crush": [".crush/agents"],
16415
+ "factory": [".factory/agents"],
16416
+ "mcpjam": [".mcpjam/agents"],
16417
+ "mux": [".mux/agents"],
16418
+ "neovate": [".neovate/agents"],
16419
+ "openhands": [".openhands/agents"],
16420
+ "pi": [".pi/agents"],
16421
+ "qoder": [".qoder/agents"],
16422
+ "qwen": [".qwen/agents"],
16423
+ "vercel": [".vercel/agents"],
16424
+ "zencoder": [".zencoder/agents"]
16098
16425
  };
16099
16426
  var ALL_AGENT_DISCOVERY_PATHS = [
16100
16427
  "agents",
16101
16428
  ".agents",
16429
+ ".amp/agents",
16430
+ ".antigravity/agents",
16102
16431
  ".claude/agents",
16432
+ ".cline/agents",
16433
+ ".clawdbot/agents",
16434
+ ".codebuddy/agents",
16435
+ ".codex/agents",
16436
+ ".commandcode/agents",
16437
+ ".continue/agents",
16438
+ ".crush/agents",
16103
16439
  ".cursor/agents",
16104
16440
  ".cursor/commands",
16105
- ".codex/agents",
16106
- ".gemini/agents",
16107
- ".opencode/agents",
16108
- ".opencode/agent",
16109
- ".antigravity/agents",
16110
- ".amp/agents",
16111
- ".clawdbot/agents",
16441
+ ".droid/agents",
16112
16442
  ".factory/agents",
16443
+ ".gemini/agents",
16113
16444
  ".github/agents",
16114
16445
  ".github/instructions",
16115
16446
  ".github/custom-agents",
@@ -16117,12 +16448,23 @@ var ALL_AGENT_DISCOVERY_PATHS = [
16117
16448
  ".kilocode/agents",
16118
16449
  ".kilocode/modes",
16119
16450
  ".kiro/agents",
16451
+ ".mcpjam/agents",
16452
+ ".mux/agents",
16453
+ ".neovate/agents",
16454
+ ".opencode/agents",
16455
+ ".opencode/agent",
16456
+ ".openhands/agents",
16457
+ ".pi/agents",
16458
+ ".qoder/agents",
16459
+ ".qwen/agents",
16120
16460
  ".roo/agents",
16121
16461
  ".roo/modes",
16122
16462
  ".trae/agents",
16123
16463
  ".trae/agent",
16464
+ ".vercel/agents",
16124
16465
  ".windsurf/agents",
16125
- ".windsurf/workflows"
16466
+ ".windsurf/workflows",
16467
+ ".zencoder/agents"
16126
16468
  ];
16127
16469
  var CUSTOM_AGENT_FORMAT_MAP = {
16128
16470
  "claude-code": "claude-agent",
@@ -16141,7 +16483,22 @@ var CUSTOM_AGENT_FORMAT_MAP = {
16141
16483
  "roo": "claude-agent",
16142
16484
  "trae": "claude-agent",
16143
16485
  "windsurf": "universal",
16144
- "universal": "universal"
16486
+ "universal": "universal",
16487
+ "cline": "claude-agent",
16488
+ "codebuddy": "claude-agent",
16489
+ "commandcode": "claude-agent",
16490
+ "continue": "claude-agent",
16491
+ "crush": "claude-agent",
16492
+ "factory": "claude-agent",
16493
+ "mcpjam": "claude-agent",
16494
+ "mux": "claude-agent",
16495
+ "neovate": "claude-agent",
16496
+ "openhands": "claude-agent",
16497
+ "pi": "claude-agent",
16498
+ "qoder": "claude-agent",
16499
+ "qwen": "claude-agent",
16500
+ "vercel": "claude-agent",
16501
+ "zencoder": "claude-agent"
16145
16502
  };
16146
16503
 
16147
16504
  // src/agents/parser.ts
@@ -17522,6 +17879,643 @@ function generateManifestFromInstalled(installedSkills) {
17522
17879
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
17523
17880
  };
17524
17881
  }
17882
+
17883
+ // src/quality/index.ts
17884
+ import { readFileSync as readFileSync26, existsSync as existsSync34 } from "fs";
17885
+ import { join as join35, basename as basename12 } from "path";
17886
+
17887
+ // src/quality/benchmark.ts
17888
+ var CATEGORY_BENCHMARKS = {
17889
+ react: {
17890
+ category: "react",
17891
+ avgScore: 78,
17892
+ topScore: 95,
17893
+ topSkills: ["react-patterns", "react-hooks-best-practices"],
17894
+ count: 150,
17895
+ distribution: { A: 15, B: 35, C: 30, D: 15, F: 5 }
17896
+ },
17897
+ typescript: {
17898
+ category: "typescript",
17899
+ avgScore: 75,
17900
+ topScore: 92,
17901
+ topSkills: ["typescript-strict", "type-safety-patterns"],
17902
+ count: 120,
17903
+ distribution: { A: 12, B: 30, C: 35, D: 18, F: 5 }
17904
+ },
17905
+ testing: {
17906
+ category: "testing",
17907
+ avgScore: 72,
17908
+ topScore: 90,
17909
+ topSkills: ["tdd-workflow", "testing-best-practices"],
17910
+ count: 80,
17911
+ distribution: { A: 10, B: 28, C: 38, D: 19, F: 5 }
17912
+ },
17913
+ git: {
17914
+ category: "git",
17915
+ avgScore: 80,
17916
+ topScore: 94,
17917
+ topSkills: ["git-workflow", "conventional-commits"],
17918
+ count: 60,
17919
+ distribution: { A: 18, B: 40, C: 28, D: 12, F: 2 }
17920
+ },
17921
+ security: {
17922
+ category: "security",
17923
+ avgScore: 76,
17924
+ topScore: 93,
17925
+ topSkills: ["security-review", "owasp-patterns"],
17926
+ count: 45,
17927
+ distribution: { A: 14, B: 32, C: 34, D: 16, F: 4 }
17928
+ },
17929
+ api: {
17930
+ category: "api",
17931
+ avgScore: 74,
17932
+ topScore: 91,
17933
+ topSkills: ["api-design", "rest-best-practices"],
17934
+ count: 55,
17935
+ distribution: { A: 11, B: 30, C: 36, D: 18, F: 5 }
17936
+ },
17937
+ general: {
17938
+ category: "general",
17939
+ avgScore: 70,
17940
+ topScore: 88,
17941
+ topSkills: ["code-review", "best-practices"],
17942
+ count: 200,
17943
+ distribution: { A: 8, B: 25, C: 40, D: 22, F: 5 }
17944
+ }
17945
+ };
17946
+ function getGrade(score) {
17947
+ if (score >= 90) return "A";
17948
+ if (score >= 80) return "B";
17949
+ if (score >= 70) return "C";
17950
+ if (score >= 60) return "D";
17951
+ return "F";
17952
+ }
17953
+ function detectCategory(skillName, tags = []) {
17954
+ const lowerName = skillName.toLowerCase();
17955
+ const lowerTags = tags.map((t) => t.toLowerCase());
17956
+ const searchTerms = [lowerName, ...lowerTags];
17957
+ const categoryKeywords = {
17958
+ react: ["react", "hooks", "jsx", "tsx", "component", "nextjs", "remix"],
17959
+ typescript: ["typescript", "type", "types", "ts", "strict"],
17960
+ testing: ["test", "testing", "tdd", "jest", "vitest", "playwright", "e2e"],
17961
+ git: ["git", "commit", "branch", "merge", "workflow", "conventional"],
17962
+ security: ["security", "auth", "owasp", "vulnerability", "safe"],
17963
+ api: ["api", "rest", "graphql", "endpoint", "http"]
17964
+ };
17965
+ for (const [category, keywords] of Object.entries(categoryKeywords)) {
17966
+ for (const term of searchTerms) {
17967
+ if (keywords.some((kw) => term.includes(kw))) {
17968
+ return category;
17969
+ }
17970
+ }
17971
+ }
17972
+ return "general";
17973
+ }
17974
+ function calculatePercentile(score, categoryStats) {
17975
+ const { distribution } = categoryStats;
17976
+ const totalSkills = distribution.A + distribution.B + distribution.C + distribution.D + distribution.F;
17977
+ let percentBelow = 0;
17978
+ if (score < 60) {
17979
+ percentBelow = score / 60 * (distribution.F / totalSkills) * 100;
17980
+ } else if (score < 70) {
17981
+ percentBelow = distribution.F / totalSkills * 100;
17982
+ percentBelow += (score - 60) / 10 * (distribution.D / totalSkills) * 100;
17983
+ } else if (score < 80) {
17984
+ percentBelow = (distribution.F + distribution.D) / totalSkills * 100;
17985
+ percentBelow += (score - 70) / 10 * (distribution.C / totalSkills) * 100;
17986
+ } else if (score < 90) {
17987
+ percentBelow = (distribution.F + distribution.D + distribution.C) / totalSkills * 100;
17988
+ percentBelow += (score - 80) / 10 * (distribution.B / totalSkills) * 100;
17989
+ } else {
17990
+ percentBelow = (distribution.F + distribution.D + distribution.C + distribution.B) / totalSkills * 100;
17991
+ percentBelow += (score - 90) / 10 * (distribution.A / totalSkills) * 100;
17992
+ }
17993
+ return Math.round(Math.min(99, Math.max(1, percentBelow)));
17994
+ }
17995
+ function generateComparisonNotes(quality, categoryStats) {
17996
+ const notes = [];
17997
+ const topScore = categoryStats.topScore;
17998
+ const avgScore = categoryStats.avgScore;
17999
+ if (quality.overall >= topScore) {
18000
+ notes.push("Your skill is among the top performers in this category");
18001
+ } else if (quality.overall >= avgScore) {
18002
+ notes.push(`Your skill is above the category average (${avgScore})`);
18003
+ } else {
18004
+ notes.push(`Your skill is ${avgScore - quality.overall} points below the category average`);
18005
+ }
18006
+ if (!quality.structure.hasExamples) {
18007
+ notes.push("Missing code examples (present in 95% of top skills)");
18008
+ }
18009
+ if (!quality.structure.hasTriggers) {
18010
+ notes.push("Missing trigger conditions (present in 80% of top skills)");
18011
+ }
18012
+ if (!quality.structure.hasBoundaries) {
18013
+ notes.push('Missing "When Not to Use" section (present in 80% of top skills)');
18014
+ }
18015
+ if (quality.specificity.vagueTermCount > 3) {
18016
+ notes.push("Trigger conditions are less specific than category average");
18017
+ }
18018
+ if (quality.clarity.lineCount > 300) {
18019
+ notes.push("Skill is longer than recommended (top skills average 150-250 lines)");
18020
+ }
18021
+ if (quality.advanced.deprecatedPatterns.length > 0) {
18022
+ notes.push("Contains deprecated patterns not found in top skills");
18023
+ }
18024
+ return notes;
18025
+ }
18026
+ function generateRecommendations(quality, categoryStats) {
18027
+ const recommendations = [];
18028
+ const gap = categoryStats.topScore - quality.overall;
18029
+ if (gap > 20) {
18030
+ recommendations.push("Consider studying top skills in this category for patterns");
18031
+ }
18032
+ if (!quality.structure.hasExamples) {
18033
+ recommendations.push(`Add ${quality.specificity.hasCodeExamples ? "more" : ""} code examples showing input/output`);
18034
+ }
18035
+ if (!quality.structure.hasTriggers) {
18036
+ recommendations.push('Add explicit trigger conditions with patterns like "Triggers when:"');
18037
+ }
18038
+ if (!quality.structure.hasBoundaries) {
18039
+ recommendations.push('Add a "Boundaries" or "Limitations" section');
18040
+ }
18041
+ if (quality.clarity.lineCount > 400) {
18042
+ recommendations.push("Split into multiple focused skills (top skills are 150-250 lines)");
18043
+ }
18044
+ if (quality.specificity.vagueTermCount > 0) {
18045
+ recommendations.push(`Replace ${quality.specificity.vagueTermCount} vague term(s) with specific instructions`);
18046
+ }
18047
+ if (quality.advanced.completeness.hasTodos) {
18048
+ recommendations.push("Complete TODO items before publishing");
18049
+ }
18050
+ return recommendations;
18051
+ }
18052
+ function benchmarkSkill(skillName, quality, tags = [], customCategoryStats) {
18053
+ const category = detectCategory(skillName, tags);
18054
+ const categoryStats = customCategoryStats || CATEGORY_BENCHMARKS[category] || CATEGORY_BENCHMARKS.general;
18055
+ const percentile = calculatePercentile(quality.overall, categoryStats);
18056
+ const comparisonNotes = generateComparisonNotes(quality, categoryStats);
18057
+ const recommendations = generateRecommendations(quality, categoryStats);
18058
+ return {
18059
+ skill: skillName,
18060
+ score: quality.overall,
18061
+ grade: getGrade(quality.overall),
18062
+ categoryAvg: categoryStats.avgScore,
18063
+ topSkillScore: categoryStats.topScore,
18064
+ percentile,
18065
+ comparisonNotes,
18066
+ recommendations
18067
+ };
18068
+ }
18069
+ function getCategoryStats(category) {
18070
+ return CATEGORY_BENCHMARKS[category] || null;
18071
+ }
18072
+ function getAllCategories() {
18073
+ return Object.keys(CATEGORY_BENCHMARKS);
18074
+ }
18075
+
18076
+ // src/quality/index.ts
18077
+ var VAGUE_TERMS = [
18078
+ "be helpful",
18079
+ "assist the user",
18080
+ "help with",
18081
+ "try to",
18082
+ "attempt to",
18083
+ "do your best",
18084
+ "as needed",
18085
+ "when appropriate",
18086
+ "if necessary",
18087
+ "general purpose",
18088
+ "various tasks",
18089
+ "many things",
18090
+ "etc.",
18091
+ "and so on",
18092
+ "stuff like that"
18093
+ ];
18094
+ var BOUNDARY_PATTERNS = [
18095
+ /never\s+(?:do|use|commit|push|delete|remove)/i,
18096
+ /always\s+(?:do|use|check|verify|ensure)/i,
18097
+ /don'?t\s+(?:do|use|commit|push|delete)/i,
18098
+ /avoid\s+(?:using|doing|committing)/i,
18099
+ /must\s+(?:not|always|never)/i,
18100
+ /forbidden/i,
18101
+ /prohibited/i,
18102
+ /required/i
18103
+ ];
18104
+ var TRIGGER_PATTERNS = [
18105
+ /when\s+to\s+use/i,
18106
+ /use\s+this\s+(?:skill|when)/i,
18107
+ /triggers?\s*(?:when|:)/i,
18108
+ /activated?\s+(?:when|by)/i,
18109
+ /applies?\s+(?:when|to)/i,
18110
+ /invoke\s+(?:when|this)/i
18111
+ ];
18112
+ var COMMAND_PATTERNS = [
18113
+ /```(?:bash|sh|shell|zsh)[\s\S]*?```/g,
18114
+ /`(?:npm|pnpm|yarn|bun|npx|git|docker|kubectl)\s+[^`]+`/g,
18115
+ /\$\s*\w+/g
18116
+ ];
18117
+ var CODE_EXAMPLE_PATTERNS = [
18118
+ /```(?:typescript|javascript|tsx|jsx|python|go|rust|java)[\s\S]*?```/g,
18119
+ /```[\s\S]{50,}?```/g
18120
+ ];
18121
+ var FILE_PATTERN_PATTERNS = [
18122
+ /\*\*\/\*\.\w+/,
18123
+ /\.\w+$/m,
18124
+ /glob[s]?\s*[:=]/i,
18125
+ /include[s]?\s*[:=]/i,
18126
+ /pattern[s]?\s*[:=]/i
18127
+ ];
18128
+ var DEPRECATED_PATTERNS = [
18129
+ { pattern: /require\s*\(['"][^'"]+['"]\)/g, message: "Uses CommonJS require() instead of ES modules" },
18130
+ { pattern: /React\.Component/g, message: "Uses class components instead of functional" },
18131
+ { pattern: /componentDidMount|componentWillUnmount|componentDidUpdate/g, message: "Uses lifecycle methods instead of hooks" },
18132
+ { pattern: /\bvar\s+\w+\s*=/g, message: "Uses var instead of const/let" },
18133
+ { pattern: /\.then\s*\([^)]*\)\.catch/g, message: "Uses .then().catch() instead of async/await" },
18134
+ { pattern: /new\s+Promise\s*\(/g, message: "Consider using async/await instead of new Promise()" }
18135
+ ];
18136
+ var SECURITY_PATTERNS = [
18137
+ { pattern: /password\s*[:=]\s*['"][^'"]+['"]/gi, message: "Potential hardcoded password" },
18138
+ { pattern: /api[_-]?key\s*[:=]\s*['"][^'"]+['"]/gi, message: "Potential hardcoded API key" },
18139
+ { pattern: /secret\s*[:=]\s*['"][^'"]+['"]/gi, message: "Potential hardcoded secret" },
18140
+ { pattern: /token\s*[:=]\s*['"][A-Za-z0-9_-]{20,}['"]/gi, message: "Potential hardcoded token" },
18141
+ { pattern: /\$\{[^}]*\}/g, message: "Template literal - ensure proper sanitization in shell commands" },
18142
+ { pattern: /eval\s*\(/g, message: "Uses eval() - potential code injection risk" },
18143
+ { pattern: /innerHTML\s*=/g, message: "Uses innerHTML - potential XSS risk" },
18144
+ { pattern: /dangerouslySetInnerHTML/g, message: "Uses dangerouslySetInnerHTML - potential XSS risk" }
18145
+ ];
18146
+ function extractFrontmatter4(content) {
18147
+ const normalizedContent = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
18148
+ const match = normalizedContent.match(/^---\s*\n([\s\S]*?)\n---/);
18149
+ if (!match) return null;
18150
+ const frontmatter = {};
18151
+ const lines = match[1].split("\n");
18152
+ for (const line of lines) {
18153
+ const colonIndex = line.indexOf(":");
18154
+ if (colonIndex > 0) {
18155
+ const key = line.slice(0, colonIndex).trim();
18156
+ const value = line.slice(colonIndex + 1).trim();
18157
+ frontmatter[key] = value;
18158
+ }
18159
+ }
18160
+ return Object.keys(frontmatter).length > 0 ? frontmatter : null;
18161
+ }
18162
+ function countTokens(text) {
18163
+ return Math.ceil(text.length / 4);
18164
+ }
18165
+ function countVagueTerms(content) {
18166
+ const lowerContent = content.toLowerCase();
18167
+ let count = 0;
18168
+ for (const term of VAGUE_TERMS) {
18169
+ const regex = new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
18170
+ const matches = lowerContent.match(regex);
18171
+ if (matches) count += matches.length;
18172
+ }
18173
+ return count;
18174
+ }
18175
+ function hasPattern(content, patterns) {
18176
+ return patterns.some((p) => p.test(content));
18177
+ }
18178
+ function countMatches(content, patterns) {
18179
+ let count = 0;
18180
+ for (const pattern of patterns) {
18181
+ const matches = content.match(pattern);
18182
+ if (matches) count += matches.length;
18183
+ }
18184
+ return count;
18185
+ }
18186
+ function calculateAvgSentenceLength(content) {
18187
+ const contentWithoutCode = content.replace(/```[\s\S]*?```/g, "");
18188
+ const sentences = contentWithoutCode.split(/[.!?]+/).filter((s) => s.trim().length > 0);
18189
+ if (sentences.length === 0) return 0;
18190
+ const totalWords = sentences.reduce((sum, s) => sum + s.trim().split(/\s+/).length, 0);
18191
+ return Math.round(totalWords / sentences.length);
18192
+ }
18193
+ function evaluateStructure(content) {
18194
+ const frontmatter = extractFrontmatter4(content);
18195
+ const hasMetadata = frontmatter !== null && Object.keys(frontmatter).length > 0;
18196
+ const hasDescription = !!frontmatter?.description || /^#+\s*description/im.test(content);
18197
+ const hasTriggers = hasPattern(content, TRIGGER_PATTERNS);
18198
+ const hasExamples = countMatches(content, CODE_EXAMPLE_PATTERNS) > 0;
18199
+ const hasBoundaries = hasPattern(content, BOUNDARY_PATTERNS);
18200
+ const hasWhenToUse = /when\s+to\s+use|use\s+case|scenario/i.test(content);
18201
+ let score = 0;
18202
+ if (hasMetadata) score += 15;
18203
+ if (hasDescription) score += 10;
18204
+ if (hasTriggers) score += 20;
18205
+ if (hasExamples) score += 20;
18206
+ if (hasBoundaries) score += 20;
18207
+ if (hasWhenToUse) score += 15;
18208
+ return {
18209
+ score: Math.min(100, score),
18210
+ hasMetadata,
18211
+ hasDescription,
18212
+ hasTriggers,
18213
+ hasExamples,
18214
+ hasBoundaries,
18215
+ hasWhenToUse
18216
+ };
18217
+ }
18218
+ function evaluateClarity(content) {
18219
+ const lines = content.split("\n");
18220
+ const lineCount = lines.length;
18221
+ const tokenCount = countTokens(content);
18222
+ const avgSentenceLength = calculateAvgSentenceLength(content);
18223
+ const hasHeaders = /^#+\s+/m.test(content);
18224
+ let score = 100;
18225
+ if (lineCount > 500) score -= 30;
18226
+ else if (lineCount > 300) score -= 15;
18227
+ else if (lineCount > 150) score -= 5;
18228
+ if (tokenCount > 4e3) score -= 30;
18229
+ else if (tokenCount > 2e3) score -= 15;
18230
+ else if (tokenCount > 1e3) score -= 5;
18231
+ if (avgSentenceLength > 30) score -= 20;
18232
+ else if (avgSentenceLength > 20) score -= 10;
18233
+ if (!hasHeaders) score -= 15;
18234
+ return {
18235
+ score: Math.max(0, score),
18236
+ lineCount,
18237
+ tokenCount,
18238
+ avgSentenceLength,
18239
+ hasHeaders
18240
+ };
18241
+ }
18242
+ function countCodeBlocks(content) {
18243
+ const fencedBlocks = content.match(/```[\s\S]*?```/g) || [];
18244
+ return fencedBlocks.length;
18245
+ }
18246
+ function detectDeprecatedPatterns(content) {
18247
+ const codeBlocks = content.match(/```[\s\S]*?```/g) || [];
18248
+ const codeContent = codeBlocks.join("\n");
18249
+ const issues = [];
18250
+ for (const { pattern, message } of DEPRECATED_PATTERNS) {
18251
+ const regex = new RegExp(pattern.source, pattern.flags);
18252
+ if (regex.test(codeContent)) {
18253
+ issues.push(message);
18254
+ }
18255
+ }
18256
+ return [...new Set(issues)];
18257
+ }
18258
+ function detectSecurityPatterns(content) {
18259
+ const issues = [];
18260
+ for (const { pattern, message } of SECURITY_PATTERNS) {
18261
+ const regex = new RegExp(pattern.source, pattern.flags);
18262
+ if (regex.test(content)) {
18263
+ if (!message.includes("Template literal") || content.includes("bash") || content.includes("shell")) {
18264
+ issues.push(message);
18265
+ }
18266
+ }
18267
+ }
18268
+ return [...new Set(issues)];
18269
+ }
18270
+ function detectConflictingInstructions(content) {
18271
+ const issues = [];
18272
+ const lowerContent = content.toLowerCase();
18273
+ const alwaysMatches = lowerContent.match(/always\s+(?:use|do|include|add)\s+(\w+)/gi) || [];
18274
+ const neverMatches = lowerContent.match(/never\s+(?:use|do|include|add)\s+(\w+)/gi) || [];
18275
+ for (const always of alwaysMatches) {
18276
+ const term = always.replace(/always\s+(?:use|do|include|add)\s+/i, "").toLowerCase();
18277
+ for (const never of neverMatches) {
18278
+ const neverTerm = never.replace(/never\s+(?:use|do|include|add)\s+/i, "").toLowerCase();
18279
+ if (term === neverTerm) {
18280
+ issues.push(`Conflicting instructions: "always" and "never" used with "${term}"`);
18281
+ }
18282
+ }
18283
+ }
18284
+ const mustMatches = lowerContent.match(/must\s+(\w+)/gi) || [];
18285
+ const mustNotMatches = lowerContent.match(/must\s+not\s+(\w+)/gi) || [];
18286
+ for (const must of mustMatches) {
18287
+ const term = must.replace(/must\s+/i, "").toLowerCase();
18288
+ for (const mustNot of mustNotMatches) {
18289
+ const notTerm = mustNot.replace(/must\s+not\s+/i, "").toLowerCase();
18290
+ if (term === notTerm) {
18291
+ issues.push(`Conflicting instructions: "must" and "must not" used with "${term}"`);
18292
+ }
18293
+ }
18294
+ }
18295
+ return [...new Set(issues)];
18296
+ }
18297
+ function assessCompleteness(content) {
18298
+ const todoMatches = content.match(/TODO|FIXME|XXX|HACK/gi) || [];
18299
+ const todoCount = todoMatches.length;
18300
+ const headerPositions = [];
18301
+ const lines = content.split("\n");
18302
+ let inFence = false;
18303
+ let offset = 0;
18304
+ for (const line of lines) {
18305
+ if (/^```|^~~~/.test(line)) {
18306
+ inFence = !inFence;
18307
+ } else if (!inFence && /^#+\s+.+$/.test(line)) {
18308
+ headerPositions.push({ header: line, index: offset });
18309
+ }
18310
+ offset += line.length + 1;
18311
+ }
18312
+ const emptySections = [];
18313
+ for (let i = 0; i < headerPositions.length - 1; i++) {
18314
+ const current = headerPositions[i];
18315
+ const next = headerPositions[i + 1];
18316
+ const sectionContent = content.slice(current.index + current.header.length, next.index).trim();
18317
+ if (sectionContent.length < 20) {
18318
+ const sectionName = current.header.replace(/^#+\s+/, "");
18319
+ emptySections.push(sectionName);
18320
+ }
18321
+ }
18322
+ if (headerPositions.length > 0) {
18323
+ const last = headerPositions[headerPositions.length - 1];
18324
+ const tailContent = content.slice(last.index + last.header.length).trim();
18325
+ if (tailContent.length < 20) {
18326
+ const sectionName = last.header.replace(/^#+\s+/, "");
18327
+ emptySections.push(sectionName);
18328
+ }
18329
+ }
18330
+ const codeBlocks = countCodeBlocks(content);
18331
+ const exampleCoverage = Math.min(100, codeBlocks * 25);
18332
+ let score = 100;
18333
+ if (todoCount > 0) score -= Math.min(30, todoCount * 10);
18334
+ if (emptySections.length > 0) score -= Math.min(30, emptySections.length * 10);
18335
+ if (codeBlocks < 2) score -= 20;
18336
+ else if (codeBlocks < 4) score -= 10;
18337
+ return {
18338
+ score: Math.max(0, score),
18339
+ hasTodos: todoCount > 0,
18340
+ todoCount,
18341
+ emptySections,
18342
+ exampleCoverage
18343
+ };
18344
+ }
18345
+ function evaluateAdvanced(content) {
18346
+ const deprecatedPatterns = detectDeprecatedPatterns(content);
18347
+ const conflictingInstructions = detectConflictingInstructions(content);
18348
+ const securityIssues = detectSecurityPatterns(content);
18349
+ const completeness = assessCompleteness(content);
18350
+ let score = 100;
18351
+ score -= Math.min(30, deprecatedPatterns.length * 10);
18352
+ score -= Math.min(30, conflictingInstructions.length * 15);
18353
+ score -= Math.min(25, securityIssues.length * 10);
18354
+ score -= Math.round((100 - completeness.score) * 0.15);
18355
+ return {
18356
+ score: Math.max(0, score),
18357
+ deprecatedPatterns,
18358
+ conflictingInstructions,
18359
+ securityIssues,
18360
+ completeness
18361
+ };
18362
+ }
18363
+ function evaluateSpecificity(content) {
18364
+ const hasConcreteCommands = countMatches(content, COMMAND_PATTERNS) > 0;
18365
+ const hasFilePatterns = hasPattern(content, FILE_PATTERN_PATTERNS);
18366
+ const codeBlockCount = countCodeBlocks(content);
18367
+ const hasCodeExamples = codeBlockCount >= 2;
18368
+ const vagueTermCount = countVagueTerms(content);
18369
+ let score = 0;
18370
+ if (hasConcreteCommands) score += 30;
18371
+ if (hasFilePatterns) score += 25;
18372
+ if (hasCodeExamples) score += 30;
18373
+ if (vagueTermCount === 0) score += 15;
18374
+ else if (vagueTermCount <= 2) score += 10;
18375
+ else if (vagueTermCount <= 5) score += 5;
18376
+ return {
18377
+ score: Math.min(100, score),
18378
+ hasConcreteCommands,
18379
+ hasFilePatterns,
18380
+ hasCodeExamples,
18381
+ vagueTermCount
18382
+ };
18383
+ }
18384
+ function generateWarnings(structure, clarity, specificity, advanced) {
18385
+ const warnings = [];
18386
+ if (!structure.hasMetadata) {
18387
+ warnings.push("Missing frontmatter metadata");
18388
+ }
18389
+ if (!structure.hasTriggers) {
18390
+ warnings.push("No trigger conditions defined");
18391
+ }
18392
+ if (!structure.hasBoundaries) {
18393
+ warnings.push("No boundaries or constraints specified");
18394
+ }
18395
+ if (clarity.lineCount > 500) {
18396
+ warnings.push(`Skill is too long (${clarity.lineCount} lines)`);
18397
+ }
18398
+ if (clarity.tokenCount > 4e3) {
18399
+ warnings.push(`High token usage (${clarity.tokenCount} tokens)`);
18400
+ }
18401
+ if (specificity.vagueTermCount > 5) {
18402
+ warnings.push(`Contains ${specificity.vagueTermCount} vague terms`);
18403
+ }
18404
+ if (!structure.hasExamples) {
18405
+ warnings.push("No code examples provided");
18406
+ } else if (!specificity.hasCodeExamples) {
18407
+ warnings.push("Only one code example provided");
18408
+ }
18409
+ for (const issue of advanced.securityIssues) {
18410
+ warnings.push(`Security: ${issue}`);
18411
+ }
18412
+ for (const conflict of advanced.conflictingInstructions) {
18413
+ warnings.push(conflict);
18414
+ }
18415
+ if (advanced.completeness.hasTodos) {
18416
+ warnings.push(`Contains ${advanced.completeness.todoCount} TODO/FIXME comment(s)`);
18417
+ }
18418
+ if (advanced.completeness.emptySections.length > 0) {
18419
+ warnings.push(`Empty sections: ${advanced.completeness.emptySections.join(", ")}`);
18420
+ }
18421
+ return warnings;
18422
+ }
18423
+ function generateSuggestions(structure, clarity, specificity, advanced) {
18424
+ const suggestions = [];
18425
+ if (!structure.hasMetadata) {
18426
+ suggestions.push("Add YAML frontmatter with name, description, and globs");
18427
+ }
18428
+ if (!structure.hasTriggers) {
18429
+ suggestions.push('Add a "When to Use" section with specific trigger conditions');
18430
+ }
18431
+ if (!structure.hasExamples) {
18432
+ suggestions.push("Include code examples showing expected output");
18433
+ }
18434
+ if (!structure.hasBoundaries) {
18435
+ suggestions.push("Define boundaries: what the agent should never do");
18436
+ }
18437
+ if (clarity.lineCount > 300) {
18438
+ suggestions.push("Consider splitting into multiple focused skills");
18439
+ }
18440
+ if (!clarity.hasHeaders) {
18441
+ suggestions.push("Use markdown headers to organize content");
18442
+ }
18443
+ if (specificity.vagueTermCount > 0) {
18444
+ suggestions.push("Replace vague terms with specific instructions");
18445
+ }
18446
+ if (!specificity.hasConcreteCommands) {
18447
+ suggestions.push("Add concrete executable commands with flags");
18448
+ }
18449
+ if (advanced.deprecatedPatterns.length > 0) {
18450
+ suggestions.push("Update code examples to use modern patterns (ES modules, hooks, async/await)");
18451
+ }
18452
+ if (advanced.securityIssues.length > 0) {
18453
+ suggestions.push("Review and remove potential security risks from examples");
18454
+ }
18455
+ if (advanced.completeness.hasTodos) {
18456
+ suggestions.push("Complete or remove TODO/FIXME comments");
18457
+ }
18458
+ if (advanced.completeness.emptySections.length > 0) {
18459
+ suggestions.push("Add content to empty sections or remove them");
18460
+ }
18461
+ if (advanced.completeness.exampleCoverage < 50) {
18462
+ suggestions.push("Add more code examples to improve coverage");
18463
+ }
18464
+ return suggestions;
18465
+ }
18466
+ function evaluateSkillContent(content) {
18467
+ const structure = evaluateStructure(content);
18468
+ const clarity = evaluateClarity(content);
18469
+ const specificity = evaluateSpecificity(content);
18470
+ const advanced = evaluateAdvanced(content);
18471
+ const overall = Math.round(
18472
+ structure.score * 0.35 + clarity.score * 0.25 + specificity.score * 0.25 + advanced.score * 0.15
18473
+ );
18474
+ const warnings = generateWarnings(structure, clarity, specificity, advanced);
18475
+ const suggestions = generateSuggestions(structure, clarity, specificity, advanced);
18476
+ return {
18477
+ overall,
18478
+ structure,
18479
+ clarity,
18480
+ specificity,
18481
+ advanced,
18482
+ warnings,
18483
+ suggestions
18484
+ };
18485
+ }
18486
+ function evaluateSkillFile(filePath) {
18487
+ if (!existsSync34(filePath)) return null;
18488
+ try {
18489
+ const content = readFileSync26(filePath, "utf-8");
18490
+ return evaluateSkillContent(content);
18491
+ } catch {
18492
+ return null;
18493
+ }
18494
+ }
18495
+ function evaluateSkillDirectory(dirPath) {
18496
+ const skillMdPath = join35(dirPath, "SKILL.md");
18497
+ if (existsSync34(skillMdPath)) {
18498
+ return evaluateSkillFile(skillMdPath);
18499
+ }
18500
+ const mdcFiles = ["index.mdc", `${basename12(dirPath)}.mdc`];
18501
+ for (const file of mdcFiles) {
18502
+ const mdcPath = join35(dirPath, file);
18503
+ if (existsSync34(mdcPath)) {
18504
+ return evaluateSkillFile(mdcPath);
18505
+ }
18506
+ }
18507
+ return null;
18508
+ }
18509
+ function getQualityGrade(score) {
18510
+ if (score >= 90) return "A";
18511
+ if (score >= 80) return "B";
18512
+ if (score >= 70) return "C";
18513
+ if (score >= 60) return "D";
18514
+ return "F";
18515
+ }
18516
+ function isHighQuality(score) {
18517
+ return score.overall >= 80 && score.warnings.length <= 2;
18518
+ }
17525
18519
  export {
17526
18520
  AGENT_CLI_CONFIGS,
17527
18521
  AGENT_CONFIG,
@@ -17620,7 +18614,9 @@ export {
17620
18614
  addToManifest,
17621
18615
  agentExists,
17622
18616
  analyzeProject,
18617
+ benchmarkSkill,
17623
18618
  buildSkillIndex,
18619
+ calculatePercentile,
17624
18620
  canTranslate,
17625
18621
  copilotTranslator,
17626
18622
  createAPIBasedCompressor,
@@ -17658,6 +18654,7 @@ export {
17658
18654
  createWorkflowOrchestrator,
17659
18655
  createWorkflowTemplate,
17660
18656
  cursorTranslator,
18657
+ detectCategory,
17661
18658
  detectProvider,
17662
18659
  detectSkillFormat,
17663
18660
  discoverAgents,
@@ -17668,6 +18665,9 @@ export {
17668
18665
  discoverSkills,
17669
18666
  dryRunExecutor,
17670
18667
  estimateTokens,
18668
+ evaluateSkillContent,
18669
+ evaluateSkillDirectory,
18670
+ evaluateSkillFile,
17671
18671
  executeWithAgent,
17672
18672
  exportBundle,
17673
18673
  extractAgentContent,
@@ -17683,7 +18683,9 @@ export {
17683
18683
  findSkill,
17684
18684
  formatSkillAsPrompt,
17685
18685
  fromCanonicalAgent,
18686
+ generateComparisonNotes,
17686
18687
  generateManifestFromInstalled,
18688
+ generateRecommendations,
17687
18689
  generateSkillsConfig,
17688
18690
  getAgentCLIConfig,
17689
18691
  getAgentConfigFile,
@@ -17695,16 +18697,19 @@ export {
17695
18697
  getAgentStats,
17696
18698
  getAgentTargetDirectory,
17697
18699
  getAgentsDirectory,
18700
+ getAllCategories,
17698
18701
  getAllProviders,
17699
18702
  getAllSkillsDirs,
17700
18703
  getAvailableCLIAgents,
17701
18704
  getBuiltinPacksDir,
17702
18705
  getCICDTemplate,
18706
+ getCategoryStats,
17703
18707
  getConfigFile,
17704
18708
  getConfigFormat,
17705
18709
  getExecutionStrategy,
17706
18710
  getGlobalConfigPath,
17707
18711
  getGlobalSkillsDir,
18712
+ getGrade,
17708
18713
  getIndexStatus,
17709
18714
  getInstallDir,
17710
18715
  getManualExecutionInstructions,
@@ -17712,6 +18717,7 @@ export {
17712
18717
  getMemoryStatus,
17713
18718
  getProjectConfigPath,
17714
18719
  getProvider,
18720
+ getQualityGrade,
17715
18721
  getSearchDirs,
17716
18722
  getSkillsDir,
17717
18723
  getStackTags,
@@ -17726,6 +18732,7 @@ export {
17726
18732
  isAgentCLIAvailable,
17727
18733
  isAgentCompatible,
17728
18734
  isGitUrl,
18735
+ isHighQuality,
17729
18736
  isIndexStale,
17730
18737
  isLocalPath,
17731
18738
  isPathInside,