@crafter/skillkit 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,14 +99,13 @@ All data stays on your machine. No telemetry. No signup.
99
99
 
100
100
  ## Supported Agents
101
101
 
102
- Works with any agent that logs tool use in JSONL session files:
103
-
104
- - Claude Code
105
- - Cursor
106
- - Codex
107
- - VS Code (via extensions)
108
- - Windsurf
109
- - Gemini CLI
102
+ Scans skill directories for 15+ agents automatically:
103
+
104
+ - Claude Code, Cursor, Codex, Windsurf, Gemini CLI
105
+ - Cline, Roo Code, Continue, OpenCode, GitHub Copilot
106
+ - OpenHands, Amp, Goose, Kilo Code, Trae
107
+
108
+ Skills installed via [skills.sh](https://skills.sh) symlinks are deduplicated across agents.
110
109
 
111
110
  ## License
112
111
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crafter/skillkit",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Local-first analytics for AI agent skills. Track usage, measure context budget, and prune what you don't use.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/bin.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import { bold, cyan, dim, yellow } from "./tui/colors";
3
3
 
4
- const VERSION = "0.1.4";
4
+ const VERSION = "0.1.5";
5
5
 
6
6
  function printHelp(): void {
7
7
  console.log(`
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { getTopSkills } from "../db/queries";
5
5
  import { getDb } from "../db/schema";
6
- import { scanInstalledSkills } from "../scanner/skills";
6
+ import { getDetectedAgents, scanInstalledSkills } from "../scanner/skills";
7
7
  import { bold, dim, green, red, yellow } from "../tui/colors";
8
8
 
9
9
  const METADATA_BUDGET = 16000;
@@ -114,7 +114,9 @@ export async function runHealth(): Promise<void> {
114
114
 
115
115
  console.log(`\n ${bold("SKILLKIT HEALTH REPORT")}\n`);
116
116
 
117
- console.log(check(`${skills.length} skills installed`));
117
+ const agents = getDetectedAgents();
118
+ console.log(check(`${skills.length} skills across ${agents.length} agents`));
119
+ console.log(dim(` ${agents.join(", ")}`));
118
120
 
119
121
  if (dbExists && hasDbData) {
120
122
  console.log(
@@ -16,10 +16,15 @@ export function runList(): void {
16
16
  const skills = scanInstalledSkills();
17
17
 
18
18
  if (skills.length === 0) {
19
- console.log("\n No skills installed in ~/.claude/skills/\n");
19
+ console.log("\n No skills found.\n");
20
20
  return;
21
21
  }
22
22
 
23
+ const agentCounts = new Map<string, number>();
24
+ for (const s of skills) {
25
+ agentCounts.set(s.agent, (agentCounts.get(s.agent) ?? 0) + 1);
26
+ }
27
+
23
28
  const totalSize = skills.reduce((acc, s) => acc + s.size, 0);
24
29
 
25
30
  console.log(`\n ${bold(`INSTALLED SKILLS (${skills.length})`)}\n`);
@@ -40,7 +45,10 @@ export function runList(): void {
40
45
  console.log(` ${name}${desc}${size}`);
41
46
  }
42
47
 
48
+ const agentSummary = [...agentCounts.entries()]
49
+ .map(([a, c]) => `${a} (${c})`)
50
+ .join(", ");
43
51
  console.log(
44
- `\n ${dim(`Total: ${skills.length} skills | ${formatSize(totalSize)} context budget`)}\n`,
52
+ `\n ${dim(`Total: ${skills.length} skills | ${formatSize(totalSize)} | ${agentSummary}`)}\n`,
45
53
  );
46
54
  }
@@ -4,7 +4,7 @@ import { join } from "node:path";
4
4
  import { upsertInstalledSkill } from "../db/queries";
5
5
  import { getDb } from "../db/schema";
6
6
  import { scanAllSessions } from "../scanner/index";
7
- import { scanInstalledSkills } from "../scanner/skills";
7
+ import { getDetectedAgents, scanInstalledSkills } from "../scanner/skills";
8
8
  import { bold, cyan, dim } from "../tui/colors";
9
9
 
10
10
  function detectSource(skillPath: string): "skills.sh" | "manual" {
@@ -37,7 +37,12 @@ function countSessions(): number {
37
37
  export async function runScan(): Promise<void> {
38
38
  const db = getDb();
39
39
 
40
- console.log(`\n ${dim("Scanning ~/.claude/skills/ ...")}`);
40
+ const agents = getDetectedAgents();
41
+ if (agents.length === 0) {
42
+ console.log(`\n ${dim("No agent skill directories found.")}\n`);
43
+ return;
44
+ }
45
+ console.log(`\n ${dim(`Scanning ${agents.length} agents: ${agents.join(", ")}`)}`);
41
46
 
42
47
  const skills = scanInstalledSkills();
43
48
 
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ export {
13
13
  } from "./db/queries";
14
14
  export { getDb } from "./db/schema";
15
15
  export { parseSessionFile, scanAllSessions } from "./scanner/index";
16
- export { scanInstalledSkills } from "./scanner/skills";
16
+ export { getDetectedAgents, scanInstalledSkills } from "./scanner/skills";
17
17
  export type {
18
18
  InstalledSkill,
19
19
  SkillInvocation,
@@ -3,6 +3,24 @@ import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import type { InstalledSkill } from "../types";
5
5
 
6
+ const AGENT_SKILL_PATHS: Array<{ agent: string; dir: string }> = [
7
+ { agent: "Claude Code", dir: join(homedir(), ".claude", "skills") },
8
+ { agent: "Cursor", dir: join(homedir(), ".cursor", "skills") },
9
+ { agent: "Codex", dir: join(homedir(), ".codex", "skills") },
10
+ { agent: "Windsurf", dir: join(homedir(), ".codeium", "windsurf", "skills") },
11
+ { agent: "Gemini CLI", dir: join(homedir(), ".gemini", "skills") },
12
+ { agent: "Cline", dir: join(homedir(), ".cline", "skills") },
13
+ { agent: "Roo Code", dir: join(homedir(), ".roo", "skills") },
14
+ { agent: "Continue", dir: join(homedir(), ".continue", "skills") },
15
+ { agent: "OpenCode", dir: join(homedir(), ".config", "opencode", "skills") },
16
+ { agent: "GitHub Copilot", dir: join(homedir(), ".copilot", "skills") },
17
+ { agent: "OpenHands", dir: join(homedir(), ".openhands", "skills") },
18
+ { agent: "Amp", dir: join(homedir(), ".config", "agents", "skills") },
19
+ { agent: "Goose", dir: join(homedir(), ".config", "goose", "skills") },
20
+ { agent: "Kilo Code", dir: join(homedir(), ".kilocode", "skills") },
21
+ { agent: "Trae", dir: join(homedir(), ".trae", "skills") },
22
+ ];
23
+
6
24
  function parseYamlFrontmatter(content: string): Record<string, string> {
7
25
  const match = content.match(/^---\n([\s\S]*?)\n---/);
8
26
  if (!match || !match[1]) return {};
@@ -38,12 +56,13 @@ function getDirSize(dirPath: string): number {
38
56
  return total;
39
57
  }
40
58
 
41
- export function scanInstalledSkills(): InstalledSkill[] {
42
- const skillsDir = join(homedir(), ".claude", "skills");
59
+ function scanSkillsDir(
60
+ skillsDir: string,
61
+ agent: string,
62
+ ): InstalledSkill[] {
43
63
  if (!existsSync(skillsDir)) return [];
44
64
 
45
65
  const skills: InstalledSkill[] = [];
46
-
47
66
  let entries: string[];
48
67
  try {
49
68
  entries = readdirSync(skillsDir);
@@ -95,8 +114,37 @@ export function scanInstalledSkills(): InstalledSkill[] {
95
114
  description,
96
115
  size,
97
116
  installedAt: new Date(stat.birthtime).toISOString(),
117
+ agent,
98
118
  });
99
119
  }
100
120
 
101
- return skills.sort((a, b) => a.name.localeCompare(b.name));
121
+ return skills;
122
+ }
123
+
124
+ export function scanInstalledSkills(): InstalledSkill[] {
125
+ const allSkills: InstalledSkill[] = [];
126
+ const seen = new Set<string>();
127
+
128
+ for (const { agent, dir } of AGENT_SKILL_PATHS) {
129
+ const skills = scanSkillsDir(dir, agent);
130
+ for (const skill of skills) {
131
+ try {
132
+ const ino = statSync(skill.path).ino;
133
+ const key = `${ino}`;
134
+ if (seen.has(key)) continue;
135
+ seen.add(key);
136
+ } catch {}
137
+ allSkills.push(skill);
138
+ }
139
+ }
140
+
141
+ return allSkills.sort((a, b) => a.name.localeCompare(b.name));
142
+ }
143
+
144
+ export function getDetectedAgents(): string[] {
145
+ const agents: string[] = [];
146
+ for (const { agent, dir } of AGENT_SKILL_PATHS) {
147
+ if (existsSync(dir)) agents.push(agent);
148
+ }
149
+ return agents;
102
150
  }
@@ -4,6 +4,7 @@ export interface InstalledSkill {
4
4
  description: string;
5
5
  size: number;
6
6
  installedAt: string;
7
+ agent: string;
7
8
  }
8
9
 
9
10
  export interface SkillInvocation {