theclawbay 0.3.33 → 0.3.34
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/commands/logout.js +191 -56
- package/dist/commands/setup.js +194 -56
- package/package.json +1 -1
package/dist/commands/logout.js
CHANGED
|
@@ -166,6 +166,57 @@ function objectRecordOr(value, fallback) {
|
|
|
166
166
|
function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
167
167
|
return typeof value === "string" && value.trim().endsWith(THECLAWBAY_OPENAI_PROXY_SUFFIX);
|
|
168
168
|
}
|
|
169
|
+
function uniqueStrings(values) {
|
|
170
|
+
const output = [];
|
|
171
|
+
const seen = new Set();
|
|
172
|
+
for (const value of values) {
|
|
173
|
+
const normalized = value.trim();
|
|
174
|
+
if (!normalized || seen.has(normalized))
|
|
175
|
+
continue;
|
|
176
|
+
seen.add(normalized);
|
|
177
|
+
output.push(normalized);
|
|
178
|
+
}
|
|
179
|
+
return output;
|
|
180
|
+
}
|
|
181
|
+
function xdgConfigHomeDir() {
|
|
182
|
+
const raw = process.env.XDG_CONFIG_HOME?.trim();
|
|
183
|
+
if (raw)
|
|
184
|
+
return raw;
|
|
185
|
+
return node_path_1.default.join(node_os_1.default.homedir(), ".config");
|
|
186
|
+
}
|
|
187
|
+
function configDirCandidates(appName) {
|
|
188
|
+
const home = node_os_1.default.homedir();
|
|
189
|
+
const dirs = [node_path_1.default.join(xdgConfigHomeDir(), appName)];
|
|
190
|
+
if (node_os_1.default.platform() === "darwin") {
|
|
191
|
+
dirs.push(node_path_1.default.join(home, "Library", "Application Support", appName));
|
|
192
|
+
}
|
|
193
|
+
else if (node_os_1.default.platform() === "win32") {
|
|
194
|
+
dirs.push(node_path_1.default.join(roamingAppDataDir(), appName));
|
|
195
|
+
}
|
|
196
|
+
return uniqueStrings(dirs);
|
|
197
|
+
}
|
|
198
|
+
function openCodeConfigCleanupTargets() {
|
|
199
|
+
const home = node_os_1.default.homedir();
|
|
200
|
+
const dirs = configDirCandidates("opencode");
|
|
201
|
+
const candidates = [];
|
|
202
|
+
for (const dir of dirs) {
|
|
203
|
+
candidates.push(node_path_1.default.join(dir, "opencode.json"));
|
|
204
|
+
candidates.push(node_path_1.default.join(dir, ".opencode.json"));
|
|
205
|
+
candidates.push(node_path_1.default.join(dir, "config.json"));
|
|
206
|
+
}
|
|
207
|
+
candidates.push(node_path_1.default.join(home, ".opencode.json"));
|
|
208
|
+
return uniqueStrings(candidates);
|
|
209
|
+
}
|
|
210
|
+
function kiloConfigCleanupTargets() {
|
|
211
|
+
const home = node_os_1.default.homedir();
|
|
212
|
+
const dirs = uniqueStrings([...configDirCandidates("kilo"), node_path_1.default.join(home, ".kilo")]);
|
|
213
|
+
const candidates = [];
|
|
214
|
+
for (const dir of dirs) {
|
|
215
|
+
candidates.push(node_path_1.default.join(dir, "opencode.json"));
|
|
216
|
+
candidates.push(node_path_1.default.join(dir, "config.json"));
|
|
217
|
+
}
|
|
218
|
+
return uniqueStrings(candidates);
|
|
219
|
+
}
|
|
169
220
|
async function readJsonObjectFile(filePath) {
|
|
170
221
|
const existingRaw = await readFileIfExists(filePath);
|
|
171
222
|
if (existingRaw === null || !existingRaw.trim())
|
|
@@ -449,85 +500,169 @@ async function cleanupOpenClawConfig() {
|
|
|
449
500
|
await promises_1.default.writeFile(configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
450
501
|
return true;
|
|
451
502
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
503
|
+
function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
504
|
+
if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot))
|
|
505
|
+
return null;
|
|
506
|
+
const obj = snapshot;
|
|
507
|
+
if (obj.version === 2 && Array.isArray(obj.targets)) {
|
|
508
|
+
const targets = [];
|
|
509
|
+
for (const entry of obj.targets) {
|
|
510
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
511
|
+
continue;
|
|
512
|
+
const candidate = entry;
|
|
513
|
+
const configPath = typeof candidate.configPath === "string" ? candidate.configPath.trim() : "";
|
|
514
|
+
if (!configPath)
|
|
515
|
+
continue;
|
|
516
|
+
targets.push({
|
|
517
|
+
configPath,
|
|
518
|
+
existed: candidate.existed === true,
|
|
519
|
+
openAiProvider: typeof candidate.openAiProvider === "object" && candidate.openAiProvider !== null && !Array.isArray(candidate.openAiProvider)
|
|
520
|
+
? candidate.openAiProvider
|
|
521
|
+
: null,
|
|
522
|
+
model: typeof candidate.model === "string" ? candidate.model : null,
|
|
523
|
+
schema: typeof candidate.schema === "string" ? candidate.schema : null,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
return { version: 2, targets };
|
|
456
527
|
}
|
|
457
|
-
|
|
528
|
+
const looksLikeV1 = "openAiProvider" in obj || "model" in obj || "schema" in obj;
|
|
529
|
+
if (!looksLikeV1)
|
|
530
|
+
return null;
|
|
531
|
+
return {
|
|
532
|
+
version: 2,
|
|
533
|
+
targets: [
|
|
534
|
+
{
|
|
535
|
+
configPath: fallbackConfigPath,
|
|
536
|
+
existed: true,
|
|
537
|
+
openAiProvider: typeof obj.openAiProvider === "object" && obj.openAiProvider !== null && !Array.isArray(obj.openAiProvider)
|
|
538
|
+
? obj.openAiProvider
|
|
539
|
+
: null,
|
|
540
|
+
model: typeof obj.model === "string" ? obj.model : null,
|
|
541
|
+
schema: typeof obj.schema === "string" ? obj.schema : null,
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
async function readOpenCodeRestoreSnapshot(restoreStatePath, fallbackConfigPath) {
|
|
547
|
+
const existingRaw = await readFileIfExists(restoreStatePath);
|
|
548
|
+
if (existingRaw === null || !existingRaw.trim())
|
|
549
|
+
return null;
|
|
458
550
|
try {
|
|
459
|
-
|
|
551
|
+
return normalizeOpenCodeRestoreSnapshot(JSON.parse(existingRaw), fallbackConfigPath);
|
|
460
552
|
}
|
|
461
553
|
catch {
|
|
462
|
-
return
|
|
554
|
+
return null;
|
|
463
555
|
}
|
|
464
|
-
|
|
556
|
+
}
|
|
557
|
+
async function cleanupOpenCodeFamilyConfigs(params) {
|
|
558
|
+
const configPaths = uniqueStrings(params.configPaths);
|
|
559
|
+
const fallbackConfigPath = configPaths[0] ?? node_path_1.default.join(xdgConfigHomeDir(), "opencode", "opencode.json");
|
|
560
|
+
const snapshot = await readOpenCodeRestoreSnapshot(params.restoreStatePath, fallbackConfigPath);
|
|
561
|
+
const snapshotTargets = snapshot?.targets ?? [];
|
|
465
562
|
let changed = false;
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
563
|
+
const restoreConfig = async (target) => {
|
|
564
|
+
if (!target.existed) {
|
|
565
|
+
changed = (await removeFileIfExists(target.configPath)) || changed;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const existingRaw = await readFileIfExists(target.configPath);
|
|
569
|
+
if (existingRaw === null || !existingRaw.trim()) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
let doc;
|
|
472
573
|
try {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
574
|
+
doc = objectRecordOr(JSON.parse(existingRaw), {});
|
|
575
|
+
}
|
|
576
|
+
catch {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const providerRoot = objectRecordOr(doc.provider, {});
|
|
580
|
+
if (DEFAULT_PROVIDER_ID in providerRoot) {
|
|
581
|
+
delete providerRoot[DEFAULT_PROVIDER_ID];
|
|
582
|
+
changed = true;
|
|
583
|
+
}
|
|
584
|
+
if (target.openAiProvider) {
|
|
585
|
+
providerRoot[OPENAI_PROVIDER_ID] = target.openAiProvider;
|
|
586
|
+
}
|
|
587
|
+
else if (OPENAI_PROVIDER_ID in providerRoot) {
|
|
588
|
+
delete providerRoot[OPENAI_PROVIDER_ID];
|
|
589
|
+
}
|
|
590
|
+
doc.provider = providerRoot;
|
|
591
|
+
if (target.model === null) {
|
|
592
|
+
if (isManagedOpenCodeModel(doc.model) ||
|
|
593
|
+
(typeof doc.model === "string" && doc.model.startsWith(`${DEFAULT_PROVIDER_ID}/`))) {
|
|
594
|
+
delete doc.model;
|
|
595
|
+
changed = true;
|
|
492
596
|
}
|
|
493
|
-
|
|
494
|
-
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
doc.model = target.model;
|
|
600
|
+
changed = true;
|
|
601
|
+
}
|
|
602
|
+
if (target.schema === null) {
|
|
603
|
+
if (typeof doc.$schema === "string") {
|
|
604
|
+
delete doc.$schema;
|
|
605
|
+
changed = true;
|
|
495
606
|
}
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
doc.$schema = target.schema;
|
|
496
610
|
changed = true;
|
|
497
|
-
await promises_1.default.writeFile(params.configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
498
|
-
await removeFileIfExists(params.restoreStatePath);
|
|
499
|
-
return changed;
|
|
500
611
|
}
|
|
501
|
-
|
|
502
|
-
|
|
612
|
+
await promises_1.default.writeFile(target.configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
613
|
+
};
|
|
614
|
+
if (snapshotTargets.length > 0) {
|
|
615
|
+
for (const target of snapshotTargets) {
|
|
616
|
+
await restoreConfig(target);
|
|
503
617
|
}
|
|
618
|
+
await removeFileIfExists(params.restoreStatePath);
|
|
619
|
+
return changed;
|
|
504
620
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
621
|
+
for (const configPath of configPaths) {
|
|
622
|
+
const existingRaw = await readFileIfExists(configPath);
|
|
623
|
+
if (existingRaw === null || !existingRaw.trim())
|
|
624
|
+
continue;
|
|
625
|
+
let doc;
|
|
626
|
+
try {
|
|
627
|
+
doc = objectRecordOr(JSON.parse(existingRaw), {});
|
|
628
|
+
}
|
|
629
|
+
catch {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
let fileChanged = false;
|
|
633
|
+
const providerRoot = objectRecordOr(doc.provider, {});
|
|
634
|
+
if (DEFAULT_PROVIDER_ID in providerRoot) {
|
|
635
|
+
delete providerRoot[DEFAULT_PROVIDER_ID];
|
|
636
|
+
fileChanged = true;
|
|
637
|
+
}
|
|
638
|
+
const model = doc.model;
|
|
639
|
+
if (typeof model === "string" &&
|
|
640
|
+
(model.startsWith(`${DEFAULT_PROVIDER_ID}/`) || isManagedOpenCodeModel(model))) {
|
|
641
|
+
delete doc.model;
|
|
642
|
+
fileChanged = true;
|
|
643
|
+
}
|
|
644
|
+
if (isManagedOpenCodeProvider(providerRoot[OPENAI_PROVIDER_ID])) {
|
|
645
|
+
delete providerRoot[OPENAI_PROVIDER_ID];
|
|
646
|
+
fileChanged = true;
|
|
647
|
+
}
|
|
648
|
+
if (!fileChanged)
|
|
649
|
+
continue;
|
|
509
650
|
changed = true;
|
|
510
|
-
}
|
|
511
|
-
if (isManagedOpenCodeProvider(providerRoot[OPENAI_PROVIDER_ID])) {
|
|
512
|
-
delete providerRoot[OPENAI_PROVIDER_ID];
|
|
513
651
|
doc.provider = providerRoot;
|
|
514
|
-
|
|
652
|
+
await promises_1.default.writeFile(configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
515
653
|
}
|
|
516
|
-
if (!changed)
|
|
517
|
-
return false;
|
|
518
|
-
await promises_1.default.writeFile(params.configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
519
654
|
await removeFileIfExists(params.restoreStatePath);
|
|
520
|
-
return
|
|
655
|
+
return changed;
|
|
521
656
|
}
|
|
522
657
|
async function cleanupOpenCodeConfig() {
|
|
523
|
-
return
|
|
524
|
-
|
|
658
|
+
return cleanupOpenCodeFamilyConfigs({
|
|
659
|
+
configPaths: openCodeConfigCleanupTargets(),
|
|
525
660
|
restoreStatePath: OPENCODE_RESTORE_STATE_PATH,
|
|
526
661
|
});
|
|
527
662
|
}
|
|
528
663
|
async function cleanupKiloConfig() {
|
|
529
|
-
return
|
|
530
|
-
|
|
664
|
+
return cleanupOpenCodeFamilyConfigs({
|
|
665
|
+
configPaths: kiloConfigCleanupTargets(),
|
|
531
666
|
restoreStatePath: KILO_RESTORE_STATE_PATH,
|
|
532
667
|
});
|
|
533
668
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -272,6 +272,35 @@ function openAiCompatibleProxyUrl(backendUrl) {
|
|
|
272
272
|
function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
273
273
|
return typeof value === "string" && value.trim().endsWith(THECLAWBAY_OPENAI_PROXY_SUFFIX);
|
|
274
274
|
}
|
|
275
|
+
function uniqueStrings(values) {
|
|
276
|
+
const output = [];
|
|
277
|
+
const seen = new Set();
|
|
278
|
+
for (const value of values) {
|
|
279
|
+
const normalized = value.trim();
|
|
280
|
+
if (!normalized || seen.has(normalized))
|
|
281
|
+
continue;
|
|
282
|
+
seen.add(normalized);
|
|
283
|
+
output.push(normalized);
|
|
284
|
+
}
|
|
285
|
+
return output;
|
|
286
|
+
}
|
|
287
|
+
function xdgConfigHomeDir() {
|
|
288
|
+
const raw = process.env.XDG_CONFIG_HOME?.trim();
|
|
289
|
+
if (raw)
|
|
290
|
+
return raw;
|
|
291
|
+
return node_path_1.default.join(node_os_1.default.homedir(), ".config");
|
|
292
|
+
}
|
|
293
|
+
function configDirCandidates(appName) {
|
|
294
|
+
const home = node_os_1.default.homedir();
|
|
295
|
+
const dirs = [node_path_1.default.join(xdgConfigHomeDir(), appName)];
|
|
296
|
+
if (node_os_1.default.platform() === "darwin") {
|
|
297
|
+
dirs.push(node_path_1.default.join(home, "Library", "Application Support", appName));
|
|
298
|
+
}
|
|
299
|
+
else if (node_os_1.default.platform() === "win32") {
|
|
300
|
+
dirs.push(node_path_1.default.join(roamingAppDataDir(), appName));
|
|
301
|
+
}
|
|
302
|
+
return uniqueStrings(dirs);
|
|
303
|
+
}
|
|
275
304
|
function roamingAppDataDir() {
|
|
276
305
|
if (process.env.APPDATA?.trim())
|
|
277
306
|
return process.env.APPDATA;
|
|
@@ -1109,6 +1138,99 @@ function buildOpenCodeModelsObject(models) {
|
|
|
1109
1138
|
}
|
|
1110
1139
|
return result;
|
|
1111
1140
|
}
|
|
1141
|
+
function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
1142
|
+
if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot))
|
|
1143
|
+
return null;
|
|
1144
|
+
const obj = snapshot;
|
|
1145
|
+
if (obj.version === 2 && Array.isArray(obj.targets)) {
|
|
1146
|
+
const targets = [];
|
|
1147
|
+
for (const entry of obj.targets) {
|
|
1148
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
1149
|
+
continue;
|
|
1150
|
+
const candidate = entry;
|
|
1151
|
+
const configPath = typeof candidate.configPath === "string" ? candidate.configPath.trim() : "";
|
|
1152
|
+
if (!configPath)
|
|
1153
|
+
continue;
|
|
1154
|
+
targets.push({
|
|
1155
|
+
configPath,
|
|
1156
|
+
existed: candidate.existed === true,
|
|
1157
|
+
openAiProvider: typeof candidate.openAiProvider === "object" && candidate.openAiProvider !== null && !Array.isArray(candidate.openAiProvider)
|
|
1158
|
+
? candidate.openAiProvider
|
|
1159
|
+
: null,
|
|
1160
|
+
model: typeof candidate.model === "string" ? candidate.model : null,
|
|
1161
|
+
schema: typeof candidate.schema === "string" ? candidate.schema : null,
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
return { version: 2, targets };
|
|
1165
|
+
}
|
|
1166
|
+
const looksLikeV1 = "openAiProvider" in obj || "model" in obj || "schema" in obj;
|
|
1167
|
+
if (!looksLikeV1)
|
|
1168
|
+
return null;
|
|
1169
|
+
return {
|
|
1170
|
+
version: 2,
|
|
1171
|
+
targets: [
|
|
1172
|
+
{
|
|
1173
|
+
configPath: fallbackConfigPath,
|
|
1174
|
+
existed: true,
|
|
1175
|
+
openAiProvider: typeof obj.openAiProvider === "object" && obj.openAiProvider !== null && !Array.isArray(obj.openAiProvider)
|
|
1176
|
+
? obj.openAiProvider
|
|
1177
|
+
: null,
|
|
1178
|
+
model: typeof obj.model === "string" ? obj.model : null,
|
|
1179
|
+
schema: typeof obj.schema === "string" ? obj.schema : null,
|
|
1180
|
+
},
|
|
1181
|
+
],
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
async function readOpenCodeRestoreSnapshot(restoreStatePath, fallbackConfigPath) {
|
|
1185
|
+
const existingRaw = await readFileIfExists(restoreStatePath);
|
|
1186
|
+
if (existingRaw === null || !existingRaw.trim())
|
|
1187
|
+
return null;
|
|
1188
|
+
try {
|
|
1189
|
+
return normalizeOpenCodeRestoreSnapshot(JSON.parse(existingRaw), fallbackConfigPath);
|
|
1190
|
+
}
|
|
1191
|
+
catch {
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function openCodeConfigFileCandidates() {
|
|
1196
|
+
const home = node_os_1.default.homedir();
|
|
1197
|
+
const dirs = configDirCandidates("opencode");
|
|
1198
|
+
const candidates = [];
|
|
1199
|
+
for (const dir of dirs) {
|
|
1200
|
+
candidates.push(node_path_1.default.join(dir, "opencode.json"));
|
|
1201
|
+
candidates.push(node_path_1.default.join(dir, ".opencode.json"));
|
|
1202
|
+
candidates.push(node_path_1.default.join(dir, "config.json"));
|
|
1203
|
+
}
|
|
1204
|
+
candidates.push(node_path_1.default.join(home, ".opencode.json"));
|
|
1205
|
+
return uniqueStrings(candidates);
|
|
1206
|
+
}
|
|
1207
|
+
function kiloConfigFileCandidates() {
|
|
1208
|
+
const home = node_os_1.default.homedir();
|
|
1209
|
+
const dirs = uniqueStrings([...configDirCandidates("kilo"), node_path_1.default.join(home, ".kilo")]);
|
|
1210
|
+
const candidates = [];
|
|
1211
|
+
for (const dir of dirs) {
|
|
1212
|
+
candidates.push(node_path_1.default.join(dir, "opencode.json"));
|
|
1213
|
+
candidates.push(node_path_1.default.join(dir, "config.json"));
|
|
1214
|
+
}
|
|
1215
|
+
return uniqueStrings(candidates);
|
|
1216
|
+
}
|
|
1217
|
+
function resolveOpenCodeConfigTargets() {
|
|
1218
|
+
const candidates = openCodeConfigFileCandidates();
|
|
1219
|
+
const existing = candidates.filter((candidate) => (0, node_fs_1.existsSync)(candidate));
|
|
1220
|
+
if (existing.length)
|
|
1221
|
+
return existing;
|
|
1222
|
+
const primaryDir = configDirCandidates("opencode")[0] ?? node_path_1.default.join(xdgConfigHomeDir(), "opencode");
|
|
1223
|
+
return uniqueStrings([node_path_1.default.join(primaryDir, "opencode.json"), node_path_1.default.join(primaryDir, ".opencode.json")]);
|
|
1224
|
+
}
|
|
1225
|
+
function resolveKiloConfigTargets() {
|
|
1226
|
+
const candidates = kiloConfigFileCandidates();
|
|
1227
|
+
const existing = candidates.filter((candidate) => (0, node_fs_1.existsSync)(candidate));
|
|
1228
|
+
if (existing.length)
|
|
1229
|
+
return existing;
|
|
1230
|
+
const home = node_os_1.default.homedir();
|
|
1231
|
+
const primaryDir = uniqueStrings([...configDirCandidates("kilo"), node_path_1.default.join(home, ".kilo")])[0] ?? node_path_1.default.join(xdgConfigHomeDir(), "kilo");
|
|
1232
|
+
return uniqueStrings([node_path_1.default.join(primaryDir, "opencode.json")]);
|
|
1233
|
+
}
|
|
1112
1234
|
function isManagedOpenCodeProvider(provider) {
|
|
1113
1235
|
const options = objectRecordOr(provider.options, {});
|
|
1114
1236
|
return isTheClawBayOpenAiCompatibleBaseUrl(options.baseURL);
|
|
@@ -1121,58 +1243,74 @@ function isManagedOpenCodeModel(value, supportedModelIds) {
|
|
|
1121
1243
|
return supportedModelIds.has(value.slice(`${OPENAI_PROVIDER_ID}/`.length));
|
|
1122
1244
|
}
|
|
1123
1245
|
async function writeOpenCodeFamilyConfig(params) {
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1246
|
+
const normalizedConfigPaths = uniqueStrings(params.configPaths);
|
|
1247
|
+
const fallbackConfigPath = normalizedConfigPaths[0] ?? node_path_1.default.join(xdgConfigHomeDir(), "opencode", "opencode.json");
|
|
1248
|
+
const restoreState = (await readOpenCodeRestoreSnapshot(params.restoreStatePath, fallbackConfigPath)) ??
|
|
1249
|
+
{
|
|
1250
|
+
version: 2,
|
|
1251
|
+
targets: [],
|
|
1252
|
+
};
|
|
1253
|
+
const supportedModelIds = new Set(params.models.map((entry) => entry.id).filter(Boolean));
|
|
1254
|
+
const restoreHasTarget = (configPath) => restoreState.targets.some((entry) => entry.configPath === configPath);
|
|
1255
|
+
for (const configPath of normalizedConfigPaths) {
|
|
1256
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(configPath), { recursive: true });
|
|
1257
|
+
let existed = true;
|
|
1258
|
+
let existingRaw = "";
|
|
1136
1259
|
try {
|
|
1137
|
-
|
|
1260
|
+
existingRaw = await promises_1.default.readFile(configPath, "utf8");
|
|
1138
1261
|
}
|
|
1139
|
-
catch {
|
|
1140
|
-
|
|
1262
|
+
catch (error) {
|
|
1263
|
+
const err = error;
|
|
1264
|
+
if (err.code !== "ENOENT")
|
|
1265
|
+
throw error;
|
|
1266
|
+
existed = false;
|
|
1141
1267
|
}
|
|
1268
|
+
let doc = {};
|
|
1269
|
+
if (existingRaw.trim()) {
|
|
1270
|
+
try {
|
|
1271
|
+
doc = objectRecordOr(JSON.parse(existingRaw), {});
|
|
1272
|
+
}
|
|
1273
|
+
catch {
|
|
1274
|
+
throw new Error(`invalid JSON in config: ${configPath}`);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
const providerRoot = objectRecordOr(doc.provider, {});
|
|
1278
|
+
const openAiProvider = objectRecordOr(providerRoot[OPENAI_PROVIDER_ID], {});
|
|
1279
|
+
const alreadyManaged = isManagedOpenCodeProvider(openAiProvider) && isManagedOpenCodeModel(doc.model, supportedModelIds);
|
|
1280
|
+
if (!alreadyManaged && !restoreHasTarget(configPath)) {
|
|
1281
|
+
restoreState.targets.push({
|
|
1282
|
+
configPath,
|
|
1283
|
+
existed,
|
|
1284
|
+
openAiProvider: Object.keys(openAiProvider).length > 0 ? openAiProvider : null,
|
|
1285
|
+
model: typeof doc.model === "string" && !doc.model.startsWith(`${DEFAULT_PROVIDER_ID}/`)
|
|
1286
|
+
? doc.model
|
|
1287
|
+
: null,
|
|
1288
|
+
schema: typeof doc.$schema === "string" ? doc.$schema : null,
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
const managedOpenAiProvider = objectRecordOr(providerRoot[OPENAI_PROVIDER_ID], {});
|
|
1292
|
+
const optionsRoot = objectRecordOr(managedOpenAiProvider.options, {});
|
|
1293
|
+
optionsRoot.baseURL = `${trimTrailingSlash(params.backendUrl)}/api/codex-auth/v1/proxy/v1`;
|
|
1294
|
+
optionsRoot.apiKey = params.apiKey;
|
|
1295
|
+
managedOpenAiProvider.options = optionsRoot;
|
|
1296
|
+
managedOpenAiProvider.models = buildOpenCodeModelsObject(params.models);
|
|
1297
|
+
managedOpenAiProvider.whitelist = params.models.map((entry) => entry.id).filter(Boolean);
|
|
1298
|
+
if ("blacklist" in managedOpenAiProvider) {
|
|
1299
|
+
delete managedOpenAiProvider.blacklist;
|
|
1300
|
+
}
|
|
1301
|
+
providerRoot[OPENAI_PROVIDER_ID] = managedOpenAiProvider;
|
|
1302
|
+
if (DEFAULT_PROVIDER_ID in providerRoot) {
|
|
1303
|
+
delete providerRoot[DEFAULT_PROVIDER_ID];
|
|
1304
|
+
}
|
|
1305
|
+
doc.$schema = params.schemaUrl;
|
|
1306
|
+
doc.provider = providerRoot;
|
|
1307
|
+
doc.model = `${OPENAI_PROVIDER_ID}/${params.model}`;
|
|
1308
|
+
await promises_1.default.writeFile(configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
1142
1309
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
if (!alreadyManaged) {
|
|
1148
|
-
const snapshot = {
|
|
1149
|
-
openAiProvider: Object.keys(openAiProvider).length > 0 ? openAiProvider : null,
|
|
1150
|
-
model: typeof doc.model === "string" && !doc.model.startsWith(`${DEFAULT_PROVIDER_ID}/`)
|
|
1151
|
-
? doc.model
|
|
1152
|
-
: null,
|
|
1153
|
-
schema: typeof doc.$schema === "string" ? doc.$schema : null,
|
|
1154
|
-
};
|
|
1155
|
-
await writeJsonObjectFile(params.restoreStatePath, snapshot, 0o600);
|
|
1156
|
-
}
|
|
1157
|
-
const managedOpenAiProvider = objectRecordOr(providerRoot[OPENAI_PROVIDER_ID], {});
|
|
1158
|
-
const optionsRoot = objectRecordOr(managedOpenAiProvider.options, {});
|
|
1159
|
-
optionsRoot.baseURL = `${trimTrailingSlash(params.backendUrl)}/api/codex-auth/v1/proxy/v1`;
|
|
1160
|
-
optionsRoot.apiKey = params.apiKey;
|
|
1161
|
-
managedOpenAiProvider.options = optionsRoot;
|
|
1162
|
-
managedOpenAiProvider.models = buildOpenCodeModelsObject(params.models);
|
|
1163
|
-
managedOpenAiProvider.whitelist = params.models.map((entry) => entry.id).filter(Boolean);
|
|
1164
|
-
if ("blacklist" in managedOpenAiProvider) {
|
|
1165
|
-
delete managedOpenAiProvider.blacklist;
|
|
1166
|
-
}
|
|
1167
|
-
providerRoot[OPENAI_PROVIDER_ID] = managedOpenAiProvider;
|
|
1168
|
-
if (DEFAULT_PROVIDER_ID in providerRoot) {
|
|
1169
|
-
delete providerRoot[DEFAULT_PROVIDER_ID];
|
|
1170
|
-
}
|
|
1171
|
-
doc.$schema = params.schemaUrl;
|
|
1172
|
-
doc.provider = providerRoot;
|
|
1173
|
-
doc.model = `${OPENAI_PROVIDER_ID}/${params.model}`;
|
|
1174
|
-
await promises_1.default.writeFile(params.configPath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
1175
|
-
return params.configPath;
|
|
1310
|
+
if (restoreState.targets.length > 0) {
|
|
1311
|
+
await writeJsonObjectFile(params.restoreStatePath, restoreState, 0o600);
|
|
1312
|
+
}
|
|
1313
|
+
return normalizedConfigPaths;
|
|
1176
1314
|
}
|
|
1177
1315
|
function buildOpenClawModels(models) {
|
|
1178
1316
|
const supportedModelMap = new Map((0, supported_models_1.getSupportedModels)().map((model) => [model.id, model]));
|
|
@@ -1199,7 +1337,7 @@ function buildOpenClawModels(models) {
|
|
|
1199
1337
|
}
|
|
1200
1338
|
async function writeOpenCodeConfig(params) {
|
|
1201
1339
|
return writeOpenCodeFamilyConfig({
|
|
1202
|
-
|
|
1340
|
+
configPaths: resolveOpenCodeConfigTargets(),
|
|
1203
1341
|
restoreStatePath: OPENCODE_RESTORE_STATE_PATH,
|
|
1204
1342
|
schemaUrl: OPENCODE_CONFIG_SCHEMA_URL,
|
|
1205
1343
|
...params,
|
|
@@ -1207,7 +1345,7 @@ async function writeOpenCodeConfig(params) {
|
|
|
1207
1345
|
}
|
|
1208
1346
|
async function writeKiloConfig(params) {
|
|
1209
1347
|
return writeOpenCodeFamilyConfig({
|
|
1210
|
-
|
|
1348
|
+
configPaths: resolveKiloConfigTargets(),
|
|
1211
1349
|
restoreStatePath: KILO_RESTORE_STATE_PATH,
|
|
1212
1350
|
schemaUrl: KILO_CONFIG_SCHEMA_URL,
|
|
1213
1351
|
...params,
|
|
@@ -1382,8 +1520,8 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
1382
1520
|
let clineConfigPaths = [];
|
|
1383
1521
|
let openClawConfigPath = null;
|
|
1384
1522
|
let openClawCliWarning = null;
|
|
1385
|
-
let
|
|
1386
|
-
let
|
|
1523
|
+
let openCodeConfigPaths = [];
|
|
1524
|
+
let kiloConfigPaths = [];
|
|
1387
1525
|
let rooConfigPaths = [];
|
|
1388
1526
|
let traeBundlePathPatched = null;
|
|
1389
1527
|
let aiderConfigPath = null;
|
|
@@ -1446,7 +1584,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
1446
1584
|
}
|
|
1447
1585
|
if (selectedSetupClients.has("opencode")) {
|
|
1448
1586
|
progress.update("Configuring OpenCode");
|
|
1449
|
-
|
|
1587
|
+
openCodeConfigPaths = await writeOpenCodeConfig({
|
|
1450
1588
|
backendUrl,
|
|
1451
1589
|
model: resolved?.model ?? DEFAULT_CODEX_MODEL,
|
|
1452
1590
|
models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
|
|
@@ -1455,7 +1593,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
1455
1593
|
}
|
|
1456
1594
|
if (selectedSetupClients.has("kilo")) {
|
|
1457
1595
|
progress.update("Configuring Kilo Code");
|
|
1458
|
-
|
|
1596
|
+
kiloConfigPaths = await writeKiloConfig({
|
|
1459
1597
|
backendUrl,
|
|
1460
1598
|
model: resolved?.model ?? DEFAULT_CODEX_MODEL,
|
|
1461
1599
|
models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
|
|
@@ -1619,7 +1757,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
1619
1757
|
}
|
|
1620
1758
|
const openCodeDetected = setupClients.find((client) => client.id === "opencode")?.detected ?? false;
|
|
1621
1759
|
if (selectedSetupClients.has("opencode")) {
|
|
1622
|
-
this.log(`- OpenCode: configured (${
|
|
1760
|
+
this.log(`- OpenCode: configured (${openCodeConfigPaths.join(", ")})`);
|
|
1623
1761
|
}
|
|
1624
1762
|
else if (openCodeDetected) {
|
|
1625
1763
|
this.log("- OpenCode: detected but skipped");
|
|
@@ -1628,7 +1766,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
1628
1766
|
this.log("- OpenCode: not detected (skipped)");
|
|
1629
1767
|
}
|
|
1630
1768
|
if (selectedSetupClients.has("kilo")) {
|
|
1631
|
-
this.log(`- Kilo Code: configured (${
|
|
1769
|
+
this.log(`- Kilo Code: configured (${kiloConfigPaths.join(", ")})`);
|
|
1632
1770
|
}
|
|
1633
1771
|
else if (kiloDetected) {
|
|
1634
1772
|
this.log("- Kilo Code: detected but skipped");
|
package/package.json
CHANGED