重构命令执行逻辑,增强项目状态检查功能。更新InitCommand以支持从MCP和CLI传递工作目录参数,确保路径有效性并提供用户友好的提示。重写多个命令的execute方法,整合项目状态提示,提升用户体验和输出格式的可读性。

This commit is contained in:
sean
2025-06-16 14:42:36 +08:00
parent 40c3b83854
commit 3d29434d24
9 changed files with 515 additions and 15 deletions

View File

@ -5,6 +5,7 @@ const { COMMANDS } = require('../../../../constants')
const { getGlobalResourceManager } = require('../../resource')
const DPMLContentParser = require('../../resource/DPMLContentParser')
const SemanticRenderer = require('../../resource/SemanticRenderer')
const CurrentProjectManager = require('../../../utils/CurrentProjectManager')
const logger = require('../../../utils/logger')
/**
@ -20,6 +21,7 @@ class ActionCommand extends BasePouchCommand {
this.resourceManager = getGlobalResourceManager()
this.dpmlParser = new DPMLContentParser()
this.semanticRenderer = new SemanticRenderer()
this.currentProjectManager = new CurrentProjectManager()
}
getPurpose () {
@ -27,6 +29,8 @@ class ActionCommand extends BasePouchCommand {
}
async getContent (args) {
// 智能提示,不阻断服务
const [roleId] = args
if (!roleId) {
@ -477,6 +481,65 @@ ${recallContent}
}
}
}
/**
* 重写execute方法以添加项目状态检查
*/
async execute (args = []) {
// 获取项目状态提示
const projectPrompt = await this.currentProjectManager.generateTopLevelProjectPrompt('action')
const purpose = this.getPurpose()
const content = await this.getContent(args)
const pateoas = await this.getPATEOAS(args)
return this.formatOutputWithProjectCheck(purpose, content, pateoas, projectPrompt)
}
/**
* 格式化带有项目检查的输出
*/
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

View File

@ -2,6 +2,7 @@ const BasePouchCommand = require('../BasePouchCommand')
const fs = require('fs-extra')
const path = require('path')
const { getGlobalResourceManager } = require('../../resource')
const CurrentProjectManager = require('../../../utils/CurrentProjectManager')
const logger = require('../../../utils/logger')
/**
@ -13,6 +14,7 @@ class HelloCommand extends BasePouchCommand {
super()
// 使用全局单例 ResourceManager
this.resourceManager = getGlobalResourceManager()
this.currentProjectManager = new CurrentProjectManager()
}
getPurpose () {
@ -170,7 +172,7 @@ class HelloCommand extends BasePouchCommand {
let content = `🤖 **AI专业角色服务清单** (共 ${totalRoles} 个专业角色可供选择)
> 💡 **重要说明**以下是可激活的AI专业角色。每个角色都有唯一的ID可通过MCP工具激活。
> 💡 **使用说明**以下是可激活的AI专业角色。每个角色都有唯一的ID可通过MCP工具激活。
## 📋 可用角色列表
@ -337,6 +339,65 @@ class HelloCommand extends BasePouchCommand {
logger.info('❌ RegistryData 不可用')
}
}
/**
* 重写execute方法以添加项目状态检查
*/
async execute (args = []) {
// 获取项目状态提示
const projectPrompt = await this.currentProjectManager.generateTopLevelProjectPrompt('list')
const purpose = this.getPurpose()
const content = await this.getContent(args)
const pateoas = await this.getPATEOAS(args)
return this.formatOutputWithProjectCheck(purpose, content, pateoas, projectPrompt)
}
/**
* 格式化带有项目检查的输出
*/
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 = HelloCommand

View File

