agent-configs 1.0.0
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 +223 -0
- package/agents/architect.md +211 -0
- package/agents/code-reviewer.md +104 -0
- package/agents/planner.md +119 -0
- package/agents/refactor-cleaner.md +306 -0
- package/agents/security-reviewer.md +545 -0
- package/agents/tdd-guide.md +280 -0
- package/bundles/bk-chat-bundle/README.md +48 -0
- package/bundles/bk-chat-bundle/manifest.json +10 -0
- package/bundles/continuous-learning/.claude/commands/evolve.md +190 -0
- package/bundles/continuous-learning/.claude/commands/instinct-status.md +64 -0
- package/bundles/continuous-learning/.claude/commands/learn.md +83 -0
- package/bundles/continuous-learning/.claude/hooks/learning-end.js +85 -0
- package/bundles/continuous-learning/.claude/hooks/observe.js +131 -0
- package/bundles/continuous-learning/.claude/lib/learning.js +559 -0
- package/bundles/continuous-learning/.claude/lib/utils.js +312 -0
- package/bundles/continuous-learning/.claude/skills/continuous-learning/SKILL.md +200 -0
- package/bundles/continuous-learning/.cursor/hooks/learning-end.js +102 -0
- package/bundles/continuous-learning/.cursor/rules/continuous-learning.mdc +34 -0
- package/bundles/continuous-learning/.cursor/skills/continuous-learning/SKILL.md +77 -0
- package/bundles/continuous-learning/README.md +159 -0
- package/bundles/continuous-learning/manifest.json +51 -0
- package/bundles/planning-bundle/README.md +34 -0
- package/bundles/planning-bundle/manifest.json +10 -0
- package/bundles/review-bundle/README.md +43 -0
- package/bundles/review-bundle/manifest.json +11 -0
- package/bundles/shared-memory/.claude/commands/list-sessions.md +124 -0
- package/bundles/shared-memory/.claude/commands/load-session.md +169 -0
- package/bundles/shared-memory/.claude/commands/save-session.md +137 -0
- package/bundles/shared-memory/.claude/hooks/memory-compact.js +43 -0
- package/bundles/shared-memory/.claude/hooks/memory-end.js +42 -0
- package/bundles/shared-memory/.claude/hooks/memory-start.js +59 -0
- package/bundles/shared-memory/.claude/lib/memory.js +416 -0
- package/bundles/shared-memory/.claude/lib/utils.js +209 -0
- package/bundles/shared-memory/.claude/skills/shared-memory/SKILL.md +183 -0
- package/bundles/shared-memory/.cursor/hooks/memory-start.js +42 -0
- package/bundles/shared-memory/.cursor/rules/shared-memory.mdc +37 -0
- package/bundles/shared-memory/.cursor/skills/shared-memory/SKILL.md +183 -0
- package/bundles/tdd-bundle/README.md +33 -0
- package/bundles/tdd-bundle/manifest.json +10 -0
- package/cli.js +978 -0
- package/commands/build-fix.md +29 -0
- package/commands/code-review.md +40 -0
- package/commands/e2e.md +363 -0
- package/commands/learn.md +114 -0
- package/commands/plan.md +113 -0
- package/commands/refactor-clean.md +28 -0
- package/commands/tdd.md +326 -0
- package/commands/test-coverage.md +27 -0
- package/commands/update-codemaps.md +17 -0
- package/commands/update-docs.md +31 -0
- package/configs.json +158 -0
- package/hooks/hooks.json +101 -0
- package/package.json +58 -0
- package/rules/agents.md +49 -0
- package/rules/coding-style.md +70 -0
- package/rules/git-workflow.md +45 -0
- package/rules/hooks.md +46 -0
- package/rules/patterns.md +55 -0
- package/rules/performance.md +47 -0
- package/rules/security.md +36 -0
- package/rules/testing.md +30 -0
- package/skills/ai-config-architect/SKILL.md +59 -0
- package/skills/ai-config-architect/references/agents.md +77 -0
- package/skills/ai-config-architect/references/commands.md +66 -0
- package/skills/ai-config-architect/references/hooks.md +70 -0
- package/skills/ai-config-architect/references/patterns.md +66 -0
- package/skills/ai-config-architect/references/platforms.md +82 -0
- package/skills/ai-config-architect/references/rules.md +66 -0
- package/skills/ai-config-architect/references/skills.md +67 -0
- package/skills/bk-chat-helper/SKILL.md +398 -0
- package/skills/bk-chat-helper/references/api-reference.md +606 -0
- package/skills/bk-chat-helper/references/examples.md +789 -0
- package/skills/bk-chat-helper/references/integration-guide.md +583 -0
- package/skills/bk-chat-x/SKILL.md +400 -0
- package/skills/bk-chat-x/references/components-api.md +340 -0
- package/skills/bk-chat-x/references/examples.md +386 -0
- package/skills/bk-chat-x/references/shortcuts-guide.md +375 -0
- package/skills/coding-standards/SKILL.md +523 -0
- package/skills/security-review/SKILL.md +497 -0
- package/skills/security-review/references/cloud-infrastructure-security.md +361 -0
- package/skills/strategic-compact/SKILL.md +66 -0
- package/skills/strategic-compact/scripts/suggest-compact.sh +52 -0
- package/skills/tdd-workflow/SKILL.md +412 -0
- package/skills/verification-loop/SKILL.md +128 -0
package/cli.js
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* agent-configs CLI
|
|
5
|
+
*
|
|
6
|
+
* Interactive CLI tool for installing Claude Code and Cursor configurations.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx agent-configs # Interactive mode
|
|
10
|
+
* npx agent-configs list # Interactive category browser
|
|
11
|
+
* npx agent-configs install <name> [--agent <platform>] [--scope <scope>]
|
|
12
|
+
* npx agent-configs uninstall <name> [--agent <platform>]
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
const readline = require('readline');
|
|
19
|
+
const { select, Separator } = require('@inquirer/prompts');
|
|
20
|
+
|
|
21
|
+
// Terminal colors
|
|
22
|
+
const colors = {
|
|
23
|
+
reset: '\x1b[0m',
|
|
24
|
+
bold: '\x1b[1m',
|
|
25
|
+
dim: '\x1b[2m',
|
|
26
|
+
green: '\x1b[32m',
|
|
27
|
+
yellow: '\x1b[33m',
|
|
28
|
+
blue: '\x1b[34m',
|
|
29
|
+
cyan: '\x1b[36m',
|
|
30
|
+
red: '\x1b[31m',
|
|
31
|
+
magenta: '\x1b[35m',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Load configs.json
|
|
35
|
+
function loadConfigs() {
|
|
36
|
+
const configsPath = path.join(__dirname, 'configs.json');
|
|
37
|
+
return JSON.parse(fs.readFileSync(configsPath, 'utf8'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Platform paths
|
|
41
|
+
const PLATFORM_PATHS = {
|
|
42
|
+
claude: {
|
|
43
|
+
global: {
|
|
44
|
+
commands: path.join(os.homedir(), '.claude', 'commands'),
|
|
45
|
+
skills: path.join(os.homedir(), '.claude', 'skills'),
|
|
46
|
+
agents: path.join(os.homedir(), '.claude', 'agents'),
|
|
47
|
+
settings: path.join(os.homedir(), '.claude', 'settings.json'),
|
|
48
|
+
},
|
|
49
|
+
project: {
|
|
50
|
+
commands: '.claude/commands',
|
|
51
|
+
skills: '.claude/skills',
|
|
52
|
+
agents: '.claude/agents',
|
|
53
|
+
settings: '.claude/settings.json',
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
cursor: {
|
|
57
|
+
global: {
|
|
58
|
+
commands: path.join(os.homedir(), '.cursor', 'commands'),
|
|
59
|
+
skills: path.join(os.homedir(), '.cursor', 'skills'),
|
|
60
|
+
agents: path.join(os.homedir(), '.cursor', 'agents'),
|
|
61
|
+
},
|
|
62
|
+
project: {
|
|
63
|
+
commands: '.cursor/commands',
|
|
64
|
+
skills: '.cursor/skills',
|
|
65
|
+
agents: '.cursor/agents',
|
|
66
|
+
rules: '.cursor/rules',
|
|
67
|
+
hooks: '.cursor/hooks.json',
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Copy file or directory
|
|
73
|
+
function copyRecursive(src, dest) {
|
|
74
|
+
const stat = fs.statSync(src);
|
|
75
|
+
|
|
76
|
+
if (stat.isDirectory()) {
|
|
77
|
+
if (!fs.existsSync(dest)) {
|
|
78
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
const entries = fs.readdirSync(src);
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
copyRecursive(path.join(src, entry), path.join(dest, entry));
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
const destDir = path.dirname(dest);
|
|
86
|
+
if (!fs.existsSync(destDir)) {
|
|
87
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
fs.copyFileSync(src, dest);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Merge JSON files (for hooks/settings)
|
|
94
|
+
function mergeJson(targetPath, sourceData) {
|
|
95
|
+
let existing = {};
|
|
96
|
+
if (fs.existsSync(targetPath)) {
|
|
97
|
+
try {
|
|
98
|
+
existing = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
99
|
+
} catch (e) {
|
|
100
|
+
existing = {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Deep merge
|
|
105
|
+
function deepMerge(target, source) {
|
|
106
|
+
for (const key in source) {
|
|
107
|
+
if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
|
108
|
+
// Merge arrays, avoiding duplicates by description
|
|
109
|
+
const existingDescs = new Set(target[key].map(h => h.description || JSON.stringify(h)));
|
|
110
|
+
for (const item of source[key]) {
|
|
111
|
+
const desc = item.description || JSON.stringify(item);
|
|
112
|
+
if (!existingDescs.has(desc)) {
|
|
113
|
+
target[key].push(item);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} else if (typeof source[key] === 'object' && source[key] !== null && typeof target[key] === 'object' && target[key] !== null) {
|
|
117
|
+
deepMerge(target[key], source[key]);
|
|
118
|
+
} else {
|
|
119
|
+
target[key] = source[key];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return target;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const merged = deepMerge(existing, sourceData);
|
|
126
|
+
const destDir = path.dirname(targetPath);
|
|
127
|
+
if (!fs.existsSync(destDir)) {
|
|
128
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
fs.writeFileSync(targetPath, JSON.stringify(merged, null, 2));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Delete file or directory
|
|
134
|
+
function deleteRecursive(targetPath) {
|
|
135
|
+
if (!fs.existsSync(targetPath)) return false;
|
|
136
|
+
|
|
137
|
+
const stat = fs.statSync(targetPath);
|
|
138
|
+
if (stat.isDirectory()) {
|
|
139
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
140
|
+
} else {
|
|
141
|
+
fs.unlinkSync(targetPath);
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Find config item by name
|
|
147
|
+
function findConfig(configs, name) {
|
|
148
|
+
for (const category of configs.categories) {
|
|
149
|
+
for (const item of category.items) {
|
|
150
|
+
if (item.name === name) {
|
|
151
|
+
return { category, item };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// List command (static output)
|
|
159
|
+
function listConfigsStatic(options = {}) {
|
|
160
|
+
const configs = loadConfigs();
|
|
161
|
+
const { category: filterCategory } = options;
|
|
162
|
+
|
|
163
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} - Claude Code & Cursor 配置共享工具\n`);
|
|
164
|
+
|
|
165
|
+
for (const category of configs.categories) {
|
|
166
|
+
if (filterCategory && category.id !== filterCategory) continue;
|
|
167
|
+
|
|
168
|
+
console.log(`${colors.bold}${colors.blue}${category.name}${colors.reset} (${category.items.length})`);
|
|
169
|
+
console.log(`${colors.dim}${category.description}${colors.reset}`);
|
|
170
|
+
|
|
171
|
+
if (category.id !== 'bundles') {
|
|
172
|
+
console.log(`${colors.dim}平台: ${(category.platforms || ['claude', 'cursor']).join(', ')}${colors.reset}`);
|
|
173
|
+
}
|
|
174
|
+
console.log();
|
|
175
|
+
|
|
176
|
+
for (const item of category.items) {
|
|
177
|
+
const featured = item.featured ? `${colors.yellow}★${colors.reset} ` : ' ';
|
|
178
|
+
const tags = item.tags ? ` ${colors.dim}[${item.tags.join(', ')}]${colors.reset}` : '';
|
|
179
|
+
console.log(` ${featured}${colors.green}${item.name}${colors.reset} - ${item.description}${tags}`);
|
|
180
|
+
}
|
|
181
|
+
console.log();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(`${colors.dim}使用 ${colors.cyan}npx agent-configs install <name>${colors.dim} 安装配置${colors.reset}`);
|
|
185
|
+
console.log(`${colors.dim}使用 ${colors.cyan}npx agent-configs list --category bundles${colors.dim} 查看特定类别${colors.reset}\n`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Custom select menu with Esc support - optimized for performance
|
|
189
|
+
async function customSelect({ message, choices, pageSize = 10 }) {
|
|
190
|
+
return new Promise((resolve) => {
|
|
191
|
+
let selectedIndex = 0;
|
|
192
|
+
const items = choices.filter(c => c.value !== undefined);
|
|
193
|
+
const allItems = choices;
|
|
194
|
+
|
|
195
|
+
// Pre-calculate selectable indices
|
|
196
|
+
const selectableIndices = [];
|
|
197
|
+
allItems.forEach((item, idx) => {
|
|
198
|
+
if (item.value !== undefined) {
|
|
199
|
+
selectableIndices.push(idx);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Pre-build all line variants (selected and unselected)
|
|
204
|
+
const headerLine = `${colors.cyan}?${colors.reset} ${colors.bold}${message}${colors.reset}`;
|
|
205
|
+
const footerLine = `${colors.dim}↑↓ 导航 • ⏎ 确认 • Esc 返回${colors.reset}`;
|
|
206
|
+
const separatorLine = `${colors.dim}──────────────${colors.reset}`;
|
|
207
|
+
|
|
208
|
+
const normalLines = [];
|
|
209
|
+
const selectedLines = [];
|
|
210
|
+
const descriptions = [];
|
|
211
|
+
|
|
212
|
+
allItems.forEach((item, idx) => {
|
|
213
|
+
if (item.value === undefined) {
|
|
214
|
+
normalLines.push(separatorLine);
|
|
215
|
+
selectedLines.push(separatorLine);
|
|
216
|
+
descriptions.push('');
|
|
217
|
+
} else {
|
|
218
|
+
normalLines.push(` ${item.name}`);
|
|
219
|
+
selectedLines.push(`${colors.cyan}❯ ${item.name}${colors.reset}`);
|
|
220
|
+
descriptions.push(item.description ? `${colors.dim}${item.description}${colors.reset}` : '');
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const totalLines = allItems.length + 3;
|
|
225
|
+
|
|
226
|
+
// Build complete output buffer
|
|
227
|
+
const buildOutput = () => {
|
|
228
|
+
const lines = [headerLine];
|
|
229
|
+
for (let i = 0; i < allItems.length; i++) {
|
|
230
|
+
lines.push(selectableIndices[selectedIndex] === i ? selectedLines[i] : normalLines[i]);
|
|
231
|
+
}
|
|
232
|
+
lines.push(descriptions[selectableIndices[selectedIndex]]);
|
|
233
|
+
lines.push(footerLine);
|
|
234
|
+
return lines.join('\n');
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const render = (isFirst = false) => {
|
|
238
|
+
if (!isFirst) {
|
|
239
|
+
process.stdout.write(`\x1b[${totalLines}A\x1b[J`);
|
|
240
|
+
}
|
|
241
|
+
process.stdout.write(buildOutput() + '\n');
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Setup keyboard input - use raw data handler for faster Esc response
|
|
245
|
+
if (process.stdin.isTTY) {
|
|
246
|
+
process.stdin.setRawMode(true);
|
|
247
|
+
}
|
|
248
|
+
process.stdin.resume();
|
|
249
|
+
|
|
250
|
+
// Direct data handler - faster than readline keypress events for Esc
|
|
251
|
+
const dataHandler = (data) => {
|
|
252
|
+
const input = data.toString();
|
|
253
|
+
|
|
254
|
+
// Esc key (single byte 0x1b, not followed by [ for escape sequences)
|
|
255
|
+
if (input === '\x1b' || input === '\u001b') {
|
|
256
|
+
cleanup();
|
|
257
|
+
resolve('__escape__');
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Arrow keys: Esc + [ + A/B/C/D
|
|
262
|
+
if (input === '\x1b[A' || input === '\u001b[A') { // Up
|
|
263
|
+
if (selectedIndex > 0) {
|
|
264
|
+
selectedIndex--;
|
|
265
|
+
render();
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (input === '\x1b[B' || input === '\u001b[B') { // Down
|
|
270
|
+
if (selectedIndex < items.length - 1) {
|
|
271
|
+
selectedIndex++;
|
|
272
|
+
render();
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Enter key
|
|
278
|
+
if (input === '\r' || input === '\n') {
|
|
279
|
+
cleanup();
|
|
280
|
+
resolve(items[selectedIndex].value);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// k/j for vim-style navigation
|
|
285
|
+
if (input === 'k') {
|
|
286
|
+
if (selectedIndex > 0) {
|
|
287
|
+
selectedIndex--;
|
|
288
|
+
render();
|
|
289
|
+
}
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (input === 'j') {
|
|
293
|
+
if (selectedIndex < items.length - 1) {
|
|
294
|
+
selectedIndex++;
|
|
295
|
+
render();
|
|
296
|
+
}
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Ctrl+C
|
|
301
|
+
if (input === '\x03') {
|
|
302
|
+
cleanup();
|
|
303
|
+
process.exit(0);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const cleanup = () => {
|
|
308
|
+
process.stdin.removeListener('data', dataHandler);
|
|
309
|
+
if (process.stdin.isTTY) {
|
|
310
|
+
process.stdin.setRawMode(false);
|
|
311
|
+
}
|
|
312
|
+
process.stdin.pause();
|
|
313
|
+
process.stdout.write('\x1b[?25h');
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
process.stdin.on('data', dataHandler);
|
|
317
|
+
process.stdout.write('\x1b[?25l');
|
|
318
|
+
render(true);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Interactive menu - Main category selection
|
|
323
|
+
async function interactiveMenu(options = {}) {
|
|
324
|
+
const configs = loadConfigs();
|
|
325
|
+
|
|
326
|
+
console.clear();
|
|
327
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} - Claude Code & Cursor 配置共享工具\n`);
|
|
328
|
+
console.log(`${colors.dim}使用 ↑↓ 选择,Enter 进入,Esc 退出${colors.reset}\n`);
|
|
329
|
+
|
|
330
|
+
while (true) {
|
|
331
|
+
try {
|
|
332
|
+
// Build category choices
|
|
333
|
+
const categoryChoices = configs.categories.map(cat => {
|
|
334
|
+
const featuredCount = cat.items.filter(i => i.featured).length;
|
|
335
|
+
const featuredMark = featuredCount > 0 ? ` ${colors.yellow}★${featuredCount}${colors.reset}` : '';
|
|
336
|
+
const platformInfo = cat.id !== 'bundles' && cat.platforms
|
|
337
|
+
? ` ${colors.dim}(${cat.platforms.join('/')})${colors.reset}`
|
|
338
|
+
: '';
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
name: `${colors.blue}${cat.name}${colors.reset} (${cat.items.length})${featuredMark}${platformInfo}`,
|
|
342
|
+
value: cat.id,
|
|
343
|
+
description: cat.description
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
categoryChoices.push(new Separator());
|
|
348
|
+
categoryChoices.push({
|
|
349
|
+
name: `${colors.dim}退出${colors.reset}`,
|
|
350
|
+
value: '__exit__'
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const selectedCategory = await customSelect({
|
|
354
|
+
message: '选择类别',
|
|
355
|
+
choices: categoryChoices,
|
|
356
|
+
pageSize: 10
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
if (selectedCategory === '__exit__' || selectedCategory === '__escape__') {
|
|
360
|
+
console.log(`\n${colors.dim}再见!${colors.reset}\n`);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Enter category submenu
|
|
365
|
+
await categorySubMenu(configs, selectedCategory, options);
|
|
366
|
+
|
|
367
|
+
} catch (error) {
|
|
368
|
+
if (error.message?.includes('User force closed') || error.name === 'ExitPromptError') {
|
|
369
|
+
console.log(`\n${colors.dim}再见!${colors.reset}\n`);
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Interactive menu - Category items
|
|
378
|
+
async function categorySubMenu(configs, categoryId, options = {}) {
|
|
379
|
+
const category = configs.categories.find(c => c.id === categoryId);
|
|
380
|
+
if (!category) return;
|
|
381
|
+
|
|
382
|
+
while (true) {
|
|
383
|
+
try {
|
|
384
|
+
console.clear();
|
|
385
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} > ${colors.blue}${category.name}${colors.reset}\n`);
|
|
386
|
+
console.log(`${colors.dim}${category.description}${colors.reset}`);
|
|
387
|
+
if (category.id !== 'bundles' && category.platforms) {
|
|
388
|
+
console.log(`${colors.dim}平台: ${category.platforms.join(', ')}${colors.reset}`);
|
|
389
|
+
}
|
|
390
|
+
console.log(`${colors.dim}使用 ↑↓ 选择,Enter 安装,Esc 返回${colors.reset}\n`);
|
|
391
|
+
|
|
392
|
+
// Build item choices
|
|
393
|
+
const itemChoices = category.items.map(item => {
|
|
394
|
+
const featured = item.featured ? `${colors.yellow}★${colors.reset} ` : ' ';
|
|
395
|
+
const tags = item.tags ? ` ${colors.dim}[${item.tags.join(', ')}]${colors.reset}` : '';
|
|
396
|
+
|
|
397
|
+
return {
|
|
398
|
+
name: `${featured}${colors.green}${item.name}${colors.reset}${tags}`,
|
|
399
|
+
value: item.name,
|
|
400
|
+
description: item.description
|
|
401
|
+
};
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
itemChoices.push(new Separator());
|
|
405
|
+
itemChoices.push({
|
|
406
|
+
name: `${colors.dim}← 返回${colors.reset}`,
|
|
407
|
+
value: '__back__'
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
const selectedItem = await customSelect({
|
|
411
|
+
message: `选择配置`,
|
|
412
|
+
choices: itemChoices,
|
|
413
|
+
pageSize: 15
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
if (selectedItem === '__back__' || selectedItem === '__escape__') {
|
|
417
|
+
console.clear();
|
|
418
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} - Claude Code & Cursor 配置共享工具\n`);
|
|
419
|
+
console.log(`${colors.dim}使用 ↑↓ 选择,Enter 进入,Esc 退出${colors.reset}\n`);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Show install options
|
|
424
|
+
await installSubMenu(selectedItem, category, options);
|
|
425
|
+
|
|
426
|
+
} catch (error) {
|
|
427
|
+
if (error.message?.includes('User force closed') || error.name === 'ExitPromptError') {
|
|
428
|
+
console.clear();
|
|
429
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} - Claude Code & Cursor 配置共享工具\n`);
|
|
430
|
+
console.log(`${colors.dim}使用 ↑↓ 选择,Enter 进入,Esc 退出${colors.reset}\n`);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Interactive menu - Install options
|
|
439
|
+
async function installSubMenu(itemName, category, options = {}) {
|
|
440
|
+
const item = category.items.find(i => i.name === itemName);
|
|
441
|
+
if (!item) return;
|
|
442
|
+
|
|
443
|
+
try {
|
|
444
|
+
console.clear();
|
|
445
|
+
console.log(`\n${colors.bold}${colors.cyan}agent-configs${colors.reset} > ${colors.blue}${category.name}${colors.reset} > ${colors.green}${item.name}${colors.reset}\n`);
|
|
446
|
+
console.log(`${colors.dim}${item.description}${colors.reset}`);
|
|
447
|
+
if (item.tags) {
|
|
448
|
+
console.log(`${colors.dim}标签: ${item.tags.join(', ')}${colors.reset}`);
|
|
449
|
+
}
|
|
450
|
+
if (item.includes) {
|
|
451
|
+
console.log(`${colors.dim}包含: ${item.includes.join(', ')}${colors.reset}`);
|
|
452
|
+
}
|
|
453
|
+
console.log();
|
|
454
|
+
|
|
455
|
+
// Build action choices based on category
|
|
456
|
+
const actionChoices = [];
|
|
457
|
+
|
|
458
|
+
// Determine available platforms
|
|
459
|
+
const platforms = category.platforms || ['claude', 'cursor'];
|
|
460
|
+
|
|
461
|
+
if (platforms.includes('cursor')) {
|
|
462
|
+
actionChoices.push({
|
|
463
|
+
name: `${colors.green}安装到 Cursor${colors.reset} ${colors.dim}(项目级别)${colors.reset}`,
|
|
464
|
+
value: 'install_cursor_project'
|
|
465
|
+
});
|
|
466
|
+
actionChoices.push({
|
|
467
|
+
name: `${colors.cyan}安装到 Cursor${colors.reset} ${colors.dim}(全局)${colors.reset}`,
|
|
468
|
+
value: 'install_cursor_global'
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (platforms.includes('claude')) {
|
|
473
|
+
actionChoices.push({
|
|
474
|
+
name: `${colors.green}安装到 Claude Code${colors.reset} ${colors.dim}(项目级别)${colors.reset}`,
|
|
475
|
+
value: 'install_claude_project'
|
|
476
|
+
});
|
|
477
|
+
actionChoices.push({
|
|
478
|
+
name: `${colors.cyan}安装到 Claude Code${colors.reset} ${colors.dim}(全局)${colors.reset}`,
|
|
479
|
+
value: 'install_claude_global'
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (platforms.length === 2) {
|
|
484
|
+
actionChoices.push(new Separator());
|
|
485
|
+
actionChoices.push({
|
|
486
|
+
name: `${colors.magenta}安装到所有平台${colors.reset} ${colors.dim}(项目级别)${colors.reset}`,
|
|
487
|
+
value: 'install_all_project'
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
actionChoices.push(new Separator());
|
|
492
|
+
actionChoices.push({
|
|
493
|
+
name: `${colors.dim}← 返回${colors.reset}`,
|
|
494
|
+
value: '__back__'
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
const action = await customSelect({
|
|
498
|
+
message: '选择操作',
|
|
499
|
+
choices: actionChoices,
|
|
500
|
+
pageSize: 10
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
if (action === '__back__' || action === '__escape__') {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Parse action
|
|
508
|
+
const [, platform, scope] = action.split('_');
|
|
509
|
+
|
|
510
|
+
console.log();
|
|
511
|
+
installConfig(item.name, {
|
|
512
|
+
agent: platform,
|
|
513
|
+
scope: scope,
|
|
514
|
+
...options
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Wait for user to see result
|
|
518
|
+
console.log(`${colors.dim}按任意键继续...${colors.reset}`);
|
|
519
|
+
await waitForKey();
|
|
520
|
+
|
|
521
|
+
} catch (error) {
|
|
522
|
+
if (error.message?.includes('User force closed') || error.name === 'ExitPromptError') {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Wait for any key press
|
|
530
|
+
function waitForKey() {
|
|
531
|
+
return new Promise(resolve => {
|
|
532
|
+
if (process.stdin.isTTY) {
|
|
533
|
+
process.stdin.setRawMode(true);
|
|
534
|
+
process.stdin.resume();
|
|
535
|
+
process.stdin.once('data', () => {
|
|
536
|
+
process.stdin.setRawMode(false);
|
|
537
|
+
process.stdin.pause();
|
|
538
|
+
resolve();
|
|
539
|
+
});
|
|
540
|
+
} else {
|
|
541
|
+
resolve();
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Install command
|
|
547
|
+
function installConfig(name, options = {}) {
|
|
548
|
+
const configs = loadConfigs();
|
|
549
|
+
const platform = options.agent || configs.defaultPlatform || 'cursor';
|
|
550
|
+
const scope = options.scope || configs.defaultScope || 'project';
|
|
551
|
+
const dryRun = options.dryRun || false;
|
|
552
|
+
|
|
553
|
+
// Handle 'all' platform
|
|
554
|
+
const platforms = platform === 'all' ? ['claude', 'cursor'] : [platform];
|
|
555
|
+
|
|
556
|
+
// Find config
|
|
557
|
+
const found = findConfig(configs, name);
|
|
558
|
+
if (!found) {
|
|
559
|
+
console.error(`${colors.red}Error: Config '${name}' not found${colors.reset}`);
|
|
560
|
+
console.log(`${colors.dim}Use 'npx agent-configs list' to see available configs${colors.reset}`);
|
|
561
|
+
process.exit(1);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const { category, item } = found;
|
|
565
|
+
|
|
566
|
+
console.log(`\n${colors.bold}Installing ${colors.green}${item.name}${colors.reset}${colors.bold}...${colors.reset}\n`);
|
|
567
|
+
|
|
568
|
+
// Handle bundles
|
|
569
|
+
if (category.id === 'bundles') {
|
|
570
|
+
if (item.hasFiles) {
|
|
571
|
+
// File-based bundle (like shared-memory)
|
|
572
|
+
installFileBundle(item, platforms, scope, dryRun);
|
|
573
|
+
} else if (item.includes) {
|
|
574
|
+
// Reference bundle
|
|
575
|
+
installReferenceBundle(item, configs, platforms, scope, dryRun);
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Handle hooks (special case)
|
|
581
|
+
if (category.id === 'hooks') {
|
|
582
|
+
installHooks(item, platforms, scope, dryRun);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Regular config installation
|
|
587
|
+
for (const p of platforms) {
|
|
588
|
+
if (!category.platforms || !category.platforms.includes(p)) {
|
|
589
|
+
console.log(`${colors.yellow}⚠ ${item.name} not supported on ${p}, skipping${colors.reset}`);
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const targetBase = PLATFORM_PATHS[p][scope];
|
|
594
|
+
if (!targetBase) {
|
|
595
|
+
console.log(`${colors.yellow}⚠ ${scope} scope not supported on ${p}, skipping${colors.reset}`);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const categoryPath = targetBase[category.id] || targetBase[category.id.replace(/s$/, '')];
|
|
600
|
+
if (!categoryPath) {
|
|
601
|
+
console.log(`${colors.yellow}⚠ ${category.id} not supported on ${p}, skipping${colors.reset}`);
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const sourcePath = path.join(__dirname, item.path);
|
|
606
|
+
const isDir = fs.statSync(sourcePath).isDirectory();
|
|
607
|
+
const targetPath = isDir
|
|
608
|
+
? path.join(categoryPath, item.name)
|
|
609
|
+
: path.join(categoryPath, path.basename(item.path));
|
|
610
|
+
|
|
611
|
+
if (dryRun) {
|
|
612
|
+
console.log(`${colors.dim}[dry-run]${colors.reset} Would copy ${sourcePath} -> ${targetPath}`);
|
|
613
|
+
} else {
|
|
614
|
+
copyRecursive(sourcePath, targetPath);
|
|
615
|
+
console.log(`${colors.green}✓${colors.reset} Installed to ${targetPath}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
console.log();
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Install file-based bundle
|
|
623
|
+
function installFileBundle(item, platforms, scope, dryRun) {
|
|
624
|
+
const bundlePath = path.join(__dirname, item.path);
|
|
625
|
+
|
|
626
|
+
for (const p of platforms) {
|
|
627
|
+
const platformDir = path.join(bundlePath, `.${p}`);
|
|
628
|
+
if (!fs.existsSync(platformDir)) {
|
|
629
|
+
console.log(`${colors.yellow}⚠ No ${p} config in ${item.name} bundle${colors.reset}`);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const entries = fs.readdirSync(platformDir);
|
|
634
|
+
for (const entry of entries) {
|
|
635
|
+
const sourcePath = path.join(platformDir, entry);
|
|
636
|
+
let targetPath;
|
|
637
|
+
|
|
638
|
+
if (scope === 'global') {
|
|
639
|
+
targetPath = path.join(os.homedir(), `.${p}`, entry);
|
|
640
|
+
} else {
|
|
641
|
+
targetPath = path.join(`.${p}`, entry);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (dryRun) {
|
|
645
|
+
console.log(`${colors.dim}[dry-run]${colors.reset} Would copy ${sourcePath} -> ${targetPath}`);
|
|
646
|
+
} else {
|
|
647
|
+
copyRecursive(sourcePath, targetPath);
|
|
648
|
+
console.log(`${colors.green}✓${colors.reset} Installed ${entry} to ${targetPath}`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
console.log(`\n${colors.green}✓${colors.reset} Bundle ${colors.bold}${item.name}${colors.reset} installed successfully\n`);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Install reference bundle
|
|
657
|
+
function installReferenceBundle(item, configs, platforms, scope, dryRun) {
|
|
658
|
+
console.log(`${colors.dim}Bundle includes: ${item.includes.join(', ')}${colors.reset}\n`);
|
|
659
|
+
|
|
660
|
+
for (const ref of item.includes) {
|
|
661
|
+
const [categoryId, configName] = ref.split('/');
|
|
662
|
+
|
|
663
|
+
// Find the config
|
|
664
|
+
const category = configs.categories.find(c => c.id === categoryId);
|
|
665
|
+
if (!category) {
|
|
666
|
+
console.log(`${colors.yellow}⚠ Category '${categoryId}' not found${colors.reset}`);
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const configItem = category.items.find(i => i.name === configName);
|
|
671
|
+
if (!configItem) {
|
|
672
|
+
console.log(`${colors.yellow}⚠ Config '${configName}' not found in ${categoryId}${colors.reset}`);
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Install the referenced config
|
|
677
|
+
for (const p of platforms) {
|
|
678
|
+
if (category.platforms && !category.platforms.includes(p)) {
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const targetBase = PLATFORM_PATHS[p][scope];
|
|
683
|
+
if (!targetBase) continue;
|
|
684
|
+
|
|
685
|
+
const categoryPath = targetBase[categoryId] || targetBase[categoryId.replace(/s$/, '')];
|
|
686
|
+
if (!categoryPath) continue;
|
|
687
|
+
|
|
688
|
+
const sourcePath = path.join(__dirname, configItem.path);
|
|
689
|
+
const isDir = fs.existsSync(sourcePath) && fs.statSync(sourcePath).isDirectory();
|
|
690
|
+
const targetPath = isDir
|
|
691
|
+
? path.join(categoryPath, configItem.name)
|
|
692
|
+
: path.join(categoryPath, path.basename(configItem.path));
|
|
693
|
+
|
|
694
|
+
if (dryRun) {
|
|
695
|
+
console.log(`${colors.dim}[dry-run]${colors.reset} Would copy ${sourcePath} -> ${targetPath}`);
|
|
696
|
+
} else {
|
|
697
|
+
copyRecursive(sourcePath, targetPath);
|
|
698
|
+
console.log(`${colors.green}✓${colors.reset} Installed ${configItem.name} to ${targetPath}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
console.log(`\n${colors.green}✓${colors.reset} Bundle ${colors.bold}${item.name}${colors.reset} installed successfully\n`);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Install hooks
|
|
707
|
+
function installHooks(item, platforms, scope, dryRun) {
|
|
708
|
+
const sourceFile = path.join(__dirname, 'hooks/hooks.json');
|
|
709
|
+
const sourceData = JSON.parse(fs.readFileSync(sourceFile, 'utf8'));
|
|
710
|
+
|
|
711
|
+
for (const p of platforms) {
|
|
712
|
+
let targetPath;
|
|
713
|
+
if (p === 'claude') {
|
|
714
|
+
targetPath = scope === 'global'
|
|
715
|
+
? PLATFORM_PATHS.claude.global.settings
|
|
716
|
+
: PLATFORM_PATHS.claude.project.settings;
|
|
717
|
+
} else {
|
|
718
|
+
targetPath = scope === 'global'
|
|
719
|
+
? path.join(os.homedir(), '.cursor', 'hooks.json')
|
|
720
|
+
: PLATFORM_PATHS.cursor.project.hooks;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (dryRun) {
|
|
724
|
+
console.log(`${colors.dim}[dry-run]${colors.reset} Would merge hooks into ${targetPath}`);
|
|
725
|
+
} else {
|
|
726
|
+
mergeJson(targetPath, sourceData);
|
|
727
|
+
console.log(`${colors.green}✓${colors.reset} Merged hooks into ${targetPath}`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
console.log();
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Uninstall command
|
|
735
|
+
function uninstallConfig(name, options = {}) {
|
|
736
|
+
const configs = loadConfigs();
|
|
737
|
+
const platform = options.agent || configs.defaultPlatform || 'cursor';
|
|
738
|
+
const scope = options.scope || configs.defaultScope || 'project';
|
|
739
|
+
|
|
740
|
+
const platforms = platform === 'all' ? ['claude', 'cursor'] : [platform];
|
|
741
|
+
|
|
742
|
+
const found = findConfig(configs, name);
|
|
743
|
+
if (!found) {
|
|
744
|
+
console.error(`${colors.red}Error: Config '${name}' not found${colors.reset}`);
|
|
745
|
+
process.exit(1);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const { category, item } = found;
|
|
749
|
+
|
|
750
|
+
console.log(`\n${colors.bold}Uninstalling ${colors.red}${item.name}${colors.reset}${colors.bold}...${colors.reset}\n`);
|
|
751
|
+
|
|
752
|
+
// Handle bundles with includes
|
|
753
|
+
if (category.id === 'bundles' && item.includes) {
|
|
754
|
+
for (const ref of item.includes) {
|
|
755
|
+
const [categoryId, configName] = ref.split('/');
|
|
756
|
+
const cat = configs.categories.find(c => c.id === categoryId);
|
|
757
|
+
if (!cat) continue;
|
|
758
|
+
|
|
759
|
+
const configItem = cat.items.find(i => i.name === configName);
|
|
760
|
+
if (!configItem) continue;
|
|
761
|
+
|
|
762
|
+
for (const p of platforms) {
|
|
763
|
+
const targetBase = PLATFORM_PATHS[p][scope];
|
|
764
|
+
if (!targetBase) continue;
|
|
765
|
+
|
|
766
|
+
const categoryPath = targetBase[categoryId];
|
|
767
|
+
if (!categoryPath) continue;
|
|
768
|
+
|
|
769
|
+
const isDir = configItem.path.endsWith('/');
|
|
770
|
+
const targetPath = isDir
|
|
771
|
+
? path.join(categoryPath, configItem.name)
|
|
772
|
+
: path.join(categoryPath, path.basename(configItem.path));
|
|
773
|
+
|
|
774
|
+
if (deleteRecursive(targetPath)) {
|
|
775
|
+
console.log(`${colors.red}✗${colors.reset} Removed ${targetPath}`);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
console.log();
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Regular uninstall
|
|
784
|
+
for (const p of platforms) {
|
|
785
|
+
const targetBase = PLATFORM_PATHS[p][scope];
|
|
786
|
+
if (!targetBase) continue;
|
|
787
|
+
|
|
788
|
+
const categoryPath = targetBase[category.id];
|
|
789
|
+
if (!categoryPath) continue;
|
|
790
|
+
|
|
791
|
+
const isDir = item.path.endsWith('/');
|
|
792
|
+
const targetPath = isDir
|
|
793
|
+
? path.join(categoryPath, item.name)
|
|
794
|
+
: path.join(categoryPath, path.basename(item.path));
|
|
795
|
+
|
|
796
|
+
if (deleteRecursive(targetPath)) {
|
|
797
|
+
console.log(`${colors.red}✗${colors.reset} Removed ${targetPath}`);
|
|
798
|
+
} else {
|
|
799
|
+
console.log(`${colors.dim}Not found: ${targetPath}${colors.reset}`);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
console.log();
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Show help
|
|
807
|
+
function showHelp() {
|
|
808
|
+
console.log(`
|
|
809
|
+
${colors.bold}${colors.cyan}agent-configs${colors.reset} - Claude Code & Cursor 配置共享工具
|
|
810
|
+
|
|
811
|
+
${colors.bold}Usage:${colors.reset}
|
|
812
|
+
npx agent-configs ${colors.dim}# 交互式菜单${colors.reset}
|
|
813
|
+
npx agent-configs <command> [options]
|
|
814
|
+
|
|
815
|
+
${colors.bold}Commands:${colors.reset}
|
|
816
|
+
${colors.green}(无)${colors.reset} 进入交互式菜单
|
|
817
|
+
${colors.green}list${colors.reset} 交互式浏览配置
|
|
818
|
+
${colors.green}list --static${colors.reset} 静态列表输出
|
|
819
|
+
${colors.green}install${colors.reset} <name> 安装指定配置
|
|
820
|
+
${colors.green}uninstall${colors.reset} <name> 卸载配置
|
|
821
|
+
|
|
822
|
+
${colors.bold}Options:${colors.reset}
|
|
823
|
+
--static 静态输出模式(不进入交互)
|
|
824
|
+
--category <cat> 过滤类别: commands, skills, rules, agents, bundles
|
|
825
|
+
--agent <platform> 目标平台: cursor (默认), claude, all
|
|
826
|
+
--scope <scope> 安装级别: project (默认), global
|
|
827
|
+
--dry-run 预览模式,不实际执行
|
|
828
|
+
--preset <name> 预设方案: minimal, recommended, full
|
|
829
|
+
|
|
830
|
+
${colors.bold}Interactive Mode:${colors.reset}
|
|
831
|
+
↑↓ 上下选择
|
|
832
|
+
Enter 进入子菜单 / 安装
|
|
833
|
+
Esc 返回上一层 / 退出
|
|
834
|
+
|
|
835
|
+
${colors.bold}Examples:${colors.reset}
|
|
836
|
+
npx agent-configs ${colors.dim}# 交互式选择${colors.reset}
|
|
837
|
+
npx agent-configs list --static ${colors.dim}# 静态列表${colors.reset}
|
|
838
|
+
npx agent-configs install plan ${colors.dim}# 直接安装${colors.reset}
|
|
839
|
+
npx agent-configs install --preset recommended
|
|
840
|
+
|
|
841
|
+
${colors.bold}Bundles (推荐):${colors.reset}
|
|
842
|
+
${colors.green}tdd-bundle${colors.reset} TDD 完整工作流
|
|
843
|
+
${colors.green}review-bundle${colors.reset} 代码审查全套
|
|
844
|
+
${colors.green}planning-bundle${colors.reset} 规划和架构设计
|
|
845
|
+
${colors.green}bk-chat-bundle${colors.reset} 蓝鲸 AI Chat 开发
|
|
846
|
+
${colors.green}shared-memory${colors.reset} 跨会话记忆系统
|
|
847
|
+
`);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Install preset
|
|
851
|
+
function installPreset(presetName, options = {}) {
|
|
852
|
+
const configs = loadConfigs();
|
|
853
|
+
const preset = configs.presets[presetName];
|
|
854
|
+
|
|
855
|
+
if (!preset) {
|
|
856
|
+
console.error(`${colors.red}Error: Preset '${presetName}' not found${colors.reset}`);
|
|
857
|
+
console.log(`${colors.dim}Available presets: ${Object.keys(configs.presets).join(', ')}${colors.reset}`);
|
|
858
|
+
process.exit(1);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
console.log(`\n${colors.bold}Installing preset ${colors.cyan}${presetName}${colors.reset}${colors.bold}...${colors.reset}\n`);
|
|
862
|
+
|
|
863
|
+
for (const pattern of preset) {
|
|
864
|
+
if (pattern === '*') {
|
|
865
|
+
// Install everything
|
|
866
|
+
for (const category of configs.categories) {
|
|
867
|
+
for (const item of category.items) {
|
|
868
|
+
installConfig(item.name, options);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} else if (pattern.endsWith('/*')) {
|
|
872
|
+
// Install all in category
|
|
873
|
+
const categoryId = pattern.replace('/*', '');
|
|
874
|
+
const category = configs.categories.find(c => c.id === categoryId);
|
|
875
|
+
if (category) {
|
|
876
|
+
for (const item of category.items) {
|
|
877
|
+
installConfig(item.name, options);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
} else {
|
|
881
|
+
// Install specific config
|
|
882
|
+
const configName = pattern.split('/').pop();
|
|
883
|
+
installConfig(configName, options);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Parse arguments
|
|
889
|
+
function parseArgs(args) {
|
|
890
|
+
const result = { _: [], options: {} };
|
|
891
|
+
|
|
892
|
+
for (let i = 0; i < args.length; i++) {
|
|
893
|
+
const arg = args[i];
|
|
894
|
+
if (arg.startsWith('--')) {
|
|
895
|
+
const key = arg.slice(2);
|
|
896
|
+
if (key === 'dry-run') {
|
|
897
|
+
result.options.dryRun = true;
|
|
898
|
+
} else if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
899
|
+
result.options[key] = args[++i];
|
|
900
|
+
} else {
|
|
901
|
+
result.options[key] = true;
|
|
902
|
+
}
|
|
903
|
+
} else if (arg.startsWith('-') && arg.length === 2) {
|
|
904
|
+
// Short flags like -h
|
|
905
|
+
const key = arg.slice(1);
|
|
906
|
+
result.options[key] = true;
|
|
907
|
+
} else {
|
|
908
|
+
result._.push(arg);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return result;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// Main entry
|
|
916
|
+
async function main() {
|
|
917
|
+
const args = parseArgs(process.argv.slice(2));
|
|
918
|
+
const command = args._[0];
|
|
919
|
+
const name = args._[1];
|
|
920
|
+
|
|
921
|
+
// Handle --help and -h flags
|
|
922
|
+
if (args.options.help || args.options.h) {
|
|
923
|
+
showHelp();
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
switch (command) {
|
|
928
|
+
case 'list':
|
|
929
|
+
case 'ls':
|
|
930
|
+
if (args.options.static) {
|
|
931
|
+
// Static output mode
|
|
932
|
+
listConfigsStatic({ category: args.options.category });
|
|
933
|
+
} else if (args.options.category) {
|
|
934
|
+
// Filter by category but still static
|
|
935
|
+
listConfigsStatic({ category: args.options.category });
|
|
936
|
+
} else {
|
|
937
|
+
// Interactive mode
|
|
938
|
+
await interactiveMenu(args.options);
|
|
939
|
+
}
|
|
940
|
+
break;
|
|
941
|
+
|
|
942
|
+
case 'install':
|
|
943
|
+
case 'i':
|
|
944
|
+
if (args.options.preset) {
|
|
945
|
+
installPreset(args.options.preset, args.options);
|
|
946
|
+
} else if (name) {
|
|
947
|
+
installConfig(name, args.options);
|
|
948
|
+
} else {
|
|
949
|
+
// No name specified, enter interactive mode
|
|
950
|
+
await interactiveMenu(args.options);
|
|
951
|
+
}
|
|
952
|
+
break;
|
|
953
|
+
|
|
954
|
+
case 'uninstall':
|
|
955
|
+
case 'rm':
|
|
956
|
+
if (name) {
|
|
957
|
+
uninstallConfig(name, args.options);
|
|
958
|
+
} else {
|
|
959
|
+
console.error(`${colors.red}Error: Please specify a config name${colors.reset}`);
|
|
960
|
+
process.exit(1);
|
|
961
|
+
}
|
|
962
|
+
break;
|
|
963
|
+
|
|
964
|
+
case 'help':
|
|
965
|
+
showHelp();
|
|
966
|
+
break;
|
|
967
|
+
|
|
968
|
+
default:
|
|
969
|
+
// No command, enter interactive mode
|
|
970
|
+
await interactiveMenu(args.options);
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
main().catch(err => {
|
|
976
|
+
console.error(`${colors.red}Error: ${err.message}${colors.reset}`);
|
|
977
|
+
process.exit(1);
|
|
978
|
+
});
|