skillops-cli 1.3.0 → 1.3.2

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 (5) hide show
  1. package/README.md +52 -49
  2. package/dist/cli.js +818 -551
  3. package/dist/index.d.ts +181 -138
  4. package/dist/index.js +701 -504
  5. package/package.json +84 -84
package/dist/cli.js CHANGED
@@ -6,15 +6,11 @@ import path10 from "path";
6
6
  import { fileURLToPath, pathToFileURL } from "url";
7
7
  import YAML6 from "yaml";
8
8
 
9
- // src/auditor/parser.ts
10
- import fs2 from "fs";
11
- import path from "path";
12
-
13
9
  // src/models.ts
14
10
  import fs from "fs";
15
11
  import YAML from "yaml";
16
12
  import { z } from "zod";
17
- var SKILLOPS_VERSION = "1.3.0";
13
+ var SKILLOPS_VERSION = "1.3.2";
18
14
  var SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
19
15
  var SEMVER_REGEX = /^\d+\.\d+\.\d+$/;
20
16
  var FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
@@ -30,7 +26,9 @@ function estimateTokenCount(text) {
30
26
  return 0;
31
27
  }
32
28
  const words = countWords(stripped);
33
- const punctBonus = Math.floor((stripped.match(PUNCT_CODE_REGEX)?.length ?? 0) / 4);
29
+ const punctBonus = Math.floor(
30
+ (stripped.match(PUNCT_CODE_REGEX)?.length ?? 0) / 4
31
+ );
34
32
  return Math.max(1, Math.ceil(words * 1.33) + punctBonus);
35
33
  }
36
34
  function splitFrontmatter(rawText, sourceLabel) {
@@ -44,7 +42,9 @@ function splitFrontmatter(rawText, sourceLabel) {
44
42
  const body = match[2] ?? "";
45
43
  const parsed = YAML.parse(yamlText);
46
44
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
47
- throw new Error(`YAML frontmatter in '${sourceLabel}' must evaluate to a key-value mapping.`);
45
+ throw new Error(
46
+ `YAML frontmatter in '${sourceLabel}' must evaluate to a key-value mapping.`
47
+ );
48
48
  }
49
49
  return [parsed, body];
50
50
  }
@@ -543,7 +543,9 @@ var SubagentManifestSchema = z.object({
543
543
  });
544
544
  }
545
545
  }),
