aicodeswitch 5.2.13 → 6.0.1
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/bin/restore.js +67 -4
- package/bin/utils/managed-fields.js +12 -0
- package/dist/server/agent-map/activity-extractor.js +8 -0
- package/dist/server/agent-map/agent-map-service.js +364 -65
- package/dist/server/coding-plan.js +3 -0
- package/dist/server/config-managed-fields.js +20 -1
- package/dist/server/config-metadata.js +78 -1
- package/dist/server/conversions/index.js +10 -2
- package/dist/server/conversions/thinking/providers.js +12 -7
- package/dist/server/fs-database.js +10 -1
- package/dist/server/main.js +412 -37
- package/dist/server/original-config-reader.js +71 -1
- package/dist/server/performance-tracker.js +78 -8
- package/dist/server/proxy-server.js +159 -34
- package/dist/server/session-migration.js +1 -0
- package/dist/server/transformers/chunk-collector.js +112 -25
- package/dist/ui/assets/index-BeM4AIzn.js +1187 -0
- package/dist/ui/assets/index-DqRzbMIU.css +1 -0
- package/dist/ui/assets/three-CFpmPosW.js +3802 -0
- package/dist/ui/index.html +3 -2
- package/package.json +3 -1
- package/scripts/dev.js +76 -30
- package/dist/server/tools-service.js +0 -203
- package/dist/server/websocket-service.js +0 -148
- package/dist/ui/assets/index-4liE4bV8.css +0 -1
- package/dist/ui/assets/index-CJMAVkIN.js +0 -813
package/bin/restore.js
CHANGED
|
@@ -5,7 +5,7 @@ const chalk = require('chalk');
|
|
|
5
5
|
const boxen = require('boxen');
|
|
6
6
|
const ora = require('ora');
|
|
7
7
|
const { parseToml, stringifyToml, mergeJsonSettings, mergeTomlSettings, atomicWriteFile } = require('./utils/config-helpers');
|
|
8
|
-
const { CLAUDE_SETTINGS_MANAGED_FIELDS, CLAUDE_JSON_MANAGED_FIELDS, CODEX_CONFIG_MANAGED_FIELDS, CODEX_AUTH_MANAGED_FIELDS } = require('./utils/managed-fields');
|
|
8
|
+
const { CLAUDE_SETTINGS_MANAGED_FIELDS, CLAUDE_JSON_MANAGED_FIELDS, CODEX_CONFIG_MANAGED_FIELDS, CODEX_AUTH_MANAGED_FIELDS, OPENCODE_CONFIG_MANAGED_FIELDS } = require('./utils/managed-fields');
|
|
9
9
|
const { isServerRunning, getServerInfo } = require('./utils/get-server');
|
|
10
10
|
const { findPidByPort } = require('./utils/port-utils');
|
|
11
11
|
|
|
@@ -240,10 +240,57 @@ const restoreCodexConfig = () => {
|
|
|
240
240
|
return results;
|
|
241
241
|
};
|
|
242
242
|
|
|
243
|
+
// 恢复 OpenCode 配置(使用智能合并)
|
|
244
|
+
const restoreOpencodeConfig = () => {
|
|
245
|
+
const results = {
|
|
246
|
+
restored: [],
|
|
247
|
+
notFound: [],
|
|
248
|
+
errors: []
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const homeDir = os.homedir();
|
|
253
|
+
const opencodeConfigPath = path.join(homeDir, '.config', 'opencode', 'opencode.json');
|
|
254
|
+
const opencodeConfigBakPath = `${opencodeConfigPath}.aicodeswitch_backup`;
|
|
255
|
+
|
|
256
|
+
if (fs.existsSync(opencodeConfigBakPath)) {
|
|
257
|
+
try {
|
|
258
|
+
const backupConfig = JSON.parse(fs.readFileSync(opencodeConfigBakPath, 'utf-8'));
|
|
259
|
+
let currentConfig = {};
|
|
260
|
+
if (fs.existsSync(opencodeConfigPath)) {
|
|
261
|
+
try {
|
|
262
|
+
currentConfig = JSON.parse(fs.readFileSync(opencodeConfigPath, 'utf-8'));
|
|
263
|
+
} catch (e) {
|
|
264
|
+
// 忽略解析错误
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const mergedConfig = mergeJsonSettings(
|
|
269
|
+
backupConfig,
|
|
270
|
+
currentConfig,
|
|
271
|
+
OPENCODE_CONFIG_MANAGED_FIELDS
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
atomicWriteFile(opencodeConfigPath, JSON.stringify(mergedConfig, null, 2));
|
|
275
|
+
fs.unlinkSync(opencodeConfigBakPath);
|
|
276
|
+
results.restored.push('opencode.json');
|
|
277
|
+
} catch (error) {
|
|
278
|
+
results.errors.push({ file: 'opencode.json', error: error.message });
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
results.notFound.push('opencode.json.aicodeswitch_backup');
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
results.errors.push({ file: 'opencode.json', error: err.message });
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return results;
|
|
288
|
+
};
|
|
289
|
+
|
|
243
290
|
// 显示恢复结果
|
|
244
291
|
const showRestoreResult = (target, results) => {
|
|
245
|
-
const targetName = target === 'claude-code' ? 'Claude Code' : 'Codex';
|
|
246
|
-
const targetColor = target === 'claude-code' ? chalk.cyan : chalk.magenta;
|
|
292
|
+
const targetName = target === 'claude-code' ? 'Claude Code' : target === 'opencode' ? 'OpenCode' : 'Codex';
|
|
293
|
+
const targetColor = target === 'claude-code' ? chalk.cyan : target === 'opencode' ? chalk.blue : chalk.magenta;
|
|
247
294
|
|
|
248
295
|
let message = targetColor.bold(`${targetName} Configuration Restore\n\n`);
|
|
249
296
|
|
|
@@ -276,6 +323,8 @@ const showRestoreResult = (target, results) => {
|
|
|
276
323
|
message += chalk.yellow.bold('⚠️ Important:\n\n');
|
|
277
324
|
if (target === 'claude-code') {
|
|
278
325
|
message += chalk.white('Please restart ') + chalk.cyan.bold('Claude Code') + chalk.white(' to apply the restored configuration.\n');
|
|
326
|
+
} else if (target === 'opencode') {
|
|
327
|
+
message += chalk.white('Please restart ') + chalk.blue.bold('OpenCode') + chalk.white(' to apply the restored configuration.\n');
|
|
279
328
|
} else {
|
|
280
329
|
message += chalk.white('Please restart ') + chalk.magenta.bold('Codex') + chalk.white(' to apply the restored configuration.\n');
|
|
281
330
|
}
|
|
@@ -307,7 +356,7 @@ const restore = async () => {
|
|
|
307
356
|
|
|
308
357
|
console.log('\n');
|
|
309
358
|
|
|
310
|
-
const validTargets = ['claude-code', 'codex', undefined];
|
|
359
|
+
const validTargets = ['claude-code', 'codex', 'opencode', undefined];
|
|
311
360
|
|
|
312
361
|
if (target && !validTargets.includes(target)) {
|
|
313
362
|
console.log(boxen(
|
|
@@ -316,6 +365,7 @@ const restore = async () => {
|
|
|
316
365
|
chalk.white('Targets:\n') +
|
|
317
366
|
chalk.white(' claude-code Restore Claude Code configuration\n') +
|
|
318
367
|
chalk.white(' codex Restore Codex configuration\n') +
|
|
368
|
+
chalk.white(' opencode Restore OpenCode configuration\n') +
|
|
319
369
|
chalk.white(' (no arg) Restore all configurations\n'),
|
|
320
370
|
{
|
|
321
371
|
padding: 1,
|
|
@@ -379,6 +429,19 @@ const restore = async () => {
|
|
|
379
429
|
showRestoreResult('codex', codexResults);
|
|
380
430
|
}
|
|
381
431
|
|
|
432
|
+
if (target === 'opencode' || !target) {
|
|
433
|
+
if (!target) console.log('');
|
|
434
|
+
|
|
435
|
+
const spinner = ora({
|
|
436
|
+
text: chalk.blue('Restoring OpenCode configuration...'),
|
|
437
|
+
color: 'blue'
|
|
438
|
+
}).start();
|
|
439
|
+
|
|
440
|
+
const opencodeResults = restoreOpencodeConfig();
|
|
441
|
+
spinner.succeed(chalk.green('OpenCode restore complete'));
|
|
442
|
+
showRestoreResult('opencode', opencodeResults);
|
|
443
|
+
}
|
|
444
|
+
|
|
382
445
|
// 停用所有激活的路由
|
|
383
446
|
console.log('');
|
|
384
447
|
const routesSpinner = ora({
|
|
@@ -56,9 +56,21 @@ const CODEX_AUTH_MANAGED_FIELDS = [
|
|
|
56
56
|
'OPENAI_API_KEY',
|
|
57
57
|
];
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* OpenCode opencode.json 管理字段列表
|
|
61
|
+
* 托管整个 provider.aicodeswitch 段与 model/small_model/mcp
|
|
62
|
+
*/
|
|
63
|
+
const OPENCODE_CONFIG_MANAGED_FIELDS = [
|
|
64
|
+
'provider.aicodeswitch',
|
|
65
|
+
'model',
|
|
66
|
+
'small_model',
|
|
67
|
+
'mcp',
|
|
68
|
+
];
|
|
69
|
+
|
|
59
70
|
module.exports = {
|
|
60
71
|
CLAUDE_SETTINGS_MANAGED_FIELDS,
|
|
61
72
|
CLAUDE_JSON_MANAGED_FIELDS,
|
|
62
73
|
CODEX_CONFIG_MANAGED_FIELDS,
|
|
63
74
|
CODEX_AUTH_MANAGED_FIELDS,
|
|
75
|
+
OPENCODE_CONFIG_MANAGED_FIELDS,
|
|
64
76
|
};
|
|
@@ -314,6 +314,14 @@ function detectTurnEnd(agent, downstream, responseBody) {
|
|
|
314
314
|
return true;
|
|
315
315
|
return null;
|
|
316
316
|
}
|
|
317
|
+
if (agent === 'opencode') {
|
|
318
|
+
// OpenAI Chat Completions:tool_calls 仍在 → 继续;finish_reason=stop / [DONE] → 本轮结束
|
|
319
|
+
if (/"finish_reason"\s*:\s*"tool_calls"/.test(raw))
|
|
320
|
+
return false;
|
|
321
|
+
if (/"finish_reason"\s*:\s*"(stop|length|content_filter)"/.test(raw) || /\[DONE\]/.test(raw))
|
|
322
|
+
return true;
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
317
325
|
// Claude:看 stop_reason(流式 message_delta 或非流式 JSON 都带该字段)
|
|
318
326
|
const m = raw.match(/"stop_reason"\s*:\s*"([a-z_]+)"/);
|
|
319
327
|
const stopReason = m ? m[1] : null;
|