skilldotmd 0.1.0 → 0.1.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 (3) hide show
  1. package/bun.lock +68 -0
  2. package/package.json +5 -5
  3. package/src/index.js +84 -18
package/bun.lock ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 0,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "skilldotmd",
7
+ "dependencies": {
8
+ "@clack/prompts": "^1.2.0",
9
+ "commander": "^12.0.0",
10
+ "ora": "^8.0.0",
11
+ "picocolors": "^1.1.1",
12
+ },
13
+ },
14
+ },
15
+ "packages": {
16
+ "@clack/core": ["@clack/core@1.2.0", "", { "dependencies": { "fast-wrap-ansi": "^0.1.3", "sisteransi": "^1.0.5" } }, "sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg=="],
17
+
18
+ "@clack/prompts": ["@clack/prompts@1.2.0", "", { "dependencies": { "@clack/core": "1.2.0", "fast-string-width": "^1.1.0", "fast-wrap-ansi": "^0.1.3", "sisteransi": "^1.0.5" } }, "sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w=="],
19
+
20
+ "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
21
+
22
+ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
23
+
24
+ "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
25
+
26
+ "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
27
+
28
+ "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
29
+
30
+ "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
31
+
32
+ "fast-string-truncated-width": ["fast-string-truncated-width@1.2.1", "", {}, "sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow=="],
33
+
34
+ "fast-string-width": ["fast-string-width@1.1.0", "", { "dependencies": { "fast-string-truncated-width": "^1.2.0" } }, "sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ=="],
35
+
36
+ "fast-wrap-ansi": ["fast-wrap-ansi@0.1.6", "", { "dependencies": { "fast-string-width": "^1.1.0" } }, "sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w=="],
37
+
38
+ "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],
39
+
40
+ "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
41
+
42
+ "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
43
+
44
+ "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
45
+
46
+ "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
47
+
48
+ "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
49
+
50
+ "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
51
+
52
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
53
+
54
+ "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
55
+
56
+ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
57
+
58
+ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
59
+
60
+ "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
61
+
62
+ "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
63
+
64
+ "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
65
+
66
+ "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
67
+ }
68
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "skilldotmd",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Teach your AI any library. Install skills for Claude Code, Cursor, Windsurf and more.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "skilldotmd": "src/index.js"
7
+ "skilldotmd": "./src/index.js"
8
8
  },
