px2cc 2.2.2 → 2.2.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/README.md +114 -114
- package/bin.js +14 -14
- package/cli.js +421 -421
- package/package.json +51 -51
- package/src/PromptXActionProcessor.js +431 -431
package/cli.js
CHANGED
|
@@ -1,422 +1,422 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PromptX CLI - 使用 @promptx/core 动态获取角色信息
|
|
5
|
-
* 注意:此文件应通过 promptx-cli wrapper 脚本运行以过滤内部日志
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { resource } from '@promptx/core';
|
|
9
|
-
import { ClaudeCodeBuilder } from 'claude-code-builder';
|
|
10
|
-
import { PromptXActionProcessor } from './src/PromptXActionProcessor.js';
|
|
11
|
-
import inquirer from 'inquirer';
|
|
12
|
-
import chalk from 'chalk';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
import fs from 'fs';
|
|
15
|
-
import { execSync } from 'child_process';
|
|
16
|
-
|
|
17
|
-
// 注意:原有的parsePromptXRole函数已被PromptXActionProcessor替代
|
|
18
|
-
// 新的处理器实现完整的PromptX Action流程,包括:
|
|
19
|
-
// 1. RoleLoader - 加载角色定义
|
|
20
|
-
// 2. DependencyAnalyzer - 分析资源依赖
|
|
21
|
-
// 3. CognitionLoader - 加载认知网络
|
|
22
|
-
// 4. LayerAssembler - 三层内容组装
|
|
23
|
-
|
|
24
|
-
// 发现MCP服务器
|
|
25
|
-
async function discoverMCPServers() {
|
|
26
|
-
const servers = {
|
|
27
|
-
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
28
|
-
mcpServers: []
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
console.log(chalk.gray(' 检查MCP服务器状态(可能需要一些时间)...'));
|
|
33
|
-
// 使用claude mcp list获取所有MCP服务器(增加超时时间到60秒)
|
|
34
|
-
const mcpOutput = execSync('claude mcp list', {
|
|
35
|
-
encoding: 'utf8',
|
|
36
|
-
timeout: 60000, // 增加到60秒
|
|
37
|
-
stdio: 'pipe' // 确保错误输出被捕获
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// 解析输出,提取服务器信息
|
|
41
|
-
const lines = mcpOutput.split('\n');
|
|
42
|
-
|
|
43
|
-
for (const line of lines) {
|
|
44
|
-
const trimmedLine = line.trim();
|
|
45
|
-
// 匹配服务器名称(格式:serverName: command - status)
|
|
46
|
-
const match = trimmedLine.match(/^([^:]+):\s+(.+)\s+-\s+(✓|✗)\s+(.*)$/);
|
|
47
|
-
if (match && !trimmedLine.includes('Checking MCP server health')) {
|
|
48
|
-
const [, name, command, status, statusText] = match;
|
|
49
|
-
servers.mcpServers.push({
|
|
50
|
-
name: name.trim(),
|
|
51
|
-
command: command.trim(),
|
|
52
|
-
connected: status === '✓',
|
|
53
|
-
status: statusText.trim()
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
console.log(chalk.green(`✅ 发现 ${servers.mcpServers.length} 个MCP服务器`));
|
|
59
|
-
|
|
60
|
-
} catch (error) {
|
|
61
|
-
if (error.code === 'ETIMEDOUT') {
|
|
62
|
-
console.error(chalk.yellow('⚠️ MCP服务器检查超时,将继续安装(只使用默认工具)'));
|
|
63
|
-
console.error(chalk.gray(' 如需使用MCP工具,请检查网络连接或使用 --skip-mcp 参数'));
|
|
64
|
-
} else {
|
|
65
|
-
console.error(chalk.yellow('⚠️ 无法获取MCP服务器列表,将继续安装(只使用默认工具)'));
|
|
66
|
-
console.error(chalk.gray(` 原因: ${error.message}`));
|
|
67
|
-
}
|
|
68
|
-
// 不再抛出错误,而是继续执行,不使用MCP服务器
|
|
69
|
-
console.log(chalk.gray(' 将继承所有可用工具(Claude Code默认行为)'));
|
|
70
|
-
return servers;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return servers;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 显示MCP服务器选择界面
|
|
77
|
-
async function selectMCPServers(roleName, availableServers) {
|
|
78
|
-
// 如果没有MCP服务器,直接返回undefined(继承所有工具)
|
|
79
|
-
if (availableServers.mcpServers.length === 0) {
|
|
80
|
-
console.log(chalk.gray(' 没有发现MCP服务器,将继承所有可用工具'));
|
|
81
|
-
return undefined;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// 只显示MCP服务器选择
|
|
85
|
-
const choices = [];
|
|
86
|
-
|
|
87
|
-
for (const server of availableServers.mcpServers) {
|
|
88
|
-
const statusIcon = server.connected ? '✓' : '✗';
|
|
89
|
-
const statusColor = server.connected ? chalk.green : chalk.red;
|
|
90
|
-
choices.push({
|
|
91
|
-
name: `${statusColor(statusIcon)} ${server.name} ${chalk.gray(`(${server.status})`)}`,
|
|
92
|
-
value: server.name,
|
|
93
|
-
checked: false, // 默认不选中任何MCP服务器
|
|
94
|
-
disabled: !server.connected ? '(未连接)' : false
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
console.log(chalk.blue('\n🔧 默认工具(自动包含):'), availableServers.defaultTools.join(', '));
|
|
99
|
-
|
|
100
|
-
const answer = await inquirer.prompt([{
|
|
101
|
-
type: 'checkbox',
|
|
102
|
-
name: 'selectedServers',
|
|
103
|
-
message: `为 ${roleName} 选择额外的MCP服务器(可选):`,
|
|
104
|
-
choices: choices
|
|
105
|
-
}]);
|
|
106
|
-
|
|
107
|
-
// 处理选中的MCP服务器
|
|
108
|
-
const selectedMCPServers = answer.selectedServers || [];
|
|
109
|
-
|
|
110
|
-
if (selectedMCPServers.length === 0) {
|
|
111
|
-
console.log(chalk.gray(' 将继承所有可用工具(Claude Code默认行为)'));
|
|
112
|
-
return undefined; // Claude Code会继承所有工具
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 如果选择了特定服务器,只包含默认工具+选中服务器的工具
|
|
116
|
-
const selectedTools = availableServers.defaultTools.slice();
|
|
117
|
-
for (const serverName of selectedMCPServers) {
|
|
118
|
-
// 添加该服务器的所有工具(使用通配符或具体工具名)
|
|
119
|
-
selectedTools.push(`mcp__${serverName}__*`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log(chalk.blue(` 已选择 ${selectedMCPServers.length} 个MCP服务器: ${selectedMCPServers.join(', ')}`));
|
|
123
|
-
return selectedTools;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 获取PromptX角色
|
|
127
|
-
async function getAllRoles() {
|
|
128
|
-
try {
|
|
129
|
-
const manager = resource.getGlobalResourceManager();
|
|
130
|
-
await manager.initializeWithNewArchitecture();
|
|
131
|
-
|
|
132
|
-
const roleResources = manager.registryData.getResourcesByProtocol('role');
|
|
133
|
-
const systemRoles = roleResources.filter(r => r.source === 'package');
|
|
134
|
-
const userRoles = roleResources.filter(r => r.source === 'user');
|
|
135
|
-
|
|
136
|
-
return { systemRoles, userRoles, manager };
|
|
137
|
-
} catch (error) {
|
|
138
|
-
throw new Error(`获取PromptX角色失败: ${error.message}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 显示欢迎界面
|
|
143
|
-
function showWelcome() {
|
|
144
|
-
console.clear();
|
|
145
|
-
console.log(chalk.blue.bold('🚀 PromptX CLI - Claude Code 角色安装器'));
|
|
146
|
-
console.log(chalk.gray(' 快速将PromptX角色集成到Claude Code中\n'));
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// 显示角色选择菜单
|
|
150
|
-
async function showRoleMenu(systemRoles, userRoles, availableServers) {
|
|
151
|
-
const choices = [
|
|
152
|
-
...systemRoles.map(role => ({
|
|
153
|
-
name: `📦 ${role.id} ${chalk.gray('(系统角色)')}`,
|
|
154
|
-
value: { role: role.id, source: 'package' },
|
|
155
|
-
short: role.id
|
|
156
|
-
})),
|
|
157
|
-
new inquirer.Separator(chalk.gray('─── 用户角色 ───')),
|
|
158
|
-
...userRoles.map(role => ({
|
|
159
|
-
name: `👤 ${role.id} ${chalk.gray('(用户角色)')}`,
|
|
160
|
-
value: { role: role.id, source: 'user' },
|
|
161
|
-
short: role.id
|
|
162
|
-
}))
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
const roleAnswer = await inquirer.prompt([
|
|
166
|
-
{
|
|
167
|
-
type: 'list',
|
|
168
|
-
name: 'selectedRole',
|
|
169
|
-
message: '请选择要安装的PromptX角色:',
|
|
170
|
-
choices: choices,
|
|
171
|
-
pageSize: 15
|
|
172
|
-
}
|
|
173
|
-
]);
|
|
174
|
-
|
|
175
|
-
// 选择安装类型
|
|
176
|
-
const typeAnswer = await inquirer.prompt([
|
|
177
|
-
{
|
|
178
|
-
type: 'list',
|
|
179
|
-
name: 'installType',
|
|
180
|
-
message: `安装 ${roleAnswer.selectedRole.role} 为:`,
|
|
181
|
-
choices: [
|
|
182
|
-
{
|
|
183
|
-
name: `🤖 Agent - 通过提及"${roleAnswer.selectedRole.role}-agent subagent"调用`,
|
|
184
|
-
value: 'agents',
|
|
185
|
-
short: 'Agent'
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
name: `⚙️ Command - 通过 /${roleAnswer.selectedRole.role} 调用`,
|
|
189
|
-
value: 'commands',
|
|
190
|
-
short: 'Command'
|
|
191
|
-
}
|
|
192
|
-
]
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
type: 'confirm',
|
|
196
|
-
name: 'customName',
|
|
197
|
-
message: '是否要自定义安装名字?',
|
|
198
|
-
default: false
|
|
199
|
-
}
|
|
200
|
-
]);
|
|
201
|
-
|
|
202
|
-
let customName = '';
|
|
203
|
-
if (typeAnswer.customName) {
|
|
204
|
-
const nameAnswer = await inquirer.prompt([
|
|
205
|
-
{
|
|
206
|
-
type: 'input',
|
|
207
|
-
name: 'name',
|
|
208
|
-
message: typeAnswer.installType === 'agents'
|
|
209
|
-
? `请输入自定义Agent名字 (默认: ${roleAnswer.selectedRole.role}-agent):`
|
|
210
|
-
: `请输入自定义Command名字 (默认: ${roleAnswer.selectedRole.role}):`,
|
|
211
|
-
default: typeAnswer.installType === 'agents'
|
|
212
|
-
? `${roleAnswer.selectedRole.role}-agent`
|
|
213
|
-
: roleAnswer.selectedRole.role,
|
|
214
|
-
validate: (input) => {
|
|
215
|
-
if (!input.trim()) {
|
|
216
|
-
return '名字不能为空';
|
|
217
|
-
}
|
|
218
|
-
// 检查名字格式
|
|
219
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(input.trim())) {
|
|
220
|
-
return '名字只能包含字母、数字、下划线和连字符';
|
|
221
|
-
}
|
|
222
|
-
return true;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
]);
|
|
226
|
-
customName = nameAnswer.name.trim();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const confirmAnswer = await inquirer.prompt([
|
|
230
|
-
{
|
|
231
|
-
type: 'confirm',
|
|
232
|
-
name: 'confirm',
|
|
233
|
-
message: customName
|
|
234
|
-
? `确认安装 ${roleAnswer.selectedRole.role} 为 ${chalk.yellow(customName)} 到Claude Code?`
|
|
235
|
-
: '确认安装到Claude Code?',
|
|
236
|
-
default: true
|
|
237
|
-
}
|
|
238
|
-
]);
|
|
239
|
-
|
|
240
|
-
let selectedTools = [];
|
|
241
|
-
if (confirmAnswer.confirm) {
|
|
242
|
-
// 选择MCP服务器和工具
|
|
243
|
-
selectedTools = await selectMCPServers(roleAnswer.selectedRole.role, availableServers);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
selectedRole: roleAnswer.selectedRole,
|
|
248
|
-
installType: typeAnswer.installType,
|
|
249
|
-
confirm: confirmAnswer.confirm,
|
|
250
|
-
customName: customName,
|
|
251
|
-
selectedTools: selectedTools
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// 检查当前目录
|
|
256
|
-
function checkDirectory() {
|
|
257
|
-
const currentDir = process.cwd();
|
|
258
|
-
const claudeDir = path.join(currentDir, '.claude');
|
|
259
|
-
|
|
260
|
-
if (!fs.existsSync(claudeDir)) {
|
|
261
|
-
console.log(chalk.yellow('📁 创建 .claude 目录...'));
|
|
262
|
-
fs.mkdirSync(claudeDir, { recursive: true });
|
|
263
|
-
fs.mkdirSync(path.join(claudeDir, 'agents'), { recursive: true });
|
|
264
|
-
fs.mkdirSync(path.join(claudeDir, 'commands'), { recursive: true });
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return claudeDir;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 安装角色
|
|
271
|
-
async function installRole(selectedRole, installType, claudeDir, selectedTools, customName = '') {
|
|
272
|
-
const roleName = selectedRole.role;
|
|
273
|
-
const results = {};
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
// 使用新的PromptXActionProcessor执行完整的action流程
|
|
277
|
-
const processor = new PromptXActionProcessor();
|
|
278
|
-
const mode = installType === 'agents' ? 'subagent' : 'command';
|
|
279
|
-
const processedContent = await processor.processRole(roleName, mode);
|
|
280
|
-
|
|
281
|
-
// 根据安装模式创建相应文件
|
|
282
|
-
const finalName = customName || (installType === 'agents' ? `${roleName}-agent` : roleName);
|
|
283
|
-
|
|
284
|
-
if (installType === 'agents') {
|
|
285
|
-
console.log(chalk.cyan(`🔧 生成 ${finalName} subagent文件...`));
|
|
286
|
-
const agentConfig = {
|
|
287
|
-
name: finalName,
|
|
288
|
-
description: `基于PromptX ${roleName}角色的专业AI助手 - 完整action实现`,
|
|
289
|
-
content: processedContent,
|
|
290
|
-
targetDir: claudeDir
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
294
|
-
if (selectedTools) {
|
|
295
|
-
agentConfig.tools = selectedTools;
|
|
296
|
-
}
|
|
297
|
-
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
298
|
-
|
|
299
|
-
const subagentResult = await ClaudeCodeBuilder.createSubagent(agentConfig);
|
|
300
|
-
|
|
301
|
-
if (!subagentResult.success) {
|
|
302
|
-
throw new Error(`创建Subagent失败: ${subagentResult.error}`);
|
|
303
|
-
}
|
|
304
|
-
results.agentFile = `${finalName}.md`;
|
|
305
|
-
results.usage = `Use the ${finalName} subagent to [任务描述]`;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (installType === 'commands') {
|
|
309
|
-
console.log(chalk.cyan(`📋 生成 ${finalName} command文件...`));
|
|
310
|
-
|
|
311
|
-
const commandConfig = {
|
|
312
|
-
name: finalName,
|
|
313
|
-
description: `基于PromptX ${roleName}角色的专业助手 - 完整action实现`,
|
|
314
|
-
content: processedContent,
|
|
315
|
-
targetDir: claudeDir
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
319
|
-
if (selectedTools) {
|
|
320
|
-
commandConfig.allowedTools = selectedTools;
|
|
321
|
-
}
|
|
322
|
-
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
323
|
-
|
|
324
|
-
const commandResult = await ClaudeCodeBuilder.createCommand(commandConfig);
|
|
325
|
-
|
|
326
|
-
if (!commandResult.success) {
|
|
327
|
-
throw new Error(`创建Command失败: ${commandResult.error}`);
|
|
328
|
-
}
|
|
329
|
-
results.commandFile = `${finalName}.md`;
|
|
330
|
-
results.usage = `/${finalName}`;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
results.roleName = roleName;
|
|
334
|
-
results.installType = installType;
|
|
335
|
-
return results;
|
|
336
|
-
|
|
337
|
-
} catch (error) {
|
|
338
|
-
throw new Error(`安装角色失败: ${error.message}`);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// 主程序入口
|
|
343
|
-
export async function main() {
|
|
344
|
-
try {
|
|
345
|
-
showWelcome();
|
|
346
|
-
|
|
347
|
-
// 检查是否跳过MCP发现(用于快速测试)
|
|
348
|
-
const skipMCP = process.argv.includes('--skip-mcp');
|
|
349
|
-
|
|
350
|
-
let availableServers;
|
|
351
|
-
if (skipMCP) {
|
|
352
|
-
console.log(chalk.yellow('⚠️ 跳过MCP发现(测试模式)'));
|
|
353
|
-
availableServers = {
|
|
354
|
-
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
355
|
-
mcpServers: []
|
|
356
|
-
};
|
|
357
|
-
} else {
|
|
358
|
-
// 发现MCP服务器
|
|
359
|
-
console.log(chalk.cyan('🔍 正在发现MCP服务器...\n'));
|
|
360
|
-
try {
|
|
361
|
-
availableServers = await discoverMCPServers();
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error(chalk.yellow('⚠️ MCP服务器发现失败,使用默认配置'));
|
|
364
|
-
availableServers = {
|
|
365
|
-
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
366
|
-
mcpServers: []
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// 加载角色
|
|
372
|
-
console.log(chalk.cyan('🔍 正在从PromptX系统加载角色...\n'));
|
|
373
|
-
const { systemRoles, userRoles, manager } = await getAllRoles();
|
|
374
|
-
|
|
375
|
-
console.log(chalk.green('✅ 加载完成!'));
|
|
376
|
-
console.log(`📊 发现 ${chalk.bold(systemRoles.length)} 个系统角色,${chalk.bold(userRoles.length)} 个用户角色\n`);
|
|
377
|
-
|
|
378
|
-
// 显示角色选择
|
|
379
|
-
const { selectedRole, installType, confirm, selectedTools, customName } = await showRoleMenu(systemRoles, userRoles, availableServers);
|
|
380
|
-
|
|
381
|
-
if (!confirm) {
|
|
382
|
-
console.log(chalk.yellow('\n👋 安装已取消'));
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// 检查目录
|
|
387
|
-
const claudeDir = checkDirectory();
|
|
388
|
-
|
|
389
|
-
console.log(chalk.blue(`\n🎭 开始安装角色: ${selectedRole.role} (${installType})`));
|
|
390
|
-
|
|
391
|
-
// 安装角色
|
|
392
|
-
const result = await installRole(selectedRole, installType, claudeDir, selectedTools, customName);
|
|
393
|
-
|
|
394
|
-
console.log(chalk.green.bold('\n✅ 角色安装完成!'));
|
|
395
|
-
console.log(`\n📄 生成的文件:`);
|
|
396
|
-
|
|
397
|
-
if (result.agentFile) {
|
|
398
|
-
console.log(` - ${chalk.gray('.claude/agents/')}${chalk.white(result.agentFile)}`);
|
|
399
|
-
}
|
|
400
|
-
if (result.commandFile) {
|
|
401
|
-
console.log(` - ${chalk.gray('.claude/commands/')}${chalk.white(result.commandFile)}`);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
console.log(chalk.magenta(`\n🎉 现在你可以在Claude Code中使用:`));
|
|
405
|
-
if (result.usage) {
|
|
406
|
-
console.log(chalk.yellow(` ${result.usage}`));
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
console.log(chalk.gray(`\n💡 提示: 重启Claude Code以确保新配置生效`));
|
|
410
|
-
|
|
411
|
-
} catch (error) {
|
|
412
|
-
console.error(chalk.red('❌ 安装失败:'), error.message);
|
|
413
|
-
process.exit(1);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// 运行主程序 - Windows兼容版本
|
|
418
|
-
// 通过bin.js调用时直接执行,通过import调用时也执行
|
|
419
|
-
main().catch(error => {
|
|
420
|
-
console.error(chalk.red('❌ 程序异常:'), error.message);
|
|
421
|
-
process.exit(1);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PromptX CLI - 使用 @promptx/core 动态获取角色信息
|
|
5
|
+
* 注意:此文件应通过 promptx-cli wrapper 脚本运行以过滤内部日志
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { resource } from '@promptx/core';
|
|
9
|
+
import { ClaudeCodeBuilder } from 'claude-code-builder';
|
|
10
|
+
import { PromptXActionProcessor } from './src/PromptXActionProcessor.js';
|
|
11
|
+
import inquirer from 'inquirer';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import { execSync } from 'child_process';
|
|
16
|
+
|
|
17
|
+
// 注意:原有的parsePromptXRole函数已被PromptXActionProcessor替代
|
|
18
|
+
// 新的处理器实现完整的PromptX Action流程,包括:
|
|
19
|
+
// 1. RoleLoader - 加载角色定义
|
|
20
|
+
// 2. DependencyAnalyzer - 分析资源依赖
|
|
21
|
+
// 3. CognitionLoader - 加载认知网络
|
|
22
|
+
// 4. LayerAssembler - 三层内容组装
|
|
23
|
+
|
|
24
|
+
// 发现MCP服务器
|
|
25
|
+
async function discoverMCPServers() {
|
|
26
|
+
const servers = {
|
|
27
|
+
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
28
|
+
mcpServers: []
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
console.log(chalk.gray(' 检查MCP服务器状态(可能需要一些时间)...'));
|
|
33
|
+
// 使用claude mcp list获取所有MCP服务器(增加超时时间到60秒)
|
|
34
|
+
const mcpOutput = execSync('claude mcp list', {
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
timeout: 60000, // 增加到60秒
|
|
37
|
+
stdio: 'pipe' // 确保错误输出被捕获
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// 解析输出,提取服务器信息
|
|
41
|
+
const lines = mcpOutput.split('\n');
|
|
42
|
+
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
const trimmedLine = line.trim();
|
|
45
|
+
// 匹配服务器名称(格式:serverName: command - status)
|
|
46
|
+
const match = trimmedLine.match(/^([^:]+):\s+(.+)\s+-\s+(✓|✗)\s+(.*)$/);
|
|
47
|
+
if (match && !trimmedLine.includes('Checking MCP server health')) {
|
|
48
|
+
const [, name, command, status, statusText] = match;
|
|
49
|
+
servers.mcpServers.push({
|
|
50
|
+
name: name.trim(),
|
|
51
|
+
command: command.trim(),
|
|
52
|
+
connected: status === '✓',
|
|
53
|
+
status: statusText.trim()
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(chalk.green(`✅ 发现 ${servers.mcpServers.length} 个MCP服务器`));
|
|
59
|
+
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error.code === 'ETIMEDOUT') {
|
|
62
|
+
console.error(chalk.yellow('⚠️ MCP服务器检查超时,将继续安装(只使用默认工具)'));
|
|
63
|
+
console.error(chalk.gray(' 如需使用MCP工具,请检查网络连接或使用 --skip-mcp 参数'));
|
|
64
|
+
} else {
|
|
65
|
+
console.error(chalk.yellow('⚠️ 无法获取MCP服务器列表,将继续安装(只使用默认工具)'));
|
|
66
|
+
console.error(chalk.gray(` 原因: ${error.message}`));
|
|
67
|
+
}
|
|
68
|
+
// 不再抛出错误,而是继续执行,不使用MCP服务器
|
|
69
|
+
console.log(chalk.gray(' 将继承所有可用工具(Claude Code默认行为)'));
|
|
70
|
+
return servers;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return servers;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 显示MCP服务器选择界面
|
|
77
|
+
async function selectMCPServers(roleName, availableServers) {
|
|
78
|
+
// 如果没有MCP服务器,直接返回undefined(继承所有工具)
|
|
79
|
+
if (availableServers.mcpServers.length === 0) {
|
|
80
|
+
console.log(chalk.gray(' 没有发现MCP服务器,将继承所有可用工具'));
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 只显示MCP服务器选择
|
|
85
|
+
const choices = [];
|
|
86
|
+
|
|
87
|
+
for (const server of availableServers.mcpServers) {
|
|
88
|
+
const statusIcon = server.connected ? '✓' : '✗';
|
|
89
|
+
const statusColor = server.connected ? chalk.green : chalk.red;
|
|
90
|
+
choices.push({
|
|
91
|
+
name: `${statusColor(statusIcon)} ${server.name} ${chalk.gray(`(${server.status})`)}`,
|
|
92
|
+
value: server.name,
|
|
93
|
+
checked: false, // 默认不选中任何MCP服务器
|
|
94
|
+
disabled: !server.connected ? '(未连接)' : false
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(chalk.blue('\n🔧 默认工具(自动包含):'), availableServers.defaultTools.join(', '));
|
|
99
|
+
|
|
100
|
+
const answer = await inquirer.prompt([{
|
|
101
|
+
type: 'checkbox',
|
|
102
|
+
name: 'selectedServers',
|
|
103
|
+
message: `为 ${roleName} 选择额外的MCP服务器(可选):`,
|
|
104
|
+
choices: choices
|
|
105
|
+
}]);
|
|
106
|
+
|
|
107
|
+
// 处理选中的MCP服务器
|
|
108
|
+
const selectedMCPServers = answer.selectedServers || [];
|
|
109
|
+
|
|
110
|
+
if (selectedMCPServers.length === 0) {
|
|
111
|
+
console.log(chalk.gray(' 将继承所有可用工具(Claude Code默认行为)'));
|
|
112
|
+
return undefined; // Claude Code会继承所有工具
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 如果选择了特定服务器,只包含默认工具+选中服务器的工具
|
|
116
|
+
const selectedTools = availableServers.defaultTools.slice();
|
|
117
|
+
for (const serverName of selectedMCPServers) {
|
|
118
|
+
// 添加该服务器的所有工具(使用通配符或具体工具名)
|
|
119
|
+
selectedTools.push(`mcp__${serverName}__*`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(chalk.blue(` 已选择 ${selectedMCPServers.length} 个MCP服务器: ${selectedMCPServers.join(', ')}`));
|
|
123
|
+
return selectedTools;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 获取PromptX角色
|
|
127
|
+
async function getAllRoles() {
|
|
128
|
+
try {
|
|
129
|
+
const manager = resource.getGlobalResourceManager();
|
|
130
|
+
await manager.initializeWithNewArchitecture();
|
|
131
|
+
|
|
132
|
+
const roleResources = manager.registryData.getResourcesByProtocol('role');
|
|
133
|
+
const systemRoles = roleResources.filter(r => r.source === 'package');
|
|
134
|
+
const userRoles = roleResources.filter(r => r.source === 'user');
|
|
135
|
+
|
|
136
|
+
return { systemRoles, userRoles, manager };
|
|
137
|
+
} catch (error) {
|
|
138
|
+
throw new Error(`获取PromptX角色失败: ${error.message}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 显示欢迎界面
|
|
143
|
+
function showWelcome() {
|
|
144
|
+
console.clear();
|
|
145
|
+
console.log(chalk.blue.bold('🚀 PromptX CLI - Claude Code 角色安装器'));
|
|
146
|
+
console.log(chalk.gray(' 快速将PromptX角色集成到Claude Code中\n'));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 显示角色选择菜单
|
|
150
|
+
async function showRoleMenu(systemRoles, userRoles, availableServers) {
|
|
151
|
+
const choices = [
|
|
152
|
+
...systemRoles.map(role => ({
|
|
153
|
+
name: `📦 ${role.id} ${chalk.gray('(系统角色)')}`,
|
|
154
|
+
value: { role: role.id, source: 'package' },
|
|
155
|
+
short: role.id
|
|
156
|
+
})),
|
|
157
|
+
new inquirer.Separator(chalk.gray('─── 用户角色 ───')),
|
|
158
|
+
...userRoles.map(role => ({
|
|
159
|
+
name: `👤 ${role.id} ${chalk.gray('(用户角色)')}`,
|
|
160
|
+
value: { role: role.id, source: 'user' },
|
|
161
|
+
short: role.id
|
|
162
|
+
}))
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const roleAnswer = await inquirer.prompt([
|
|
166
|
+
{
|
|
167
|
+
type: 'list',
|
|
168
|
+
name: 'selectedRole',
|
|
169
|
+
message: '请选择要安装的PromptX角色:',
|
|
170
|
+
choices: choices,
|
|
171
|
+
pageSize: 15
|
|
172
|
+
}
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
// 选择安装类型
|
|
176
|
+
const typeAnswer = await inquirer.prompt([
|
|
177
|
+
{
|
|
178
|
+
type: 'list',
|
|
179
|
+
name: 'installType',
|
|
180
|
+
message: `安装 ${roleAnswer.selectedRole.role} 为:`,
|
|
181
|
+
choices: [
|
|
182
|
+
{
|
|
183
|
+
name: `🤖 Agent - 通过提及"${roleAnswer.selectedRole.role}-agent subagent"调用`,
|
|
184
|
+
value: 'agents',
|
|
185
|
+
short: 'Agent'
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: `⚙️ Command - 通过 /${roleAnswer.selectedRole.role} 调用`,
|
|
189
|
+
value: 'commands',
|
|
190
|
+
short: 'Command'
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
type: 'confirm',
|
|
196
|
+
name: 'customName',
|
|
197
|
+
message: '是否要自定义安装名字?',
|
|
198
|
+
default: false
|
|
199
|
+
}
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
let customName = '';
|
|
203
|
+
if (typeAnswer.customName) {
|
|
204
|
+
const nameAnswer = await inquirer.prompt([
|
|
205
|
+
{
|
|
206
|
+
type: 'input',
|
|
207
|
+
name: 'name',
|
|
208
|
+
message: typeAnswer.installType === 'agents'
|
|
209
|
+
? `请输入自定义Agent名字 (默认: ${roleAnswer.selectedRole.role}-agent):`
|
|
210
|
+
: `请输入自定义Command名字 (默认: ${roleAnswer.selectedRole.role}):`,
|
|
211
|
+
default: typeAnswer.installType === 'agents'
|
|
212
|
+
? `${roleAnswer.selectedRole.role}-agent`
|
|
213
|
+
: roleAnswer.selectedRole.role,
|
|
214
|
+
validate: (input) => {
|
|
215
|
+
if (!input.trim()) {
|
|
216
|
+
return '名字不能为空';
|
|
217
|
+
}
|
|
218
|
+
// 检查名字格式
|
|
219
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(input.trim())) {
|
|
220
|
+
return '名字只能包含字母、数字、下划线和连字符';
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
]);
|
|
226
|
+
customName = nameAnswer.name.trim();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const confirmAnswer = await inquirer.prompt([
|
|
230
|
+
{
|
|
231
|
+
type: 'confirm',
|
|
232
|
+
name: 'confirm',
|
|
233
|
+
message: customName
|
|
234
|
+
? `确认安装 ${roleAnswer.selectedRole.role} 为 ${chalk.yellow(customName)} 到Claude Code?`
|
|
235
|
+
: '确认安装到Claude Code?',
|
|
236
|
+
default: true
|
|
237
|
+
}
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
let selectedTools = [];
|
|
241
|
+
if (confirmAnswer.confirm) {
|
|
242
|
+
// 选择MCP服务器和工具
|
|
243
|
+
selectedTools = await selectMCPServers(roleAnswer.selectedRole.role, availableServers);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
selectedRole: roleAnswer.selectedRole,
|
|
248
|
+
installType: typeAnswer.installType,
|
|
249
|
+
confirm: confirmAnswer.confirm,
|
|
250
|
+
customName: customName,
|
|
251
|
+
selectedTools: selectedTools
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 检查当前目录
|
|
256
|
+
function checkDirectory() {
|
|
257
|
+
const currentDir = process.cwd();
|
|
258
|
+
const claudeDir = path.join(currentDir, '.claude');
|
|
259
|
+
|
|
260
|
+
if (!fs.existsSync(claudeDir)) {
|
|
261
|
+
console.log(chalk.yellow('📁 创建 .claude 目录...'));
|
|
262
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
263
|
+
fs.mkdirSync(path.join(claudeDir, 'agents'), { recursive: true });
|
|
264
|
+
fs.mkdirSync(path.join(claudeDir, 'commands'), { recursive: true });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return claudeDir;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 安装角色
|
|
271
|
+
async function installRole(selectedRole, installType, claudeDir, selectedTools, customName = '') {
|
|
272
|
+
const roleName = selectedRole.role;
|
|
273
|
+
const results = {};
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
// 使用新的PromptXActionProcessor执行完整的action流程
|
|
277
|
+
const processor = new PromptXActionProcessor();
|
|
278
|
+
const mode = installType === 'agents' ? 'subagent' : 'command';
|
|
279
|
+
const processedContent = await processor.processRole(roleName, mode);
|
|
280
|
+
|
|
281
|
+
// 根据安装模式创建相应文件
|
|
282
|
+
const finalName = customName || (installType === 'agents' ? `${roleName}-agent` : roleName);
|
|
283
|
+
|
|
284
|
+
if (installType === 'agents') {
|
|
285
|
+
console.log(chalk.cyan(`🔧 生成 ${finalName} subagent文件...`));
|
|
286
|
+
const agentConfig = {
|
|
287
|
+
name: finalName,
|
|
288
|
+
description: `基于PromptX ${roleName}角色的专业AI助手 - 完整action实现`,
|
|
289
|
+
content: processedContent,
|
|
290
|
+
targetDir: claudeDir
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
294
|
+
if (selectedTools) {
|
|
295
|
+
agentConfig.tools = selectedTools;
|
|
296
|
+
}
|
|
297
|
+
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
298
|
+
|
|
299
|
+
const subagentResult = await ClaudeCodeBuilder.createSubagent(agentConfig);
|
|
300
|
+
|
|
301
|
+
if (!subagentResult.success) {
|
|
302
|
+
throw new Error(`创建Subagent失败: ${subagentResult.error}`);
|
|
303
|
+
}
|
|
304
|
+
results.agentFile = `${finalName}.md`;
|
|
305
|
+
results.usage = `Use the ${finalName} subagent to [任务描述]`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (installType === 'commands') {
|
|
309
|
+
console.log(chalk.cyan(`📋 生成 ${finalName} command文件...`));
|
|
310
|
+
|
|
311
|
+
const commandConfig = {
|
|
312
|
+
name: finalName,
|
|
313
|
+
description: `基于PromptX ${roleName}角色的专业助手 - 完整action实现`,
|
|
314
|
+
content: processedContent,
|
|
315
|
+
targetDir: claudeDir
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
319
|
+
if (selectedTools) {
|
|
320
|
+
commandConfig.allowedTools = selectedTools;
|
|
321
|
+
}
|
|
322
|
+
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
323
|
+
|
|
324
|
+
const commandResult = await ClaudeCodeBuilder.createCommand(commandConfig);
|
|
325
|
+
|
|
326
|
+
if (!commandResult.success) {
|
|
327
|
+
throw new Error(`创建Command失败: ${commandResult.error}`);
|
|
328
|
+
}
|
|
329
|
+
results.commandFile = `${finalName}.md`;
|
|
330
|
+
results.usage = `/${finalName}`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
results.roleName = roleName;
|
|
334
|
+
results.installType = installType;
|
|
335
|
+
return results;
|
|
336
|
+
|
|
337
|
+
} catch (error) {
|
|
338
|
+
throw new Error(`安装角色失败: ${error.message}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 主程序入口
|
|
343
|
+
export async function main() {
|
|
344
|
+
try {
|
|
345
|
+
showWelcome();
|
|
346
|
+
|
|
347
|
+
// 检查是否跳过MCP发现(用于快速测试)
|
|
348
|
+
const skipMCP = process.argv.includes('--skip-mcp');
|
|
349
|
+
|
|
350
|
+
let availableServers;
|
|
351
|
+
if (skipMCP) {
|
|
352
|
+
console.log(chalk.yellow('⚠️ 跳过MCP发现(测试模式)'));
|
|
353
|
+
availableServers = {
|
|
354
|
+
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
355
|
+
mcpServers: []
|
|
356
|
+
};
|
|
357
|
+
} else {
|
|
358
|
+
// 发现MCP服务器
|
|
359
|
+
console.log(chalk.cyan('🔍 正在发现MCP服务器...\n'));
|
|
360
|
+
try {
|
|
361
|
+
availableServers = await discoverMCPServers();
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error(chalk.yellow('⚠️ MCP服务器发现失败,使用默认配置'));
|
|
364
|
+
availableServers = {
|
|
365
|
+
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
366
|
+
mcpServers: []
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// 加载角色
|
|
372
|
+
console.log(chalk.cyan('🔍 正在从PromptX系统加载角色...\n'));
|
|
373
|
+
const { systemRoles, userRoles, manager } = await getAllRoles();
|
|
374
|
+
|
|
375
|
+
console.log(chalk.green('✅ 加载完成!'));
|
|
376
|
+
console.log(`📊 发现 ${chalk.bold(systemRoles.length)} 个系统角色,${chalk.bold(userRoles.length)} 个用户角色\n`);
|
|
377
|
+
|
|
378
|
+
// 显示角色选择
|
|
379
|
+
const { selectedRole, installType, confirm, selectedTools, customName } = await showRoleMenu(systemRoles, userRoles, availableServers);
|
|
380
|
+
|
|
381
|
+
if (!confirm) {
|
|
382
|
+
console.log(chalk.yellow('\n👋 安装已取消'));
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 检查目录
|
|
387
|
+
const claudeDir = checkDirectory();
|
|
388
|
+
|
|
389
|
+
console.log(chalk.blue(`\n🎭 开始安装角色: ${selectedRole.role} (${installType})`));
|
|
390
|
+
|
|
391
|
+
// 安装角色
|
|
392
|
+
const result = await installRole(selectedRole, installType, claudeDir, selectedTools, customName);
|
|
393
|
+
|
|
394
|
+
console.log(chalk.green.bold('\n✅ 角色安装完成!'));
|
|
395
|
+
console.log(`\n📄 生成的文件:`);
|
|
396
|
+
|
|
397
|
+
if (result.agentFile) {
|
|
398
|
+
console.log(` - ${chalk.gray('.claude/agents/')}${chalk.white(result.agentFile)}`);
|
|
399
|
+
}
|
|
400
|
+
if (result.commandFile) {
|
|
401
|
+
console.log(` - ${chalk.gray('.claude/commands/')}${chalk.white(result.commandFile)}`);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
console.log(chalk.magenta(`\n🎉 现在你可以在Claude Code中使用:`));
|
|
405
|
+
if (result.usage) {
|
|
406
|
+
console.log(chalk.yellow(` ${result.usage}`));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
console.log(chalk.gray(`\n💡 提示: 重启Claude Code以确保新配置生效`));
|
|
410
|
+
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.error(chalk.red('❌ 安装失败:'), error.message);
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// 运行主程序 - Windows兼容版本
|
|
418
|
+
// 通过bin.js调用时直接执行,通过import调用时也执行
|
|
419
|
+
main().catch(error => {
|
|
420
|
+
console.error(chalk.red('❌ 程序异常:'), error.message);
|
|
421
|
+
process.exit(1);
|
|
422
422
|
});
|