px2cc 2.2.3 → 2.2.5

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/bin.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * Px2CC 启动器 - Windows兼容版本
package/cli.js CHANGED
@@ -186,11 +186,17 @@ async function showRoleMenu(systemRoles, userRoles, availableServers) {
186
186
  },
187
187
  {
188
188
  name: `⚙️ Command - 通过 /${roleAnswer.selectedRole.role} 调用`,
189
- value: 'commands',
189
+ value: 'commands',
190
190
  short: 'Command'
191
191
  }
192
192
  ]
193
193
  },
194
+ {
195
+ type: 'confirm',
196
+ name: 'includeKnowledge',
197
+ message: '是否包含专业知识(Knowledge)?(知识内容可能较多,会增加文件大小)',
198
+ default: true
199
+ },
194
200
  {
195
201
  type: 'confirm',
196
202
  name: 'customName',
@@ -246,6 +252,7 @@ async function showRoleMenu(systemRoles, userRoles, availableServers) {
246
252
  return {
247
253
  selectedRole: roleAnswer.selectedRole,
248
254
  installType: typeAnswer.installType,
255
+ includeKnowledge: typeAnswer.includeKnowledge,
249
256
  confirm: confirmAnswer.confirm,
250
257
  customName: customName,
251
258
  selectedTools: selectedTools
@@ -268,7 +275,7 @@ function checkDirectory() {
268
275
  }
269
276
 
270
277
  // 安装角色
271
- async function installRole(selectedRole, installType, claudeDir, selectedTools, customName = '') {
278
+ async function installRole(selectedRole, installType, claudeDir, selectedTools, customName = '', includeKnowledge = true) {
272
279
  const roleName = selectedRole.role;
273
280
  const results = {};
274
281
 
@@ -276,7 +283,7 @@ async function installRole(selectedRole, installType, claudeDir, selectedTools,
276
283
  // 使用新的PromptXActionProcessor执行完整的action流程
277
284
  const processor = new PromptXActionProcessor();
278
285
  const mode = installType === 'agents' ? 'subagent' : 'command';
279
- const processedContent = await processor.processRole(roleName, mode);
286
+ const processedContent = await processor.processRole(roleName, mode, { includeKnowledge });
280
287
 
281
288
  // 根据安装模式创建相应文件
282
289
  const finalName = customName || (installType === 'agents' ? `${roleName}-agent` : roleName);
@@ -376,7 +383,7 @@ export async function main() {
376
383
  console.log(`📊 发现 ${chalk.bold(systemRoles.length)} 个系统角色,${chalk.bold(userRoles.length)} 个用户角色\n`);
377
384
 
378
385
  // 显示角色选择
379
- const { selectedRole, installType, confirm, selectedTools, customName } = await showRoleMenu(systemRoles, userRoles, availableServers);
386
+ const { selectedRole, installType, includeKnowledge, confirm, selectedTools, customName } = await showRoleMenu(systemRoles, userRoles, availableServers);
380
387
 
381
388
  if (!confirm) {
382
389
  console.log(chalk.yellow('\n👋 安装已取消'));
@@ -387,9 +394,12 @@ export async function main() {
387
394
  const claudeDir = checkDirectory();
388
395
 
389
396
  console.log(chalk.blue(`\n🎭 开始安装角色: ${selectedRole.role} (${installType})`));
397
+ if (!includeKnowledge) {
398
+ console.log(chalk.gray(' 📚 不包含专业知识(Knowledge)'));
399
+ }
390
400
 
391
401
  // 安装角色
392
- const result = await installRole(selectedRole, installType, claudeDir, selectedTools, customName);
402
+ const result = await installRole(selectedRole, installType, claudeDir, selectedTools, customName, includeKnowledge);
393
403
 
394
404
  console.log(chalk.green.bold('\n✅ 角色安装完成!'));
395
405
  console.log(`\n📄 生成的文件:`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "px2cc",
3
- "version": "2.2.3",
3
+ "version": "2.2.5",
4
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",
@@ -60,38 +60,80 @@ class RoleLoader {
60
60
  }
61
61
 
62
62
  /**
63
- * 解析DPML角色文档
63
+ * 解析DPML角色文档(支持新旧两种格式)
64
64
  * @param {string} content - 原始内容
65
65
  * @returns {Object} 解析后的sections
66
66
  */
67
67
  parseDPMLContent(content) {
68
68
  const sections = {};
69
69
 
70
- // 解析 <role> 标签
70
+ // 尝试旧格式:<role>...</role> 包裹的 XML 格式
71
71
  const roleMatch = content.match(/<role>([\s\S]*?)<\/role>/);
72
72
  if (roleMatch) {
73
73
  const roleContent = roleMatch[1];
74
74
 
75
75
  // 提取各个部分
76
- sections.personality = this.extractSection(roleContent, 'personality');
77
- sections.principle = this.extractSection(roleContent, 'principle');
78
- sections.knowledge = this.extractSection(roleContent, 'knowledge');
76
+ sections.personality = this.extractXMLSection(roleContent, 'personality');
77
+ sections.principle = this.extractXMLSection(roleContent, 'principle');
78
+ sections.knowledge = this.extractXMLSection(roleContent, 'knowledge');
79
+
80
+ // 如果成功提取到内容,返回
81
+ if (sections.personality || sections.principle || sections.knowledge) {
82
+ return sections;
83
+ }
84
+ }
85
+
86
+ // 尝试新格式:<role id="..."> 开头的 Markdown 格式
87
+ const newRoleMatch = content.match(/<role\s+id="[^"]*">/);
88
+ if (newRoleMatch || !roleMatch) {
89
+ // 新格式:直接使用整个内容作为角色定义
90
+ // 移除 <role id="..."> 和 </role> 标签
91
+ let cleanContent = content
92
+ .replace(/<role\s+id="[^"]*">\s*/g, '')
93
+ .replace(/<\/role>\s*$/g, '')
94
+ .trim();
95
+
96
+ // 将整个 Markdown 内容作为角色定义
97
+ sections.fullContent = cleanContent;
98
+
99
+ // 尝试从 Markdown 中提取结构化内容
100
+ sections.personality = this.extractMarkdownSection(cleanContent, ['核心定位', '角色定位', '人格', '身份']);
101
+ sections.principle = this.extractMarkdownSection(cleanContent, ['核心能力', '工作原则', '原则', '方法论']);
102
+ sections.knowledge = this.extractMarkdownSection(cleanContent, ['专业知识', '知识体系', '领域知识']);
79
103
  }
80
104
 
81
105
  return sections;
82
106
  }
83
107
 
84
108
  /**
85
- * 提取XML标签内容
109
+ * 提取XML标签内容(旧格式)
86
110
  * @param {string} content - 内容
87
111
  * @param {string} tagName - 标签名
88
112
  * @returns {string|null} 提取的内容
89
113
  */
90
- extractSection(content, tagName) {
114
+ extractXMLSection(content, tagName) {
91
115
  const regex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, 'i');
92
116
  const match = content.match(regex);
93
117
  return match ? match[1].trim() : null;
94
118
  }
119
+
120
+ /**
121
+ * 从 Markdown 内容中提取指定标题下的内容(新格式)
122
+ * @param {string} content - Markdown 内容
123
+ * @param {Array<string>} headingKeywords - 可能的标题关键词
124
+ * @returns {string|null} 提取的内容
125
+ */
126
+ extractMarkdownSection(content, headingKeywords) {
127
+ for (const keyword of headingKeywords) {
128
+ // 匹配 ## 或 ### 开头的标题
129
+ const regex = new RegExp(`^##\\s*${keyword}[^\\n]*\\n([\\s\\S]*?)(?=^##\\s|$)`, 'im');
130
+ const match = content.match(regex);
131
+ if (match) {
132
+ return match[1].trim();
133
+ }
134
+ }
135
+ return null;
136
+ }
95
137
  }
96
138
 
97
139
  /**
@@ -116,12 +158,12 @@ class DependencyAnalyzer {
116
158
  knowledges: []
117
159
  };
118
160
 
119
- if (!roleInfo.sections) {
161
+ if (!roleInfo.sections && !roleInfo.raw) {
120
162
  return dependencies;
121
163
  }
122
164
 
123
- // 收集所有资源引用
124
- const allRefs = this.extractResourceReferences(roleInfo.sections);
165
+ // 收集所有资源引用(从 sections 和原始内容中提取)
166
+ const allRefs = this.extractResourceReferences(roleInfo.sections, roleInfo.raw);
125
167
 
126
168
  console.log(chalk.gray(` 发现 ${allRefs.length} 个资源引用`));
127
169
 
@@ -157,10 +199,12 @@ class DependencyAnalyzer {
157
199
  /**
158
200
  * 提取资源引用
159
201
  * @param {Object} sections - 角色sections
202
+ * @param {string} rawContent - 原始内容
160
203
  * @returns {Array} 引用列表
161
204
  */
162
- extractResourceReferences(sections) {
205
+ extractResourceReferences(sections, rawContent) {
163
206
  const refs = [];
207
+ const seenRefs = new Set(); // 用于去重
164
208
 
165
209
  const extractFromText = (text) => {
166
210
  if (!text) return [];
@@ -172,10 +216,25 @@ class DependencyAnalyzer {
172
216
  }));
173
217
  };
174
218
 
219
+ const addRef = (ref) => {
220
+ const key = `${ref.protocol}://${ref.resource}`;
221
+ if (!seenRefs.has(key)) {
222
+ seenRefs.add(key);
223
+ refs.push(ref);
224
+ }
225
+ };
226
+
175
227
  // 从所有sections中提取引用
176
- Object.values(sections).forEach(section => {
177
- refs.push(...extractFromText(section));
178
- });
228
+ if (sections) {
229
+ Object.values(sections).forEach(section => {
230
+ extractFromText(section).forEach(addRef);
231
+ });
232
+ }
233
+
234
+ // 从原始内容中提取引用(确保不遗漏)
235
+ if (rawContent) {
236
+ extractFromText(rawContent).forEach(addRef);
237
+ }
179
238
 
180
239
  return refs;
181
240
  }
@@ -260,9 +319,12 @@ class LayerAssembler {
260
319
  * @param {Object} dependencies - 依赖资源
261
320
  * @param {Object} cognitionData - 认知数据
262
321
  * @param {string} mode - 模式 (command|subagent)
322
+ * @param {Object} options - 选项
323
+ * @param {boolean} options.includeKnowledge - 是否包含知识内容
263
324
  * @returns {string} 组装后的内容
264
325
  */
265
- assembleContent(roleInfo, dependencies, cognitionData, mode = 'command') {
326
+ assembleContent(roleInfo, dependencies, cognitionData, mode = 'command', options = {}) {
327
+ const { includeKnowledge = true } = options;
266
328
  const parts = [];
267
329
 
268
330
  // 标题部分
@@ -294,22 +356,30 @@ class LayerAssembler {
294
356
  parts.push('');
295
357
 
296
358
  // RoleLayer - 角色定义
297
- if (roleInfo.sections.personality) {
298
- parts.push('## 🎭 角色人格');
299
- parts.push(this.cleanContent(roleInfo.sections.personality));
359
+ // 如果有完整的 Markdown 内容(新格式),直接使用
360
+ if (roleInfo.sections.fullContent) {
361
+ parts.push('## 🎭 角色定义');
362
+ parts.push(this.cleanContent(roleInfo.sections.fullContent));
300
363
  parts.push('');
301
- }
364
+ } else {
365
+ // 旧格式:分别展示各个部分
366
+ if (roleInfo.sections.personality) {
367
+ parts.push('## 🎭 角色人格');
368
+ parts.push(this.cleanContent(roleInfo.sections.personality));
369
+ parts.push('');
370
+ }
302
371
 
303
- if (roleInfo.sections.principle) {
304
- parts.push('## 🔧 工作原则');
305
- parts.push(this.cleanContent(roleInfo.sections.principle));
306
- parts.push('');
307
- }
372
+ if (roleInfo.sections.principle) {
373
+ parts.push('## 🔧 工作原则');
374
+ parts.push(this.cleanContent(roleInfo.sections.principle));
375
+ parts.push('');
376
+ }
308
377
 
309
- if (roleInfo.sections.knowledge) {
310
- parts.push('## 📚 专业知识');
311
- parts.push(this.cleanContent(roleInfo.sections.knowledge));
312
- parts.push('');
378
+ if (roleInfo.sections.knowledge) {
379
+ parts.push('## 📚 专业知识');
380
+ parts.push(this.cleanContent(roleInfo.sections.knowledge));
381
+ parts.push('');
382
+ }
313
383
  }
314
384
 
315
385
  // 依赖资源
@@ -331,6 +401,20 @@ class LayerAssembler {
331
401
  });
332
402
  }
333
403
 
404
+ if (includeKnowledge && dependencies.knowledges.length > 0) {
405
+ parts.push('## 📚 专业知识');
406
+ dependencies.knowledges.forEach(knowledge => {
407
+ parts.push(`### ${knowledge.id}`);
408
+ parts.push(this.cleanContent(knowledge.content));
409
+ parts.push('');
410
+ });
411
+ } else if (!includeKnowledge && dependencies.knowledges.length > 0) {
412
+ parts.push('## 📚 专业知识');
413
+ parts.push(`> ℹ️ 该角色包含 ${dependencies.knowledges.length} 个知识模块,已按用户选择跳过加载。`);
414
+ parts.push(`> 知识模块: ${dependencies.knowledges.map(k => k.id).join(', ')}`);
415
+ parts.push('');
416
+ }
417
+
334
418
  // StateLayer - 状态信息
335
419
  parts.push('---');
336
420
  parts.push('');
@@ -402,11 +486,18 @@ export class PromptXActionProcessor {
402
486
  * 执行完整的PromptX Action流程
403
487
  * @param {string} roleId - 角色ID
404
488
  * @param {string} mode - 模式 (command|subagent)
489
+ * @param {Object} options - 选项
490
+ * @param {boolean} options.includeKnowledge - 是否包含知识内容(默认true)
405
491
  * @returns {string} 处理后的内容
406
492
  */
407
- async processRole(roleId, mode = 'command') {
493
+ async processRole(roleId, mode = 'command', options = {}) {
494
+ const { includeKnowledge = true } = options;
495
+
408
496
  try {
409
497
  console.log(chalk.blue(`\n🎭 开始执行 ${roleId} 的 PromptX Action 流程 (${mode} 模式)`));
498
+ if (!includeKnowledge) {
499
+ console.log(chalk.gray(` 📚 跳过知识内容加载`));
500
+ }
410
501
 
411
502
  // 1. 加载角色定义
412
503
  const roleInfo = await this.roleLoader.loadRole(roleId);
@@ -418,7 +509,7 @@ export class PromptXActionProcessor {
418
509
  const cognitionData = await this.cognitionLoader.checkNetworkExists(roleId);
419
510
 
420
511
  // 4. 三层组装
421
- const content = this.layerAssembler.assembleContent(roleInfo, dependencies, cognitionData, mode);
512
+ const content = this.layerAssembler.assembleContent(roleInfo, dependencies, cognitionData, mode, { includeKnowledge });
422
513
 
423
514
  console.log(chalk.green(`✅ PromptX Action 流程完成!`));
424
515