UNPKG

@ai-coding-labs/playwright-mcp-plus

Version:

Enhanced Playwright Tools for MCP with Project Session Isolation

193 lines (192 loc) 7.55 kB
/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { SessionDirectoryManager } from './sessionDirectoryManager.js'; import { ProjectIsolationManager, validateProjectIsolationParams } from './projectIsolation.js'; /** * 增强的项目隔离管理器 * 集成新的SessionDirectoryManager和现有的ProjectIsolationManager * 保持向后兼容性,同时提供扩展功能 */ export class EnhancedProjectIsolationManager { /** * 从配置和MCP工具参数创建用户数据目录 */ static async createUserDataDir(config, toolParams) { // 如果没有启用项目隔离,使用默认行为 if (!config.projectIsolation) return undefined; // 获取项目信息 const projectInfo = this.extractProjectInfo(toolParams); if (!projectInfo || !validateProjectIsolationParams(projectInfo)) throw new Error('Project isolation is enabled but required parameters are missing. Please provide both projectDrive and projectPath parameters.'); // 获取会话策略(默认为'system',用户无感知) const strategy = config.projectIsolationSessionStrategy || 'system'; try { // 使用新的SessionDirectoryManager const sessionOptions = { strategy, projectDrive: projectInfo.projectDrive, projectPath: projectInfo.projectPath, customRootDir: config.projectIsolationSessionRootDir, browserName: config.browser?.browserName, browserChannel: config.browser?.launchOptions?.channel, }; // 验证配置 const validation = SessionDirectoryManager.validateOptions(sessionOptions); if (!validation.valid) { // Invalid session directory configuration return undefined; } const userDataDir = SessionDirectoryManager.createUserDataDir(sessionOptions); if (userDataDir) { // 如果是项目策略,使用原有的ProjectIsolationManager来处理.gitignore等 if (strategy === 'project') await ProjectIsolationManager.ensureProjectDataDir(userDataDir); // Created session directory // 可选:清理旧的会话数据 if (strategy !== 'project') SessionDirectoryManager.cleanupOldSessions(userDataDir); } return userDataDir; } catch (error) { // Failed to create enhanced user data directory, falling back to original project isolation return ProjectIsolationManager.createUserDataDir(projectInfo); } } /** * 从MCP工具参数提取项目信息 */ static extractProjectInfo(toolParams) { if (!toolParams?.projectDrive || !toolParams?.projectPath) return undefined; return { projectDrive: toolParams.projectDrive, projectPath: toolParams.projectPath, }; } /** * 获取会话目录信息(用于调试和管理) */ static getSessionDirectoryInfo(config, toolParams) { const info = { enabled: !!config.projectIsolation, strategy: config.projectIsolationSessionStrategy || 'system', expectedPath: undefined, fallbackPath: undefined, }; if (!info.enabled) return info; const projectInfo = this.extractProjectInfo(toolParams); if (projectInfo) { // 计算预期路径 const sessionOptions = { strategy: info.strategy, projectDrive: projectInfo.projectDrive, projectPath: projectInfo.projectPath, customRootDir: config.projectIsolationSessionRootDir, browserName: config.browser?.browserName, browserChannel: config.browser?.launchOptions?.channel, }; try { info.expectedPath = SessionDirectoryManager.createUserDataDir(sessionOptions); } catch { // 忽略错误 } // 计算降级路径 try { info.fallbackPath = ProjectIsolationManager.createUserDataDir(projectInfo); } catch { // 忽略错误 } } return info; } /** * 迁移现有的项目会话目录到新策略 * 这是一个可选的工具函数,用于帮助用户迁移数据 */ static async migrateSessionDirectory(fromStrategy, toStrategy, projectInfo, customRootDir) { try { // 计算源路径 const fromOptions = { strategy: fromStrategy, projectDrive: projectInfo.projectDrive, projectPath: projectInfo.projectPath, customRootDir, }; // 计算目标路径 const toOptions = { strategy: toStrategy, projectDrive: projectInfo.projectDrive, projectPath: projectInfo.projectPath, customRootDir, }; const fromPath = SessionDirectoryManager.createUserDataDir(fromOptions); const toPath = SessionDirectoryManager.createUserDataDir(toOptions); if (!fromPath || !toPath) { return { success: false, error: 'Failed to calculate migration paths', }; } if (fromPath === toPath) { return { success: true, fromPath, toPath, }; } // 这里可以实现实际的迁移逻辑 // 目前只是返回路径信息,实际迁移需要更复杂的逻辑 return { success: true, fromPath, toPath, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * 获取所有策略的可能路径(用于调试) */ static getAllPossiblePaths(projectInfo, customRootDir) { const strategies = ['system', 'project', 'custom']; const paths = {}; for (const strategy of strategies) { try { const options = { strategy, projectDrive: projectInfo.projectDrive, projectPath: projectInfo.projectPath, customRootDir, }; paths[strategy] = SessionDirectoryManager.createUserDataDir(options); } catch { paths[strategy] = undefined; } } return paths; } }