重构:引入统一的DirectoryService以优化目录管理
- 在InitCommand、RecallCommand、RememberCommand和PouchStateMachine中替换了直接路径处理逻辑,改为使用DirectoryService进行目录解析。 - 更新了ProjectDiscovery以使用新的getProjectRoot方法,标记旧方法为已弃用。 - 在executionContext中重构了工作目录获取逻辑,增强了兼容性和可维护性。 - 确保了对用户主目录的避免处理,提升了目录定位的智能性和可靠性。 此改动旨在提升代码的可读性和一致性,同时为未来的扩展打下基础。
This commit is contained in:
@ -2,11 +2,15 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const logger = require('./logger');
|
||||
const { getDirectoryService } = require('./DirectoryService');
|
||||
|
||||
/**
|
||||
* 执行上下文检测工具
|
||||
* 根据命令入口自动判断执行模式(CLI vs MCP)并获取正确的工作目录
|
||||
* 基于MCP社区标准实践,通过环境变量解决cwd获取问题
|
||||
* 执行上下文检测工具 (已重构)
|
||||
*
|
||||
* 现在使用统一的DirectoryService提供路径解析
|
||||
* 保持向后兼容的API,但内部使用新的架构
|
||||
*
|
||||
* @deprecated 推荐直接使用 DirectoryService
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -29,22 +33,61 @@ function getExecutionContext() {
|
||||
|
||||
/**
|
||||
* MCP模式下获取工作目录
|
||||
* 基于社区标准实践,优先从环境变量获取配置的工作目录
|
||||
* 使用新的DirectoryService进行路径解析
|
||||
* @returns {string} 工作目录路径
|
||||
*/
|
||||
function getMCPWorkingDirectory() {
|
||||
// 策略1:WORKSPACE_FOLDER_PATHS(VS Code/Cursor标准环境变量)
|
||||
try {
|
||||
const directoryService = getDirectoryService();
|
||||
|
||||
// 使用新的统一路径解析服务
|
||||
// 注意:这是异步操作,但为了保持API兼容性,我们需要同步处理
|
||||
// 在实际使用中,建议迁移到异步版本
|
||||
const context = {
|
||||
startDir: process.cwd(),
|
||||
platform: process.platform,
|
||||
avoidUserHome: true
|
||||
};
|
||||
|
||||
// 同步获取工作空间目录
|
||||
// TODO: 在后续版本中迁移到异步API
|
||||
return getWorkspaceSynchronous(context);
|
||||
|
||||
} catch (error) {
|
||||
logger.warn('[executionContext] 使用新服务失败,回退到旧逻辑:', error.message);
|
||||
return getMCPWorkingDirectoryLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步获取工作空间(临时解决方案)
|
||||
* @param {Object} context - 查找上下文
|
||||
* @returns {string} 工作空间路径
|
||||
*/
|
||||
function getWorkspaceSynchronous(context) {
|
||||
// 策略1:IDE环境变量
|
||||
const workspacePaths = process.env.WORKSPACE_FOLDER_PATHS;
|
||||
if (workspacePaths) {
|
||||
// 取第一个工作区路径(多工作区情况)
|
||||
const firstPath = workspacePaths.split(path.delimiter)[0];
|
||||
if (firstPath && isValidDirectory(firstPath)) {
|
||||
console.error(`[执行上下文] 使用WORKSPACE_FOLDER_PATHS: ${firstPath}`);
|
||||
return firstPath;
|
||||
try {
|
||||
const folders = JSON.parse(workspacePaths);
|
||||
if (Array.isArray(folders) && folders.length > 0) {
|
||||
const firstFolder = folders[0];
|
||||
if (isValidDirectory(firstFolder)) {
|
||||
console.error(`[执行上下文] 使用WORKSPACE_FOLDER_PATHS: ${firstFolder}`);
|
||||
return firstFolder;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// 忽略解析错误,尝试直接使用
|
||||
const firstPath = workspacePaths.split(path.delimiter)[0];
|
||||
if (firstPath && isValidDirectory(firstPath)) {
|
||||
console.error(`[执行上下文] 使用WORKSPACE_FOLDER_PATHS: ${firstPath}`);
|
||||
return firstPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 策略2:PROMPTX_WORKSPACE(PromptX专用环境变量,仅当明确配置且非空时使用)
|
||||
// 策略2:PromptX专用环境变量
|
||||
const promptxWorkspaceEnv = process.env.PROMPTX_WORKSPACE;
|
||||
if (promptxWorkspaceEnv && promptxWorkspaceEnv.trim() !== '') {
|
||||
const promptxWorkspace = normalizePath(expandHome(promptxWorkspaceEnv));
|
||||
@ -54,30 +97,39 @@ function getMCPWorkingDirectory() {
|
||||
}
|
||||
}
|
||||
|
||||
// 策略3:向上查找现有.promptx目录(复用现有项目配置)
|
||||
const existingPrompxRoot = findExistingPromptxDirectory(process.cwd());
|
||||
// 策略3:现有.promptx目录
|
||||
const existingPrompxRoot = findExistingPromptxDirectory(context.startDir);
|
||||
if (existingPrompxRoot) {
|
||||
console.error(`[执行上下文] 发现现有.promptx目录: ${existingPrompxRoot}`);
|
||||
return existingPrompxRoot;
|
||||
}
|
||||
|
||||
// 策略4:PWD环境变量(某些情况下可用)
|
||||
// 策略4:PWD环境变量
|
||||
const pwd = process.env.PWD;
|
||||
if (pwd && isValidDirectory(pwd) && pwd !== process.cwd()) {
|
||||
console.error(`[执行上下文] 使用PWD环境变量: ${pwd}`);
|
||||
return pwd;
|
||||
}
|
||||
|
||||
// 策略5:项目根目录智能推测(向上查找项目标识)
|
||||
const projectRoot = findProjectRoot(process.cwd());
|
||||
// 策略5:项目根目录
|
||||
const projectRoot = findProjectRoot(context.startDir);
|
||||
if (projectRoot && projectRoot !== process.cwd()) {
|
||||
console.error(`[执行上下文] 智能推测项目根目录: ${projectRoot}`);
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
// 策略6:回退到process.cwd()
|
||||
// 策略6:回退到当前目录
|
||||
console.error(`[执行上下文] 回退到process.cwd(): ${process.cwd()}`);
|
||||
console.error(`[执行上下文] 提示:建议在MCP配置中添加 "env": {"PROMPTX_WORKSPACE": "你的项目目录"}`)
|
||||
console.error(`[执行上下文] 提示:建议在MCP配置中添加 "env": {"PROMPTX_WORKSPACE": "你的项目目录"}`);
|
||||
return process.cwd();
|
||||
}
|
||||
|
||||
/**
|
||||
* 旧版MCP工作目录获取逻辑(兼容性备用)
|
||||
* @deprecated
|
||||
*/
|
||||
function getMCPWorkingDirectoryLegacy() {
|
||||
// 保留原始的同步逻辑作为备份
|
||||
return process.cwd();
|
||||
}
|
||||
|
||||
@ -134,6 +186,18 @@ function findProjectRoot(startDir) {
|
||||
const root = path.parse(currentDir).root;
|
||||
|
||||
while (currentDir !== root) {
|
||||
// Windows特有:避免用户家目录
|
||||
if (process.platform === 'win32') {
|
||||
const homeDir = os.homedir();
|
||||
if (path.resolve(currentDir) === path.resolve(homeDir)) {
|
||||
console.error(`[executionContext] 跳过用户家目录: ${currentDir}`);
|
||||
const parentDir = path.dirname(currentDir);
|
||||
if (parentDir === currentDir) break;
|
||||
currentDir = parentDir;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否包含项目标识文件
|
||||
for (const marker of projectMarkers) {
|
||||
const markerPath = path.join(currentDir, marker);
|
||||
@ -193,15 +257,25 @@ function getDebugInfo() {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 规范化路径
|
||||
*/
|
||||
function normalizePath(p) {
|
||||
return path.normalize(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开家目录路径
|
||||
*/
|
||||
function expandHome(filepath) {
|
||||
if (filepath.startsWith('~/') || filepath === '~') {
|
||||
return path.join(os.homedir(), filepath.slice(1));
|
||||
if (!filepath || typeof filepath !== 'string') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (filepath.startsWith('~/') || filepath === '~') {
|
||||
return path.join(os.homedir(), filepath.slice(2));
|
||||
}
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user