6a-spec-install 1.0.1-dev.1 → 1.0.1-dev.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/README.md +30 -8
- package/bin/6a-spec-install +9 -5
- package/lib/installer.js +151 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,19 +7,32 @@
|
|
|
7
7
|
### 安装
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
# 安装 Cursor
|
|
10
|
+
# 安装 Cursor 配置(默认,完全覆盖模式)
|
|
11
11
|
npx 6a-spec-install
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
npx 6a-spec-install --tool cursor
|
|
13
|
+
# 智能合并模式(推荐,保留用户自定义文件)
|
|
14
|
+
npx 6a-spec-install --tool cursor --merge
|
|
15
15
|
|
|
16
|
-
# 安装 Claude
|
|
17
|
-
npx 6a-spec-install --tool claude
|
|
16
|
+
# 安装 Claude 配置(合并模式)
|
|
17
|
+
npx 6a-spec-install --tool claude --merge
|
|
18
18
|
|
|
19
19
|
# 同时安装两种工具
|
|
20
|
-
npx 6a-spec-install --tool all
|
|
20
|
+
npx 6a-spec-install --tool all --merge
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
### 安装模式
|
|
24
|
+
|
|
25
|
+
#### 完全覆盖模式(默认)
|
|
26
|
+
- 会先备份现有配置到 `.cursor.backup.时间戳`
|
|
27
|
+
- 完全覆盖目标目录
|
|
28
|
+
- 适合首次安装或需要完全重置配置
|
|
29
|
+
|
|
30
|
+
#### 智能合并模式(`--merge`)
|
|
31
|
+
- **只更新包中存在的文件**,保留用户新增的自定义文件
|
|
32
|
+
- 不会创建备份(因为不会删除文件)
|
|
33
|
+
- 适合更新配置时保留自定义修改
|
|
34
|
+
- 会显示更新和新增的文件统计
|
|
35
|
+
|
|
23
36
|
### 全局安装(可选)
|
|
24
37
|
|
|
25
38
|
```bash
|
|
@@ -33,7 +46,8 @@ npm install -g 6a-spec-install
|
|
|
33
46
|
|
|
34
47
|
- ✅ 支持 Cursor IDE
|
|
35
48
|
- ✅ 支持 Claude Desktop
|
|
36
|
-
- ✅
|
|
49
|
+
- ✅ 智能合并模式:保留用户自定义文件,只更新包中文件
|
|
50
|
+
- ✅ 完全覆盖模式:自动备份现有配置后完全覆盖
|
|
37
51
|
- ✅ 一键安装,开箱即用
|
|
38
52
|
|
|
39
53
|
## 目录结构
|
|
@@ -52,10 +66,18 @@ npm install -g 6a-spec-install
|
|
|
52
66
|
## 更新
|
|
53
67
|
|
|
54
68
|
```bash
|
|
55
|
-
#
|
|
69
|
+
# 更新到最新版本(智能合并,推荐)
|
|
70
|
+
npx 6a-spec-install@latest --tool cursor --merge
|
|
71
|
+
|
|
72
|
+
# 更新到最新版本(完全覆盖)
|
|
56
73
|
npx 6a-spec-install@latest --tool cursor
|
|
57
74
|
```
|
|
58
75
|
|
|
76
|
+
**推荐使用 `--merge` 模式**,这样可以:
|
|
77
|
+
- 保留你在 `.cursor/` 目录中自定义的文件
|
|
78
|
+
- 只更新包中提供的文件
|
|
79
|
+
- 不会丢失你的个性化配置
|
|
80
|
+
|
|
59
81
|
## 开发
|
|
60
82
|
|
|
61
83
|
### 本地测试
|
package/bin/6a-spec-install
CHANGED
|
@@ -7,6 +7,7 @@ const installer = require('../lib/installer');
|
|
|
7
7
|
const args = process.argv.slice(2);
|
|
8
8
|
let tool = 'cursor';
|
|
9
9
|
let help = false;
|
|
10
|
+
let mergeMode = false;
|
|
10
11
|
|
|
11
12
|
for (let i = 0; i < args.length; i++) {
|
|
12
13
|
const arg = args[i];
|
|
@@ -14,6 +15,8 @@ for (let i = 0; i < args.length; i++) {
|
|
|
14
15
|
tool = args[++i] || 'cursor';
|
|
15
16
|
} else if (arg === '--help' || arg === '-h') {
|
|
16
17
|
help = true;
|
|
18
|
+
} else if (arg === '--merge' || arg === '-m') {
|
|
19
|
+
mergeMode = true;
|
|
17
20
|
}
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -26,13 +29,14 @@ if (help) {
|
|
|
26
29
|
|
|
27
30
|
选项:
|
|
28
31
|
--tool, -t TOOL 安装目标工具 (cursor/claude/all, 默认: cursor)
|
|
32
|
+
--merge, -m 智能合并模式(保留用户自定义文件,只更新包中文件)
|
|
29
33
|
--help, -h 显示帮助信息
|
|
30
34
|
|
|
31
35
|
示例:
|
|
32
|
-
npx 6a-spec-install --tool cursor
|
|
33
|
-
npx 6a-spec-install --tool
|
|
34
|
-
npx 6a-spec-install --tool
|
|
35
|
-
npx 6a-spec-install
|
|
36
|
+
npx 6a-spec-install --tool cursor # 完全覆盖模式(会先备份)
|
|
37
|
+
npx 6a-spec-install --tool cursor --merge # 智能合并模式(保留自定义文件)
|
|
38
|
+
npx 6a-spec-install --tool claude --merge # 安装 Claude 配置(合并模式)
|
|
39
|
+
npx 6a-spec-install --tool all # 安装两种工具配置
|
|
36
40
|
|
|
37
41
|
支持的工具:
|
|
38
42
|
cursor - 安装 Cursor IDE 的提示词配置
|
|
@@ -43,7 +47,7 @@ if (help) {
|
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
// 执行安装
|
|
46
|
-
installer.install(tool).catch(err => {
|
|
50
|
+
installer.install(tool, mergeMode).catch(err => {
|
|
47
51
|
console.error('❌ 安装失败:', err.message);
|
|
48
52
|
process.exit(1);
|
|
49
53
|
});
|
package/lib/installer.js
CHANGED
|
@@ -6,6 +6,7 @@ class Installer {
|
|
|
6
6
|
// 获取包目录(安装后)
|
|
7
7
|
this.packageDir = this.findPackageDir();
|
|
8
8
|
this.targetDir = process.cwd();
|
|
9
|
+
this.mergeMode = false; // 合并模式标志
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
// 查找包目录(支持本地开发和 npm 安装)
|
|
@@ -50,7 +51,7 @@ class Installer {
|
|
|
50
51
|
return null;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
+
// 递归复制目录(完全覆盖模式)
|
|
54
55
|
copyDir(src, dest) {
|
|
55
56
|
if (!fs.existsSync(dest)) {
|
|
56
57
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -70,6 +71,60 @@ class Installer {
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
// 智能合并目录(只更新包中存在的文件,保留用户自定义文件)
|
|
75
|
+
mergeDir(src, dest) {
|
|
76
|
+
if (!fs.existsSync(dest)) {
|
|
77
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
81
|
+
let updatedCount = 0;
|
|
82
|
+
let addedCount = 0;
|
|
83
|
+
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
const srcPath = path.join(src, entry.name);
|
|
86
|
+
const destPath = path.join(dest, entry.name);
|
|
87
|
+
|
|
88
|
+
if (entry.isDirectory()) {
|
|
89
|
+
const result = this.mergeDir(srcPath, destPath);
|
|
90
|
+
updatedCount += result.updated;
|
|
91
|
+
addedCount += result.added;
|
|
92
|
+
} else {
|
|
93
|
+
const exists = fs.existsSync(destPath);
|
|
94
|
+
fs.copyFileSync(srcPath, destPath);
|
|
95
|
+
if (exists) {
|
|
96
|
+
updatedCount++;
|
|
97
|
+
} else {
|
|
98
|
+
addedCount++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { updated: updatedCount, added: addedCount };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 获取目录中所有文件的相对路径列表
|
|
107
|
+
getAllFiles(dir, baseDir = dir) {
|
|
108
|
+
const files = [];
|
|
109
|
+
if (!fs.existsSync(dir)) {
|
|
110
|
+
return files;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const fullPath = path.join(dir, entry.name);
|
|
116
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
117
|
+
|
|
118
|
+
if (entry.isDirectory()) {
|
|
119
|
+
files.push(...this.getAllFiles(fullPath, baseDir));
|
|
120
|
+
} else {
|
|
121
|
+
files.push(relativePath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return files;
|
|
126
|
+
}
|
|
127
|
+
|
|
73
128
|
// 安装 Cursor 配置
|
|
74
129
|
installCursor() {
|
|
75
130
|
this.log('开始安装 Cursor 配置...');
|
|
@@ -81,10 +136,35 @@ class Installer {
|
|
|
81
136
|
throw new Error('未找到 .cursor 源目录');
|
|
82
137
|
}
|
|
83
138
|
|
|
84
|
-
|
|
139
|
+
const targetExists = fs.existsSync(targetDir);
|
|
85
140
|
|
|
86
|
-
this.
|
|
87
|
-
|
|
141
|
+
if (this.mergeMode && targetExists) {
|
|
142
|
+
// 智能合并模式
|
|
143
|
+
this.log('使用智能合并模式(保留用户自定义文件)...');
|
|
144
|
+
|
|
145
|
+
// 统计用户自定义文件
|
|
146
|
+
const sourceFiles = new Set(this.getAllFiles(sourceDir, sourceDir));
|
|
147
|
+
const targetFiles = this.getAllFiles(targetDir, targetDir);
|
|
148
|
+
const customFiles = targetFiles.filter(f => !sourceFiles.has(f));
|
|
149
|
+
|
|
150
|
+
if (customFiles.length > 0) {
|
|
151
|
+
this.log(`检测到 ${customFiles.length} 个用户自定义文件,将保留`, 'info');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = this.mergeDir(sourceDir, targetDir);
|
|
155
|
+
this.log(`更新了 ${result.updated} 个文件,新增了 ${result.added} 个文件`, 'info');
|
|
156
|
+
|
|
157
|
+
if (customFiles.length > 0) {
|
|
158
|
+
this.log(`保留了 ${customFiles.length} 个用户自定义文件`, 'info');
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
// 完全覆盖模式
|
|
162
|
+
if (targetExists) {
|
|
163
|
+
this.backupDir(targetDir);
|
|
164
|
+
}
|
|
165
|
+
this.log('复制 Cursor 配置文件...');
|
|
166
|
+
this.copyDir(sourceDir, targetDir);
|
|
167
|
+
}
|
|
88
168
|
|
|
89
169
|
this.log('✓ Cursor 配置安装完成!', 'success');
|
|
90
170
|
}
|
|
@@ -100,44 +180,90 @@ class Installer {
|
|
|
100
180
|
throw new Error('未找到源配置目录');
|
|
101
181
|
}
|
|
102
182
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.log('转换并复制 Claude 配置文件...');
|
|
183
|
+
const targetExists = fs.existsSync(targetDir);
|
|
106
184
|
|
|
107
185
|
// 创建目标目录结构
|
|
108
186
|
if (!fs.existsSync(targetDir)) {
|
|
109
187
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
110
188
|
}
|
|
111
189
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
190
|
+
if (this.mergeMode && targetExists) {
|
|
191
|
+
// 智能合并模式
|
|
192
|
+
this.log('使用智能合并模式(保留用户自定义文件)...');
|
|
193
|
+
|
|
194
|
+
// 复制 commands 到 prompts
|
|
195
|
+
const commandsDir = path.join(sourceDir, 'commands');
|
|
196
|
+
if (fs.existsSync(commandsDir)) {
|
|
197
|
+
const promptsDir = path.join(targetDir, 'prompts');
|
|
198
|
+
const result = this.mergeDir(commandsDir, promptsDir);
|
|
199
|
+
if (result.updated > 0 || result.added > 0) {
|
|
200
|
+
this.log(`prompts: 更新了 ${result.updated} 个文件,新增了 ${result.added} 个文件`, 'info');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
118
203
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
204
|
+
// 复制 rules
|
|
205
|
+
const rulesDir = path.join(sourceDir, 'rules');
|
|
206
|
+
if (fs.existsSync(rulesDir)) {
|
|
207
|
+
const targetRulesDir = path.join(targetDir, 'rules');
|
|
208
|
+
const result = this.mergeDir(rulesDir, targetRulesDir);
|
|
209
|
+
if (result.updated > 0 || result.added > 0) {
|
|
210
|
+
this.log(`rules: 更新了 ${result.updated} 个文件,新增了 ${result.added} 个文件`, 'info');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 复制 scripts
|
|
215
|
+
const scriptDir = path.join(sourceDir, 'script');
|
|
216
|
+
if (fs.existsSync(scriptDir)) {
|
|
217
|
+
const targetScriptDir = path.join(targetDir, 'script');
|
|
218
|
+
const result = this.mergeDir(scriptDir, targetScriptDir);
|
|
219
|
+
if (result.updated > 0 || result.added > 0) {
|
|
220
|
+
this.log(`script: 更新了 ${result.updated} 个文件,新增了 ${result.added} 个文件`, 'info');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
// 完全覆盖模式
|
|
225
|
+
if (targetExists) {
|
|
226
|
+
this.backupDir(targetDir);
|
|
227
|
+
}
|
|
228
|
+
this.log('转换并复制 Claude 配置文件...');
|
|
229
|
+
|
|
230
|
+
// 复制 commands 到 prompts
|
|
231
|
+
const commandsDir = path.join(sourceDir, 'commands');
|
|
232
|
+
if (fs.existsSync(commandsDir)) {
|
|
233
|
+
const promptsDir = path.join(targetDir, 'prompts');
|
|
234
|
+
this.copyDir(commandsDir, promptsDir);
|
|
235
|
+
}
|
|
125
236
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
237
|
+
// 复制 rules
|
|
238
|
+
const rulesDir = path.join(sourceDir, 'rules');
|
|
239
|
+
if (fs.existsSync(rulesDir)) {
|
|
240
|
+
const targetRulesDir = path.join(targetDir, 'rules');
|
|
241
|
+
this.copyDir(rulesDir, targetRulesDir);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 复制 scripts
|
|
245
|
+
const scriptDir = path.join(sourceDir, 'script');
|
|
246
|
+
if (fs.existsSync(scriptDir)) {
|
|
247
|
+
const targetScriptDir = path.join(targetDir, 'script');
|
|
248
|
+
this.copyDir(scriptDir, targetScriptDir);
|
|
249
|
+
}
|
|
131
250
|
}
|
|
132
251
|
|
|
133
252
|
this.log('✓ Claude 配置安装完成!', 'success');
|
|
134
253
|
}
|
|
135
254
|
|
|
136
255
|
// 主安装方法
|
|
137
|
-
async install(tool = 'cursor') {
|
|
256
|
+
async install(tool = 'cursor', mergeMode = false) {
|
|
257
|
+
this.mergeMode = mergeMode;
|
|
258
|
+
|
|
138
259
|
this.log(`6A-spec 安装工具`);
|
|
139
260
|
this.log(`目标目录: ${this.targetDir}`);
|
|
140
261
|
this.log(`工具: ${tool}`);
|
|
262
|
+
if (mergeMode) {
|
|
263
|
+
this.log(`模式: 智能合并(保留用户自定义文件)`, 'info');
|
|
264
|
+
} else {
|
|
265
|
+
this.log(`模式: 完全覆盖(会先备份现有配置)`, 'info');
|
|
266
|
+
}
|
|
141
267
|
|
|
142
268
|
try {
|
|
143
269
|
switch (tool.toLowerCase()) {
|