learn-skill.md 1.0.3 → 1.0.4

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/bin/cli.mjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { parseArgs } from 'node:util'
4
4
  import { add } from '../src/install.mjs'
5
+ import { addPack } from '../src/install-pack.mjs'
5
6
  import { search, list } from '../src/search.mjs'
6
7
  import { AGENTS, detectAgents } from '../src/agents.mjs'
7
8
 
@@ -17,6 +18,7 @@ const HELP = `${BANNER}
17
18
  usage:
18
19
  learn-skill-md add <slug> install a skill
19
20
  learn-skill-md add <slug> -a claude install to a specific agent
21
+ learn-skill-md add-pack <slug> install a skill pack
20
22
  learn-skill-md search <query> search for skills
21
23
  learn-skill-md list list recent skills
22
24
  learn-skill-md agents show supported agents
@@ -46,7 +48,7 @@ const { values, positionals } = parseArgs({
46
48
  const [command, ...args] = positionals
47
49
 
48
50
  if (values.version) {
49
- console.log('learn-skill-md v1.0.3')
51
+ console.log('learn-skill-md v1.0.4')
50
52
  process.exit(0)
51
53
  }
52
54
 
@@ -67,6 +69,16 @@ async function main() {
67
69
  await add(slug, { agent: values.agent, yes: values.yes })
68
70
  break
69
71
  }
72
+ case 'add-pack':
73
+ case 'install-pack': {
74
+ const slug = args[0]
75
+ if (!slug) {
76
+ console.error(' error: missing pack slug\n usage: learn-skill-md add-pack <slug>')
77
+ process.exit(1)
78
+ }
79
+ await addPack(slug, { agent: values.agent, yes: values.yes })
80
+ break
81
+ }
70
82
  case 'search':
71
83
  case 'find': {
72
84
  const query = args.join(' ')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "learn-skill.md",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Install AI agent skills from learn-skill.md — the skill marketplace for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.mjs CHANGED
@@ -25,3 +25,7 @@ export function rawUrl(slug) {
25
25
  export function installUrl(slug) {
26
26
  return `${BASE_URL}/install/${slug}`
27
27
  }
28
+
29
+ export function installPackUrl(slug) {
30
+ return `${BASE_URL}/install/pack/${slug}`
31
+ }
@@ -0,0 +1,104 @@
1
+ import { mkdirSync, createWriteStream } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+ import { tmpdir } from 'node:os'
5
+ import { pipeline } from 'node:stream/promises'
6
+ import { Readable } from 'node:stream'
7
+
8
+ import { AGENTS, detectAgents, getAgent, getSkillDir } from './agents.mjs'
9
+ import { get, installPackUrl } from './api.mjs'
10
+ import { chooseMultiple, confirm } from './prompt.mjs'
11
+
12
+ export async function addPack(slug, opts = {}) {
13
+ // 1. fetch pack metadata
14
+ console.log(`\n fetching pack: ${slug}...`)
15
+ const data = await get(`/api/packs/${slug}`)
16
+ const pack = data.pack
17
+
18
+ if (!pack) {
19
+ throw new Error(`pack "${slug}" not found`)
20
+ }
21
+
22
+ console.log(` found: ${pack.name}`)
23
+ if (pack.description) console.log(` ${pack.description}`)
24
+ console.log(` skills: ${pack.skills.length}`)
25
+ for (const s of pack.skills) {
26
+ console.log(` - ${s.slug}: ${s.title}`)
27
+ }
28
+
29
+ // 2. pick agent(s)
30
+ let agents = []
31
+
32
+ if (opts.agent) {
33
+ const agent = getAgent(opts.agent)
34
+ if (!agent) {
35
+ throw new Error(
36
+ `unknown agent "${opts.agent}". supported: ${AGENTS.map((a) => a.id).join(', ')}`
37
+ )
38
+ }
39
+ agents = [agent]
40
+ } else {
41
+ const detected = detectAgents()
42
+ const agentOptions = AGENTS.map((a) => ({
43
+ label: `${a.name}${detected.includes(a.id) ? ' (detected)' : ''}`,
44
+ value: a,
45
+ }))
46
+
47
+ const selected = await chooseMultiple('install to which agent(s)?', agentOptions)
48
+ agents = selected.map((s) => s.value)
49
+ }
50
+
51
+ if (agents.length === 0) {
52
+ console.log(' no agents selected, aborting.')
53
+ return
54
+ }
55
+
56
+ // 3. confirm
57
+ if (!opts.yes) {
58
+ console.log('\n will install to:')
59
+ for (const a of agents) {
60
+ console.log(` - ${a.name} (${getSkillDir(a)})`)
61
+ }
62
+ const ok = await confirm('proceed?')
63
+ if (!ok) {
64
+ console.log(' cancelled.')
65
+ return
66
+ }
67
+ }
68
+
69
+ // 4. download tar.gz to temp
70
+ console.log('\n downloading pack...')
71
+ const url = installPackUrl(slug)
72
+ const res = await fetch(url)
73
+ if (!res.ok) {
74
+ throw new Error(`download failed: ${res.status}`)
75
+ }
76
+
77
+ const tmpFile = join(tmpdir(), `learn-skill-pack-${slug}-${Date.now()}.tar.gz`)
78
+ const fileStream = createWriteStream(tmpFile)
79
+ await pipeline(Readable.fromWeb(res.body), fileStream)
80
+
81
+ // 5. extract to each agent's skill dir
82
+ for (const agent of agents) {
83
+ const skillDir = getSkillDir(agent)
84
+ mkdirSync(skillDir, { recursive: true })
85
+
86
+ console.log(` installing to ${agent.name}...`)
87
+ try {
88
+ execSync(`tar -xzf "${tmpFile}" -C "${skillDir}"`, { stdio: 'pipe' })
89
+ for (const s of pack.skills) {
90
+ console.log(` ${skillDir}/${s.slug}/`)
91
+ }
92
+ } catch (err) {
93
+ console.error(` failed to extract to ${agent.name}: ${err.message}`)
94
+ }
95
+ }
96
+
97
+ // 6. cleanup
98
+ try {
99
+ const { unlinkSync } = await import('node:fs')
100
+ unlinkSync(tmpFile)
101
+ } catch {}
102
+
103
+ console.log(`\n pack "${pack.name}" (${pack.skills.length} skills) installed successfully!\n`)
104
+ }