skillio 0.1.15 → 0.1.16

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 (2) hide show
  1. package/dist/cli.js +57 -36
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -861,9 +861,8 @@ var listCommand = defineCommand({
861
861
  render: () => {
862
862
  if (rows.lock.totalCount === 0)
863
863
  return "";
864
- if (orphans.length === 0)
865
- return green("All skills onboard!");
866
- return orphans.map((n) => red(n.name)).join(" ");
864
+ const orphanSet = new Set(orphans.map((n) => n.name));
865
+ return rows.lock.names.map((n) => orphanSet.has(n.name) ? red(n.name) : n.name).join(" ");
867
866
  }
868
867
  }
869
868
  ];
@@ -900,7 +899,6 @@ var listCommand = defineCommand({
900
899
  });
901
900
 
902
901
  // src/commands/remove.ts
903
- import { existsSync as existsSync3, lstatSync as lstatSync3 } from "node:fs";
904
902
  import { homedir as homedir2 } from "node:os";
905
903
  import { dirname as dirname2, join as join3, resolve as resolve3 } from "node:path";
906
904
 
@@ -988,17 +986,24 @@ function createConfirmer(opts = {}) {
988
986
  }
989
987
 
990
988
  // src/utils/fs-rm.ts
991
- import { existsSync as existsSync2, lstatSync as lstatSync2, readdirSync, rmSync } from "node:fs";
989
+ import { lstatSync as lstatSync2, readdirSync, rmSync } from "node:fs";
992
990
  import { join as join2, resolve as resolve2 } from "node:path";
993
991
  function isInside(target, root) {
994
992
  const t = resolve2(target);
995
993
  const r = resolve2(root);
996
994
  return t === r || t.startsWith(`${r}/`);
997
995
  }