@ -4,6 +4,7 @@ const { COMMANDS } = require('../../../../constants')
const { getDirectoryService } = require('../../../utils/DirectoryService')
const RegistryData = require('../../resource/RegistryData')
const ProjectDiscovery = require('../../resource/discovery/ProjectDiscovery')
const CurrentProjectManager = require('../../../utils/CurrentProjectManager')
const logger = require('../../../utils/logger')
const path = require('path')
const fs = require('fs-extra')
@ -19,6 +20,7 @@ class InitCommand extends BasePouchCommand {
this.resourceManager = getGlobalResourceManager()
this.projectDiscovery = new ProjectDiscovery()
this.directoryService = getDirectoryService()
this.currentProjectManager = new CurrentProjectManager()
}
getPurpose () {
@ -26,18 +28,70 @@ class InitCommand extends BasePouchCommand {
}
async getContent (args) {
const [workspacePath = '.'] = args
// 获取工作目录参数,支持两种格式:
// 1. 来自MCP的对象格式{ workingDirectory: "path" }
// 2. 来自CLI的字符串格式["path"]
let workingDirectory
if (args && typeof args[0] === 'object' && args[0].workingDirectory) {
// MCP格式
workingDirectory = args[0].workingDirectory
} else if (args && typeof args[0] === 'string') {
// CLI格式
workingDirectory = args[0]
} else if (args && args.length > 0 && args[0]) {
// 兜底:直接取第一个参数
workingDirectory = args[0]
}
let projectPath
if (workingDirectory) {
// AI提供了工作目录使用AI提供的路径
projectPath = path.resolve(workingDirectory)
// 验证AI提供的路径是否有效
if (!await this.currentProjectManager.validateProjectPath(projectPath)) {
return `❌ 提供的工作目录无效: ${projectPath}
请确保:
1. 路径存在且为目录
2. 不是用户主目录
3. 具有适当的访问权限
// 构建统一的查找上下文
// 对于init命令我们优先使用当前目录不向上查找现有.promptx
💡 请提供一个有效的项目目录路径。`
}
// 保存AI提供的项目路径
await this.currentProjectManager.setCurrentProject(projectPath)
} else {
// AI没有提供工作目录检查是否已有保存的项目
const savedProject = await this.currentProjectManager.getCurrentProject()
if (savedProject) {
// 使用之前保存的项目路径
projectPath = savedProject
} else {
// 没有保存的项目要求AI提供
return `🎯 PromptX需要知道当前项目的工作目录。
请在调用此工具时提供 workingDirectory 参数,例如:
- workingDirectory: "/Users/sean/WorkSpaces/DeepracticeProjects/PromptX"
💡 你当前工作在哪个项目目录?请提供完整的绝对路径。`
}
}
// 构建统一的查找上下文,使用确定的项目路径
const context = {
startDir: workspacePath === '.' ? process.cwd() : path.resolve(workspacePath),
startDir: projectPath,
platform: process.platform,
avoidUserHome: true, // 特别是Windows环境下避免用户家目录
avoidUserHome: true,
// init命令特有优先当前目录不查找现有.promptx
strategies: [
'currentWorkingDirectoryIfHasMarkers',
'currentWorkingDirectory' // 如果当前目录没有项目标识,就直接使用当前目录
'currentWorkingDirectory'
]
}

View File

@ -2,6 +2,7 @@ const BasePouchCommand = require('../BasePouchCommand')
const { getGlobalResourceManager } = require('../../resource')
const DPMLContentParser = require('../../resource/DPMLContentParser')
const SemanticRenderer = require('../../resource/SemanticRenderer')
const CurrentProjectManager = require('../../../utils/CurrentProjectManager')
const { COMMANDS } = require('../../../../constants')
/**
@ -16,6 +17,7 @@ class LearnCommand extends BasePouchCommand {
this.resourceManager = getGlobalResourceManager()
this.dpmlParser = new DPMLContentParser()
this.semanticRenderer = new SemanticRenderer()
this.currentProjectManager = new CurrentProjectManager()
}
getPurpose () {
@ -66,7 +68,7 @@ class LearnCommand extends BasePouchCommand {
}
}
return this.formatSuccessResponse(protocol, resourceId, finalContent)
return await this.formatSuccessResponse(protocol, resourceId, finalContent)
} catch (error) {
return this.formatErrorResponse(resourceUrl, error.message)
}
@ -97,7 +99,7 @@ class LearnCommand extends BasePouchCommand {
/**
* 格式化成功响应
*/
formatSuccessResponse (protocol, resourceId, content) {
async formatSuccessResponse (protocol, resourceId, content) {
const protocolLabels = {
thought: '🧠 思维模式',
execution: '⚡ 执行模式',
@ -274,6 +276,65 @@ ${errorMessage}
}
}
}
/**
* 重写execute方法以添加项目状态检查
*/
async execute (args = []) {
// 获取项目状态提示
const projectPrompt = await this.currentProjectManager.generateTopLevelProjectPrompt('learn')
const purpose = this.getPurpose()
const content = await this.getContent(args)
const pateoas = await this.getPATEOAS(args)
return this.formatOutputWithProjectCheck(purpose, content, pateoas, projectPrompt)
}
/**
* 格式化带有项目检查的输出
*/
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 = LearnCommand

View File

@ -1,6 +1,6 @@
const BasePouchCommand = require('../BasePouchCommand')
const ResourceManager = require('../../resource/resourceManager')
const DPMLContentParser = require('../../resource/DPMLContentParser')
const DPMLContentParser = require('../../dpml/DPMLContentParser')
const SemanticRenderer = require('../../resource/SemanticRenderer')
const { COMMANDS } = require('../../../../constants')