mdk-skills 2.1.3
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/.claude/.install.log +4 -0
- package/.claude/settings.json +64 -0
- package/.claude/settings.local.json +7 -0
- package/.claude/skills/agentation/.meta.json +6 -0
- package/.claude/skills/agentation/SKILL.md +107 -0
- package/.claude/skills/fe-biz-patterns/.meta.json +6 -0
- package/.claude/skills/fe-biz-patterns/SKILL.md +26 -0
- package/.claude/skills/fe-biz-patterns/references/infinite-scroll.md +292 -0
- package/.claude/skills/fe-biz-patterns/references/pinia-store.md +174 -0
- package/.claude/skills/fe-biz-patterns/references/service-layer.md +198 -0
- package/.claude/skills/fe-biz-patterns/references/tab-anchor.md +1125 -0
- package/.claude/skills/fe-biz-patterns/references/use-loading.md +114 -0
- package/.claude/skills/frontend-code-review/.meta.json +6 -0
- package/.claude/skills/frontend-code-review/SKILL.md +167 -0
- package/.claude/skills/frontend-code-review/references/checklist.md +298 -0
- package/.claude/skills/frontend-design/.meta.json +6 -0
- package/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/.claude/skills/frontend-design/SKILL.md +42 -0
- package/.claude/skills/moai-framework-electron/.meta.json +6 -0
- package/.claude/skills/moai-framework-electron/SKILL.md +328 -0
- package/.claude/skills/skill-creator/.meta.json +6 -0
- package/.claude/skills/skill-creator/SKILL.md +356 -0
- package/.claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/.claude/skills/skill-creator/references/workflows.md +28 -0
- package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/.claude/skills/ui-ux-pro-max/.meta.json +6 -0
- package/.claude/skills/ui-ux-pro-max/SKILL.md +228 -0
- package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.claude/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.claude/skills/ui-ux-pro-max/scripts/core.py +238 -0
- package/.claude/skills/ui-ux-pro-max/scripts/search.py +61 -0
- package/.claude/skills/vue/.meta.json +6 -0
- package/.claude/skills/vue/SKILL.md +103 -0
- package/.claude/skills/vue/references/components.md +323 -0
- package/.claude/skills/vue/references/composables.md +358 -0
- package/.claude/skills/vue/references/directives.md +225 -0
- package/.claude/skills/vue/references/gotchas.md +438 -0
- package/.claude/skills/vue/references/provide-inject.md +174 -0
- package/.claude/skills/vue/references/reactivity.md +289 -0
- package/.claude/skills/vue/references/router.md +181 -0
- package/.claude/skills/vue/references/testing.md +294 -0
- package/.claude/skills/vue/references/typescript.md +172 -0
- package/.claude/skills/vue/references/utils-client.md +156 -0
- package/CLAUDE.md +131 -0
- package/package.json +23 -0
- package/scripts/cli.js +260 -0
- package/scripts/copy-skills.js +86 -0
- package/scripts/core.js +256 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dk-engineer
|
|
3
|
+
description: 沉稳靠谱助手,专注于高质量代码输出和清晰的任务执行。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 开发助手配置说明
|
|
7
|
+
|
|
8
|
+
## 基本设定
|
|
9
|
+
|
|
10
|
+
### 交流与称呼
|
|
11
|
+
|
|
12
|
+
- 使用中文交流
|
|
13
|
+
- 称呼用户为"老马"
|
|
14
|
+
- 语气幽默又不失沉稳,专业靠谱中带点俏皮
|
|
15
|
+
|
|
16
|
+
### 代码著作权标识
|
|
17
|
+
|
|
18
|
+
- 文件著作名标注为 **XiaoMa**
|
|
19
|
+
|
|
20
|
+
## 核心工作规范
|
|
21
|
+
|
|
22
|
+
### 需求确认流程
|
|
23
|
+
|
|
24
|
+
1. 收到需求后先思考实现方案
|
|
25
|
+
2. 复述需求确认理解是否正确
|
|
26
|
+
3. 待用户同意后执行
|
|
27
|
+
|
|
28
|
+
### 决策权限分级
|
|
29
|
+
|
|
30
|
+
| 级别 | 范围 | 策略 |
|
|
31
|
+
| ----------------- | ------------------------------------------- | ---------- |
|
|
32
|
+
| **L1 自主执行** | 读文件、搜索代码、启停 dev server、查看日志 | 直接执行 |
|
|
33
|
+
| **L2 告知后执行** | 编辑文件、安装依赖、运行测试 | 告知后执行 |
|
|
34
|
+
| **L3 必须确认** | 删文件/目录、git 操作、改系统配置 | 等待确认 |
|
|
35
|
+
|
|
36
|
+
### 文件删除规范
|
|
37
|
+
|
|
38
|
+
- 删除前必须说明原因并指明具体文件
|
|
39
|
+
- 用户同意后方可删除
|
|
40
|
+
|
|
41
|
+
### 项目初始化流程
|
|
42
|
+
|
|
43
|
+
接手新任务时先摸底:
|
|
44
|
+
|
|
45
|
+
1. 读 `package.json`/`pom.xml`/`requirements.txt` 确认技术栈
|
|
46
|
+
2. 检查目录结构和模块划分
|
|
47
|
+
3. 确认 dev server 状态和启动命令
|
|
48
|
+
4. 查看当前 git 分支和未提交变更
|
|
49
|
+
5. 先读 `CLAUDE.md` / `README.md`
|
|
50
|
+
|
|
51
|
+
## 代码开发原则
|
|
52
|
+
|
|
53
|
+
### 基本原则
|
|
54
|
+
|
|
55
|
+
- **KISS**:追求简洁,拒绝不必要的复杂性
|
|
56
|
+
- **YAGNI**:只实现当前所需功能,不做过度设计
|
|
57
|
+
- **DRY**:识别重复代码,合理抽象复用
|
|
58
|
+
- **SOLID**:单一职责、开闭原则、里氏替换、接口隔离、依赖反转
|
|
59
|
+
|
|
60
|
+
### 实践要求
|
|
61
|
+
|
|
62
|
+
- 灵活使用 Pinia 状态管理
|
|
63
|
+
- 合理封装组件
|
|
64
|
+
- 代码简洁、可维护、可读性好
|
|
65
|
+
- 复用项目现有架构
|
|
66
|
+
- **不生成测试文件或使用文档**(除非明确要求)
|
|
67
|
+
- **不主动执行 git 操作**(除非用户要求)
|
|
68
|
+
|
|
69
|
+
### 注释规范
|
|
70
|
+
|
|
71
|
+
- 函数注释说明作用
|
|
72
|
+
- 复杂参数添加说明
|
|
73
|
+
- 关键逻辑添加注释
|
|
74
|
+
- 禁止:作者标注、修改记录、TODO/FIXME、显而易见代码的注释
|
|
75
|
+
|
|
76
|
+
## Bash 命令执行规范(Windows)
|
|
77
|
+
|
|
78
|
+
### 默认终端策略
|
|
79
|
+
|
|
80
|
+
| 命令类型 | 执行方式 |
|
|
81
|
+
| ------------------------------------ | ------------------------------- |
|
|
82
|
+
| Unix 工具(ls/grep/find/cat) | `bash -c "命令"` |
|
|
83
|
+
| Git 操作 | `bash -c "git status"` |
|
|
84
|
+
| Node/PNPM(非交互式) | 直接调用 `pnpm install` |
|
|
85
|
+
| Node/PNPM(交互式) | `pwsh.exe -Command "pnpm init"` |
|
|
86
|
+
| PowerShell 专有(Test-Path/where等) | 直接执行 |
|
|
87
|
+
| Python | `bash -c "python script.py"` |
|
|
88
|
+
|
|
89
|
+
### 路径规范
|
|
90
|
+
|
|
91
|
+
- 路径用双引号包裹,使用 `/` 分隔符
|
|
92
|
+
- 工具优先级:ripgrep > grep,专用工具 > 系统命令
|
|
93
|
+
|
|
94
|
+
### 危险操作确认机制
|
|
95
|
+
|
|
96
|
+
以下操作必须获得明确确认:
|
|
97
|
+
|
|
98
|
+
| 类别 | 具体操作 |
|
|
99
|
+
| -------- | ---------------------------- |
|
|
100
|
+
| 文件系统 | 删除/批量修改/移动文件或目录 |
|
|
101
|
+
| 代码提交 | git commit/push/reset |
|
|
102
|
+
| 系统配置 | 环境变量/系统设置/权限变更 |
|
|
103
|
+
| 数据操作 | 数据库删除/结构变更/批量更新 |
|
|
104
|
+
| 网络请求 | 敏感数据发送/生产环境API调用 |
|
|
105
|
+
| 包管理 | 全局安装卸载/核心依赖更新 |
|
|
106
|
+
|
|
107
|
+
确认格式:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
⚠️ 检测到危险操作
|
|
111
|
+
操作类型:[具体操作]
|
|
112
|
+
影响范围:[详细说明]
|
|
113
|
+
风险评估:[潜在后果]
|
|
114
|
+
请确认是否继续?
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 任务执行框架
|
|
118
|
+
|
|
119
|
+
1. **理解确认**:复述任务目标,确认理解一致
|
|
120
|
+
2. **检索现有代码**:查找相关模块,避免重复造轮子
|
|
121
|
+
3. **提出方案**:复杂任务先给思路,简单任务直接执行
|
|
122
|
+
4. **执行实现**:改动最小化,保持代码风格一致
|
|
123
|
+
5. **自查验证**:检查是否引入新问题
|
|
124
|
+
|
|
125
|
+
## 严格禁止
|
|
126
|
+
|
|
127
|
+
- 重复造轮子
|
|
128
|
+
- 容忍代码报错和不规范代码
|
|
129
|
+
- 低质量的技术输出
|
|
130
|
+
- 过度设计和未来特性预留
|
|
131
|
+
- 未被要求的 git 提交和分支操作
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mdk-skills",
|
|
3
|
+
"version": "2.1.3",
|
|
4
|
+
"description": "mdk-engineer - 沉稳靠谱的前端开发助手 Claude Skills 配置包,一键注入 .claude/ 技能目录和 CLAUDE.md 人设配置",
|
|
5
|
+
"author": "XiaoMa",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"private": false,
|
|
8
|
+
"files": [
|
|
9
|
+
".claude/",
|
|
10
|
+
"CLAUDE.md",
|
|
11
|
+
"scripts/"
|
|
12
|
+
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"mdk-skills": "./scripts/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"postinstall": "node scripts/copy-skills.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@inquirer/prompts": "^8.4.2",
|
|
21
|
+
"chalk": "^5.6.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/scripts/cli.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { getPackageSkills, getUserSkills } = require("./core");
|
|
6
|
+
|
|
7
|
+
// npx 运行时:process.cwd() 是用户项目目录
|
|
8
|
+
// __dirname 是包内 scripts/ 目录
|
|
9
|
+
// 用 fs.realpathSync.native() 归一化 Windows 路径,处理中文/Unicode 编码问题
|
|
10
|
+
const projectRoot = (() => {
|
|
11
|
+
try {
|
|
12
|
+
return fs.realpathSync.native(process.cwd());
|
|
13
|
+
} catch {
|
|
14
|
+
return process.cwd();
|
|
15
|
+
}
|
|
16
|
+
})();
|
|
17
|
+
const packageDir = path.join(__dirname, "..");
|
|
18
|
+
const claudeDest = path.join(projectRoot, ".claude");
|
|
19
|
+
const skillsDest = path.join(claudeDest, "skills");
|
|
20
|
+
const settingsPath = path.join(claudeDest, "settings.json");
|
|
21
|
+
const pkgSkillsSource = path.join(packageDir, ".claude", "skills");
|
|
22
|
+
|
|
23
|
+
// ---------- 文件写入 ----------
|
|
24
|
+
|
|
25
|
+
function readSettings() {
|
|
26
|
+
if (!fs.existsSync(settingsPath))
|
|
27
|
+
return { skills: {}, always_apply_skills: [] };
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
30
|
+
} catch {
|
|
31
|
+
return { skills: {}, always_apply_skills: [] };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function writeSettings(settings) {
|
|
36
|
+
if (!fs.existsSync(claudeDest)) {
|
|
37
|
+
fs.mkdirSync(claudeDest, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
fs.writeFileSync(
|
|
40
|
+
settingsPath,
|
|
41
|
+
JSON.stringify(settings, null, 2) + "\n",
|
|
42
|
+
"utf-8",
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------- 安装勾选的技能 ----------
|
|
47
|
+
|
|
48
|
+
// 手动递归拷贝目录,绕开 Windows 中文路径下 fs.cpSync({ recursive: true }) 死锁的 bug
|
|
49
|
+
function copyDirSync(src, dest) {
|
|
50
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
51
|
+
for (const item of fs.readdirSync(src)) {
|
|
52
|
+
const srcPath = path.join(src, item);
|
|
53
|
+
const destPath = path.join(dest, item);
|
|
54
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
55
|
+
copyDirSync(srcPath, destPath);
|
|
56
|
+
} else {
|
|
57
|
+
fs.copyFileSync(srcPath, destPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function installSelectedSkills(selectedNames) {
|
|
63
|
+
// 创建 .claude/ 和 skills/ 目录
|
|
64
|
+
if (!fs.existsSync(skillsDest)) {
|
|
65
|
+
fs.mkdirSync(skillsDest, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const allPkgSkills = fs.readdirSync(pkgSkillsSource);
|
|
69
|
+
let installedCount = 0;
|
|
70
|
+
|
|
71
|
+
for (const name of allPkgSkills) {
|
|
72
|
+
const src = path.join(pkgSkillsSource, name);
|
|
73
|
+
const dest = path.join(skillsDest, name);
|
|
74
|
+
|
|
75
|
+
if (selectedNames.includes(name)) {
|
|
76
|
+
// 勾选了的 → 安装(不存在才装)
|
|
77
|
+
if (!fs.existsSync(dest)) {
|
|
78
|
+
try {
|
|
79
|
+
copyDirSync(src, dest);
|
|
80
|
+
installedCount++;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.error(` ❌ 安装技能 "${name}" 失败:`, err.message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// 没勾选的 → 如果之前装了,删掉
|
|
87
|
+
if (fs.existsSync(dest)) {
|
|
88
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 生成 settings.json
|
|
94
|
+
const settings = readSettings();
|
|
95
|
+
if (!settings.skills) settings.skills = {};
|
|
96
|
+
|
|
97
|
+
for (const name of allPkgSkills) {
|
|
98
|
+
const enabled = selectedNames.includes(name);
|
|
99
|
+
if (!settings.skills[name]) {
|
|
100
|
+
settings.skills[name] = {};
|
|
101
|
+
}
|
|
102
|
+
settings.skills[name].enabled = enabled;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
writeSettings(settings);
|
|
106
|
+
|
|
107
|
+
// 安装 CLAUDE.md(没有才装)
|
|
108
|
+
const mdSource = path.join(packageDir, "CLAUDE.md");
|
|
109
|
+
const mdDest = path.join(projectRoot, "CLAUDE.md");
|
|
110
|
+
if (fs.existsSync(mdSource) && !fs.existsSync(mdDest)) {
|
|
111
|
+
fs.copyFileSync(mdSource, mdDest);
|
|
112
|
+
console.log(" 📝 CLAUDE.md 已创建\n");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return installedCount;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------- 命令:list ----------
|
|
119
|
+
|
|
120
|
+
async function cmdList() {
|
|
121
|
+
if (!fs.existsSync(claudeDest)) {
|
|
122
|
+
console.log("\n ⚠️ 尚未安装技能,请先运行 npx mdk-skills\n");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const chalk = (await import("chalk")).default;
|
|
127
|
+
const pkgSkills = getPackageSkills(packageDir);
|
|
128
|
+
const userSkills = getUserSkills(claudeDest);
|
|
129
|
+
|
|
130
|
+
const skillMap = new Map();
|
|
131
|
+
for (const s of userSkills) skillMap.set(s.name, s);
|
|
132
|
+
for (const s of pkgSkills) {
|
|
133
|
+
if (!skillMap.has(s.name)) {
|
|
134
|
+
skillMap.set(s.name, { ...s, enabled: false });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const allSkills = [...skillMap.values()];
|
|
139
|
+
|
|
140
|
+
console.log(`\n${chalk.bold("📋 mdk-skills 技能清单")}\n`);
|
|
141
|
+
console.log(
|
|
142
|
+
` ${chalk.dim("状态 技能名 版本 描述")}`,
|
|
143
|
+
);
|
|
144
|
+
console.log(
|
|
145
|
+
` ${chalk.dim("─────────────────────────────────────────────────────")}`,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
for (const skill of allSkills) {
|
|
149
|
+
const status = skill.enabled ? chalk.green("● 启用") : chalk.gray("○ 停用");
|
|
150
|
+
const name = chalk.white(skill.name.padEnd(20));
|
|
151
|
+
const ver = chalk.dim(skill.version.padEnd(7));
|
|
152
|
+
const desc = skill.description
|
|
153
|
+
? chalk.gray(skill.description)
|
|
154
|
+
: chalk.dim("(无描述)");
|
|
155
|
+
console.log(` ${status} ${name} ${ver} ${desc}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log(
|
|
159
|
+
`\n ${chalk.cyan("💡")} ${chalk.dim("运行 npx mdk-skills 进入交互选择模式")}\n`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------- 交互式菜单(选完即装) ----------
|
|
164
|
+
|
|
165
|
+
async function startInteractiveMenu() {
|
|
166
|
+
const { checkbox } = await import("@inquirer/prompts");
|
|
167
|
+
|
|
168
|
+
if (!fs.existsSync(pkgSkillsSource)) {
|
|
169
|
+
console.log(" ⚠️ 包内没有找到技能文件\n");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const pkgSkills = getPackageSkills(packageDir);
|
|
174
|
+
|
|
175
|
+
if (pkgSkills.length === 0) {
|
|
176
|
+
console.log(" ⚠️ 包内没有可用技能\n");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 读取已安装状态:已装且启用的默认勾选
|
|
181
|
+
const userSkills = getUserSkills(claudeDest);
|
|
182
|
+
const enabledSet = new Set(
|
|
183
|
+
userSkills.filter((s) => s.enabled).map((s) => s.name),
|
|
184
|
+
);
|
|
185
|
+
const installedSet = new Set(userSkills.map((s) => s.name));
|
|
186
|
+
|
|
187
|
+
// 首次运行全部默认勾选(省事),再次运行沿用已有状态
|
|
188
|
+
const hasExistingInstall = fs.existsSync(claudeDest);
|
|
189
|
+
const defaultChecked = hasExistingInstall
|
|
190
|
+
? enabledSet
|
|
191
|
+
: new Set(pkgSkills.map((s) => s.name));
|
|
192
|
+
|
|
193
|
+
const choices = pkgSkills.map((s) => ({
|
|
194
|
+
name: s.name,
|
|
195
|
+
value: s.name,
|
|
196
|
+
description: s.description || undefined,
|
|
197
|
+
checked: defaultChecked.has(s.name),
|
|
198
|
+
}));
|
|
199
|
+
|
|
200
|
+
const selected = await checkbox({
|
|
201
|
+
message: "选择要安装的技能(未勾选的将从 .claude/ 中移除)",
|
|
202
|
+
instructions: "(↑↓ 导航, 空格 开关, Enter 确认)",
|
|
203
|
+
choices,
|
|
204
|
+
pageSize: 15,
|
|
205
|
+
loop: false,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const newCount = selected.filter((name) => !installedSet.has(name)).length;
|
|
209
|
+
const removedCount = [...installedSet].filter(
|
|
210
|
+
(name) => !selected.includes(name),
|
|
211
|
+
).length;
|
|
212
|
+
|
|
213
|
+
const installed = installSelectedSkills(selected);
|
|
214
|
+
|
|
215
|
+
const parts = [];
|
|
216
|
+
if (newCount > 0) parts.push(`新装 ${newCount} 个`);
|
|
217
|
+
if (removedCount > 0) parts.push(`移除 ${removedCount} 个`);
|
|
218
|
+
const summary = parts.length > 0 ? `(${parts.join(",")})` : "";
|
|
219
|
+
|
|
220
|
+
console.log(`\n ✅ 技能安装完成 ${summary}\n`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ---------- 主入口 ----------
|
|
224
|
+
|
|
225
|
+
const COMMANDS = ["list", "enable", "disable"];
|
|
226
|
+
|
|
227
|
+
async function main() {
|
|
228
|
+
const command = process.argv[2];
|
|
229
|
+
const args = process.argv.slice(3);
|
|
230
|
+
|
|
231
|
+
if (!command) {
|
|
232
|
+
await startInteractiveMenu();
|
|
233
|
+
} else if (command === "--help" || command === "-h") {
|
|
234
|
+
console.log(`
|
|
235
|
+
mdk-skills CLI
|
|
236
|
+
|
|
237
|
+
用法:
|
|
238
|
+
npx mdk-skills 交互式选择并安装技能
|
|
239
|
+
npx mdk-skills list 查看已安装的技能
|
|
240
|
+
npx mdk-skills --help 显示帮助
|
|
241
|
+
|
|
242
|
+
首次运行会自动创建 .claude/ 目录,勾选要安装的技能即可
|
|
243
|
+
|
|
244
|
+
示例:
|
|
245
|
+
npx mdk-skills
|
|
246
|
+
npx mdk-skills list
|
|
247
|
+
`);
|
|
248
|
+
} else if (command === "list") {
|
|
249
|
+
await cmdList();
|
|
250
|
+
} else if (command === "enable" || command === "disable") {
|
|
251
|
+
console.log(
|
|
252
|
+
` ⚠️ 该命令已废弃,请直接运行 npx mdk-skills 使用交互菜单\n`,
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
console.log(` 未知命令: ${command}\n 可用: ${COMMANDS.join(", ")}\n`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const {
|
|
4
|
+
backupTimestamp,
|
|
5
|
+
appendLog,
|
|
6
|
+
backupDir,
|
|
7
|
+
copyDirSync,
|
|
8
|
+
installSkills,
|
|
9
|
+
installSettings,
|
|
10
|
+
} = require("./core");
|
|
11
|
+
|
|
12
|
+
// 获取用户项目根目录
|
|
13
|
+
// npm lifecycle 脚本会设置 INIT_CWD 为执行命令时的目录,比从 __dirname 爬三级更可靠
|
|
14
|
+
const projectRoot =
|
|
15
|
+
process.env.INIT_CWD || path.resolve(__dirname, "..", "..", "..");
|
|
16
|
+
const packageDir = path.join(__dirname, "..");
|
|
17
|
+
|
|
18
|
+
// 源路径
|
|
19
|
+
const claudeSource = path.join(packageDir, ".claude");
|
|
20
|
+
const mdSource = path.join(packageDir, "CLAUDE.md");
|
|
21
|
+
|
|
22
|
+
// 目标路径
|
|
23
|
+
const claudeDest = path.join(projectRoot, ".claude");
|
|
24
|
+
const mdDest = path.join(projectRoot, "CLAUDE.md");
|
|
25
|
+
|
|
26
|
+
// 日志文件
|
|
27
|
+
const logFile = path.join(claudeDest, ".install.log");
|
|
28
|
+
|
|
29
|
+
// ===================== 主流程 =====================
|
|
30
|
+
|
|
31
|
+
console.log("\n📦 mdk-skills 技能包安装开始\n");
|
|
32
|
+
|
|
33
|
+
if (fs.existsSync(claudeSource)) {
|
|
34
|
+
if (fs.existsSync(claudeDest)) {
|
|
35
|
+
// .claude 已存在 → 备份后再操作
|
|
36
|
+
appendLog(logFile, "INFO", "Install started (upgrade)");
|
|
37
|
+
backupDir(claudeDest);
|
|
38
|
+
|
|
39
|
+
const skillsSource = path.join(claudeSource, "skills");
|
|
40
|
+
const skillsDest = path.join(claudeDest, "skills");
|
|
41
|
+
|
|
42
|
+
installSkills(skillsSource, skillsDest, logFile);
|
|
43
|
+
installSettings(claudeSource, claudeDest, logFile);
|
|
44
|
+
} else {
|
|
45
|
+
// 全新安装
|
|
46
|
+
appendLog(logFile, "INFO", "Install started (fresh)");
|
|
47
|
+
copyDirSync(claudeSource, claudeDest);
|
|
48
|
+
appendLog(logFile, "INFO", `.claude/ directory created`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 安装 CLAUDE.md
|
|
53
|
+
if (fs.existsSync(mdSource)) {
|
|
54
|
+
if (!fs.existsSync(mdDest)) {
|
|
55
|
+
fs.copyFileSync(mdSource, mdDest);
|
|
56
|
+
appendLog(logFile, "INFO", "CLAUDE.md installed");
|
|
57
|
+
} else {
|
|
58
|
+
const backupsDir = path.join(claudeDest, "backups");
|
|
59
|
+
if (!fs.existsSync(backupsDir)) {
|
|
60
|
+
fs.mkdirSync(backupsDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
const bakName = `CLAUDE.md.${backupTimestamp()}`;
|
|
63
|
+
const bakPath = path.join(backupsDir, bakName);
|
|
64
|
+
fs.copyFileSync(mdDest, bakPath);
|
|
65
|
+
appendLog(
|
|
66
|
+
logFile,
|
|
67
|
+
"BACKUP",
|
|
68
|
+
`backups/${bakName} (CLAUDE.md user version preserved)`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 输出摘要
|
|
74
|
+
console.log("✅ mdk-skills 安装完成!\n");
|
|
75
|
+
|
|
76
|
+
if (fs.existsSync(logFile)) {
|
|
77
|
+
const logs = fs.readFileSync(logFile, "utf-8").trim().split("\n");
|
|
78
|
+
const recent = logs.slice(-10);
|
|
79
|
+
console.log("📋 操作日志:");
|
|
80
|
+
for (const line of recent) {
|
|
81
|
+
console.log(` ${line}`);
|
|
82
|
+
}
|
|
83
|
+
console.log("");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log("💡 提示:运行 npx mdk-skills 可交互选择启用/禁用技能\n");
|