ccman 3.3.17 → 3.3.18
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 +69 -65
- package/dist/index.js +499 -191
- package/dist/templates/codex/config.toml +4 -2
- package/dist/templates/openclaw/models.base.template.json +10 -10
- package/dist/templates/openclaw/openclaw.base.template.json +12 -11
- package/dist/templates/opencode/opencode.json +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,69 +9,6 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// ../core/package.json
|
|
13
|
-
var package_default;
|
|
14
|
-
var init_package = __esm({
|
|
15
|
-
"../core/package.json"() {
|
|
16
|
-
package_default = {
|
|
17
|
-
name: "@ccman/core",
|
|
18
|
-
version: "3.3.17",
|
|
19
|
-
type: "module",
|
|
20
|
-
description: "Core business logic for ccman - Manage Codex, Claude Code, Gemini CLI, OpenCode, OpenClaw, and MCP configurations",
|
|
21
|
-
main: "./dist/index.js",
|
|
22
|
-
types: "./dist/index.d.ts",
|
|
23
|
-
files: [
|
|
24
|
-
"dist",
|
|
25
|
-
"templates"
|
|
26
|
-
],
|
|
27
|
-
scripts: {
|
|
28
|
-
build: "tsc",
|
|
29
|
-
test: "vitest run",
|
|
30
|
-
"test:watch": "vitest",
|
|
31
|
-
clean: "rm -rf dist"
|
|
32
|
-
},
|
|
33
|
-
keywords: [
|
|
34
|
-
"codex",
|
|
35
|
-
"claude",
|
|
36
|
-
"claude-code",
|
|
37
|
-
"gemini",
|
|
38
|
-
"gemini-cli",
|
|
39
|
-
"opencode",
|
|
40
|
-
"openclaw",
|
|
41
|
-
"mcp",
|
|
42
|
-
"model-context-protocol",
|
|
43
|
-
"ai",
|
|
44
|
-
"api",
|
|
45
|
-
"config",
|
|
46
|
-
"manager"
|
|
47
|
-
],
|
|
48
|
-
author: "2ue",
|
|
49
|
-
license: "MIT",
|
|
50
|
-
repository: {
|
|
51
|
-
type: "git",
|
|
52
|
-
url: "https://github.com/2ue/ccman.git",
|
|
53
|
-
directory: "packages/core"
|
|
54
|
-
},
|
|
55
|
-
homepage: "https://github.com/2ue/ccman#readme",
|
|
56
|
-
bugs: {
|
|
57
|
-
url: "https://github.com/2ue/ccman/issues"
|
|
58
|
-
},
|
|
59
|
-
dependencies: {
|
|
60
|
-
"@ccman/types": "workspace:*",
|
|
61
|
-
"@iarna/toml": "^2.2.5",
|
|
62
|
-
"proper-lockfile": "^4.1.2",
|
|
63
|
-
webdav: "^5.8.0"
|
|
64
|
-
},
|
|
65
|
-
devDependencies: {
|
|
66
|
-
vitest: "^1.0.0"
|
|
67
|
-
},
|
|
68
|
-
engines: {
|
|
69
|
-
node: ">=18.0.0"
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
12
|
// ../types/dist/index.js
|
|
76
13
|
var TOOL_TYPES, MAIN_TOOL_TYPES, TOOL_CONFIG;
|
|
77
14
|
var init_dist = __esm({
|
|
@@ -273,6 +210,35 @@ var init_file = __esm({
|
|
|
273
210
|
}
|
|
274
211
|
});
|
|
275
212
|
|
|
213
|
+
// ../core/dist/utils/template.js
|
|
214
|
+
function replaceVariables(template, variables) {
|
|
215
|
+
const jsonStr = JSON.stringify(template);
|
|
216
|
+
let result = jsonStr;
|
|
217
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
218
|
+
const escapedValue = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
219
|
+
result = result.replace(new RegExp(`{{${key}}}`, "g"), escapedValue);
|
|
220
|
+
}
|
|
221
|
+
return JSON.parse(result);
|
|
222
|
+
}
|
|
223
|
+
function deepMerge(target, source) {
|
|
224
|
+
const result = { ...target };
|
|
225
|
+
for (const key in source) {
|
|
226
|
+
const sourceValue = source[key];
|
|
227
|
+
const targetValue = result[key];
|
|
228
|
+
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
229
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
230
|
+
} else {
|
|
231
|
+
result[key] = sourceValue;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
var init_template = __esm({
|
|
237
|
+
"../core/dist/utils/template.js"() {
|
|
238
|
+
"use strict";
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
276
242
|
// ../core/dist/writers/codex.js
|
|
277
243
|
import * as fs2 from "fs";
|
|
278
244
|
import * as path3 from "path";
|
|
@@ -295,7 +261,7 @@ function resolveTemplatePath(relativePath) {
|
|
|
295
261
|
}
|
|
296
262
|
function resolveCodexProviderKey(provider) {
|
|
297
263
|
const baseUrl = (provider.baseUrl || "").toLowerCase();
|
|
298
|
-
if (baseUrl.includes(
|
|
264
|
+
if (GMN_PROVIDER_HOSTS.some((host) => baseUrl.includes(host)))
|
|
299
265
|
return "gmn";
|
|
300
266
|
return provider.name;
|
|
301
267
|
}
|
|
@@ -310,43 +276,105 @@ function loadCodexTemplateConfig() {
|
|
|
310
276
|
}
|
|
311
277
|
return CODEX_DEFAULT_CONFIG;
|
|
312
278
|
}
|
|
313
|
-
function
|
|
279
|
+
function removeDeprecatedKeys(config) {
|
|
280
|
+
if (config.features && typeof config.features === "object" && !Array.isArray(config.features) && "web_search_request" in config.features) {
|
|
281
|
+
delete config.features.web_search_request;
|
|
282
|
+
}
|
|
283
|
+
if ("web_search_request" in config) {
|
|
284
|
+
delete config.web_search_request;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function loadExistingCodexConfig(configPath) {
|
|
288
|
+
if (!fileExists(configPath)) {
|
|
289
|
+
return {};
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
293
|
+
return parseToml(content);
|
|
294
|
+
} catch {
|
|
295
|
+
return {};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function buildManagedProvider(provider, providerKey) {
|
|
299
|
+
return {
|
|
300
|
+
name: providerKey,
|
|
301
|
+
base_url: provider.baseUrl,
|
|
302
|
+
wire_api: "responses",
|
|
303
|
+
requires_openai_auth: true
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function writeCodexConfigOverwrite(provider) {
|
|
314
307
|
ensureDir(getCodexDir());
|
|
315
308
|
const configPath = getCodexConfigPath();
|
|
316
309
|
const templateConfig = loadCodexTemplateConfig();
|
|
317
310
|
const nextConfig = { ...templateConfig };
|
|
318
|
-
|
|
319
|
-
delete nextConfig.features.web_search_request;
|
|
320
|
-
}
|
|
321
|
-
if ("web_search_request" in nextConfig) {
|
|
322
|
-
delete nextConfig.web_search_request;
|
|
323
|
-
}
|
|
311
|
+
removeDeprecatedKeys(nextConfig);
|
|
324
312
|
const providerKey = resolveCodexProviderKey(provider);
|
|
325
313
|
nextConfig.model_provider = providerKey;
|
|
326
|
-
nextConfig.model = provider.model || nextConfig.model || "gpt-5.
|
|
314
|
+
nextConfig.model = provider.model || nextConfig.model || "gpt-5.4";
|
|
327
315
|
nextConfig.model_providers = {
|
|
328
|
-
[providerKey]:
|
|
329
|
-
name: providerKey,
|
|
330
|
-
base_url: provider.baseUrl,
|
|
331
|
-
wire_api: "responses",
|
|
332
|
-
requires_openai_auth: true
|
|
333
|
-
}
|
|
316
|
+
[providerKey]: buildManagedProvider(provider, providerKey)
|
|
334
317
|
};
|
|
335
318
|
fs2.writeFileSync(configPath, stringifyToml(nextConfig), { mode: 384 });
|
|
336
319
|
const authPath = getCodexAuthPath();
|
|
337
320
|
const auth = { OPENAI_API_KEY: provider.apiKey };
|
|
338
321
|
writeJSON(authPath, auth);
|
|
339
322
|
}
|
|
340
|
-
|
|
323
|
+
function writeCodexConfigMerge(provider) {
|
|
324
|
+
ensureDir(getCodexDir());
|
|
325
|
+
const configPath = getCodexConfigPath();
|
|
326
|
+
const existingConfig = loadExistingCodexConfig(configPath);
|
|
327
|
+
const templateConfig = loadCodexTemplateConfig();
|
|
328
|
+
const nextConfig = deepMerge(templateConfig, existingConfig);
|
|
329
|
+
const providerKey = resolveCodexProviderKey(provider);
|
|
330
|
+
removeDeprecatedKeys(nextConfig);
|
|
331
|
+
nextConfig.model_provider = providerKey;
|
|
332
|
+
nextConfig.model = provider.model || nextConfig.model || "gpt-5.4";
|
|
333
|
+
const existingProviders = nextConfig.model_providers && typeof nextConfig.model_providers === "object" && !Array.isArray(nextConfig.model_providers) ? { ...nextConfig.model_providers } : {};
|
|
334
|
+
const lowerProviderKey = providerKey.toLowerCase();
|
|
335
|
+
for (const key of Object.keys(existingProviders)) {
|
|
336
|
+
if (key.toLowerCase() === lowerProviderKey) {
|
|
337
|
+
delete existingProviders[key];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
nextConfig.model_providers = {
|
|
341
|
+
...existingProviders,
|
|
342
|
+
[providerKey]: buildManagedProvider(provider, providerKey)
|
|
343
|
+
};
|
|
344
|
+
fs2.writeFileSync(configPath, stringifyToml(nextConfig), { mode: 384 });
|
|
345
|
+
const authPath = getCodexAuthPath();
|
|
346
|
+
let existingAuth = { OPENAI_API_KEY: "" };
|
|
347
|
+
if (fileExists(authPath)) {
|
|
348
|
+
try {
|
|
349
|
+
existingAuth = readJSON(authPath);
|
|
350
|
+
} catch {
|
|
351
|
+
existingAuth = { OPENAI_API_KEY: "" };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const nextAuth = {
|
|
355
|
+
...existingAuth,
|
|
356
|
+
OPENAI_API_KEY: provider.apiKey
|
|
357
|
+
};
|
|
358
|
+
writeJSON(authPath, nextAuth);
|
|
359
|
+
}
|
|
360
|
+
function writeCodexConfig(provider, options = {}) {
|
|
361
|
+
if (options.mode === "overwrite") {
|
|
362
|
+
writeCodexConfigOverwrite(provider);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
writeCodexConfigMerge(provider);
|
|
366
|
+
}
|
|
367
|
+
var __filename, __dirname, CODEX_DEFAULT_CONFIG, GMN_PROVIDER_HOSTS;
|
|
341
368
|
var init_codex = __esm({
|
|
342
369
|
"../core/dist/writers/codex.js"() {
|
|
343
370
|
"use strict";
|
|
344
371
|
init_paths();
|
|
345
372
|
init_file();
|
|
373
|
+
init_template();
|
|
346
374
|
__filename = fileURLToPath(import.meta.url);
|
|
347
375
|
__dirname = path3.dirname(__filename);
|
|
348
376
|
CODEX_DEFAULT_CONFIG = {
|
|
349
|
-
model: "gpt-5.
|
|
377
|
+
model: "gpt-5.4",
|
|
350
378
|
model_reasoning_effort: "xhigh",
|
|
351
379
|
disable_response_storage: true,
|
|
352
380
|
sandbox_mode: "danger-full-access",
|
|
@@ -392,35 +420,15 @@ var init_codex = __esm({
|
|
|
392
420
|
hide_gpt5_1_migration_prompt: true
|
|
393
421
|
}
|
|
394
422
|
};
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
result = result.replace(new RegExp(`{{${key}}}`, "g"), escapedValue);
|
|
405
|
-
}
|
|
406
|
-
return JSON.parse(result);
|
|
407
|
-
}
|
|
408
|
-
function deepMerge(target, source) {
|
|
409
|
-
const result = { ...target };
|
|
410
|
-
for (const key in source) {
|
|
411
|
-
const sourceValue = source[key];
|
|
412
|
-
const targetValue = result[key];
|
|
413
|
-
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
414
|
-
result[key] = deepMerge(targetValue, sourceValue);
|
|
415
|
-
} else {
|
|
416
|
-
result[key] = sourceValue;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return result;
|
|
420
|
-
}
|
|
421
|
-
var init_template = __esm({
|
|
422
|
-
"../core/dist/utils/template.js"() {
|
|
423
|
-
"use strict";
|
|
423
|
+
GMN_PROVIDER_HOSTS = [
|
|
424
|
+
"gmn.chuangzuoli.com",
|
|
425
|
+
"cdn.gmnchuangzuoli.com",
|
|
426
|
+
"gmncodex.com",
|
|
427
|
+
"gmncode.cn",
|
|
428
|
+
"cdn.gmncode.cn",
|
|
429
|
+
"gmn.codex.com",
|
|
430
|
+
"cdn.gmncode.com"
|
|
431
|
+
];
|
|
424
432
|
}
|
|
425
433
|
});
|
|
426
434
|
|
|
@@ -454,19 +462,23 @@ function loadClaudeTemplateConfig() {
|
|
|
454
462
|
}
|
|
455
463
|
return CLAUDE_CONFIG_TEMPLATE;
|
|
456
464
|
}
|
|
457
|
-
function writeClaudeConfig(provider) {
|
|
465
|
+
function writeClaudeConfig(provider, options = {}) {
|
|
458
466
|
ensureDir(getClaudeDir());
|
|
459
467
|
const configPath = getClaudeConfigPath();
|
|
460
|
-
let userConfig = {};
|
|
461
|
-
if (fileExists(configPath)) {
|
|
462
|
-
const content = fs3.readFileSync(configPath, "utf-8");
|
|
463
|
-
userConfig = JSON.parse(content);
|
|
464
|
-
}
|
|
465
468
|
const defaultTemplate = loadClaudeTemplateConfig();
|
|
466
469
|
const defaultConfig = replaceVariables(defaultTemplate, {
|
|
467
470
|
apiKey: provider.apiKey,
|
|
468
471
|
baseUrl: provider.baseUrl
|
|
469
472
|
});
|
|
473
|
+
if (options.mode === "overwrite") {
|
|
474
|
+
fs3.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), { mode: 384 });
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
let userConfig = {};
|
|
478
|
+
if (fileExists(configPath)) {
|
|
479
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
480
|
+
userConfig = JSON.parse(content);
|
|
481
|
+
}
|
|
470
482
|
const mergedConfig = deepMerge(defaultConfig, userConfig);
|
|
471
483
|
mergedConfig.env = mergedConfig.env || {};
|
|
472
484
|
mergedConfig.env.ANTHROPIC_AUTH_TOKEN = provider.apiKey;
|
|
@@ -893,13 +905,14 @@ function saveEnvFile(envPath, env) {
|
|
|
893
905
|
fs5.writeFileSync(tempPath, content, { mode: 384 });
|
|
894
906
|
fs5.renameSync(tempPath, envPath);
|
|
895
907
|
}
|
|
896
|
-
function writeGeminiConfig(provider) {
|
|
908
|
+
function writeGeminiConfig(provider, options = {}) {
|
|
897
909
|
const settingsPath = getGeminiSettingsPath();
|
|
898
910
|
const envPath = getGeminiEnvPath();
|
|
899
911
|
const dir = getGeminiDir();
|
|
900
912
|
ensureDir(dir);
|
|
913
|
+
const settingsTemplate = loadGeminiSettingsTemplate();
|
|
901
914
|
let userSettings = {};
|
|
902
|
-
if (fileExists(settingsPath)) {
|
|
915
|
+
if (options.mode !== "overwrite" && fileExists(settingsPath)) {
|
|
903
916
|
try {
|
|
904
917
|
const content = fs5.readFileSync(settingsPath, "utf-8");
|
|
905
918
|
const parsed = JSON.parse(content);
|
|
@@ -910,8 +923,7 @@ function writeGeminiConfig(provider) {
|
|
|
910
923
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6 Gemini settings.json: ${error.message}`);
|
|
911
924
|
}
|
|
912
925
|
}
|
|
913
|
-
const
|
|
914
|
-
const settings = deepMerge(settingsTemplate, userSettings);
|
|
926
|
+
const settings = options.mode === "overwrite" ? { ...settingsTemplate } : deepMerge(settingsTemplate, userSettings);
|
|
915
927
|
if (!settings.ide || typeof settings.ide !== "object") {
|
|
916
928
|
settings.ide = {};
|
|
917
929
|
}
|
|
@@ -936,7 +948,7 @@ function writeGeminiConfig(provider) {
|
|
|
936
948
|
} catch (error) {
|
|
937
949
|
throw new Error(`\u5199\u5165 Gemini settings.json \u5931\u8D25: ${error.message}`);
|
|
938
950
|
}
|
|
939
|
-
const existingEnv = loadEnvFile(envPath);
|
|
951
|
+
const existingEnv = options.mode === "overwrite" ? {} : loadEnvFile(envPath);
|
|
940
952
|
const templateEnv = loadGeminiEnvTemplate(provider);
|
|
941
953
|
const env = {
|
|
942
954
|
...existingEnv,
|
|
@@ -1063,7 +1075,8 @@ function enforceAgentStoreFalse(agent) {
|
|
|
1063
1075
|
}
|
|
1064
1076
|
function enforceModelStoreFalse(models) {
|
|
1065
1077
|
const base = models && typeof models === "object" && !Array.isArray(models) ? models : {};
|
|
1066
|
-
|
|
1078
|
+
const mergedModels = deepMerge(DEFAULT_MODELS, base);
|
|
1079
|
+
return deepMerge(mergedModels, {
|
|
1067
1080
|
[OPENCODE_MODEL_KEY]: {
|
|
1068
1081
|
options: {
|
|
1069
1082
|
store: false
|
|
@@ -1074,20 +1087,31 @@ function enforceModelStoreFalse(models) {
|
|
|
1074
1087
|
high: {},
|
|
1075
1088
|
xhigh: {}
|
|
1076
1089
|
}
|
|
1090
|
+
},
|
|
1091
|
+
[OPENCODE_SECONDARY_MODEL_KEY]: {
|
|
1092
|
+
options: {
|
|
1093
|
+
store: false
|
|
1094
|
+
},
|
|
1095
|
+
variants: {
|
|
1096
|
+
low: {},
|
|
1097
|
+
medium: {},
|
|
1098
|
+
high: {},
|
|
1099
|
+
xhigh: {}
|
|
1100
|
+
}
|
|
1077
1101
|
}
|
|
1078
1102
|
});
|
|
1079
1103
|
}
|
|
1080
|
-
function writeOpenCodeConfig(provider) {
|
|
1104
|
+
function writeOpenCodeConfig(provider, options = {}) {
|
|
1081
1105
|
ensureDir(getOpenCodeDir());
|
|
1082
1106
|
const configPath = getOpenCodeConfigPath();
|
|
1083
|
-
const existingConfig = fileExists(configPath) ? readJSON(configPath) : {};
|
|
1107
|
+
const existingConfig = options.mode === "overwrite" ? {} : fileExists(configPath) ? readJSON(configPath) : {};
|
|
1084
1108
|
const meta = parseProviderMeta(provider.model);
|
|
1085
1109
|
const template = loadOpenCodeTemplateConfig();
|
|
1086
1110
|
const defaultConfig = replaceVariables(template, {
|
|
1087
1111
|
baseUrl: provider.baseUrl,
|
|
1088
1112
|
apiKey: provider.apiKey
|
|
1089
1113
|
});
|
|
1090
|
-
const mergedConfig = deepMerge(defaultConfig, existingConfig);
|
|
1114
|
+
const mergedConfig = options.mode === "overwrite" ? { ...defaultConfig } : deepMerge(defaultConfig, existingConfig);
|
|
1091
1115
|
const templateProvider = defaultConfig.provider?.[OPENCODE_PROVIDER_KEY];
|
|
1092
1116
|
const existingProvider = mergedConfig.provider?.[OPENCODE_PROVIDER_KEY];
|
|
1093
1117
|
const models = enforceModelStoreFalse(meta?.models || existingProvider?.models || templateProvider?.models || DEFAULT_MODELS);
|
|
@@ -1100,7 +1124,7 @@ function writeOpenCodeConfig(provider) {
|
|
|
1100
1124
|
},
|
|
1101
1125
|
models
|
|
1102
1126
|
});
|
|
1103
|
-
const existingProviders = mergedConfig.provider && typeof mergedConfig.provider === "object" && !Array.isArray(mergedConfig.provider) ? { ...mergedConfig.provider } : {};
|
|
1127
|
+
const existingProviders = options.mode === "overwrite" ? {} : mergedConfig.provider && typeof mergedConfig.provider === "object" && !Array.isArray(mergedConfig.provider) ? { ...mergedConfig.provider } : {};
|
|
1104
1128
|
const nextConfig = {
|
|
1105
1129
|
...mergedConfig,
|
|
1106
1130
|
$schema: OPENCODE_SCHEMA,
|
|
@@ -1113,7 +1137,7 @@ function writeOpenCodeConfig(provider) {
|
|
|
1113
1137
|
};
|
|
1114
1138
|
writeJSON(configPath, nextConfig);
|
|
1115
1139
|
}
|
|
1116
|
-
var OPENCODE_SCHEMA, OPENCODE_PROVIDER_KEY, OPENCODE_MODEL, OPENCODE_MODEL_KEY, __filename4, __dirname4, DEFAULT_MODELS, OPENCODE_CONFIG_TEMPLATE;
|
|
1140
|
+
var OPENCODE_SCHEMA, OPENCODE_PROVIDER_KEY, OPENCODE_MODEL, OPENCODE_MODEL_KEY, OPENCODE_SECONDARY_MODEL_KEY, __filename4, __dirname4, DEFAULT_MODELS, OPENCODE_CONFIG_TEMPLATE;
|
|
1117
1141
|
var init_opencode2 = __esm({
|
|
1118
1142
|
"../core/dist/writers/opencode.js"() {
|
|
1119
1143
|
"use strict";
|
|
@@ -1122,13 +1146,26 @@ var init_opencode2 = __esm({
|
|
|
1122
1146
|
init_template();
|
|
1123
1147
|
OPENCODE_SCHEMA = "https://opencode.ai/config.json";
|
|
1124
1148
|
OPENCODE_PROVIDER_KEY = "openai";
|
|
1125
|
-
OPENCODE_MODEL = "openai/gpt-5.
|
|
1126
|
-
OPENCODE_MODEL_KEY = "gpt-5.
|
|
1149
|
+
OPENCODE_MODEL = "openai/gpt-5.4";
|
|
1150
|
+
OPENCODE_MODEL_KEY = "gpt-5.4";
|
|
1151
|
+
OPENCODE_SECONDARY_MODEL_KEY = "gpt-5.3-codex";
|
|
1127
1152
|
__filename4 = fileURLToPath4(import.meta.url);
|
|
1128
1153
|
__dirname4 = path7.dirname(__filename4);
|
|
1129
1154
|
DEFAULT_MODELS = {
|
|
1130
1155
|
[OPENCODE_MODEL_KEY]: {
|
|
1131
|
-
name: "GPT-5.
|
|
1156
|
+
name: "GPT-5.4",
|
|
1157
|
+
options: {
|
|
1158
|
+
store: false
|
|
1159
|
+
},
|
|
1160
|
+
variants: {
|
|
1161
|
+
low: {},
|
|
1162
|
+
medium: {},
|
|
1163
|
+
high: {},
|
|
1164
|
+
xhigh: {}
|
|
1165
|
+
}
|
|
1166
|
+
},
|
|
1167
|
+
[OPENCODE_SECONDARY_MODEL_KEY]: {
|
|
1168
|
+
name: "GPT-5.3 Codex",
|
|
1132
1169
|
options: {
|
|
1133
1170
|
store: false
|
|
1134
1171
|
},
|
|
@@ -1257,7 +1294,7 @@ function replaceProviderEntry(providers, providerName, nextProvider) {
|
|
|
1257
1294
|
}
|
|
1258
1295
|
return result;
|
|
1259
1296
|
}
|
|
1260
|
-
function writeOpenClawConfig(provider) {
|
|
1297
|
+
function writeOpenClawConfig(provider, options = {}) {
|
|
1261
1298
|
const configPath = getOpenClawConfigPath();
|
|
1262
1299
|
const modelsPath = getOpenClawModelsPath();
|
|
1263
1300
|
const homeDir = path8.dirname(getOpenClawDir());
|
|
@@ -1273,6 +1310,26 @@ function writeOpenClawConfig(provider) {
|
|
|
1273
1310
|
};
|
|
1274
1311
|
const nextOpenClawConfig = replaceVariables(rawConfigTemplate, variables);
|
|
1275
1312
|
const nextModelsConfig = replaceVariables(rawModelsTemplate, variables);
|
|
1313
|
+
if (options.mode === "overwrite") {
|
|
1314
|
+
const overwriteConfig = {
|
|
1315
|
+
...nextOpenClawConfig,
|
|
1316
|
+
agents: {
|
|
1317
|
+
...nextOpenClawConfig.agents,
|
|
1318
|
+
defaults: {
|
|
1319
|
+
...nextOpenClawConfig.agents?.defaults || {},
|
|
1320
|
+
workspace: homeDir,
|
|
1321
|
+
imageModel: nextOpenClawConfig.agents?.defaults?.imageModel || `${providerName}/gpt-5.4`,
|
|
1322
|
+
model: {
|
|
1323
|
+
...nextOpenClawConfig.agents?.defaults?.model || {},
|
|
1324
|
+
primary: nextOpenClawConfig.agents?.defaults?.model?.primary || `${providerName}/gpt-5.4`
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
writeJSON(configPath, overwriteConfig);
|
|
1330
|
+
writeJSON(modelsPath, nextModelsConfig);
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1276
1333
|
const existingOpenClawConfig = loadExistingJSON(configPath) || {};
|
|
1277
1334
|
const existingModelsConfig = loadExistingJSON(modelsPath) || {};
|
|
1278
1335
|
const mergedConfigModels = deepMerge(existingOpenClawConfig.models || {}, nextOpenClawConfig.models || {});
|
|
@@ -1282,7 +1339,8 @@ function writeOpenClawConfig(provider) {
|
|
|
1282
1339
|
const mergedAgents = deepMerge(nextOpenClawConfig.agents || {}, existingOpenClawConfig.agents || {});
|
|
1283
1340
|
const mergedDefaults = mergedAgents.defaults || {};
|
|
1284
1341
|
const mergedModel = mergedDefaults.model || {};
|
|
1285
|
-
const templatePrimary = nextOpenClawConfig.agents?.defaults?.model?.primary || `${providerName}/gpt-5.
|
|
1342
|
+
const templatePrimary = nextOpenClawConfig.agents?.defaults?.model?.primary || `${providerName}/gpt-5.4`;
|
|
1343
|
+
const templateImageModel = nextOpenClawConfig.agents?.defaults?.imageModel || `${providerName}/gpt-5.4`;
|
|
1286
1344
|
const workspace = typeof mergedDefaults.workspace === "string" && mergedDefaults.workspace.trim() ? mergedDefaults.workspace : homeDir;
|
|
1287
1345
|
const finalOpenClawConfig = {
|
|
1288
1346
|
...existingOpenClawConfig,
|
|
@@ -1292,6 +1350,7 @@ function writeOpenClawConfig(provider) {
|
|
|
1292
1350
|
defaults: {
|
|
1293
1351
|
...mergedDefaults,
|
|
1294
1352
|
workspace,
|
|
1353
|
+
imageModel: templateImageModel,
|
|
1295
1354
|
model: {
|
|
1296
1355
|
...mergedModel,
|
|
1297
1356
|
primary: templatePrimary
|
|
@@ -1308,7 +1367,7 @@ function writeOpenClawConfig(provider) {
|
|
|
1308
1367
|
writeJSON(configPath, finalOpenClawConfig);
|
|
1309
1368
|
writeJSON(modelsPath, finalModelsConfig);
|
|
1310
1369
|
}
|
|
1311
|
-
var DEFAULT_PROVIDER_NAME, PRIMARY_MODEL_ID, __filename5, __dirname5, OPENCLAW_CONFIG_TEMPLATE, OPENCLAW_MODELS_TEMPLATE;
|
|
1370
|
+
var DEFAULT_PROVIDER_NAME, PRIMARY_MODEL_ID, SECONDARY_MODEL_ID, PRIMARY_MODEL_INPUTS, SECONDARY_MODEL_INPUTS, __filename5, __dirname5, OPENCLAW_CONFIG_TEMPLATE, OPENCLAW_MODELS_TEMPLATE;
|
|
1312
1371
|
var init_openclaw2 = __esm({
|
|
1313
1372
|
"../core/dist/writers/openclaw.js"() {
|
|
1314
1373
|
"use strict";
|
|
@@ -1316,7 +1375,10 @@ var init_openclaw2 = __esm({
|
|
|
1316
1375
|
init_file();
|
|
1317
1376
|
init_template();
|
|
1318
1377
|
DEFAULT_PROVIDER_NAME = "gmn";
|
|
1319
|
-
PRIMARY_MODEL_ID = "gpt-5.
|
|
1378
|
+
PRIMARY_MODEL_ID = "gpt-5.4";
|
|
1379
|
+
SECONDARY_MODEL_ID = "gpt-5.3-codex";
|
|
1380
|
+
PRIMARY_MODEL_INPUTS = ["text", "image"];
|
|
1381
|
+
SECONDARY_MODEL_INPUTS = ["text", "image"];
|
|
1320
1382
|
__filename5 = fileURLToPath5(import.meta.url);
|
|
1321
1383
|
__dirname5 = path8.dirname(__filename5);
|
|
1322
1384
|
OPENCLAW_CONFIG_TEMPLATE = {
|
|
@@ -1334,24 +1396,24 @@ var init_openclaw2 = __esm({
|
|
|
1334
1396
|
authHeader: true,
|
|
1335
1397
|
models: [
|
|
1336
1398
|
{
|
|
1337
|
-
id: "gpt-5.
|
|
1338
|
-
name: "gpt-5.
|
|
1399
|
+
id: "gpt-5.4",
|
|
1400
|
+
name: "gpt-5.4",
|
|
1339
1401
|
api: "openai-responses",
|
|
1340
|
-
reasoning:
|
|
1341
|
-
input:
|
|
1402
|
+
reasoning: true,
|
|
1403
|
+
input: PRIMARY_MODEL_INPUTS,
|
|
1342
1404
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1343
|
-
contextWindow:
|
|
1344
|
-
maxTokens:
|
|
1405
|
+
contextWindow: 105e4,
|
|
1406
|
+
maxTokens: 128e3
|
|
1345
1407
|
},
|
|
1346
1408
|
{
|
|
1347
|
-
id:
|
|
1348
|
-
name:
|
|
1409
|
+
id: SECONDARY_MODEL_ID,
|
|
1410
|
+
name: SECONDARY_MODEL_ID,
|
|
1349
1411
|
api: "openai-responses",
|
|
1350
1412
|
reasoning: false,
|
|
1351
|
-
input:
|
|
1413
|
+
input: SECONDARY_MODEL_INPUTS,
|
|
1352
1414
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1353
|
-
contextWindow:
|
|
1354
|
-
maxTokens:
|
|
1415
|
+
contextWindow: 4e5,
|
|
1416
|
+
maxTokens: 128e3
|
|
1355
1417
|
}
|
|
1356
1418
|
]
|
|
1357
1419
|
}
|
|
@@ -1360,8 +1422,9 @@ var init_openclaw2 = __esm({
|
|
|
1360
1422
|
agents: {
|
|
1361
1423
|
defaults: {
|
|
1362
1424
|
workspace: "",
|
|
1425
|
+
imageModel: "{{providerName}}/gpt-5.4",
|
|
1363
1426
|
model: {
|
|
1364
|
-
primary: "{{providerName}}/gpt-5.
|
|
1427
|
+
primary: "{{providerName}}/gpt-5.4"
|
|
1365
1428
|
},
|
|
1366
1429
|
thinkingDefault: "xhigh"
|
|
1367
1430
|
}
|
|
@@ -1380,24 +1443,24 @@ var init_openclaw2 = __esm({
|
|
|
1380
1443
|
},
|
|
1381
1444
|
models: [
|
|
1382
1445
|
{
|
|
1383
|
-
id: "gpt-5.
|
|
1384
|
-
name: "gpt-5.
|
|
1446
|
+
id: "gpt-5.4",
|
|
1447
|
+
name: "gpt-5.4",
|
|
1385
1448
|
api: "openai-responses",
|
|
1386
|
-
reasoning:
|
|
1387
|
-
input:
|
|
1449
|
+
reasoning: true,
|
|
1450
|
+
input: PRIMARY_MODEL_INPUTS,
|
|
1388
1451
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1389
|
-
contextWindow:
|
|
1390
|
-
maxTokens:
|
|
1452
|
+
contextWindow: 105e4,
|
|
1453
|
+
maxTokens: 128e3
|
|
1391
1454
|
},
|
|
1392
1455
|
{
|
|
1393
|
-
id:
|
|
1394
|
-
name:
|
|
1456
|
+
id: SECONDARY_MODEL_ID,
|
|
1457
|
+
name: SECONDARY_MODEL_ID,
|
|
1395
1458
|
api: "openai-responses",
|
|
1396
1459
|
reasoning: false,
|
|
1397
|
-
input:
|
|
1460
|
+
input: SECONDARY_MODEL_INPUTS,
|
|
1398
1461
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1399
|
-
contextWindow:
|
|
1400
|
-
maxTokens:
|
|
1462
|
+
contextWindow: 4e5,
|
|
1463
|
+
maxTokens: 128e3
|
|
1401
1464
|
}
|
|
1402
1465
|
]
|
|
1403
1466
|
}
|
|
@@ -1537,7 +1600,7 @@ function createToolManager(tool) {
|
|
|
1537
1600
|
return void 0;
|
|
1538
1601
|
return config.providers.find((p) => p.name.trim().toLowerCase() === lowerName);
|
|
1539
1602
|
},
|
|
1540
|
-
switch(id) {
|
|
1603
|
+
switch(id, options) {
|
|
1541
1604
|
const config = loadConfig2();
|
|
1542
1605
|
const provider = config.providers.find((p) => p.id === id);
|
|
1543
1606
|
if (!provider) {
|
|
@@ -1546,7 +1609,7 @@ function createToolManager(tool) {
|
|
|
1546
1609
|
config.currentProviderId = id;
|
|
1547
1610
|
provider.lastUsedAt = Date.now();
|
|
1548
1611
|
saveConfig2(config);
|
|
1549
|
-
toolConfig.writer(provider);
|
|
1612
|
+
toolConfig.writer(provider, options);
|
|
1550
1613
|
},
|
|
1551
1614
|
getCurrent() {
|
|
1552
1615
|
const config = loadConfig2();
|
|
@@ -1559,10 +1622,11 @@ function createToolManager(tool) {
|
|
|
1559
1622
|
// 注:edit 方法的"复杂度"来自必要的业务逻辑(检查存在性、名称冲突、更新 4 个可选字段、同步配置)
|
|
1560
1623
|
// 每个 if 都不可避免,没有特殊情况或嵌套逻辑,因此禁用 complexity 检查
|
|
1561
1624
|
// eslint-disable-next-line complexity
|
|
1562
|
-
edit(id, updates) {
|
|
1625
|
+
edit(id, updates, options = {}) {
|
|
1563
1626
|
const config = loadConfig2();
|
|
1564
1627
|
const provider = config.providers.find((p) => p.id === id);
|
|
1565
1628
|
const normalizedUpdates = trimProviderUpdates(updates);
|
|
1629
|
+
const shouldApplyWrite = options.applyWrite !== false;
|
|
1566
1630
|
if (!provider) {
|
|
1567
1631
|
throw new ProviderNotFoundError(id);
|
|
1568
1632
|
}
|
|
@@ -1587,10 +1651,10 @@ function createToolManager(tool) {
|
|
|
1587
1651
|
provider.model = normalizedUpdates.model;
|
|
1588
1652
|
provider.lastModified = Date.now();
|
|
1589
1653
|
saveConfig2(config);
|
|
1590
|
-
if (config.currentProviderId === id) {
|
|
1654
|
+
if (shouldApplyWrite && config.currentProviderId === id) {
|
|
1591
1655
|
toolConfig.writer(provider);
|
|
1592
1656
|
}
|
|
1593
|
-
if (toolConfig.autoSync) {
|
|
1657
|
+
if (shouldApplyWrite && toolConfig.autoSync) {
|
|
1594
1658
|
toolConfig.writer(provider);
|
|
1595
1659
|
}
|
|
1596
1660
|
return provider;
|
|
@@ -2806,11 +2870,11 @@ var init_claude_clean = __esm({
|
|
|
2806
2870
|
});
|
|
2807
2871
|
|
|
2808
2872
|
// ../core/dist/index.js
|
|
2809
|
-
|
|
2873
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
2874
|
+
var pkg, VERSION;
|
|
2810
2875
|
var init_dist2 = __esm({
|
|
2811
2876
|
"../core/dist/index.js"() {
|
|
2812
2877
|
"use strict";
|
|
2813
|
-
init_package();
|
|
2814
2878
|
init_constants();
|
|
2815
2879
|
init_tool_manager();
|
|
2816
2880
|
init_codex2();
|
|
@@ -2829,7 +2893,8 @@ var init_dist2 = __esm({
|
|
|
2829
2893
|
init_merge_advanced();
|
|
2830
2894
|
init_export();
|
|
2831
2895
|
init_claude_clean();
|
|
2832
|
-
|
|
2896
|
+
pkg = JSON.parse(readFileSync10(new URL("../package.json", import.meta.url), "utf-8"));
|
|
2897
|
+
VERSION = pkg.version;
|
|
2833
2898
|
}
|
|
2834
2899
|
});
|
|
2835
2900
|
|
|
@@ -7151,20 +7216,180 @@ import fs13 from "fs";
|
|
|
7151
7216
|
import path15 from "path";
|
|
7152
7217
|
import chalk54 from "chalk";
|
|
7153
7218
|
import inquirer38 from "inquirer";
|
|
7219
|
+
|
|
7220
|
+
// src/utils/endpoint-latency.ts
|
|
7221
|
+
import { request as httpRequest } from "http";
|
|
7222
|
+
import { request as httpsRequest } from "https";
|
|
7223
|
+
import { performance } from "perf_hooks";
|
|
7224
|
+
function normalizeEndpointUrl(url) {
|
|
7225
|
+
const normalized = url.trim().replace(/\/+$/, "");
|
|
7226
|
+
new URL(normalized);
|
|
7227
|
+
return normalized;
|
|
7228
|
+
}
|
|
7229
|
+
function calculateMedian(values) {
|
|
7230
|
+
if (values.length === 0) {
|
|
7231
|
+
throw new Error("\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u91C7\u6837\u503C");
|
|
7232
|
+
}
|
|
7233
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
7234
|
+
const middle = Math.floor(sorted.length / 2);
|
|
7235
|
+
if (sorted.length % 2 === 0) {
|
|
7236
|
+
return Math.round((sorted[middle - 1] + sorted[middle]) / 2);
|
|
7237
|
+
}
|
|
7238
|
+
return sorted[middle];
|
|
7239
|
+
}
|
|
7240
|
+
function probeOnce(url, timeoutMs) {
|
|
7241
|
+
return new Promise((resolve6) => {
|
|
7242
|
+
const target = new URL(url);
|
|
7243
|
+
const requester = target.protocol === "http:" ? httpRequest : httpsRequest;
|
|
7244
|
+
const start = performance.now();
|
|
7245
|
+
let settled = false;
|
|
7246
|
+
const finish = (result) => {
|
|
7247
|
+
if (settled) return;
|
|
7248
|
+
settled = true;
|
|
7249
|
+
resolve6(result);
|
|
7250
|
+
};
|
|
7251
|
+
const req = requester(
|
|
7252
|
+
target,
|
|
7253
|
+
{
|
|
7254
|
+
method: "GET",
|
|
7255
|
+
headers: {
|
|
7256
|
+
Accept: "application/json",
|
|
7257
|
+
"Cache-Control": "no-cache",
|
|
7258
|
+
"User-Agent": "ccman-latency-probe/1.0"
|
|
7259
|
+
}
|
|
7260
|
+
},
|
|
7261
|
+
(response) => {
|
|
7262
|
+
const latencyMs = Math.max(1, Math.round(performance.now() - start));
|
|
7263
|
+
const statusCode = response.statusCode ?? null;
|
|
7264
|
+
response.destroy();
|
|
7265
|
+
finish({ latencyMs, statusCode });
|
|
7266
|
+
}
|
|
7267
|
+
);
|
|
7268
|
+
req.setTimeout(timeoutMs, () => {
|
|
7269
|
+
req.destroy(new Error(`\u6D4B\u901F\u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09`));
|
|
7270
|
+
});
|
|
7271
|
+
req.on("error", (error) => {
|
|
7272
|
+
finish({
|
|
7273
|
+
latencyMs: null,
|
|
7274
|
+
statusCode: null,
|
|
7275
|
+
error: error.message
|
|
7276
|
+
});
|
|
7277
|
+
});
|
|
7278
|
+
req.end();
|
|
7279
|
+
});
|
|
7280
|
+
}
|
|
7281
|
+
async function probeCandidate(candidate, originalIndex, options) {
|
|
7282
|
+
const normalizedUrl = normalizeEndpointUrl(candidate.url);
|
|
7283
|
+
const normalizedProbeUrl = candidate.probeUrl ? normalizeEndpointUrl(candidate.probeUrl) : normalizedUrl;
|
|
7284
|
+
const samples = [];
|
|
7285
|
+
let statusCode = null;
|
|
7286
|
+
let lastError;
|
|
7287
|
+
for (let index = 0; index < options.sampleCount; index += 1) {
|
|
7288
|
+
const result = await probeOnce(normalizedProbeUrl, options.timeoutMs);
|
|
7289
|
+
if (result.latencyMs !== null) {
|
|
7290
|
+
samples.push(result.latencyMs);
|
|
7291
|
+
statusCode = result.statusCode;
|
|
7292
|
+
} else if (!lastError) {
|
|
7293
|
+
lastError = result.error;
|
|
7294
|
+
}
|
|
7295
|
+
}
|
|
7296
|
+
return {
|
|
7297
|
+
...candidate,
|
|
7298
|
+
url: normalizedUrl,
|
|
7299
|
+
probeUrl: normalizedProbeUrl,
|
|
7300
|
+
originalIndex,
|
|
7301
|
+
samples,
|
|
7302
|
+
statusCode,
|
|
7303
|
+
latencyMs: samples.length > 0 ? calculateMedian(samples) : null,
|
|
7304
|
+
error: samples.length > 0 ? void 0 : lastError || "\u6D4B\u901F\u5931\u8D25"
|
|
7305
|
+
};
|
|
7306
|
+
}
|
|
7307
|
+
async function probeEndpointCandidates(candidates, options = {}) {
|
|
7308
|
+
const resolvedOptions = {
|
|
7309
|
+
sampleCount: options.sampleCount ?? 3,
|
|
7310
|
+
timeoutMs: options.timeoutMs ?? 2500
|
|
7311
|
+
};
|
|
7312
|
+
return Promise.all(
|
|
7313
|
+
candidates.map((candidate, index) => probeCandidate(candidate, index, resolvedOptions))
|
|
7314
|
+
);
|
|
7315
|
+
}
|
|
7316
|
+
function sortEndpointProbeResults(results) {
|
|
7317
|
+
return [...results].sort((left, right) => {
|
|
7318
|
+
const leftReachable = left.latencyMs !== null;
|
|
7319
|
+
const rightReachable = right.latencyMs !== null;
|
|
7320
|
+
if (leftReachable && !rightReachable) return -1;
|
|
7321
|
+
if (!leftReachable && rightReachable) return 1;
|
|
7322
|
+
if (!leftReachable && !rightReachable) return left.originalIndex - right.originalIndex;
|
|
7323
|
+
if (left.latencyMs !== right.latencyMs) {
|
|
7324
|
+
return (left.latencyMs || 0) - (right.latencyMs || 0);
|
|
7325
|
+
}
|
|
7326
|
+
return left.originalIndex - right.originalIndex;
|
|
7327
|
+
});
|
|
7328
|
+
}
|
|
7329
|
+
function pickDefaultEndpoint(results) {
|
|
7330
|
+
return sortEndpointProbeResults(results)[0];
|
|
7331
|
+
}
|
|
7332
|
+
|
|
7333
|
+
// src/commands/gmn.ts
|
|
7154
7334
|
var DEFAULT_PROVIDER_NAME2 = "gmn";
|
|
7155
7335
|
var VALID_PLATFORMS = ["codex", "opencode", "openclaw"];
|
|
7156
7336
|
var DEFAULT_PLATFORMS = ["codex", "opencode"];
|
|
7337
|
+
var GMN_BASE_URLS = [
|
|
7338
|
+
{
|
|
7339
|
+
label: "\u539F\u59CB\u5730\u5740",
|
|
7340
|
+
url: "https://gmn.chuangzuoli.com",
|
|
7341
|
+
description: "GMN \u539F\u59CB\u5165\u53E3"
|
|
7342
|
+
},
|
|
7343
|
+
{
|
|
7344
|
+
label: "\u65E7\u57DF\u540D CDN",
|
|
7345
|
+
url: "https://cdn.gmnchuangzuoli.com",
|
|
7346
|
+
description: "CDN \u56DE\u56FD\u52A0\u901F"
|
|
7347
|
+
},
|
|
7348
|
+
{
|
|
7349
|
+
label: "\u963F\u91CC\u4E91 CDN",
|
|
7350
|
+
url: "https://gmncodex.com",
|
|
7351
|
+
description: "\u963F\u91CC\u4E91\u89E3\u6790 CDN \u56DE\u56FD\u52A0\u901F"
|
|
7352
|
+
},
|
|
7353
|
+
{
|
|
7354
|
+
label: "\u5168\u7403\u8FB9\u7F18 A",
|
|
7355
|
+
url: "https://gmncode.cn",
|
|
7356
|
+
description: "\u5168\u7403\u8FB9\u7F18\u8282\u70B9\u52A0\u901F"
|
|
7357
|
+
},
|
|
7358
|
+
{
|
|
7359
|
+
label: "CF CDN A",
|
|
7360
|
+
url: "https://cdn.gmncode.cn",
|
|
7361
|
+
description: "CF \u89E3\u6790 CDN \u56DE\u56FD\u52A0\u901F"
|
|
7362
|
+
},
|
|
7363
|
+
{
|
|
7364
|
+
label: "\u5168\u7403\u8FB9\u7F18 B",
|
|
7365
|
+
url: "https://gmn.codex.com",
|
|
7366
|
+
description: "\u5168\u7403\u8FB9\u7F18\u8282\u70B9\u52A0\u901F"
|
|
7367
|
+
},
|
|
7368
|
+
{
|
|
7369
|
+
label: "CF CDN B",
|
|
7370
|
+
url: "https://cdn.gmncode.com",
|
|
7371
|
+
description: "CF \u89E3\u6790 CDN \u56DE\u56FD\u52A0\u901F"
|
|
7372
|
+
}
|
|
7373
|
+
];
|
|
7157
7374
|
var GMN_PROFILE = {
|
|
7158
7375
|
commandName: "gmn",
|
|
7159
7376
|
title: "GMN",
|
|
7160
|
-
|
|
7377
|
+
baseUrls: GMN_BASE_URLS
|
|
7161
7378
|
};
|
|
7162
7379
|
var GMN1_PROFILE = {
|
|
7163
7380
|
commandName: "gmn1",
|
|
7164
7381
|
title: "GMN1",
|
|
7165
|
-
|
|
7382
|
+
baseUrls: [
|
|
7383
|
+
{
|
|
7384
|
+
label: "GMN1 \u9ED8\u8BA4\u7EBF\u8DEF",
|
|
7385
|
+
url: "https://gmncode.cn",
|
|
7386
|
+
description: "\u5168\u7403\u8FB9\u7F18\u8282\u70B9\u52A0\u901F"
|
|
7387
|
+
}
|
|
7388
|
+
]
|
|
7166
7389
|
};
|
|
7167
|
-
var TOTAL_STEPS =
|
|
7390
|
+
var TOTAL_STEPS = 4;
|
|
7391
|
+
var BASE_URL_PROBE_SAMPLE_COUNT = 3;
|
|
7392
|
+
var BASE_URL_PROBE_TIMEOUT_MS = 2500;
|
|
7168
7393
|
function renderStep(current, total, title) {
|
|
7169
7394
|
const barLength = total;
|
|
7170
7395
|
const filledLength = Math.min(current, total);
|
|
@@ -7280,6 +7505,78 @@ async function resolvePlatforms(platformArg, title = "GMN") {
|
|
|
7280
7505
|
}
|
|
7281
7506
|
return promptPlatforms(title);
|
|
7282
7507
|
}
|
|
7508
|
+
function formatLatency(result) {
|
|
7509
|
+
if (result.latencyMs === null) {
|
|
7510
|
+
return result.error || "\u6D4B\u901F\u5931\u8D25";
|
|
7511
|
+
}
|
|
7512
|
+
return `${result.latencyMs} ms`;
|
|
7513
|
+
}
|
|
7514
|
+
function buildProbeCandidates(baseUrls, platforms) {
|
|
7515
|
+
const openClawOnly = platforms.length === 1 && platforms[0] === "openclaw";
|
|
7516
|
+
return baseUrls.map((item) => ({
|
|
7517
|
+
...item,
|
|
7518
|
+
probeUrl: openClawOnly ? buildOpenClawBaseUrl(item.url) : item.url
|
|
7519
|
+
}));
|
|
7520
|
+
}
|
|
7521
|
+
function printBaseUrlProbeResults(results, platforms) {
|
|
7522
|
+
const usingOpenClawPath = platforms.length === 1 && platforms[0] === "openclaw";
|
|
7523
|
+
console.log(
|
|
7524
|
+
chalk54.gray(
|
|
7525
|
+
`\u6D4B\u901F\u65B9\u5F0F\uFF1AHTTPS \u9996\u5305\u5EF6\u8FDF\uFF08${BASE_URL_PROBE_SAMPLE_COUNT} \u6B21\u4E2D\u4F4D\u6570\uFF09${usingOpenClawPath ? "\uFF0C\u5F53\u524D\u4EC5\u68C0\u6D4B OpenClaw \u7684 /v1 \u7AEF\u70B9" : ""}`
|
|
7526
|
+
)
|
|
7527
|
+
);
|
|
7528
|
+
for (const result of results) {
|
|
7529
|
+
const latencyText = result.latencyMs === null ? chalk54.red(formatLatency(result)) : chalk54.green(formatLatency(result));
|
|
7530
|
+
console.log(` ${chalk54.cyan(result.label)} \xB7 ${latencyText}`);
|
|
7531
|
+
console.log(chalk54.gray(` ${result.url}`));
|
|
7532
|
+
console.log(chalk54.gray(` ${result.description}`));
|
|
7533
|
+
}
|
|
7534
|
+
}
|
|
7535
|
+
async function resolveOpenAiBaseUrl(profile, platforms, baseUrlArg) {
|
|
7536
|
+
if (baseUrlArg && baseUrlArg.trim().length > 0) {
|
|
7537
|
+
const normalized = normalizeEndpointUrl(baseUrlArg);
|
|
7538
|
+
console.log(chalk54.gray(`\u5DF2\u901A\u8FC7\u53C2\u6570\u6307\u5B9A Base URL: ${normalized}`));
|
|
7539
|
+
return normalized;
|
|
7540
|
+
}
|
|
7541
|
+
const probeResults = sortEndpointProbeResults(
|
|
7542
|
+
await probeEndpointCandidates(buildProbeCandidates(profile.baseUrls, platforms), {
|
|
7543
|
+
sampleCount: BASE_URL_PROBE_SAMPLE_COUNT,
|
|
7544
|
+
timeoutMs: BASE_URL_PROBE_TIMEOUT_MS
|
|
7545
|
+
})
|
|
7546
|
+
);
|
|
7547
|
+
if (probeResults.length === 0) {
|
|
7548
|
+
throw new Error("\u6CA1\u6709\u53EF\u7528\u7684 Base URL \u5019\u9009\u9879");
|
|
7549
|
+
}
|
|
7550
|
+
printBaseUrlProbeResults(probeResults, platforms);
|
|
7551
|
+
const defaultResult = pickDefaultEndpoint(probeResults) || probeResults[0];
|
|
7552
|
+
const allFailed = probeResults.every((result) => result.latencyMs === null);
|
|
7553
|
+
if (allFailed) {
|
|
7554
|
+
console.log(chalk54.yellow("\u26A0\uFE0F \u6240\u6709\u5019\u9009\u5730\u5740\u6D4B\u901F\u5931\u8D25\uFF0C\u5C06\u9ED8\u8BA4\u9009\u4E2D\u7B2C\u4E00\u4E2A\u5730\u5740\uFF0C\u4F60\u4E5F\u53EF\u4EE5\u624B\u52A8\u5207\u6362\u3002"));
|
|
7555
|
+
} else {
|
|
7556
|
+
console.log(chalk54.gray(`\u9ED8\u8BA4\u5DF2\u9009\u5EF6\u8FDF\u6700\u4F4E\u5730\u5740\uFF1A${defaultResult.url}`));
|
|
7557
|
+
}
|
|
7558
|
+
if (probeResults.length === 1) {
|
|
7559
|
+
console.log(chalk54.green(`\u5DF2\u81EA\u52A8\u9009\u62E9: ${defaultResult.url}`));
|
|
7560
|
+
return defaultResult.url;
|
|
7561
|
+
}
|
|
7562
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
7563
|
+
console.log(chalk54.yellow(`\u975E\u4EA4\u4E92\u73AF\u5883\uFF0C\u5DF2\u81EA\u52A8\u4F7F\u7528\u9ED8\u8BA4\u5730\u5740\uFF1A${defaultResult.url}`));
|
|
7564
|
+
return defaultResult.url;
|
|
7565
|
+
}
|
|
7566
|
+
const answers = await inquirer38.prompt([
|
|
7567
|
+
{
|
|
7568
|
+
type: "list",
|
|
7569
|
+
name: "baseUrl",
|
|
7570
|
+
message: "\u9009\u62E9\u8981\u4F7F\u7528\u7684 Base URL\uFF08\u9ED8\u8BA4\u5DF2\u9009\u5EF6\u8FDF\u6700\u4F4E\uFF09:",
|
|
7571
|
+
choices: probeResults.map((result) => ({
|
|
7572
|
+
name: `${result.label} \xB7 ${result.url} \xB7 ${formatLatency(result)} \xB7 ${result.description}`,
|
|
7573
|
+
value: result.url
|
|
7574
|
+
})),
|
|
7575
|
+
default: defaultResult.url
|
|
7576
|
+
}
|
|
7577
|
+
]);
|
|
7578
|
+
return answers.baseUrl;
|
|
7579
|
+
}
|
|
7283
7580
|
function resolveProviderName2(providerNameArg) {
|
|
7284
7581
|
if (providerNameArg === void 0) {
|
|
7285
7582
|
return DEFAULT_PROVIDER_NAME2;
|
|
@@ -7369,7 +7666,7 @@ function buildOpenClawBaseUrl(openaiBaseUrl) {
|
|
|
7369
7666
|
const normalized = openaiBaseUrl.replace(/\/+$/, "");
|
|
7370
7667
|
return `${normalized}/v1`;
|
|
7371
7668
|
}
|
|
7372
|
-
async function runGmnCommand(profile, apiKey, platformArg, providerNameArg) {
|
|
7669
|
+
async function runGmnCommand(profile, apiKey, platformArg, providerNameArg, baseUrlArg) {
|
|
7373
7670
|
printBanner(profile.title);
|
|
7374
7671
|
let platforms;
|
|
7375
7672
|
let providerName;
|
|
@@ -7385,9 +7682,24 @@ ${renderStep(1, TOTAL_STEPS, "\u9009\u62E9\u8981\u914D\u7F6E\u7684\u5DE5\u5177")
|
|
|
7385
7682
|
console.log(chalk54.gray(`\u5DF2\u9009\u62E9: ${platforms.join(", ")}`));
|
|
7386
7683
|
console.log(chalk54.gray(`\u670D\u52A1\u5546\u540D\u79F0: ${providerName}`));
|
|
7387
7684
|
printKeyNotice();
|
|
7685
|
+
console.log(chalk54.cyan(`
|
|
7686
|
+
${renderStep(2, TOTAL_STEPS, "\u6D4B\u901F\u5E76\u9009\u62E9 Base URL")}`));
|
|
7687
|
+
let openaiBaseUrl;
|
|
7688
|
+
try {
|
|
7689
|
+
openaiBaseUrl = await resolveOpenAiBaseUrl(profile, platforms, baseUrlArg);
|
|
7690
|
+
} catch (error) {
|
|
7691
|
+
console.error(chalk54.red(`\u274C ${error.message}`));
|
|
7692
|
+
process.exit(1);
|
|
7693
|
+
}
|
|
7694
|
+
const openclawBaseUrl = buildOpenClawBaseUrl(openaiBaseUrl);
|
|
7695
|
+
const platformBaseUrls = {
|
|
7696
|
+
codex: openaiBaseUrl,
|
|
7697
|
+
opencode: openaiBaseUrl,
|
|
7698
|
+
openclaw: openclawBaseUrl
|
|
7699
|
+
};
|
|
7388
7700
|
let resolvedApiKey = apiKey?.trim();
|
|
7389
7701
|
console.log(chalk54.cyan(`
|
|
7390
|
-
${renderStep(
|
|
7702
|
+
${renderStep(3, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
|
|
7391
7703
|
if (!resolvedApiKey) {
|
|
7392
7704
|
resolvedApiKey = await promptApiKey(profile.title);
|
|
7393
7705
|
} else {
|
|
@@ -7397,19 +7709,10 @@ ${renderStep(2, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
|
|
|
7397
7709
|
console.error(chalk54.red("\u274C \u9519\u8BEF: API Key \u4E0D\u80FD\u4E3A\u7A7A"));
|
|
7398
7710
|
process.exit(1);
|
|
7399
7711
|
}
|
|
7400
|
-
const openaiBaseUrl = profile.openaiBaseUrl;
|
|
7401
|
-
const openclawBaseUrl = buildOpenClawBaseUrl(openaiBaseUrl);
|
|
7402
|
-
const platformBaseUrls = {
|
|
7403
|
-
codex: openaiBaseUrl,
|
|
7404
|
-
opencode: openaiBaseUrl,
|
|
7405
|
-
openclaw: openclawBaseUrl
|
|
7406
|
-
};
|
|
7407
7712
|
console.log(chalk54.cyan(`
|
|
7408
|
-
${renderStep(
|
|
7713
|
+
${renderStep(4, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
|
|
7409
7714
|
console.log(chalk54.gray(`\u5DF2\u9009\u62E9\u5E73\u53F0: ${platforms.join(", ")}`));
|
|
7410
|
-
|
|
7411
|
-
console.log(chalk54.gray(`OpenAI Base URL: ${openaiBaseUrl}`));
|
|
7412
|
-
}
|
|
7715
|
+
console.log(chalk54.gray(`OpenAI Base URL: ${openaiBaseUrl}`));
|
|
7413
7716
|
if (platforms.includes("openclaw")) {
|
|
7414
7717
|
console.log(chalk54.gray(`OpenClaw Base URL: ${openclawBaseUrl}`));
|
|
7415
7718
|
}
|
|
@@ -7447,8 +7750,12 @@ ${renderStep(3, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
|
|
|
7447
7750
|
}
|
|
7448
7751
|
const baseUrl = platformBaseUrls[platform];
|
|
7449
7752
|
const existing = findPreferredProvider(manager.list(), providerName);
|
|
7450
|
-
const provider = existing ? manager.edit(
|
|
7451
|
-
|
|
7753
|
+
const provider = existing ? manager.edit(
|
|
7754
|
+
existing.id,
|
|
7755
|
+
{ name: providerName, baseUrl, apiKey: resolvedApiKey },
|
|
7756
|
+
{ applyWrite: false }
|
|
7757
|
+
) : manager.add({ name: providerName, baseUrl, apiKey: resolvedApiKey });
|
|
7758
|
+
manager.switch(provider.id, { mode: "overwrite" });
|
|
7452
7759
|
completed += 1;
|
|
7453
7760
|
console.log(chalk54.green(`\u2705 ${name}`));
|
|
7454
7761
|
successBackups.push({
|
|
@@ -7494,11 +7801,11 @@ ${renderStep(3, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
|
|
|
7494
7801
|
}
|
|
7495
7802
|
console.log(chalk54.gray("\u63D0\u793A\uFF1A\u8BF7\u91CD\u542F\u5BF9\u5E94\u5DE5\u5177/\u63D2\u4EF6\u4EE5\u4F7F\u914D\u7F6E\u751F\u6548\u3002"));
|
|
7496
7803
|
}
|
|
7497
|
-
async function gmnCommand(apiKey, platformArg, providerNameArg) {
|
|
7498
|
-
await runGmnCommand(GMN_PROFILE, apiKey, platformArg, providerNameArg);
|
|
7804
|
+
async function gmnCommand(apiKey, platformArg, providerNameArg, baseUrlArg) {
|
|
7805
|
+
await runGmnCommand(GMN_PROFILE, apiKey, platformArg, providerNameArg, baseUrlArg);
|
|
7499
7806
|
}
|
|
7500
|
-
async function gmn1Command(apiKey, platformArg, providerNameArg) {
|
|
7501
|
-
await runGmnCommand(GMN1_PROFILE, apiKey, platformArg, providerNameArg);
|
|
7807
|
+
async function gmn1Command(apiKey, platformArg, providerNameArg, baseUrlArg) {
|
|
7808
|
+
await runGmnCommand(GMN1_PROFILE, apiKey, platformArg, providerNameArg, baseUrlArg);
|
|
7502
7809
|
}
|
|
7503
7810
|
|
|
7504
7811
|
// src/index.ts
|
|
@@ -7536,7 +7843,8 @@ program.on("command:*", (operands) => {
|
|
|
7536
7843
|
"export",
|
|
7537
7844
|
"import",
|
|
7538
7845
|
"gmn",
|
|
7539
|
-
"gmn1"
|
|
7846
|
+
"gmn1",
|
|
7847
|
+
"gmncode"
|
|
7540
7848
|
];
|
|
7541
7849
|
const suggestions = availableCommands.filter(
|
|
7542
7850
|
(cmd) => cmd.includes(unknownCommand) || unknownCommand.includes(cmd)
|
|
@@ -7595,11 +7903,11 @@ sync.action(async () => {
|
|
|
7595
7903
|
});
|
|
7596
7904
|
exportCommand(program);
|
|
7597
7905
|
importCommand(program);
|
|
7598
|
-
program.command("gmn [apiKey]").description("\u914D\u7F6E GMN \u5230 Codex\u3001OpenCode\u3001OpenClaw").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (codex,opencode,openclaw,all)").option("-n, --name <providerName>", "\u6307\u5B9A\u670D\u52A1\u5546\u540D\u79F0\uFF08\u9ED8\u8BA4: gmn\uFF09").action(async (apiKey, options) => {
|
|
7599
|
-
await gmnCommand(apiKey, options.platform, options.name);
|
|
7906
|
+
program.command("gmn [apiKey]").description("\u914D\u7F6E GMN \u5230 Codex\u3001OpenCode\u3001OpenClaw\uFF08\u81EA\u52A8\u6D4B\u901F\u5E76\u9ED8\u8BA4\u9009\u62E9\u6700\u4F4E\u5EF6\u8FDF\u7EBF\u8DEF\uFF09").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (codex,opencode,openclaw,all)").option("-n, --name <providerName>", "\u6307\u5B9A\u670D\u52A1\u5546\u540D\u79F0\uFF08\u9ED8\u8BA4: gmn\uFF09").option("-b, --base-url <baseUrl>", "\u6307\u5B9A Base URL\uFF1B\u4E0D\u6307\u5B9A\u65F6\u81EA\u52A8\u6D4B\u901F\u5E76\u53EF\u624B\u52A8\u5207\u6362").action(async (apiKey, options) => {
|
|
7907
|
+
await gmnCommand(apiKey, options.platform, options.name, options.baseUrl);
|
|
7600
7908
|
});
|
|
7601
|
-
program.command("gmn1 [apiKey]").description("\u914D\u7F6E GMN1 \u5230 Codex\u3001OpenCode\u3001OpenClaw\uFF08\u9ED8\u8BA4 URL: https://gmncode.cn\uFF09").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (codex,opencode,openclaw,all)").option("-n, --name <providerName>", "\u6307\u5B9A\u670D\u52A1\u5546\u540D\u79F0\uFF08\u9ED8\u8BA4: gmn\uFF09").action(async (apiKey, options) => {
|
|
7602
|
-
await gmn1Command(apiKey, options.platform, options.name);
|
|
7909
|
+
program.command("gmn1 [apiKey]").alias("gmncode").description("\u914D\u7F6E GMN1 \u5230 Codex\u3001OpenCode\u3001OpenClaw\uFF08\u9ED8\u8BA4 URL: https://gmncode.cn\uFF09").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (codex,opencode,openclaw,all)").option("-n, --name <providerName>", "\u6307\u5B9A\u670D\u52A1\u5546\u540D\u79F0\uFF08\u9ED8\u8BA4: gmn\uFF09").option("-b, --base-url <baseUrl>", "\u6307\u5B9A Base URL\uFF1B\u4E0D\u6307\u5B9A\u65F6\u81EA\u52A8\u6D4B\u901F\u5E76\u53EF\u624B\u52A8\u5207\u6362").action(async (apiKey, options) => {
|
|
7910
|
+
await gmn1Command(apiKey, options.platform, options.name, options.baseUrl);
|
|
7603
7911
|
});
|
|
7604
7912
|
(async () => {
|
|
7605
7913
|
if (!process.argv.slice(2).length) {
|