fix: 修复Windows路径解析兼容性问题 (Issue #31)
- 增强PackageProtocol的Windows NPX环境检测逻辑 - 添加Windows特定的.cmd/.bat文件检测 - 标准化环境变量路径处理(Windows反斜杠) - 支持LOCALAPPDATA、APPDATA、TEMP等Windows目录 - 优化跨平台路径规范化 - 新增normalizePathForComparison方法统一路径比较 - 使用Node.js原生API确保路径处理正确性 - 改进文件访问权限验证的跨平台兼容性 - 增强NPX模式下的访问权限处理 - NPX模式下采用警告而非错误的宽松策略 - 优化开发和生产环境的权限检查差异 - 新增全面的Windows兼容性测试套件 - 创建Issue #31专项测试覆盖关键场景 - 模拟Windows环境进行跨平台测试验证 - 覆盖NPX检测、路径解析、资源加载、角色激活等核心流程 修复了Windows用户在NPX环境下激活角色时出现的"思维模式未在注册表中找到"等路径解析错误。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -105,20 +105,56 @@ class PackageProtocol extends ResourceProtocol {
|
||||
* 检测是否是npx执行
|
||||
*/
|
||||
_isNpxExecution () {
|
||||
// 检查环境变量
|
||||
if (process.env.npm_execpath && process.env.npm_execpath.includes('npx')) {
|
||||
return true
|
||||
// 标准化环境变量路径(处理Windows反斜杠)
|
||||
const normalizeEnvPath = (envPath) => {
|
||||
return envPath ? envPath.replace(/\\/g, '/').toLowerCase() : ''
|
||||
}
|
||||
|
||||
// 检查npm_config_cache路径
|
||||
if (process.env.npm_config_cache && process.env.npm_config_cache.includes('_npx')) {
|
||||
return true
|
||||
// 检查环境变量 - Windows和Unix兼容
|
||||
if (process.env.npm_execpath) {
|
||||
const normalizedExecPath = normalizeEnvPath(process.env.npm_execpath)
|
||||
if (normalizedExecPath.includes('npx')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 检查执行路径
|
||||
// 检查npm_config_cache路径 - Windows和Unix兼容
|
||||
if (process.env.npm_config_cache) {
|
||||
const normalizedCachePath = normalizeEnvPath(process.env.npm_config_cache)
|
||||
if (normalizedCachePath.includes('_npx')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 检查执行路径 - Windows和Unix兼容
|
||||
const scriptPath = process.argv[1]
|
||||
if (scriptPath && scriptPath.includes('_npx')) {
|
||||
return true
|
||||
if (scriptPath) {
|
||||
const normalizedScriptPath = normalizeEnvPath(scriptPath)
|
||||
if (normalizedScriptPath.includes('_npx')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Windows特定检查:检查.cmd或.bat文件
|
||||
if (process.platform === 'win32') {
|
||||
// 检查是否通过npx.cmd执行
|
||||
if (process.env.npm_execpath &&
|
||||
(process.env.npm_execpath.endsWith('npx.cmd') ||
|
||||
process.env.npm_execpath.endsWith('npx.bat'))) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Windows NPX缓存目录通常包含_npx
|
||||
const windowsNpxPaths = [
|
||||
process.env.LOCALAPPDATA && path.join(process.env.LOCALAPPDATA, 'npm-cache', '_npx'),
|
||||
process.env.APPDATA && path.join(process.env.APPDATA, 'npm', '_npx'),
|
||||
process.env.TEMP && path.join(process.env.TEMP, '_npx')
|
||||
].filter(Boolean)
|
||||
|
||||
const currentPath = __dirname
|
||||
if (windowsNpxPaths.some(npxPath => currentPath.includes(npxPath))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@ -391,13 +427,13 @@ class PackageProtocol extends ResourceProtocol {
|
||||
return
|
||||
}
|
||||
|
||||
// 标准化路径
|
||||
const normalizedPath = relativePath.replace(/^\/+/, '').replace(/\\/g, '/')
|
||||
// 使用Node.js原生API进行跨平台路径规范化
|
||||
const normalizedPath = this.normalizePathForComparison(relativePath)
|
||||
|
||||
// 检查是否匹配files字段中的任何模式
|
||||
const isAllowed = packageJson.files.some(filePattern => {
|
||||
// 标准化文件模式
|
||||
const normalizedPattern = filePattern.replace(/^\/+/, '').replace(/\\/g, '/')
|
||||
const normalizedPattern = this.normalizePathForComparison(filePattern)
|
||||
|
||||
// 精确匹配
|
||||
if (normalizedPattern === normalizedPath) {
|
||||
@ -430,7 +466,7 @@ class PackageProtocol extends ResourceProtocol {
|
||||
if (!isAllowed) {
|
||||
// 在生产环境严格检查,开发环境只警告
|
||||
const installMode = this.detectInstallMode()
|
||||
if (installMode === 'development') {
|
||||
if (installMode === 'development' || installMode === 'npx') {
|
||||
console.warn(`⚠️ Warning: Path '${relativePath}' not in package.json files field. This may cause issues after publishing.`)
|
||||
} else {
|
||||
throw new Error(`Access denied: Path '${relativePath}' is not included in package.json files field`)
|
||||
@ -439,7 +475,7 @@ class PackageProtocol extends ResourceProtocol {
|
||||
} catch (error) {
|
||||
// 如果读取package.json失败,在开发模式下允许访问
|
||||
const installMode = this.detectInstallMode()
|
||||
if (installMode === 'development') {
|
||||
if (installMode === 'development' || installMode === 'npx') {
|
||||
console.warn(`⚠️ Warning: Could not validate file access for '${relativePath}': ${error.message}`)
|
||||
} else {
|
||||
throw error
|
||||
@ -447,6 +483,28 @@ class PackageProtocol extends ResourceProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跨平台路径规范化函数
|
||||
* @param {string} inputPath - 输入路径
|
||||
* @returns {string} 规范化后的路径
|
||||
*/
|
||||
normalizePathForComparison (inputPath) {
|
||||
if (!inputPath || typeof inputPath !== 'string') {
|
||||
return ''
|
||||
}
|
||||
|
||||
// 使用Node.js原生API进行路径规范化
|
||||
let normalized = path.normalize(inputPath)
|
||||
|
||||
// 统一使用正斜杠进行比较(但不破坏实际的文件系统操作)
|
||||
normalized = normalized.replace(/\\/g, '/')
|
||||
|
||||
// 移除开头的斜杠
|
||||
normalized = normalized.replace(/^\/+/, '')
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查资源是否存在
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user