skills-agents 0.1.0

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/README.md +43 -0
  2. package/bin.mjs +221 -0
  3. package/package.json +32 -0
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # skills-agents
2
+
3
+ One command for both halves of an agent-capability catalog: **skills**
4
+ (`SKILL.md` — read by Claude Code, Codex, and Cursor) and **subagents**
5
+ (`AGENT.md` — read by Claude Code). Works anywhere Node does, Windows
6
+ included.
7
+
8
+ ```sh
9
+ # a whole build stage — every skill AND agent in it
10
+ npx skills-agents add https://docs.codehance.com/stage/start -g -y
11
+
12
+ # one subagent
13
+ npx skills-agents add https://docs.codehance.com --agent idea-researcher -g
14
+
15
+ # one skill, pinned to a tool
16
+ npx skills-agents add https://docs.codehance.com --skill idea -g --tool claude-code
17
+ ```
18
+
19
+ ## How it works
20
+
21
+ A **source** is any URL serving the standard well-known indexes:
22
+ `/.well-known/skills/index.json` and/or `/.well-known/agents/index.json`.
23
+
24
+ - **Skills** are delegated to the [`skills`](https://www.npmjs.com/package/skills)
25
+ CLI, so multi-tool targeting (Claude Code, Codex, Cursor), lockfiles, and
26
+ `npx skills update` all keep working.
27
+ - **Subagents** are downloaded into the agents folder —
28
+ `~/.claude/agents/` with `-g`, `./.claude/agents/` without. Subagents are
29
+ currently a Claude Code concept; other tools get them when they support
30
+ subagent definitions.
31
+
32
+ ## Flags
33
+
34
+ | Flag | Meaning |
35
+ | --- | --- |
36
+ | `-g, --global` | Install at user level (available in every project) |
37
+ | `-y, --yes` | Skip confirmation prompts |
38
+ | `--skill <name>` | Install only this skill (repeatable) |
39
+ | `--agent <name>` | Install only this subagent (repeatable) |
40
+ | `--tool <tool>` | Target tool(s) for skills: `claude-code`, `codex`, `cursor` (default: auto-detect) |
41
+
42
+ With no `--skill`/`--agent`, everything the source lists is installed —
43
+ that's what makes stage sources one-command.
package/bin.mjs ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+ // skills-agents — one command for both halves of a well-known source:
3
+ // skills (SKILL.md, installed via the `skills` CLI so Claude Code, Codex,
4
+ // and Cursor targeting keeps working) and subagents (AGENT.md, downloaded
5
+ // into the agents folder — currently a Claude Code concept).
6
+ //
7
+ // npx skills-agents add <source> [flags]
8
+ //
9
+ // A source is any site serving /.well-known/skills/index.json and/or
10
+ // /.well-known/agents/index.json (e.g. https://docs.codehance.com or a
11
+ // stage source like https://docs.codehance.com/stage/start).
12
+
13
+ import { spawnSync } from 'node:child_process'
14
+ import { mkdirSync, writeFileSync } from 'node:fs'
15
+ import { homedir } from 'node:os'
16
+ import { join } from 'node:path'
17
+
18
+ const VERSION = '0.1.0'
19
+
20
+ const HELP = `skills-agents ${VERSION} — install skills and subagents from a well-known source
21
+
22
+ Usage:
23
+ npx skills-agents add <source> [flags]
24
+
25
+ Source:
26
+ Any URL serving /.well-known/skills/index.json and/or
27
+ /.well-known/agents/index.json, e.g.
28
+ https://docs.codehance.com (whole catalog)
29
+ https://docs.codehance.com/stage/start (one build stage)
30
+
31
+ Flags:
32
+ -g, --global Install at user level (works in every project)
33
+ -y, --yes Skip confirmation prompts
34
+ --skill <name> Install only this skill (repeatable)
35
+ --agent <name> Install only this subagent (repeatable)
36
+ --tool <tool> Target coding tool(s) for skills: claude-code, codex,
37
+ cursor (repeatable; default: auto-detect). Subagents
38
+ are currently Claude Code-only.
39
+ -h, --help Show this help
40
+ -v, --version Show version
41
+
42
+ Examples:
43
+ npx skills-agents add https://docs.codehance.com/stage/start -g -y
44
+ npx skills-agents add https://docs.codehance.com --agent idea-researcher -g
45
+ npx skills-agents add https://docs.codehance.com --skill idea -g --tool claude-code
46
+ `
47
+
48
+ function fail(message) {
49
+ console.error(`skills-agents: ${message}`)
50
+ process.exit(1)
51
+ }
52
+
53
+ function parseArgs(argv) {
54
+ const opts = {
55
+ command: null,
56
+ source: null,
57
+ global: false,
58
+ yes: false,
59
+ skills: [],
60
+ agents: [],
61
+ tools: [],
62
+ }
63
+ const takeValue = (flag, i) => {
64
+ if (i + 1 >= argv.length) fail(`${flag} needs a value`)
65
+ return argv[i + 1]
66
+ }
67
+ for (let i = 0; i < argv.length; i++) {
68
+ const arg = argv[i]
69
+ switch (arg) {
70
+ case '-h':
71
+ case '--help':
72
+ console.log(HELP)
73
+ process.exit(0)
74
+ case '-v':
75
+ case '--version':
76
+ console.log(VERSION)
77
+ process.exit(0)
78
+ case '-g':
79
+ case '--global':
80
+ opts.global = true
81
+ break
82
+ case '-y':
83
+ case '--yes':
84
+ opts.yes = true
85
+ break
86
+ case '--skill':
87
+ opts.skills.push(takeValue(arg, i))
88
+ i++
89
+ break
90
+ case '--agent':
91
+ opts.agents.push(takeValue(arg, i))
92
+ i++
93
+ break
94
+ case '--tool':
95
+ opts.tools.push(takeValue(arg, i))
96
+ i++
97
+ break
98
+ default:
99
+ if (arg.startsWith('-')) fail(`unknown flag '${arg}' (see --help)`)
100
+ if (!opts.command) opts.command = arg
101
+ else if (!opts.source) opts.source = arg
102
+ else fail(`unexpected argument '${arg}'`)
103
+ }
104
+ }
105
+ return opts
106
+ }
107
+
108
+ async function fetchIndex(source, kind) {
109
+ const url = `${source.replace(/\/$/, '')}/.well-known/${kind}/index.json`
110
+ let res
111
+ try {
112
+ res = await fetch(url)
113
+ } catch (err) {
114
+ fail(`could not reach ${url} (${err.message})`)
115
+ }
116
+ if (res.status === 404) return null // source has no <kind> half — fine
117
+ if (!res.ok) fail(`${url} responded ${res.status}`)
118
+ try {
119
+ const body = await res.json()
120
+ const entries = body[kind]
121
+ return Array.isArray(entries) ? entries : null
122
+ } catch {
123
+ fail(`${url} is not a valid index`)
124
+ }
125
+ }
126
+
127
+ // Skills install delegates to the `skills` CLI — it already handles
128
+ // multi-tool targeting (Claude Code, Codex, Cursor), lockfiles, and
129
+ // updates. Its --agent flag means "target tool"; ours is --tool.
130
+ function installSkills(opts) {
131
+ const args = ['--yes', 'skills', 'add', opts.source]
132
+ for (const s of opts.skills) args.push('-s', s)
133
+ for (const t of opts.tools) args.push('--agent', t)
134
+ if (opts.global) args.push('-g')
135
+ if (opts.yes) args.push('-y')
136
+ const result = spawnSync('npx', args, {
137
+ stdio: 'inherit',
138
+ shell: process.platform === 'win32',
139
+ })
140
+ if (result.error) fail(`could not run the skills CLI: ${result.error.message}`)
141
+ return result.status ?? 1
142
+ }
143
+
144
+ async function installAgents(opts, entries) {
145
+ const wanted = opts.agents.length
146
+ ? entries.filter((e) => opts.agents.includes(e.name))
147
+ : entries
148
+ if (opts.agents.length) {
149
+ const found = new Set(wanted.map((e) => e.name))
150
+ const missing = opts.agents.filter((n) => !found.has(n))
151
+ if (missing.length) {
152
+ fail(
153
+ `agent${missing.length > 1 ? 's' : ''} not found at this source: ${missing.join(', ')}\n` +
154
+ `available: ${entries.map((e) => e.name).join(', ') || '(none)'}`
155
+ )
156
+ }
157
+ }
158
+ if (!wanted.length) return
159
+
160
+ // Subagents are a Claude Code concept today; other tools get them when
161
+ // they support subagent definitions.
162
+ if (opts.tools.length && !opts.tools.includes('claude-code')) {
163
+ console.log('skills-agents: skipping subagents (only claude-code reads them)')
164
+ return
165
+ }
166
+
167
+ const dir = opts.global
168
+ ? join(homedir(), '.claude', 'agents')
169
+ : join('.claude', 'agents')
170
+ mkdirSync(dir, { recursive: true })
171
+
172
+ const base = opts.source.replace(/\/$/, '')
173
+ for (const entry of wanted) {
174
+ const file = entry.files?.[0] ?? 'AGENT.md'
175
+ const url = `${base}/.well-known/agents/${entry.name}/${file}`
176
+ const res = await fetch(url)
177
+ if (!res.ok) fail(`download failed (${res.status}): ${url}`)
178
+ const target = join(dir, `${entry.name}.md`)
179
+ writeFileSync(target, Buffer.from(await res.arrayBuffer()))
180
+ console.log(`✓ agent ${entry.name} → ${target}`)
181
+ }
182
+ }
183
+
184
+ async function main() {
185
+ const opts = parseArgs(process.argv.slice(2))
186
+ if (!opts.command) {
187
+ console.log(HELP)
188
+ process.exit(1)
189
+ }
190
+ if (opts.command !== 'add') fail(`unknown command '${opts.command}' (only 'add' is supported)`)
191
+ if (!opts.source) fail('add needs a source URL (see --help)')
192
+ if (!/^https?:\/\//.test(opts.source)) fail(`source must be an http(s) URL, got '${opts.source}'`)
193
+
194
+ // --skill only → skills half; --agent only → agents half; neither → both.
195
+ const wantSkills = opts.skills.length > 0 || opts.agents.length === 0
196
+ const wantAgents = opts.agents.length > 0 || opts.skills.length === 0
197
+
198
+ let exitCode = 0
199
+
200
+ if (wantSkills) {
201
+ const skillsIndex = await fetchIndex(opts.source, 'skills')
202
+ if (skillsIndex?.length) {
203
+ exitCode = installSkills(opts)
204
+ } else if (opts.skills.length) {
205
+ fail('this source lists no skills')
206
+ }
207
+ }
208
+
209
+ if (wantAgents && exitCode === 0) {
210
+ const agentsIndex = await fetchIndex(opts.source, 'agents')
211
+ if (agentsIndex?.length) {
212
+ await installAgents(opts, agentsIndex)
213
+ } else if (opts.agents.length) {
214
+ fail('this source lists no agents')
215
+ }
216
+ }
217
+
218
+ process.exit(exitCode)
219
+ }
220
+
221
+ main().catch((err) => fail(err.message))
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "skills-agents",
3
+ "version": "0.1.0",
4
+ "description": "Install agent skills (SKILL.md) and subagents (AGENT.md) from any well-known source with one command — skills for Claude Code, Codex, and Cursor via the skills CLI; subagents downloaded natively.",
5
+ "keywords": [
6
+ "skills",
7
+ "agents",
8
+ "subagents",
9
+ "claude-code",
10
+ "codex",
11
+ "cursor",
12
+ "agent-skills"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Codehance <claude@codehance.com>",
16
+ "homepage": "https://docs.codehance.com",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/CodehanceHQ/docs.git",
20
+ "directory": "cli"
21
+ },
22
+ "type": "module",
23
+ "bin": {
24
+ "skills-agents": "bin.mjs"
25
+ },
26
+ "files": [
27
+ "bin.mjs"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18.17"
31
+ }
32
+ }