aicodeswitch 1.2.6 → 1.3.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/cli.js +5 -0
- package/bin/restore.js +220 -0
- package/bin/update.js +7 -7
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ const commands = {
|
|
|
34
34
|
stop: () => require(path.join(binDir, 'stop')),
|
|
35
35
|
restart: () => require(path.join(binDir, 'restart')),
|
|
36
36
|
update: () => require(path.join(binDir, 'update')),
|
|
37
|
+
restore: () => require(path.join(binDir, 'restore')),
|
|
37
38
|
version: () => require(path.join(binDir, 'version')),
|
|
38
39
|
};
|
|
39
40
|
|
|
@@ -46,6 +47,7 @@ Commands:
|
|
|
46
47
|
stop Stop the AI Code Switch server
|
|
47
48
|
restart Restart the AI Code Switch server
|
|
48
49
|
update Update to the latest version and restart
|
|
50
|
+
restore Restore original configuration files
|
|
49
51
|
version Show current version information
|
|
50
52
|
|
|
51
53
|
Example:
|
|
@@ -53,6 +55,9 @@ Example:
|
|
|
53
55
|
aicos stop
|
|
54
56
|
aicos restart
|
|
55
57
|
aicos update
|
|
58
|
+
aicos restore
|
|
59
|
+
aicos restore claude-code
|
|
60
|
+
aicos restore codex
|
|
56
61
|
aicos version
|
|
57
62
|
`);
|
|
58
63
|
process.exit(1);
|
package/bin/restore.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const boxen = require('boxen');
|
|
6
|
+
const ora = require('ora');
|
|
7
|
+
|
|
8
|
+
// 恢复 Claude Code 配置
|
|
9
|
+
const restoreClaudeConfig = () => {
|
|
10
|
+
const results = {
|
|
11
|
+
restored: [],
|
|
12
|
+
notFound: [],
|
|
13
|
+
errors: []
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const homeDir = os.homedir();
|
|
18
|
+
const claudeDir = path.join(homeDir, '.claude');
|
|
19
|
+
const claudeSettingsPath = path.join(claudeDir, 'settings.json');
|
|
20
|
+
const claudeSettingsBakPath = path.join(claudeDir, 'settings.json.bak');
|
|
21
|
+
|
|
22
|
+
// Restore settings.json
|
|
23
|
+
if (fs.existsSync(claudeSettingsBakPath)) {
|
|
24
|
+
if (fs.existsSync(claudeSettingsPath)) {
|
|
25
|
+
fs.unlinkSync(claudeSettingsPath);
|
|
26
|
+
}
|
|
27
|
+
fs.renameSync(claudeSettingsBakPath, claudeSettingsPath);
|
|
28
|
+
results.restored.push('settings.json');
|
|
29
|
+
} else {
|
|
30
|
+
results.notFound.push('settings.json.bak');
|
|
31
|
+
}
|
|
32
|
+
} catch (err) {
|
|
33
|
+
results.errors.push({ file: 'settings.json', error: err.message });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const homeDir = os.homedir();
|
|
38
|
+
const claudeJsonPath = path.join(homeDir, '.claude.json');
|
|
39
|
+
const claudeJsonBakPath = path.join(homeDir, '.claude.json.bak');
|
|
40
|
+
|
|
41
|
+
// Restore .claude.json
|
|
42
|
+
if (fs.existsSync(claudeJsonBakPath)) {
|
|
43
|
+
if (fs.existsSync(claudeJsonPath)) {
|
|
44
|
+
fs.unlinkSync(claudeJsonPath);
|
|
45
|
+
}
|
|
46
|
+
fs.renameSync(claudeJsonBakPath, claudeJsonPath);
|
|
47
|
+
results.restored.push('.claude.json');
|
|
48
|
+
} else {
|
|
49
|
+
results.notFound.push('.claude.json.bak');
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
results.errors.push({ file: '.claude.json', error: err.message });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return results;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// 恢复 Codex 配置
|
|
59
|
+
const restoreCodexConfig = () => {
|
|
60
|
+
const results = {
|
|
61
|
+
restored: [],
|
|
62
|
+
notFound: [],
|
|
63
|
+
errors: []
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const homeDir = os.homedir();
|
|
68
|
+
const codexDir = path.join(homeDir, '.codex');
|
|
69
|
+
const codexConfigPath = path.join(codexDir, 'config.toml');
|
|
70
|
+
const codexConfigBakPath = path.join(codexDir, 'config.toml.bak');
|
|
71
|
+
|
|
72
|
+
// Restore config.toml
|
|
73
|
+
if (fs.existsSync(codexConfigBakPath)) {
|
|
74
|
+
if (fs.existsSync(codexConfigPath)) {
|
|
75
|
+
fs.unlinkSync(codexConfigPath);
|
|
76
|
+
}
|
|
77
|
+
fs.renameSync(codexConfigBakPath, codexConfigPath);
|
|
78
|
+
results.restored.push('config.toml');
|
|
79
|
+
} else {
|
|
80
|
+
results.notFound.push('config.toml.bak');
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
results.errors.push({ file: 'config.toml', error: err.message });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const homeDir = os.homedir();
|
|
88
|
+
const codexAuthPath = path.join(homeDir, '.codex', 'auth.json');
|
|
89
|
+
const codexAuthBakPath = path.join(homeDir, '.codex', 'auth.json.bak');
|
|
90
|
+
|
|
91
|
+
// Restore auth.json
|
|
92
|
+
if (fs.existsSync(codexAuthBakPath)) {
|
|
93
|
+
if (fs.existsSync(codexAuthPath)) {
|
|
94
|
+
fs.unlinkSync(codexAuthPath);
|
|
95
|
+
}
|
|
96
|
+
fs.renameSync(codexAuthBakPath, codexAuthPath);
|
|
97
|
+
results.restored.push('auth.json');
|
|
98
|
+
} else {
|
|
99
|
+
results.notFound.push('auth.json.bak');
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
results.errors.push({ file: 'auth.json', error: err.message });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return results;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// 显示恢复结果
|
|
109
|
+
const showRestoreResult = (target, results) => {
|
|
110
|
+
const targetName = target === 'claude-code' ? 'Claude Code' : 'Codex';
|
|
111
|
+
const targetColor = target === 'claude-code' ? chalk.cyan : chalk.magenta;
|
|
112
|
+
|
|
113
|
+
let message = targetColor.bold(`${targetName} Configuration Restore\n\n`);
|
|
114
|
+
|
|
115
|
+
if (results.restored.length > 0) {
|
|
116
|
+
message += chalk.green('Restored files:\n');
|
|
117
|
+
results.restored.forEach(file => {
|
|
118
|
+
message += chalk.white(` ✓ ${file}\n`);
|
|
119
|
+
});
|
|
120
|
+
message += '\n';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (results.notFound.length > 0) {
|
|
124
|
+
message += chalk.gray('No backup found:\n');
|
|
125
|
+
results.notFound.forEach(file => {
|
|
126
|
+
message += chalk.gray(` - ${file}\n`);
|
|
127
|
+
});
|
|
128
|
+
message += '\n';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (results.errors.length > 0) {
|
|
132
|
+
message += chalk.red('Errors:\n');
|
|
133
|
+
results.errors.forEach(({ file, error }) => {
|
|
134
|
+
message += chalk.red(` ✗ ${file}: ${error}\n`);
|
|
135
|
+
});
|
|
136
|
+
message += '\n';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 添加重启提示
|
|
140
|
+
if (results.restored.length > 0) {
|
|
141
|
+
message += chalk.yellow.bold('⚠️ Important:\n\n');
|
|
142
|
+
if (target === 'claude-code') {
|
|
143
|
+
message += chalk.white('Please restart ') + chalk.cyan.bold('Claude Code') + chalk.white(' to apply the restored configuration.\n');
|
|
144
|
+
} else {
|
|
145
|
+
message += chalk.white('Please restart ') + chalk.magenta.bold('Codex') + chalk.white(' to apply the restored configuration.\n');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const borderColor = results.errors.length > 0 ? 'red' :
|
|
150
|
+
results.restored.length > 0 ? 'green' : 'gray';
|
|
151
|
+
|
|
152
|
+
console.log(boxen(message, {
|
|
153
|
+
padding: 1,
|
|
154
|
+
margin: 1,
|
|
155
|
+
borderStyle: 'round',
|
|
156
|
+
borderColor
|
|
157
|
+
}));
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// 主恢复逻辑
|
|
161
|
+
const restore = async () => {
|
|
162
|
+
const args = process.argv.slice(2);
|
|
163
|
+
const target = args[0]; // claude-code, codex, or undefined (all)
|
|
164
|
+
|
|
165
|
+
console.log('\n');
|
|
166
|
+
|
|
167
|
+
const validTargets = ['claude-code', 'codex', undefined];
|
|
168
|
+
|
|
169
|
+
if (target && !validTargets.includes(target)) {
|
|
170
|
+
console.log(boxen(
|
|
171
|
+
chalk.red.bold('✗ Invalid target\n\n') +
|
|
172
|
+
chalk.white('Usage: ') + chalk.cyan('aicos restore [target]\n\n') +
|
|
173
|
+
chalk.white('Targets:\n') +
|
|
174
|
+
chalk.white(' claude-code Restore Claude Code configuration\n') +
|
|
175
|
+
chalk.white(' codex Restore Codex configuration\n') +
|
|
176
|
+
chalk.white(' (no arg) Restore all configurations\n'),
|
|
177
|
+
{
|
|
178
|
+
padding: 1,
|
|
179
|
+
margin: 1,
|
|
180
|
+
borderStyle: 'round',
|
|
181
|
+
borderColor: 'red'
|
|
182
|
+
}
|
|
183
|
+
));
|
|
184
|
+
console.log('');
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 恢复配置
|
|
189
|
+
if (target === 'claude-code' || !target) {
|
|
190
|
+
const spinner = ora({
|
|
191
|
+
text: chalk.cyan('Restoring Claude Code configuration...'),
|
|
192
|
+
color: 'cyan'
|
|
193
|
+
}).start();
|
|
194
|
+
|
|
195
|
+
const claudeResults = restoreClaudeConfig();
|
|
196
|
+
spinner.succeed(chalk.green('Claude Code restore complete'));
|
|
197
|
+
showRestoreResult('claude-code', claudeResults);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (target === 'codex' || !target) {
|
|
201
|
+
if (!target) console.log(''); // Add spacing when restoring both
|
|
202
|
+
|
|
203
|
+
const spinner = ora({
|
|
204
|
+
text: chalk.magenta('Restoring Codex configuration...'),
|
|
205
|
+
color: 'magenta'
|
|
206
|
+
}).start();
|
|
207
|
+
|
|
208
|
+
const codexResults = restoreCodexConfig();
|
|
209
|
+
spinner.succeed(chalk.green('Codex restore complete'));
|
|
210
|
+
showRestoreResult('codex', codexResults);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log(chalk.cyan('💡 Tips:\n'));
|
|
215
|
+
console.log(chalk.white(' • Write config: ') + chalk.cyan('aicos write-config [target]'));
|
|
216
|
+
console.log(chalk.white(' • Start server: ') + chalk.cyan('aicos start'));
|
|
217
|
+
console.log('\n');
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
module.exports = restore();
|
package/bin/update.js
CHANGED
|
@@ -268,19 +268,19 @@ const update = async () => {
|
|
|
268
268
|
color: 'cyan'
|
|
269
269
|
}).start();
|
|
270
270
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
271
|
+
const npmArgs = ['npm', 'install', '-g', `${PACKAGE_NAME}@latest`];
|
|
272
|
+
if (needSudo) {
|
|
273
|
+
npmArgs.unshift('sudo');
|
|
274
|
+
}
|
|
276
275
|
|
|
277
|
-
|
|
276
|
+
try {
|
|
277
|
+
await execCommand(npmArgs);
|
|
278
278
|
updateSpinner.succeed(chalk.green('Update successful!'));
|
|
279
279
|
} catch (err) {
|
|
280
280
|
updateSpinner.fail(chalk.red('Update failed'));
|
|
281
281
|
console.log(chalk.yellow(`\nUpdate failed with error code ${err.code || 'unknown'}\n`));
|
|
282
282
|
console.log(chalk.white('You can try manually updating:\n'));
|
|
283
|
-
console.log(chalk.cyan(` ${
|
|
283
|
+
console.log(chalk.cyan(` ${npmArgs.join(' ')}\n`));
|
|
284
284
|
|
|
285
285
|
// 尝试重新启动服务器
|
|
286
286
|
console.log(chalk.yellow('Attempting to restart server...\n'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicodeswitch",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "A tool to help you manage AI programming tools to access large language models locally. It allows your Claude Code, Codex and other tools to no longer be limited to official models.",
|
|
5
5
|
"author": "tangshuang",
|
|
6
6
|
"license": "MIT",
|