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.
Files changed (2) hide show
  1. package/package.json +5 -1
  2. 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.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, installed: 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("\n📋 dk-frontend-skills 技能清单\n");
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
- const name = skill.name.padEnd(20);
73
- const ver = skill.version.padEnd(7);
74
- const desc = skill.description || "(无描述)";
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 进入交互选择模式\n`);
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
- // ---------- 交互式 TUI 菜单 ----------
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
- process.exit(0);
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
- // choices 只包含包内有的技能
134
- const skills = pkgSkills.map((s) => ({
135
- ...s,
136
- enabled: userMap.has(s.name) ? userMap.get(s.name) : false,
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
- let cursor = 0;
140
- const toggled = skills.map((s) => s.enabled);
141
- const stdin = process.stdin;
142
- const stdout = process.stdout;
143
-
144
- function render() {
145
- stdout.write("\x1Bc"); // 清屏
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
- function exitMenu(saved) {
174
- stdin.setRawMode(false);
175
- stdin.pause();
176
- if (saved) {
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
- render();
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
- if (!command) {
215
- // 无参数 启动交互菜单
216
- startInteractiveMenu();
217
- } else if (command === "--help" || command === "-h") {
218
- console.log(`
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
- cmdList();
235
- } else if (command === "enable") {
236
- cmdToggle(true, args);
237
- } else if (command === "disable") {
238
- cmdToggle(false, args);
239
- } else {
240
- console.log(` 未知命令: ${command}\n 可用: ${COMMANDS.join(", ")}\n`);
241
- process.exit(1);
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);