skillio 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +30 -96
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -66,14 +66,16 @@ audits both Claude Code and Codex over all time).
66
66
  ## Usage
67
67
 
68
68
  ```sh
69
- # bare command — quick summary across global + local sources, with verdict
69
+ # bare command — per-skill ambient token cost, sorted desc, with verdict
70
70
  skl
71
71
  skillio # equivalent
72
72
 
73
73
  # subcommands
74
74
  skl ls # list skills per source with diffs
75
75
  skl cost # ambient ballast cost (frontmatter tokens) per skill
76
+ skl cst # alias for cost
76
77
  skl usage # consumption: usage count × frontmatter tokens
78
+ skl usg # alias for usage
77
79
  skl rm brainstorming # remove from lock + delete on-disk dir (with Y/n prompt)
78
80
  skl rm brainstorming writing-plans # remove multiple
79
81
  skl rm --yes brainstorming # skip confirmation
@@ -97,11 +99,9 @@ skl usage -a claude -a codex # equivalent: repeated --agent flag
97
99
  | anywhere with `-g` / `--global` | global override |
98
100
  | with `--root <dir>` | that exact dir, treated as global |
99
101
 
100
- > Bare `skl` (no subcommand) ignores `-g` — it always shows both Global and Local sections plus a grand Total.
101
-
102
102
  ## What it does
103
103
 
104
- - **Summary** (`skl`) — counts and tokens across `.claude/skills`, `.agents/skills`, and `skills-lock.json` for both global and local scopes, with a cleanup verdict.
104
+ - **Cost** (`skl`) — per-skill ambient token cost sorted descending, with a cleanup verdict. Bare `skl` = `skl cost` in local scope; `skl -g` = global scope.
105
105
  - **Audit skill usage** (`skl usage`) — parse agent session logs and count which skills were invoked, when, and how often.
106
106
  - **Manage a skills lock** (`skl ls`, `skl rm`) — inspect and remove skills from a local or global lock file.
107
107
 
package/dist/cli.js CHANGED
@@ -596,6 +596,9 @@ function yellow(s) {
596
596
  function red(s) {
597
597
  return enabled ? `\x1B[31m${s}\x1B[0m` : s;
598
598
  }
599
+ function cyan2(s) {
600
+ return enabled ? `\x1B[36m${s}\x1B[0m` : s;
601
+ }
599
602
 
600
603
  // src/utils/discover-skills.ts
601
604
  import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, statSync } from "node:fs";
@@ -717,7 +720,8 @@ var costCommand = defineCommand({
717
720
  cell = "missing";
718
721
  else
719
722
  cell = "(no frontmatter)";
720
- console.log(`${r.name.padEnd(nameWidth)} ${cell}`);
723
+ const pad = " ".repeat(nameWidth - r.name.length);
724
+ console.log(`${cyan2(r.name)}${pad} ${cell}`);
721
725
  }
722
726
  console.log("");
723
727
  console.log(`Total: ~${total} tok across ${rows.length} skills ${paint(message)}`);
@@ -788,19 +792,19 @@ var listCommand = defineCommand({
788
792
  if (!row)
789
793
  continue;
790
794
  const countCell = countCells[i] ?? "";
791
- const namesText = row.names.length ? row.names.join(" ") : "";
795
+ const namesText = row.names.length ? row.names.map(cyan2).join(" ") : "";
792
796
  const line = `${row.label.padEnd(labelWidth)} : ${countCell.padEnd(countWidth)}${namesText ? ` : ${namesText}` : ""}`;
793
797
  console.log(line.trimEnd());
794
798
  }
795
799
  const diffs = [];
796
800
  if (lockOnly.length) {
797
- diffs.push(`skills-lock.json has ${lockOnly.length} skill${lockOnly.length === 1 ? "" : "s"} missing on disk: ${lockOnly.join(", ")}`);
801
+ diffs.push(`skills-lock.json has ${lockOnly.length} skill${lockOnly.length === 1 ? "" : "s"} missing on disk: ${lockOnly.map(cyan2).join(", ")}`);
798
802
  }
799
803
  if (claudeNotInLock.length) {
800
- diffs.push(`.claude/skills has ${claudeNotInLock.length} skill${claudeNotInLock.length === 1 ? "" : "s"} not in lock: ${claudeNotInLock.join(", ")}`);
804
+ diffs.push(`.claude/skills has ${claudeNotInLock.length} skill${claudeNotInLock.length === 1 ? "" : "s"} not in lock: ${claudeNotInLock.map(cyan2).join(", ")}`);
801
805
  }
802
806
  if (agentsNotInLock.length) {
803
- diffs.push(`.agents/skills has ${agentsNotInLock.length} skill${agentsNotInLock.length === 1 ? "" : "s"} not in lock: ${agentsNotInLock.join(", ")}`);
807
+ diffs.push(`.agents/skills has ${agentsNotInLock.length} skill${agentsNotInLock.length === 1 ? "" : "s"} not in lock: ${agentsNotInLock.map(cyan2).join(", ")}`);
804
808
  }
805
809
  if (diffs.length) {
806
810
  console.log("");
@@ -976,89 +980,6 @@ var removeCommand = defineCommand({
976
980
  }
977
981
  });
978
982
 
979
- // src/commands/summary.ts
980
- function classify2(total) {
981
- if (total < 1000)
982
- return { verdict: "ok", message: "OK — keep it lean", paint: green };
983
- if (total <= 1500)
984
- return { verdict: "plan", message: "time to plan some cleanup", paint: yellow };
985
- return { verdict: "cleanup", message: "ballast — clean it up", paint: red };
986
- }
987
- function bucketTokens(records, source) {
988
- return records.filter((r) => r.sources.includes(source)).reduce((acc, r) => acc + (r.frontmatterTokens ?? 0), 0);
989
- }
990
- function bucketCount(records, source) {
991
- return records.filter((r) => r.sources.includes(source)).length;
992
- }
993
- function buildSection(opts) {
994
- const lockPath = getLockPath(opts.isGlobal);
995
- const records = [
996
- ...discoverSkills({ isGlobal: opts.isGlobal, cwd: opts.cwd, lockPath }).values()
997
- ];
998
- const rows = [
999
- {
1000
- label: `${opts.prefix}.claude/skills`,
1001
- count: bucketCount(records, ".claude"),
1002
- tokens: bucketTokens(records, ".claude")
1003
- },
1004
- {
1005
- label: `${opts.prefix}.agents/skills`,
1006
- count: bucketCount(records, ".agents"),
1007
- tokens: bucketTokens(records, ".agents")
1008
- },
1009
- {
1010
- label: `${opts.prefix}skills-lock.json`,
1011
- count: bucketCount(records, "lock"),
1012
- tokens: bucketTokens(records, "lock")
1013
- }
1014
- ];
1015
- const totalTokens = records.reduce((acc, r) => acc + (r.frontmatterTokens ?? 0), 0);
1016
- const totalCount = records.length;
1017
- return {
1018
- title: opts.isGlobal ? "Global" : "Local",
1019
- rows,
1020
- totalCount,
1021
- totalTokens
1022
- };
1023
- }
1024
- function formatRow(row, labelW, countW, tokenW) {
1025
- const countCell = row.count === 0 ? "(empty)" : `${row.count} skill${row.count === 1 ? "" : "s"}`;
1026
- const tokensCell = `~${row.tokens} tok`;
1027
- return `${row.label.padEnd(labelW)} : ${countCell.padEnd(countW)} ${tokensCell.padStart(tokenW)}`;
1028
- }
1029
- function renderSection(section) {
1030
- const labelW = Math.max(...section.rows.map((r) => r.label.length));
1031
- const countCells = section.rows.map((r) => r.count === 0 ? "(empty)" : `${r.count} skill${r.count === 1 ? "" : "s"}`);
1032
- const countW = Math.max(...countCells.map((c) => c.length));
1033
- const tokenW = Math.max(...section.rows.map((r) => `~${r.tokens} tok`.length));
1034
- return [section.title, ...section.rows.map((r) => formatRow(r, labelW, countW, tokenW))];
1035
- }
1036
- function runSummary(args) {
1037
- const cwd = process.cwd();
1038
- const global = buildSection({ isGlobal: true, cwd, prefix: "~/" });
1039
- const local = buildSection({ isGlobal: false, cwd, prefix: "" });
1040
- const lines = [];
1041
- lines.push(...renderSection(global));
1042
- lines.push("");
1043
- lines.push(...renderSection(local));
1044
- lines.push("");
1045
- const grandTokens = global.totalTokens + local.totalTokens;
1046
- const grandCount = global.totalCount + local.totalCount;
1047
- const { message, paint } = classify2(grandTokens);
1048
- lines.push(`Total: ${grandCount} skills ~${grandTokens} tok ${paint(message)}`);
1049
- console.log(lines.join(`
1050
- `));
1051
- }
1052
- var summaryCommand = defineCommand({
1053
- meta: { description: "Show skill counts and tokens across global + local sources" },
1054
- args: {
1055
- global: { type: "boolean", alias: "g", default: false, description: "Use global scope" }
1056
- },
1057
- run({ args }) {
1058
- runSummary({ global: args.global });
1059
- }
1060
- });
1061
-
1062
983
  // src/commands/usage.ts
1063
984
  import { existsSync as existsSync9 } from "node:fs";
1064
985
  import { join as join10 } from "node:path";
@@ -1397,7 +1318,7 @@ function pad(n, width) {
1397
1318
  return String(n).padStart(width);
1398
1319
  }
1399
1320
  function formatUsageRow(row) {
1400
- return `${pad(row.count, row.countWidth)} ${row.name}`;
1321
+ return `${pad(row.count, row.countWidth)} ${cyan2(row.name)}`;
1401
1322
  }
1402
1323
  function parseAgents(agent) {
1403
1324
  if (!agent)
@@ -1670,7 +1591,18 @@ function mergeAgentArgs(argv) {
1670
1591
  out.splice(slotIdx, 0, "--agent", values.join("\x1F"));
1671
1592
  return out;
1672
1593
  }
1673
- var SUBCOMMAND_NAMES = new Set(["list", "ls", "remove", "rm", "cost", "co", "usage", "us"]);
1594
+ var SUBCOMMAND_NAMES = new Set([
1595
+ "list",
1596
+ "ls",
1597
+ "remove",
1598
+ "rm",
1599
+ "cost",
1600
+ "co",
1601
+ "cst",
1602
+ "usage",
1603
+ "us",
1604
+ "usg"
1605
+ ]);
1674
1606
  function reorderRootFlagsToSubcommand(argv) {
1675
1607
  const tail = argv.slice(2);
1676
1608
  const subIdx = tail.findIndex((t) => !!t && SUBCOMMAND_NAMES.has(t));
@@ -1702,8 +1634,8 @@ function printRootHelp() {
1702
1634
  "",
1703
1635
  " list, ls List skills per source with totals and lock-vs-disk diff",
1704
1636
  " remove, rm Remove skills from lock and delete their on-disk dirs",
1705
- " cost, co Show ambient ballast cost (per-skill frontmatter tokens) sorted desc",
1706
- " usage, us Show skill usage × cost (consumption) with missed rows"
1637
+ " cost, co, cst Show ambient ballast cost (per-skill frontmatter tokens) sorted desc",
1638
+ " usage, us, usg Show skill usage × cost (consumption) with missed rows"
1707
1639
  ];
1708
1640
  console.log(lines.join(`
1709
1641
  `));
@@ -1754,13 +1686,13 @@ var main = defineCommand({
1754
1686
  version,
1755
1687
  description: "Audit and manage AI agent skills"
1756
1688
  },
1757
- args: summaryCommand.args,
1689
+ args: costCommand.args,
1758
1690
  async run({ args }) {
1759
1691
  if (hasSubcommand(process.argv))
1760
1692
  return;
1761
- await summaryCommand.run?.({
1693
+ await costCommand.run?.({
1762
1694
  args,
1763
- cmd: summaryCommand,
1695
+ cmd: costCommand,
1764
1696
  rawArgs: process.argv.slice(2)
1765
1697
  });
1766
1698
  },
@@ -1771,8 +1703,10 @@ var main = defineCommand({
1771
1703
  rm: removeCommand,
1772
1704
  cost: costCommand,
1773
1705
  co: costCommand,
1706
+ cst: costCommand,
1774
1707
  usage: usageCommand,
1775
- us: usageCommand
1708
+ us: usageCommand,
1709
+ usg: usageCommand
1776
1710
  }
1777
1711
  });
1778
1712
  (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillio",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Audit and manage AI agent skills for Claude Code and Codex",
5
5
  "license": "MIT",
6
6
  "author": "ihororlovskyi",