9
9
  "keywords": [
10
10
  "claude",
@@ -17,10 +17,10 @@
17
17
  "author": "imPiyushkashyap",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@clack/prompts": "^0.7.0",
20
+ "@clack/prompts": "^1.2.0",
21
21
  "commander": "^12.0.0",
22
- "picocolors": "^1.0.0",
23
- "ora": "^8.0.0"
22
+ "ora": "^8.0.0",
23
+ "picocolors": "^1.1.1"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=18.0.0"
package/src/index.js CHANGED
@@ -1,13 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { intro, outro, select, text, spinner } from "@clack/prompts"
3
+ import {
4
+ intro,
5
+ outro,
6
+ select,
7
+ text,
8
+ spinner,
9
+ isCancel,
10
+ cancel,
11
+ } from "@clack/prompts"
4
12
  import { Command } from "commander"
5
13
  import pc from "picocolors"
6
- import { execSync } from "child_process"
7
14
  import fs from "fs"
8
15
  import path from "path"
9
16
 
10
- const VERSION = "0.1.0"
17
+ const VERSION = "0.2.0"
11
18
 
12
19
  const TOOLS = {
13
20
  claude: { label: "Claude Code", projectPath: ".claude/skills" },
@@ -34,6 +41,34 @@ function detectTool() {
34
41
  return null
35
42
  }
36
43
 
44
+ function parseSkillPath(input) {
45
+ const parts = input.split("/")
46
+ if (parts.length < 3) return null
47
+ const owner = parts[0]
48
+ const repo = parts[1]
49
+ const skillPath = parts.slice(2).join("/")
50
+ const skillName = parts[parts.length - 1]
51
+ return { owner, repo, skillPath, skillName }
52
+ }
53
+
54
+ async function downloadSkill(parsed) {
55
+ const branches = ["main", "master"]
56
+ for (const branch of branches) {
57
+ const url = `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/${branch}/${parsed.skillPath}/SKILL.md`
58
+ const res = await fetch(url)
59
+ if (res.ok) return await res.text()
60
+ }
61
+ throw new Error(`Skill not found at ${parsed.owner}/${parsed.repo}/${parsed.skillPath}`)
62
+ }
63
+
64
+ function installSkill(tool, skillName, content) {
65
+ const cwd = process.cwd()
66
+ const targetDir = path.join(cwd, TOOLS[tool].projectPath, skillName)
67
+ fs.mkdirSync(targetDir, { recursive: true })
68
+ fs.writeFileSync(path.join(targetDir, "SKILL.md"), content)
69
+ return targetDir
70
+ }
71
+
37
72
  const program = new Command()
38
73
 
39
74
  program
@@ -47,26 +82,38 @@ program
47
82
  .option("--for <tool>", "AI tool to install for")
48
83
  .action(async (skill, options) => {
49
84
  printBanner()
50
- intro(pc.bold("Add a skill"))
85
+ intro(pc.bold(pc.cyan("SkillDotMD — Add Skill")))
51
86
 
52
- let skillPath = skill
87
+ let skillInput = skill
53
88
 
54
- if (!skillPath) {
55
- skillPath = await text({
56
- message: "Which skill do you want to install?",
57
- placeholder: "imPiyushkashyap/SkillDotMD-Library/groq",
89
+ if (!skillInput) {
90
+ skillInput = await text({
91
+ message: "Enter skill path (GitHub)",
92
+ placeholder: "owner/repo/path/to/skill",
58
93
  validate(value) {
59
94
  if (!value) return "Please enter a skill path"
60
95
  },
61
96
  })
62
- if (typeof skillPath === "symbol") process.exit(0)
97
+
98
+ if (isCancel(skillInput)) {
99
+ cancel("Operation cancelled.")
100
+ process.exit(0)
101
+ }
102
+ }
103
+
104
+ const parsed = parseSkillPath(skillInput)
105
+ if (!parsed) {
106
+ outro(pc.red("✗ Invalid format\nExpected: owner/repo/path/to/skill"))
107
+ process.exit(1)
63
108
  }
64
109
 
65
110
  let tool = options.for
111
+
66
112
  if (!tool) {
67
113
  const detected = detectTool()
114
+
68
115
  tool = await select({
69
- message: "Which AI tool are you using?",
116
+ message: "Select your AI tool",
70
117
  options: Object.entries(TOOLS).map(([value, config]) => ({
71
118
  value,
72
119
  label: config.label,
@@ -74,21 +121,33 @@ program
74
121
  })),
75
122
  initialValue: detected || "claude",
76
123
  })
77
- if (typeof tool === "symbol") process.exit(0)
124
+
125
+ if (isCancel(tool)) {
126
+ cancel("Operation cancelled.")
127
+ process.exit(0)
128
+ }
78
129
  }
79
130
 
80
131
  const s = spinner()
81
- s.start(`Installing ${pc.cyan(skillPath)}`)
132
+ s.start(`Fetching ${pc.cyan(parsed.skillName)}...`)
82
133
 
83
134
  try {
84
- execSync(`npx skills add ${skillPath}`, { stdio: "pipe" })
85
- s.stop(`${pc.green("✓")} Installed ${pc.cyan(skillPath)}`)
135
+ const content = await downloadSkill(parsed)
136
+ const installDir = installSkill(tool, parsed.skillName, content)
137
+
138
+ s.stop(`${pc.green("✓")} Installed ${pc.cyan(parsed.skillName)}`)
139
+
140
+ console.log("")
141
+ console.log(pc.bold("Next steps:"))
142
+ console.log(pc.dim("• Restart your editor"))
143
+ console.log(pc.dim("• Start using the skill"))
144
+ console.log(pc.dim(`• Installed at: ${installDir}`))
86
145
  } catch (err) {
87
- s.stop(`${pc.red("✗")} Failed to install skill`)
146
+ s.stop(`${pc.red("✗")} ${err.message}`)
88
147
  process.exit(1)
89
148
  }
90
149
 
91
- outro(`${pc.green("")} Your AI now knows this skill. Restart your editor to use it.`)
150
+ outro(pc.green("Done 🚀"))
92
151
  })
93
152
 
94
153
  program
@@ -97,14 +156,18 @@ program
97
156
  .action(() => {
98
157
  printBanner()
99
158
  intro(pc.bold("Installed skills"))
159
+
100
160
  const cwd = process.cwd()
101
161
  let found = false
162
+
102
163
  for (const [, config] of Object.entries(TOOLS)) {
103
164
  const dir = path.join(cwd, config.projectPath)
165
+
104
166
  if (fs.existsSync(dir)) {
105
167
  const skills = fs.readdirSync(dir).filter(f =>
106
168
  fs.statSync(path.join(dir, f)).isDirectory()
107
169
  )
170
+
108
171
  if (skills.length > 0) {
109
172
  found = true
110
173
  console.log(`\n ${pc.bold(config.label)}`)
@@ -112,11 +175,14 @@ program
112
175
  }
113
176
  }
114
177
  }
178
+
115
179
  if (!found) {
116
180
  console.log(pc.dim("\n No skills installed."))
181
+ console.log(pc.dim(" Run `skilldotmd add` to install one."))
117
182
  }
183
+
118
184
  console.log("")
119
185
  outro("Done")
120
186
  })
121
187
 
122
- program.parse()
188
+ program.parse()