openai-cli-unofficial
Version:
A powerful OpenAI CLI Coding Agent built with TypeScript
545 lines • 18.8 kB
JavaScript
;
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