UNPKG

dpml-prompt

Version:

DPML-powered AI prompt framework - Revolutionary AI-First CLI system based on Deepractice Prompt Markup Language. Build sophisticated AI agents with structured prompts, memory systems, and execution frameworks.

600 lines (500 loc) 18.9 kB
const BasePouchCommand = require('../BasePouchCommand') const fs = require('fs-extra') const path = require('path') const { COMMANDS } = require('../../../../constants') const { getGlobalResourceManager } = require('../../resource') const DPMLContentParser = require('../../dpml/DPMLContentParser') const SemanticRenderer = require('../../dpml/SemanticRenderer') const ProjectManager = require('../../../utils/ProjectManager') const { getGlobalProjectManager } = require('../../../utils/ProjectManager') const { getGlobalServerEnvironment } = require('../../../utils/ServerEnvironment') const logger = require('../../../utils/logger') /** * 角色激活锦囊命令 * 负责分析角色文件,提取需要学习的thought、execution和knowledge */ class ActionCommand extends BasePouchCommand { constructor () { super() // 使用全局单例 ResourceManager this.resourceManager = getGlobalResourceManager() this.dpmlParser = new DPMLContentParser() this.semanticRenderer = new SemanticRenderer() this.projectManager = getGlobalProjectManager() } getPurpose () { return '激活特定AI角色,分析并生成具体的思维模式、行为模式和知识学习计划' } async getContent (args) { // 智能提示,不阻断服务 const [roleId] = args if (!roleId) { return `❌ 请指定要激活的角色ID 🔍 使用方法: 通过 MCP PromptX 工具的 action 功能激活角色 💡 查看可用角色: 使用 MCP PromptX 工具的 welcome 功能` } try { logger.debug(`[ActionCommand] 开始激活角色: ${roleId}`) // 0. 初始化 ResourceManager(确保引用解析正常工作) if (!this.resourceManager.initialized) { await this.resourceManager.initializeWithNewArchitecture() } // 1. 获取角色信息 const roleInfo = await this.getRoleInfo(roleId) logger.debug(`[ActionCommand] getRoleInfo结果:`, roleInfo) if (!roleInfo) { logger.warn(`[ActionCommand] 角色 "${roleId}" 不存在!`) return `❌ 角色 "${roleId}" 不存在! 🔍 可能的原因: - 角色尚未注册到系统中 - 刚刚创建的新角色需要刷新注册表 💡 解决方案: 1. **首先尝试**:使用 MCP PromptX 工具的 **init** 功能刷新注册表 2. **然后重试**:再次使用 action 功能激活角色 3. **查看角色**:使用 welcome 功能查看所有可用角色 🚨 **特别提示**:如果刚刚用女娲创建了新角色,必须先执行 init 刷新注册表!` } // 2. 分析角色文件,提取依赖 const dependencies = await this.analyzeRoleDependencies(roleInfo) // 3. 生成学习计划并直接加载所有内容 return await this.generateLearningPlan(roleInfo, dependencies) } catch (error) { logger.error('Action command error:', error) return `❌ 激活角色 "${roleId}" 时发生错误。 🔍 可能的原因: - 角色文件不存在或格式错误 - 新创建的角色尚未注册到系统 - 权限不足 - 系统资源问题 💡 解决方案: 1. **优先尝试**:使用 MCP PromptX 工具的 **init** 功能刷新注册表 2. **然后重试**:再次尝试激活角色 3. **查看可用角色**:使用 welcome 功能查看角色列表 🚨 **新角色提示**:如果是女娲等工具刚创建的角色,必须先执行 init! 📋 **错误详情**:${error.message}` } } /** * 获取角色信息(直接从ResourceManager) */ async getRoleInfo (roleId) { logger.debug(`[ActionCommand] getRoleInfo调用,角色ID: ${roleId}`) // 直接使用ResourceManager获取角色信息,移除对WelcomeCommand的依赖 logger.debug(`[ActionCommand] 直接从ResourceManager获取角色信息`) const roles = this.resourceManager.registryData.getResourcesByProtocol('role') logger.debug(`[ActionCommand] 找到${roles.length}个角色`) const role = roles.find(r => r.id === roleId) logger.debug(`[ActionCommand] 查找角色${roleId}结果:`, role ? '找到' : '未找到') if (!role) { return null } const result = { id: role.id, name: role.name, description: role.description, file: role.reference } logger.debug(`[ActionCommand] 返回角色信息:`, result) return result } /** * 分析角色文件,提取完整的角色语义(@引用 + 直接内容) */ async analyzeRoleDependencies (roleInfo) { try { // 处理文件路径,将@package://和@project://前缀替换为实际路径 let filePath = roleInfo.file if (filePath.startsWith('@package://')) { const PackageProtocol = require('../../resource/protocols/PackageProtocol') const packageProtocol = new PackageProtocol() const relativePath = filePath.replace('@package://', '') filePath = await packageProtocol.resolvePath(relativePath) } else if (filePath.startsWith('@project://')) { // 🎯 使用ProjectProtocol确保HTTP模式下正确的路径映射 const projectProtocol = this.resourceManager.protocols.get('project') const relativePath = filePath.replace('@project://', '') filePath = await projectProtocol.resolvePath(relativePath) } // 读取角色文件内容 const roleContent = await fs.readFile(filePath, 'utf-8') // 使用DPMLContentParser解析完整的角色语义 const roleSemantics = this.dpmlParser.parseRoleDocument(roleContent) // 提取@引用依赖(保持兼容性) // 注意:对于包含语义内容的角色,引用已在语义渲染中处理,无需重复加载 const thoughts = new Set() const executions = new Set() // 从所有标签中提取thought和execution引用 // 但排除已在语义内容中处理的引用 Object.values(roleSemantics).forEach(tagSemantics => { if (tagSemantics && tagSemantics.references) { tagSemantics.references.forEach(ref => { // 跳过已在语义内容中处理的引用 if (tagSemantics.fullSemantics) { // 如果标签有完整语义内容,其引用将在语义渲染中处理,无需独立加载 return } if (ref.protocol === 'thought') { thoughts.add(ref.resource) } else if (ref.protocol === 'execution') { executions.add(ref.resource) } }) } }) return { // 保持原有结构(兼容性) thoughts, executions, knowledge: [roleInfo.id], // 新增:完整的角色语义结构 roleSemantics: { personality: roleSemantics.personality || null, principle: roleSemantics.principle || null, knowledge: roleSemantics.knowledge || null } } } catch (error) { logger.error('Error analyzing role dependencies:', error) // 如果分析失败,返回基础结构 return { thoughts: [], executions: [], knowledge: [roleInfo.id], roleSemantics: { personality: null, principle: null, knowledge: null } } } } /** * 生成学习指引(基于分析出的依赖) */ generateLearningGuide (roleInfo, dependencies) { let guide = `🎬 **角色激活计划:${roleInfo.name}** 📋 **角色概述** ${roleInfo.description} ` // 思维模式部分 if (dependencies.thoughts.length > 0) { guide += `## 🧠 第一步:学习思维模式 掌握角色所需的核心思考技能 ` dependencies.thoughts.forEach((thought, index) => { guide += `### ${index + 1}. ${thought} \`\`\`bash promptx learn thought://${thought} \`\`\` ` }) } // 行为模式部分 if (dependencies.executions.length > 0) { guide += `## ⚖️ 第二步:学习行为模式 掌握角色所需的核心执行技能 ` dependencies.executions.forEach((execution, index) => { guide += `### ${index + 1}. ${execution} \`\`\`bash promptx learn execution://${execution} \`\`\` ` }) } // 知识部分 guide += `## 📚 第三步:学习专业知识 获取角色的领域知识体系 ` dependencies.knowledge.forEach((knowledge, index) => { guide += `### ${index + 1}. ${knowledge} 领域知识 \`\`\`bash promptx learn knowledge://${knowledge} \`\`\` ` }) // 编排学习 guide += `## 🎪 第四步:学习编排方式 理解如何组合使用已学的技能 \`\`\`bash promptx learn personality://${roleInfo.id} \`\`\` \`\`\`bash promptx learn principle://${roleInfo.id} \`\`\` ## ✅ 角色激活确认 完成学习后,请确认角色激活: 1. **思维确认**:🧠 "我已掌握所需的思考技能!" 2. **行为确认**:⚖️ "我已掌握所需的执行技能!" 3. **知识确认**:📚 "我已具备领域专业知识!" 4. **编排确认**:🎪 "我已理解技能的组合使用方式!" ## 🎯 下一步操作 角色激活完成后,可以: - 📝 **开始专业工作** - 运用角色能力解决实际问题 - 🔍 **调用记忆** - 使用 \`promptx recall\` 检索相关经验 - 🔄 **切换角色** - 使用 \`promptx welcome\` 选择其他专业角色 💡 **设计理念**:基于 DPML 基础协议组合,通过thought和execution的灵活编排实现角色能力。` return guide } /** * 加载学习内容(复用LearnCommand逻辑) */ async loadLearnContent (resourceUrl) { try { const result = await this.resourceManager.resolve(resourceUrl) if (!result.success) { return `❌ 无法加载 ${resourceUrl}: ${result.error.message}\n\n` } // 解析协议信息 const urlMatch = resourceUrl.match(/^(@[!?]?)?([a-zA-Z][a-zA-Z0-9_-]*):\/\/(.+)$/) if (!urlMatch) { return `❌ 无效的资源URL格式: ${resourceUrl}\n\n` } const [, loadingSemantic, protocol, resourceId] = urlMatch const protocolLabels = { thought: '🧠 思维模式', execution: '⚡ 执行模式', memory: '💾 记忆模式', personality: '👤 角色人格', principle: '⚖️ 行为原则', knowledge: '📚 专业知识' } const label = protocolLabels[protocol] || `📄 ${protocol}` return `## ✅ ${label}${resourceId} ${result.content} --- ` } catch (error) { return `❌ 加载 ${resourceUrl} 时发生错误: ${error.message}\n\n` } } /** * 生成学习计划并直接加载所有内容(包含完整的角色语义) */ async generateLearningPlan (roleInfo, dependencies) { const { thoughts, executions, roleSemantics } = dependencies const { id: roleId } = roleInfo let content = `🎭 **角色激活完成:\`${roleId}\` (${roleInfo.name})** - 所有技能已自动加载\n` // 加载思维模式技能(仅包含独立的thought引用) if (thoughts.size > 0) { content += `# 🧠 思维模式技能 (${thoughts.size}个)\n` // 加载引用的思维资源 for (const thought of Array.from(thoughts)) { content += await this.loadLearnContent(`thought://${thought}`) } } // 添加角色人格特征(支持@引用占位符语义渲染) if (roleSemantics.personality && roleSemantics.personality.fullSemantics) { content += `# 👤 角色人格特征\n` content += `## ✅ 👤 人格特征:${roleId}\n` const personalityContent = await this.semanticRenderer.renderSemanticContent( roleSemantics.personality, this.resourceManager ) content += `${personalityContent}\n` content += `---\n` } // 加载执行技能(仅包含独立的execution引用) if (executions.size > 0) { content += `# ⚡ 执行技能 (${executions.size}个)\n` // 加载引用的执行资源 for (const execution of Array.from(executions)) { content += await this.loadLearnContent(`execution://${execution}`) } } // 添加角色行为原则(支持@引用占位符语义渲染) if (roleSemantics.principle && roleSemantics.principle.fullSemantics) { content += `# ⚖️ 角色行为原则\n` content += `## ✅ ⚖️ 行为原则:${roleId}\n` const principleContent = await this.semanticRenderer.renderSemanticContent( roleSemantics.principle, this.resourceManager ) content += `${principleContent}\n` content += `---\n` } // 添加语义渲染的知识体系(支持@引用占位符) if (roleSemantics.knowledge && roleSemantics.knowledge.fullSemantics) { content += `# 📚 专业知识体系\n` content += `## ✅ 📚 知识体系:${roleId}-knowledge\n` const knowledgeContent = await this.semanticRenderer.renderSemanticContent( roleSemantics.knowledge, this.resourceManager ) content += `${knowledgeContent}\n` content += `---\n` } // 激活总结 content += `# 🎯 角色激活总结\n` content += `✅ **\`${roleId}\` (${roleInfo.name}) 角色已完全激活!**\n` content += `📋 **已获得能力**:\n` if (thoughts.size > 0) content += `- 🧠 思维模式:${Array.from(thoughts).join(', ')}\n` if (executions.size > 0) content += `- ⚡ 执行技能:${Array.from(executions).join(', ')}\n` // 显示角色核心组件 const roleComponents = [] if (roleSemantics.personality?.fullSemantics) roleComponents.push('👤 人格特征') if (roleSemantics.principle?.fullSemantics) roleComponents.push('⚖️ 行为原则') if (roleSemantics.knowledge?.fullSemantics) roleComponents.push('📚 专业知识') if (roleComponents.length > 0) { content += `- 🎭 角色组件:${roleComponents.join(', ')}\n` } content += `💡 **现在可以立即开始以 \`${roleId}\` (${roleInfo.name}) 身份提供专业服务!**\n` // 自动执行 recall 命令 content += await this.executeRecall(roleId) return content } /** * 自动执行 recall 命令 */ async executeRecall (roleId) { try { // 懒加载 RecallCommand const RecallCommand = require('./RecallCommand') const recallCommand = new RecallCommand() // 执行 recall,获取所有记忆(传入角色ID参数) const recallContent = await recallCommand.getContent([roleId]) return `--- ## 🧠 自动记忆检索结果 ${recallContent} ⚠️ **重要**: recall已自动执行完成,以上记忆将作为角色工作的重要参考依据 ` } catch (error) { logger.error('Auto recall error:', error) return `--- ## 🧠 自动记忆检索结果 ⚠️ **记忆检索出现问题**: ${error.message} 💡 **建议**: 可使用 MCP PromptX 工具的 recall 功能来检索相关记忆 ` } } getPATEOAS (args) { const [roleId] = args if (!roleId) { return { currentState: 'action_awaiting_role', availableTransitions: ['welcome'], nextActions: [ { name: '查看可用角色', description: '返回角色发现页面', method: 'MCP PromptX welcome 工具', priority: 'high' } ], metadata: { message: '需要指定角色ID' } } } return { currentState: 'role_activated_with_memory', availableTransitions: ['welcome', 'remember', 'learn'], nextActions: [ { name: '开始专业服务', description: '角色已激活并完成记忆检索,可直接提供专业服务', method: '开始对话', priority: 'high' }, { name: '返回角色选择', description: '选择其他角色', method: 'MCP PromptX welcome 工具', priority: 'medium' }, { name: '记忆新知识', description: '内化更多专业知识', method: 'MCP PromptX remember 工具', priority: 'low' }, { name: '学习新资源', description: '学习相关专业资源', method: 'MCP PromptX learn 工具', priority: 'low' } ], metadata: { targetRole: roleId, roleActivated: true, memoryRecalled: true, architecture: 'DPML协议组合', approach: '直接激活-自动记忆-立即可用', systemVersion: '锦囊串联状态机 v2.1', designPhilosophy: 'AI use CLI get prompt for AI - 一键专家化,自动记忆' } } } /** * 重写execute方法以添加多项目状态检查 */ async execute (args = []) { // 从执行上下文获取MCP信息 const mcpId = this.detectMcpId() const ideType = await this.detectIdeType() // 获取多项目状态提示 const projectPrompt = await this.projectManager.generateTopLevelProjectPrompt('action', mcpId, ideType) const purpose = this.getPurpose() const content = await this.getContent(args) const pateoas = await this.getPATEOAS(args) return this.formatOutputWithProjectCheck(purpose, content, pateoas, projectPrompt) } /** * 检测MCP进程ID */ detectMcpId() { const serverEnv = getGlobalServerEnvironment() if (serverEnv.isInitialized()) { return serverEnv.getMcpId() } return ProjectManager.generateMcpId() } /** * 检测IDE类型 - 从配置文件读取,移除环境变量检测 */ async detectIdeType() { const mcpId = this.detectMcpId() return await this.projectManager.getIdeType(mcpId) } /** * 格式化带有项目检查的输出 */ formatOutputWithProjectCheck(purpose, content, pateoas, projectPrompt) { const output = { purpose, content, pateoas, context: this.context, format: this.outputFormat, projectPrompt } if (this.outputFormat === 'json') { return output } // 人类可读格式 return { ...output, toString () { const divider = '='.repeat(60) const nextSteps = (pateoas.nextActions || []) .map(action => ` - ${action.name}: ${action.description}\n 方式: ${action.method || action.command || '通过MCP工具'}`) .join('\n') return `${projectPrompt} ${divider} 🎯 锦囊目的:${purpose} ${divider} 📜 锦囊内容: ${content} 🔄 下一步行动: ${nextSteps} 📍 当前状态:${pateoas.currentState} ${divider} ` } } } } module.exports = ActionCommand