dk-frontend-skills 3.0.1 → 3.0.2

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dk-frontend-skills",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "dk-engineer - 幽默沉稳靠谱的前端开发助手 Claude Skills 配置包,一键注入 .claude/ 技能目录和 CLAUDE.md 人设配置",
5
5
  "author": "XiaoMa",
6
6
  "license": "MIT",
package/scripts/cli.js CHANGED
@@ -52,80 +52,62 @@ function writeSettings(settings) {
52
52
 
53
53
  async function downloadAndInstallSkill(name, index) {
54
54
  const skillInfo = index.skills[name];
55
- if (!skillInfo) {
56
- console.error(` ❌ 技能 "${name}" 不在索引中`);
57
- return false;
58
- }
55
+ if (!skillInfo) return false;
59
56
 
60
57
  const destDir = path.join(skillsDest, name);
61
58
 
62
- // 检查本地是否已安装且版本一致
59
+ // 检查本地版本
63
60
  const localMetaPath = path.join(destDir, ".meta.json");
64
61
  if (fs.existsSync(localMetaPath)) {
65
62
  try {
66
63
  const localMeta = JSON.parse(fs.readFileSync(localMetaPath, "utf-8"));
67
- if (localMeta.version === skillInfo.version) {
68
- return true; // 已是最新,跳过
69
- }
70
- } catch {
71
- // 元信息损坏,重新下载
72
- }
64
+ if (localMeta.version === skillInfo.version) return true;
65
+ } catch {}
73
66
  }
74
67
 
75
- // 构造下载地址
76
68
  const url = `${index.baseUrl}/${skillInfo.fileName}`;
77
69
  const tempDir = path.join(claudeDest, ".temp");
78
- if (!fs.existsSync(tempDir)) {
79
- fs.mkdirSync(tempDir, { recursive: true });
80
- }
81
- const tempFile = path.join(tempDir, skillInfo.fileName);
70
+ if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });
82
71
 
83
- // 下载带进度条
84
72
  const { SingleBar, Presets } = await import("cli-progress");
85
- const bar = new SingleBar(
86
- {
87
- format: ` 📥 ${name} |{bar}| {percentage}% | {value}/{total} bytes`,
88
- barCompleteChar: "\u2588",
89
- barIncompleteChar: "\u2591",
90
- hideCursor: true,
91
- },
92
- Presets.shades_classic,
93
- );
73
+ const bar = new SingleBar({
74
+ format: ` ${name} |{bar}| {percentage}%`,
75
+ barCompleteChar: "\u2588",
76
+ barIncompleteChar: "\u2591",
77
+ hideCursor: true,
78
+ }, Presets.shades_classic);
94
79
 
95
- try {
96
- console.log(` ⏬ 正在下载 ${name} (${skillInfo.version})...`);
97
- bar.start(skillInfo.size || 100, 0);
98
- await downloadFile(url, tempFile, (downloaded, total) => {
99
- bar.setTotal(total || skillInfo.size || 100);
100
- bar.update(downloaded);
101
- });
102
- bar.stop();
103
-
104
- // 创建目标目录,解压
105
- if (fs.existsSync(destDir)) {
106
- fs.rmSync(destDir, { recursive: true, force: true });
80
+ const MAX_RETRIES = 3;
81
+
82
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
83
+ const tempFile = path.join(tempDir, skillInfo.fileName);
84
+ try {
85
+ if (attempt > 1) console.log(` ↻ ${name} 重试第 ${attempt} 次...`);
86
+ bar.start(100, 0);
87
+ await downloadFile(url, tempFile, (d, t) => {
88
+ bar.setTotal(t || skillInfo.size || 100);
89
+ bar.update(d);
90
+ });
91
+ bar.stop();
92
+
93
+ if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
94
+ fs.mkdirSync(destDir, { recursive: true });
95
+
96
+ await tar.x({ file: tempFile, C: destDir });
97
+
98
+ fs.rmSync(tempFile, { force: true });
99
+ return true;
100
+ } catch (err) {
101
+ bar.stop();
102
+ if (fs.existsSync(tempFile)) fs.rmSync(tempFile, { force: true });
103
+ if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
104
+ if (attempt === MAX_RETRIES) {
105
+ console.error(` ✗ ${name}: ${err.message}`);
106
+ return false;
107
+ }
107
108
  }
108
- fs.mkdirSync(destDir, { recursive: true });
109
-
110
- await tar.x({
111
- file: tempFile,
112
- C: destDir,
113
- });
114
-
115
- // 清理临时文件
116
- fs.rmSync(tempFile, { force: true });
117
-
118
- console.log(` ✅ ${name} (${skillInfo.version}) 安装成功`);
119
- return true;
120
- } catch (err) {
121
- bar.stop();
122
- // 清理残留
123
- if (fs.existsSync(tempFile)) fs.rmSync(tempFile, { force: true });
124
- if (fs.existsSync(destDir))
125
- fs.rmSync(destDir, { recursive: true, force: true });
126
- console.error(` ❌ 下载 "${name}" 失败: ${err.message}`);
127
- return false;
128
109
  }
110
+ return false;
129
111
  }
