codexgo 0.1.4
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/README.md +76 -0
- package/bin/cli.js +490 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# codexgo
|
|
2
|
+
|
|
3
|
+
用于一键写入 Codex CLI 配置的 npm CLI。
|
|
4
|
+
|
|
5
|
+
## 前置环境
|
|
6
|
+
|
|
7
|
+
运行 `npx codexgo` 之前,请先安装:
|
|
8
|
+
|
|
9
|
+
1. `Node.js 18` 或更高版本
|
|
10
|
+
2. `npm`
|
|
11
|
+
|
|
12
|
+
安装完成后先检查:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node -v
|
|
16
|
+
npm -v
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
如果这两个命令没有版本号,请先去 `https://nodejs.org/` 安装 `LTS` 版本,再重新打开终端。
|
|
20
|
+
|
|
21
|
+
直接运行会进入交互菜单,可选择:
|
|
22
|
+
|
|
23
|
+
- 安装 Codex 并配置
|
|
24
|
+
- 仅配置
|
|
25
|
+
- 更换 Key
|
|
26
|
+
- 卸载配置
|
|
27
|
+
- 查看当前配置
|
|
28
|
+
|
|
29
|
+
默认配置目标:
|
|
30
|
+
|
|
31
|
+
- Base URL: `http://103.236.78.68:18080`
|
|
32
|
+
- Model: `gpt-5.4`
|
|
33
|
+
|
|
34
|
+
## 使用方式
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx codexgo
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
启用 WebSocket:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx codexgo --api-key 你的APIKey --ws
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
直接指定动作:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx codexgo --install --api-key 你的APIKey
|
|
50
|
+
npx codexgo --install-with-codex --api-key 你的APIKey
|
|
51
|
+
npx codexgo --install --with-codex --api-key 你的APIKey
|
|
52
|
+
npx codexgo --replace-key --api-key 你的新Key
|
|
53
|
+
npx codexgo --uninstall
|
|
54
|
+
npx codexgo --status
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
自定义模型或地址:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx codexgo \
|
|
61
|
+
--api-key 你的APIKey \
|
|
62
|
+
--base-url http://103.236.78.68:18080 \
|
|
63
|
+
--model gpt-5.4
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
脚本会自动:
|
|
67
|
+
|
|
68
|
+
- 创建 `~/.codex`
|
|
69
|
+
- 备份已有的 `config.toml` 和 `auth.json`
|
|
70
|
+
- 写入新的 Codex 配置
|
|
71
|
+
|
|
72
|
+
## 发布
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm publish --access public
|
|
76
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const readline = require("readline");
|
|
7
|
+
const { spawnSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const DEFAULT_BASE_URL = "http://103.236.78.68:18080";
|
|
10
|
+
const DEFAULT_MODEL = "gpt-5.4";
|
|
11
|
+
const CODEX_NPM_PACKAGE = "@openai/codex";
|
|
12
|
+
|
|
13
|
+
function printHelp() {
|
|
14
|
+
console.log(`codexgo
|
|
15
|
+
|
|
16
|
+
用法:
|
|
17
|
+
npx codexgo
|
|
18
|
+
npx codexgo --install --api-key 你的APIKey
|
|
19
|
+
|
|
20
|
+
可选参数:
|
|
21
|
+
--install 直接执行安装
|
|
22
|
+
--install-with-codex 直接安装 Codex CLI 并写入配置
|
|
23
|
+
--replace-key 只更换 API Key
|
|
24
|
+
--uninstall 卸载 Codex 配置
|
|
25
|
+
--status 查看当前配置状态
|
|
26
|
+
--with-codex 安装时同时安装/更新 Codex CLI
|
|
27
|
+
--api-key <key> 你的 API Key
|
|
28
|
+
--base-url <url> 默认: ${DEFAULT_BASE_URL}
|
|
29
|
+
--model <model> 默认: ${DEFAULT_MODEL}
|
|
30
|
+
--ws 启用 WebSocket 配置
|
|
31
|
+
--codex-dir <path> 自定义 Codex 配置目录,默认: ~/.codex
|
|
32
|
+
--yes 跳过确认
|
|
33
|
+
-h, --help 显示帮助
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseArgs(argv) {
|
|
38
|
+
const options = {
|
|
39
|
+
action: "",
|
|
40
|
+
apiKey: "",
|
|
41
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
42
|
+
model: DEFAULT_MODEL,
|
|
43
|
+
codexDir: path.join(os.homedir(), ".codex"),
|
|
44
|
+
ws: false,
|
|
45
|
+
wsSpecified: false,
|
|
46
|
+
withCodex: false,
|
|
47
|
+
withCodexSpecified: false,
|
|
48
|
+
yes: false
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
52
|
+
const arg = argv[i];
|
|
53
|
+
switch (arg) {
|
|
54
|
+
case "--install":
|
|
55
|
+
options.action = "install";
|
|
56
|
+
break;
|
|
57
|
+
case "--install-with-codex":
|
|
58
|
+
options.action = "install-with-codex";
|
|
59
|
+
options.withCodex = true;
|
|
60
|
+
options.withCodexSpecified = true;
|
|
61
|
+
break;
|
|
62
|
+
case "--replace-key":
|
|
63
|
+
options.action = "replace-key";
|
|
64
|
+
break;
|
|
65
|
+
case "--uninstall":
|
|
66
|
+
options.action = "uninstall";
|
|
67
|
+
break;
|
|
68
|
+
case "--status":
|
|
69
|
+
options.action = "status";
|
|
70
|
+
break;
|
|
71
|
+
case "--with-codex":
|
|
72
|
+
options.withCodex = true;
|
|
73
|
+
options.withCodexSpecified = true;
|
|
74
|
+
break;
|
|
75
|
+
case "--api-key":
|
|
76
|
+
options.apiKey = argv[++i] || "";
|
|
77
|
+
break;
|
|
78
|
+
case "--base-url":
|
|
79
|
+
options.baseUrl = argv[++i] || options.baseUrl;
|
|
80
|
+
break;
|
|
81
|
+
case "--model":
|
|
82
|
+
options.model = argv[++i] || options.model;
|
|
83
|
+
break;
|
|
84
|
+
case "--codex-dir":
|
|
85
|
+
options.codexDir = argv[++i] || options.codexDir;
|
|
86
|
+
break;
|
|
87
|
+
case "--ws":
|
|
88
|
+
options.ws = true;
|
|
89
|
+
options.wsSpecified = true;
|
|
90
|
+
break;
|
|
91
|
+
case "--yes":
|
|
92
|
+
options.yes = true;
|
|
93
|
+
break;
|
|
94
|
+
case "-h":
|
|
95
|
+
case "--help":
|
|
96
|
+
options.help = true;
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
throw new Error(`未知参数: ${arg}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return options;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function prompt(question) {
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
const rl = readline.createInterface({
|
|
109
|
+
input: process.stdin,
|
|
110
|
+
output: process.stdout
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
rl.question(question, (answer) => {
|
|
114
|
+
rl.close();
|
|
115
|
+
resolve(answer.trim());
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function promptYesNo(question, defaultValue = false) {
|
|
121
|
+
const suffix = defaultValue ? " [Y/n]: " : " [y/N]: ";
|
|
122
|
+
const answer = (await prompt(`${question}${suffix}`)).toLowerCase();
|
|
123
|
+
|
|
124
|
+
if (!answer) {
|
|
125
|
+
return defaultValue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return answer === "y" || answer === "yes";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function chooseAction() {
|
|
132
|
+
console.log("");
|
|
133
|
+
console.log("请选择功能:");
|
|
134
|
+
console.log("1. 安装 Codex 并配置");
|
|
135
|
+
console.log("2. 仅配置");
|
|
136
|
+
console.log("3. 更换 Key");
|
|
137
|
+
console.log("4. 卸载配置");
|
|
138
|
+
console.log("5. 查看当前配置");
|
|
139
|
+
console.log("6. 退出");
|
|
140
|
+
|
|
141
|
+
while (true) {
|
|
142
|
+
const answer = await prompt("请输入序号: ");
|
|
143
|
+
switch (answer) {
|
|
144
|
+
case "1":
|
|
145
|
+
return "install-with-codex";
|
|
146
|
+
case "2":
|
|
147
|
+
return "install";
|
|
148
|
+
case "3":
|
|
149
|
+
return "replace-key";
|
|
150
|
+
case "4":
|
|
151
|
+
return "uninstall";
|
|
152
|
+
case "5":
|
|
153
|
+
return "status";
|
|
154
|
+
case "6":
|
|
155
|
+
return "exit";
|
|
156
|
+
default:
|
|
157
|
+
console.log("无效选项,请重新输入。");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function escapeToml(value) {
|
|
163
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function buildConfigToml({ baseUrl, model, ws }) {
|
|
167
|
+
const lines = [
|
|
168
|
+
'model_provider = "OpenAI"',
|
|
169
|
+
`model = "${escapeToml(model)}"`,
|
|
170
|
+
`review_model = "${escapeToml(model)}"`,
|
|
171
|
+
'model_reasoning_effort = "xhigh"',
|
|
172
|
+
"disable_response_storage = true",
|
|
173
|
+
'network_access = "enabled"',
|
|
174
|
+
"windows_wsl_setup_acknowledged = true",
|
|
175
|
+
"model_context_window = 1000000",
|
|
176
|
+
"model_auto_compact_token_limit = 900000",
|
|
177
|
+
"",
|
|
178
|
+
"[model_providers.OpenAI]",
|
|
179
|
+
'name = "OpenAI"',
|
|
180
|
+
`base_url = "${escapeToml(baseUrl)}"`,
|
|
181
|
+
'wire_api = "responses"'
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
if (ws) {
|
|
185
|
+
lines.push("supports_websockets = true");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
lines.push("requires_openai_auth = true");
|
|
189
|
+
|
|
190
|
+
if (ws) {
|
|
191
|
+
lines.push("", "[features]", "responses_websockets_v2 = true");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
lines.push("");
|
|
195
|
+
return lines.join("\n");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function buildAuthJson(apiKey) {
|
|
199
|
+
return `${JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)}\n`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function commandExists(command) {
|
|
203
|
+
const result = spawnSync(command, ["--version"], {
|
|
204
|
+
stdio: "ignore",
|
|
205
|
+
shell: process.platform === "win32"
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return !result.error && result.status === 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getCommandVersion(command) {
|
|
212
|
+
const result = spawnSync(command, ["--version"], {
|
|
213
|
+
encoding: "utf8",
|
|
214
|
+
shell: process.platform === "win32"
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (result.error || result.status !== 0) {
|
|
218
|
+
return "";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return (result.stdout || result.stderr || "").trim();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function getPaths(codexDir) {
|
|
225
|
+
return {
|
|
226
|
+
configPath: path.join(codexDir, "config.toml"),
|
|
227
|
+
authPath: path.join(codexDir, "auth.json")
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function backupFile(filePath, stamp) {
|
|
232
|
+
if (fs.existsSync(filePath)) {
|
|
233
|
+
const backupPath = `${filePath}.bak.${stamp}`;
|
|
234
|
+
fs.copyFileSync(filePath, backupPath);
|
|
235
|
+
console.log(`已备份: ${backupPath}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function maskApiKey(apiKey) {
|
|
240
|
+
if (!apiKey) {
|
|
241
|
+
return "";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (apiKey.length <= 10) {
|
|
245
|
+
return `${apiKey.slice(0, 3)}***`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return `${apiKey.slice(0, 6)}...${apiKey.slice(-4)}`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function readStatus(options) {
|
|
252
|
+
const { configPath, authPath } = getPaths(options.codexDir);
|
|
253
|
+
const configExists = fs.existsSync(configPath);
|
|
254
|
+
const authExists = fs.existsSync(authPath);
|
|
255
|
+
const configText = configExists ? fs.readFileSync(configPath, "utf8") : "";
|
|
256
|
+
|
|
257
|
+
let baseUrl = "";
|
|
258
|
+
let wsEnabled = false;
|
|
259
|
+
if (configText) {
|
|
260
|
+
const baseMatch = configText.match(/base_url = "([^"]+)"/);
|
|
261
|
+
baseUrl = baseMatch ? baseMatch[1] : "";
|
|
262
|
+
wsEnabled = /supports_websockets = true/.test(configText);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let authKeyMasked = "";
|
|
266
|
+
if (authExists) {
|
|
267
|
+
try {
|
|
268
|
+
const auth = JSON.parse(fs.readFileSync(authPath, "utf8"));
|
|
269
|
+
authKeyMasked = maskApiKey(auth.OPENAI_API_KEY || "");
|
|
270
|
+
} catch {
|
|
271
|
+
authKeyMasked = "读取失败";
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const codexInstalled = commandExists("codex");
|
|
276
|
+
const codexVersion = codexInstalled ? getCommandVersion("codex") : "";
|
|
277
|
+
|
|
278
|
+
console.log("");
|
|
279
|
+
console.log("当前配置状态");
|
|
280
|
+
console.log(`- 目录: ${options.codexDir}`);
|
|
281
|
+
console.log(`- codex 已安装: ${codexInstalled ? "是" : "否"}`);
|
|
282
|
+
if (codexVersion) {
|
|
283
|
+
console.log(`- codex 版本: ${codexVersion}`);
|
|
284
|
+
}
|
|
285
|
+
console.log(`- config.toml: ${configExists ? "存在" : "不存在"}`);
|
|
286
|
+
console.log(`- auth.json: ${authExists ? "存在" : "不存在"}`);
|
|
287
|
+
console.log(`- Base URL: ${baseUrl || "未检测到"}`);
|
|
288
|
+
console.log(`- WebSocket: ${configExists ? (wsEnabled ? "开启" : "关闭") : "未检测到"}`);
|
|
289
|
+
console.log(`- API Key: ${authKeyMasked || "未检测到"}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function installCodexCli() {
|
|
293
|
+
if (!commandExists("npm")) {
|
|
294
|
+
throw new Error("未检测到 npm,无法自动安装 Codex CLI。请先安装 Node.js 和 npm。");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
console.log("");
|
|
298
|
+
console.log(`开始安装/更新 Codex CLI: npm install -g ${CODEX_NPM_PACKAGE}`);
|
|
299
|
+
const result = spawnSync("npm", ["install", "-g", CODEX_NPM_PACKAGE], {
|
|
300
|
+
stdio: "inherit",
|
|
301
|
+
shell: process.platform === "win32"
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (result.error || result.status !== 0) {
|
|
305
|
+
throw new Error("Codex CLI 安装失败,请检查 npm 环境后重试。");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log("Codex CLI 安装完成。");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function writeInstallFiles(options) {
|
|
312
|
+
fs.mkdirSync(options.codexDir, { recursive: true });
|
|
313
|
+
|
|
314
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
315
|
+
const { configPath, authPath } = getPaths(options.codexDir);
|
|
316
|
+
|
|
317
|
+
backupFile(configPath, stamp);
|
|
318
|
+
backupFile(authPath, stamp);
|
|
319
|
+
|
|
320
|
+
fs.writeFileSync(configPath, buildConfigToml(options), "utf8");
|
|
321
|
+
fs.writeFileSync(authPath, buildAuthJson(options.apiKey), "utf8");
|
|
322
|
+
|
|
323
|
+
console.log("");
|
|
324
|
+
console.log("配置完成。");
|
|
325
|
+
console.log(`config.toml: ${configPath}`);
|
|
326
|
+
console.log(`auth.json: ${authPath}`);
|
|
327
|
+
console.log("");
|
|
328
|
+
console.log("建议下一步:");
|
|
329
|
+
console.log("1. 打开 Codex CLI");
|
|
330
|
+
console.log("2. 测试一次对话");
|
|
331
|
+
console.log("3. 如果连接异常,先检查 API Key、线路分组和余额");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function writeAuthOnly(options) {
|
|
335
|
+
fs.mkdirSync(options.codexDir, { recursive: true });
|
|
336
|
+
|
|
337
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
338
|
+
const { authPath } = getPaths(options.codexDir);
|
|
339
|
+
|
|
340
|
+
backupFile(authPath, stamp);
|
|
341
|
+
fs.writeFileSync(authPath, buildAuthJson(options.apiKey), "utf8");
|
|
342
|
+
|
|
343
|
+
console.log("");
|
|
344
|
+
console.log("API Key 已更新。");
|
|
345
|
+
console.log(`auth.json: ${authPath}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function uninstallFiles(options) {
|
|
349
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
350
|
+
const { configPath, authPath } = getPaths(options.codexDir);
|
|
351
|
+
const hasConfig = fs.existsSync(configPath);
|
|
352
|
+
const hasAuth = fs.existsSync(authPath);
|
|
353
|
+
|
|
354
|
+
if (!hasConfig && !hasAuth) {
|
|
355
|
+
console.log("");
|
|
356
|
+
console.log("未发现可卸载的 Codex 配置。");
|
|
357
|
+
console.log(`目录: ${options.codexDir}`);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (hasConfig) {
|
|
362
|
+
backupFile(configPath, stamp);
|
|
363
|
+
fs.rmSync(configPath, { force: true });
|
|
364
|
+
console.log(`已删除: ${configPath}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (hasAuth) {
|
|
368
|
+
backupFile(authPath, stamp);
|
|
369
|
+
fs.rmSync(authPath, { force: true });
|
|
370
|
+
console.log(`已删除: ${authPath}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (fs.existsSync(options.codexDir) && fs.readdirSync(options.codexDir).length === 0) {
|
|
374
|
+
fs.rmdirSync(options.codexDir);
|
|
375
|
+
console.log(`已移除空目录: ${options.codexDir}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
console.log("");
|
|
379
|
+
console.log("卸载完成。");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async function main() {
|
|
383
|
+
let options;
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
options = parseArgs(process.argv.slice(2));
|
|
387
|
+
} catch (error) {
|
|
388
|
+
console.error(error.message);
|
|
389
|
+
printHelp();
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (options.help) {
|
|
394
|
+
printHelp();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!options.action) {
|
|
399
|
+
options.action = await chooseAction();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (options.action === "exit") {
|
|
403
|
+
console.log("已退出。");
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (options.action === "status") {
|
|
408
|
+
readStatus(options);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (options.action === "install-with-codex") {
|
|
413
|
+
options.action = "install";
|
|
414
|
+
options.withCodex = true;
|
|
415
|
+
options.withCodexSpecified = true;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (options.action === "install") {
|
|
419
|
+
if (!options.withCodexSpecified) {
|
|
420
|
+
options.withCodex = await promptYesNo("是否同时安装/更新 Codex CLI?", false);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!options.wsSpecified) {
|
|
424
|
+
options.ws = await promptYesNo("是否启用 WebSocket 版配置?", false);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (!options.apiKey) {
|
|
428
|
+
options.apiKey = await prompt("请输入你的 API Key: ");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!options.apiKey) {
|
|
432
|
+
console.error("API Key 不能为空。");
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (!options.yes) {
|
|
437
|
+
console.log("");
|
|
438
|
+
console.log("即将执行安装:");
|
|
439
|
+
console.log(`- 目录: ${options.codexDir}`);
|
|
440
|
+
console.log(`- Base URL: ${options.baseUrl}`);
|
|
441
|
+
console.log(`- Model: ${options.model}`);
|
|
442
|
+
console.log(`- 安装 Codex CLI: ${options.withCodex ? "是" : "否"}`);
|
|
443
|
+
console.log(`- WebSocket: ${options.ws ? "开启" : "关闭"}`);
|
|
444
|
+
if (!(await promptYesNo("确认继续?", false))) {
|
|
445
|
+
console.log("已取消。");
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (options.withCodex) {
|
|
451
|
+
installCodexCli();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
writeInstallFiles(options);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (options.action === "replace-key") {
|
|
459
|
+
if (!options.apiKey) {
|
|
460
|
+
options.apiKey = await prompt("请输入新的 API Key: ");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (!options.apiKey) {
|
|
464
|
+
console.error("API Key 不能为空。");
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (!options.yes && !(await promptYesNo("确认只更新 API Key?", false))) {
|
|
469
|
+
console.log("已取消。");
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
writeAuthOnly(options);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (options.action === "uninstall") {
|
|
478
|
+
if (!options.yes && !(await promptYesNo("确认卸载当前 Codex 配置?", false))) {
|
|
479
|
+
console.log("已取消。");
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
uninstallFiles(options);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
main().catch((error) => {
|
|
488
|
+
console.error(error.stack || error.message);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codexgo",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "One-command Codex CLI setup for Sub2API gateways",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codexgo": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"codex",
|
|
14
|
+
"sub2api",
|
|
15
|
+
"setup",
|
|
16
|
+
"openai",
|
|
17
|
+
"cli"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
}
|
|
26
|
+
}
|