996
+ function lstatOrNull(path) {
997
+ try {
998
+ return lstatSync2(path);
999
+ } catch {
1000
+ return null;
1001
+ }
1002
+ }
998
1003
  function countFiles(path) {
999
- if (!existsSync2(path))
1004
+ const stat = lstatOrNull(path);
1005
+ if (!stat)
1000
1006
  return 0;
1001
- const stat = lstatSync2(path);
1002
1007
  if (stat.isFile())
1003
1008
  return 1;
1004
1009
  if (!stat.isDirectory())
@@ -1029,7 +1034,7 @@ function rmSkillDir(path, opts) {
1029
1034
  if (!safe) {
1030
1035
  throw new Error(`Refusing to delete: "${path}" is outside allowed roots`);
1031
1036
  }
1032
- if (!existsSync2(path))
1037
+ if (!lstatOrNull(path))
1033
1038
  return { removed: false, fileCount: 0 };
1034
1039
  const fileCount = countFiles(path);
1035
1040
  rmSync(path, { recursive: true, force: true });
@@ -1038,12 +1043,13 @@ function rmSkillDir(path, opts) {
1038
1043
 
1039
1044
  // src/commands/remove.ts
1040
1045
  function buildLocation(dir) {
1041
- if (!existsSync3(dir))
1042
- return { kind: "missing", folders: 0, files: 0 };
1043
- if (lstatSync3(dir).isSymbolicLink())
1044
- return { kind: "symlink", folders: 0, files: 0 };
1046
+ const stat = lstatOrNull(dir);
1047
+ if (!stat)
1048
+ return { kind: "missing", subfolders: 0, files: 0 };
1049
+ if (stat.isSymbolicLink())
1050
+ return { kind: "symlink", subfolders: 0, files: 0 };
1045
1051
  const { folders, files } = countFoldersAndFiles(dir);
1046
- return { kind: "real", folders, files };
1052
+ return { kind: "real", subfolders: folders, files };
1047
1053
  }
1048
1054
  function rootFor2(base, isGlobal, lockPath) {
1049
1055
  return isGlobal ? join3(homedir2(), base, "skills") : join3(dirname2(resolve3(lockPath)), base, "skills");
@@ -1072,53 +1078,63 @@ function header(targets, verb) {
1072
1078
  }
1073
1079
  function aggregateLocations(infos) {
1074
1080
  let folders = 0;
1081
+ let subfolders = 0;
1075
1082
  let files = 0;
1076
1083
  let symlinks = 0;
1077
1084
  for (const info of infos) {
1078
1085
  if (info.kind === "real") {
1079
- folders += info.folders;
1086
+ folders += 1;
1087
+ subfolders += info.subfolders;
1080
1088
  files += info.files;
1081
1089
  } else if (info.kind === "symlink") {
1082
1090
  symlinks += 1;
1083
1091
  }
1084
1092
  }
1085
- return { folders, files, symlinks, found: infos.some((i) => i.kind !== "missing") };
1093
+ return { folders, subfolders, files, symlinks, found: infos.some((i) => i.kind !== "missing") };
1086
1094
  }
1087
- function diskLine(label, singleName, infos, variant) {
1088
- const displayLabel = singleName ? `${label}/${singleName}/` : label;
1095
+ function diskCell(infos, variant) {
1089
1096
  const agg = aggregateLocations(infos);
1090
1097
  if (!agg.found)
1091
- return ` ${displayLabel} (not found)`;
1098
+ return "not found";
1092
1099
  const parts = [];
1093
1100
  if (agg.folders > 0 || agg.files > 0) {
1094
- const text = `${plural(agg.folders, "folder")}, ${plural(agg.files, "file")}`;
1101
+ const text = `${plural(agg.folders, "folder")}, ${plural(agg.subfolders, "subfolder")}, ${plural(agg.files, "file")}`;
1095
1102
  parts.push(variant === "summary" ? red(text) : green(text));
1096
1103
  }
1097
1104
  if (agg.symlinks > 0) {
1098
1105
  const text = plural(agg.symlinks, "symlink");
1099
1106
  parts.push(variant === "summary" ? red(text) : yellow(text));
1100
1107
  }
1101
- return ` ${displayLabel} (${parts.join(", ")})`;
1108
+ return parts.join(", ");
1102
1109
  }
1103
- function lockLine(n, variant) {
1104
- const label = "skills-lock.json";
1110
+ function lockCell(n, variant) {
1105
1111
  if (n === 0)
1106
- return ` ${label} (not in lock)`;
1112
+ return "not in lock";
1107
1113
  if (variant === "kept")
1108
- return ` ${green(`${label} (${plural(n, "line")} kept)`)}`;
1109
- return ` ${red(`${label} (${plural(n, "line")})`)}`;
1114
+ return green(`${plural(n, "line")} kept`);
1115
+ return red(plural(n, "line"));
1110
1116
  }
1111
1117
  function printBlock(targets, scope, verb, lockLinesToRemove, diskVariant, lockVariant) {
1112
1118
  console.log(header(targets, verb));
1113
- const singleName = targets.length === 1 ? targets[0]?.name : undefined;
1119
+ const rows = [];
1114
1120
  if (scope === "all" || scope === "agents-only") {
1115
- console.log(diskLine(".agents/skills", singleName, targets.map((t) => t.agents), diskVariant));
1121
+ rows.push([
1122
+ ".agents/skills/",
1123
+ diskCell(targets.map((t) => t.agents), diskVariant)
1124
+ ]);
1116
1125
  }
1117
1126
  if (scope === "all" || scope === "claude-only") {
1118
- console.log(diskLine(".claude/skills", singleName, targets.map((t) => t.claude), diskVariant));
1127
+ rows.push([
1128
+ ".claude/skills/",
1129
+ diskCell(targets.map((t) => t.claude), diskVariant)
1130
+ ]);
1119
1131
  }
1120
1132
  if (scope === "all" || scope === "lock-only") {
1121
- console.log(lockLine(lockLinesToRemove, lockVariant));
1133
+ rows.push(["skills-lock.json", lockCell(lockLinesToRemove, lockVariant)]);
1134
+ }
1135
+ const labelWidth = Math.max(...rows.map(([label]) => label.length));
1136
+ for (const [label, cell] of rows) {
1137
+ console.log(`${label.padEnd(labelWidth)} ${cell}`);
1122
1138
  }
1123
1139
  }
1124
1140
  var removeCommand = defineCommand({
@@ -1190,6 +1206,7 @@ var removeCommand = defineCommand({
1190
1206
  printBlock(targets, scope, "will be removed from:", lockLinesToRemove, "plan", "removed");
1191
1207
  const ask = createConfirmer();
1192
1208
  if (!yes) {
1209
+ console.log("");
1193
1210
  const ok = await ask("Proceed?");
1194
1211
  if (!ok) {
1195
1212
  console.log("Aborted");
@@ -1211,7 +1228,11 @@ var removeCommand = defineCommand({
1211
1228
  removeSkillFromLock(lockPath, t.name);
1212
1229
  lockCleaned = true;
1213
1230
  } else if (scope === "all" && lockLinesToRemove > 0) {
1214
- const cleanLock = yes || await ask(`Clean skills-lock.json (${plural(lockLinesToRemove, "line")})?`);
1231
+ let cleanLock = yes;
1232
+ if (!yes) {
1233
+ console.log("");
1234
+ cleanLock = await ask(`Clean skills-lock.json (${plural(lockLinesToRemove, "line")})?`);
1235
+ }
1215
1236
  if (cleanLock) {
1216
1237
  for (const t of targets)
1217
1238
  removeSkillFromLock(lockPath, t.name);
@@ -1224,7 +1245,7 @@ var removeCommand = defineCommand({
1224
1245
  });
1225
1246
 
1226
1247
  // src/commands/usage.ts
1227
- import { existsSync as existsSync6 } from "node:fs";
1248
+ import { existsSync as existsSync4 } from "node:fs";
1228
1249
  import { join as join7 } from "node:path";
1229
1250
 
1230
1251
  // src/readers/claude.ts
@@ -1558,10 +1579,10 @@ function readClaudeUsage(options) {
1558
1579
  }
1559
1580
 
1560
1581
  // src/readers/codex.ts
1561
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
1582
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
1562
1583
 
1563
1584
  // src/utils/scope.ts
1564
- import { existsSync as existsSync4 } from "node:fs";
1585
+ import { existsSync as existsSync2 } from "node:fs";
1565
1586
  import { homedir as homedir4 } from "node:os";
1566
1587
  import { dirname as dirname3, join as join6 } from "node:path";
1567
1588
  function detectScope(opts) {
@@ -1583,7 +1604,7 @@ function encodeClaudeProjectDir(absPath) {
1583
1604
  function findGitRoot(start) {
1584
1605
  let dir = start;
1585
1606
  while (true) {
1586
- if (existsSync4(join6(dir, ".git")))
1607
+ if (existsSync2(join6(dir, ".git")))
1587
1608
  return dir;
1588
1609
  const parent = dirname3(dir);
1589
1610
  if (parent === dir)
@@ -1656,7 +1677,7 @@ function readCodexMentions(options) {
1656
1677
  const historyPath = expandHome(options.history ?? "~/.codex/history.jsonl");
1657
1678
  const counts = new Map;
1658
1679
  let linesRead = 0;
1659
- if (!existsSync5(historyPath))
1680
+ if (!existsSync3(historyPath))
1660
1681
  return { counts, filesRead: 0, linesRead: 0 };
1661
1682
  for (const line of readFileSync3(historyPath, "utf8").split(`
1662
1683
  `)) {
@@ -1766,7 +1787,7 @@ async function runUsage(args) {
1766
1787
  });
1767
1788
  const claudeProjectsRoot = expandHome("~/.claude/projects");
1768
1789
  const claudeRoot = args.root ?? (scope.projectRoot ? join7(claudeProjectsRoot, encodeClaudeProjectDir(scope.projectRoot)) : claudeProjectsRoot);
1769
- const claudeRootMissing = !args.root && !!scope.projectRoot && !existsSync6(claudeRoot);
1790
+ const claudeRootMissing = !args.root && !!scope.projectRoot && !existsSync4(claudeRoot);
1770
1791
  const lockPath = getLockPath(args.global);
1771
1792
  const skillUniverse = discoverSkills({
1772
1793
  isGlobal: args.global,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillio",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Audit and manage AI agent skills for Claude Code and Codex",
5
5
  "license": "MIT",
6
6
  "author": "ihororlovskyi",