🎯 实现统一项目工作目录:@project://.promptx/cwd

## 🎯 核心功能
- **统一分析环境**:所有工具分析阶段使用@project://.promptx/cwd作为工作目录
- **保持执行隔离**:工具执行阶段继续使用独立沙箱@user://.promptx/toolbox/{toolId}
- **协议路径支持**:新增resolveProtocolPath()方法处理@project://协议
- **自动目录创建**:首次使用时自动创建统一工作目录

##  设计价值
### **语义清晰**
- @project://.promptx/cwd 明确表达项目级统一工作目录概念
- 完美融入PromptX资源协议体系,保持架构一致性

### **功能优化**
- 分析阶段:统一环境,所有工具共享相同的工作目录上下文
- 执行阶段:隔离环境,每个工具独立沙箱确保安全性
- 路径可预测:开发者明确知道工具运行的目录环境

### **架构改进**
- 符合奥卡姆剃刀原则:用简洁的协议表达明确的语义
- 符合单一职责:统一工作目录专注于分析环境,沙箱专注于执行隔离
- 易于扩展:未来可轻松扩展@project://.promptx/temp等目录

## 🔧 技术实现
### **新增方法**
- `resolveProtocolPath(protocolPath)` - 解析@project://等协议路径
- 更新`createSandbox()`默认sandboxPath为`@project://.promptx/cwd`

### **路径映射**
```
分析阶段: @project://.promptx/cwd → /Users/sean/Management/ContradictionManagement/.promptx/cwd
执行阶段: @user://.promptx/toolbox/{toolId} → /Users/sean/.promptx/toolbox/{toolId}
```

## 🧪 测试验证
-  协议路径解析正确
-  统一工作目录自动创建
-  工具分析和执行流程正常
-  heywhale-activity-scraper完整测试通过

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sean
2025-07-05 22:02:35 +08:00
parent 32c9a521b8
commit 65eddb96df

View File

@ -74,7 +74,7 @@ class ToolSandbox {
this.toolContent = toolResult.content; this.toolContent = toolResult.content;
// 3. 设置沙箱路径 // 3. 设置沙箱路径(工具专用沙箱)
this.sandboxPath = await this.resolveSandboxPath(); this.sandboxPath = await this.resolveSandboxPath();
// 4. 在基础沙箱中分析工具 // 4. 在基础沙箱中分析工具
@ -207,9 +207,9 @@ class ToolSandbox {
* 在基础沙箱中分析工具 * 在基础沙箱中分析工具
*/ */
async analyzeToolInSandbox() { async analyzeToolInSandbox() {
const sandbox = this.createSandbox({ const sandbox = await this.createSandbox({
supportDependencies: false, supportDependencies: false
sandboxPath: process.cwd() // 使用默认的@project://.promptx/cwd
}); });
const script = new vm.Script(this.toolContent, { filename: `${this.toolId}.js` }); const script = new vm.Script(this.toolContent, { filename: `${this.toolId}.js` });
const context = vm.createContext(sandbox); const context = vm.createContext(sandbox);
@ -445,9 +445,9 @@ class ToolSandbox {
* 创建执行沙箱环境 * 创建执行沙箱环境
*/ */
async createExecutionSandbox() { async createExecutionSandbox() {
this.sandboxContext = this.createSandbox({ this.sandboxContext = await this.createSandbox({
supportDependencies: true, supportDependencies: true,
sandboxPath: this.sandboxPath sandboxPath: this.sandboxPath // 保持使用工具专用沙箱
}); });
// 在智能沙箱中重新加载工具 // 在智能沙箱中重新加载工具
@ -468,24 +468,27 @@ class ToolSandbox {
* 创建统一沙箱环境 * 创建统一沙箱环境
* @param {Object} options - 沙箱配置 * @param {Object} options - 沙箱配置
* @param {boolean} options.supportDependencies - 是否支持依赖解析 * @param {boolean} options.supportDependencies - 是否支持依赖解析
* @param {string} options.sandboxPath - 沙箱工作目录 * @param {string} options.sandboxPath - 沙箱工作目录,支持协议路径
* @returns {Object} 沙箱环境对象 * @returns {Object} 沙箱环境对象
*/ */
createSandbox(options = {}) { async createSandbox(options = {}) {
const { const {
supportDependencies = false, supportDependencies = false,
sandboxPath = process.cwd() sandboxPath = '@project://.promptx/cwd'
} = options; } = options;
// 解析协议路径为实际路径
const resolvedPath = await this.resolveProtocolPath(sandboxPath);
return { return {
require: supportDependencies ? require: supportDependencies ?
this.createSmartRequire(sandboxPath) : this.createSmartRequire(resolvedPath) :
this.createAnalysisRequire(), this.createAnalysisRequire(),
module: { exports: {} }, module: { exports: {} },
exports: {}, exports: {},
console: console, console: console,
Buffer: Buffer, Buffer: Buffer,
process: this.createProcessMock(sandboxPath), process: this.createProcessMock(resolvedPath),
setTimeout: setTimeout, setTimeout: setTimeout,
clearTimeout: clearTimeout, clearTimeout: clearTimeout,
setInterval: setInterval, setInterval: setInterval,
@ -504,6 +507,50 @@ class ToolSandbox {
}; };
} }
/**
* 解析协议路径(支持@project://等协议)
* @param {string} protocolPath - 协议路径,如@project://.promptx/cwd
* @returns {Promise<string>} 解析后的绝对路径
*/
async resolveProtocolPath(protocolPath) {
// 处理undefined或null的情况
if (!protocolPath) {
throw new Error('protocolPath is required but was undefined');
}
// 如果是协议路径使用ResourceManager解析
if (protocolPath.startsWith('@')) {
if (!this.resourceManager) {
throw new Error('ResourceManager not set. Cannot resolve protocol path.');
}
const projectProtocol = this.resourceManager.protocols.get('project');
if (!projectProtocol) {
throw new Error('ProjectProtocol not found. Cannot resolve @project:// path.');
}
// 提取协议路径的相对部分
const relativePath = protocolPath.replace(/^@project:\/\//, '');
const resolvedPath = await projectProtocol.resolvePath(relativePath, new Map());
// 确保目录存在
const fs = require('fs').promises;
try {
await fs.access(resolvedPath);
} catch (error) {
if (error.code === 'ENOENT') {
await fs.mkdir(resolvedPath, { recursive: true });
console.log(`[ToolSandbox] 创建统一工作目录: ${resolvedPath}`);
}
}
return resolvedPath;
}
// 普通路径直接返回
return protocolPath;
}
/** /**
* 创建完整的process对象mock * 创建完整的process对象mock
* @param {string} sandboxPath - 沙箱工作目录 * @param {string} sandboxPath - 沙箱工作目录