更新.gitignore以排除.kilocode目录;在DirectoryLocator.js中增强目录查找策略的注释,增加对IDE环境变量的检测逻辑,优化路径回退策略;在DirectoryService.js中添加IDE检测信息和路径配置建议,提升用户体验和环境配置的灵活性。

This commit is contained in:
sean
2025-06-15 21:33:55 +08:00
parent 195815def7
commit 920a41ec5a
3 changed files with 228 additions and 26 deletions

1
.gitignore vendored
View File

@ -76,3 +76,4 @@ temp/
*.orig *.orig
.husky/_ .husky/_
.kilocode/

View File

@ -90,13 +90,13 @@ class ProjectRootLocator extends DirectoryLocator {
constructor(options = {}) { constructor(options = {}) {
super(options) super(options)
// 可配置的查找策略优先级 // 可配置的查找策略优先级(按可靠性和准确性排序)
this.strategies = options.strategies || [ this.strategies = options.strategies || [
'existingPromptxDirectory', 'existingPromptxDirectory', // 1. 现有.promptx目录最可靠的项目标识
'currentWorkingDirectoryIfHasMarkers', 'packageJsonDirectory', // 2. 向上查找项目标识文件(最准确的项目边界)
'packageJsonDirectory', 'gitRootDirectory', // 3. Git根目录通用可靠
'gitRootDirectory', 'currentWorkingDirectoryIfHasMarkers', // 4. 当前目录项目标识(降级策略)
'currentWorkingDirectory' 'currentWorkingDirectory' // 5. 纯当前目录(最后回退)
] ]
// 项目标识文件 // 项目标识文件
@ -284,19 +284,19 @@ class PromptXWorkspaceLocator extends DirectoryLocator {
return cached return cached
} }
// 策略1IDE环境变量 // 策略1IDE环境变量(最高优先级 - 用户/IDE明确指定
const workspaceFromIDE = await this._fromIDEEnvironment() const workspaceFromIDE = await this._fromIDEEnvironment()
if (workspaceFromIDE) { if (workspaceFromIDE) {
return this.setCached(cacheKey, workspaceFromIDE) return this.setCached(cacheKey, workspaceFromIDE)
} }
// 策略2PromptX专用环境变量 // 策略2PromptX专用环境变量(用户手动配置)
const workspaceFromEnv = await this._fromPromptXEnvironment() const workspaceFromEnv = await this._fromPromptXEnvironment()
if (workspaceFromEnv) { if (workspaceFromEnv) {
return this.setCached(cacheKey, workspaceFromEnv) return this.setCached(cacheKey, workspaceFromEnv)
} }
// 策略3如果上下文指定了特定策略如init命令,直接使用项目根目录 // 策略3特定上下文策略如init命令的强制指定
if (context.strategies) { if (context.strategies) {
const workspaceFromProject = await this._fromProjectRoot(context) const workspaceFromProject = await this._fromProjectRoot(context)
if (workspaceFromProject) { if (workspaceFromProject) {
@ -304,40 +304,103 @@ class PromptXWorkspaceLocator extends DirectoryLocator {
} }
} }
// 策略4现有.promptx目录 // 策略4现有.promptx目录(已初始化的项目)
const workspaceFromExisting = await this._fromExistingDirectory(context.startDir) const workspaceFromExisting = await this._fromExistingDirectory(context.startDir)
if (workspaceFromExisting) { if (workspaceFromExisting) {
return this.setCached(cacheKey, workspaceFromExisting) return this.setCached(cacheKey, workspaceFromExisting)
} }
// 策略5项目根目录 // 策略5项目根目录(基于项目结构推断)
const workspaceFromProject = await this._fromProjectRoot(context) const workspaceFromProject = await this._fromProjectRoot(context)
if (workspaceFromProject) { if (workspaceFromProject) {
return this.setCached(cacheKey, workspaceFromProject) return this.setCached(cacheKey, workspaceFromProject)
} }
// 策略6回退到当前目录 // 策略6智能回退策略(兜底方案)
return this.setCached(cacheKey, context.startDir || process.cwd()) return this.setCached(cacheKey, await this._getSmartFallback(context))
} }
/** /**
* 从IDE环境变量获取 * 从IDE环境变量获取支持多种IDE
*/ */
async _fromIDEEnvironment() { async _fromIDEEnvironment() {
const workspaceFolders = process.env.WORKSPACE_FOLDER_PATHS // IDE环境变量检测策略按优先级排序
if (workspaceFolders) { const ideStrategies = [
// Claude IDE (现有格式)
{
name: 'Claude IDE',
vars: ['WORKSPACE_FOLDER_PATHS'],
parse: (value) => {
try { try {
const folders = JSON.parse(workspaceFolders) const folders = JSON.parse(value)
if (Array.isArray(folders) && folders.length > 0) { return Array.isArray(folders) && folders.length > 0 ? folders[0] : null
const firstFolder = folders[0]
if (await this.isValidDirectory(firstFolder)) {
return firstFolder
}
}
} catch { } catch {
// 忽略解析错误 return null
} }
} }
},
// VSCode
{
name: 'VSCode',
vars: ['VSCODE_WORKSPACE_FOLDER', 'VSCODE_CWD'],
parse: (value) => value
},
// IntelliJ IDEA / WebStorm / PhpStorm
{
name: 'JetBrains IDEs',
vars: ['PROJECT_ROOT', 'IDEA_INITIAL_DIRECTORY', 'WEBSTORM_PROJECT_PATH'],
parse: (value) => value
},
// Sublime Text
{
name: 'Sublime Text',
vars: ['SUBLIME_PROJECT_PATH', 'SUBL_PROJECT_DIR'],
parse: (value) => value
},
// Atom
{
name: 'Atom',
vars: ['ATOM_PROJECT_PATH', 'ATOM_HOME_PROJECT'],
parse: (value) => value
},
// Vim/Neovim
{
name: 'Vim/Neovim',
vars: ['VIM_PROJECT_ROOT', 'NVIM_PROJECT_ROOT'],
parse: (value) => value
},
// 通用工作目录
{
name: 'Generic',
vars: ['WORKSPACE_ROOT', 'PROJECT_DIR', 'WORKING_DIRECTORY'],
parse: (value) => value
}
]
// 按策略逐一检测
for (const strategy of ideStrategies) {
for (const varName of strategy.vars) {
const envValue = process.env[varName]
if (envValue && envValue.trim() !== '') {
const parsedPath = strategy.parse(envValue.trim())
if (parsedPath) {
const normalizedPath = this.normalizePath(this.expandHome(parsedPath))
if (normalizedPath && await this.isValidDirectory(normalizedPath)) {
// 记录检测到的IDE类型用于调试
this._detectedIDE = strategy.name
return normalizedPath
}
}
}
}
}
return null return null
} }
@ -370,6 +433,95 @@ class PromptXWorkspaceLocator extends DirectoryLocator {
const projectRoot = await this.projectRootLocator.locate(context) const projectRoot = await this.projectRootLocator.locate(context)
return projectRoot return projectRoot
} }
/**
* 智能回退策略
*/
async _getSmartFallback(context) {
// 1. 尝试从命令行参数推断
const argPath = await this._fromProcessArguments()
if (argPath && await this.isValidDirectory(argPath)) {
return argPath
}
// 2. 尝试从进程的工作目录
const processCwd = process.cwd()
if (await this.isValidDirectory(processCwd)) {
return processCwd
}
// 3. 最后回退到用户主目录
return os.homedir()
}
/**
* 从进程参数推断项目路径
*/
async _fromProcessArguments() {
const args = process.argv
// 查找可能的路径参数
for (let i = 0; i < args.length; i++) {
const arg = args[i]
// 查找 --project-path 或类似参数
if (arg.startsWith('--project-path=')) {
return arg.split('=')[1]
}
if (arg === '--project-path' && i + 1 < args.length) {
return args[i + 1]
}
// 查找 --cwd 参数
if (arg.startsWith('--cwd=')) {
return arg.split('=')[1]
}
if (arg === '--cwd' && i + 1 < args.length) {
return args[i + 1]
}
}
return null
}
/**
* 获取检测调试信息
*/
getDetectionInfo() {
return {
detectedIDE: this._detectedIDE || 'Unknown',
availableEnvVars: this._getAvailableEnvVars(),
platform: process.platform,
cwd: process.cwd(),
args: process.argv
}
}
/**
* 获取可用的环境变量
*/
_getAvailableEnvVars() {
const relevantVars = [
'WORKSPACE_FOLDER_PATHS', 'VSCODE_WORKSPACE_FOLDER', 'VSCODE_CWD',
'PROJECT_ROOT', 'IDEA_INITIAL_DIRECTORY', 'WEBSTORM_PROJECT_PATH',
'SUBLIME_PROJECT_PATH', 'SUBL_PROJECT_DIR',
'ATOM_PROJECT_PATH', 'ATOM_HOME_PROJECT',
'VIM_PROJECT_ROOT', 'NVIM_PROJECT_ROOT',
'WORKSPACE_ROOT', 'PROJECT_DIR', 'WORKING_DIRECTORY',
'PROMPTX_WORKSPACE', 'PWD'
]
const available = {}
for (const varName of relevantVars) {
if (process.env[varName]) {
available[varName] = process.env[varName]
}
}
return available
}
} }
/** /**

View File

@ -150,15 +150,30 @@ class DirectoryService {
const workspace = await this.getWorkspace(context) const workspace = await this.getWorkspace(context)
const promptxDir = await this.getPromptXDirectory(context) const promptxDir = await this.getPromptXDirectory(context)
// 获取IDE检测信息
const ideDetectionInfo = this.workspaceLocator?.getDetectionInfo() || {}
return { return {
platform: process.platform, platform: process.platform,
projectRoot, projectRoot,
workspace, workspace,
promptxDirectory: promptxDir, promptxDirectory: promptxDir,
isSame: projectRoot === workspace, isSame: projectRoot === workspace,
ideDetection: {
detectedIDE: ideDetectionInfo.detectedIDE,
availableEnvVars: ideDetectionInfo.availableEnvVars,
cwd: process.cwd(),
args: process.argv.slice(2) // 隐藏node和脚本路径
},
environment: { environment: {
// 主要IDE环境变量
WORKSPACE_FOLDER_PATHS: process.env.WORKSPACE_FOLDER_PATHS, WORKSPACE_FOLDER_PATHS: process.env.WORKSPACE_FOLDER_PATHS,
VSCODE_WORKSPACE_FOLDER: process.env.VSCODE_WORKSPACE_FOLDER,
PROJECT_ROOT: process.env.PROJECT_ROOT,
SUBLIME_PROJECT_PATH: process.env.SUBLIME_PROJECT_PATH,
// PromptX专用
PROMPTX_WORKSPACE: process.env.PROMPTX_WORKSPACE, PROMPTX_WORKSPACE: process.env.PROMPTX_WORKSPACE,
// 系统环境
PWD: process.env.PWD, PWD: process.env.PWD,
NODE_ENV: process.env.NODE_ENV NODE_ENV: process.env.NODE_ENV
}, },
@ -166,8 +181,42 @@ class DirectoryService {
cache: { cache: {
projectRootCacheSize: this.projectRootLocator?.cache.size || 0, projectRootCacheSize: this.projectRootLocator?.cache.size || 0,
workspaceCacheSize: this.workspaceLocator?.cache.size || 0 workspaceCacheSize: this.workspaceLocator?.cache.size || 0
},
recommendations: this._getPathRecommendations(ideDetectionInfo)
} }
} }
/**
* 获取路径配置建议
*/
_getPathRecommendations(ideDetectionInfo = {}) {
const recommendations = []
if (!ideDetectionInfo.detectedIDE || ideDetectionInfo.detectedIDE === 'Unknown') {
recommendations.push({
type: 'env_var',
message: '未检测到IDE环境变量建议设置项目路径环境变量',
suggestions: [
'export PROMPTX_WORKSPACE="/path/to/your/project"',
'export PROJECT_ROOT="/path/to/your/project"',
'export WORKSPACE_ROOT="/path/to/your/project"'
]
})
}
if (!ideDetectionInfo.availableEnvVars || Object.keys(ideDetectionInfo.availableEnvVars).length === 0) {
recommendations.push({
type: 'manual_config',
message: '建议在IDE中配置MCP工作目录',
suggestions: [
'VSCode: 在settings.json中设置workspace.folders',
'IntelliJ: 在Run Configuration中设置Working directory',
'Claude IDE: 确保workspace路径正确传递'
]
})
}
return recommendations
} }
/** /**