harveyz-skill 0.3.0 → 0.5.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.
- package/README.md +18 -29
- package/bin/cli.js +96 -21
- package/lib/targets.js +20 -9
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Harvey 的个人 Claude Code 技能仓库。
|
|
|
4
4
|
|
|
5
5
|
## 技能清单
|
|
6
6
|
|
|
7
|
-
按 bundle 分组,`
|
|
7
|
+
按 bundle 分组,`hskill install --bundle <bundle>` 安装对应分组。
|
|
8
8
|
|
|
9
9
|
### analysis — 分析工具
|
|
10
10
|
|
|
@@ -63,7 +63,7 @@ Harvey 的个人 Claude Code 技能仓库。
|
|
|
63
63
|
|
|
64
64
|
## 工具清单
|
|
65
65
|
|
|
66
|
-
Shell 工具,通过 `
|
|
66
|
+
Shell 工具,通过 `hskill install --tool p-launch` 安装。
|
|
67
67
|
|
|
68
68
|
| 工具 | 说明 |
|
|
69
69
|
|------|------|
|
|
@@ -74,50 +74,39 @@ Shell 工具,通过 `npx harveyz-skill --bundle shell-tools` 安装。
|
|
|
74
74
|
|
|
75
75
|
## 安装
|
|
76
76
|
|
|
77
|
-
### 推荐:npx 一键安装
|
|
78
|
-
|
|
79
77
|
```bash
|
|
80
|
-
|
|
78
|
+
npm install -g harveyz-skill
|
|
81
79
|
```
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
安装后使用 `hskill` 命令管理 skills。
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
npx harveyz-skill --bundle brainstorming --target claude
|
|
88
|
-
npx harveyz-skill --bundle brainstorming,dev --target all
|
|
89
|
-
```
|
|
83
|
+
### 常用命令
|
|
90
84
|
|
|
91
|
-
**查看可用 bundle:**
|
|
92
85
|
```bash
|
|
93
|
-
|
|
86
|
+
hskill # 交互式选择安装
|
|
87
|
+
hskill install --bundle dev --target claude # 安装指定 bundle
|
|
88
|
+
hskill install --skill git-workflow-init # 安装指定 skill
|
|
89
|
+
hskill install --tool p-launch # 安装 shell 工具
|
|
90
|
+
hskill list # 查看可用 skill
|
|
91
|
+
hskill update # 更新到最新版
|
|
92
|
+
hskill --help # 查看帮助
|
|
94
93
|
```
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
Skills 安装到 `~/.claude/skills/`,shell 工具安装到 `~/.local/bin/`。
|
|
97
96
|
|
|
98
|
-
|
|
97
|
+
### 本地源码开发
|
|
99
98
|
|
|
100
99
|
```bash
|
|
101
|
-
# 交互式选择 bundle 和目标工具
|
|
102
|
-
node bin/cli.js
|
|
103
|
-
|
|
104
100
|
# 安装指定 skill
|
|
105
|
-
node bin/cli.js --skill mermaid-diagram --target claude
|
|
106
|
-
node bin/cli.js --skill brainstorming,writing-plans --target claude
|
|
107
|
-
|
|
108
|
-
# 安装整个 skill bundle
|
|
109
|
-
node bin/cli.js --bundle dev --target claude
|
|
101
|
+
node bin/cli.js install --skill mermaid-diagram --target claude
|
|
110
102
|
|
|
111
|
-
#
|
|
112
|
-
node bin/cli.js --
|
|
103
|
+
# 安装整个 bundle
|
|
104
|
+
node bin/cli.js install --bundle dev --target claude
|
|
113
105
|
|
|
114
106
|
# 覆盖已有安装
|
|
115
|
-
node bin/cli.js --skill mermaid-diagram --target claude --force
|
|
116
|
-
node bin/cli.js --tool p-launch --force
|
|
107
|
+
node bin/cli.js install --skill mermaid-diagram --target claude --force
|
|
117
108
|
```
|
|
118
109
|
|
|
119
|
-
Skills 安装到 `~/.claude/skills/`,shell 工具安装到 `~/.local/bin/`。
|
|
120
|
-
|
|
121
110
|
## Skill 开发指南
|
|
122
111
|
|
|
123
112
|
### 命名规范
|
package/bin/cli.js
CHANGED
|
@@ -1,29 +1,75 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { checkbox } from '@inquirer/prompts'
|
|
2
|
+
import { checkbox, select } from '@inquirer/prompts'
|
|
3
3
|
import chalk from 'chalk'
|
|
4
|
+
import { execSync } from 'child_process'
|
|
5
|
+
import { createRequire } from 'module'
|
|
4
6
|
import {
|
|
5
7
|
buildAllChoices, getAllSkillItems, getAllToolItems,
|
|
6
8
|
resolveSkills, resolveSkillsByName, resolveTools, resolveToolsByName,
|
|
7
9
|
TOOL_BUNDLE_CHOICES,
|
|
8
10
|
} from '../lib/bundles.js'
|
|
9
|
-
import {
|
|
11
|
+
import { buildTargetChoices, resolveTargets, TARGETS } from '../lib/targets.js'
|
|
10
12
|
import { installSkills, installTools } from '../lib/installer.js'
|
|
11
13
|
|
|
14
|
+
const require = createRequire(import.meta.url)
|
|
15
|
+
const { version } = require('../package.json')
|
|
16
|
+
|
|
12
17
|
const args = process.argv.slice(2)
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
const subcommand = args[0]
|
|
19
|
+
|
|
20
|
+
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
21
|
+
function printHelp() {
|
|
22
|
+
console.log(`
|
|
23
|
+
${chalk.bold('hskill')} — skill manager for Claude Code, Cursor, and Codex v${version}
|
|
24
|
+
|
|
25
|
+
${chalk.cyan('Usage:')}
|
|
26
|
+
hskill interactive install
|
|
27
|
+
hskill install interactive install (explicit)
|
|
28
|
+
hskill install --bundle <b> install a skill bundle
|
|
29
|
+
hskill install --skill <s> install specific skill(s)
|
|
30
|
+
hskill install --tool <t> install shell tool(s)
|
|
31
|
+
hskill install --target <t> set target (claude/cursor/codex/all)
|
|
32
|
+
hskill install --scope <s> set scope: user (default) or project
|
|
33
|
+
hskill install --force overwrite existing installs
|
|
34
|
+
hskill list list available skills and bundles
|
|
35
|
+
hskill update update hskill to the latest version
|
|
36
|
+
hskill --version show version
|
|
37
|
+
hskill --help show this help
|
|
38
|
+
|
|
39
|
+
${chalk.cyan('Examples:')}
|
|
40
|
+
hskill install --bundle dev --target claude
|
|
41
|
+
hskill install --skill git-workflow-init --target claude --scope project
|
|
42
|
+
hskill install --tool p-launch
|
|
43
|
+
hskill update
|
|
44
|
+
`)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (args[0] === '--help' || args[0] === '-h') {
|
|
48
|
+
printHelp()
|
|
49
|
+
process.exit(0)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (args[0] === '--version' || args[0] === '-v') {
|
|
53
|
+
console.log(version)
|
|
54
|
+
process.exit(0)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Update ───────────────────────────────────────────────────────────────────
|
|
58
|
+
if (subcommand === 'update') {
|
|
59
|
+
console.log(chalk.dim(' · Updating hskill…'))
|
|
60
|
+
try {
|
|
61
|
+
execSync('npm update -g harveyz-skill', { stdio: 'inherit' })
|
|
62
|
+
console.log(chalk.green(' ✔ hskill updated'))
|
|
63
|
+
} catch {
|
|
64
|
+
console.error(chalk.red(' ✗ Update failed. Try: npm update -g harveyz-skill'))
|
|
65
|
+
process.exit(1)
|
|
66
|
+
}
|
|
67
|
+
process.exit(0)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── List ─────────────────────────────────────────────────────────────────────
|
|
71
|
+
if (subcommand === 'list') {
|
|
72
|
+
const { bundleMeta, skills, tools = [] } = require('../skills-index.json')
|
|
27
73
|
const byBundle = {}
|
|
28
74
|
for (const s of skills) {
|
|
29
75
|
if (!byBundle[s.bundle]) byBundle[s.bundle] = []
|
|
@@ -41,6 +87,22 @@ if (args[0] === 'list') {
|
|
|
41
87
|
process.exit(0)
|
|
42
88
|
}
|
|
43
89
|
|
|
90
|
+
// ── Install ───────────────────────────────────────────────────────────────────
|
|
91
|
+
// subcommand is 'install' or omitted (default behavior)
|
|
92
|
+
const installArgs = subcommand === 'install' ? args.slice(1) : args
|
|
93
|
+
|
|
94
|
+
const forceFlag = installArgs.includes('--force')
|
|
95
|
+
const bundleIdx = installArgs.indexOf('--bundle')
|
|
96
|
+
const targetIdx = installArgs.indexOf('--target')
|
|
97
|
+
const toolIdx = installArgs.indexOf('--tool')
|
|
98
|
+
const skillIdx = installArgs.indexOf('--skill')
|
|
99
|
+
const scopeIdx = installArgs.indexOf('--scope')
|
|
100
|
+
const bundleArg = bundleIdx !== -1 ? installArgs[bundleIdx + 1] : undefined
|
|
101
|
+
const targetArg = targetIdx !== -1 ? installArgs[targetIdx + 1] : undefined
|
|
102
|
+
const toolArg = toolIdx !== -1 ? installArgs[toolIdx + 1] : undefined
|
|
103
|
+
const skillArg = skillIdx !== -1 ? installArgs[skillIdx + 1] : undefined
|
|
104
|
+
const scopeArg = scopeIdx !== -1 ? installArgs[scopeIdx + 1] : undefined
|
|
105
|
+
|
|
44
106
|
const TOOL_BUNDLE_VALUES = new Set(TOOL_BUNDLE_CHOICES.map(c => c.value))
|
|
45
107
|
|
|
46
108
|
function buildInteractiveChoices() {
|
|
@@ -103,23 +165,36 @@ try {
|
|
|
103
165
|
process.exit(0)
|
|
104
166
|
}
|
|
105
167
|
|
|
106
|
-
// ── Install skills
|
|
168
|
+
// ── Install skills ──────────────────────────────────────────────────────────
|
|
107
169
|
if (skillItems.length > 0) {
|
|
170
|
+
// Resolve scope
|
|
171
|
+
let scope = scopeArg ?? 'user'
|
|
172
|
+
if (!scopeArg && !targetArg) {
|
|
173
|
+
scope = await select({
|
|
174
|
+
message: 'Scope:',
|
|
175
|
+
choices: [
|
|
176
|
+
{ name: `user — ~/.claude/skills/ (shared across all projects)`, value: 'user' },
|
|
177
|
+
{ name: `project — .claude/skills/ (current project only)`, value: 'project' },
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Resolve target
|
|
108
183
|
let selectedTargets
|
|
109
184
|
if (targetArg) {
|
|
110
|
-
selectedTargets = targetArg === 'all' ?
|
|
185
|
+
selectedTargets = targetArg === 'all' ? ['claude', 'cursor', 'codex'] : [targetArg]
|
|
111
186
|
} else {
|
|
112
187
|
selectedTargets = await checkbox({
|
|
113
188
|
message: 'Install to which tools (space to select, enter to confirm):',
|
|
114
189
|
choices: [
|
|
115
|
-
...
|
|
190
|
+
...buildTargetChoices(scope),
|
|
116
191
|
{ name: 'all — all tools', value: 'all' },
|
|
117
192
|
],
|
|
118
193
|
})
|
|
119
194
|
}
|
|
120
195
|
|
|
121
196
|
if (selectedTargets.length > 0) {
|
|
122
|
-
const targets = resolveTargets(selectedTargets)
|
|
197
|
+
const targets = resolveTargets(selectedTargets, scope)
|
|
123
198
|
console.log('')
|
|
124
199
|
const summary = await installSkills(skillItems, targets, forceFlag)
|
|
125
200
|
console.log('')
|
|
@@ -134,7 +209,7 @@ try {
|
|
|
134
209
|
}
|
|
135
210
|
}
|
|
136
211
|
|
|
137
|
-
// ── Install shell tools
|
|
212
|
+
// ── Install shell tools ─────────────────────────────────────────────────────
|
|
138
213
|
if (toolItems.length > 0) {
|
|
139
214
|
console.log('')
|
|
140
215
|
const installed = await installTools(
|
package/lib/targets.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import os from 'os'
|
|
2
2
|
import path from 'path'
|
|
3
3
|
|
|
4
|
+
const SKILL_TARGETS = ['claude', 'cursor', 'codex']
|
|
5
|
+
|
|
6
|
+
function skillDir(name, scope) {
|
|
7
|
+
if (scope === 'project') return path.join(process.cwd(), `.${name}`, 'skills')
|
|
8
|
+
return path.join(os.homedir(), `.${name}`, 'skills')
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
export const TARGETS = {
|
|
5
12
|
claude: path.join(os.homedir(), '.claude', 'skills'),
|
|
6
13
|
cursor: path.join(os.homedir(), '.cursor', 'skills'),
|
|
@@ -8,17 +15,21 @@ export const TARGETS = {
|
|
|
8
15
|
shell: path.join(os.homedir(), '.local', 'bin'),
|
|
9
16
|
}
|
|
10
17
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})
|
|
18
|
+
export function buildTargetChoices(scope = 'user') {
|
|
19
|
+
return SKILL_TARGETS.map(name => {
|
|
20
|
+
const dir = skillDir(name, scope)
|
|
21
|
+
return { name: `${name.padEnd(8)} (${dir})`, value: name }
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const TARGET_CHOICES = buildTargetChoices('user')
|
|
15
26
|
|
|
16
27
|
// 返回选中 targets 的 { name, dir } 列表,all 展开为全部
|
|
17
|
-
export function resolveTargets(selected) {
|
|
18
|
-
|
|
28
|
+
export function resolveTargets(selected, scope = 'user') {
|
|
29
|
+
const allTargets = SKILL_TARGETS.map(name => ({ name, dir: skillDir(name, scope) }))
|
|
30
|
+
if (selected.includes('all')) return allTargets
|
|
19
31
|
return selected.map(name => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return { name, dir }
|
|
32
|
+
if (!SKILL_TARGETS.includes(name)) throw new Error(`Unknown target: "${name}"`)
|
|
33
|
+
return { name, dir: skillDir(name, scope) }
|
|
23
34
|
})
|
|
24
35
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harveyz-skill",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Skill manager for Claude Code, Cursor, and Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
7
|
+
"hskill": "bin/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"prepack": "node scripts/generate-npmignore.js"
|