546
- tools: z.array(z.string().min(1)).min(1, { message: "Subagent must declare an explicit non-empty tool allowlist per INV-SKILL-04." }).superRefine((tools, ctx) => {
546
+ tools: z.array(z.string().min(1)).min(1, {
547
+ message: "Subagent must declare an explicit non-empty tool allowlist per INV-SKILL-04."
548
+ }).superRefine((tools, ctx) => {
547
549
  for (const tool of tools) {
548
550
  if (FORBIDDEN_WILDCARD_TOOLS.has(tool.trim().toLowerCase())) {
549
551
  ctx.addIssue({
@@ -734,7 +736,14 @@ var SyncedArtifactSchema = z.object({
734
736
  skill_name: z.string().min(1),
735
737
  relative_path: z.string().min(1),
736
738
  sha256: z.string().regex(/^[0-9a-f]{64}$/),
737
- action: z.enum(["created", "updated", "unchanged", "removed", "planned", "conflict"])
739
+ action: z.enum([
740
+ "created",
741
+ "updated",
742
+ "unchanged",
743
+ "removed",
744
+ "planned",
745
+ "conflict"
746
+ ])
738
747
  }).strict();
739
748
  var SyncLockEntrySchema = z.object({
740
749
  target: RuntimeTargetSchema,
@@ -820,6 +829,8 @@ function loadSkillOpsConfig(repoPath) {
820
829
  }
821
830
 
822
831
  // src/auditor/parser.ts
832
+ import fs2 from "fs";
833
+ import path from "path";
823
834
  function walkForFilesNamed(rootDir, targetFilename) {
824
835
  if (!fs2.existsSync(rootDir)) {
825
836
  return [];
@@ -852,7 +863,10 @@ function parseSkillDirectory(skillDir, options = {}) {
852
863
  const rawText = fs2.readFileSync(skillMdPath, "utf-8");
853
864
  const lines = rawText.split(/\r?\n/);
854
865
  const totalLines = rawText.endsWith("\n") ? lines.length - 1 : lines.length;
855
- const [, markdownBody] = splitFrontmatter(rawText, skillMdPath.replace(/\\/g, "/"));
866
+ const [, markdownBody] = splitFrontmatter(
867
+ rawText,
868
+ skillMdPath.replace(/\\/g, "/")
869
+ );
856
870
  const manifest = parseSkillMdFile(skillMdPath);
857
871
  const declaredScripts = [];
858
872
  const missingDeclaredScripts = [];
@@ -886,7 +900,9 @@ function parseSkillDirectory(skillDir, options = {}) {
886
900
  const referencesDir = path.join(skillDir, "references");
887
901
  const referenceFiles = [];
888
902
  if (fs2.existsSync(referencesDir) && fs2.statSync(referencesDir).isDirectory()) {
889
- for (const entry of fs2.readdirSync(referencesDir, { withFileTypes: true })) {
903
+ for (const entry of fs2.readdirSync(referencesDir, {
904
+ withFileTypes: true
905
+ })) {
890
906
  if (entry.isFile() && entry.name.endsWith(".md")) {
891
907
  referenceFiles.push(path.join(referencesDir, entry.name));
892
908
  }
@@ -951,112 +967,6 @@ function parseSubagentFile(filePath) {
951
967
  };
952
968
  }
953
969
 
954
- // src/auditor/token_budget.ts
955
- function auditSkillTokenBudget(skillDir, options = {}) {
956
- const requireLayout = options.requireLayout ?? false;
957
- try {
958
- const parsed = parseSkillDirectory(skillDir, { requireLayout });
959
- const warnings = [];
960
- const errors = [];
961
- if (parsed.manifest.routing_signals.negative_triggers.length === 0 && !parsed.manifest.description.toLowerCase().includes("do not trigger")) {
962
- warnings.push(
963
- `Skill '${parsed.manifest.name}' has no explicit negative triggers ('Do not trigger for...' or routing_signals.negative_triggers).`
964
- );
965
- }
966
- if (requireLayout && parsed.missingDeclaredScripts.length > 0) {
967
- errors.push(
968
- `Skill '${parsed.manifest.name}' is missing declared script(s): ${parsed.missingDeclaredScripts.join(", ")}`
969
- );
970
- }
971
- return {
972
- skillName: parsed.manifest.name,
973
- skillDir: skillDir.replace(/\\/g, "/"),
974
- l1Words: parsed.manifest.description_words,
975
- l1Tokens: parsed.manifest.description_tokens,
976
- l2Lines: parsed.manifest.body_lines,
977
- l2Tokens: parsed.manifest.body_tokens,
978
- totalLines: parsed.totalLines,
979
- scriptsCount: parsed.declaredScripts.length,
980
- passed: errors.length === 0,
981
- errors,
982
- warnings
983
- };
984
- } catch (err) {
985
- const message = err instanceof Error ? err.message : String(err);
986
- return {
987
- skillName: skillDir.split(/[\\/]/).pop() ?? "unknown",
988
- skillDir: skillDir.replace(/\\/g, "/"),
989
- l1Words: 0,
990
- l1Tokens: 0,
991
- l2Lines: 0,
992
- l2Tokens: 0,
993
- totalLines: 0,
994
- scriptsCount: 0,
995
- passed: false,
996
- errors: [message],
997
- warnings: []
998
- };
999
- }
1000
- }
1001
- function auditSubagentTokenBudget(filePath) {
1002
- try {
1003
- const parsed = parseSubagentFile(filePath);
1004
- return {
1005
- subagentName: parsed.manifest.name,
1006
- filePath: filePath.replace(/\\/g, "/"),
1007
- descriptionTokens: parsed.manifest.description_tokens,
1008
- systemPromptLines: parsed.manifest.system_prompt_lines,
1009
- systemPromptTokens: parsed.manifest.system_prompt_tokens,
1010
- maxOutputTokens: parsed.manifest.max_output_tokens,
1011
- tools: parsed.manifest.tools,
1012
- passed: true,
1013
- errors: []
1014
- };
1015
- } catch (err) {
1016
- const message = err instanceof Error ? err.message : String(err);
1017
- return {
1018
- subagentName: filePath.split(/[\\/]/).pop() ?? "unknown",
1019
- filePath: filePath.replace(/\\/g, "/"),
1020
- descriptionTokens: 0,
1021
- systemPromptLines: 0,
1022
- systemPromptTokens: 0,
1023
- maxOutputTokens: 0,
1024
- tools: [],
1025
- passed: false,
1026
- errors: [message]
1027
- };
1028
- }
1029
- }
1030
- function auditCatalogTokenBudgets(catalogDir, options = {}) {
1031
- const skillDirs = discoverSkillDirectories(catalogDir);
1032
- const subagentFiles = discoverSubagentFiles(catalogDir);
1033
- const skills = skillDirs.map((dir) => auditSkillTokenBudget(dir, options));
1034
- const subagents = subagentFiles.map((file) => auditSubagentTokenBudget(file));
1035
- const errors = [];
1036
- const warnings = [];
1037
- let totalL1Tokens = 0;
1038
- let totalSubagentPromptTokens = 0;
1039
- for (const s of skills) {
1040
- totalL1Tokens += s.l1Tokens;
1041
- errors.push(...s.errors);
1042
- warnings.push(...s.warnings);
1043
- }
1044
- for (const sa of subagents) {
1045
- totalSubagentPromptTokens += sa.systemPromptTokens;
1046
- errors.push(...sa.errors);
1047
- }
1048
- return {
1049
- catalogPath: catalogDir.replace(/\\/g, "/"),
1050
- skills,
1051
- subagents,
1052
- totalL1Tokens,
1053
- totalSubagentPromptTokens,
1054
- errors,
1055
- warnings,
1056
- passed: errors.length === 0
1057
- };
1058
- }
1059
-
1060
970
  // src/auditor/collision.ts
1061
971
  var ROUTING_STOPWORDS = /* @__PURE__ */ new Set([
1062
972
  "a",
@@ -1385,6 +1295,12 @@ function auditCatalog(catalogDir, options = {}) {
1385
1295
  });
1386
1296
  }
1387
1297
 
1298
+ // src/auditor/doctor.ts
1299
+ import { spawnSync } from "child_process";
1300
+ import crypto from "crypto";
1301
+ import fs4 from "fs";
1302
+ import path3 from "path";
1303
+
1388
1304
  // src/auditor/token_economy.ts
1389
1305
  import fs3 from "fs";
1390
1306
  import path2 from "path";
@@ -1456,42 +1372,10 @@ function padVisible(text, width, align = "left") {
1456
1372
  }
1457
1373
  return `${text}${" ".repeat(diff)}`;
1458
1374
  }
1459
- function renderBox(lines, options) {
1460
- const paddingX = options?.paddingX ?? 2;
1461
- const minWidth = options?.minWidth ?? 64;
1462
- const colorEnabled = options?.colorEnabled;
1463
- const borderFn = options?.borderColor ?? style.cyan;
1464
- const titleText = options?.title ? ` ${options.title.trim()} ` : "";
1465
- const titleVisibleLen = visibleLength(titleText);
1466
- const maxLineLen = lines.reduce(
1467
- (max, line) => Math.max(max, visibleLength(line)),
1468
- 0
1469
- );
1470
- const innerWidth = Math.max(
1471
- minWidth,
1472
- maxLineLen + paddingX * 2,
1473
- titleVisibleLen + 4
1474
- );
1475
- const contentWidth = innerWidth - paddingX * 2;
1476
- const padStr = " ".repeat(paddingX);
1477
- const topBorder = titleVisibleLen > 0 ? `${borderFn("\u256D\u2500", colorEnabled)}${style.bold(titleText, colorEnabled)}${borderFn(`${"\u2500".repeat(Math.max(1, innerWidth - titleVisibleLen - 1))}\u256E`, colorEnabled)}` : borderFn(`\u256D${"\u2500".repeat(innerWidth)}\u256E`, colorEnabled);
1478
- const bodyLines = lines.map((line) => {
1479
- const padded = padVisible(line, contentWidth, "left");
1480
- return `${borderFn("\u2502", colorEnabled)}${padStr}${padded}${padStr}${borderFn("\u2502", colorEnabled)}`;
1481
- });
1482
- const bottomBorder = borderFn(`\u2570${"\u2500".repeat(innerWidth)}\u256F`, colorEnabled);
1483
- return [topBorder, ...bodyLines, bottomBorder].join("\n");
1484
- }
1485
- function renderHeaderBanner(subtitle = "Framework & Library for High-End AI Coding Skills & Subagents", options) {
1375
+ function renderHeaderBanner(subtitle = "Framework & Library for AI Skills & Subagents", options) {
1486
1376
  const ver = options?.version ?? SKILLOPS_VERSION;
1487
1377
  const c = options?.colorEnabled;
1488
- const headline = `${style.bold(style.cyan(`\u26A1 SkillOps v${ver}`, c), c)} ${style.dim("\u2014", c)} ${subtitle}`;
1489
- return renderBox([headline], {
1490
- borderColor: style.cyan,
1491
- paddingX: 2,
1492
- minWidth: 72,
1493
- colorEnabled: c
1494
- });
1378
+ return `${style.bold(style.cyan(`\u25C6 SkillOps v${ver}`, c), c)} ${style.dim("\u2014", c)} ${subtitle}`;
1495
1379
  }
1496
1380
  function renderTable(headers, rows, options) {
1497
1381
  const indent = " ".repeat(options?.indent ?? 2);
@@ -1524,7 +1408,7 @@ function renderTable(headers, rows, options) {
1524
1408
  ].join("\n");
1525
1409
  }
1526
1410
  function renderTokenBar(current, max, options) {
1527
- const width = options?.width ?? 18;
1411
+ const width = options?.width ?? 10;
1528
1412
  const unit = options?.unit ?? "tokens";
1529
1413
  const c = options?.colorEnabled;
1530
1414
  const safeMax = max > 0 ? max : 1;
@@ -1542,9 +1426,8 @@ function renderTokenBar(current, max, options) {
1542
1426
  var renderProgressBar = renderTokenBar;
1543
1427
  function renderSectionHeader(title, colorEnabled) {
1544
1428
  const c = colorEnabled;
1545
- return `
1546
- ${style.bold(style.cyan(title, c), c)}
1547
- ${style.dim("\u2500".repeat(Math.max(24, visibleLength(title))), c)}`;
1429
+ return `${style.dim("\u2502", c)}
1430
+ ${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan(title, c), c)}`;
1548
1431
  }
1549
1432
  function formatBadge(type, customLabel, colorEnabled) {
1550
1433
  switch (type) {
@@ -1583,73 +1466,72 @@ function formatBadge(type, customLabel, colorEnabled) {
1583
1466
  function renderStep(step, total, title, detail, status = "done", colorEnabled) {
1584
1467
  const icon = status === "done" ? style.green("\u2714", colorEnabled) : status === "warn" ? style.yellow("\u26A0", colorEnabled) : style.dim("\u25CB", colorEnabled);
1585
1468
  const stepBadge = style.dim(`[${step}/${total}]`, colorEnabled);
1586
- const titleStyled = style.bold(padVisible(title, 28, "left"), colorEnabled);
1587
- const detailStyled = detail ? ` ${style.dim("\u2022", colorEnabled)} ${detail}` : "";
1588
- return ` ${icon} ${stepBadge} ${titleStyled}${detailStyled}`;
1469
+ const titleStyled = style.bold(padVisible(title, 20, "left"), colorEnabled);
1470
+ const detailStyled = detail ? ` ${style.dim("\xB7", colorEnabled)} ${detail}` : "";
1471
+ return `${style.dim("\u2502", colorEnabled)} ${icon} ${stepBadge} ${titleStyled}${detailStyled}`;
1589
1472
  }
1590
1473
  function renderNextSteps(hints, colorEnabled) {
1591
1474
  if (hints.length === 0) {
1592
1475
  return "";
1593
1476
  }
1594
1477
  const c = colorEnabled;
1595
- const maxCmdLen = hints.reduce(
1596
- (m, h) => Math.max(m, visibleLength(h.command)),
1597
- 0
1478
+ const maxCmdLen = Math.min(
1479
+ 44,
1480
+ hints.reduce((m, h) => Math.max(m, visibleLength(h.command)), 0)
1598
1481
  );
1599
1482
  const lines = [
1600
- "",
1601
- ` ${style.bold(style.cyan("\u{1F4A1} Next Steps:", c), c)}`,
1602
- ...hints.map(
1603
- (h) => ` ${style.green(padVisible(h.command, maxCmdLen + 2, "left"), c)} ${style.dim(`# ${h.description}`, c)}`
1604
- ),
1605
- ""
1483
+ style.dim("\u2502", c),
1484
+ `${style.dim("\u2570\u2500", c)} ${style.bold(style.cyan("Next Steps:", c), c)}`,
1485
+ ...hints.map((h) => {
1486
+ const cmdPadded = padVisible(h.command, maxCmdLen, "left");
1487
+ const prefixCols = 5 + visibleLength(cmdPadded) + 3;
1488
+ const maxDescCols = Math.max(10, 76 - prefixCols);
1489
+ const desc = h.description.length > maxDescCols ? `${h.description.slice(0, maxDescCols - 1)}\u2026` : h.description;
1490
+ return ` ${style.dim("$", c)} ${style.green(cmdPadded, c)} ${style.dim(`\u2014 ${desc}`, c)}`;
1491
+ })
1606
1492
  ];
1607
- return lines.join("\n");
1493
+ return `${lines.join("\n")}
1494
+ `;
1608
1495
  }
1609
1496
  function renderAiUsageGuide(targets, skills, subagents, colorEnabled) {
1610
1497
  const c = colorEnabled;
1611
1498
  const sampleSkill = skills[0] ?? "systematic-debugging";
1612
1499
  const sampleAgent = subagents[0] ?? "context-scout";
1500
+ const bar = style.dim("\u2502", c);
1613
1501
  const lines = [
1614
- `${style.bold("How to use your installed Skills & Subagents inside your AI:", c)}`,
1615
- ""
1502
+ bar,
1503
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan("Using Your Skills & Subagents", c), c)}`
1616
1504
  ];
1617
1505
  const targetSet = new Set(targets);
1618
1506
  if (targetSet.has("claude") || targetSet.size === 0) {
1619
1507
  lines.push(
1620
- `\u2022 ${style.bold("Claude Code:", c)} Ask naturally (auto-routed via .claude/skills/${sampleSkill}/SKILL.md) or delegate to @${sampleAgent}`
1508
+ `${bar} \u2022 ${style.bold("Claude Code:", c)} Auto-routed (${sampleSkill}) or @${sampleAgent}`
1621
1509
  );
1622
1510
  }
1623
1511
  if (targetSet.has("cursor")) {
1624
1512
  lines.push(
1625
- `\u2022 ${style.bold("Cursor IDE:", c)} Type ${style.cyan(`@${sampleSkill}`, c)} in Cursor Chat/Composer or let .cursor/rules/${sampleSkill}.mdc auto-attach`
1513
+ `${bar} \u2022 ${style.bold("Cursor IDE:", c)} Type ${style.cyan(`@${sampleSkill}`, c)} in Chat (.cursor/rules/)`
1626
1514
  );
1627
1515
  }
1628
1516
  if (targetSet.has("antigravity")) {
1629
1517
  lines.push(
1630
- `\u2022 ${style.bold("Antigravity / Gemini:", c)} Auto-activated from .agent/skills/${sampleSkill}/SKILL.md when your prompt matches its domain`
1518
+ `${bar} \u2022 ${style.bold("Antigravity:", c)} Auto-activated (.agent/skills/${sampleSkill})`
1631
1519
  );
1632
1520
  }
1633
1521
  if (targetSet.has("copilot")) {
1634
1522
  lines.push(
1635
- `\u2022 ${style.bold("GitHub Copilot:", c)} Use ${style.cyan(`/${sampleSkill}`, c)} prompt in Copilot Chat or reference .github/instructions/${sampleSkill}.instructions.md`
1523
+ `${bar} \u2022 ${style.bold("Copilot:", c)} Use ${style.cyan(`/${sampleSkill}`, c)} in Chat (.github/instructions/)`
1636
1524
  );
1637
1525
  }
1638
1526
  if (targetSet.has("windsurf") || targetSet.has("cline") || targetSet.has("roocode") || targetSet.has("kilocode")) {
1639
1527
  lines.push(
1640
- `\u2022 ${style.bold("Windsurf / Cline / Roo / Kilo:", c)} Rules in .windsurf/rules/, .clinerules/, .roo/rules/, .kilocode/rules/ activate automatically`
1528
+ `${bar} \u2022 ${style.bold("Windsurf/Cline/Roo/Kilo:", c)} Workspace rules load automatically`
1641
1529
  );
1642
1530
  }
1643
1531
  lines.push(
1644
- `\u2022 ${style.bold("Inspect any Skill/Agent:", c)} Run ${style.green(`npx skillops-cli info ${sampleSkill}`, c)} to view triggers, L3 scripts & prompts`
1532
+ `${bar} \u2022 ${style.bold("Inspect:", c)} ${style.green(`npx skillops-cli info ${sampleSkill}`, c)}`
1645
1533
  );
1646
- return renderBox(lines, {
1647
- title: "\u{1F680} Using Your Skills & Subagents",
1648
- borderColor: style.green,
1649
- paddingX: 2,
1650
- minWidth: 72,
1651
- colorEnabled: c
1652
- });
1534
+ return lines.join("\n");
1653
1535
  }
1654
1536
  function levenshteinDistance(a, b) {
1655
1537
  const s1 = a.toLowerCase();
@@ -2087,7 +1969,7 @@ function formatTokenEconomyReport(report, format = "table") {
2087
1969
  const startupBar = renderProgressBar(
2088
1970
  report.startup_token_tax,
2089
1971
  report.startup_tax_budget,
2090
- { width: 18, unit: "tokens" }
1972
+ { width: 10, unit: "tokens" }
2091
1973
  );
2092
1974
  const lines = [
2093
1975
  "=== SkillOps Token Economy & Startup Context Tax Analyzer ===",
@@ -2112,11 +1994,11 @@ function formatTokenEconomyReport(report, format = "table") {
2112
1994
  renderNextSteps([
2113
1995
  {
2114
1996
  command: "npx skillops-cli quickstart",
2115
- description: "Sync Progressive Disclosure Skills & Context-Isolated Subagents"
1997
+ description: "Sync Progressive Disclosure Skills & Subagents"
2116
1998
  },
2117
1999
  {
2118
2000
  command: "npx skillops-cli doctor",
2119
- description: "Inspect repository lockfile & startup tax diagnostics"
2001
+ description: "Inspect lockfile & startup tax diagnostics"
2120
2002
  }
2121
2003
  ]).trimEnd()
2122
2004
  );
@@ -2125,10 +2007,6 @@ function formatTokenEconomyReport(report, format = "table") {
2125
2007
  }
2126
2008
 
2127
2009
  // src/auditor/doctor.ts
2128
- import { spawnSync } from "child_process";
2129
- import crypto from "crypto";
2130
- import fs4 from "fs";
2131
- import path3 from "path";
2132
2010
  function computeFileSha256(content) {
2133
2011
  return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
2134
2012
  }
@@ -2360,10 +2238,12 @@ function inspectHarnesses(repoPath) {
2360
2238
  const repoLabel = path3.basename(resolvedRepo) || ".";
2361
2239
  const detectedHarnesses = detectInstalledHarnesses(resolvedRepo);
2362
2240
  const detectedSet = new Set(detectedHarnesses);
2363
- const harnesses = ALL_RUNTIME_TARGETS.map((target) => ({
2364
- ...RUNTIME_HARNESS_SPECS[target],
2365
- detected: detectedSet.has(target)
2366
- }));
2241
+ const harnesses = ALL_RUNTIME_TARGETS.map(
2242
+ (target) => ({
2243
+ ...RUNTIME_HARNESS_SPECS[target],
2244
+ detected: detectedSet.has(target)
2245
+ })
2246
+ );
2367
2247
  return {
2368
2248
  repo_path: repoLabel,
2369
2249
  total_supported: harnesses.length,
@@ -2420,9 +2300,13 @@ function formatDoctorReport(report, format = "table") {
2420
2300
  }
2421
2301
  for (const check of report.checks) {
2422
2302
  if (check.status === "fail") {
2423
- lines2.push(`::error title=SkillOps Doctor (${check.title})::${check.summary}`);
2303
+ lines2.push(
2304
+ `::error title=SkillOps Doctor (${check.title})::${check.summary}`
2305
+ );
2424
2306
  } else if (check.status === "warn") {
2425
- lines2.push(`::warning title=SkillOps Doctor (${check.title})::${check.summary}`);
2307
+ lines2.push(
2308
+ `::warning title=SkillOps Doctor (${check.title})::${check.summary}`
2309
+ );
2426
2310
  }
2427
2311
  }
2428
2312
  lines2.push(
@@ -2492,7 +2376,9 @@ function formatDoctorReport(report, format = "table") {
2492
2376
  lines.push("-".repeat(64), "Tracked Lockfile Artifacts:");
2493
2377
  for (const art of report.artifacts) {
2494
2378
  const badge = art.status === "healthy" ? "[HEALTHY]" : art.status === "drifted" ? "[DRIFTED]" : "[MISSING]";
2495
- lines.push(` ${badge} ${art.relative_path} (${art.target} :: ${art.item_name})`);
2379
+ lines.push(
2380
+ ` ${badge} ${art.relative_path} (${art.target} :: ${art.item_name})`
2381
+ );
2496
2382
  }
2497
2383
  }
2498
2384
  if (report.remediation.length > 0) {
@@ -2504,6 +2390,112 @@ function formatDoctorReport(report, format = "table") {
2504
2390
  return lines.join("\n");
2505
2391
  }
2506
2392
 
2393
+ // src/auditor/token_budget.ts
2394
+ function auditSkillTokenBudget(skillDir, options = {}) {
2395
+ const requireLayout = options.requireLayout ?? false;
2396
+ try {
2397
+ const parsed = parseSkillDirectory(skillDir, { requireLayout });
2398
+ const warnings = [];
2399
+ const errors = [];
2400
+ if (parsed.manifest.routing_signals.negative_triggers.length === 0 && !parsed.manifest.description.toLowerCase().includes("do not trigger")) {
2401
+ warnings.push(
2402
+ `Skill '${parsed.manifest.name}' has no explicit negative triggers ('Do not trigger for...' or routing_signals.negative_triggers).`
2403
+ );
2404
+ }
2405
+ if (requireLayout && parsed.missingDeclaredScripts.length > 0) {
2406
+ errors.push(
2407
+ `Skill '${parsed.manifest.name}' is missing declared script(s): ${parsed.missingDeclaredScripts.join(", ")}`
2408
+ );
2409
+ }
2410
+ return {
2411
+ skillName: parsed.manifest.name,
2412
+ skillDir: skillDir.replace(/\\/g, "/"),
2413
+ l1Words: parsed.manifest.description_words,
2414
+ l1Tokens: parsed.manifest.description_tokens,
2415
+ l2Lines: parsed.manifest.body_lines,
2416
+ l2Tokens: parsed.manifest.body_tokens,
2417
+ totalLines: parsed.totalLines,
2418
+ scriptsCount: parsed.declaredScripts.length,
2419
+ passed: errors.length === 0,
2420
+ errors,
2421
+ warnings
2422
+ };
2423
+ } catch (err) {
2424
+ const message = err instanceof Error ? err.message : String(err);
2425
+ return {
2426
+ skillName: skillDir.split(/[\\/]/).pop() ?? "unknown",
2427
+ skillDir: skillDir.replace(/\\/g, "/"),
2428
+ l1Words: 0,
2429
+ l1Tokens: 0,
2430
+ l2Lines: 0,
2431
+ l2Tokens: 0,
2432
+ totalLines: 0,
2433
+ scriptsCount: 0,
2434
+ passed: false,
2435
+ errors: [message],
2436
+ warnings: []
2437
+ };
2438
+ }
2439
+ }
2440
+ function auditSubagentTokenBudget(filePath) {
2441
+ try {
2442
+ const parsed = parseSubagentFile(filePath);
2443
+ return {
2444
+ subagentName: parsed.manifest.name,
2445
+ filePath: filePath.replace(/\\/g, "/"),
2446
+ descriptionTokens: parsed.manifest.description_tokens,
2447
+ systemPromptLines: parsed.manifest.system_prompt_lines,
2448
+ systemPromptTokens: parsed.manifest.system_prompt_tokens,
2449
+ maxOutputTokens: parsed.manifest.max_output_tokens,
2450
+ tools: parsed.manifest.tools,
2451
+ passed: true,
2452
+ errors: []
2453
+ };
2454
+ } catch (err) {
2455
+ const message = err instanceof Error ? err.message : String(err);
2456
+ return {
2457
+ subagentName: filePath.split(/[\\/]/).pop() ?? "unknown",
2458
+ filePath: filePath.replace(/\\/g, "/"),
2459
+ descriptionTokens: 0,
2460
+ systemPromptLines: 0,
2461
+ systemPromptTokens: 0,
2462
+ maxOutputTokens: 0,
2463
+ tools: [],
2464
+ passed: false,
2465
+ errors: [message]
2466
+ };
2467
+ }
2468
+ }
2469
+ function auditCatalogTokenBudgets(catalogDir, options = {}) {
2470
+ const skillDirs = discoverSkillDirectories(catalogDir);
2471
+ const subagentFiles = discoverSubagentFiles(catalogDir);
2472
+ const skills = skillDirs.map((dir) => auditSkillTokenBudget(dir, options));
2473
+ const subagents = subagentFiles.map((file) => auditSubagentTokenBudget(file));
2474
+ const errors = [];
2475
+ const warnings = [];
2476
+ let totalL1Tokens = 0;
2477
+ let totalSubagentPromptTokens = 0;
2478
+ for (const s of skills) {
2479
+ totalL1Tokens += s.l1Tokens;
2480
+ errors.push(...s.errors);
2481
+ warnings.push(...s.warnings);
2482
+ }
2483
+ for (const sa of subagents) {
2484
+ totalSubagentPromptTokens += sa.systemPromptTokens;
2485
+ errors.push(...sa.errors);
2486
+ }
2487
+ return {
2488
+ catalogPath: catalogDir.replace(/\\/g, "/"),
2489
+ skills,
2490
+ subagents,
2491
+ totalL1Tokens,
2492
+ totalSubagentPromptTokens,
2493
+ errors,
2494
+ warnings,
2495
+ passed: errors.length === 0
2496
+ };
2497
+ }
2498
+
2507
2499
  // src/eval/index.ts
2508
2500
  import fs5 from "fs";
2509
2501
  import path4 from "path";
@@ -2563,10 +2555,15 @@ function evaluateSkillDirectory(skillDir) {
2563
2555
  const evalsPath = path4.join(skillDir, "evals", "evals.json");
2564
2556
  const rawSuite = JSON.parse(fs5.readFileSync(evalsPath, "utf-8"));
2565
2557
  const suite = SkillEvalSuiteSchema.parse(rawSuite);
2566
- const assertionsCount = suite.evals.reduce((acc, c) => acc + c.assertions.length, 0);
2558
+ const assertionsCount = suite.evals.reduce(
2559
+ (acc, c) => acc + c.assertions.length,
2560
+ 0
2561
+ );
2567
2562
  const benchmarkPath = path4.join(skillDir, "evals", "benchmark.json");
2568
2563
  if (fs5.existsSync(benchmarkPath) && fs5.statSync(benchmarkPath).isFile()) {
2569
- const rawBench = JSON.parse(fs5.readFileSync(benchmarkPath, "utf-8"));
2564
+ const rawBench = JSON.parse(
2565
+ fs5.readFileSync(benchmarkPath, "utf-8")
2566
+ );
2570
2567
  const bench = SkillBenchmarkSchema.parse({
2571
2568
  ...rawBench,
2572
2569
  eval_cases_count: suite.evals.length,
@@ -2622,18 +2619,25 @@ function evaluateCatalog(catalogDir, options = {}) {
2622
2619
  }
2623
2620
  const count = benchmarks.length;
2624
2621
  const meanWith = count > 0 ? Number(
2625
- (benchmarks.reduce((acc, b) => acc + b.with_skill.pass_rate_mean, 0) / count).toFixed(4)
2622
+ (benchmarks.reduce(
2623
+ (acc, b) => acc + b.with_skill.pass_rate_mean,
2624
+ 0
2625
+ ) / count).toFixed(4)
2626
2626
  ) : 0;
2627
2627
  const meanWithout = count > 0 ? Number(
2628
- (benchmarks.reduce((acc, b) => acc + b.without_skill.pass_rate_mean, 0) / count).toFixed(
2629
- 4
2630
- )
2628
+ (benchmarks.reduce(
2629
+ (acc, b) => acc + b.without_skill.pass_rate_mean,
2630
+ 0
2631
+ ) / count).toFixed(4)
2631
2632
  ) : 0;
2632
2633
  const meanGain = count > 0 ? Number(
2633
2634
  (benchmarks.reduce((acc, b) => acc + b.delta.pass_rate_gain, 0) / count).toFixed(4)
2634
2635
  ) : 0;
2635
2636
  const meanTokRed = count > 0 ? Number(
2636
- (benchmarks.reduce((acc, b) => acc + b.delta.token_reduction_pct, 0) / count).toFixed(2)
2637
+ (benchmarks.reduce(
2638
+ (acc, b) => acc + b.delta.token_reduction_pct,
2639
+ 0
2640
+ ) / count).toFixed(2)
2637
2641
  ) : 0;
2638
2642
  return CatalogEvalSummarySchema.parse({
2639
2643
  catalog_path: resolvedCatalog.replace(/\\/g, "/"),
@@ -2739,6 +2743,9 @@ import path7 from "path";
2739
2743
  import readline from "readline";
2740
2744
  import YAML3 from "yaml";
2741
2745
 
2746
+ // src/router/bundle_compiler.ts
2747
+ import path6 from "path";
2748
+
2742
2749
  // src/router/fingerprinter.ts
2743
2750
  import fs6 from "fs";
2744
2751
  import path5 from "path";
@@ -2838,13 +2845,17 @@ var RepoFingerprinter = class {
2838
2845
  python312Plus = true;
2839
2846
  signals.add("python3.12");
2840
2847
  }
2841
- const quotedSpecs = content.match(/["']([a-zA-Z0-9._-]+(?:\[[a-zA-Z0-9,_-]+\])?\s*(?:[><=~!][^"']+)?)["']/g) ?? [];
2848
+ const quotedSpecs = content.match(
2849
+ /["']([a-zA-Z0-9._-]+(?:\[[a-zA-Z0-9,_-]+\])?\s*(?:[><=~!][^"']+)?)["']/g
2850
+ ) ?? [];
2842
2851
  for (const spec of quotedSpecs) {
2843
2852
  recordDep(spec);
2844
2853
  }
2845
2854
  }
2846
2855
  if (fs6.existsSync(this.repoPath)) {
2847
- for (const entry of fs6.readdirSync(this.repoPath, { withFileTypes: true })) {
2856
+ for (const entry of fs6.readdirSync(this.repoPath, {
2857
+ withFileTypes: true
2858
+ })) {
2848
2859
  if (entry.isFile() && /^requirements.*\.txt$/i.test(entry.name)) {
2849
2860
  detectedFiles.add(entry.name);
2850
2861
  languages.add("python");
@@ -2864,8 +2875,14 @@ var RepoFingerprinter = class {
2864
2875
  signals.add("nodejs");
2865
2876
  signals.add("package.json");
2866
2877
  try {
2867
- const pkgJson = JSON.parse(fs6.readFileSync(pkgJsonPath, "utf-8"));
2868
- const depSections = ["dependencies", "devDependencies", "peerDependencies"];
2878
+ const pkgJson = JSON.parse(
2879
+ fs6.readFileSync(pkgJsonPath, "utf-8")
2880
+ );
2881
+ const depSections = [
2882
+ "dependencies",
2883
+ "devDependencies",
2884
+ "peerDependencies"
2885
+ ];
2869
2886
  for (const section of depSections) {
2870
2887
  const obj = pkgJson[section];
2871
2888
  if (obj && typeof obj === "object") {
@@ -2969,7 +2986,6 @@ function fingerprintRepository(repoPath) {
2969
2986
  }
2970
2987
 
2971
2988
  // src/router/bundle_compiler.ts
2972
- import path6 from "path";
2973
2989
  function scoreSkillAgainstProfile(parsedSkill, profile, taskPrompt = "") {
2974
2990
  const manifest = parsedSkill.manifest;
2975
2991
  const repoSignalSet = new Set(
@@ -3190,7 +3206,7 @@ function formatRoutedBundle(bundle, format = "table", colorEnabled) {
3190
3206
  bundle.total_l1_tokens,
3191
3207
  bundle.max_l1_tokens,
3192
3208
  {
3193
- width: 18,
3209
+ width: 10,
3194
3210
  unit: "tokens",
3195
3211
  colorEnabled
3196
3212
  }
@@ -3199,11 +3215,11 @@ function formatRoutedBundle(bundle, format = "table", colorEnabled) {
3199
3215
  [
3200
3216
  {
3201
3217
  command: "npx skillops-cli quickstart",
3202
- description: "Install this recommended bundle & wire MCP in 1 step"
3218
+ description: "Install recommended bundle & wire MCP"
3203
3219
  },
3204
3220
  {
3205
3221
  command: `npx skillops-cli info ${topSkill}`,
3206
- description: `Inspect ${topSkill} triggers, L3 scripts & AI invocation guide`
3222
+ description: `Inspect ${topSkill} triggers & L3 scripts`
3207
3223
  }
3208
3224
  ],
3209
3225
  colorEnabled
@@ -3230,7 +3246,10 @@ var MCP_TOOLS = [
3230
3246
  inputSchema: {
3231
3247
  type: "object",
3232
3248
  properties: {
3233
- catalog_dir: { type: "string", description: "Optional path to catalog directory." }
3249
+ catalog_dir: {
3250
+ type: "string",
3251
+ description: "Optional path to catalog directory."
3252
+ }
3234
3253
  },
3235
3254
  additionalProperties: false
3236
3255
  }
@@ -3241,8 +3260,14 @@ var MCP_TOOLS = [
3241
3260
  inputSchema: {
3242
3261
  type: "object",
3243
3262
  properties: {
3244
- repo_path: { type: "string", description: "Target repository root path." },
3245
- startup_tax_budget: { type: "number", description: "Max startup token budget." }
3263
+ repo_path: {
3264
+ type: "string",
3265
+ description: "Target repository root path."
3266
+ },
3267
+ startup_tax_budget: {
3268
+ type: "number",
3269
+ description: "Max startup token budget."
3270
+ }
3246
3271
  },
3247
3272
  additionalProperties: false
3248
3273
  }
@@ -3253,8 +3278,14 @@ var MCP_TOOLS = [
3253
3278
  inputSchema: {
3254
3279
  type: "object",
3255
3280
  properties: {
3256
- repo_path: { type: "string", description: "Target repository root path." },
3257
- task_prompt: { type: "string", description: "Optional developer task description." }
3281
+ repo_path: {
3282
+ type: "string",
3283
+ description: "Target repository root path."
3284
+ },
3285
+ task_prompt: {
3286
+ type: "string",
3287
+ description: "Optional developer task description."
3288
+ }
3258
3289
  },
3259
3290
  additionalProperties: false
3260
3291
  }
@@ -3277,7 +3308,10 @@ var MCP_TOOLS = [
3277
3308
  inputSchema: {
3278
3309
  type: "object",
3279
3310
  properties: {
3280
- skill_name: { type: "string", description: "Optional skill name filter." }
3311
+ skill_name: {
3312
+ type: "string",
3313
+ description: "Optional skill name filter."
3314
+ }
3281
3315
  },
3282
3316
  additionalProperties: false
3283
3317
  }
@@ -3297,8 +3331,14 @@ var MCP_TOOLS = [
3297
3331
  inputSchema: {
3298
3332
  type: "object",
3299
3333
  properties: {
3300
- repo_path: { type: "string", description: "Target repository root path." },
3301
- startup_tax_budget: { type: "number", description: "Optional startup token budget override." }
3334
+ repo_path: {
3335
+ type: "string",
3336
+ description: "Target repository root path."
3337
+ },
3338
+ startup_tax_budget: {
3339
+ type: "number",
3340
+ description: "Optional startup token budget override."
3341
+ }
3302
3342
  },
3303
3343
  additionalProperties: false
3304
3344
  }
@@ -3309,7 +3349,10 @@ var MCP_TOOLS = [
3309
3349
  inputSchema: {
3310
3350
  type: "object",
3311
3351
  properties: {
3312
- repo_path: { type: "string", description: "Target repository root path." }
3352
+ repo_path: {
3353
+ type: "string",
3354
+ description: "Target repository root path."
3355
+ }
3313
3356
  },
3314
3357
  additionalProperties: false
3315
3358
  }
@@ -3391,7 +3434,9 @@ function handleMcpJsonRpcRequest(request, context) {
3391
3434
  const skillFilter = typeof args.skill_name === "string" ? args.skill_name : void 0;
3392
3435
  payload = evaluateCatalog(context.catalogDir, { skillFilter });
3393
3436
  } else if (toolName === "list_catalog_items") {
3394
- payload = auditCatalogTokenBudgets(context.catalogDir, { requireLayout: false });
3437
+ payload = auditCatalogTokenBudgets(context.catalogDir, {
3438
+ requireLayout: false
3439
+ });
3395
3440
  } else if (toolName === "diagnose_repo") {
3396
3441
  const repoPath = typeof args.repo_path === "string" ? args.repo_path : context.repoPath;
3397
3442
  const budget = typeof args.startup_tax_budget === "number" ? args.startup_tax_budget : void 0;
@@ -3596,7 +3641,11 @@ function setupMcpForHarnesses(repoPath, options = {}) {
3596
3641
  const absPath = path7.join(resolvedRepo, spec.mcpConfigPath);
3597
3642
  const exists = fs7.existsSync(absPath) && fs7.statSync(absPath).isFile();
3598
3643
  const existingRaw = exists ? fs7.readFileSync(absPath, "utf-8") : null;
3599
- const updatedRaw = buildUpdatedMcpConfigContent(target, existingRaw, serverName);
3644
+ const updatedRaw = buildUpdatedMcpConfigContent(
3645
+ target,
3646
+ existingRaw,
3647
+ serverName
3648
+ );
3600
3649
  let status;
3601
3650
  if (!exists) {
3602
3651
  status = "created";
@@ -3616,7 +3665,9 @@ function setupMcpForHarnesses(repoPath, options = {}) {
3616
3665
  status
3617
3666
  });
3618
3667
  }
3619
- const configuredCount = actions.filter((a) => a.status !== "unsupported").length;
3668
+ const configuredCount = actions.filter(
3669
+ (a) => a.status !== "unsupported"
3670
+ ).length;
3620
3671
  return {
3621
3672
  repo_path: path7.basename(resolvedRepo) || ".",
3622
3673
  dry_run: dryRun,
@@ -4460,29 +4511,21 @@ function formatSyncReport(report, format = "table", colorEnabled) {
4460
4511
  (a) => a.action === "created" || a.action === "updated" || a.action === "unchanged"
4461
4512
  );
4462
4513
  const firstSkill = activeArtifacts.find((a) => a.skill_name !== "codex-agents-index")?.skill_name ?? report.routed_bundle.selected_skills[0]?.name ?? "security-sast-gate";
4463
- const usageBox = activeArtifacts.length > 0 ? renderBox(
4464
- [
4465
- `${style.bold("How to use your installed Skills & Subagents inside your AI:", c)}`,
4466
- ` \u2022 ${style.cyan("Claude Code / Antigravity:", c)} Ask naturally (auto-routed via SKILL.md) or delegate to a Subagent`,
4467
- ` \u2022 ${style.cyan("Cursor / Windsurf / Cline / Copilot:", c)} Reference ${style.green(`@${firstSkill}`, c)} in Chat or let rules auto-attach`,
4468
- ` \u2022 ${style.cyan("Deep-Inspect:", c)} Run ${style.green(`npx skillops-cli info ${firstSkill}`, c)} to view triggers & Level 3 scripts`
4469
- ],
4470
- {
4471
- title: "\u{1F680} Using Your Skills & Subagents",
4472
- borderColor: style.cyan,
4473
- minWidth: 74,
4474
- colorEnabled: c
4475
- }
4514
+ const usageBox = activeArtifacts.length > 0 ? renderAiUsageGuide(
4515
+ report.targets,
4516
+ [firstSkill],
4517
+ report.routed_bundle.recommended_subagents,
4518
+ c
4476
4519
  ) : "";
4477
4520
  const nextSteps = renderNextSteps(
4478
4521
  [
4479
4522
  {
4480
4523
  command: `npx skillops-cli info ${firstSkill}`,
4481
- description: "Inspect triggers, token budget & Level 3 scripts"
4524
+ description: "Inspect triggers, token budget & L3 scripts"
4482
4525
  },
4483
4526
  {
4484
4527
  command: "npx skillops-cli doctor",
4485
- description: "Verify lockfile SHA-256 integrity & Startup Token Tax"
4528
+ description: "Verify lockfile SHA-256 & Startup Token Tax"
4486
4529
  }
4487
4530
  ],
4488
4531
  c
@@ -4509,20 +4552,20 @@ var COMMAND_HELP_SPECS = [
4509
4552
  name: "quickstart",
4510
4553
  aliases: ["setup"],
4511
4554
  pillar: "library",
4512
- summary: "1-step onboarding: detect project stack, route optimal Skills & Subagents, sync to AI harnesses & wire MCP",
4555
+ summary: "1-step onboarding: detect, route & sync",
4513
4556
  usage: "npx skillops-cli quickstart [options]",
4514
4557
  options: [
4515
4558
  {
4516
- flags: "--project, --repo, -p <dir>",
4517
- description: "Target repository directory (default: current directory)"
4559
+ flags: "-p, --project <dir>",
4560
+ description: "Target repository directory (default: cwd)"
4518
4561
  },
4519
4562
  {
4520
- flags: "--harness, --targets, -t <list|auto|all>",
4521
- description: "Target AI coding harnesses (e.g. claude,cursor,windsurf or auto/all)"
4563
+ flags: "-t, --harness <list|auto|all>",
4564
+ description: "Target AI coding harnesses (claude,cursor...)"
4522
4565
  },
4523
4566
  {
4524
4567
  flags: "--top, --max-skills <n>",
4525
- description: "Maximum number of Skills to activate in the bundle (default: 12)"
4568
+ description: "Max Skills to activate in bundle (default: 12)"
4526
4569
  },
4527
4570
  {
4528
4571
  flags: "--skip-mcp, --no-mcp",
@@ -4530,25 +4573,25 @@ var COMMAND_HELP_SPECS = [
4530
4573
  },
4531
4574
  {
4532
4575
  flags: "--dry-run",
4533
- description: "Preview planned changes without writing files to disk"
4576
+ description: "Preview planned changes without writing files"
4534
4577
  },
4535
4578
  {
4536
4579
  flags: "--force",
4537
- description: "Overwrite locally modified artifacts if drift is detected"
4580
+ description: "Overwrite locally modified artifacts"
4538
4581
  },
4539
4582
  {
4540
- flags: "--format, -f <table|json|markdown>",
4583
+ flags: "-f, --format <table|json|md>",
4541
4584
  description: "Output report format (default: table)"
4542
4585
  }
4543
4586
  ],
4544
4587
  examples: [
4545
4588
  {
4546
4589
  command: "npx skillops-cli quickstart",
4547
- description: "Auto-detect stack & harnesses, install optimal Skills/Subagents, and configure MCP"
4590
+ description: "Auto-detect stack, sync Skills & wire MCP"
4548
4591
  },
4549
4592
  {
4550
- command: "npx skillops-cli quickstart --harness cursor,claude --top 6",
4551
- description: "Quickstart specifically for Cursor and Claude Code with top 6 Skills"
4593
+ command: "npx skillops-cli quickstart -t cursor,claude --top 6",
4594
+ description: "Sync top 6 Skills to Cursor & Claude Code"
4552
4595
  }
4553
4596
  ]
4554
4597
  },
@@ -4556,7 +4599,7 @@ var COMMAND_HELP_SPECS = [
4556
4599
  name: "list",
4557
4600
  aliases: [],
4558
4601
  pillar: "library",
4559
- summary: "Browse all bundled Hybrid Executable Skills & Context-Isolated Subagents with token budgets",
4602
+ summary: "Browse all 10 Skills & 9 Subagents",
4560
4603
  usage: "npx skillops-cli list [options]",
4561
4604
  options: [
4562
4605
  {
@@ -4564,18 +4607,18 @@ var COMMAND_HELP_SPECS = [
4564
4607
  description: "Custom catalog directory to list"
4565
4608
  },
4566
4609
  {
4567
- flags: "--format, -f <table|json|markdown>",
4610
+ flags: "-f, --format <table|json|md>",
4568
4611
  description: "Output format (default: table)"
4569
4612
  }
4570
4613
  ],
4571
4614
  examples: [
4572
4615
  {
4573
4616
  command: "npx skillops-cli list",
4574
- description: "Display all 10 Skills and 9 Subagents with L1/L2 token footprints"
4617
+ description: "Display all 10 Skills & 9 Subagents"
4575
4618
  },
4576
4619
  {
4577
4620
  command: "npx skillops-cli info security-sast-gate",
4578
- description: "Deep-inspect a specific Skill from the Library after listing"
4621
+ description: "Inspect a specific Skill from the Library"
4579
4622
  }
4580
4623
  ]
4581
4624
  },
@@ -4583,7 +4626,7 @@ var COMMAND_HELP_SPECS = [
4583
4626
  name: "search",
4584
4627
  aliases: ["find"],
4585
4628
  pillar: "library",
4586
- summary: "Search the Library of Skills & Subagents by keyword, domain, framework, or routing signal",
4629
+ summary: "Search catalog by keyword, stack or domain",
4587
4630
  usage: "npx skillops-cli search <query> [options]",
4588
4631
  options: [
4589
4632
  {
@@ -4591,18 +4634,18 @@ var COMMAND_HELP_SPECS = [
4591
4634
  description: "Custom catalog directory to search"
4592
4635
  },
4593
4636
  {
4594
- flags: "--format, -f <table|json|markdown>",
4637
+ flags: "-f, --format <table|json|md>",
4595
4638
  description: "Output format (default: table)"
4596
4639
  }
4597
4640
  ],
4598
4641
  examples: [
4599
4642
  {
4600
4643
  command: "npx skillops-cli search security",
4601
- description: "Find Skills and Subagents matching security/SAST/OWASP signals"
4644
+ description: "Find Skills/Subagents matching security/SAST"
4602
4645
  },
4603
4646
  {
4604
4647
  command: "npx skillops-cli find postgres",
4605
- description: "Find database & PostgreSQL optimization Skills in the Library"
4648
+ description: "Find database & PostgreSQL optimization Skills"
4606
4649
  }
4607
4650
  ]
4608
4651
  },
@@ -4610,65 +4653,65 @@ var COMMAND_HELP_SPECS = [
4610
4653
  name: "info",
4611
4654
  aliases: ["show", "inspect"],
4612
4655
  pillar: "library",
4613
- summary: "Inspect a Skill or Subagent's L1 routing triggers, L2 token budget, L3 scripts & how to use it in your AI",
4614
- usage: "npx skillops-cli info <skill-or-subagent-name> [options]",
4656
+ summary: "Inspect triggers, L2 budget & AI usage",
4657
+ usage: "npx skillops-cli info <name> [options]",
4615
4658
  options: [
4616
4659
  {
4617
4660
  flags: "--catalog <dir>",
4618
4661
  description: "Custom catalog directory"
4619
4662
  },
4620
4663
  {
4621
- flags: "--format, -f <table|json|markdown>",
4664
+ flags: "-f, --format <table|json|md>",
4622
4665
  description: "Output format (default: table)"
4623
4666
  }
4624
4667
  ],
4625
4668
  examples: [
4626
4669
  {
4627
4670
  command: "npx skillops-cli info bug-reproducer-tdd",
4628
- description: "Inspect routing triggers, L3 scripts & IDE invocation guide for bug-reproducer-tdd"
4671
+ description: "Inspect triggers, L3 scripts & IDE invocation"
4629
4672
  },
4630
4673
  {
4631
4674
  command: "npx skillops-cli show red-team-breaker",
4632
- description: "Inspect the red-team-breaker Context-Isolated Subagent card"
4675
+ description: "Inspect the red-team-breaker Subagent card"
4633
4676
  }
4634
4677
  ]
4635
4678
  },
4636
4679
  {
4637
4680
  name: "add",
4638
- aliases: ["install", "i"],
4681
+ aliases: ["install"],
4639
4682
  pillar: "library",
4640
- summary: "Install one or more Skills or Subagents into your active AI coding harnesses",
4683
+ summary: "Install Skills/Subagents into AI harnesses",
4641
4684
  usage: "npx skillops-cli add <name...> [options]",
4642
4685
  options: [
4643
4686
  {
4644
- flags: "--project, --repo, -p <dir>",
4687
+ flags: "-p, --project <dir>",
4645
4688
  description: "Target repository directory"
4646
4689
  },
4647
4690
  {
4648
- flags: "--harness, --targets, -t <list|auto|all>",
4649
- description: "Target AI coding harnesses (e.g. claude,cursor,windsurf or all)"
4691
+ flags: "-t, --harness <list|auto|all>",
4692
+ description: "Target AI harnesses (claude,cursor,all...)"
4650
4693
  },
4651
4694
  {
4652
4695
  flags: "--dry-run",
4653
- description: "Preview planned file writes without modifying disk"
4696
+ description: "Preview planned writes without modifying disk"
4654
4697
  },
4655
4698
  {
4656
4699
  flags: "--force",
4657
4700
  description: "Overwrite locally drifted files"
4658
4701
  },
4659
4702
  {
4660
- flags: "--format, -f <table|json|markdown>",
4703
+ flags: "-f, --format <table|json|md>",
4661
4704
  description: "Output format (default: table)"
4662
4705
  }
4663
4706
  ],
4664
4707
  examples: [
4665
4708
  {
4666
4709
  command: "npx skillops-cli install security-sast-gate",
4667
- description: "Install the security-sast-gate Skill into configured/default harnesses"
4710
+ description: "Install security-sast-gate into harnesses"
4668
4711
  },
4669
4712
  {
4670
- command: "npx skillops-cli add mcp-architect context-scout --harness claude,cursor",
4671
- description: "Install both a Skill and a Subagent into Claude & Cursor"
4713
+ command: "npx skillops-cli add mcp-architect -t claude,cursor",
4714
+ description: "Install mcp-architect into Claude & Cursor"
4672
4715
  }
4673
4716
  ]
4674
4717
  },
@@ -4676,26 +4719,26 @@ var COMMAND_HELP_SPECS = [
4676
4719
  name: "remove",
4677
4720
  aliases: ["uninstall", "rm"],
4678
4721
  pillar: "library",
4679
- summary: "Surgically uninstall a synced Skill or Subagent from active AI harnesses",
4722
+ summary: "Remove a Skill/Subagent from harnesses",
4680
4723
  usage: "npx skillops-cli remove <name...> [options]",
4681
4724
  options: [
4682
4725
  {
4683
- flags: "--project, --repo, -p <dir>",
4726
+ flags: "-p, --project <dir>",
4684
4727
  description: "Target repository directory"
4685
4728
  },
4686
4729
  {
4687
- flags: "--harness, --targets, -t <list>",
4730
+ flags: "-t, --harness <list>",
4688
4731
  description: "Restrict removal to specific harnesses"
4689
4732
  },
4690
4733
  {
4691
4734
  flags: "--force",
4692
- description: "Remove even if local SHA-256 drift is detected"
4735
+ description: "Remove even if SHA-256 drift is detected"
4693
4736
  }
4694
4737
  ],
4695
4738
  examples: [
4696
4739
  {
4697
4740
  command: "npx skillops-cli uninstall mcp-architect",
4698
- description: "Remove all transpiled runtime files for mcp-architect and update .skillops-lock.json"
4741
+ description: "Remove runtime files & update lockfile"
4699
4742
  }
4700
4743
  ]
4701
4744
  },
@@ -4703,16 +4746,16 @@ var COMMAND_HELP_SPECS = [
4703
4746
  name: "route",
4704
4747
  aliases: ["recommend"],
4705
4748
  pillar: "library",
4706
- summary: "Fingerprint repository stack and recommend the optimal collision-free <=12 Skill bundle",
4749
+ summary: "Recommend optimal <=12 Skill bundle",
4707
4750
  usage: "npx skillops-cli recommend [options]",
4708
4751
  options: [
4709
4752
  {
4710
- flags: "--project, --repo, -p <dir>",
4753
+ flags: "-p, --project <dir>",
4711
4754
  description: "Repository directory to fingerprint"
4712
4755
  },
4713
4756
  {
4714
4757
  flags: "--task <prompt>",
4715
- description: "Optional natural-language task prompt to boost task-specific Skills"
4758
+ description: "Task prompt to boost task-specific Skills"
4716
4759
  },
4717
4760
  {
4718
4761
  flags: "--top, --max-skills <n>",
@@ -4720,21 +4763,21 @@ var COMMAND_HELP_SPECS = [
4720
4763
  },
4721
4764
  {
4722
4765
  flags: "--max-l1-tokens <n>",
4723
- description: "Maximum total L1 routing token budget (default: 1500)"
4766
+ description: "Maximum L1 routing token budget (default: 1500)"
4724
4767
  },
4725
4768
  {
4726
- flags: "--format, -f <table|json|markdown>",
4769
+ flags: "-f, --format <table|json|md>",
4727
4770
  description: "Output format (default: table)"
4728
4771
  }
4729
4772
  ],
4730
4773
  examples: [
4731
4774
  {
4732
4775
  command: "npx skillops-cli recommend",
4733
- description: "Recommend the best Skills & Subagents for the current repository stack"
4776
+ description: "Recommend best Skills for current repo stack"
4734
4777
  },
4735
4778
  {
4736
- command: 'npx skillops-cli route --task "optimize slow postgres queries in FastAPI" --top 4',
4737
- description: "Route top 4 Skills tailored to a specific engineering task"
4779
+ command: 'npx skillops-cli route --task "slow postgres" --top 4',
4780
+ description: "Route top 4 Skills for a specific task"
4738
4781
  }
4739
4782
  ]
4740
4783
  },
@@ -4742,12 +4785,12 @@ var COMMAND_HELP_SPECS = [
4742
4785
  name: "create",
4743
4786
  aliases: ["new"],
4744
4787
  pillar: "framework",
4745
- summary: "Scaffold a custom Skill (SKILL.md + L3 script + evals.json) or Subagent (SUBAGENT.md) using the SkillOps Framework",
4746
- usage: "npx skillops-cli create <skill|subagent> <kebab-case-name> [options]",
4788
+ summary: "Scaffold custom Skill or Subagent template",
4789
+ usage: "npx skillops-cli create <skill|subagent> <name> [options]",
4747
4790
  options: [
4748
4791
  {
4749
- flags: "--description, -d <text>",
4750
- description: "Custom trigger description (automatically normalized to INV-SKILL-01..04 contracts)"
4792
+ flags: "-d, --description <text>",
4793
+ description: "Custom trigger description (INV-SKILL-01..04)"
4751
4794
  },
4752
4795
  {
4753
4796
  flags: "--catalog <dir>",
@@ -4758,18 +4801,18 @@ var COMMAND_HELP_SPECS = [
4758
4801
  description: "Overwrite existing Skill or Subagent template"
4759
4802
  },
4760
4803
  {
4761
- flags: "--format, -f <table|json|markdown>",
4804
+ flags: "-f, --format <table|json|md>",
4762
4805
  description: "Output format (default: table)"
4763
4806
  }
4764
4807
  ],
4765
4808
  examples: [
4766
4809
  {
4767
4810
  command: "npx skillops-cli create skill graphql-schema-guard",
4768
- description: "Scaffold a new INV-SKILL-01..03 compliant Skill with Level 3 script & eval suite"
4811
+ description: "Scaffold a new Skill with L3 script & evals"
4769
4812
  },
4770
4813
  {
4771
4814
  command: "npx skillops-cli create subagent migration-reviewer",
4772
- description: "Scaffold a new INV-SKILL-04 compliant Context-Isolated Subagent"
4815
+ description: "Scaffold a new Context-Isolated Subagent"
4773
4816
  }
4774
4817
  ]
4775
4818
  },
@@ -4777,7 +4820,7 @@ var COMMAND_HELP_SPECS = [
4777
4820
  name: "audit",
4778
4821
  aliases: [],
4779
4822
  pillar: "framework",
4780
- summary: "Run L1/L2/L3 token budget linter, Subagent contract verifier & TF-IDF cosine collision matrix",
4823
+ summary: "Verify L1/L2 budgets & TF-IDF collisions",
4781
4824
  usage: "npx skillops-cli audit [options]",
4782
4825
  options: [
4783
4826
  {
@@ -4786,21 +4829,21 @@ var COMMAND_HELP_SPECS = [
4786
4829
  },
4787
4830
  {
4788
4831
  flags: "--require-layout",
4789
- description: "Enforce full directory layout including evals/evals.json and executable L3 scripts"
4832
+ description: "Enforce evals/evals.json and L3 scripts"
4790
4833
  },
4791
4834
  {
4792
4835
  flags: "--strict",
4793
- description: "Fail with non-zero exit code on HIGH_RISK collisions as well as BLOCKING collisions"
4836
+ description: "Fail on HIGH_RISK as well as BLOCKING collisions"
4794
4837
  },
4795
4838
  {
4796
- flags: "--format, -f <table|json|github>",
4839
+ flags: "-f, --format <table|json|gh>",
4797
4840
  description: "Output format (default: table)"
4798
4841
  }
4799
4842
  ],
4800
4843
  examples: [
4801
4844
  {
4802
4845
  command: "npx skillops-cli audit --require-layout --strict",
4803
- description: "Certify that all Skills & Subagents pass token budgets and zero-collision invariants"
4846
+ description: "Certify token budgets & zero collisions"
4804
4847
  }
4805
4848
  ]
4806
4849
  },
@@ -4808,7 +4851,7 @@ var COMMAND_HELP_SPECS = [
4808
4851
  name: "eval",
4809
4852
  aliases: [],
4810
4853
  pillar: "framework",
4811
- summary: "Execute zero-API deterministic TDD benchmarks (with_skill vs without_skill) and export dashboards",
4854
+ summary: "Run deterministic A/B TDD benchmarks",
4812
4855
  usage: "npx skillops-cli eval [options]",
4813
4856
  options: [
4814
4857
  {
@@ -4821,25 +4864,25 @@ var COMMAND_HELP_SPECS = [
4821
4864
  },
4822
4865
  {
4823
4866
  flags: "--out <file>",
4824
- description: "Write formatted benchmark report (e.g. HTML/Markdown) to disk"
4867
+ description: "Write benchmark report (HTML/Markdown) to disk"
4825
4868
  },
4826
4869
  {
4827
4870
  flags: "--strict",
4828
- description: "Exit with code 4 if any Skill fails CERTIFIED_IMPROVEMENT"
4871
+ description: "Exit 4 if any Skill fails CERTIFIED_IMPROVEMENT"
4829
4872
  },
4830
4873
  {
4831
- flags: "--format, -f <table|json|markdown|html|github>",
4874
+ flags: "-f, --format <table|json|html>",
4832
4875
  description: "Output format (default: table)"
4833
4876
  }
4834
4877
  ],
4835
4878
  examples: [
4836
4879
  {
4837
4880
  command: "npx skillops-cli eval --strict",
4838
- description: "Run deterministic A/B evals across all Skills in the catalog"
4881
+ description: "Run deterministic A/B evals across catalog"
4839
4882
  },
4840
4883
  {
4841
- command: "npx skillops-cli eval --format html --out benchmark.html",
4842
- description: "Export a standalone HTML benchmark dashboard"
4884
+ command: "npx skillops-cli eval -f html --out benchmark.html",
4885
+ description: "Export standalone HTML benchmark dashboard"
4843
4886
  }
4844
4887
  ]
4845
4888
  },
@@ -4847,22 +4890,22 @@ var COMMAND_HELP_SPECS = [
4847
4890
  name: "init",
4848
4891
  aliases: [],
4849
4892
  pillar: "runtime",
4850
- summary: "Scaffold declarative .skillops.yml and detect repository AI coding harnesses",
4893
+ summary: "Create .skillops.yml and detect harnesses",
4851
4894
  usage: "npx skillops-cli init [options]",
4852
4895
  options: [
4853
4896
  {
4854
- flags: "--project, --repo, -p <dir>",
4897
+ flags: "-p, --project <dir>",
4855
4898
  description: "Target repository directory"
4856
4899
  },
4857
4900
  {
4858
- flags: "--harness, --targets, -t <list|auto|all>",
4859
- description: "Initial target harnesses to record in .skillops.yml"
4901
+ flags: "-t, --harness <list|auto|all>",
4902
+ description: "Initial target harnesses for .skillops.yml"
4860
4903
  }
4861
4904
  ],
4862
4905
  examples: [
4863
4906
  {
4864
4907
  command: "npx skillops-cli init",
4865
- description: "Create .skillops.yml with auto-detected stack and harnesses"
4908
+ description: "Create .skillops.yml with detected harnesses"
4866
4909
  }
4867
4910
  ]
4868
4911
  },
@@ -4870,16 +4913,16 @@ var COMMAND_HELP_SPECS = [
4870
4913
  name: "sync",
4871
4914
  aliases: [],
4872
4915
  pillar: "runtime",
4873
- summary: "Transpile routed Skills & Subagents across up to 20 AI coding agents with SHA-256 lockfile protection",
4916
+ summary: "Transpile bundle across 20 AI agents",
4874
4917
  usage: "npx skillops-cli sync [options]",
4875
4918
  options: [
4876
4919
  {
4877
- flags: "--project, --repo, -p <dir>",
4920
+ flags: "-p, --project <dir>",
4878
4921
  description: "Target repository directory"
4879
4922
  },
4880
4923
  {
4881
- flags: "--harness, --targets, -t <list|auto|all>",
4882
- description: "Target AI coding harnesses (default: .skillops.yml targets or core 5)"
4924
+ flags: "-t, --harness <list|auto|all>",
4925
+ description: "Target AI harnesses (default: .skillops.yml)"
4883
4926
  },
4884
4927
  {
4885
4928
  flags: "--top, --max-skills <n>",
@@ -4887,7 +4930,7 @@ var COMMAND_HELP_SPECS = [
4887
4930
  },
4888
4931
  {
4889
4932
  flags: "--dry-run",
4890
- description: "Preview planned artifacts without writing files"
4933
+ description: "Preview planned artifacts without writing"
4891
4934
  },
4892
4935
  {
4893
4936
  flags: "--force",
@@ -4897,11 +4940,11 @@ var COMMAND_HELP_SPECS = [
4897
4940
  examples: [
4898
4941
  {
4899
4942
  command: "npx skillops-cli sync --auto",
4900
- description: "Sync optimal Skills & Subagents into all AI harnesses detected in the repo"
4943
+ description: "Sync bundle into all detected AI harnesses"
4901
4944
  },
4902
4945
  {
4903
4946
  command: "npx skillops-cli sync --harness all",
4904
- description: "Transpile across all 20 supported AI coding agents"
4947
+ description: "Transpile across all 20 supported AI agents"
4905
4948
  }
4906
4949
  ]
4907
4950
  },
@@ -4909,11 +4952,11 @@ var COMMAND_HELP_SPECS = [
4909
4952
  name: "clean",
4910
4953
  aliases: [],
4911
4954
  pillar: "runtime",
4912
- summary: "Remove all SkillOps-managed runtime artifacts tracked in .skillops-lock.json",
4955
+ summary: "Remove all tracked runtime artifacts",
4913
4956
  usage: "npx skillops-cli clean [options]",
4914
4957
  options: [
4915
4958
  {
4916
- flags: "--project, --repo, -p <dir>",
4959
+ flags: "-p, --project <dir>",
4917
4960
  description: "Target repository directory"
4918
4961
  },
4919
4962
  {
@@ -4928,7 +4971,7 @@ var COMMAND_HELP_SPECS = [
4928
4971
  examples: [
4929
4972
  {
4930
4973
  command: "npx skillops-cli clean",
4931
- description: "Cleanly remove all synced artifacts and .skillops-lock.json"
4974
+ description: "Remove all synced artifacts & lockfile"
4932
4975
  }
4933
4976
  ]
4934
4977
  },
@@ -4936,11 +4979,11 @@ var COMMAND_HELP_SPECS = [
4936
4979
  name: "tokens",
4937
4980
  aliases: ["budget"],
4938
4981
  pillar: "runtime",
4939
- summary: "Analyze repository Startup Token Tax, Progressive Disclosure savings & context bloat hotspots",
4982
+ summary: "Analyze Startup Token Tax & context bloat",
4940
4983
  usage: "npx skillops-cli budget [options]",
4941
4984
  options: [
4942
4985
  {
4943
- flags: "--project, --repo, -p <dir>",
4986
+ flags: "-p, --project <dir>",
4944
4987
  description: "Repository directory to inspect"
4945
4988
  },
4946
4989
  {
@@ -4949,17 +4992,17 @@ var COMMAND_HELP_SPECS = [
4949
4992
  },
4950
4993
  {
4951
4994
  flags: "--strict",
4952
- description: "Fail with exit code 3 if Startup Token Tax exceeds budget"
4995
+ description: "Exit 3 if Startup Token Tax exceeds budget"
4953
4996
  },
4954
4997
  {
4955
- flags: "--format, -f <table|json|markdown|github>",
4998
+ flags: "-f, --format <table|json|md>",
4956
4999
  description: "Output format (default: table)"
4957
5000
  }
4958
5001
  ],
4959
5002
  examples: [
4960
5003
  {
4961
5004
  command: "npx skillops-cli budget",
4962
- description: "Inspect repository Startup Token Tax and Progressive Disclosure savings"
5005
+ description: "Inspect repository Startup Token Tax & savings"
4963
5006
  }
4964
5007
  ]
4965
5008
  },
@@ -4967,11 +5010,11 @@ var COMMAND_HELP_SPECS = [
4967
5010
  name: "doctor",
4968
5011
  aliases: ["status"],
4969
5012
  pillar: "runtime",
4970
- summary: "Diagnose Node/Python environment, .skillops.yml validity, lockfile SHA-256 drift & Startup Token Tax",
5013
+ summary: "Diagnose environment, drift & token budget",
4971
5014
  usage: "npx skillops-cli doctor [options]",
4972
5015
  options: [
4973
5016
  {
4974
- flags: "--project, --repo, -p <dir>",
5017
+ flags: "-p, --project <dir>",
4975
5018
  description: "Repository directory to diagnose"
4976
5019
  },
4977
5020
  {
@@ -4979,7 +5022,7 @@ var COMMAND_HELP_SPECS = [
4979
5022
  description: "Fail on warnings as well as errors"
4980
5023
  },
4981
5024
  {
4982
- flags: "--format, -f <table|json|markdown|github>",
5025
+ flags: "-f, --format <table|json|md>",
4983
5026
  description: "Output format (default: table)"
4984
5027
  }
4985
5028
  ],
@@ -4994,22 +5037,22 @@ var COMMAND_HELP_SPECS = [
4994
5037
  name: "harnesses",
4995
5038
  aliases: [],
4996
5039
  pillar: "runtime",
4997
- summary: "List all 20 supported AI coding agents, target paths, MCP support & repository detection status",
5040
+ summary: "List 20 supported AI agents & repo status",
4998
5041
  usage: "npx skillops-cli harnesses [options]",
4999
5042
  options: [
5000
5043
  {
5001
- flags: "--project, --repo, -p <dir>",
5044
+ flags: "-p, --project <dir>",
5002
5045
  description: "Repository directory to scan for AI harnesses"
5003
5046
  },
5004
5047
  {
5005
- flags: "--format, -f <table|json|markdown>",
5048
+ flags: "-f, --format <table|json|md>",
5006
5049
  description: "Output format (default: table)"
5007
5050
  }
5008
5051
  ],
5009
5052
  examples: [
5010
5053
  {
5011
5054
  command: "npx skillops-cli harnesses",
5012
- description: "View all 20 supported AI coding IDEs/CLI agents and which ones are active in your repo"
5055
+ description: "View all 20 supported AI IDEs/CLI agents"
5013
5056
  }
5014
5057
  ]
5015
5058
  },
@@ -5017,15 +5060,15 @@ var COMMAND_HELP_SPECS = [
5017
5060
  name: "mcp-setup",
5018
5061
  aliases: [],
5019
5062
  pillar: "runtime",
5020
- summary: "Register SkillOps MCP server across all 13 MCP-compatible AI coding IDEs & agents",
5063
+ summary: "Wire MCP server across 13 AI IDEs & agents",
5021
5064
  usage: "npx skillops-cli mcp-setup [options]",
5022
5065
  options: [
5023
5066
  {
5024
- flags: "--project, --repo, -p <dir>",
5067
+ flags: "-p, --project <dir>",
5025
5068
  description: "Target repository directory"
5026
5069
  },
5027
5070
  {
5028
- flags: "--harness, --targets, -t <list|auto|all>",
5071
+ flags: "-t, --harness <list|auto|all>",
5029
5072
  description: "Target harnesses to configure MCP for"
5030
5073
  },
5031
5074
  {
@@ -5036,7 +5079,7 @@ var COMMAND_HELP_SPECS = [
5036
5079
  examples: [
5037
5080
  {
5038
5081
  command: "npx skillops-cli mcp-setup --auto",
5039
- description: "Automatically wire SkillOps MCP server into detected IDEs (.mcp.json, .cursor/mcp.json, etc.)"
5082
+ description: "Wire SkillOps MCP into detected IDEs"
5040
5083
  }
5041
5084
  ]
5042
5085
  },
@@ -5044,18 +5087,18 @@ var COMMAND_HELP_SPECS = [
5044
5087
  name: "mcp",
5045
5088
  aliases: [],
5046
5089
  pillar: "runtime",
5047
- summary: "Start native JSON-RPC 2.0 stdio Model Context Protocol server",
5090
+ summary: "Start stdio JSON-RPC 2.0 MCP server",
5048
5091
  usage: "npx skillops-cli mcp [options]",
5049
5092
  options: [
5050
5093
  {
5051
- flags: "--project, --repo, -p <dir>",
5094
+ flags: "-p, --project <dir>",
5052
5095
  description: "Repository root served over MCP"
5053
5096
  }
5054
5097
  ],
5055
5098
  examples: [
5056
5099
  {
5057
5100
  command: "npx skillops-cli mcp",
5058
- description: "Start stdio MCP server (invoked automatically by AI IDEs)"
5101
+ description: "Start stdio MCP server for AI IDEs"
5059
5102
  }
5060
5103
  ]
5061
5104
  }
@@ -5068,117 +5111,264 @@ function findCommandHelpSpec(commandOrAlias) {
5068
5111
  }
5069
5112
  function renderGlobalHelp(version, colorEnabled) {
5070
5113
  const c = colorEnabled;
5114
+ const bar = style.dim("\u2502", c);
5071
5115
  const banner = renderHeaderBanner(
5072
- "The Zero-API Framework & Library for High-End AI Coding Skills & Context-Isolated Subagents",
5116
+ "Skills & Agents Library for AI Coding IDEs",
5073
5117
  {
5074
5118
  version,
5075
5119
  colorEnabled: c
5076
5120
  }
5077
5121
  );
5078
- const quickstartBox = renderBox(
5079
- [
5080
- `${style.bold(style.green("npx skillops-cli quickstart", c), c)} ${style.dim("# 1-step setup: detect stack, install Skills/Subagents & wire MCP", c)}`,
5081
- `${style.bold(style.cyan("npx skillops-cli info <name>", c), c)} ${style.dim("# Inspect any Skill/Subagent & see how to invoke it in your AI", c)}`,
5082
- `${style.bold(style.magenta("npx skillops-cli create skill <name>", c), c)} ${style.dim("# Scaffold your own custom Skill using the SkillOps Framework", c)}`
5083
- ],
5122
+ const coreCmds = [
5084
5123
  {
5085
- title: "\u{1F680} 10-Second Quickstart (Library + Framework)",
5086
- borderColor: style.cyan,
5087
- minWidth: 88,
5088
- colorEnabled: c
5124
+ cmd: "add [name...]",
5125
+ desc: "Import Skills or Agents (interactive if no name given)"
5126
+ },
5127
+ {
5128
+ cmd: "list [query]",
5129
+ desc: "List or filter available Skills & Agents in catalog"
5130
+ },
5131
+ {
5132
+ cmd: "info <name>",
5133
+ desc: "View details and how to use a Skill or Agent"
5134
+ },
5135
+ {
5136
+ cmd: "remove <name>",
5137
+ desc: "Remove an imported Skill or Agent from your project"
5138
+ },
5139
+ {
5140
+ cmd: "init",
5141
+ desc: "Auto-detect stack & IDE and import recommended bundle"
5089
5142
  }
5090
- );
5091
- const formatCmdSection = (pillar) => {
5092
- const specs = COMMAND_HELP_SPECS.filter((s) => s.pillar === pillar);
5093
- return renderTable(
5094
- ["Command", "Aliases", "Description"],
5095
- specs.map((s) => [
5096
- style.bold(style.cyan(s.name, c), c),
5097
- s.aliases.length > 0 ? style.dim(s.aliases.join(", "), c) : style.dim("\u2014", c),
5098
- s.summary
5099
- ]),
5100
- { colorEnabled: c, indent: 2 }
5101
- );
5102
- };
5103
- const globalFlagsTable = renderTable(
5104
- ["Global Flag", "Description"],
5105
- [
5106
- [
5107
- style.cyan("--project, --repo, -p <dir>", c),
5108
- "Target project/repository directory (default: current working directory)"
5109
- ],
5110
- [
5111
- style.cyan("--harness, --targets, -t <list|auto|all>", c),
5112
- "Target AI coding harnesses (e.g. claude,cursor,windsurf,copilot or auto/all)"
5113
- ],
5114
- [
5115
- style.cyan("--format, -f <table|json|markdown|github>", c),
5116
- "Output format for reports and CI pipelines (default: table)"
5117
- ],
5118
- [
5119
- style.cyan("--help, -h / --version, -V", c),
5120
- "Show global or per-command help (`npx skillops-cli <cmd> --help`) / CLI version"
5121
- ]
5122
- ],
5123
- { colorEnabled: c, indent: 2 }
5124
- );
5143
+ ];
5144
+ const cmdRows = coreCmds.map(
5145
+ (item) => `${bar} ${padVisible(style.bold(style.cyan(item.cmd, c), c), 18, "left")}${item.desc}`
5146
+ ).join("\n");
5125
5147
  return [
5126
- `SkillOps v${version} \u2014 The Zero-API NPX Engine for High-End AI Skills & Subagents`,
5127
- "Usage: npx skillops-cli <command> [options]",
5128
- "",
5129
5148
  banner,
5130
- quickstartBox,
5131
- renderSectionHeader(
5132
- "\u{1F4DA} 1. Library of High-End Skills & Subagents (Explore, Search & Install)",
5133
- c
5134
- ),
5135
- formatCmdSection("library"),
5136
- renderSectionHeader(
5137
- "\u{1F6E0}\uFE0F 2. Framework for Building Custom Skills & Subagents (Scaffold, Audit & Certify)",
5138
- c
5139
- ),
5140
- formatCmdSection("framework"),
5141
- renderSectionHeader(
5142
- "\u2699\uFE0F 3. Universal Runtime Sync, Token Economy & Diagnostics (Top 20 AI Harnesses)",
5143
- c
5144
- ),
5145
- formatCmdSection("runtime"),
5146
- renderSectionHeader("\u{1F310} Global Options", c),
5147
- globalFlagsTable,
5148
- "",
5149
- ` ${style.dim("\u{1F4A1} Tip: Run", c)} ${style.bold(style.cyan("npx skillops-cli <command> --help", c), c)} ${style.dim("for detailed flags and copy-paste examples.", c)}`,
5150
- ""
5149
+ `${bar} Usage: skillops <command> [options]`,
5150
+ renderSectionHeader("Commands", c),
5151
+ cmdRows,
5152
+ renderSectionHeader("Options", c),
5153
+ `${bar} ${padVisible(style.cyan("-t, --target <ide>", c), 22, "left")}AI IDE (cursor, claude, copilot, windsurf, auto)`,
5154
+ `${bar} ${padVisible(style.cyan("-p, --project <dir>", c), 22, "left")}Project folder (default: current directory)`,
5155
+ `${bar} ${padVisible(style.cyan("--all", c), 22, "left")}Import all 10 Skills & 9 Agents`,
5156
+ renderSectionHeader("Examples", c),
5157
+ `${bar} ${style.dim("$", c)} ${style.green("skillops add", c)} ${style.dim("\u2014 Interactive selector", c)}`,
5158
+ `${bar} ${style.dim("$", c)} ${style.green("skillops add bug-reproducer-tdd red-team-breaker", c)} ${style.dim("\u2014 Direct import", c)}`,
5159
+ `${bar} ${style.dim("$", c)} ${style.green("skillops list", c)} ${style.dim("\u2014 Browse catalog", c)}`,
5160
+ bar,
5161
+ `${style.dim("\u2570\u2500", c)} ${style.dim("Run", c)} ${style.cyan("skillops <cmd> -h", c)} ${style.dim("for command options.", c)}`
5151
5162
  ].join("\n");
5152
5163
  }
5153
5164
  function renderCommandHelp(spec, version, colorEnabled) {
5154
5165
  const c = colorEnabled;
5166
+ const bar = style.dim("\u2502", c);
5155
5167
  const pillarBadge = spec.pillar === "library" ? formatBadge("info", "LIBRARY", c) : spec.pillar === "framework" ? formatBadge("pass", "FRAMEWORK", c) : formatBadge("subagent", "RUNTIME", c);
5156
5168
  const aliasText = spec.aliases.length > 0 ? ` (aliases: ${spec.aliases.map((a) => style.cyan(a, c)).join(", ")})` : "";
5157
- const headerBox = renderBox(
5158
- [
5159
- `${pillarBadge} ${style.bold(style.cyan(`skillops ${spec.name}`, c), c)}${aliasText}`,
5160
- "",
5161
- spec.summary,
5162
- "",
5163
- `${style.bold("Usage:", c)} ${style.green(spec.usage, c)}`
5164
- ],
5165
- {
5166
- title: `SkillOps v${version} \u2014 Command Reference`,
5167
- borderColor: style.cyan,
5168
- minWidth: 78,
5169
- colorEnabled: c
5170
- }
5171
- );
5169
+ const headerLines = [
5170
+ `${style.bold(style.cyan(`\u25C6 SkillOps v${version}`, c), c)} ${style.dim("\u2014", c)} ${style.bold(`skillops ${spec.name}`, c)}${aliasText} ${pillarBadge}`,
5171
+ `${bar} ${spec.summary}`,
5172
+ `${bar} ${style.bold("Usage:", c)} ${style.green(spec.usage, c)}`
5173
+ ].join("\n");
5172
5174
  const optionsSection = spec.options.length > 0 ? [
5173
5175
  renderSectionHeader("Options & Flags", c),
5174
5176
  renderTable(
5175
5177
  ["Flag", "Description"],
5176
5178
  spec.options.map((o) => [style.cyan(o.flags, c), o.description]),
5177
- { colorEnabled: c, indent: 2 }
5179
+ { colorEnabled: c, indent: 3 }
5178
5180
  )
5179
5181
  ].join("\n") : "";
5180
5182
  const examplesSection = renderNextSteps(spec.examples, c);
5181
- return [headerBox, optionsSection, examplesSection].filter(Boolean).join("\n");
5183
+ return [headerLines, optionsSection, examplesSection].filter(Boolean).join("\n");
5184
+ }
5185
+
5186
+ // src/ui/prompt.ts
5187
+ function createMultiSelectState(options) {
5188
+ const initial = /* @__PURE__ */ new Set();
5189
+ for (const opt of options) {
5190
+ if (opt.initialSelected) {
5191
+ initial.add(opt.value);
5192
+ }
5193
+ }
5194
+ return {
5195
+ options,
5196
+ cursor: 0,
5197
+ selected: initial,
5198
+ status: "active"
5199
+ };
5200
+ }
5201
+ function applyMultiSelectKey(state, key) {
5202
+ if (state.status !== "active" || state.options.length === 0) {
5203
+ return state;
5204
+ }
5205
+ const count = state.options.length;
5206
+ if (key === "" || key === "\x1B" || key === "q" || key === "Q") {
5207
+ return {
5208
+ ...state,
5209
+ status: "cancelled"
5210
+ };
5211
+ }
5212
+ if (key === "\r" || key === "\n") {
5213
+ return {
5214
+ ...state,
5215
+ status: "submitted"
5216
+ };
5217
+ }
5218
+ if (key === "\x1B[A" || key === "\x1BOA" || key === "k" || key === "K") {
5219
+ const nextCursor = (state.cursor - 1 + count) % count;
5220
+ return {
5221
+ ...state,
5222
+ cursor: nextCursor
5223
+ };
5224
+ }
5225
+ if (key === "\x1B[B" || key === "\x1BOB" || key === "j" || key === "J") {
5226
+ const nextCursor = (state.cursor + 1) % count;
5227
+ return {
5228
+ ...state,
5229
+ cursor: nextCursor
5230
+ };
5231
+ }
5232
+ if (key === " ") {
5233
+ const currentOpt = state.options[state.cursor];
5234
+ if (!currentOpt) {
5235
+ return state;
5236
+ }
5237
+ const nextSelected = new Set(state.selected);
5238
+ if (nextSelected.has(currentOpt.value)) {
5239
+ nextSelected.delete(currentOpt.value);
5240
+ } else {
5241
+ nextSelected.add(currentOpt.value);
5242
+ }
5243
+ return {
5244
+ ...state,
5245
+ selected: nextSelected
5246
+ };
5247
+ }
5248
+ if (key === "a" || key === "A") {
5249
+ const allSelected = state.selected.size === count;
5250
+ const nextSelected = /* @__PURE__ */ new Set();
5251
+ if (!allSelected) {
5252
+ for (const opt of state.options) {
5253
+ nextSelected.add(opt.value);
5254
+ }
5255
+ }
5256
+ return {
5257
+ ...state,
5258
+ selected: nextSelected
5259
+ };
5260
+ }
5261
+ return state;
5262
+ }
5263
+ function renderMultiSelectFrame(title, state, options = {}) {
5264
+ const c = options.colorEnabled;
5265
+ const bar = style.dim("\u2502", c);
5266
+ const maxVisible = options.maxVisible ?? 10;
5267
+ const total = state.options.length;
5268
+ const header = `${style.bold(style.cyan(`\u25C6 ${title}`, c), c)}`;
5269
+ const instructions = `${bar} ${style.dim("(\u2191/\u2193 move \xB7 Space select \xB7 'a' toggle all \xB7 Enter confirm)", c)}`;
5270
+ const lines = [header];
5271
+ if (options.subtitle) {
5272
+ lines.push(`${bar} ${options.subtitle}`);
5273
+ }
5274
+ lines.push(instructions, bar);
5275
+ let startIdx = 0;
5276
+ if (total > maxVisible) {
5277
+ const half = Math.floor(maxVisible / 2);
5278
+ startIdx = Math.max(0, Math.min(state.cursor - half, total - maxVisible));
5279
+ }
5280
+ const endIdx = Math.min(total, startIdx + maxVisible);
5281
+ if (startIdx > 0) {
5282
+ lines.push(`${bar} ${style.dim(`\u2191 ${startIdx} more above...`, c)}`);
5283
+ }
5284
+ const maxLabelCols = Math.min(
5285
+ 26,
5286
+ state.options.reduce((m, o) => Math.max(m, visibleLength(o.label)), 14)
5287
+ );
5288
+ for (let i = startIdx; i < endIdx; i++) {
5289
+ const opt = state.options[i];
5290
+ if (!opt) continue;
5291
+ const isCurrent = i === state.cursor;
5292
+ const isChecked = state.selected.has(opt.value);
5293
+ const pointer = isCurrent ? style.cyan("\u276F", c) : " ";
5294
+ const checkbox = isChecked ? style.green("\u25FC", c) : style.dim("\u25FB", c);
5295
+ const kindTag = opt.kind === "skill" ? style.cyan("skill ", c) : opt.kind === "agent" ? style.magenta("agent ", c) : "";
5296
+ const labelRaw = opt.label.length > maxLabelCols ? `${opt.label.slice(0, maxLabelCols - 1)}\u2026` : opt.label;
5297
+ const labelPadded = padVisible(labelRaw, maxLabelCols + 1, "left");
5298
+ const styledLabel = isCurrent ? style.bold(labelPadded, c) : isChecked ? style.green(labelPadded, c) : labelPadded;
5299
+ const prefixWidth = 6 + (opt.kind === "skill" || opt.kind === "agent" ? 6 : 0) + maxLabelCols + 1;
5300
+ const maxHintCols = Math.max(10, 75 - prefixWidth);
5301
+ const rawHint = opt.hint ?? "";
5302
+ const shortHint = rawHint.length > maxHintCols ? `${rawHint.slice(0, maxHintCols - 1)}\u2026` : rawHint;
5303
+ const hintPart = shortHint ? ` ${style.dim(shortHint, c)}` : "";
5304
+ lines.push(
5305
+ `${bar} ${pointer} ${checkbox} ${kindTag}${styledLabel}${hintPart}`
5306
+ );
5307
+ }
5308
+ if (endIdx < total) {
5309
+ lines.push(`${bar} ${style.dim(`\u2193 ${total - endIdx} more below...`, c)}`);
5310
+ }
5311
+ lines.push(bar);
5312
+ const targetSuffix = options.targetHint ? ` \xB7 IDE: ${options.targetHint}` : "";
5313
+ lines.push(
5314
+ `${style.dim("\u2570\u2500", c)} ${style.bold(`${state.selected.size} selected`, c)}${style.dim(`${targetSuffix} \u2014 Enter to import`, c)}`
5315
+ );
5316
+ return lines.join("\n");
5317
+ }
5318
+ async function runMultiSelectPrompt(title, options, renderOpts = {}) {
5319
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
5320
+ return null;
5321
+ }
5322
+ let state = createMultiSelectState(options);
5323
+ let renderedLineCount = 0;
5324
+ const render = () => {
5325
+ const frame = renderMultiSelectFrame(title, state, renderOpts);
5326
+ if (renderedLineCount > 0) {
5327
+ process.stdout.write(`\x1B[${renderedLineCount}A\x1B[J`);
5328
+ }
5329
+ process.stdout.write(`${frame}
5330
+ `);
5331
+ renderedLineCount = frame.split("\n").length;
5332
+ };
5333
+ return new Promise((resolve) => {
5334
+ const stdin = process.stdin;
5335
+ const wasRaw = stdin.isRaw;
5336
+ stdin.setRawMode(true);
5337
+ stdin.resume();
5338
+ stdin.setEncoding("utf-8");
5339
+ process.stdout.write("\x1B[?25l");
5340
+ render();
5341
+ const cleanup = () => {
5342
+ stdin.removeListener("data", onData);
5343
+ if (stdin.isTTY) {
5344
+ stdin.setRawMode(Boolean(wasRaw));
5345
+ }
5346
+ stdin.pause();
5347
+ process.stdout.write("\x1B[?25h");
5348
+ };
5349
+ const onData = (chunk) => {
5350
+ const key = typeof chunk === "string" ? chunk : chunk.toString("utf-8");
5351
+ state = applyMultiSelectKey(state, key);
5352
+ if (state.status === "cancelled") {
5353
+ if (renderedLineCount > 0) {
5354
+ process.stdout.write(`\x1B[${renderedLineCount}A\x1B[J`);
5355
+ }
5356
+ cleanup();
5357
+ resolve(null);
5358
+ return;
5359
+ }
5360
+ if (state.status === "submitted") {
5361
+ if (renderedLineCount > 0) {
5362
+ process.stdout.write(`\x1B[${renderedLineCount}A\x1B[J`);
5363
+ }
5364
+ cleanup();
5365
+ resolve([...state.selected]);
5366
+ return;
5367
+ }
5368
+ render();
5369
+ };
5370
+ stdin.on("data", onData);
5371
+ });
5182
5372
  }
5183
5373
 
5184
5374
  // src/framework/index.ts
@@ -5280,71 +5470,66 @@ function formatCatalogItemInfo(info, format = "table", colorEnabled) {
5280
5470
  return lines.join("\n");
5281
5471
  }
5282
5472
  const c = colorEnabled;
5473
+ const bar = style.dim("\u2502", c);
5283
5474
  const badge = info.kind === "skill" ? formatBadge("skill", "HYBRID EXECUTABLE SKILL", c) : formatBadge("subagent", "CONTEXT-ISOLATED SUBAGENT", c);
5475
+ const shortDesc = info.description.length > 68 ? `${info.description.slice(0, 65)}...` : info.description;
5284
5476
  const cardLines = [
5285
- `${badge} ${style.bold(style.cyan(info.name, c), c)}`,
5286
- "",
5287
- `${style.bold("Description:", c)}`,
5288
- ` ${info.description}`,
5289
- ""
5477
+ `${style.bold(style.cyan(`\u25C6 SkillOps Library Inspector \u2014 ${info.name}`, c), c)}`,
5478
+ `${bar} ${badge}`,
5479
+ `${bar} ${shortDesc}`,
5480
+ bar
5290
5481
  ];
5291
5482
  if (info.kind === "skill") {
5292
5483
  cardLines.push(
5293
- `${style.bold("Token Economy (INV-SKILL-01..03):", c)}`,
5294
- ` \u2022 L1 Routing Footprint : ${style.green(`${info.l1Tokens} tokens`, c)} (<= 160 budget)`,
5295
- ` \u2022 L2 Playbook Body : ${info.l2Lines} lines (${info.l2Tokens} tokens, <= 250 lines)`,
5296
- ` \u2022 Progressive Savings : ${style.bold(style.green(`${info.savingsPct}%`, c), c)} Startup Token Tax saved until triggered`,
5297
- ` \u2022 L3 Scripts (${info.scripts.length}) : ${info.scripts.length > 0 ? style.cyan(info.scripts.join(", "), c) : "none"}`,
5298
- ` \u2022 TDD Eval Cases : ${info.evalCasesCount} deterministic benchmark cases`
5484
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan("Token Economy (INV-SKILL-01..03)", c), c)}`,
5485
+ `${bar} \u2022 L1 Routing : ${style.green(`${info.l1Tokens} tokens`, c)} (<= 160 budget)`,
5486
+ `${bar} \u2022 L2 Playbook : ${info.l2Lines} lines (${info.l2Tokens}t, <= 250 lines)`,
5487
+ `${bar} \u2022 Token Savings : ${style.bold(style.green(`${info.savingsPct}%`, c), c)} Startup Tax saved`,
5488
+ `${bar} \u2022 L3 Scripts (${info.scripts.length}) : ${info.scripts.length > 0 ? style.cyan(info.scripts.join(", "), c) : "none"}`,
5489
+ `${bar} \u2022 TDD Evals : ${info.evalCasesCount} deterministic cases`
5299
5490
  );
5300
5491
  } else {
5301
5492
  cardLines.push(
5302
- `${style.bold("Context Isolation Contract (INV-SKILL-04):", c)}`,
5303
- ` \u2022 System Prompt Tokens : ${style.green(`${info.l1Tokens} tokens`, c)}`,
5304
- ` \u2022 Max Output Cap : <= ${style.bold(`${info.maxOutputTokens} tokens`, c)}`,
5305
- ` \u2022 Isolation Mode : ${style.cyan(info.isolation ?? "context-isolated", c)}`,
5306
- ` \u2022 Allowed Tools (${info.tools.length}) : ${info.tools.join(", ")}`
5493
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan("Context Isolation Contract (INV-SKILL-04)", c), c)}`,
5494
+ `${bar} \u2022 System Prompt : ${style.green(`${info.l1Tokens} tokens`, c)}`,
5495
+ `${bar} \u2022 Max Output Cap : <= ${style.bold(`${info.maxOutputTokens} tokens`, c)}`,
5496
+ `${bar} \u2022 Isolation Mode : ${style.cyan(info.isolation ?? "context-isolated", c)}`,
5497
+ `${bar} \u2022 Allowed Tools : ${info.tools.join(", ")}`
5307
5498
  );
5308
5499
  }
5309
5500
  if (info.headings.length > 0) {
5310
5501
  cardLines.push(
5311
- "",
5312
- `${style.bold("Workflow Playbook Sections:", c)}`,
5313
- ...info.headings.slice(0, 6).map((h) => ` \u2022 ${h}`)
5502
+ bar,
5503
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan("Playbook Sections", c), c)}`,
5504
+ ...info.headings.slice(0, 5).map((h) => `${bar} \u2022 ${h}`)
5314
5505
  );
5315
5506
  }
5316
5507
  cardLines.push(
5317
- "",
5318
- `${style.bold("How to Invoke in Your AI Agent:", c)}`,
5319
- ` \u2022 ${style.bold("Install into repo:", c)} ${style.green(`npx skillops-cli add ${info.name}`, c)}`,
5320
- info.kind === "skill" ? ` \u2022 ${style.bold("Cursor / Copilot / Claude:", c)} Reference ${style.cyan(`@${info.name}`, c)} or ${style.cyan(`/${info.name}`, c)} in chat` : ` \u2022 ${style.bold("Delegate Subagent:", c)} Ask your main agent to delegate heavy exploration to ${style.magenta(`@${info.name}`, c)}`
5508
+ bar,
5509
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan("How to Invoke in Your AI Agent", c), c)}`,
5510
+ `${bar} \u2022 ${style.bold("Install:", c)} ${style.green(`npx skillops-cli add ${info.name}`, c)}`,
5511
+ info.kind === "skill" ? `${bar} \u2022 ${style.bold("IDE Chat:", c)} Reference ${style.cyan(`@${info.name}`, c)} or ${style.cyan(`/${info.name}`, c)}` : `${bar} \u2022 ${style.bold("Delegate:", c)} Ask main agent to run ${style.magenta(`@${info.name}`, c)}`
5321
5512
  );
5322
- const box = renderBox(cardLines, {
5323
- title: `\u{1F4E6} SkillOps Library Inspector \u2014 ${info.name}`,
5324
- borderColor: info.kind === "skill" ? style.cyan : style.magenta,
5325
- minWidth: 74,
5326
- colorEnabled: c
5327
- });
5328
5513
  const nextSteps = renderNextSteps(
5329
5514
  [
5330
5515
  {
5331
5516
  command: `npx skillops-cli add ${info.name}`,
5332
- description: `Install '${info.name}' into your active AI coding agents`
5517
+ description: "Install into AI agents"
5333
5518
  },
5334
5519
  ...info.kind === "skill" ? [
5335
5520
  {
5336
5521
  command: `npx skillops-cli eval --skill ${info.name}`,
5337
- description: `Run deterministic TDD benchmark for '${info.name}'`
5522
+ description: "Run TDD benchmark"
5338
5523
  }
5339
5524
  ] : [],
5340
5525
  {
5341
5526
  command: "npx skillops-cli list",
5342
- description: "Browse all 10 Skills & 9 Subagents in the Library"
5527
+ description: "Browse 10 Skills & 9 Subagents"
5343
5528
  }
5344
5529
  ],
5345
5530
  c
5346
5531
  );
5347
- return `${box}
5532
+ return `${cardLines.join("\n")}
5348
5533
  ${nextSteps}`;
5349
5534
  }
5350
5535
  function searchCatalog(catalogDir, query) {
@@ -5373,7 +5558,7 @@ function searchCatalog(catalogDir, query) {
5373
5558
  name: parsed.manifest.name,
5374
5559
  score,
5375
5560
  tokens: parsed.manifest.description_tokens,
5376
- summary: parsed.manifest.description.length > 78 ? `${parsed.manifest.description.slice(0, 75)}...` : parsed.manifest.description
5561
+ summary: parsed.manifest.description.length > 30 ? `${parsed.manifest.description.slice(0, 27)}...` : parsed.manifest.description
5377
5562
  });
5378
5563
  }
5379
5564
  }
@@ -5400,7 +5585,7 @@ function searchCatalog(catalogDir, query) {
5400
5585
  name: parsed.manifest.name,
5401
5586
  score,
5402
5587
  tokens: parsed.manifest.system_prompt_tokens,
5403
- summary: parsed.manifest.description.length > 78 ? `${parsed.manifest.description.slice(0, 75)}...` : parsed.manifest.description
5588
+ summary: parsed.manifest.description.length > 30 ? `${parsed.manifest.description.slice(0, 27)}...` : parsed.manifest.description
5404
5589
  });
5405
5590
  }
5406
5591
  }
@@ -5430,43 +5615,39 @@ function formatCatalogSearchReport(report, format = "table", colorEnabled) {
5430
5615
  return lines.join("\n");
5431
5616
  }
5432
5617
  const c = colorEnabled;
5433
- const header = renderBox(
5434
- [
5435
- `${style.bold(style.cyan("\u{1F50D} SkillOps Library Search", c), c)} \u2014 Query: ${style.bold(`"${report.query || "*"}"`, c)} (${report.total_matches} matches)`
5436
- ],
5437
- { minWidth: 74, colorEnabled: c }
5438
- );
5618
+ const bar = style.dim("\u2502", c);
5619
+ const header = `${style.bold(style.cyan("\u25C6 SkillOps Library Search", c), c)} ${style.dim("\u2014", c)} Query: ${style.bold(`"${report.query || "*"}"`, c)} (${report.total_matches} matches)`;
5439
5620
  if (report.matches.length === 0) {
5440
5621
  return `${header}
5441
- ${formatBadge("warn", "No matching Skills or Subagents found.", c)}
5442
- ${renderNextSteps([{ command: "npx skillops-cli list", description: "View all 10 Skills & 9 Subagents in the Library" }], c)}`;
5622
+ ${bar} ${formatBadge("warn", "No matching Skills or Subagents found.", c)}
5623
+ ${renderNextSteps([{ command: "npx skillops-cli list", description: "View all 10 Skills & 9 Subagents" }], c)}`;
5443
5624
  }
5444
5625
  const table = renderTable(
5445
- ["Type", "Name", "Tokens", "When to Use / Summary"],
5626
+ ["Type", "Name", "Tokens", "Summary"],
5446
5627
  report.matches.map((m) => [
5447
5628
  m.kind === "skill" ? formatBadge("skill", "SKILL", c) : formatBadge("subagent", "SUBAGENT", c),
5448
5629
  style.bold(m.name, c),
5449
5630
  `${m.tokens}t`,
5450
5631
  m.summary
5451
5632
  ]),
5452
- { align: ["left", "left", "right", "left"], colorEnabled: c }
5633
+ { align: ["left", "left", "right", "left"], colorEnabled: c, indent: 3 }
5453
5634
  );
5454
5635
  const topItem = report.matches[0]?.name ?? "bug-reproducer-tdd";
5455
5636
  const nextSteps = renderNextSteps(
5456
5637
  [
5457
5638
  {
5458
5639
  command: `npx skillops-cli info ${topItem}`,
5459
- description: `Inspect '${topItem}' in detail`
5640
+ description: "Inspect triggers & usage"
5460
5641
  },
5461
5642
  {
5462
5643
  command: `npx skillops-cli add ${topItem}`,
5463
- description: `Install '${topItem}' into your project's AI agents`
5644
+ description: "Install into AI agents"
5464
5645
  }
5465
5646
  ],
5466
5647
  c
5467
5648
  );
5468
5649
  return `${header}
5469
-
5650
+ ${bar}
5470
5651
  ${table}
5471
5652
  ${nextSteps}`;
5472
5653
  }
@@ -5684,38 +5865,31 @@ function formatScaffoldReport(result, format = "table", colorEnabled) {
5684
5865
  ].join("\n");
5685
5866
  }
5686
5867
  const c = colorEnabled;
5687
- const box = renderBox(
5688
- [
5689
- `${formatBadge("pass", "CREATED", c)} Scaffolded new SkillOps Framework ${style.bold(result.kind.toUpperCase(), c)}: ${style.bold(style.cyan(result.name, c), c)}`,
5690
- "",
5691
- `${style.bold("Generated Files:", c)}`,
5692
- ...result.created_files.map((f) => ` \u2022 ${style.green(f, c)}`)
5693
- ],
5694
- {
5695
- title: "\u{1F6E0}\uFE0F SkillOps Framework Scaffolder",
5696
- borderColor: style.green,
5697
- minWidth: 74,
5698
- colorEnabled: c
5699
- }
5700
- );
5868
+ const bar = style.dim("\u2502", c);
5869
+ const treeHeader = [
5870
+ `${style.bold(style.cyan("\u25C6 SkillOps Framework Scaffolder", c), c)} ${style.dim("\u2014", c)} ${formatBadge("pass", "CREATED", c)} ${style.bold(result.kind.toUpperCase(), c)} ${style.bold(style.cyan(result.name, c), c)}`,
5871
+ bar,
5872
+ `${style.dim("\u251C\u2500", c)} ${style.bold("Generated Files:", c)}`,
5873
+ ...result.created_files.map((f) => `${bar} \u2022 ${style.green(f, c)}`)
5874
+ ].join("\n");
5701
5875
  const nextSteps = renderNextSteps(
5702
5876
  [
5703
5877
  {
5704
5878
  command: `npx skillops-cli info ${result.name}`,
5705
- description: `Inspect your new ${result.kind} metadata & token budget`
5879
+ description: `Inspect new ${result.kind} metadata & budget`
5706
5880
  },
5707
5881
  {
5708
5882
  command: "npx skillops-cli audit --require-layout",
5709
- description: "Verify INV-SKILL-01..04 contract compliance & cosine collisions"
5883
+ description: "Verify INV-SKILL-01..04 & collisions"
5710
5884
  },
5711
5885
  {
5712
5886
  command: `npx skillops-cli add ${result.name}`,
5713
- description: `Transpile & install '${result.name}' into your AI coding agents`
5887
+ description: `Install '${result.name}' into AI agents`
5714
5888
  }
5715
5889
  ],
5716
5890
  c
5717
5891
  );
5718
- return `${box}
5892
+ return `${treeHeader}
5719
5893
  ${nextSteps}`;
5720
5894
  }
5721
5895
  function runQuickstart(repoPath, catalogDir, options = {}) {
@@ -5814,34 +5988,35 @@ function formatQuickstartReport(report, format = "table", colorEnabled) {
5814
5988
  ].join("\n");
5815
5989
  }
5816
5990
  const c = colorEnabled;
5817
- const stackLabel = [...report.detected_languages, ...report.detected_frameworks].join(", ") || "general-purpose";
5818
- const targetsLabel = report.active_targets.length > 5 ? `${report.active_targets.slice(0, 5).join(", ")} (+${report.active_targets.length - 5} more)` : report.active_targets.join(", ");
5991
+ const bar = style.dim("\u2502", c);
5992
+ const stackLabel = [...report.detected_languages, ...report.detected_frameworks].join(", ") || "general";
5993
+ const targetsLabel = report.active_targets.length > 4 ? `${report.active_targets.slice(0, 4).join(", ")} (+${report.active_targets.length - 4})` : report.active_targets.join(", ");
5819
5994
  const banner = renderHeaderBanner(
5820
- `1-Step Quickstart & AI Agent Library Setup ${report.dry_run ? "[DRY-RUN]" : "[READY]"}`,
5995
+ `Quickstart Setup ${report.dry_run ? "[DRY-RUN]" : "[READY]"}`,
5821
5996
  { colorEnabled: c }
5822
5997
  );
5823
5998
  const stepsBlock = [
5824
5999
  renderStep(
5825
6000
  1,
5826
6001
  4,
5827
- "Detect Stack & AI Agents",
5828
- `Stack: ${style.cyan(stackLabel, c)} \u2022 Targets: ${style.bold(targetsLabel, c)}`,
6002
+ "Detect Stack & Agents",
6003
+ `${style.cyan(stackLabel, c)} \xB7 ${style.bold(targetsLabel, c)}`,
5829
6004
  "done",
5830
6005
  c
5831
6006
  ),
5832
6007
  renderStep(
5833
6008
  2,
5834
6009
  4,
5835
- "Route Optimal Library Bundle",
5836
- `${style.green(`${report.selected_skills.length} Skills`, c)} + ${style.magenta(`${report.selected_subagents.length} Subagents`, c)} selected`,
6010
+ "Route Library Bundle",
6011
+ `${style.green(`${report.selected_skills.length} Skills`, c)} + ${style.magenta(`${report.selected_subagents.length} Subagents`, c)}`,
5837
6012
  "done",
5838
6013
  c
5839
6014
  ),
5840
6015
  renderStep(
5841
6016
  3,
5842
6017
  4,
5843
- "Transpile & Sync Artifacts",
5844
- `${report.synced_files_count} files synced (${report.dry_run ? "dry-run" : ".skillops.yml + .skillops-lock.json"})`,
6018
+ "Transpile & Sync",
6019
+ `${report.synced_files_count} files (${report.dry_run ? "dry-run" : ".skillops.yml + lockfile"})`,
5845
6020
  "done",
5846
6021
  c
5847
6022
  ),
@@ -5849,12 +6024,12 @@ function formatQuickstartReport(report, format = "table", colorEnabled) {
5849
6024
  4,
5850
6025
  4,
5851
6026
  "Register MCP Server",
5852
- `${report.mcp_configured_count} MCP-compatible agent config(s) updated`,
6027
+ `${report.mcp_configured_count} MCP agent config(s) wired`,
5853
6028
  "done",
5854
6029
  c
5855
6030
  )
5856
6031
  ].join("\n");
5857
- const tokenBar = ` ${renderTokenBar(
6032
+ const tokenBar = `${bar} ${renderTokenBar(
5858
6033
  report.total_l1_tokens,
5859
6034
  report.max_l1_budget,
5860
6035
  {
@@ -5862,21 +6037,16 @@ function formatQuickstartReport(report, format = "table", colorEnabled) {
5862
6037
  colorEnabled: c
5863
6038
  }
5864
6039
  )}`;
5865
- const bundleBox = renderBox(
5866
- [
5867
- `${style.bold("Installed Hybrid Executable Skills:", c)}`,
5868
- ` ${report.selected_skills.map((s) => style.cyan(s, c)).join(", ")}`,
5869
- "",
5870
- `${style.bold("Installed Context-Isolated Subagents:", c)}`,
5871
- ` ${report.selected_subagents.map((a) => style.magenta(a, c)).join(", ")}`
5872
- ],
5873
- {
5874
- title: "\u{1F4E6} Active Skills & Subagents Bundle",
5875
- borderColor: style.cyan,
5876
- minWidth: 72,
5877
- colorEnabled: c
5878
- }
5879
- );
6040
+ const bundleTree = [
6041
+ bar,
6042
+ `${style.dim("\u251C\u2500", c)} ${style.bold(style.cyan(`Active Bundle (${report.selected_skills.length} Skills \xB7 ${report.selected_subagents.length} Subagents)`, c), c)}`,
6043
+ `${bar} \u2022 ${style.bold("Skills:", c)} ${report.selected_skills.slice(0, 2).map((s) => style.cyan(s, c)).join(
6044
+ ", "
6045
+ )}${report.selected_skills.length > 2 ? ` (+${report.selected_skills.length - 2} more)` : ""}`,
6046
+ `${bar} \u2022 ${style.bold("Subagents:", c)} ${report.selected_subagents.slice(0, 2).map((a) => style.magenta(a, c)).join(
6047
+ ", "
6048
+ )}${report.selected_subagents.length > 2 ? ` (+${report.selected_subagents.length - 2} more)` : ""}`
6049
+ ].join("\n");
5880
6050
  const usageGuide = renderAiUsageGuide(
5881
6051
  report.active_targets,
5882
6052
  report.selected_skills,
@@ -5887,32 +6057,29 @@ function formatQuickstartReport(report, format = "table", colorEnabled) {
5887
6057
  [
5888
6058
  {
5889
6059
  command: `npx skillops-cli info ${report.selected_skills[0] ?? "bug-reproducer-tdd"}`,
5890
- description: "Inspect a Skill's triggers, L3 scripts & AI invocation syntax"
6060
+ description: "Inspect Skill triggers & L3 scripts"
5891
6061
  },
5892
6062
  {
5893
6063
  command: "npx skillops-cli list",
5894
- description: "Browse all 10 Skills & 9 Subagents in the Library"
6064
+ description: "Browse all 10 Skills & 9 Subagents"
5895
6065
  },
5896
6066
  {
5897
- command: "npx skillops-cli create skill my-custom-skill",
5898
- description: "Create your own custom Skill using the SkillOps Framework"
6067
+ command: "npx skillops-cli create skill my-skill",
6068
+ description: "Create a custom Skill"
5899
6069
  },
5900
6070
  {
5901
6071
  command: "npx skillops-cli doctor",
5902
- description: "Verify lockfile integrity & Startup Token Tax savings"
6072
+ description: "Verify lockfile & Startup Token Tax"
5903
6073
  }
5904
6074
  ],
5905
6075
  c
5906
6076
  );
5907
6077
  return [
5908
6078
  banner,
5909
- "",
6079
+ bar,
5910
6080
  stepsBlock,
5911
- "",
5912
6081
  tokenBar,
5913
- "",
5914
- bundleBox,
5915
- "",
6082
+ bundleTree,
5916
6083
  usageGuide,
5917
6084
  nextSteps
5918
6085
  ].join("\n");
@@ -6014,6 +6181,41 @@ function resolveCatalogDir(args, repoPath, loadedConfig) {
6014
6181
  }
6015
6182
  return path10.join(PACKAGE_ROOT, "catalog");
6016
6183
  }
6184
+ function buildInteractiveCatalogOptions(catalogDir) {
6185
+ const options = [];
6186
+ const seen = /* @__PURE__ */ new Set();
6187
+ for (const skillDir of discoverSkillDirectories(catalogDir)) {
6188
+ try {
6189
+ const parsed = parseSkillDirectory(skillDir, { requireLayout: false });
6190
+ if (!seen.has(parsed.manifest.name)) {
6191
+ seen.add(parsed.manifest.name);
6192
+ options.push({
6193
+ value: parsed.manifest.name,
6194
+ label: parsed.manifest.name,
6195
+ kind: "skill",
6196
+ hint: parsed.manifest.description
6197
+ });
6198
+ }
6199
+ } catch {
6200
+ }
6201
+ }
6202
+ for (const saPath of discoverSubagentFiles(catalogDir)) {
6203
+ try {
6204
+ const parsed = parseSubagentFile(saPath);
6205
+ if (!seen.has(parsed.manifest.name)) {
6206
+ seen.add(parsed.manifest.name);
6207
+ options.push({
6208
+ value: parsed.manifest.name,
6209
+ label: parsed.manifest.name,
6210
+ kind: "agent",
6211
+ hint: parsed.manifest.description
6212
+ });
6213
+ }
6214
+ } catch {
6215
+ }
6216
+ }
6217
+ return options;
6218
+ }
6017
6219
  function runCli(argv) {
6018
6220
  const args = argv.slice(2);
6019
6221
  if (args.includes("--version") || args.includes("-V") || args[0] === "version") {
@@ -6026,15 +6228,18 @@ function runCli(argv) {
6026
6228
  if (targetCmd && !targetCmd.startsWith("-")) {
6027
6229
  const spec = findCommandHelpSpec(targetCmd);
6028
6230
  if (spec) {
6029
- process.stdout.write(renderCommandHelp(spec, SKILLOPS_VERSION));
6231
+ process.stdout.write(`${renderCommandHelp(spec, SKILLOPS_VERSION)}
6232
+ `);
6030
6233
  return ExitCode.SUCCESS;
6031
6234
  }
6032
6235
  }
6033
- process.stdout.write(renderGlobalHelp(SKILLOPS_VERSION));
6236
+ process.stdout.write(`${renderGlobalHelp(SKILLOPS_VERSION)}
6237
+ `);
6034
6238
  return ExitCode.SUCCESS;
6035
6239
  }
6036
6240
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
6037
- process.stdout.write(renderGlobalHelp(SKILLOPS_VERSION));
6241
+ process.stdout.write(`${renderGlobalHelp(SKILLOPS_VERSION)}
6242
+ `);
6038
6243
  return ExitCode.SUCCESS;
6039
6244
  }
6040
6245
  if (args.includes("--help") || args.includes("-h")) {
@@ -6042,11 +6247,13 @@ function runCli(argv) {
6042
6247
  if (firstCmd) {
6043
6248
  const spec = findCommandHelpSpec(firstCmd);
6044
6249
  if (spec) {
6045
- process.stdout.write(renderCommandHelp(spec, SKILLOPS_VERSION));
6250
+ process.stdout.write(`${renderCommandHelp(spec, SKILLOPS_VERSION)}
6251
+ `);
6046
6252
  return ExitCode.SUCCESS;
6047
6253
  }
6048
6254
  }
6049
- process.stdout.write(renderGlobalHelp(SKILLOPS_VERSION));
6255
+ process.stdout.write(`${renderGlobalHelp(SKILLOPS_VERSION)}
6256
+ `);
6050
6257
  return ExitCode.SUCCESS;
6051
6258
  }
6052
6259
  const command = args[0] ?? "";
@@ -6207,6 +6414,7 @@ function runCli(argv) {
6207
6414
  return ExitCode.SUCCESS;
6208
6415
  }
6209
6416
  if (command === "list") {
6417
+ const positionals = getPositionalArgs(args);
6210
6418
  const repoPath = getFlagValue(args, "--repo", "--project", "-p") ?? process.cwd();
6211
6419
  const cfgRes = loadSkillOpsConfig(repoPath);
6212
6420
  if (cfgRes.error) {
@@ -6218,6 +6426,12 @@ function runCli(argv) {
6218
6426
  }
6219
6427
  const catalogDir = resolveCatalogDir(args, repoPath, cfgRes.config);
6220
6428
  const rawFormat = getFlagValue(args, "--format", "-f") ?? "table";
6429
+ if (positionals.length > 0) {
6430
+ const format = rawFormat === "json" || rawFormat === "markdown" ? rawFormat : "table";
6431
+ const report = searchCatalog(catalogDir, positionals.join(" "));
6432
+ process.stdout.write(formatCatalogSearchReport(report, format));
6433
+ return ExitCode.SUCCESS;
6434
+ }
6221
6435
  const summary = auditCatalogTokenBudgets(catalogDir, {
6222
6436
  requireLayout: false
6223
6437
  });
@@ -6253,7 +6467,7 @@ function runCli(argv) {
6253
6467
  return ExitCode.SUCCESS;
6254
6468
  }
6255
6469
  const l1Bar = renderProgressBar(summary.totalL1Tokens, 1500, {
6256
- width: 18,
6470
+ width: 10,
6257
6471
  unit: "tokens"
6258
6472
  });
6259
6473
  const firstSkill = summary.skills[0]?.skillName ?? "security-sast-gate";
@@ -6271,15 +6485,15 @@ function runCli(argv) {
6271
6485
  renderNextSteps([
6272
6486
  {
6273
6487
  command: `npx skillops-cli info ${firstSkill}`,
6274
- description: "Inspect triggers, L3 scripts & how to invoke in your AI"
6488
+ description: "Inspect triggers & usage"
6275
6489
  },
6276
6490
  {
6277
6491
  command: "npx skillops-cli search <keyword>",
6278
- description: "Search Skills & Subagents by domain or signal"
6492
+ description: "Search Skills & Subagents"
6279
6493
  },
6280
6494
  {
6281
6495
  command: "npx skillops-cli quickstart",
6282
- description: "Auto-detect project stack & install optimal bundle"
6496
+ description: "Auto-detect & install"
6283
6497
  }
6284
6498
  ])
6285
6499
  ];
@@ -6467,7 +6681,9 @@ function runCli(argv) {
6467
6681
  const force = args.includes("--force");
6468
6682
  const rawFormat = getFlagValue(args, "--format", "-f") ?? "table";
6469
6683
  const format = rawFormat === "json" || rawFormat === "markdown" ? rawFormat : "table";
6470
- if (positionals.length === 0) {
6684
+ const importAll = args.includes("--all");
6685
+ const itemsToAdd = importAll && positionals.length === 0 ? buildInteractiveCatalogOptions(catalogDir).map((o) => o.value) : positionals;
6686
+ if (itemsToAdd.length === 0) {
6471
6687
  if (command === "add") {
6472
6688
  process.stderr.write(
6473
6689
  "Usage: npx skillops-cli add <skill-or-subagent-name> [more-names...] [options]\n"
@@ -6488,19 +6704,27 @@ function runCli(argv) {
6488
6704
  return report.passed ? ExitCode.SUCCESS : ExitCode.ERROR;
6489
6705
  }
6490
6706
  try {
6491
- let allPassed = true;
6492
- for (const itemName of positionals) {
6493
- const report = addSkillOrSubagent(repoPath, catalogDir, itemName, {
6707
+ const reports = itemsToAdd.map(
6708
+ (itemName) => addSkillOrSubagent(repoPath, catalogDir, itemName, {
6494
6709
  targets,
6495
6710
  dryRun,
6496
6711
  force
6497
- });
6498
- process.stdout.write(formatSyncReport(report, format));
6499
- if (!report.passed) {
6500
- allPassed = false;
6501
- }
6712
+ })
6713
+ );
6714
+ const firstReport = reports[0];
6715
+ if (!firstReport) {
6716
+ return ExitCode.ERROR;
6502
6717
  }
6503
- return allPassed ? ExitCode.SUCCESS : ExitCode.ERROR;
6718
+ const finalReport = reports.length === 1 ? firstReport : {
6719
+ ...firstReport,
6720
+ artifacts: reports.flatMap((r) => r.artifacts),
6721
+ drift_conflicts: [
6722
+ ...new Set(reports.flatMap((r) => r.drift_conflicts))
6723
+ ],
6724
+ passed: reports.every((r) => r.passed)
6725
+ };
6726
+ process.stdout.write(formatSyncReport(finalReport, format));
6727
+ return finalReport.passed ? ExitCode.SUCCESS : ExitCode.ERROR;
6504
6728
  } catch (err) {
6505
6729
  const msg = err instanceof Error ? err.message : String(err);
6506
6730
  process.stderr.write(`Error: ${msg}
@@ -6677,6 +6901,46 @@ function runCli(argv) {
6677
6901
  );
6678
6902
  return ExitCode.ERROR;
6679
6903
  }
6904
+ async function runCliInteractive(argv) {
6905
+ const args = argv.slice(2);
6906
+ const command = args[0];
6907
+ if (command === "add" && !args.includes("--help") && !args.includes("-h") && !args.includes("--all") && getPositionalArgs(args).length === 0 && process.stdin.isTTY && process.stdout.isTTY) {
6908
+ const repoPath = getFlagValue(args, "--repo", "--project", "-p") ?? process.cwd();
6909
+ const cfgRes = loadSkillOpsConfig(repoPath);
6910
+ if (cfgRes.error) {
6911
+ process.stderr.write(
6912
+ `Invalid .skillops.yml at ${cfgRes.configPath}: ${cfgRes.error}
6913
+ `
6914
+ );
6915
+ return ExitCode.BUDGET_OR_CONTRACT_ERROR;
6916
+ }
6917
+ const catalogDir = resolveCatalogDir(args, repoPath, cfgRes.config);
6918
+ const targetsArg = resolveTargetsArg(args);
6919
+ let targets;
6920
+ try {
6921
+ targets = targetsArg ? resolveRuntimeTargets(targetsArg, repoPath) : cfgRes.config?.targets ?? [...CORE_RUNTIME_TARGETS];
6922
+ } catch (err) {
6923
+ const msg = err instanceof Error ? err.message : String(err);
6924
+ process.stderr.write(`Invalid --targets: ${msg}
6925
+ `);
6926
+ return ExitCode.BUDGET_OR_CONTRACT_ERROR;
6927
+ }
6928
+ const options = buildInteractiveCatalogOptions(catalogDir);
6929
+ const selected = await runMultiSelectPrompt(
6930
+ "SkillOps \u2014 Select Skills & Agents to Import",
6931
+ options,
6932
+ {
6933
+ targetHint: `${targets.join(", ")} -> ${repoPath.replace(/\\/g, "/")}`
6934
+ }
6935
+ );
6936
+ if (!selected || selected.length === 0) {
6937
+ process.stdout.write("No Skills or Agents selected.\n");
6938
+ return ExitCode.SUCCESS;
6939
+ }
6940
+ return runCli([...argv, ...selected]);
6941
+ }
6942
+ return runCli(argv);
6943
+ }
6680
6944
  function isDirectCliInvocation() {
6681
6945
  const entryArg = process.argv[1];
6682
6946
  if (!entryArg) {
@@ -6693,9 +6957,12 @@ function isDirectCliInvocation() {
6693
6957
  }
6694
6958
  }
6695
6959
  if (isDirectCliInvocation()) {
6696
- const code = runCli(process.argv);
6697
- process.exit(code);
6960
+ runCliInteractive(process.argv).then((code) => {
6961
+ process.exit(code);
6962
+ });
6698
6963
  }
6699
6964
  export {
6700
- runCli
6965
+ buildInteractiveCatalogOptions,
6966
+ runCli,
6967
+ runCliInteractive
6701
6968
  };