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
JavaScript
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