easyrouter-config 1.0.1 → 1.0.3
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/dist/index.js +100 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
intro,
|
|
6
6
|
outro,
|
|
7
7
|
text,
|
|
8
|
+
select,
|
|
8
9
|
confirm,
|
|
9
10
|
spinner,
|
|
10
11
|
isCancel,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
import { execa } from "execa";
|
|
16
17
|
import pc from "picocolors";
|
|
17
18
|
import { parseArgs } from "util";
|
|
18
|
-
var VERSION = "0.1.
|
|
19
|
+
var VERSION = "0.1.1";
|
|
19
20
|
var CLAUDE_BASE_URL = "https://easyrouter.io";
|
|
20
21
|
var CODEX_BASE_URL = "https://easyrouter.io/v1";
|
|
21
22
|
function parseCliArgs() {
|
|
@@ -74,6 +75,8 @@ ${pc.bold("\u539F\u7406:")}
|
|
|
74
75
|
\u2022 Codex \u2192 ~/.codex/config.toml + ~/.codex/auth.json
|
|
75
76
|
`);
|
|
76
77
|
}
|
|
78
|
+
var IDLE_TIMEOUT_MS = 6e4;
|
|
79
|
+
var HARD_TIMEOUT_MS = 3e5;
|
|
77
80
|
async function runZcf(opts) {
|
|
78
81
|
const args = [
|
|
79
82
|
"-y",
|
|
@@ -108,27 +111,86 @@ async function runZcf(opts) {
|
|
|
108
111
|
"false"
|
|
109
112
|
// 不装状态栏
|
|
110
113
|
];
|
|
114
|
+
const isWin = process.platform === "win32";
|
|
115
|
+
const cmd = isWin ? "npx.cmd" : "npx";
|
|
111
116
|
let capturedOut = "";
|
|
112
117
|
let capturedErr = "";
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
let lastDataAt = Date.now();
|
|
119
|
+
let killedReason = null;
|
|
120
|
+
const child = execa(cmd, args, {
|
|
121
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
122
|
+
env: {
|
|
123
|
+
...process.env,
|
|
124
|
+
FORCE_COLOR: "0",
|
|
125
|
+
// 强制无颜色,免得 ANSI 干扰我们的检测
|
|
126
|
+
CI: "1",
|
|
127
|
+
// 让某些库自动进入"非交互模式"
|
|
128
|
+
npm_config_yes: "true"
|
|
129
|
+
// npx 自动 yes
|
|
130
|
+
},
|
|
131
|
+
reject: false,
|
|
132
|
+
// 我们自己处理退出码,避免 throw 时丢失输出
|
|
133
|
+
windowsHide: true
|
|
134
|
+
});
|
|
135
|
+
const handleChunk = (chunk, target) => {
|
|
136
|
+
const text2 = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
137
|
+
if (target === "out") capturedOut += text2;
|
|
138
|
+
else capturedErr += text2;
|
|
139
|
+
lastDataAt = Date.now();
|
|
140
|
+
if (opts.onProgress) {
|
|
141
|
+
const lines = text2.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
142
|
+
const last = lines[lines.length - 1];
|
|
143
|
+
if (last) opts.onProgress(last.slice(0, 80));
|
|
126
144
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
if (opts.verbose) {
|
|
146
|
+
process.stderr.write(text2);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
child.stdout?.on("data", (c) => handleChunk(c, "out"));
|
|
150
|
+
child.stderr?.on("data", (c) => handleChunk(c, "err"));
|
|
151
|
+
const idleTimer = setInterval(() => {
|
|
152
|
+
if (Date.now() - lastDataAt > IDLE_TIMEOUT_MS) {
|
|
153
|
+
killedReason = `\u5B50\u8FDB\u7A0B\u5DF2 ${Math.floor(IDLE_TIMEOUT_MS / 1e3)} \u79D2\u65E0\u8F93\u51FA\uFF08\u7591\u4F3C\u5361\u5728\u4EA4\u4E92\u5F0F\u63D0\u95EE\u6216\u7F51\u7EDC\u95EE\u9898\uFF09`;
|
|
154
|
+
child.kill("SIGTERM");
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
try {
|
|
157
|
+
child.kill("SIGKILL");
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}, 5e3);
|
|
161
|
+
}
|
|
162
|
+
}, 5e3);
|
|
163
|
+
const hardTimer = setTimeout(() => {
|
|
164
|
+
killedReason = `\u5B50\u8FDB\u7A0B\u8D85\u8FC7 ${Math.floor(HARD_TIMEOUT_MS / 1e3)} \u79D2\u672A\u7ED3\u675F\uFF08\u5F3A\u5236\u8D85\u65F6\uFF09`;
|
|
165
|
+
child.kill("SIGTERM");
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
try {
|
|
168
|
+
child.kill("SIGKILL");
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}, 5e3);
|
|
172
|
+
}, HARD_TIMEOUT_MS);
|
|
173
|
+
const result = await child.catch((e) => e);
|
|
174
|
+
clearInterval(idleTimer);
|
|
175
|
+
clearTimeout(hardTimer);
|
|
176
|
+
const exitCode = result?.exitCode ?? null;
|
|
177
|
+
const signal = result?.signal ?? null;
|
|
178
|
+
if (killedReason) {
|
|
130
179
|
throw new Error(
|
|
131
|
-
`zcf \
|
|
180
|
+
`zcf \u8C03\u7528\u5931\u8D25\uFF1A${killedReason}
|
|
181
|
+
|
|
182
|
+
\u5E38\u89C1\u539F\u56E0\uFF1A
|
|
183
|
+
\u2022 \u6CA1\u88C5\u76EE\u6807\u5BA2\u6237\u7AEF\uFF08zcf \u8BD5\u56FE\u8BE2\u95EE\u662F\u5426\u5B89\u88C5\uFF09
|
|
184
|
+
\u2022 npm \u955C\u50CF/\u7F51\u7EDC\u6162\uFF0Cnpx \u4E0B\u8F7D zcf \u5305\u5361\u4F4F
|
|
185
|
+
\u2022 \u9632\u706B\u5899\u62E6\u622A\u4E86 registry.npmjs.org
|
|
186
|
+
|
|
187
|
+
\u5EFA\u8BAE\uFF1A\u7528 ${pc.green("--verbose")} \u91CD\u65B0\u8FD0\u884C\u67E5\u770B\u8BE6\u7EC6\u65E5\u5FD7`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (exitCode !== 0 || signal) {
|
|
191
|
+
const detail = (capturedErr || capturedOut || "").slice(-2e3) || `exit ${exitCode}, signal ${signal}`;
|
|
192
|
+
throw new Error(
|
|
193
|
+
`zcf \u5F02\u5E38\u9000\u51FA\uFF08code-type=${opts.codeType}, exit=${exitCode}\uFF09:
|
|
132
194
|
${detail}
|
|
133
195
|
|
|
134
196
|
\u{1F4A1} \u7528 ${pc.green("--verbose")} \u91CD\u65B0\u8FD0\u884C\u53EF\u770B\u5230\u5B8C\u6574\u65E5\u5FD7`
|
|
@@ -212,6 +274,22 @@ async function main() {
|
|
|
212
274
|
configCodex = false;
|
|
213
275
|
} else if (args.only === "codex") {
|
|
214
276
|
configClaude = false;
|
|
277
|
+
} else if (!args.apiKey) {
|
|
278
|
+
const target = await select({
|
|
279
|
+
message: "\u8BF7\u9009\u62E9\u8981\u914D\u7F6E\u7684\u5BA2\u6237\u7AEF",
|
|
280
|
+
options: [
|
|
281
|
+
{ value: "both", label: "Claude Code + Codex", hint: "\u4E24\u4E2A\u90FD\u914D\uFF08\u63A8\u8350\uFF09" },
|
|
282
|
+
{ value: "claude", label: "\u4EC5 Claude Code", hint: "\u53EA\u914D ~/.claude/settings.json" },
|
|
283
|
+
{ value: "codex", label: "\u4EC5 Codex", hint: "\u53EA\u914D ~/.codex/config.toml" }
|
|
284
|
+
],
|
|
285
|
+
initialValue: "both"
|
|
286
|
+
});
|
|
287
|
+
if (isCancel(target)) {
|
|
288
|
+
cancel("\u5DF2\u53D6\u6D88");
|
|
289
|
+
process.exit(0);
|
|
290
|
+
}
|
|
291
|
+
if (target === "claude") configCodex = false;
|
|
292
|
+
else if (target === "codex") configClaude = false;
|
|
215
293
|
}
|
|
216
294
|
note(
|
|
217
295
|
[
|
|
@@ -246,7 +324,8 @@ async function main() {
|
|
|
246
324
|
codeType: "cc",
|
|
247
325
|
baseUrl: CLAUDE_BASE_URL,
|
|
248
326
|
apiKey,
|
|
249
|
-
verbose
|
|
327
|
+
verbose,
|
|
328
|
+
onProgress: (line) => s?.message(`\u914D\u7F6E Claude Code \xB7 ${pc.dim(line)}`)
|
|
250
329
|
});
|
|
251
330
|
s?.stop(pc.green("\u2713 Claude Code \u914D\u7F6E\u5B8C\u6210 ") + pc.dim("\u2192 ~/.claude/settings.json"));
|
|
252
331
|
if (!s) log.success(pc.green("\u2713 Claude Code \u914D\u7F6E\u5B8C\u6210 \u2192 ~/.claude/settings.json"));
|
|
@@ -268,7 +347,8 @@ async function main() {
|
|
|
268
347
|
codeType: "cx",
|
|
269
348
|
baseUrl: CODEX_BASE_URL,
|
|
270
349
|
apiKey,
|
|
271
|
-
verbose
|
|
350
|
+
verbose,
|
|
351
|
+
onProgress: (line) => s?.message(`\u914D\u7F6E Codex \xB7 ${pc.dim(line)}`)
|
|
272
352
|
});
|
|
273
353
|
s?.stop(pc.green("\u2713 Codex \u914D\u7F6E\u5B8C\u6210 ") + pc.dim("\u2192 ~/.codex/config.toml"));
|
|
274
354
|
if (!s) log.success(pc.green("\u2713 Codex \u914D\u7F6E\u5B8C\u6210 \u2192 ~/.codex/config.toml"));
|