dk-frontend-skills 2.0.1 → 2.1.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
CHANGED
package/scripts/cli.js
CHANGED
|
@@ -4,13 +4,16 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { getPackageSkills, getUserSkills } = require("./core");
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
|
|
7
|
+
// npx 运行时:process.cwd() 是用户项目目录
|
|
8
|
+
// __dirname 是包内 scripts/ 目录
|
|
9
|
+
const projectRoot = process.cwd();
|
|
9
10
|
const packageDir = path.join(__dirname, "..");
|
|
10
11
|
const claudeDest = path.join(projectRoot, ".claude");
|
|
12
|
+
const skillsDest = path.join(claudeDest, "skills");
|
|
11
13
|
const settingsPath = path.join(claudeDest, "settings.json");
|
|
14
|
+
const pkgSkillsSource = path.join(packageDir, ".claude", "skills");
|
|
12
15
|
|
|
13
|
-
// ----------
|
|
16
|
+
// ---------- 文件写入 ----------
|
|
14
17
|
|
|
15
18
|
function readSettings() {
|
|
16
19
|
if (!fs.existsSync(settingsPath)) return { skills: {}, always_apply_skills: [] };
|
|
@@ -22,14 +25,47 @@ function readSettings() {
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
function writeSettings(settings) {
|
|
28
|
+
if (!fs.existsSync(claudeDest)) {
|
|
29
|
+
fs.mkdirSync(claudeDest, { recursive: true });
|
|
30
|
+
}
|
|
25
31
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
// ---------- 安装勾选的技能 ----------
|
|
35
|
+
|
|
36
|
+
function installSelectedSkills(selectedNames) {
|
|
37
|
+
// 创建 .claude/ 和 skills/ 目录
|
|
38
|
+
if (!fs.existsSync(skillsDest)) {
|
|
39
|
+
fs.mkdirSync(skillsDest, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const allPkgSkills = fs.readdirSync(pkgSkillsSource);
|
|
43
|
+
let installedCount = 0;
|
|
44
|
+
|
|
45
|
+
for (const name of allPkgSkills) {
|
|
46
|
+
const src = path.join(pkgSkillsSource, name);
|
|
47
|
+
const dest = path.join(skillsDest, name);
|
|
48
|
+
|
|
49
|
+
if (selectedNames.includes(name)) {
|
|
50
|
+
// 勾选了的 → 安装(不存在才装)
|
|
51
|
+
if (!fs.existsSync(dest)) {
|
|
52
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
53
|
+
installedCount++;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
// 没勾选的 → 如果之前装了,删掉
|
|
57
|
+
if (fs.existsSync(dest)) {
|
|
58
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 生成 settings.json
|
|
29
64
|
const settings = readSettings();
|
|
30
65
|
if (!settings.skills) settings.skills = {};
|
|
31
66
|
|
|
32
|
-
for (const
|
|
67
|
+
for (const name of allPkgSkills) {
|
|
68
|
+
const enabled = selectedNames.includes(name);
|
|
33
69
|
if (!settings.skills[name]) {
|
|
34
70
|
settings.skills[name] = {};
|
|
35
71
|
}
|
|
@@ -37,11 +73,26 @@ function saveSkillSelection(choices) {
|
|
|
37
73
|
}
|
|
38
74
|
|
|
39
75
|
writeSettings(settings);
|
|
76
|
+
|
|
77
|
+
// 安装 CLAUDE.md(没有才装)
|
|
78
|
+
const mdSource = path.join(packageDir, "CLAUDE.md");
|
|
79
|
+
const mdDest = path.join(projectRoot, "CLAUDE.md");
|
|
80
|
+
if (fs.existsSync(mdSource) && !fs.existsSync(mdDest)) {
|
|
81
|
+
fs.copyFileSync(mdSource, mdDest);
|
|
82
|
+
console.log(" 📝 CLAUDE.md 已创建\n");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return installedCount;
|
|
40
86
|
}
|
|
41
87
|
|
|
42
88
|
// ---------- 命令:list ----------
|
|
43
89
|
|
|
44
90
|
async function cmdList() {
|
|
91
|
+
if (!fs.existsSync(claudeDest)) {
|
|
92
|
+
console.log("\n ⚠️ 尚未安装技能,请先运行 npx dk-frontend-skills\n");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
45
96
|
const chalk = (await import("chalk")).default;
|
|
46
97
|
const pkgSkills = getPackageSkills(packageDir);
|
|
47
98
|
const userSkills = getUserSkills(claudeDest);
|
|
@@ -72,52 +123,19 @@ async function cmdList() {
|
|
|
72
123
|
console.log(` ${status} ${name} ${ver} ${desc}`);
|
|
73
124
|
}
|
|
74
125
|
|
|
75
|
-
console.log(`\n ${chalk.cyan("💡")} ${chalk.dim("运行 npx dk-skills 进入交互选择模式")}\n`);
|
|
126
|
+
console.log(`\n ${chalk.cyan("💡")} ${chalk.dim("运行 npx dk-frontend-skills 进入交互选择模式")}\n`);
|
|
76
127
|
}
|
|
77
128
|
|
|
78
|
-
// ----------
|
|
79
|
-
|
|
80
|
-
function cmdToggle(enable, names) {
|
|
81
|
-
if (names.length === 0) {
|
|
82
|
-
console.log(` 用法: npx dk-skills ${enable ? "enable" : "disable"} <技能名...>`);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const pkgSkills = getPackageSkills(packageDir);
|
|
87
|
-
const pkgNames = new Set(pkgSkills.map((s) => s.name));
|
|
88
|
-
const userSkills = getUserSkills(claudeDest);
|
|
89
|
-
const userNames = new Set(userSkills.map((s) => s.name));
|
|
129
|
+
// ---------- 交互式菜单(选完即装) ----------
|
|
90
130
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
console.log(` ⚠️ 未知技能: ${notFound.join(", ")}`);
|
|
94
|
-
console.log(` 可用: ${[...pkgNames].join(", ")}\n`);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
131
|
+
async function startInteractiveMenu() {
|
|
132
|
+
const { checkbox } = await import("@inquirer/prompts");
|
|
97
133
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log(` ⚠️ 以下技能尚未安装: ${notInstalled.join(", ")}`);
|
|
101
|
-
console.log(` 请先执行 npm i dk-frontend-skills 安装完整技能包\n`);
|
|
134
|
+
if (!fs.existsSync(pkgSkillsSource)) {
|
|
135
|
+
console.log(" ⚠️ 包内没有找到技能文件\n");
|
|
102
136
|
return;
|
|
103
137
|
}
|
|
104
138
|
|
|
105
|
-
const choices = userSkills.map((s) => ({
|
|
106
|
-
name: s.name,
|
|
107
|
-
enabled: names.includes(s.name) ? enable : s.enabled,
|
|
108
|
-
}));
|
|
109
|
-
|
|
110
|
-
saveSkillSelection(choices);
|
|
111
|
-
|
|
112
|
-
const action = enable ? "启用" : "停用";
|
|
113
|
-
console.log(` ✅ 已${action}: ${names.join(", ")}\n`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ---------- 交互式菜单 (@inquirer/prompts) ----------
|
|
117
|
-
|
|
118
|
-
async function startInteractiveMenu() {
|
|
119
|
-
const { checkbox } = await import("@inquirer/prompts");
|
|
120
|
-
|
|
121
139
|
const pkgSkills = getPackageSkills(packageDir);
|
|
122
140
|
|
|
123
141
|
if (pkgSkills.length === 0) {
|
|
@@ -125,31 +143,45 @@ async function startInteractiveMenu() {
|
|
|
125
143
|
return;
|
|
126
144
|
}
|
|
127
145
|
|
|
146
|
+
// 读取已安装状态:已装且启用的默认勾选
|
|
128
147
|
const userSkills = getUserSkills(claudeDest);
|
|
129
|
-
const
|
|
148
|
+
const enabledSet = new Set(
|
|
149
|
+
userSkills.filter((s) => s.enabled).map((s) => s.name),
|
|
150
|
+
);
|
|
151
|
+
const installedSet = new Set(userSkills.map((s) => s.name));
|
|
152
|
+
|
|
153
|
+
// 首次运行全部默认勾选(省事),再次运行沿用已有状态
|
|
154
|
+
const hasExistingInstall = fs.existsSync(claudeDest);
|
|
155
|
+
const defaultChecked = hasExistingInstall
|
|
156
|
+
? enabledSet
|
|
157
|
+
: new Set(pkgSkills.map((s) => s.name));
|
|
130
158
|
|
|
131
159
|
const choices = pkgSkills.map((s) => ({
|
|
132
160
|
name: s.name,
|
|
133
161
|
value: s.name,
|
|
134
162
|
description: s.description || undefined,
|
|
135
|
-
checked:
|
|
163
|
+
checked: defaultChecked.has(s.name),
|
|
136
164
|
}));
|
|
137
165
|
|
|
138
166
|
const selected = await checkbox({
|
|
139
|
-
message: "
|
|
167
|
+
message: "选择要安装的技能(未勾选的将从 .claude/ 中移除)",
|
|
140
168
|
instructions: "(↑↓ 导航, 空格 开关, Enter 确认)",
|
|
141
169
|
choices,
|
|
142
170
|
pageSize: 15,
|
|
143
171
|
loop: false,
|
|
144
172
|
});
|
|
145
173
|
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
174
|
+
const newCount = selected.filter((name) => !installedSet.has(name)).length;
|
|
175
|
+
const removedCount = [...installedSet].filter((name) => !selected.includes(name)).length;
|
|
176
|
+
|
|
177
|
+
const installed = installSelectedSkills(selected);
|
|
150
178
|
|
|
151
|
-
|
|
152
|
-
|
|
179
|
+
const parts = [];
|
|
180
|
+
if (newCount > 0) parts.push(`新装 ${newCount} 个`);
|
|
181
|
+
if (removedCount > 0) parts.push(`移除 ${removedCount} 个`);
|
|
182
|
+
const summary = parts.length > 0 ? `(${parts.join(",")})` : "";
|
|
183
|
+
|
|
184
|
+
console.log(`\n ✅ 技能安装完成 ${summary}\n`);
|
|
153
185
|
}
|
|
154
186
|
|
|
155
187
|
// ---------- 主入口 ----------
|
|
@@ -167,23 +199,20 @@ async function main() {
|
|
|
167
199
|
dk-frontend-skills CLI
|
|
168
200
|
|
|
169
201
|
用法:
|
|
170
|
-
npx dk-skills
|
|
171
|
-
npx dk-skills list
|
|
172
|
-
npx dk-skills
|
|
173
|
-
|
|
174
|
-
|
|
202
|
+
npx dk-frontend-skills 交互式选择并安装技能
|
|
203
|
+
npx dk-frontend-skills list 查看已安装的技能
|
|
204
|
+
npx dk-frontend-skills --help 显示帮助
|
|
205
|
+
|
|
206
|
+
首次运行会自动创建 .claude/ 目录,勾选要安装的技能即可
|
|
175
207
|
|
|
176
208
|
示例:
|
|
177
|
-
npx dk-skills
|
|
178
|
-
npx dk-skills
|
|
179
|
-
npx dk-skills disable moai-framework-electron
|
|
209
|
+
npx dk-frontend-skills
|
|
210
|
+
npx dk-frontend-skills list
|
|
180
211
|
`);
|
|
181
212
|
} else if (command === "list") {
|
|
182
213
|
await cmdList();
|
|
183
|
-
} else if (command === "enable") {
|
|
184
|
-
|
|
185
|
-
} else if (command === "disable") {
|
|
186
|
-
cmdToggle(false, args);
|
|
214
|
+
} else if (command === "enable" || command === "disable") {
|
|
215
|
+
console.log(` ⚠️ 该命令已废弃,请直接运行 npx dk-frontend-skills 使用交互菜单\n`);
|
|
187
216
|
} else {
|
|
188
217
|
console.log(` 未知命令: ${command}\n 可用: ${COMMANDS.join(", ")}\n`);
|
|
189
218
|
process.exit(1);
|