skillio 0.1.8 → 0.1.9

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 +65 -16
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -871,6 +871,7 @@ function rmSkillDir(path, opts) {
871
871
  }
872
872
 
873
873
  // src/commands/remove.ts
874
+ var q = (name) => `"${cyan2(name)}"`;
874
875
  function buildTarget(name, isGlobal, lockPath) {
875
876
  const lock = readLock(lockPath);
876
877
  const inLock = Object.hasOwn(lock.skills, name);
@@ -897,7 +898,7 @@ function fileCount(dir) {
897
898
  }
898
899
  function printPlan(plan) {
899
900
  const { target } = plan;
900
- console.log(`Will remove "${target.name}":`);
901
+ console.log(`Will remove ${q(target.name)}:`);
901
902
  if (target.inLock)
902
903
  console.log(" - skills-lock.json");
903
904
  else
@@ -931,7 +932,7 @@ var removeCommand = defineCommand({
931
932
  const orphan = targets.filter((t) => !t.inLock && !t.claudeDir && !t.agentsDir);
932
933
  if (orphan.length) {
933
934
  for (const o of orphan)
934
- console.log(`"${o.name}" is not in lock or on disk`);
935
+ console.log(`${q(o.name)} is not in lock or on disk`);
935
936
  process.exit(1);
936
937
  }
937
938
  const plans = targets.map((t) => ({
@@ -960,19 +961,19 @@ var removeCommand = defineCommand({
960
961
  if (target.inLock) {
961
962
  const r = removeSkillFromLock(lockPath, target.name);
962
963
  if (r.removed)
963
- console.log(`Removed "${target.name}" from skills-lock.json`);
964
+ console.log(`Removed ${q(target.name)} from skills-lock.json`);
964
965
  } else {
965
966
  console.log(`Skipped skills-lock.json (not in lock)`);
966
967
  }
967
968
  if (target.claudeDir) {
968
969
  const r = rmSkillDir(target.claudeDir, { allowedRoots });
969
- console.log(`Removed "${target.name}" from .claude/skills (${r.fileCount} files)`);
970
+ console.log(`Removed ${q(target.name)} from .claude/skills (${r.fileCount} files)`);
970
971
  } else {
971
972
  console.log("Skipped .claude/skills (not found)");
972
973
  }
973
974
  if (target.agentsDir) {
974
975
  const r = rmSkillDir(target.agentsDir, { allowedRoots });
975
- console.log(`Removed "${target.name}" from .agents/skills (${r.fileCount} files)`);
976
+ console.log(`Removed ${q(target.name)} from .agents/skills (${r.fileCount} files)`);
976
977
  } else {
977
978
  console.log("Skipped .agents/skills (not found)");
978
979
  }
@@ -1047,6 +1048,26 @@ function extractCodexActivations(entry) {
1047
1048
  }
1048
1049
  return [...paths].map(skillNameFromPath).filter((s) => s !== null);
1049
1050
  }
1051
+ if (e.type === "response_item" && payload?.type === "function_call" && payload?.name === "exec_command") {
1052
+ const argsStr = payload?.arguments;
1053
+ if (typeof argsStr !== "string")
1054
+ return [];
1055
+ let parsed;
1056
+ try {
1057
+ parsed = JSON.parse(argsStr);
1058
+ } catch {
1059
+ return [];
1060
+ }
1061
+ const cmd = parsed?.cmd;
1062
+ if (typeof cmd !== "string")
1063
+ return [];
1064
+ const paths = new Set;
1065
+ for (const m of cmd.matchAll(/(?:^|['"\s])([^'"\s]+\/SKILL\.md)(?=$|['"\s])/g)) {
1066
+ if (m[1])
1067
+ paths.add(m[1]);
1068
+ }
1069
+ return [...paths].map(skillNameFromPath).filter((s) => s !== null);
1070
+ }
1050
1071
  return [];
1051
1072
  }
1052
1073
 
@@ -1131,13 +1152,6 @@ function isRecentEntry(entry, since) {
1131
1152
  }
1132
1153
 
1133
1154
  // src/readers/claude.ts
1134
- function extractSkills(entry, mode) {
1135
- if (mode === "attributed")
1136
- return extractAttributed(entry);
1137
- if (mode === "activations")
1138
- return extractClaudeActivations(entry);
1139
- return extractClaudeMentions(entry);
1140
- }
1141
1155
  function readClaudeUsage(options) {
1142
1156
  const root = expandHome(options.root ?? "~/.claude/projects");
1143
1157
  const counts = new Map;
@@ -1146,6 +1160,9 @@ function readClaudeUsage(options) {
1146
1160
  const since = options.scanAllFiles ? undefined : options.since;
1147
1161
  for (const file of findJsonlFiles(root, since)) {
1148
1162
  filesRead++;
1163
+ let prevSkill = null;
1164
+ const sessionAttr = new Map;
1165
+ const sessionAct = new Map;
1149
1166
  for (const line of readFileSync5(file, "utf8").split(`
1150
1167
  `)) {
1151
1168
  if (!line.trim())
@@ -1159,8 +1176,37 @@ function readClaudeUsage(options) {
1159
1176
  }
1160
1177
  if (!isRecentEntry(entry, options.since))
1161
1178
  continue;
1162
- for (const skill of extractSkills(entry, options.mode)) {
1163
- counts.set(skill, (counts.get(skill) ?? 0) + 1);
1179
+ if (options.mode === "attributed" || options.mode === "merged") {
1180
+ const cur = extractAttributed(entry)[0];
1181
+ if (cur !== undefined) {
1182
+ if (cur !== prevSkill) {
1183
+ sessionAttr.set(cur, (sessionAttr.get(cur) ?? 0) + 1);
1184
+ }
1185
+ prevSkill = cur;
1186
+ }
1187
+ }
1188
+ if (options.mode === "activations" || options.mode === "merged") {
1189
+ for (const skill of extractClaudeActivations(entry)) {
1190
+ sessionAct.set(skill, (sessionAct.get(skill) ?? 0) + 1);
1191
+ }
1192
+ }
1193
+ if (options.mode === "mentions") {
1194
+ for (const skill of extractClaudeMentions(entry)) {
1195
+ counts.set(skill, (counts.get(skill) ?? 0) + 1);
1196
+ }
1197
+ }
1198
+ }
1199
+ if (options.mode === "attributed") {
1200
+ for (const [k, v] of sessionAttr)
1201
+ counts.set(k, (counts.get(k) ?? 0) + v);
1202
+ } else if (options.mode === "activations") {
1203
+ for (const [k, v] of sessionAct)
1204
+ counts.set(k, (counts.get(k) ?? 0) + v);
1205
+ } else if (options.mode === "merged") {
1206
+ const keys = new Set([...sessionAttr.keys(), ...sessionAct.keys()]);
1207
+ for (const k of keys) {
1208
+ const merged = Math.max(sessionAttr.get(k) ?? 0, sessionAct.get(k) ?? 0);
1209
+ counts.set(k, (counts.get(k) ?? 0) + merged);
1164
1210
  }
1165
1211
  }
1166
1212
  }
@@ -1345,7 +1391,10 @@ var usageArgs = {
1345
1391
  description: "30sec, 5min, 12h, 7d, 2w, 1m, 1y, all"
1346
1392
  },
1347
1393
  since: { type: "string", description: "yyyy-mm-dd, overrides --period" },
1348
- mode: { type: "string", description: "attributed | activations | mentions" },
1394
+ mode: {
1395
+ type: "string",
1396
+ description: "merged (default for claude-code) | attributed | activations | mentions"
1397
+ },
1349
1398
  format: { type: "string", default: "text", description: "text | json" },
1350
1399
  root: { type: "string", description: "Override agent sessions directory; implies global" },
1351
1400
  "scan-all-files": { type: "boolean", default: false, description: "Ignore file mtime" },
@@ -1385,7 +1434,7 @@ async function runUsage(args) {
1385
1434
  let stats;
1386
1435
  let mode;
1387
1436
  if (agent === "claude-code") {
1388
- mode = args.mode ?? "attributed";
1437
+ mode = args.mode ?? "merged";
1389
1438
  const result = claudeRootMissing ? { counts: new Map, filesRead: 0, linesRead: 0 } : readClaudeUsage({ since, mode, root: claudeRoot, scanAllFiles });
1390
1439
  counts = result.counts;
1391
1440
  stats = { filesRead: result.filesRead, linesRead: result.linesRead };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillio",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Audit and manage AI agent skills for Claude Code and Codex",
5
5
  "license": "MIT",
6
6
  "author": "ihororlovskyi",