dk-frontend-skills 2.0.0 → 2.0.1
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/package.json +5 -1
- package/scripts/cli.js +58 -107
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dk-frontend-skills",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "dk-engineer - 幽默沉稳靠谱的前端开发助手 Claude Skills 配置包,一键注入 .claude/ 技能目录和 CLAUDE.md 人设配置",
|
|
5
5
|
"author": "XiaoMa",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,5 +15,9 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"postinstall": "node scripts/copy-skills.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@inquirer/prompts": "^8.4.2",
|
|
21
|
+
"chalk": "^5.6.2"
|
|
18
22
|
}
|
|
19
23
|
}
|
package/scripts/cli.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const readline = require("readline");
|
|
6
5
|
const { getPackageSkills, getUserSkills } = require("./core");
|
|
7
6
|
|
|
8
7
|
// 定位项目根目录和包目录
|
|
@@ -11,9 +10,6 @@ const packageDir = path.join(__dirname, "..");
|
|
|
11
10
|
const claudeDest = path.join(projectRoot, ".claude");
|
|
12
11
|
const settingsPath = path.join(claudeDest, "settings.json");
|
|
13
12
|
|
|
14
|
-
const command = process.argv[2];
|
|
15
|
-
const args = process.argv.slice(3);
|
|
16
|
-
|
|
17
13
|
// ---------- 辅助函数 ----------
|
|
18
14
|
|
|
19
15
|
function readSettings() {
|
|
@@ -29,9 +25,6 @@ function writeSettings(settings) {
|
|
|
29
25
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
/**
|
|
33
|
-
* 保存技能选择结果到 settings.json
|
|
34
|
-
*/
|
|
35
28
|
function saveSkillSelection(choices) {
|
|
36
29
|
const settings = readSettings();
|
|
37
30
|
if (!settings.skills) settings.skills = {};
|
|
@@ -48,34 +41,38 @@ function saveSkillSelection(choices) {
|
|
|
48
41
|
|
|
49
42
|
// ---------- 命令:list ----------
|
|
50
43
|
|
|
51
|
-
function cmdList() {
|
|
44
|
+
async function cmdList() {
|
|
45
|
+
const chalk = (await import("chalk")).default;
|
|
52
46
|
const pkgSkills = getPackageSkills(packageDir);
|
|
53
47
|
const userSkills = getUserSkills(claudeDest);
|
|
54
48
|
|
|
55
|
-
// 合并包内和用户已安装的技能状态
|
|
56
49
|
const skillMap = new Map();
|
|
57
50
|
for (const s of userSkills) skillMap.set(s.name, s);
|
|
58
51
|
for (const s of pkgSkills) {
|
|
59
52
|
if (!skillMap.has(s.name)) {
|
|
60
|
-
skillMap.set(s.name, { ...s, enabled: false
|
|
53
|
+
skillMap.set(s.name, { ...s, enabled: false });
|
|
61
54
|
}
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
const allSkills = [...skillMap.values()];
|
|
65
58
|
|
|
66
|
-
console.log("
|
|
67
|
-
console.log("
|
|
68
|
-
console.log("
|
|
59
|
+
console.log(`\n${chalk.bold("📋 dk-frontend-skills 技能清单")}\n`);
|
|
60
|
+
console.log(` ${chalk.dim("状态 技能名 版本 描述")}`);
|
|
61
|
+
console.log(` ${chalk.dim("─────────────────────────────────────────────────────")}`);
|
|
69
62
|
|
|
70
63
|
for (const skill of allSkills) {
|
|
71
|
-
const status = skill.enabled
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
64
|
+
const status = skill.enabled
|
|
65
|
+
? chalk.green("● 启用")
|
|
66
|
+
: chalk.gray("○ 停用");
|
|
67
|
+
const name = chalk.white(skill.name.padEnd(20));
|
|
68
|
+
const ver = chalk.dim(skill.version.padEnd(7));
|
|
69
|
+
const desc = skill.description
|
|
70
|
+
? chalk.gray(skill.description)
|
|
71
|
+
: chalk.dim("(无描述)");
|
|
75
72
|
console.log(` ${status} ${name} ${ver} ${desc}`);
|
|
76
73
|
}
|
|
77
74
|
|
|
78
|
-
console.log(`\n 💡 运行 npx dk-skills
|
|
75
|
+
console.log(`\n ${chalk.cyan("💡")} ${chalk.dim("运行 npx dk-skills 进入交互选择模式")}\n`);
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
// ---------- 命令:enable / disable ----------
|
|
@@ -116,106 +113,57 @@ function cmdToggle(enable, names) {
|
|
|
116
113
|
console.log(` ✅ 已${action}: ${names.join(", ")}\n`);
|
|
117
114
|
}
|
|
118
115
|
|
|
119
|
-
// ----------
|
|
116
|
+
// ---------- 交互式菜单 (@inquirer/prompts) ----------
|
|
117
|
+
|
|
118
|
+
async function startInteractiveMenu() {
|
|
119
|
+
const { checkbox } = await import("@inquirer/prompts");
|
|
120
120
|
|
|
121
|
-
function startInteractiveMenu() {
|
|
122
121
|
const pkgSkills = getPackageSkills(packageDir);
|
|
123
122
|
|
|
124
123
|
if (pkgSkills.length === 0) {
|
|
125
124
|
console.log(" ⚠️ 包内没有可用技能\n");
|
|
126
|
-
|
|
125
|
+
return;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
// 读取当前 settings 中的启用状态
|
|
130
128
|
const userSkills = getUserSkills(claudeDest);
|
|
131
129
|
const userMap = new Map(userSkills.map((s) => [s.name, s.enabled]));
|
|
132
130
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
const choices = pkgSkills.map((s) => ({
|
|
132
|
+
name: s.name,
|
|
133
|
+
value: s.name,
|
|
134
|
+
description: s.description || undefined,
|
|
135
|
+
checked: userMap.has(s.name) ? userMap.get(s.name) : false,
|
|
137
136
|
}));
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
stdout.write("╔══════════════════════════════════════════════╗\n");
|
|
147
|
-
stdout.write("║ dk-frontend-skills 技能选择 ║\n");
|
|
148
|
-
stdout.write("╠══════════════════════════════════════════════╣\n");
|
|
149
|
-
stdout.write("║ ↑↓ 导航 ␣ 开关 Enter 确认 q 退出 ║\n");
|
|
150
|
-
stdout.write("╚══════════════════════════════════════════════╝\n\n");
|
|
151
|
-
|
|
152
|
-
for (let i = 0; i < skills.length; i++) {
|
|
153
|
-
const s = skills[i];
|
|
154
|
-
const arrow = i === cursor ? "❯" : " ";
|
|
155
|
-
const check = toggled[i] ? "✓" : " ";
|
|
156
|
-
const name = s.name.padEnd(20);
|
|
157
|
-
const desc = s.description || "";
|
|
158
|
-
stdout.write(` ${arrow} [${check}] ${name} ${desc}\n`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
stdout.write("\n 选中: ");
|
|
162
|
-
const selectedNames = skills.filter((_, i) => toggled[i]).map((s) => s.name);
|
|
163
|
-
if (selectedNames.length === 0) {
|
|
164
|
-
stdout.write("(无)");
|
|
165
|
-
} else if (selectedNames.length <= 3) {
|
|
166
|
-
stdout.write(selectedNames.join(", "));
|
|
167
|
-
} else {
|
|
168
|
-
stdout.write(`${selectedNames.length} 个技能`);
|
|
169
|
-
}
|
|
170
|
-
stdout.write("\n");
|
|
171
|
-
}
|
|
138
|
+
const selected = await checkbox({
|
|
139
|
+
message: "选择要启用的技能",
|
|
140
|
+
instructions: "(↑↓ 导航, 空格 开关, Enter 确认)",
|
|
141
|
+
choices,
|
|
142
|
+
pageSize: 15,
|
|
143
|
+
loop: false,
|
|
144
|
+
});
|
|
172
145
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
console.log("\n ✅ 技能选择已保存\n");
|
|
178
|
-
}
|
|
179
|
-
process.exit(0);
|
|
180
|
-
}
|
|
146
|
+
const allChoices = pkgSkills.map((s) => ({
|
|
147
|
+
name: s.name,
|
|
148
|
+
enabled: selected.includes(s.name),
|
|
149
|
+
}));
|
|
181
150
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
readline.emitKeypressEvents(stdin);
|
|
185
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
186
|
-
stdin.resume();
|
|
187
|
-
|
|
188
|
-
stdin.on("keypress", (str, key) => {
|
|
189
|
-
if (!key) return;
|
|
190
|
-
|
|
191
|
-
if (key.name === "up") {
|
|
192
|
-
cursor = Math.max(0, cursor - 1);
|
|
193
|
-
render();
|
|
194
|
-
} else if (key.name === "down") {
|
|
195
|
-
cursor = Math.min(skills.length - 1, cursor + 1);
|
|
196
|
-
render();
|
|
197
|
-
} else if (key.name === "space") {
|
|
198
|
-
toggled[cursor] = !toggled[cursor];
|
|
199
|
-
render();
|
|
200
|
-
} else if (key.name === "return") {
|
|
201
|
-
const choices = skills.map((s, i) => ({ name: s.name, enabled: toggled[i] }));
|
|
202
|
-
saveSkillSelection(choices);
|
|
203
|
-
exitMenu(true);
|
|
204
|
-
} else if (key.name === "q" || (key.ctrl && key.name === "c")) {
|
|
205
|
-
exitMenu(false);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
151
|
+
saveSkillSelection(allChoices);
|
|
152
|
+
console.log("\n ✅ 技能选择已保存\n");
|
|
208
153
|
}
|
|
209
154
|
|
|
210
155
|
// ---------- 主入口 ----------
|
|
211
156
|
|
|
212
157
|
const COMMANDS = ["list", "enable", "disable"];
|
|
213
158
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
159
|
+
async function main() {
|
|
160
|
+
const command = process.argv[2];
|
|
161
|
+
const args = process.argv.slice(3);
|
|
162
|
+
|
|
163
|
+
if (!command) {
|
|
164
|
+
await startInteractiveMenu();
|
|
165
|
+
} else if (command === "--help" || command === "-h") {
|
|
166
|
+
console.log(`
|
|
219
167
|
dk-frontend-skills CLI
|
|
220
168
|
|
|
221
169
|
用法:
|
|
@@ -230,13 +178,16 @@ if (!command) {
|
|
|
230
178
|
npx dk-skills enable vue fe-biz-patterns
|
|
231
179
|
npx dk-skills disable moai-framework-electron
|
|
232
180
|
`);
|
|
233
|
-
} else if (command === "list") {
|
|
234
|
-
|
|
235
|
-
} else if (command === "enable") {
|
|
236
|
-
|
|
237
|
-
} else if (command === "disable") {
|
|
238
|
-
|
|
239
|
-
} else {
|
|
240
|
-
|
|
241
|
-
|
|
181
|
+
} else if (command === "list") {
|
|
182
|
+
await cmdList();
|
|
183
|
+
} else if (command === "enable") {
|
|
184
|
+
cmdToggle(true, args);
|
|
185
|
+
} else if (command === "disable") {
|
|
186
|
+
cmdToggle(false, args);
|
|
187
|
+
} else {
|
|
188
|
+
console.log(` 未知命令: ${command}\n 可用: ${COMMANDS.join(", ")}\n`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
242
191
|
}
|
|
192
|
+
|
|
193
|
+
main().catch(console.error);
|