px2cc 1.1.0 → 2.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/cli.js +135 -83
- package/package.json +3 -2
- package/src/PromptXActionProcessor.js +490 -0
package/cli.js
CHANGED
|
@@ -7,85 +7,117 @@
|
|
|
7
7
|
|
|
8
8
|
import { resource } from '@promptx/core';
|
|
9
9
|
import { ClaudeCodeBuilder } from 'claude-code-builder';
|
|
10
|
+
import { PromptXActionProcessor } from './src/PromptXActionProcessor.js';
|
|
10
11
|
import inquirer from 'inquirer';
|
|
11
12
|
import chalk from 'chalk';
|
|
12
13
|
import path from 'path';
|
|
13
14
|
import fs from 'fs';
|
|
14
15
|
import { execSync } from 'child_process';
|
|
15
16
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
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 = {
|
|
19
27
|
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
20
|
-
|
|
28
|
+
mcpServers: []
|
|
21
29
|
};
|
|
22
30
|
|
|
23
31
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
console.log(chalk.gray(' 检查MCP服务器状态(可能需要一些时间)...'));
|
|
33
|
+
// 使用claude mcp list获取所有MCP服务器(增加超时时间)
|
|
34
|
+
const mcpOutput = execSync('claude mcp list', {
|
|
26
35
|
encoding: 'utf8',
|
|
27
|
-
timeout:
|
|
36
|
+
timeout: 30000 // 增加到30秒
|
|
28
37
|
});
|
|
29
38
|
|
|
30
|
-
//
|
|
39
|
+
// 解析输出,提取服务器信息
|
|
31
40
|
const lines = mcpOutput.split('\n');
|
|
41
|
+
|
|
32
42
|
for (const line of lines) {
|
|
33
43
|
const trimmedLine = line.trim();
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
// 匹配服务器名称(格式:serverName: command - status)
|
|
45
|
+
const match = trimmedLine.match(/^([^:]+):\s+(.+)\s+-\s+(✓|✗)\s+(.*)$/);
|
|
46
|
+
if (match && !trimmedLine.includes('Checking MCP server health')) {
|
|
47
|
+
const [, name, command, status, statusText] = match;
|
|
48
|
+
servers.mcpServers.push({
|
|
49
|
+
name: name.trim(),
|
|
50
|
+
command: command.trim(),
|
|
51
|
+
connected: status === '✓',
|
|
52
|
+
status: statusText.trim()
|
|
53
|
+
});
|
|
37
54
|
}
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
console.log(chalk.green(`✅ 发现 ${
|
|
57
|
+
console.log(chalk.green(`✅ 发现 ${servers.mcpServers.length} 个MCP服务器`));
|
|
41
58
|
|
|
42
59
|
} catch (error) {
|
|
43
|
-
|
|
44
|
-
|
|
60
|
+
if (error.code === 'ETIMEDOUT') {
|
|
61
|
+
console.error(chalk.red('❌ MCP服务器检查超时'));
|
|
62
|
+
console.error(chalk.gray(' 请检查网络连接或MCP服务器配置'));
|
|
63
|
+
} else {
|
|
64
|
+
console.error(chalk.red('❌ 无法获取MCP服务器列表'));
|
|
65
|
+
console.error(chalk.gray(` 原因: ${error.message}`));
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
45
68
|
}
|
|
46
69
|
|
|
47
|
-
return
|
|
70
|
+
return servers;
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
//
|
|
51
|
-
async function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
checked: true,
|
|
58
|
-
disabled: '(必需)'
|
|
59
|
-
}))
|
|
60
|
-
];
|
|
73
|
+
// 显示MCP服务器选择界面
|
|
74
|
+
async function selectMCPServers(roleName, availableServers) {
|
|
75
|
+
// 如果没有MCP服务器,直接返回undefined(继承所有工具)
|
|
76
|
+
if (availableServers.mcpServers.length === 0) {
|
|
77
|
+
console.log(chalk.gray(' 没有发现MCP服务器,将继承所有可用工具'));
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
61
80
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}))
|
|
70
|
-
|
|
81
|
+
// 只显示MCP服务器选择
|
|
82
|
+
const choices = [];
|
|
83
|
+
|
|
84
|
+
for (const server of availableServers.mcpServers) {
|
|
85
|
+
const statusIcon = server.connected ? '✓' : '✗';
|
|
86
|
+
const statusColor = server.connected ? chalk.green : chalk.red;
|
|
87
|
+
choices.push({
|
|
88
|
+
name: `${statusColor(statusIcon)} ${server.name} ${chalk.gray(`(${server.status})`)}`,
|
|
89
|
+
value: server.name,
|
|
90
|
+
checked: false, // 默认不选中任何MCP服务器
|
|
91
|
+
disabled: !server.connected ? '(未连接)' : false
|
|
92
|
+
});
|
|
71
93
|
}
|
|
72
94
|
|
|
95
|
+
console.log(chalk.blue('\n🔧 默认工具(自动包含):'), availableServers.defaultTools.join(', '));
|
|
96
|
+
|
|
73
97
|
const answer = await inquirer.prompt([{
|
|
74
98
|
type: 'checkbox',
|
|
75
|
-
name: '
|
|
76
|
-
message: `为 ${roleName}
|
|
77
|
-
choices: choices
|
|
78
|
-
validate: (input) => {
|
|
79
|
-
// 确保包含所有默认工具
|
|
80
|
-
const hasAllDefaults = availableTools.defaultTools.every(tool => input.includes(tool));
|
|
81
|
-
if (!hasAllDefaults) {
|
|
82
|
-
return '必须包含所有默认工具';
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
99
|
+
name: 'selectedServers',
|
|
100
|
+
message: `为 ${roleName} 选择额外的MCP服务器(可选):`,
|
|
101
|
+
choices: choices
|
|
86
102
|
}]);
|
|
87
103
|
|
|
88
|
-
|
|
104
|
+
// 处理选中的MCP服务器
|
|
105
|
+
const selectedMCPServers = answer.selectedServers || [];
|
|
106
|
+
|
|
107
|
+
if (selectedMCPServers.length === 0) {
|
|
108
|
+
console.log(chalk.gray(' 将继承所有可用工具(Claude Code默认行为)'));
|
|
109
|
+
return undefined; // Claude Code会继承所有工具
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 如果选择了特定服务器,只包含默认工具+选中服务器的工具
|
|
113
|
+
const selectedTools = availableServers.defaultTools.slice();
|
|
114
|
+
for (const serverName of selectedMCPServers) {
|
|
115
|
+
// 添加该服务器的所有工具(使用通配符或具体工具名)
|
|
116
|
+
selectedTools.push(`mcp__${serverName}__*`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(chalk.blue(` 已选择 ${selectedMCPServers.length} 个MCP服务器: ${selectedMCPServers.join(', ')}`));
|
|
120
|
+
return selectedTools;
|
|
89
121
|
}
|
|
90
122
|
|
|
91
123
|
// 获取PromptX角色
|
|
@@ -112,7 +144,7 @@ function showWelcome() {
|
|
|
112
144
|
}
|
|
113
145
|
|
|
114
146
|
// 显示角色选择菜单
|
|
115
|
-
async function showRoleMenu(systemRoles, userRoles,
|
|
147
|
+
async function showRoleMenu(systemRoles, userRoles, availableServers) {
|
|
116
148
|
const choices = [
|
|
117
149
|
...systemRoles.map(role => ({
|
|
118
150
|
name: `📦 ${role.id} ${chalk.gray('(系统角色)')}`,
|
|
@@ -166,8 +198,8 @@ async function showRoleMenu(systemRoles, userRoles, availableTools) {
|
|
|
166
198
|
|
|
167
199
|
let selectedTools = [];
|
|
168
200
|
if (typeAnswer.confirm) {
|
|
169
|
-
//
|
|
170
|
-
selectedTools = await
|
|
201
|
+
// 选择MCP服务器和工具
|
|
202
|
+
selectedTools = await selectMCPServers(roleAnswer.selectedRole.role, availableServers);
|
|
171
203
|
}
|
|
172
204
|
|
|
173
205
|
return {
|
|
@@ -199,27 +231,31 @@ async function installRole(selectedRole, installType, claudeDir, manager, select
|
|
|
199
231
|
const results = {};
|
|
200
232
|
|
|
201
233
|
try {
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
const
|
|
234
|
+
// 使用新的PromptXActionProcessor执行完整的action流程
|
|
235
|
+
const processor = new PromptXActionProcessor();
|
|
236
|
+
const mode = installType === 'agents' ? 'subagent' : 'command';
|
|
237
|
+
const processedContent = await processor.processRole(roleName, mode);
|
|
205
238
|
|
|
206
|
-
|
|
207
|
-
throw new Error(`无法加载角色 ${roleName} 的内容`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// 2. 根据安装目录创建相应文件
|
|
239
|
+
// 根据安装模式创建相应文件
|
|
211
240
|
if (installType === 'agents') {
|
|
212
|
-
console.log(chalk.cyan(`🔧 生成 ${roleName}
|
|
213
|
-
const
|
|
241
|
+
console.log(chalk.cyan(`🔧 生成 ${roleName} subagent文件...`));
|
|
242
|
+
const agentConfig = {
|
|
214
243
|
name: roleName,
|
|
215
|
-
description: `基于PromptX ${roleName}角色的专业AI
|
|
216
|
-
content:
|
|
217
|
-
tools: selectedTools,
|
|
244
|
+
description: `基于PromptX ${roleName}角色的专业AI助手 - 完整action实现`,
|
|
245
|
+
content: processedContent,
|
|
218
246
|
targetDir: claudeDir
|
|
219
|
-
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
250
|
+
if (selectedTools) {
|
|
251
|
+
agentConfig.tools = selectedTools;
|
|
252
|
+
}
|
|
253
|
+
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
254
|
+
|
|
255
|
+
const subagentResult = await ClaudeCodeBuilder.createSubagent(agentConfig);
|
|
220
256
|
|
|
221
257
|
if (!subagentResult.success) {
|
|
222
|
-
throw new Error(`创建
|
|
258
|
+
throw new Error(`创建Subagent失败: ${subagentResult.error}`);
|
|
223
259
|
}
|
|
224
260
|
results.agentFile = `${roleName}.md`;
|
|
225
261
|
results.usage = `/subagent ${roleName}`;
|
|
@@ -227,20 +263,21 @@ async function installRole(selectedRole, installType, claudeDir, manager, select
|
|
|
227
263
|
|
|
228
264
|
if (installType === 'commands') {
|
|
229
265
|
console.log(chalk.cyan(`📋 生成 ${roleName} command文件...`));
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
${roleContent.content}
|
|
234
|
-
|
|
235
|
-
现在开始处理用户需求。`;
|
|
236
|
-
|
|
237
|
-
const commandResult = await ClaudeCodeBuilder.createCommand({
|
|
266
|
+
|
|
267
|
+
const commandConfig = {
|
|
238
268
|
name: roleName,
|
|
239
|
-
description: `基于PromptX ${roleName}
|
|
240
|
-
content:
|
|
241
|
-
allowedTools: selectedTools,
|
|
269
|
+
description: `基于PromptX ${roleName}角色的专业助手 - 完整action实现`,
|
|
270
|
+
content: processedContent,
|
|
242
271
|
targetDir: claudeDir
|
|
243
|
-
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// 设置工具配置 - 如果用户没有选择特定工具,则继承所有可用工具
|
|
275
|
+
if (selectedTools) {
|
|
276
|
+
commandConfig.allowedTools = selectedTools;
|
|
277
|
+
}
|
|
278
|
+
// 如果没有选择特定工具,Claude Code会自动继承所有可用工具
|
|
279
|
+
|
|
280
|
+
const commandResult = await ClaudeCodeBuilder.createCommand(commandConfig);
|
|
244
281
|
|
|
245
282
|
if (!commandResult.success) {
|
|
246
283
|
throw new Error(`创建Command失败: ${commandResult.error}`);
|
|
@@ -263,9 +300,21 @@ async function main() {
|
|
|
263
300
|
try {
|
|
264
301
|
showWelcome();
|
|
265
302
|
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
|
|
303
|
+
// 检查是否跳过MCP发现(用于快速测试)
|
|
304
|
+
const skipMCP = process.argv.includes('--skip-mcp');
|
|
305
|
+
|
|
306
|
+
let availableServers;
|
|
307
|
+
if (skipMCP) {
|
|
308
|
+
console.log(chalk.yellow('⚠️ 跳过MCP发现(测试模式)'));
|
|
309
|
+
availableServers = {
|
|
310
|
+
defaultTools: ['Read', 'Write', 'Edit', 'Bash'],
|
|
311
|
+
mcpServers: []
|
|
312
|
+
};
|
|
313
|
+
} else {
|
|
314
|
+
// 发现MCP服务器
|
|
315
|
+
console.log(chalk.cyan('🔍 正在发现MCP服务器...\n'));
|
|
316
|
+
availableServers = await discoverMCPServers();
|
|
317
|
+
}
|
|
269
318
|
|
|
270
319
|
// 加载角色
|
|
271
320
|
console.log(chalk.cyan('🔍 正在从PromptX系统加载角色...\n'));
|
|
@@ -275,7 +324,7 @@ async function main() {
|
|
|
275
324
|
console.log(`📊 发现 ${chalk.bold(systemRoles.length)} 个系统角色,${chalk.bold(userRoles.length)} 个用户角色\n`);
|
|
276
325
|
|
|
277
326
|
// 显示角色选择
|
|
278
|
-
const { selectedRole, installType, confirm, selectedTools } = await showRoleMenu(systemRoles, userRoles,
|
|
327
|
+
const { selectedRole, installType, confirm, selectedTools } = await showRoleMenu(systemRoles, userRoles, availableServers);
|
|
279
328
|
|
|
280
329
|
if (!confirm) {
|
|
281
330
|
console.log(chalk.yellow('\n👋 安装已取消'));
|
|
@@ -314,6 +363,9 @@ async function main() {
|
|
|
314
363
|
}
|
|
315
364
|
|
|
316
365
|
// 运行主程序
|
|
317
|
-
if (import.meta.url ===
|
|
318
|
-
main()
|
|
366
|
+
if (import.meta.url === new URL(process.argv[1], 'file:').href) {
|
|
367
|
+
main().catch(error => {
|
|
368
|
+
console.error(chalk.red('❌ 程序异常:'), error.message);
|
|
369
|
+
process.exit(1);
|
|
370
|
+
});
|
|
319
371
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "px2cc",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "CLI tool
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "CLI tool that implements complete PromptX Action flow in Claude Code - role activation, dependency loading, cognition networks & memory systems",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"cli.js",
|
|
24
24
|
"bin.js",
|
|
25
|
+
"src/",
|
|
25
26
|
"README.md",
|
|
26
27
|
"package.json"
|
|
27
28
|
],
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptXActionProcessor - 实现完整的PromptX Action流程
|
|
3
|
+
*
|
|
4
|
+
* 替代简单的parsePromptXRole函数,实现:
|
|
5
|
+
* 1. 角色加载器 (RoleLoader)
|
|
6
|
+
* 2. 依赖分析器 (DependencyAnalyzer)
|
|
7
|
+
* 3. 认知网络加载器 (CognitionLoader)
|
|
8
|
+
* 4. 三层组装器 (LayerAssembler)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { resource } from '@promptx/core';
|
|
12
|
+
import fs from 'fs/promises';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import os from 'os';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 角色加载器 - 替代PromptX的ResourceManager
|
|
19
|
+
*/
|
|
20
|
+
class RoleLoader {
|
|
21
|
+
constructor(resourceManager) {
|
|
22
|
+
this.resourceManager = resourceManager;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 加载角色定义
|
|
27
|
+
* @param {string} roleId - 角色ID
|
|
28
|
+
* @returns {Object} 角色信息
|
|
29
|
+
*/
|
|
30
|
+
async loadRole(roleId) {
|
|
31
|
+
console.log(chalk.cyan(`📖 加载角色定义: ${roleId}`));
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// 确保ResourceManager已初始化
|
|
35
|
+
if (!this.resourceManager.initialized) {
|
|
36
|
+
await this.resourceManager.initializeWithNewArchitecture();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 加载角色资源
|
|
40
|
+
const result = await this.resourceManager.loadResource(`@role://${roleId}`);
|
|
41
|
+
|
|
42
|
+
if (!result || !result.success || !result.content) {
|
|
43
|
+
throw new Error(`无法加载角色 ${roleId} 的内容`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 解析DPML内容
|
|
47
|
+
const parsedContent = this.parseDPMLContent(result.content);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
id: roleId,
|
|
51
|
+
raw: result.content,
|
|
52
|
+
sections: parsedContent,
|
|
53
|
+
metadata: result.metadata || {}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red(`❌ 角色加载失败: ${error.message}`));
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 解析DPML角色文档
|
|
64
|
+
* @param {string} content - 原始内容
|
|
65
|
+
* @returns {Object} 解析后的sections
|
|
66
|
+
*/
|
|
67
|
+
parseDPMLContent(content) {
|
|
68
|
+
const sections = {};
|
|
69
|
+
|
|
70
|
+
// 解析 <role> 标签
|
|
71
|
+
const roleMatch = content.match(/<role>([\s\S]*?)<\/role>/);
|
|
72
|
+
if (roleMatch) {
|
|
73
|
+
const roleContent = roleMatch[1];
|
|
74
|
+
|
|
75
|
+
// 提取各个部分
|
|
76
|
+
sections.personality = this.extractSection(roleContent, 'personality');
|
|
77
|
+
sections.principle = this.extractSection(roleContent, 'principle');
|
|
78
|
+
sections.knowledge = this.extractSection(roleContent, 'knowledge');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return sections;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 提取XML标签内容
|
|
86
|
+
* @param {string} content - 内容
|
|
87
|
+
* @param {string} tagName - 标签名
|
|
88
|
+
* @returns {string|null} 提取的内容
|
|
89
|
+
*/
|
|
90
|
+
extractSection(content, tagName) {
|
|
91
|
+
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, 'i');
|
|
92
|
+
const match = content.match(regex);
|
|
93
|
+
return match ? match[1].trim() : null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 依赖分析器 - 分析和加载资源依赖
|
|
99
|
+
*/
|
|
100
|
+
class DependencyAnalyzer {
|
|
101
|
+
constructor(resourceManager) {
|
|
102
|
+
this.resourceManager = resourceManager;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 分析角色依赖
|
|
107
|
+
* @param {Object} roleInfo - 角色信息
|
|
108
|
+
* @returns {Object} 依赖资源
|
|
109
|
+
*/
|
|
110
|
+
async analyzeDependencies(roleInfo) {
|
|
111
|
+
console.log(chalk.cyan(`🔍 分析资源依赖...`));
|
|
112
|
+
|
|
113
|
+
const dependencies = {
|
|
114
|
+
thoughts: [],
|
|
115
|
+
executions: [],
|
|
116
|
+
knowledges: []
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
if (!roleInfo.sections) {
|
|
120
|
+
return dependencies;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 收集所有资源引用
|
|
124
|
+
const allRefs = this.extractResourceReferences(roleInfo.sections);
|
|
125
|
+
|
|
126
|
+
console.log(chalk.gray(` 发现 ${allRefs.length} 个资源引用`));
|
|
127
|
+
|
|
128
|
+
// 并发加载所有依赖
|
|
129
|
+
const loadPromises = allRefs.map(ref => this.loadDependency(ref));
|
|
130
|
+
const results = await Promise.allSettled(loadPromises);
|
|
131
|
+
|
|
132
|
+
// 分类处理结果
|
|
133
|
+
results.forEach((result, index) => {
|
|
134
|
+
if (result.status === 'fulfilled' && result.value) {
|
|
135
|
+
const ref = allRefs[index];
|
|
136
|
+
const content = result.value;
|
|
137
|
+
|
|
138
|
+
switch (ref.protocol) {
|
|
139
|
+
case 'thought':
|
|
140
|
+
dependencies.thoughts.push({ id: ref.resource, content });
|
|
141
|
+
break;
|
|
142
|
+
case 'execution':
|
|
143
|
+
dependencies.executions.push({ id: ref.resource, content });
|
|
144
|
+
break;
|
|
145
|
+
case 'knowledge':
|
|
146
|
+
dependencies.knowledges.push({ id: ref.resource, content });
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
console.log(chalk.green(`✅ 依赖分析完成: thoughts=${dependencies.thoughts.length}, executions=${dependencies.executions.length}, knowledges=${dependencies.knowledges.length}`));
|
|
153
|
+
|
|
154
|
+
return dependencies;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 提取资源引用
|
|
159
|
+
* @param {Object} sections - 角色sections
|
|
160
|
+
* @returns {Array} 引用列表
|
|
161
|
+
*/
|
|
162
|
+
extractResourceReferences(sections) {
|
|
163
|
+
const refs = [];
|
|
164
|
+
|
|
165
|
+
const extractFromText = (text) => {
|
|
166
|
+
if (!text) return [];
|
|
167
|
+
// 匹配 @protocol://resource 格式
|
|
168
|
+
const matches = text.matchAll(/@([^:]+):\/\/([^\\s\\>\\<]+)/g);
|
|
169
|
+
return Array.from(matches).map(match => ({
|
|
170
|
+
protocol: match[1],
|
|
171
|
+
resource: match[2]
|
|
172
|
+
}));
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// 从所有sections中提取引用
|
|
176
|
+
Object.values(sections).forEach(section => {
|
|
177
|
+
refs.push(...extractFromText(section));
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return refs;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 加载单个依赖
|
|
185
|
+
* @param {Object} ref - 引用对象
|
|
186
|
+
* @returns {Promise<string>} 内容
|
|
187
|
+
*/
|
|
188
|
+
async loadDependency(ref) {
|
|
189
|
+
try {
|
|
190
|
+
const resourceUrl = `@${ref.protocol}://${ref.resource}`;
|
|
191
|
+
const result = await this.resourceManager.loadResource(resourceUrl);
|
|
192
|
+
|
|
193
|
+
if (result && result.success && result.content) {
|
|
194
|
+
return result.content;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.warn(chalk.yellow(`⚠️ 无法加载依赖: ${resourceUrl}`));
|
|
198
|
+
return null;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.warn(chalk.yellow(`⚠️ 依赖加载失败: @${ref.protocol}://${ref.resource} - ${error.message}`));
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 认知网络加载器 - 加载PromptX认知数据
|
|
208
|
+
*/
|
|
209
|
+
class CognitionLoader {
|
|
210
|
+
constructor() {
|
|
211
|
+
this.basePath = path.join(os.homedir(), '.promptx', 'cognition');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 加载认知网络
|
|
216
|
+
* @param {string} roleId - 角色ID
|
|
217
|
+
* @returns {Object} Mind对象和可视化
|
|
218
|
+
*/
|
|
219
|
+
async loadCognitionNetwork(roleId) {
|
|
220
|
+
console.log(chalk.cyan(`🧠 加载认知网络: ${roleId}`));
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const networkFilePath = path.join(this.basePath, roleId, 'network.json');
|
|
224
|
+
|
|
225
|
+
// 检查文件是否存在
|
|
226
|
+
try {
|
|
227
|
+
await fs.access(networkFilePath);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.log(chalk.gray(` 未找到认知网络文件: ${roleId}`));
|
|
230
|
+
return {
|
|
231
|
+
mind: null,
|
|
232
|
+
mindmap: null,
|
|
233
|
+
hasNetwork: false
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 读取网络数据
|
|
238
|
+
const networkData = JSON.parse(await fs.readFile(networkFilePath, 'utf8'));
|
|
239
|
+
|
|
240
|
+
// 生成mindmap
|
|
241
|
+
const mindmap = this.generateMindmap(networkData);
|
|
242
|
+
|
|
243
|
+
// 构建Mind对象
|
|
244
|
+
const mind = this.buildMindObject(networkData);
|
|
245
|
+
|
|
246
|
+
console.log(chalk.green(`✅ 认知网络加载成功: ${mind.nodeCount} 个节点, ${mind.connectionCount} 个连接`));
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
mind,
|
|
250
|
+
mindmap,
|
|
251
|
+
hasNetwork: true,
|
|
252
|
+
networkData
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.warn(chalk.yellow(`⚠️ 认知网络加载失败: ${error.message}`));
|
|
257
|
+
return {
|
|
258
|
+
mind: null,
|
|
259
|
+
mindmap: null,
|
|
260
|
+
hasNetwork: false
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* 生成Mermaid mindmap
|
|
267
|
+
* @param {Object} networkData - 网络数据
|
|
268
|
+
* @returns {string} mindmap代码
|
|
269
|
+
*/
|
|
270
|
+
generateMindmap(networkData) {
|
|
271
|
+
if (!networkData.cues || Object.keys(networkData.cues).length === 0) {
|
|
272
|
+
return 'mindmap\n root((暂无认知数据))';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 找到权重最高的概念作为根节点
|
|
276
|
+
const cues = Object.entries(networkData.cues);
|
|
277
|
+
const rootCue = cues.reduce((max, [word, cue]) => {
|
|
278
|
+
const totalWeight = (cue.connections || []).reduce((sum, conn) => sum + (conn.weight || 0), 0);
|
|
279
|
+
return totalWeight > (max.totalWeight || 0) ? { word, totalWeight } : max;
|
|
280
|
+
}, {});
|
|
281
|
+
|
|
282
|
+
let mindmap = 'mindmap\n';
|
|
283
|
+
mindmap += ` root((${rootCue.word || '认知中心'}))\n`;
|
|
284
|
+
|
|
285
|
+
// 添加相关概念(取权重前10的连接)
|
|
286
|
+
if (rootCue.word && networkData.cues[rootCue.word]?.connections) {
|
|
287
|
+
const connections = networkData.cues[rootCue.word].connections
|
|
288
|
+
.sort((a, b) => (b.weight || 0) - (a.weight || 0))
|
|
289
|
+
.slice(0, 10);
|
|
290
|
+
|
|
291
|
+
connections.forEach(conn => {
|
|
292
|
+
if (conn.target) {
|
|
293
|
+
mindmap += ` ${conn.target}\n`;
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return mindmap;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 构建Mind对象
|
|
303
|
+
* @param {Object} networkData - 网络数据
|
|
304
|
+
* @returns {Object} Mind对象
|
|
305
|
+
*/
|
|
306
|
+
buildMindObject(networkData) {
|
|
307
|
+
const cues = networkData.cues || {};
|
|
308
|
+
const nodeCount = Object.keys(cues).length;
|
|
309
|
+
let connectionCount = 0;
|
|
310
|
+
|
|
311
|
+
Object.values(cues).forEach(cue => {
|
|
312
|
+
connectionCount += (cue.connections || []).length;
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
nodeCount,
|
|
317
|
+
connectionCount,
|
|
318
|
+
activatedCues: Object.keys(cues),
|
|
319
|
+
timestamp: networkData.timestamp,
|
|
320
|
+
version: networkData.version
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* 三层组装器 - 组装最终输出内容
|
|
327
|
+
*/
|
|
328
|
+
class LayerAssembler {
|
|
329
|
+
/**
|
|
330
|
+
* 组装完整内容
|
|
331
|
+
* @param {Object} roleInfo - 角色信息
|
|
332
|
+
* @param {Object} dependencies - 依赖资源
|
|
333
|
+
* @param {Object} cognitionData - 认知数据
|
|
334
|
+
* @param {string} mode - 模式 (command|subagent)
|
|
335
|
+
* @returns {string} 组装后的内容
|
|
336
|
+
*/
|
|
337
|
+
assembleContent(roleInfo, dependencies, cognitionData, mode = 'command') {
|
|
338
|
+
const parts = [];
|
|
339
|
+
|
|
340
|
+
// 标题部分
|
|
341
|
+
parts.push(`# 🧠 [Consciousness Prime] ${roleInfo.id}${mode === 'subagent' ? '专业助手' : '角色已激活'}`);
|
|
342
|
+
parts.push('');
|
|
343
|
+
|
|
344
|
+
// CognitionLayer - 认知网络可视化
|
|
345
|
+
if (cognitionData.hasNetwork && cognitionData.mindmap) {
|
|
346
|
+
parts.push('## 💭 Hippocampus网络');
|
|
347
|
+
parts.push('```mermaid');
|
|
348
|
+
parts.push(cognitionData.mindmap);
|
|
349
|
+
parts.push('```');
|
|
350
|
+
parts.push('');
|
|
351
|
+
|
|
352
|
+
if (cognitionData.mind) {
|
|
353
|
+
parts.push(`**网络状态**: ${cognitionData.mind.nodeCount} 个概念节点,${cognitionData.mind.connectionCount} 个关联连接`);
|
|
354
|
+
parts.push('');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// RoleLayer - 角色定义
|
|
359
|
+
if (roleInfo.sections.personality) {
|
|
360
|
+
parts.push('## 🎭 角色人格');
|
|
361
|
+
parts.push(this.cleanContent(roleInfo.sections.personality));
|
|
362
|
+
parts.push('');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (roleInfo.sections.principle) {
|
|
366
|
+
parts.push('## 🔧 工作原则');
|
|
367
|
+
parts.push(this.cleanContent(roleInfo.sections.principle));
|
|
368
|
+
parts.push('');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (roleInfo.sections.knowledge) {
|
|
372
|
+
parts.push('## 📚 专业知识');
|
|
373
|
+
parts.push(this.cleanContent(roleInfo.sections.knowledge));
|
|
374
|
+
parts.push('');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 依赖资源
|
|
378
|
+
if (dependencies.thoughts.length > 0) {
|
|
379
|
+
parts.push('## 💡 思维模式');
|
|
380
|
+
dependencies.thoughts.forEach(thought => {
|
|
381
|
+
parts.push(`### ${thought.id}`);
|
|
382
|
+
parts.push(this.cleanContent(thought.content));
|
|
383
|
+
parts.push('');
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (dependencies.executions.length > 0) {
|
|
388
|
+
parts.push('## ⚡ 执行技能');
|
|
389
|
+
dependencies.executions.forEach(execution => {
|
|
390
|
+
parts.push(`### ${execution.id}`);
|
|
391
|
+
parts.push(this.cleanContent(execution.content));
|
|
392
|
+
parts.push('');
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// StateLayer - 状态信息
|
|
397
|
+
parts.push('---');
|
|
398
|
+
parts.push('');
|
|
399
|
+
|
|
400
|
+
if (mode === 'command') {
|
|
401
|
+
parts.push(`🎉 ${roleInfo.id}角色激活完成!我现在以该角色身份为你服务。`);
|
|
402
|
+
} else {
|
|
403
|
+
parts.push('## 🤖 助手说明');
|
|
404
|
+
parts.push(`我是基于PromptX ${roleInfo.id}角色的专业AI助手。我会:`);
|
|
405
|
+
parts.push(`- 始终保持${roleInfo.id}的专业身份和思维模式`);
|
|
406
|
+
parts.push('- 利用完整的PromptX工具生态提供专业服务');
|
|
407
|
+
parts.push('- 在我们的对话过程中持续学习和记忆');
|
|
408
|
+
parts.push('');
|
|
409
|
+
parts.push('请告诉我你需要什么帮助?');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
parts.push('');
|
|
413
|
+
parts.push('💡 **可用的PromptX工具生态**:');
|
|
414
|
+
parts.push('- 使用PromptX的 `recall` 工具激活相关记忆和经验');
|
|
415
|
+
parts.push('- 使用PromptX的 `remember` 工具保存新的学习成果');
|
|
416
|
+
parts.push('- 使用PromptX的 `learn` 工具学习新的资源和知识');
|
|
417
|
+
parts.push('- 使用PromptX的 `toolx` 工具执行专业工具');
|
|
418
|
+
parts.push('- 具体工具名称取决于你的MCP配置');
|
|
419
|
+
parts.push('');
|
|
420
|
+
|
|
421
|
+
if (mode === 'command') {
|
|
422
|
+
parts.push('现在开始处理用户需求。');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return parts.join('\n');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 清理内容格式
|
|
430
|
+
* @param {string} content - 原始内容
|
|
431
|
+
* @returns {string} 清理后的内容
|
|
432
|
+
*/
|
|
433
|
+
cleanContent(content) {
|
|
434
|
+
if (!content) return '';
|
|
435
|
+
|
|
436
|
+
return content
|
|
437
|
+
// 移除PromptX资源引用标签(但保留引用内容的展开结果)
|
|
438
|
+
.replace(/<reference[^>]*>/g, '')
|
|
439
|
+
.replace(/<\/reference>/g, '')
|
|
440
|
+
// 清理多余空行
|
|
441
|
+
.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
442
|
+
// 移除开头结尾空白
|
|
443
|
+
.trim();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* PromptX Action处理器主类
|
|
449
|
+
*/
|
|
450
|
+
export class PromptXActionProcessor {
|
|
451
|
+
constructor() {
|
|
452
|
+
this.resourceManager = resource.getGlobalResourceManager();
|
|
453
|
+
this.roleLoader = new RoleLoader(this.resourceManager);
|
|
454
|
+
this.dependencyAnalyzer = new DependencyAnalyzer(this.resourceManager);
|
|
455
|
+
this.cognitionLoader = new CognitionLoader();
|
|
456
|
+
this.layerAssembler = new LayerAssembler();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* 执行完整的PromptX Action流程
|
|
461
|
+
* @param {string} roleId - 角色ID
|
|
462
|
+
* @param {string} mode - 模式 (command|subagent)
|
|
463
|
+
* @returns {string} 处理后的内容
|
|
464
|
+
*/
|
|
465
|
+
async processRole(roleId, mode = 'command') {
|
|
466
|
+
try {
|
|
467
|
+
console.log(chalk.blue(`\n🎭 开始执行 ${roleId} 的 PromptX Action 流程 (${mode} 模式)`));
|
|
468
|
+
|
|
469
|
+
// 1. 加载角色定义
|
|
470
|
+
const roleInfo = await this.roleLoader.loadRole(roleId);
|
|
471
|
+
|
|
472
|
+
// 2. 分析依赖资源
|
|
473
|
+
const dependencies = await this.dependencyAnalyzer.analyzeDependencies(roleInfo);
|
|
474
|
+
|
|
475
|
+
// 3. 加载认知网络
|
|
476
|
+
const cognitionData = await this.cognitionLoader.loadCognitionNetwork(roleId);
|
|
477
|
+
|
|
478
|
+
// 4. 三层组装
|
|
479
|
+
const content = this.layerAssembler.assembleContent(roleInfo, dependencies, cognitionData, mode);
|
|
480
|
+
|
|
481
|
+
console.log(chalk.green(`✅ PromptX Action 流程完成!`));
|
|
482
|
+
|
|
483
|
+
return content;
|
|
484
|
+
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.error(chalk.red(`❌ PromptX Action 流程失败: ${error.message}`));
|
|
487
|
+
throw error;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|