@vibeapi/api-helper 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.js +119 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +130 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +105 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +5 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/lang.d.ts +1 -0
- package/dist/commands/lang.js +28 -0
- package/dist/commands/lang.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-validator.d.ts +12 -0
- package/dist/lib/api-validator.js +79 -0
- package/dist/lib/api-validator.js.map +1 -0
- package/dist/lib/claude-code-manager.d.ts +86 -0
- package/dist/lib/claude-code-manager.js +233 -0
- package/dist/lib/claude-code-manager.js.map +1 -0
- package/dist/lib/command.d.ts +10 -0
- package/dist/lib/command.js +168 -0
- package/dist/lib/command.js.map +1 -0
- package/dist/lib/config.d.ts +64 -0
- package/dist/lib/config.js +226 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/i18n.d.ts +20 -0
- package/dist/lib/i18n.js +149 -0
- package/dist/lib/i18n.js.map +1 -0
- package/dist/lib/opencode-manager.d.ts +55 -0
- package/dist/lib/opencode-manager.js +134 -0
- package/dist/lib/opencode-manager.js.map +1 -0
- package/dist/lib/tool-manager.d.ts +25 -0
- package/dist/lib/tool-manager.js +280 -0
- package/dist/lib/tool-manager.js.map +1 -0
- package/dist/lib/wizard.d.ts +23 -0
- package/dist/lib/wizard.js +360 -0
- package/dist/lib/wizard.js.map +1 -0
- package/dist/locales/en_US.json +146 -0
- package/dist/locales/zh_CN.json +146 -0
- package/dist/utils/logger.d.ts +55 -0
- package/dist/utils/logger.js +202 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/string-width.d.ts +38 -0
- package/dist/utils/string-width.js +131 -0
- package/dist/utils/string-width.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, readdirSync, statSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import * as yaml from 'js-yaml';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
export const DEFAULT_BASE_URL = 'https://www.vibeapi.cn';
|
|
7
|
+
export const DEFAULT_MODELS = {
|
|
8
|
+
haiku: 'claude-haiku-4-5-20251001',
|
|
9
|
+
sonnet: 'claude-sonnet-4-6',
|
|
10
|
+
opus: 'claude-opus-4-6',
|
|
11
|
+
reasoning: 'claude-opus-4-6'
|
|
12
|
+
};
|
|
13
|
+
export class ConfigManager {
|
|
14
|
+
static instance;
|
|
15
|
+
configDir;
|
|
16
|
+
configPath;
|
|
17
|
+
config;
|
|
18
|
+
constructor() {
|
|
19
|
+
// chelper 配置文件路径(跨平台支持)
|
|
20
|
+
// - macOS/Linux: ~/.chelper/config.yaml
|
|
21
|
+
// - Windows: %USERPROFILE%\.chelper\config.yaml
|
|
22
|
+
// (例如: C:\Users\username\.chelper\config.yaml)
|
|
23
|
+
this.configDir = this.getConfigDir();
|
|
24
|
+
this.configPath = join(this.configDir, 'config.yaml');
|
|
25
|
+
this.config = this.loadConfig();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 获取配置目录路径,支持环境变量覆盖
|
|
29
|
+
*/
|
|
30
|
+
getConfigDir() {
|
|
31
|
+
// 支持环境变量覆盖
|
|
32
|
+
const customDir = process.env.CHELPER_CONFIG_DIR;
|
|
33
|
+
if (customDir && customDir.trim()) {
|
|
34
|
+
return customDir.trim();
|
|
35
|
+
}
|
|
36
|
+
// 支持测试环境
|
|
37
|
+
const testHome = process.env.CHELPER_TEST_HOME;
|
|
38
|
+
if (testHome && testHome.trim()) {
|
|
39
|
+
return join(testHome.trim(), '.chelper');
|
|
40
|
+
}
|
|
41
|
+
return join(homedir(), '.chelper');
|
|
42
|
+
}
|
|
43
|
+
static getInstance() {
|
|
44
|
+
if (!ConfigManager.instance) {
|
|
45
|
+
ConfigManager.instance = new ConfigManager();
|
|
46
|
+
}
|
|
47
|
+
return ConfigManager.instance;
|
|
48
|
+
}
|
|
49
|
+
ensureConfigDir() {
|
|
50
|
+
if (!existsSync(this.configDir)) {
|
|
51
|
+
mkdirSync(this.configDir, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
loadConfig() {
|
|
55
|
+
try {
|
|
56
|
+
if (existsSync(this.configPath)) {
|
|
57
|
+
const fileContent = readFileSync(this.configPath, 'utf-8');
|
|
58
|
+
const config = yaml.load(fileContent);
|
|
59
|
+
const migratedConfig = this.migrateOldConfig(config || { lang: 'en_US' });
|
|
60
|
+
// 如果配置被迁移,保存新配置
|
|
61
|
+
if (this.needsMigration(config)) {
|
|
62
|
+
this.backupConfig();
|
|
63
|
+
this.atomicWrite(this.configPath, yaml.dump(migratedConfig));
|
|
64
|
+
}
|
|
65
|
+
return migratedConfig;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.warn('Failed to load config, using defaults:', error);
|
|
70
|
+
logger.logError('ConfigManager.loadConfig', error);
|
|
71
|
+
}
|
|
72
|
+
return { lang: 'en_US' };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 检查配置是否需要迁移
|
|
76
|
+
*/
|
|
77
|
+
needsMigration(config) {
|
|
78
|
+
return config && 'plan' in config;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 迁移旧配置格式
|
|
82
|
+
*/
|
|
83
|
+
migrateOldConfig(config) {
|
|
84
|
+
if (config.plan) {
|
|
85
|
+
// 迁移旧配置,删除 plan 字段,添加 models 默认值
|
|
86
|
+
const { plan, ...rest } = config;
|
|
87
|
+
return {
|
|
88
|
+
...rest,
|
|
89
|
+
lang: config.lang || 'en_US',
|
|
90
|
+
api_key: config.api_key,
|
|
91
|
+
models: DEFAULT_MODELS
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return config;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 原子写入文件
|
|
98
|
+
*/
|
|
99
|
+
atomicWrite(path, content) {
|
|
100
|
+
const tempPath = `${path}.tmp`;
|
|
101
|
+
try {
|
|
102
|
+
writeFileSync(tempPath, content, 'utf-8');
|
|
103
|
+
renameSync(tempPath, path);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// 清理临时文件
|
|
107
|
+
if (existsSync(tempPath)) {
|
|
108
|
+
try {
|
|
109
|
+
unlinkSync(tempPath);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// 忽略清理错误
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 备份当前配置
|
|
120
|
+
*/
|
|
121
|
+
backupConfig() {
|
|
122
|
+
if (!existsSync(this.configPath)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const backupDir = join(this.configDir, 'backups');
|
|
126
|
+
if (!existsSync(backupDir)) {
|
|
127
|
+
mkdirSync(backupDir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
130
|
+
const backupPath = join(backupDir, `config-${timestamp}.yaml`);
|
|
131
|
+
try {
|
|
132
|
+
const content = readFileSync(this.configPath, 'utf-8');
|
|
133
|
+
writeFileSync(backupPath, content, 'utf-8');
|
|
134
|
+
// 保留最近 10 个备份
|
|
135
|
+
this.rotateBackups(backupDir, 10);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
logger.logError('ConfigManager.backupConfig', error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 轮转备份文件,保留最近的 N 个
|
|
143
|
+
*/
|
|
144
|
+
rotateBackups(backupDir, maxBackups) {
|
|
145
|
+
try {
|
|
146
|
+
const files = readdirSync(backupDir)
|
|
147
|
+
.filter(f => f.startsWith('config-') && f.endsWith('.yaml'))
|
|
148
|
+
.map(f => ({
|
|
149
|
+
name: f,
|
|
150
|
+
path: join(backupDir, f),
|
|
151
|
+
mtime: statSync(join(backupDir, f)).mtime
|
|
152
|
+
}))
|
|
153
|
+
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
154
|
+
// 删除超出数量的旧备份
|
|
155
|
+
files.slice(maxBackups).forEach(file => {
|
|
156
|
+
try {
|
|
157
|
+
unlinkSync(file.path);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
logger.logError('ConfigManager.rotateBackups', error);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
logger.logError('ConfigManager.rotateBackups', error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
saveConfig(config) {
|
|
169
|
+
try {
|
|
170
|
+
this.ensureConfigDir();
|
|
171
|
+
this.backupConfig(); // 保存前先备份
|
|
172
|
+
const configToSave = config || this.config;
|
|
173
|
+
const yamlContent = yaml.dump(configToSave);
|
|
174
|
+
this.atomicWrite(this.configPath, yamlContent);
|
|
175
|
+
this.config = configToSave;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error('Failed to save config:', error);
|
|
179
|
+
logger.logError('ConfigManager.saveConfig', error);
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
getConfig() {
|
|
184
|
+
return { ...this.config };
|
|
185
|
+
}
|
|
186
|
+
updateConfig(updates) {
|
|
187
|
+
this.config = { ...this.config, ...updates };
|
|
188
|
+
this.saveConfig();
|
|
189
|
+
}
|
|
190
|
+
isFirstRun() {
|
|
191
|
+
return !existsSync(this.configPath);
|
|
192
|
+
}
|
|
193
|
+
getLang() {
|
|
194
|
+
return this.config.lang || 'en_US';
|
|
195
|
+
}
|
|
196
|
+
setLang(lang) {
|
|
197
|
+
this.updateConfig({ lang });
|
|
198
|
+
}
|
|
199
|
+
getApiKey() {
|
|
200
|
+
return this.config.api_key;
|
|
201
|
+
}
|
|
202
|
+
setApiKey(apiKey) {
|
|
203
|
+
this.updateConfig({ api_key: apiKey });
|
|
204
|
+
}
|
|
205
|
+
revokeApiKey() {
|
|
206
|
+
this.updateConfig({ api_key: undefined });
|
|
207
|
+
}
|
|
208
|
+
getModels() {
|
|
209
|
+
return this.config.models || DEFAULT_MODELS;
|
|
210
|
+
}
|
|
211
|
+
setModels(models) {
|
|
212
|
+
this.updateConfig({ models });
|
|
213
|
+
}
|
|
214
|
+
updateModels(partial) {
|
|
215
|
+
const currentModels = this.getModels();
|
|
216
|
+
const updatedModels = {
|
|
217
|
+
haiku: partial.haiku ?? currentModels.haiku,
|
|
218
|
+
sonnet: partial.sonnet ?? currentModels.sonnet,
|
|
219
|
+
opus: partial.opus ?? currentModels.opus,
|
|
220
|
+
reasoning: partial.reasoning ?? currentModels.reasoning
|
|
221
|
+
};
|
|
222
|
+
this.updateConfig({ models: updatedModels });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
export const configManager = ConfigManager.getInstance();
|
|
226
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare class I18n {
|
|
2
|
+
private static instance;
|
|
3
|
+
private currentLocale;
|
|
4
|
+
private translations;
|
|
5
|
+
private fallbackLocale;
|
|
6
|
+
private localesDir;
|
|
7
|
+
private constructor();
|
|
8
|
+
static getInstance(): I18n;
|
|
9
|
+
private loadTranslations;
|
|
10
|
+
setLocale(locale: string): void;
|
|
11
|
+
getLocale(): string;
|
|
12
|
+
getAvailableLocales(): string[];
|
|
13
|
+
translate(key: string, params?: Record<string, string>): string;
|
|
14
|
+
t(key: string, params?: Record<string, string>): string;
|
|
15
|
+
private saveLocale;
|
|
16
|
+
private loadSavedLocale;
|
|
17
|
+
loadFromConfig(locale: string): void;
|
|
18
|
+
}
|
|
19
|
+
export declare const i18n: I18n;
|
|
20
|
+
export { i18n as I18n };
|
package/dist/lib/i18n.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
class I18n {
|
|
5
|
+
static instance;
|
|
6
|
+
currentLocale = 'en_US';
|
|
7
|
+
translations = new Map();
|
|
8
|
+
fallbackLocale = 'en_US';
|
|
9
|
+
localesDir;
|
|
10
|
+
constructor() {
|
|
11
|
+
// Determine the locales directory path
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
// Both in development (src/lib/i18n.ts) and production (dist/lib/i18n.js),
|
|
15
|
+
// locales is at the same relative path: lib -> parent -> locales
|
|
16
|
+
this.localesDir = join(__dirname, '..', 'locales');
|
|
17
|
+
this.loadTranslations();
|
|
18
|
+
this.loadSavedLocale();
|
|
19
|
+
}
|
|
20
|
+
static getInstance() {
|
|
21
|
+
if (!I18n.instance) {
|
|
22
|
+
I18n.instance = new I18n();
|
|
23
|
+
}
|
|
24
|
+
return I18n.instance;
|
|
25
|
+
}
|
|
26
|
+
loadTranslations() {
|
|
27
|
+
try {
|
|
28
|
+
// Check if locales directory exists
|
|
29
|
+
if (!existsSync(this.localesDir)) {
|
|
30
|
+
console.warn(`Locales directory not found at ${this.localesDir}`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Get all JSON files in the locales directory
|
|
34
|
+
const files = readdirSync(this.localesDir);
|
|
35
|
+
const localeFiles = files.filter(file => file.endsWith('.json'));
|
|
36
|
+
if (localeFiles.length === 0) {
|
|
37
|
+
console.warn('No locale files found in locales directory');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Load each locale file
|
|
41
|
+
for (const file of localeFiles) {
|
|
42
|
+
const locale = file.replace('.json', '');
|
|
43
|
+
const filePath = join(this.localesDir, file);
|
|
44
|
+
try {
|
|
45
|
+
const fileContent = readFileSync(filePath, 'utf-8');
|
|
46
|
+
const translations = JSON.parse(fileContent);
|
|
47
|
+
this.translations.set(locale, translations);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.warn(`Failed to load locale file ${file}:`, error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Try to detect locale from environment
|
|
54
|
+
const envLocale = process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES;
|
|
55
|
+
if (envLocale) {
|
|
56
|
+
const localeCode = envLocale.split('.')[0].replace('_', '-');
|
|
57
|
+
// First try exact match
|
|
58
|
+
if (this.translations.has(localeCode)) {
|
|
59
|
+
this.currentLocale = localeCode;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Try language-only match (e.g., 'en' from 'en-US')
|
|
63
|
+
const langOnly = localeCode.split('-')[0];
|
|
64
|
+
const matchingLocale = Array.from(this.translations.keys()).find(key => key.startsWith(langOnly + '_'));
|
|
65
|
+
if (matchingLocale) {
|
|
66
|
+
this.currentLocale = matchingLocale;
|
|
67
|
+
}
|
|
68
|
+
else if (langOnly === 'zh') {
|
|
69
|
+
// Fallback to zh_CN for Chinese
|
|
70
|
+
this.currentLocale = 'zh_CN';
|
|
71
|
+
}
|
|
72
|
+
else if (langOnly === 'en') {
|
|
73
|
+
// Fallback to en_US for English
|
|
74
|
+
this.currentLocale = 'en_US';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.warn('Failed to load translations:', error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
setLocale(locale) {
|
|
84
|
+
if (this.translations.has(locale)) {
|
|
85
|
+
this.currentLocale = locale;
|
|
86
|
+
this.saveLocale();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.warn(`Locale '${locale}' not supported, falling back to '${this.currentLocale}'`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
getLocale() {
|
|
93
|
+
return this.currentLocale;
|
|
94
|
+
}
|
|
95
|
+
getAvailableLocales() {
|
|
96
|
+
return Array.from(this.translations.keys());
|
|
97
|
+
}
|
|
98
|
+
translate(key, params) {
|
|
99
|
+
const keys = key.split('.');
|
|
100
|
+
let translation = this.translations.get(this.currentLocale);
|
|
101
|
+
for (const k of keys) {
|
|
102
|
+
if (translation && typeof translation === 'object' && k in translation) {
|
|
103
|
+
translation = translation[k];
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Fallback to fallback locale
|
|
107
|
+
translation = this.translations.get(this.fallbackLocale);
|
|
108
|
+
for (const fallbackKey of keys) {
|
|
109
|
+
if (translation && typeof translation === 'object' && fallbackKey in translation) {
|
|
110
|
+
translation = translation[fallbackKey];
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return key; // Return key if translation not found
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (typeof translation !== 'string') {
|
|
120
|
+
return key;
|
|
121
|
+
}
|
|
122
|
+
// Replace parameters in the translation string
|
|
123
|
+
if (params) {
|
|
124
|
+
return translation.replace(/\{\{(\w+)\}\}/g, (match, param) => {
|
|
125
|
+
return params[param] || match;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return translation;
|
|
129
|
+
}
|
|
130
|
+
t(key, params) {
|
|
131
|
+
return this.translate(key, params);
|
|
132
|
+
}
|
|
133
|
+
saveLocale() {
|
|
134
|
+
// Language is now saved via ConfigManager
|
|
135
|
+
// This method is kept for compatibility
|
|
136
|
+
}
|
|
137
|
+
loadSavedLocale() {
|
|
138
|
+
// Language is now loaded via ConfigManager
|
|
139
|
+
// This method is kept for compatibility
|
|
140
|
+
}
|
|
141
|
+
loadFromConfig(locale) {
|
|
142
|
+
if (this.translations.has(locale)) {
|
|
143
|
+
this.currentLocale = locale;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export const i18n = I18n.getInstance();
|
|
148
|
+
export { i18n as I18n };
|
|
149
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/lib/i18n.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { DEFAULT_MODELS } from './config.js';
|
|
2
|
+
export interface OpenCodeConfig {
|
|
3
|
+
$schema?: string;
|
|
4
|
+
provider?: Record<string, {
|
|
5
|
+
options?: {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
};
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}>;
|
|
11
|
+
model?: string;
|
|
12
|
+
small_model?: string;
|
|
13
|
+
mcp?: Record<string, OpenCodeMCPServerConfig>;
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
export interface OpenCodeMCPServerConfig {
|
|
17
|
+
type: 'local' | 'remote';
|
|
18
|
+
command?: string[];
|
|
19
|
+
environment?: Record<string, string>;
|
|
20
|
+
url?: string;
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export declare class OpenCodeManager {
|
|
24
|
+
private static instance;
|
|
25
|
+
private configPath;
|
|
26
|
+
private constructor();
|
|
27
|
+
static getInstance(): OpenCodeManager;
|
|
28
|
+
/**
|
|
29
|
+
* 确保配置目录存在
|
|
30
|
+
*/
|
|
31
|
+
private ensureConfigDir;
|
|
32
|
+
/**
|
|
33
|
+
* 读取配置
|
|
34
|
+
*/
|
|
35
|
+
getConfig(): OpenCodeConfig;
|
|
36
|
+
/**
|
|
37
|
+
* 保存配置
|
|
38
|
+
*/
|
|
39
|
+
saveConfig(config: OpenCodeConfig): void;
|
|
40
|
+
/**
|
|
41
|
+
* 加载私有 NewAPI 配置到 OpenCode
|
|
42
|
+
*/
|
|
43
|
+
loadPrivateConfig(apiKey: string, models: typeof DEFAULT_MODELS): void;
|
|
44
|
+
/**
|
|
45
|
+
* 卸载私有配置
|
|
46
|
+
*/
|
|
47
|
+
unloadPrivateConfig(): void;
|
|
48
|
+
/**
|
|
49
|
+
* 检测当前 OpenCode 配置的 API Key
|
|
50
|
+
*/
|
|
51
|
+
detectCurrentConfig(): {
|
|
52
|
+
apiKey: string | null;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export declare const openCodeManager: OpenCodeManager;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { DEFAULT_BASE_URL, DEFAULT_MODELS } from './config.js';
|
|
6
|
+
export class OpenCodeManager {
|
|
7
|
+
static instance;
|
|
8
|
+
configPath;
|
|
9
|
+
constructor() {
|
|
10
|
+
// OpenCode 配置文件路径
|
|
11
|
+
// ~/.config/opencode/opencode.json
|
|
12
|
+
this.configPath = join(homedir(), '.config', 'opencode', 'opencode.json');
|
|
13
|
+
}
|
|
14
|
+
static getInstance() {
|
|
15
|
+
if (!OpenCodeManager.instance) {
|
|
16
|
+
OpenCodeManager.instance = new OpenCodeManager();
|
|
17
|
+
}
|
|
18
|
+
return OpenCodeManager.instance;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 确保配置目录存在
|
|
22
|
+
*/
|
|
23
|
+
ensureConfigDir() {
|
|
24
|
+
const dir = dirname(this.configPath);
|
|
25
|
+
if (!existsSync(dir)) {
|
|
26
|
+
mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 读取配置
|
|
31
|
+
*/
|
|
32
|
+
getConfig() {
|
|
33
|
+
try {
|
|
34
|
+
if (existsSync(this.configPath)) {
|
|
35
|
+
const content = readFileSync(this.configPath, 'utf-8');
|
|
36
|
+
return JSON.parse(content);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn('Failed to read OpenCode config:', error);
|
|
41
|
+
logger.logError('OpenCodeManager.getConfig', error);
|
|
42
|
+
}
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 保存配置
|
|
47
|
+
*/
|
|
48
|
+
saveConfig(config) {
|
|
49
|
+
try {
|
|
50
|
+
this.ensureConfigDir();
|
|
51
|
+
writeFileSync(this.configPath, JSON.stringify(config, null, 4), 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to save OpenCode config: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 加载私有 NewAPI 配置到 OpenCode
|
|
59
|
+
*/
|
|
60
|
+
loadPrivateConfig(apiKey, models) {
|
|
61
|
+
const currentConfig = this.getConfig();
|
|
62
|
+
// 移除旧的 provider 配置(如果存在)
|
|
63
|
+
const { provider: oldProvider, ...restConfig } = currentConfig;
|
|
64
|
+
const newProvider = {};
|
|
65
|
+
// 保留其他 provider(如果有的话),但移除旧的配置
|
|
66
|
+
if (oldProvider) {
|
|
67
|
+
for (const [key, value] of Object.entries(oldProvider)) {
|
|
68
|
+
if (key !== 'private-newapi') {
|
|
69
|
+
newProvider[key] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 添加新的 provider 配置
|
|
74
|
+
newProvider['private-newapi'] = {
|
|
75
|
+
options: {
|
|
76
|
+
apiKey: apiKey,
|
|
77
|
+
baseURL: DEFAULT_BASE_URL
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const newConfig = {
|
|
81
|
+
$schema: 'https://opencode.ai/config.json',
|
|
82
|
+
...restConfig,
|
|
83
|
+
provider: newProvider,
|
|
84
|
+
model: `private-newapi/${models.opus || DEFAULT_MODELS.opus}`,
|
|
85
|
+
small_model: `private-newapi/${models.haiku || DEFAULT_MODELS.haiku}`
|
|
86
|
+
};
|
|
87
|
+
this.saveConfig(newConfig);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 卸载私有配置
|
|
91
|
+
*/
|
|
92
|
+
unloadPrivateConfig() {
|
|
93
|
+
const currentConfig = this.getConfig();
|
|
94
|
+
// 移除 provider 中的 private-newapi 配置
|
|
95
|
+
if (currentConfig.provider) {
|
|
96
|
+
delete currentConfig.provider['private-newapi'];
|
|
97
|
+
// 如果 provider 为空,删除 provider 字段
|
|
98
|
+
if (Object.keys(currentConfig.provider).length === 0) {
|
|
99
|
+
delete currentConfig.provider;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// 移除 model 和 small_model(如果是 private-newapi 的)
|
|
103
|
+
if (currentConfig.model?.includes('private-newapi')) {
|
|
104
|
+
delete currentConfig.model;
|
|
105
|
+
}
|
|
106
|
+
if (currentConfig.small_model?.includes('private-newapi')) {
|
|
107
|
+
delete currentConfig.small_model;
|
|
108
|
+
}
|
|
109
|
+
this.saveConfig(currentConfig);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 检测当前 OpenCode 配置的 API Key
|
|
113
|
+
*/
|
|
114
|
+
detectCurrentConfig() {
|
|
115
|
+
try {
|
|
116
|
+
const config = this.getConfig();
|
|
117
|
+
// 检查 provider 配置
|
|
118
|
+
if (!config.provider) {
|
|
119
|
+
return { apiKey: null };
|
|
120
|
+
}
|
|
121
|
+
// 检查是否有 private-newapi
|
|
122
|
+
let apiKey = null;
|
|
123
|
+
if (config.provider['private-newapi']) {
|
|
124
|
+
apiKey = config.provider['private-newapi'].options?.apiKey || null;
|
|
125
|
+
}
|
|
126
|
+
return { apiKey };
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return { apiKey: null };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export const openCodeManager = OpenCodeManager.getInstance();
|
|
134
|
+
//# sourceMappingURL=opencode-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-manager.js","sourceRoot":"","sources":["../../src/lib/opencode-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DEFAULT_MODELS } from './config.js';
|
|
2
|
+
export interface ToolInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
command: string;
|
|
5
|
+
installCommand: string;
|
|
6
|
+
configPath: string;
|
|
7
|
+
displayName: string;
|
|
8
|
+
hidden?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const SUPPORTED_TOOLS: Record<string, ToolInfo>;
|
|
11
|
+
export declare class ToolManager {
|
|
12
|
+
private static instance;
|
|
13
|
+
private constructor();
|
|
14
|
+
static getInstance(): ToolManager;
|
|
15
|
+
isToolInstalled(toolName: string): boolean;
|
|
16
|
+
installTool(toolName: string): Promise<void>;
|
|
17
|
+
getToolConfig(toolName: string): any;
|
|
18
|
+
updateToolConfig(toolName: string, config: any): void;
|
|
19
|
+
loadPrivateConfig(toolName: string, apiKey: string, models: typeof DEFAULT_MODELS): void;
|
|
20
|
+
getInstalledTools(): string[];
|
|
21
|
+
unloadPrivateConfig(toolName: string): void;
|
|
22
|
+
getSupportedTools(): ToolInfo[];
|
|
23
|
+
isGitInstalled(): boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare const toolManager: ToolManager;
|