trinity-config 1.1.0 → 1.2.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/README.md +10 -42
- package/dist/index.js +169 -59
- package/dist/merge-codex-config-GC7ZDP7R.js +107 -0
- package/dist/merge-openclaw-config-XV25MSSC.js +126 -0
- package/dist/merge-opencode-config-P4QJ63DF.js +107 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,56 +1,24 @@
|
|
|
1
1
|
# trinity-config
|
|
2
2
|
|
|
3
|
-
> 一键把 [Trinity API](https://trinitydesk.ai) 接入 **Claude Code**
|
|
3
|
+
> 一键把 [Trinity API](https://trinitydesk.ai) 接入 **Claude Code** / **Codex CLI** / **OpenCode** / **OpenClaw**
|
|
4
4
|
|
|
5
5
|
## 快速开始
|
|
6
6
|
|
|
7
|
-
### 交互式
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
|
-
npx -y trinity-config
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
按提示选择 **工具类型**、粘贴 Key、确认 **model_code**。
|
|
14
|
-
|
|
15
|
-
### 一行命令(推荐)
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# Claude Code
|
|
19
8
|
npx -y trinity-config --type claude -k xh-你的key
|
|
20
|
-
|
|
21
|
-
# Codex CLI
|
|
22
9
|
npx -y trinity-config --type codex -k xh-你的key --model gpt-5.4
|
|
10
|
+
npx -y trinity-config --type opencode -k xh-你的key --model gpt-5.4
|
|
11
|
+
npx -y trinity-config --type openclaw -k xh-你的key --model gpt-5.4
|
|
23
12
|
```
|
|
24
13
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
| `--type` | `-t` | **必填(非交互)**:`claude` \| `codex` |
|
|
32
|
-
| `--api-key` | `-k` | Trinity API Key |
|
|
33
|
-
| `--model` | `-M` | 默认 model_code(省略则按 type 内置推荐) |
|
|
34
|
-
| `--base-url` | | 默认 `https://api.trinitydesk.ai` |
|
|
35
|
-
| `--skip-verify` | | 跳过连通性验证 |
|
|
36
|
-
| `--verbose` | `-v` | 显示 zcf 详细输出 |
|
|
37
|
-
|
|
38
|
-
### 按 type 的默认模型
|
|
39
|
-
|
|
40
|
-
| `--type` | 默认 `--model` |
|
|
41
|
-
| --- | --- |
|
|
42
|
-
| `claude` | `claude-sonnet-4-6` |
|
|
43
|
-
| `codex` | `gpt-5.4` |
|
|
44
|
-
|
|
45
|
-
## 扩展新工具
|
|
46
|
-
|
|
47
|
-
后续增加 Cursor、OpenCode 等时,只需新增 `type` 枚举与对应写入逻辑,**不再**为每个工具增加 `--xxx-model` 参数。
|
|
48
|
-
|
|
49
|
-
## 注意
|
|
14
|
+
| `--type` | 默认模型 | 接口 | 写入 |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `claude` | `claude-sonnet-4-6` | `/v1/messages` | `~/.claude/settings.json` |
|
|
17
|
+
| `codex` | `gpt-5.4` | `/v1/responses` | `~/.codex/config.toml` + `auth.json` |
|
|
18
|
+
| `opencode` | `gpt-5.4` | `/v1/chat/completions` | `~/.config/opencode/opencode.json` |
|
|
19
|
+
| `openclaw` | `gpt-5.4` | `/v1/chat/completions` | `~/.openclaw/openclaw.json` |
|
|
50
20
|
|
|
51
|
-
|
|
52
|
-
- 非交互模式必须同时提供 `--type` 与 `-k`。
|
|
53
|
-
- Codex 侧 zcf 写入仍可能有已知限制,见设计文档。
|
|
21
|
+
OpenClaw 改完后请重启 Gateway(或重新 `openclaw dashboard`)。
|
|
54
22
|
|
|
55
23
|
## License
|
|
56
24
|
|
package/dist/index.js
CHANGED
|
@@ -5,52 +5,86 @@ import pc from "picocolors";
|
|
|
5
5
|
|
|
6
6
|
// src/constants.ts
|
|
7
7
|
var PACKAGE_NAME = "trinity-config";
|
|
8
|
-
var PACKAGE_VERSION = "1.1
|
|
8
|
+
var PACKAGE_VERSION = "1.2.1";
|
|
9
9
|
var TRINITY_BASE_URL = "https://api.trinitydesk.ai";
|
|
10
10
|
var DEFAULT_CLAUDE_MODEL = "claude-sonnet-4-6";
|
|
11
11
|
var DEFAULT_CLAUDE_FAST_MODEL = "claude-sonnet-4-6";
|
|
12
12
|
var DEFAULT_CODEX_MODEL = "gpt-5.4";
|
|
13
|
+
var DEFAULT_OPENCODE_MODEL = "gpt-5.4";
|
|
14
|
+
var DEFAULT_OPENCLAW_MODEL = "gpt-5.4";
|
|
13
15
|
var VERIFY_TIMEOUT_MS = 15e3;
|
|
14
16
|
|
|
15
17
|
// src/model.ts
|
|
16
18
|
function defaultModelForType(type) {
|
|
17
|
-
|
|
19
|
+
switch (type) {
|
|
20
|
+
case "claude":
|
|
21
|
+
return DEFAULT_CLAUDE_MODEL;
|
|
22
|
+
case "codex":
|
|
23
|
+
return DEFAULT_CODEX_MODEL;
|
|
24
|
+
case "opencode":
|
|
25
|
+
return DEFAULT_OPENCODE_MODEL;
|
|
26
|
+
case "openclaw":
|
|
27
|
+
return DEFAULT_OPENCLAW_MODEL;
|
|
28
|
+
}
|
|
18
29
|
}
|
|
19
30
|
function resolveModel(type, model) {
|
|
20
31
|
return model?.trim() || defaultModelForType(type);
|
|
21
32
|
}
|
|
22
33
|
function parseToolType(raw) {
|
|
23
34
|
const value = raw.trim().toLowerCase();
|
|
24
|
-
if (value === "claude" || value === "codex") {
|
|
35
|
+
if (value === "claude" || value === "codex" || value === "opencode" || value === "openclaw") {
|
|
25
36
|
return value;
|
|
26
37
|
}
|
|
27
|
-
throw new Error("--type \u987B\u4E3A claude \u6216
|
|
38
|
+
throw new Error("--type \u987B\u4E3A claude\u3001codex\u3001opencode \u6216 openclaw");
|
|
28
39
|
}
|
|
29
40
|
function toolLabel(type) {
|
|
30
|
-
|
|
41
|
+
switch (type) {
|
|
42
|
+
case "claude":
|
|
43
|
+
return "Claude Code";
|
|
44
|
+
case "codex":
|
|
45
|
+
return "Codex CLI";
|
|
46
|
+
case "opencode":
|
|
47
|
+
return "OpenCode";
|
|
48
|
+
case "openclaw":
|
|
49
|
+
return "OpenClaw";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function launchCommand(type) {
|
|
53
|
+
switch (type) {
|
|
54
|
+
case "claude":
|
|
55
|
+
return "claude";
|
|
56
|
+
case "codex":
|
|
57
|
+
return "codex";
|
|
58
|
+
case "opencode":
|
|
59
|
+
return "opencode";
|
|
60
|
+
case "openclaw":
|
|
61
|
+
return "openclaw dashboard";
|
|
62
|
+
}
|
|
31
63
|
}
|
|
32
64
|
|
|
33
65
|
// src/args.ts
|
|
34
66
|
function printHelp() {
|
|
35
67
|
console.log(`
|
|
36
|
-
trinity-config \u2014 \u4E00\u952E\u628A Trinity API \u63A5\u5165\u7EC8\u7AEF\u7F16\u7A0B\u52A9\u624B
|
|
68
|
+
trinity-config \u2014 \u4E00\u952E\u628A Trinity API \u63A5\u5165\u7EC8\u7AEF\u7F16\u7A0B\u52A9\u624B / Agent \u7F51\u5173
|
|
37
69
|
|
|
38
70
|
\u7528\u6CD5:
|
|
39
|
-
npx -y trinity-config --type <claude|codex> [\u9009\u9879]
|
|
71
|
+
npx -y trinity-config --type <claude|codex|opencode|openclaw> [\u9009\u9879]
|
|
40
72
|
|
|
41
73
|
\u9009\u9879:
|
|
42
|
-
-t, --type <claude|codex> \u8981\u914D\u7F6E\u7684\u5DE5\u5177\uFF08\u975E\u4EA4\u4E92\u987B\u6307\u5B9A\
|
|
43
|
-
-k, --api-key <key>
|
|
44
|
-
-M, --model <model_code>
|
|
45
|
-
--base-url <url>
|
|
46
|
-
--skip-verify
|
|
47
|
-
-v, --verbose
|
|
48
|
-
-h, --help
|
|
49
|
-
-V, --version
|
|
74
|
+
-t, --type <claude|codex|opencode|openclaw> \u8981\u914D\u7F6E\u7684\u5DE5\u5177\uFF08\u975E\u4EA4\u4E92\u987B\u6307\u5B9A\uFF09
|
|
75
|
+
-k, --api-key <key> Trinity API Key\uFF08xh- \u524D\u7F00\uFF09
|
|
76
|
+
-M, --model <model_code> \u9ED8\u8BA4\u6A21\u578B\uFF08\u7701\u7565\u5219\u6309 type \u63A8\u8350\uFF09
|
|
77
|
+
--base-url <url> API \u6839\u5730\u5740\uFF08\u9ED8\u8BA4 https://api.trinitydesk.ai\uFF09
|
|
78
|
+
--skip-verify \u8DF3\u8FC7 GET /v1/models \u8FDE\u901A\u6027\u68C0\u67E5
|
|
79
|
+
-v, --verbose \u663E\u793A zcf \u8BE6\u7EC6\u8F93\u51FA\uFF08\u4EC5 Claude\uFF09
|
|
80
|
+
-h, --help \u663E\u793A\u5E2E\u52A9
|
|
81
|
+
-V, --version \u663E\u793A\u7248\u672C
|
|
50
82
|
|
|
51
83
|
\u793A\u4F8B:
|
|
52
84
|
npx -y trinity-config --type claude -k xh-your-key
|
|
53
85
|
npx -y trinity-config --type codex -k xh-your-key --model gpt-5.4
|
|
86
|
+
npx -y trinity-config --type opencode -k xh-your-key --model gpt-5.4
|
|
87
|
+
npx -y trinity-config --type openclaw -k xh-your-key --model gpt-5.4
|
|
54
88
|
npx -y trinity-config
|
|
55
89
|
`);
|
|
56
90
|
}
|
|
@@ -98,7 +132,7 @@ function parseArgs(argv) {
|
|
|
98
132
|
break;
|
|
99
133
|
case "--only": {
|
|
100
134
|
const legacy = args.shift();
|
|
101
|
-
console.warn("\u8B66\u544A: --only \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u6539\u7528 --type
|
|
135
|
+
console.warn("\u8B66\u544A: --only \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u6539\u7528 --type");
|
|
102
136
|
opts.type = parseToolType(String(legacy ?? ""));
|
|
103
137
|
break;
|
|
104
138
|
}
|
|
@@ -129,7 +163,7 @@ function normalizeApiKey(raw) {
|
|
|
129
163
|
function requireType(type, hasApiKeyFlag) {
|
|
130
164
|
if (type) return type;
|
|
131
165
|
if (!hasApiKeyFlag) return void 0;
|
|
132
|
-
throw new Error("\u975E\u4EA4\u4E92\u6A21\u5F0F\u987B\u6307\u5B9A --type claude \u6216
|
|
166
|
+
throw new Error("\u975E\u4EA4\u4E92\u6A21\u5F0F\u987B\u6307\u5B9A --type claude\u3001codex\u3001opencode \u6216 openclaw");
|
|
133
167
|
}
|
|
134
168
|
|
|
135
169
|
// src/merge-claude-env.ts
|
|
@@ -218,14 +252,9 @@ async function configureClaude(apiKey, baseUrl, claudeModel, verbose) {
|
|
|
218
252
|
verbose
|
|
219
253
|
});
|
|
220
254
|
}
|
|
221
|
-
async function configureCodex(apiKey, codexBaseUrl, codexModel,
|
|
222
|
-
await
|
|
223
|
-
|
|
224
|
-
apiKey,
|
|
225
|
-
baseUrl: codexBaseUrl,
|
|
226
|
-
primaryModel: codexModel,
|
|
227
|
-
verbose
|
|
228
|
-
});
|
|
255
|
+
async function configureCodex(apiKey, codexBaseUrl, codexModel, _verbose) {
|
|
256
|
+
const { configureCodexDirect } = await import("./merge-codex-config-GC7ZDP7R.js");
|
|
257
|
+
return configureCodexDirect(apiKey, codexBaseUrl, codexModel);
|
|
229
258
|
}
|
|
230
259
|
function resolveBaseUrls(baseUrl) {
|
|
231
260
|
const root = (baseUrl ?? TRINITY_BASE_URL).replace(/\/+$/, "");
|
|
@@ -237,6 +266,24 @@ function baseUrlForType(type, baseUrl) {
|
|
|
237
266
|
const { claudeBaseUrl, codexBaseUrl } = resolveBaseUrls(baseUrl);
|
|
238
267
|
return type === "claude" ? claudeBaseUrl : codexBaseUrl;
|
|
239
268
|
}
|
|
269
|
+
async function configureOpenCode(apiKey, openCodeBaseUrl, model, modelIds) {
|
|
270
|
+
const { configureOpenCodeDirect } = await import("./merge-opencode-config-P4QJ63DF.js");
|
|
271
|
+
return configureOpenCodeDirect({
|
|
272
|
+
apiKey,
|
|
273
|
+
baseUrl: openCodeBaseUrl,
|
|
274
|
+
model,
|
|
275
|
+
modelIds
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
async function configureOpenClaw(apiKey, openClawBaseUrl, model, modelIds) {
|
|
279
|
+
const { configureOpenClawDirect } = await import("./merge-openclaw-config-XV25MSSC.js");
|
|
280
|
+
return configureOpenClawDirect({
|
|
281
|
+
apiKey,
|
|
282
|
+
baseUrl: openClawBaseUrl,
|
|
283
|
+
model,
|
|
284
|
+
modelIds
|
|
285
|
+
});
|
|
286
|
+
}
|
|
240
287
|
|
|
241
288
|
// src/verify.ts
|
|
242
289
|
import https from "https";
|
|
@@ -332,7 +379,9 @@ async function verifyTrinityApi(apiKey, baseUrl = TRINITY_BASE_URL) {
|
|
|
332
379
|
function pickRecommendedModels(modelIds) {
|
|
333
380
|
const claude = modelIds.find((id) => id === DEFAULT_CLAUDE_MODEL) ?? modelIds.find((id) => id.includes("claude-sonnet")) ?? modelIds.find((id) => id.toLowerCase().includes("claude"));
|
|
334
381
|
const codex = modelIds.find((id) => id === DEFAULT_CODEX_MODEL) ?? modelIds.find((id) => id === "gpt-5.4") ?? modelIds.find((id) => id.startsWith("gpt-5")) ?? modelIds.find((id) => id.toLowerCase().includes("gpt"));
|
|
335
|
-
|
|
382
|
+
const opencode = modelIds.find((id) => id === DEFAULT_OPENCODE_MODEL) ?? codex ?? modelIds.find((id) => id.toLowerCase().includes("qwen"));
|
|
383
|
+
const openclaw = modelIds.find((id) => id === DEFAULT_OPENCLAW_MODEL) ?? opencode ?? codex;
|
|
384
|
+
return { claude, codex, opencode, openclaw };
|
|
336
385
|
}
|
|
337
386
|
|
|
338
387
|
// src/index.ts
|
|
@@ -361,7 +410,9 @@ async function promptToolType(initial) {
|
|
|
361
410
|
message: "\u8981\u914D\u7F6E\u54EA\u4E2A\u5DE5\u5177\uFF1F",
|
|
362
411
|
options: [
|
|
363
412
|
{ value: "claude", label: "Claude Code\uFF08/v1/messages\uFF09" },
|
|
364
|
-
{ value: "codex", label: "Codex CLI\uFF08/v1/responses\uFF09" }
|
|
413
|
+
{ value: "codex", label: "Codex CLI\uFF08/v1/responses\uFF09" },
|
|
414
|
+
{ value: "opencode", label: "OpenCode\uFF08/v1/chat/completions\uFF09" },
|
|
415
|
+
{ value: "openclaw", label: "OpenClaw\uFF08/v1/chat/completions\uFF09" }
|
|
365
416
|
]
|
|
366
417
|
});
|
|
367
418
|
if (p.isCancel(value)) {
|
|
@@ -389,6 +440,18 @@ async function promptModel(type, initial) {
|
|
|
389
440
|
}
|
|
390
441
|
return String(value).trim();
|
|
391
442
|
}
|
|
443
|
+
function recommendedHint(toolType, recommended) {
|
|
444
|
+
switch (toolType) {
|
|
445
|
+
case "claude":
|
|
446
|
+
return recommended.claude;
|
|
447
|
+
case "codex":
|
|
448
|
+
return recommended.codex;
|
|
449
|
+
case "opencode":
|
|
450
|
+
return recommended.opencode;
|
|
451
|
+
case "openclaw":
|
|
452
|
+
return recommended.openclaw;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
392
455
|
async function run() {
|
|
393
456
|
let opts;
|
|
394
457
|
try {
|
|
@@ -413,6 +476,26 @@ async function run() {
|
|
|
413
476
|
const { claudeBaseUrl } = resolveBaseUrls(opts.baseUrl);
|
|
414
477
|
p.log.info(`\u5DE5\u5177: ${toolLabel(toolType)} \xB7 \u6A21\u578B: ${model}`);
|
|
415
478
|
const spinner2 = p.spinner();
|
|
479
|
+
let verifiedModelIds;
|
|
480
|
+
if (!opts.skipVerify) {
|
|
481
|
+
spinner2.start("\u9A8C\u8BC1 Trinity API \u8FDE\u901A\u6027\u2026");
|
|
482
|
+
const result = await verifyTrinityApi(apiKey, claudeBaseUrl);
|
|
483
|
+
if (result.ok) {
|
|
484
|
+
spinner2.stop(pc.green(result.message));
|
|
485
|
+
verifiedModelIds = result.modelIds;
|
|
486
|
+
const recommended = pickRecommendedModels(result.modelIds ?? []);
|
|
487
|
+
const hint = recommendedHint(toolType, recommended);
|
|
488
|
+
if (hint && hint !== model) {
|
|
489
|
+
p.note(`\u540C\u7C7B\u578B\u63A8\u8350\u6A21\u578B: ${hint}`, "\u6A21\u578B");
|
|
490
|
+
}
|
|
491
|
+
} else {
|
|
492
|
+
spinner2.stop(pc.yellow(result.message));
|
|
493
|
+
p.note(
|
|
494
|
+
"\u8FDE\u901A\u6027\u68C0\u67E5\u672A\u901A\u8FC7\uFF1B\u4ECD\u5C06\u5C1D\u8BD5\u5199\u5165\u672C\u5730\u914D\u7F6E\u3002\u8BF7\u68C0\u67E5 API Key\u3001\u7F51\u7EDC\uFF0C\u6216\u5728\u63A7\u5236\u53F0\u786E\u8BA4 Key \u6709\u6548\u3002",
|
|
495
|
+
"\u63D0\u793A"
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
416
499
|
if (toolType === "claude") {
|
|
417
500
|
spinner2.start("\u914D\u7F6E Claude Code\u2026");
|
|
418
501
|
try {
|
|
@@ -421,53 +504,80 @@ async function run() {
|
|
|
421
504
|
spinner2.stop("Claude Code \u914D\u7F6E\u5DF2\u5199\u5165 ~/.claude/settings.json");
|
|
422
505
|
} catch (error) {
|
|
423
506
|
spinner2.stop(pc.red("Claude Code \u914D\u7F6E\u5931\u8D25"));
|
|
424
|
-
console.error(
|
|
507
|
+
console.error(formatConfigError(error));
|
|
425
508
|
return 1;
|
|
426
509
|
}
|
|
427
|
-
} else {
|
|
510
|
+
} else if (toolType === "codex") {
|
|
428
511
|
spinner2.start("\u914D\u7F6E Codex CLI\u2026");
|
|
429
512
|
try {
|
|
430
|
-
await configureCodex(apiKey, apiBaseUrl, model, opts.verbose);
|
|
431
|
-
|
|
513
|
+
const backupDir = await configureCodex(apiKey, apiBaseUrl, model, opts.verbose);
|
|
514
|
+
const backupHint = backupDir ? `
|
|
515
|
+
\u5907\u4EFD: ${backupDir}` : "";
|
|
516
|
+
spinner2.stop(`Codex \u914D\u7F6E\u5DF2\u5199\u5165 ~/.codex/config.toml \u4E0E auth.json${backupHint}`);
|
|
432
517
|
} catch (error) {
|
|
433
518
|
spinner2.stop(pc.red("Codex \u914D\u7F6E\u5931\u8D25"));
|
|
434
|
-
console.error(
|
|
519
|
+
console.error(formatConfigError(error));
|
|
435
520
|
return 1;
|
|
436
521
|
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
p.note(
|
|
451
|
-
"\u672C\u5730\u914D\u7F6E\u5DF2\u5199\u5165\uFF0C\u4F46\u8FDE\u901A\u6027\u68C0\u67E5\u672A\u901A\u8FC7\u3002\u8BF7\u68C0\u67E5 API Key\u3001\u7F51\u7EDC\uFF0C\u6216\u5728\u63A7\u5236\u53F0\u786E\u8BA4 Key \u6709\u6548\u3002",
|
|
452
|
-
"\u63D0\u793A"
|
|
522
|
+
} else if (toolType === "opencode") {
|
|
523
|
+
spinner2.start("\u914D\u7F6E OpenCode\u2026");
|
|
524
|
+
try {
|
|
525
|
+
const backupDir = await configureOpenCode(
|
|
526
|
+
apiKey,
|
|
527
|
+
apiBaseUrl,
|
|
528
|
+
model,
|
|
529
|
+
verifiedModelIds
|
|
530
|
+
);
|
|
531
|
+
const backupHint = backupDir ? `
|
|
532
|
+
\u5907\u4EFD: ${backupDir}` : "";
|
|
533
|
+
spinner2.stop(
|
|
534
|
+
`OpenCode \u914D\u7F6E\u5DF2\u5199\u5165 ~/.config/opencode/opencode.json${backupHint}`
|
|
453
535
|
);
|
|
454
|
-
|
|
536
|
+
} catch (error) {
|
|
537
|
+
spinner2.stop(pc.red("OpenCode \u914D\u7F6E\u5931\u8D25"));
|
|
538
|
+
console.error(formatConfigError(error));
|
|
455
539
|
return 1;
|
|
456
540
|
}
|
|
541
|
+
} else {
|
|
542
|
+
spinner2.start("\u914D\u7F6E OpenClaw\u2026");
|
|
543
|
+
try {
|
|
544
|
+
const backupDir = await configureOpenClaw(
|
|
545
|
+
apiKey,
|
|
546
|
+
apiBaseUrl,
|
|
547
|
+
model,
|
|
548
|
+
verifiedModelIds
|
|
549
|
+
);
|
|
550
|
+
const backupHint = backupDir ? `
|
|
551
|
+
\u5907\u4EFD: ${backupDir}` : "";
|
|
552
|
+
spinner2.stop(
|
|
553
|
+
`OpenClaw \u914D\u7F6E\u5DF2\u5199\u5165 ~/.openclaw/openclaw.json${backupHint}`
|
|
554
|
+
);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
spinner2.stop(pc.red("OpenClaw \u914D\u7F6E\u5931\u8D25"));
|
|
557
|
+
console.error(formatConfigError(error));
|
|
558
|
+
return 1;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (!opts.skipVerify && verifiedModelIds === void 0) {
|
|
562
|
+
p.outro(pc.yellow("\u914D\u7F6E\u5B8C\u6210\uFF08\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF09"));
|
|
563
|
+
return 1;
|
|
564
|
+
}
|
|
565
|
+
const nextSteps = [
|
|
566
|
+
`\u8FD0\u884C ${launchCommand(toolType)} \u542F\u52A8 ${toolLabel(toolType)}`
|
|
567
|
+
];
|
|
568
|
+
if (toolType === "opencode") {
|
|
569
|
+
nextSteps.push("\u5728 OpenCode \u5185\u7528 /models \u9009\u62E9 trinity/<model_code>");
|
|
570
|
+
} else if (toolType === "openclaw") {
|
|
571
|
+
nextSteps.push("\u9ED8\u8BA4\u6A21\u578B\u4E3A trinity/<model_code>\uFF1B\u6539\u5B8C\u914D\u7F6E\u540E\u8BF7\u91CD\u542F Gateway");
|
|
572
|
+
} else {
|
|
573
|
+
nextSteps.push("\u5728\u5DE5\u5177\u5185\u7528 /model \u5207\u6362\u4E3A Trinity \u5DF2\u4E0A\u67B6\u7684 model_code");
|
|
457
574
|
}
|
|
458
|
-
|
|
459
|
-
p.note(
|
|
460
|
-
[
|
|
461
|
-
`\u8FD0\u884C ${launchCmd} \u542F\u52A8 ${toolLabel(toolType)}`,
|
|
462
|
-
"\u5728\u5DE5\u5177\u5185\u7528 /model \u5207\u6362\u4E3A Trinity \u5DF2\u4E0A\u67B6\u7684 model_code",
|
|
463
|
-
"\u914D\u7F6E\u540E\u8BF7\u6C42\u8D70 Trinity \u8BA1\u8D39\uFF0C\u4E0D\u518D\u4F7F\u7528 Anthropic/OpenAI \u5B98\u65B9\u989D\u5EA6"
|
|
464
|
-
].join("\n"),
|
|
465
|
-
"\u4E0B\u4E00\u6B65"
|
|
466
|
-
);
|
|
575
|
+
nextSteps.push("\u914D\u7F6E\u540E\u8BF7\u6C42\u8D70 Trinity \u8BA1\u8D39\uFF0C\u4E0D\u518D\u4F7F\u7528\u5B98\u65B9\u989D\u5EA6");
|
|
576
|
+
p.note(nextSteps.join("\n"), "\u4E0B\u4E00\u6B65");
|
|
467
577
|
p.outro(pc.green("\u5B8C\u6210"));
|
|
468
578
|
return 0;
|
|
469
579
|
}
|
|
470
|
-
function
|
|
580
|
+
function formatConfigError(error) {
|
|
471
581
|
if (error instanceof Error && "timed out" in error) {
|
|
472
582
|
return "zcf \u6267\u884C\u8D85\u65F6\uFF08>3 \u5206\u949F\uFF09\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u7A0D\u540E\u91CD\u8BD5\u3002";
|
|
473
583
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/merge-codex-config.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { parse, stringify } from "smol-toml";
|
|
6
|
+
var TRINITY_CODEX_PROVIDER = "trinity";
|
|
7
|
+
var TRINITY_CODEX_TEMP_ENV_KEY = "TRINITY_API_KEY";
|
|
8
|
+
function codexHome() {
|
|
9
|
+
return process.env.CODEX_HOME?.trim() || path.join(os.homedir(), ".codex");
|
|
10
|
+
}
|
|
11
|
+
function codexConfigPath() {
|
|
12
|
+
return path.join(codexHome(), "config.toml");
|
|
13
|
+
}
|
|
14
|
+
function codexAuthPath() {
|
|
15
|
+
return path.join(codexHome(), "auth.json");
|
|
16
|
+
}
|
|
17
|
+
function timestampLabel() {
|
|
18
|
+
const now = /* @__PURE__ */ new Date();
|
|
19
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
20
|
+
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
21
|
+
}
|
|
22
|
+
function backupCodexFiles() {
|
|
23
|
+
const home = codexHome();
|
|
24
|
+
const configPath = codexConfigPath();
|
|
25
|
+
const authPath = codexAuthPath();
|
|
26
|
+
if (!fs.existsSync(configPath) && !fs.existsSync(authPath)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const backupDir = path.join(home, "backup", `trinity-config-${timestampLabel()}`);
|
|
30
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
31
|
+
for (const src of [configPath, authPath]) {
|
|
32
|
+
if (fs.existsSync(src)) {
|
|
33
|
+
fs.copyFileSync(src, path.join(backupDir, path.basename(src)));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return backupDir;
|
|
37
|
+
}
|
|
38
|
+
function readCodexConfigDoc() {
|
|
39
|
+
const configPath = codexConfigPath();
|
|
40
|
+
if (!fs.existsSync(configPath)) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
44
|
+
if (!raw.trim()) {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return parse(raw);
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 ${configPath}\uFF0C\u8BF7\u68C0\u67E5 TOML \u8BED\u6CD5\u540E\u91CD\u8BD5\u3002`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function buildTrinityProvider(baseUrl) {
|
|
54
|
+
return {
|
|
55
|
+
name: "Trinity API",
|
|
56
|
+
base_url: baseUrl.replace(/\/+$/, ""),
|
|
57
|
+
wire_api: "responses",
|
|
58
|
+
temp_env_key: TRINITY_CODEX_TEMP_ENV_KEY,
|
|
59
|
+
requires_openai_auth: false
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function mergeCodexConfig(model, baseUrl) {
|
|
63
|
+
const configPath = codexConfigPath();
|
|
64
|
+
const doc = readCodexConfigDoc();
|
|
65
|
+
doc.model = model;
|
|
66
|
+
doc.model_provider = TRINITY_CODEX_PROVIDER;
|
|
67
|
+
doc.disable_response_storage = true;
|
|
68
|
+
const providers = doc.model_providers && typeof doc.model_providers === "object" ? { ...doc.model_providers } : {};
|
|
69
|
+
providers[TRINITY_CODEX_PROVIDER] = buildTrinityProvider(baseUrl);
|
|
70
|
+
doc.model_providers = providers;
|
|
71
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
72
|
+
fs.writeFileSync(configPath, `${stringify(doc)}
|
|
73
|
+
`, "utf8");
|
|
74
|
+
}
|
|
75
|
+
function mergeCodexAuth(apiKey) {
|
|
76
|
+
const authPath = codexAuthPath();
|
|
77
|
+
let auth = {};
|
|
78
|
+
if (fs.existsSync(authPath)) {
|
|
79
|
+
try {
|
|
80
|
+
auth = JSON.parse(fs.readFileSync(authPath, "utf8"));
|
|
81
|
+
} catch {
|
|
82
|
+
auth = {};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
auth[TRINITY_CODEX_TEMP_ENV_KEY] = apiKey;
|
|
86
|
+
auth.OPENAI_API_KEY = apiKey;
|
|
87
|
+
fs.mkdirSync(path.dirname(authPath), { recursive: true });
|
|
88
|
+
fs.writeFileSync(authPath, `${JSON.stringify(auth, null, 2)}
|
|
89
|
+
`, "utf8");
|
|
90
|
+
}
|
|
91
|
+
function configureCodexDirect(apiKey, codexBaseUrl, model) {
|
|
92
|
+
const backupDir = backupCodexFiles();
|
|
93
|
+
mergeCodexConfig(model, codexBaseUrl);
|
|
94
|
+
mergeCodexAuth(apiKey);
|
|
95
|
+
return backupDir;
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
TRINITY_CODEX_PROVIDER,
|
|
99
|
+
TRINITY_CODEX_TEMP_ENV_KEY,
|
|
100
|
+
backupCodexFiles,
|
|
101
|
+
codexAuthPath,
|
|
102
|
+
codexConfigPath,
|
|
103
|
+
codexHome,
|
|
104
|
+
configureCodexDirect,
|
|
105
|
+
mergeCodexAuth,
|
|
106
|
+
mergeCodexConfig
|
|
107
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// src/merge-openclaw-config.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
var TRINITY_OPENCLAW_PROVIDER = "trinity";
|
|
6
|
+
function openclawHome() {
|
|
7
|
+
if (process.env.OPENCLAW_HOME?.trim()) {
|
|
8
|
+
return process.env.OPENCLAW_HOME.trim();
|
|
9
|
+
}
|
|
10
|
+
return path.join(os.homedir(), ".openclaw");
|
|
11
|
+
}
|
|
12
|
+
function openclawConfigPath() {
|
|
13
|
+
if (process.env.OPENCLAW_CONFIG?.trim()) {
|
|
14
|
+
return process.env.OPENCLAW_CONFIG.trim();
|
|
15
|
+
}
|
|
16
|
+
return path.join(openclawHome(), "openclaw.json");
|
|
17
|
+
}
|
|
18
|
+
function timestampLabel() {
|
|
19
|
+
const now = /* @__PURE__ */ new Date();
|
|
20
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
21
|
+
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
22
|
+
}
|
|
23
|
+
function backupOpenClawConfig() {
|
|
24
|
+
const configPath = openclawConfigPath();
|
|
25
|
+
if (!fs.existsSync(configPath)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const backupDir = path.join(openclawHome(), "backup", `trinity-config-${timestampLabel()}`);
|
|
29
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
30
|
+
fs.copyFileSync(configPath, path.join(backupDir, path.basename(configPath)));
|
|
31
|
+
return backupDir;
|
|
32
|
+
}
|
|
33
|
+
function readOpenClawConfig() {
|
|
34
|
+
const configPath = openclawConfigPath();
|
|
35
|
+
if (!fs.existsSync(configPath)) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
39
|
+
if (!raw.trim()) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
} catch {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`\u65E0\u6CD5\u89E3\u6790 ${configPath}\u3002\u82E5\u6587\u4EF6\u4E3A JSON5\uFF0C\u8BF7\u5148\u6539\u4E3A\u6807\u51C6 JSON\uFF0C\u6216\u5907\u4EFD\u540E\u5220\u9664\u518D\u91CD\u8DD1\u3002`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isLikelyNonTextModel(id) {
|
|
51
|
+
const lower = id.toLowerCase();
|
|
52
|
+
return lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling");
|
|
53
|
+
}
|
|
54
|
+
function buildModelEntries(primaryModel, modelIds) {
|
|
55
|
+
const ids = [primaryModel];
|
|
56
|
+
const seen = new Set(ids);
|
|
57
|
+
for (const id of modelIds ?? []) {
|
|
58
|
+
const trimmed = id?.trim();
|
|
59
|
+
if (!trimmed || seen.has(trimmed) || isLikelyNonTextModel(trimmed)) continue;
|
|
60
|
+
seen.add(trimmed);
|
|
61
|
+
ids.push(trimmed);
|
|
62
|
+
if (ids.length >= 80) break;
|
|
63
|
+
}
|
|
64
|
+
return ids.map((id) => ({
|
|
65
|
+
id,
|
|
66
|
+
name: id,
|
|
67
|
+
reasoning: false,
|
|
68
|
+
input: ["text"],
|
|
69
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
70
|
+
contextWindow: 128e3,
|
|
71
|
+
maxTokens: 8192
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
function mergeOpenClawConfig(options) {
|
|
75
|
+
const configPath = openclawConfigPath();
|
|
76
|
+
const doc = readOpenClawConfig();
|
|
77
|
+
const modelsBlock = doc.models && typeof doc.models === "object" ? { ...doc.models } : {};
|
|
78
|
+
modelsBlock.mode = modelsBlock.mode ?? "merge";
|
|
79
|
+
const providers = modelsBlock.providers && typeof modelsBlock.providers === "object" ? { ...modelsBlock.providers } : {};
|
|
80
|
+
const existing = providers[TRINITY_OPENCLAW_PROVIDER] ?? {};
|
|
81
|
+
const existingModels = Array.isArray(existing.models) ? existing.models : [];
|
|
82
|
+
const byId = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const m of existingModels) {
|
|
84
|
+
if (m && typeof m === "object" && typeof m.id === "string") {
|
|
85
|
+
byId.set(m.id, m);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const m of buildModelEntries(options.model, options.modelIds)) {
|
|
89
|
+
byId.set(m.id, { ...byId.get(m.id), ...m });
|
|
90
|
+
}
|
|
91
|
+
providers[TRINITY_OPENCLAW_PROVIDER] = {
|
|
92
|
+
...existing,
|
|
93
|
+
baseUrl: options.baseUrl.replace(/\/+$/, ""),
|
|
94
|
+
apiKey: options.apiKey,
|
|
95
|
+
api: "openai-completions",
|
|
96
|
+
models: [...byId.values()]
|
|
97
|
+
};
|
|
98
|
+
modelsBlock.providers = providers;
|
|
99
|
+
doc.models = modelsBlock;
|
|
100
|
+
const agents = doc.agents && typeof doc.agents === "object" ? { ...doc.agents } : {};
|
|
101
|
+
const defaults = agents.defaults && typeof agents.defaults === "object" ? { ...agents.defaults } : {};
|
|
102
|
+
const modelCfg = defaults.model && typeof defaults.model === "object" ? { ...defaults.model } : {};
|
|
103
|
+
modelCfg.primary = `${TRINITY_OPENCLAW_PROVIDER}/${options.model}`;
|
|
104
|
+
defaults.model = modelCfg;
|
|
105
|
+
const allow = defaults.models && typeof defaults.models === "object" ? { ...defaults.models } : {};
|
|
106
|
+
allow[`${TRINITY_OPENCLAW_PROVIDER}/*`] = allow[`${TRINITY_OPENCLAW_PROVIDER}/*`] ?? {};
|
|
107
|
+
defaults.models = allow;
|
|
108
|
+
agents.defaults = defaults;
|
|
109
|
+
doc.agents = agents;
|
|
110
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
111
|
+
fs.writeFileSync(configPath, `${JSON.stringify(doc, null, 2)}
|
|
112
|
+
`, "utf8");
|
|
113
|
+
}
|
|
114
|
+
function configureOpenClawDirect(options) {
|
|
115
|
+
const backupDir = backupOpenClawConfig();
|
|
116
|
+
mergeOpenClawConfig(options);
|
|
117
|
+
return backupDir;
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
TRINITY_OPENCLAW_PROVIDER,
|
|
121
|
+
backupOpenClawConfig,
|
|
122
|
+
configureOpenClawDirect,
|
|
123
|
+
mergeOpenClawConfig,
|
|
124
|
+
openclawConfigPath,
|
|
125
|
+
openclawHome
|
|
126
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/merge-opencode-config.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
var TRINITY_OPENCODE_PROVIDER = "trinity";
|
|
6
|
+
function opencodeConfigDir() {
|
|
7
|
+
if (process.env.OPENCODE_CONFIG_DIR?.trim()) {
|
|
8
|
+
return process.env.OPENCODE_CONFIG_DIR.trim();
|
|
9
|
+
}
|
|
10
|
+
return path.join(os.homedir(), ".config", "opencode");
|
|
11
|
+
}
|
|
12
|
+
function opencodeConfigPath() {
|
|
13
|
+
if (process.env.OPENCODE_CONFIG?.trim()) {
|
|
14
|
+
return process.env.OPENCODE_CONFIG.trim();
|
|
15
|
+
}
|
|
16
|
+
return path.join(opencodeConfigDir(), "opencode.json");
|
|
17
|
+
}
|
|
18
|
+
function timestampLabel() {
|
|
19
|
+
const now = /* @__PURE__ */ new Date();
|
|
20
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
21
|
+
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
22
|
+
}
|
|
23
|
+
function backupOpenCodeConfig() {
|
|
24
|
+
const configPath = opencodeConfigPath();
|
|
25
|
+
if (!fs.existsSync(configPath)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const backupDir = path.join(opencodeConfigDir(), "backup", `trinity-config-${timestampLabel()}`);
|
|
29
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
30
|
+
fs.copyFileSync(configPath, path.join(backupDir, path.basename(configPath)));
|
|
31
|
+
return backupDir;
|
|
32
|
+
}
|
|
33
|
+
function readOpenCodeConfig() {
|
|
34
|
+
const configPath = opencodeConfigPath();
|
|
35
|
+
if (!fs.existsSync(configPath)) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
39
|
+
if (!raw.trim()) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
} catch {
|
|
45
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 ${configPath}\uFF0C\u8BF7\u68C0\u67E5 JSON \u8BED\u6CD5\u540E\u91CD\u8BD5\u3002`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function buildModelMap(primaryModel, modelIds) {
|
|
49
|
+
const ids = [primaryModel];
|
|
50
|
+
const seen = new Set(ids);
|
|
51
|
+
for (const id of modelIds ?? []) {
|
|
52
|
+
const trimmed = id?.trim();
|
|
53
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
54
|
+
const lower = trimmed.toLowerCase();
|
|
55
|
+
if (lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling")) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
seen.add(trimmed);
|
|
59
|
+
ids.push(trimmed);
|
|
60
|
+
if (ids.length >= 80) break;
|
|
61
|
+
}
|
|
62
|
+
const models = {};
|
|
63
|
+
for (const id of ids) {
|
|
64
|
+
models[id] = { name: id };
|
|
65
|
+
}
|
|
66
|
+
return models;
|
|
67
|
+
}
|
|
68
|
+
function mergeOpenCodeConfig(options) {
|
|
69
|
+
const configPath = opencodeConfigPath();
|
|
70
|
+
const doc = readOpenCodeConfig();
|
|
71
|
+
doc.$schema = doc.$schema ?? "https://opencode.ai/config.json";
|
|
72
|
+
doc.model = `${TRINITY_OPENCODE_PROVIDER}/${options.model}`;
|
|
73
|
+
const providers = doc.provider && typeof doc.provider === "object" ? { ...doc.provider } : {};
|
|
74
|
+
const existing = providers[TRINITY_OPENCODE_PROVIDER] ?? {};
|
|
75
|
+
const existingModels = existing.models && typeof existing.models === "object" ? existing.models : {};
|
|
76
|
+
providers[TRINITY_OPENCODE_PROVIDER] = {
|
|
77
|
+
...existing,
|
|
78
|
+
npm: "@ai-sdk/openai-compatible",
|
|
79
|
+
name: "Trinity",
|
|
80
|
+
options: {
|
|
81
|
+
...existing.options ?? {},
|
|
82
|
+
baseURL: options.baseUrl.replace(/\/+$/, ""),
|
|
83
|
+
apiKey: options.apiKey
|
|
84
|
+
},
|
|
85
|
+
models: {
|
|
86
|
+
...existingModels,
|
|
87
|
+
...buildModelMap(options.model, options.modelIds)
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
doc.provider = providers;
|
|
91
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
92
|
+
fs.writeFileSync(configPath, `${JSON.stringify(doc, null, 2)}
|
|
93
|
+
`, "utf8");
|
|
94
|
+
}
|
|
95
|
+
function configureOpenCodeDirect(options) {
|
|
96
|
+
const backupDir = backupOpenCodeConfig();
|
|
97
|
+
mergeOpenCodeConfig(options);
|
|
98
|
+
return backupDir;
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
TRINITY_OPENCODE_PROVIDER,
|
|
102
|
+
backupOpenCodeConfig,
|
|
103
|
+
configureOpenCodeDirect,
|
|
104
|
+
mergeOpenCodeConfig,
|
|
105
|
+
opencodeConfigDir,
|
|
106
|
+
opencodeConfigPath
|
|
107
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trinity-config",
|
|
3
|
-
"version": "1.1
|
|
4
|
-
"description": "一键把 Trinity API 接入 Claude Code
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "一键把 Trinity API 接入 Claude Code、Codex、OpenCode、OpenClaw",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
"trinitydesk",
|
|
30
30
|
"claude-code",
|
|
31
31
|
"codex",
|
|
32
|
+
"opencode",
|
|
33
|
+
"openclaw",
|
|
32
34
|
"cli",
|
|
33
35
|
"ai-gateway",
|
|
34
36
|
"zcf"
|
|
@@ -42,7 +44,8 @@
|
|
|
42
44
|
"dependencies": {
|
|
43
45
|
"@clack/prompts": "^0.11.0",
|
|
44
46
|
"execa": "^9.5.2",
|
|
45
|
-
"picocolors": "^1.1.1"
|
|
47
|
+
"picocolors": "^1.1.1",
|
|
48
|
+
"smol-toml": "^1.3.1"
|
|
46
49
|
},
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@types/node": "^22.10.0",
|