130
112
 
131
113
  async function installSelectedSkills(selectedNames) {
@@ -275,11 +257,11 @@ async function startInteractiveMenu() {
275
257
  const installed = await installSelectedSkills(selected);
276
258
 
277
259
  const parts = [];
278
- if (newCount > 0) parts.push(`新装 ${newCount} 个`);
279
- if (removedCount > 0) parts.push(`移除 ${removedCount} 个`);
280
- const summary = parts.length > 0 ? `(${parts.join("")})` : "";
260
+ if (newCount > 0) parts.push(`+${newCount}`);
261
+ if (removedCount > 0) parts.push(`-${removedCount}`);
262
+ const summary = parts.length > 0 ? ` ${parts.join(" ")}` : "";
281
263
 
282
- console.log(`\n技能安装完成 ${summary}\n`);
264
+ console.log(`完成${summary}\n`);
283
265
  }
284
266
 
285
267
  // ---------- 主入口 ----------
@@ -7,7 +7,6 @@ const {
7
7
  } = require("./core");
8
8
 
9
9
  // 获取用户项目根目录
10
- // npm lifecycle 脚本会设置 INIT_CWD 为执行命令时的目录,比从 __dirname 爬三级更可靠
11
10
  const projectRoot =
12
11
  process.env.INIT_CWD || path.resolve(__dirname, "..", "..", "..");
13
12
  const packageDir = path.join(__dirname, "..");
@@ -25,15 +24,12 @@ const logFile = path.join(claudeDest, ".install.log");
25
24
 
26
25
  // ===================== 主流程 =====================
27
26
 
28
- console.log("\n📦 dk-frontend-skills 技能包安装开始\n");
29
-
30
- // 确保 .claude/ 目录存在
27
+ // 确保 .claude/ skills/ 目录存在
31
28
  if (!fs.existsSync(claudeDest)) {
32
29
  fs.mkdirSync(claudeDest, { recursive: true });
33
30
  appendLog(logFile, "INFO", `.claude/ directory created`);
34
31
  }
35
32
 
36
- // 确保 .claude/skills/ 目录存在(不覆盖已有技能)
37
33
  const skillsDest = path.join(claudeDest, "skills");
38
34
  if (!fs.existsSync(skillsDest)) {
39
35
  fs.mkdirSync(skillsDest, { recursive: true });
@@ -55,25 +51,8 @@ if (fs.existsSync(mdSource)) {
55
51
  const bakName = `CLAUDE.md.${backupTimestamp()}`;
56
52
  const bakPath = path.join(backupsDir, bakName);
57
53
  fs.copyFileSync(mdDest, bakPath);
58
- appendLog(
59
- logFile,
60
- "BACKUP",
61
- `backups/${bakName} (CLAUDE.md user version preserved)`,
62
- );
63
- }
64
- }
65
-
66
- // 输出摘要
67
- console.log("✅ dk-frontend-skills 安装完成!\n");
68
-
69
- if (fs.existsSync(logFile)) {
70
- const logs = fs.readFileSync(logFile, "utf-8").trim().split("\n");
71
- const recent = logs.slice(-10);
72
- console.log("📋 操作日志:");
73
- for (const line of recent) {
74
- console.log(` ${line}`);
54
+ appendLog(logFile, "BACKUP", `backups/${bakName} (CLAUDE.md user version preserved)`);
75
55
  }
76
- console.log("");
77
56
  }
78
57
 
79
- console.log("💡 提示:运行 npx dk-skills 可交互选择安装/启用/禁用技能\n");
58
+ console.log("💡 npx dk-skills 可交互选择安装技能\n");