UNPKG

openai-cli-unofficial

Version:

A powerful OpenAI CLI Coding Agent built with TypeScript

545 lines 18.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.StorageService = void 0; const fs = __importStar(require("fs")); const os = __importStar(require("os")); const path = __importStar(require("path")); const locales_1 = require("../locales"); /** * 配置存储服务 * 处理用户偏好设置的持久化 */ class StorageService { /** * 添加配置变更监听器 */ static onConfigChange(listener) { StorageService.configChangeListeners.push(listener); } /** * 移除配置变更监听器 */ static removeConfigChangeListener(listener) { const index = StorageService.configChangeListeners.indexOf(listener); if (index > -1) { StorageService.configChangeListeners.splice(index, 1); } } /** * 通知所有监听器配置已变更 */ static notifyConfigChange() { const apiConfig = StorageService.getApiConfig(); StorageService.configChangeListeners.forEach(listener => { try { listener(apiConfig); } catch (error) { console.warn('配置变更监听器执行失败:', error); } }); } /** * 确保配置目录存在 */ static ensureConfigDir() { if (!fs.existsSync(StorageService.CONFIG_DIR)) { fs.mkdirSync(StorageService.CONFIG_DIR, { recursive: true }); } } /** * 读取配置文件 */ static readConfig() { try { if (fs.existsSync(StorageService.CONFIG_FILE)) { const content = fs.readFileSync(StorageService.CONFIG_FILE, 'utf8'); return JSON.parse(content); } } catch (error) { console.warn('Failed to read config file:', error); } return {}; } /** * 写入配置文件 */ static writeConfig(config) { try { StorageService.ensureConfigDir(); fs.writeFileSync(StorageService.CONFIG_FILE, JSON.stringify(config, null, 2)); } catch (error) { console.warn('Failed to write config file:', error); } } /** * 初始化配置文件 * 如果配置文件不存在,则创建一个包含默认值的配置文件 */ static initializeConfig() { StorageService.ensureConfigDir(); if (!fs.existsSync(StorageService.CONFIG_FILE)) { const defaultConfig = { language: 'en', baseUrl: 'https://api.openai.com/v1', apiKey: '', model: 'gpt-4.1', contextTokens: 128000, maxConcurrency: 5, role: 'You are a professional software engineer.', maxToolCalls: 25, terminalSensitiveWords: [ 'rm -rf', 'mv', 'cp', 'dd', 'npm install', 'yarn add', 'pnpm install', 'git commit --amend', 'git push --force', ], mcpConfig: { mcpServers: {} }, }; // 确保内置MCP服务添加到默认配置中 const finalConfig = { ...defaultConfig, mcpConfig: StorageService.ensureBuiltInMcpServices(defaultConfig.mcpConfig) }; StorageService.writeConfig(finalConfig); } } /** * 获取保存的语言设置 */ static getSavedLanguage() { const config = StorageService.readConfig(); return config.language || null; } /** * 保存语言设置 */ static saveLanguage(language) { const config = StorageService.readConfig(); config.language = language; StorageService.writeConfig(config); } /** * 获取API配置 */ static getApiConfig() { const config = StorageService.readConfig(); return { baseUrl: config.baseUrl, apiKey: config.apiKey, model: config.model, contextTokens: config.contextTokens || 128000, maxConcurrency: config.maxConcurrency || 5, role: config.role, maxToolCalls: config.maxToolCalls || 25, terminalSensitiveWords: config.terminalSensitiveWords || [ 'rm -rf', 'mv', 'cp', 'dd', 'npm install', 'yarn add', 'pnpm install', 'git commit --amend', 'git push --force', ], }; } /** * 保存API基础地址 */ static saveBaseUrl(baseUrl) { const config = StorageService.readConfig(); config.baseUrl = baseUrl; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存API密钥 */ static saveApiKey(apiKey) { const config = StorageService.readConfig(); config.apiKey = apiKey; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存模型 */ static saveModel(model) { const config = StorageService.readConfig(); config.model = model; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存上下文token数量 */ static saveContextTokens(contextTokens) { const config = StorageService.readConfig(); config.contextTokens = contextTokens; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存最大并发数 */ static saveMaxConcurrency(maxConcurrency) { const config = StorageService.readConfig(); config.maxConcurrency = maxConcurrency; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存最大工具调用次数 */ static saveMaxToolCalls(maxToolCalls) { const config = StorageService.readConfig(); config.maxToolCalls = maxToolCalls; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存角色 */ static saveRole(role) { const config = StorageService.readConfig(); config.role = role; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 保存终端敏感词 */ static saveTerminalSensitiveWords(words) { const config = StorageService.readConfig(); config.terminalSensitiveWords = words; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 获取MCP配置 */ static getMcpConfig() { const config = StorageService.readConfig(); let mcpConfig = config.mcpConfig || { mcpServers: {} }; // 确保系统自带的MCP服务存在,如果有更新则保存 const originalJson = JSON.stringify(mcpConfig); mcpConfig = StorageService.ensureBuiltInMcpServices(mcpConfig); const updatedJson = JSON.stringify(mcpConfig); // 如果配置有变化,立即保存 if (originalJson !== updatedJson) { config.mcpConfig = mcpConfig; StorageService.writeConfig(config); } return mcpConfig; } /** * 确保系统自带的MCP服务存在 */ static ensureBuiltInMcpServices(mcpConfig) { // 使用默认语言'en'获取消息,避免循环依赖 const messages = (0, locales_1.getCurrentMessages)('en'); const builtInServices = StorageService.getBuiltInMcpServices(); // 检查所有内置服务 for (const [serviceName, serviceConfig] of Object.entries(builtInServices)) { const existingConfig = mcpConfig.mcpServers[serviceName]; if (!existingConfig) { // 没有配置,添加新的内置服务配置 mcpConfig.mcpServers[serviceName] = { ...serviceConfig }; } else if (existingConfig.command === 'openai-cli-mcp' || existingConfig.transport === 'stdio' || existingConfig.description?.includes('系统自带') || existingConfig.description?.includes('Built-in')) { // 存在旧配置,更新为内置服务配置 mcpConfig.mcpServers[serviceName] = { ...serviceConfig }; } } return mcpConfig; } /** * 保存MCP配置 */ static saveMcpConfig(mcpConfig) { const config = StorageService.readConfig(); // 确保保存时也包含系统自带的服务 mcpConfig = StorageService.ensureBuiltInMcpServices(mcpConfig); config.mcpConfig = mcpConfig; StorageService.writeConfig(config); } /** * 获取MCP配置的JSON字符串(用于编辑) */ static getMcpConfigJson() { const mcpConfig = StorageService.getMcpConfig(); return JSON.stringify(mcpConfig, null, 2); } /** * 从JSON字符串保存MCP配置 */ static saveMcpConfigFromJson(jsonString) { try { const mcpConfig = JSON.parse(jsonString); StorageService.saveMcpConfig(mcpConfig); } catch (error) { throw new Error('Invalid JSON format for MCP configuration'); } } /** * 批量保存API配置 */ static saveApiConfig(apiConfig) { const config = StorageService.readConfig(); if (apiConfig.baseUrl !== undefined) config.baseUrl = apiConfig.baseUrl; if (apiConfig.apiKey !== undefined) config.apiKey = apiConfig.apiKey; if (apiConfig.model !== undefined) config.model = apiConfig.model; if (apiConfig.contextTokens !== undefined) config.contextTokens = apiConfig.contextTokens; if (apiConfig.maxConcurrency !== undefined) config.maxConcurrency = apiConfig.maxConcurrency; if (apiConfig.maxToolCalls !== undefined) config.maxToolCalls = apiConfig.maxToolCalls; if (apiConfig.role !== undefined) config.role = apiConfig.role; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 获取所有配置 */ static getConfig() { return StorageService.readConfig(); } /** * 设置配置项 */ static setConfig(key, value) { const config = StorageService.readConfig(); config[key] = value; StorageService.writeConfig(config); } /** * 清除所有配置 */ static clearConfig() { const config = StorageService.readConfig(); delete config.baseUrl; delete config.apiKey; delete config.model; delete config.contextTokens; delete config.maxConcurrency; delete config.role; delete config.mcpConfig; delete config.mcpFunctionConfirmation; delete config.maxToolCalls; delete config.terminalSensitiveWords; // 保留语言设置 // delete config.language; StorageService.writeConfig(config); StorageService.notifyConfigChange(); } /** * 检查配置是否存在 */ static hasConfig() { return fs.existsSync(StorageService.CONFIG_FILE); } /** * 验证API配置完整性 */ static validateApiConfig() { const config = StorageService.getApiConfig(); const missing = []; if (!config.baseUrl) missing.push('baseUrl'); if (!config.apiKey) missing.push('apiKey'); if (!config.model) missing.push('model'); return { isValid: missing.length === 0, missing }; } /** * 强制更新MCP配置(修复旧配置) */ static updateMcpConfig() { const config = StorageService.readConfig(); let mcpConfig = config.mcpConfig || { mcpServers: {} }; // 强制重新检查和更新内置服务配置 mcpConfig = StorageService.ensureBuiltInMcpServices(mcpConfig); // 保存更新后的配置 config.mcpConfig = mcpConfig; StorageService.writeConfig(config); } /** * 获取系统内置MCP服务列表 */ static getBuiltInMcpServices() { // 使用默认语言'en'获取消息,避免循环依赖 const messages = (0, locales_1.getCurrentMessages)('en'); return { 'file-system': { transport: 'builtin', description: 'Unified file system service for reading, creating, editing, and managing files and directories' }, 'todos': { transport: 'builtin', description: 'Service for creating and managing a list of tasks (todos) to plan and track work.' }, 'terminal': { transport: 'builtin', description: 'Service for executing shell commands and getting the output.' } }; } /** * 检查并恢复缺失的系统MCP服务 * @param userMcpConfig 用户编辑的MCP配置 * @returns 包含系统服务的完整配置和是否有更新 */ static validateAndRestoreSystemMcpServices(userMcpConfig) { const builtInServices = StorageService.getBuiltInMcpServices(); const restoredServices = []; let hasUpdates = false; // 检查每个系统服务是否存在 for (const [serviceName, serviceConfig] of Object.entries(builtInServices)) { const userService = userMcpConfig.mcpServers[serviceName]; if (!userService) { // 系统服务不存在,添加它 userMcpConfig.mcpServers[serviceName] = { ...serviceConfig }; restoredServices.push(serviceName); hasUpdates = true; } else if (userService.transport !== 'builtin') { // 系统服务存在但配置不正确,修复它 userMcpConfig.mcpServers[serviceName] = { ...serviceConfig }; restoredServices.push(serviceName); hasUpdates = true; } } return { config: userMcpConfig, hasUpdates, restoredServices }; } /** * 检查MCP配置中是否包含受保护的系统服务 * @param mcpConfigJson 用户提供的JSON字符串 * @returns 验证结果 */ static validateMcpConfigJson(mcpConfigJson) { try { const parsedConfig = JSON.parse(mcpConfigJson); // 验证基本结构 if (!parsedConfig.mcpServers || typeof parsedConfig.mcpServers !== 'object') { // 使用默认语言'en'获取消息,避免循环依赖 const messages = (0, locales_1.getCurrentMessages)('en'); return { isValid: false, error: messages.systemDetector.validation.mcpConfigStructure }; } // 检查并恢复系统服务 const validation = StorageService.validateAndRestoreSystemMcpServices(parsedConfig); return { isValid: true, parsedConfig: validation.config, hasSystemUpdates: validation.hasUpdates, restoredServices: validation.restoredServices }; } catch (error) { // 使用默认语言'en'获取消息,避免循环依赖 const messages = (0, locales_1.getCurrentMessages)('en'); return { isValid: false, error: messages.systemDetector.validation.invalidJson }; } } /** * 获取MCP函数确认配置 */ static getMcpFunctionConfirmationConfig() { const config = StorageService.readConfig(); return config.mcpFunctionConfirmation || {}; } /** * 保存MCP函数确认配置 */ static saveMcpFunctionConfirmationConfig(confirmationConfig) { const config = StorageService.readConfig(); config.mcpFunctionConfirmation = confirmationConfig; StorageService.writeConfig(config); } /** * 检查指定函数是否需要确认 */ static isFunctionConfirmationRequired(functionName) { const config = StorageService.getMcpFunctionConfirmationConfig(); return config[functionName] === true; } /** * 设置指定函数的确认状态 */ static setFunctionConfirmationRequired(functionName, required) { const config = StorageService.getMcpFunctionConfirmationConfig(); config[functionName] = required; StorageService.saveMcpFunctionConfirmationConfig(config); } } exports.StorageService = StorageService; StorageService.CONFIG_DIR = path.join(os.homedir(), '.openai-cli'); StorageService.CONFIG_FILE = path.join(StorageService.CONFIG_DIR, 'config.json'); StorageService.configChangeListeners = []; //# sourceMappingURL=storage.js.map