theclawbay 0.3.53 → 0.3.55
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 +173 -0
- package/dist/commands/setup.js +166 -18
- package/package.json +3 -2
package/dist/commands/logout.js
CHANGED
|
@@ -31,7 +31,12 @@ const CONTINUE_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(
|
|
|
31
31
|
const CLINE_GLOBAL_STATE_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "globalState.json");
|
|
32
32
|
const CLINE_SECRETS_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "secrets.json");
|
|
33
33
|
const AIDER_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".aider.conf.yml");
|
|
34
|
+
const GSD_AGENT_DIR = node_path_1.default.join(node_os_1.default.homedir(), ".gsd", "agent");
|
|
35
|
+
const GSD_MODELS_PATH = node_path_1.default.join(GSD_AGENT_DIR, "models.json");
|
|
36
|
+
const GSD_AUTH_PATH = node_path_1.default.join(GSD_AGENT_DIR, "auth.json");
|
|
37
|
+
const GSD_SETTINGS_PATH = node_path_1.default.join(GSD_AGENT_DIR, "settings.json");
|
|
34
38
|
const CLINE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "cline.restore.json");
|
|
39
|
+
const GSD_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "gsd.restore.json");
|
|
35
40
|
const OPENCODE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "opencode.restore.json");
|
|
36
41
|
const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "kilo.restore.json");
|
|
37
42
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
@@ -414,6 +419,168 @@ async function cleanupClineConfig() {
|
|
|
414
419
|
await removeFileIfExists(CLINE_RESTORE_STATE_PATH);
|
|
415
420
|
return changed;
|
|
416
421
|
}
|
|
422
|
+
function isEmptyObject(value) {
|
|
423
|
+
return Object.keys(value).length === 0;
|
|
424
|
+
}
|
|
425
|
+
function normalizeGsdRestoreSnapshot(value) {
|
|
426
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
427
|
+
return null;
|
|
428
|
+
const obj = value;
|
|
429
|
+
return {
|
|
430
|
+
version: 1,
|
|
431
|
+
modelsExisted: obj.modelsExisted === true,
|
|
432
|
+
providerConfig: typeof obj.providerConfig === "object" && obj.providerConfig !== null && !Array.isArray(obj.providerConfig)
|
|
433
|
+
? obj.providerConfig
|
|
434
|
+
: null,
|
|
435
|
+
authExisted: obj.authExisted === true,
|
|
436
|
+
authEntry: typeof obj.authEntry === "object" && obj.authEntry !== null && !Array.isArray(obj.authEntry)
|
|
437
|
+
? obj.authEntry
|
|
438
|
+
: null,
|
|
439
|
+
settingsExisted: obj.settingsExisted === true,
|
|
440
|
+
defaultProvider: typeof obj.defaultProvider === "string" ? obj.defaultProvider : null,
|
|
441
|
+
defaultModel: typeof obj.defaultModel === "string" ? obj.defaultModel : null,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function normalizeGsdCredential(value) {
|
|
445
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
446
|
+
return null;
|
|
447
|
+
return { ...value };
|
|
448
|
+
}
|
|
449
|
+
async function cleanupGsdConfig() {
|
|
450
|
+
const snapshotRaw = await readFileIfExists(GSD_RESTORE_STATE_PATH);
|
|
451
|
+
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
452
|
+
return false;
|
|
453
|
+
let snapshot = null;
|
|
454
|
+
try {
|
|
455
|
+
snapshot = normalizeGsdRestoreSnapshot(JSON.parse(snapshotRaw));
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
snapshot = null;
|
|
459
|
+
}
|
|
460
|
+
if (!snapshot)
|
|
461
|
+
return false;
|
|
462
|
+
let changed = false;
|
|
463
|
+
const modelsRaw = await readFileIfExists(GSD_MODELS_PATH);
|
|
464
|
+
if (modelsRaw !== null) {
|
|
465
|
+
let fileChanged = false;
|
|
466
|
+
let doc = objectRecordOr({}, {});
|
|
467
|
+
try {
|
|
468
|
+
doc = modelsRaw.trim() ? objectRecordOr(JSON.parse(modelsRaw), {}) : {};
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
doc = {};
|
|
472
|
+
}
|
|
473
|
+
const providersRoot = objectRecordOr(doc.providers, {});
|
|
474
|
+
if (snapshot.providerConfig) {
|
|
475
|
+
const currentProvider = objectRecordOr(providersRoot[DEFAULT_PROVIDER_ID], {});
|
|
476
|
+
const nextProvider = JSON.stringify(snapshot.providerConfig);
|
|
477
|
+
if (JSON.stringify(currentProvider) !== nextProvider) {
|
|
478
|
+
providersRoot[DEFAULT_PROVIDER_ID] = snapshot.providerConfig;
|
|
479
|
+
fileChanged = true;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else if (DEFAULT_PROVIDER_ID in providersRoot) {
|
|
483
|
+
delete providersRoot[DEFAULT_PROVIDER_ID];
|
|
484
|
+
fileChanged = true;
|
|
485
|
+
}
|
|
486
|
+
if (isEmptyObject(providersRoot)) {
|
|
487
|
+
if ("providers" in doc)
|
|
488
|
+
fileChanged = true;
|
|
489
|
+
delete doc.providers;
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
doc.providers = providersRoot;
|
|
493
|
+
}
|
|
494
|
+
if (!fileChanged) {
|
|
495
|
+
// Preserve the file exactly if nothing changed.
|
|
496
|
+
}
|
|
497
|
+
else if (!snapshot.modelsExisted && isEmptyObject(doc)) {
|
|
498
|
+
changed = (await removeFileIfExists(GSD_MODELS_PATH)) || changed;
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
await writeJsonFile(GSD_MODELS_PATH, doc);
|
|
502
|
+
changed = true;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const authRaw = await readFileIfExists(GSD_AUTH_PATH);
|
|
506
|
+
if (authRaw !== null) {
|
|
507
|
+
let fileChanged = false;
|
|
508
|
+
let doc = objectRecordOr({}, {});
|
|
509
|
+
try {
|
|
510
|
+
doc = authRaw.trim() ? objectRecordOr(JSON.parse(authRaw), {}) : {};
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
doc = {};
|
|
514
|
+
}
|
|
515
|
+
if (snapshot.authEntry) {
|
|
516
|
+
const currentEntry = normalizeGsdCredential(doc[DEFAULT_PROVIDER_ID]);
|
|
517
|
+
const nextEntry = JSON.stringify(snapshot.authEntry);
|
|
518
|
+
if (JSON.stringify(currentEntry) !== nextEntry) {
|
|
519
|
+
doc[DEFAULT_PROVIDER_ID] = snapshot.authEntry;
|
|
520
|
+
fileChanged = true;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
else if (DEFAULT_PROVIDER_ID in doc) {
|
|
524
|
+
delete doc[DEFAULT_PROVIDER_ID];
|
|
525
|
+
fileChanged = true;
|
|
526
|
+
}
|
|
527
|
+
if (!fileChanged) {
|
|
528
|
+
// Preserve the file exactly if nothing changed.
|
|
529
|
+
}
|
|
530
|
+
else if (!snapshot.authExisted && isEmptyObject(doc)) {
|
|
531
|
+
changed = (await removeFileIfExists(GSD_AUTH_PATH)) || changed;
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
await writeJsonFile(GSD_AUTH_PATH, doc, 0o600);
|
|
535
|
+
changed = true;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const settingsRaw = await readFileIfExists(GSD_SETTINGS_PATH);
|
|
539
|
+
if (settingsRaw !== null) {
|
|
540
|
+
let fileChanged = false;
|
|
541
|
+
let doc = objectRecordOr({}, {});
|
|
542
|
+
try {
|
|
543
|
+
doc = settingsRaw.trim() ? objectRecordOr(JSON.parse(settingsRaw), {}) : {};
|
|
544
|
+
}
|
|
545
|
+
catch {
|
|
546
|
+
doc = {};
|
|
547
|
+
}
|
|
548
|
+
if (doc.defaultProvider === DEFAULT_PROVIDER_ID) {
|
|
549
|
+
if (snapshot.defaultProvider === null) {
|
|
550
|
+
if ("defaultProvider" in doc) {
|
|
551
|
+
delete doc.defaultProvider;
|
|
552
|
+
fileChanged = true;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
else if (doc.defaultProvider !== snapshot.defaultProvider) {
|
|
556
|
+
doc.defaultProvider = snapshot.defaultProvider;
|
|
557
|
+
fileChanged = true;
|
|
558
|
+
}
|
|
559
|
+
if (snapshot.defaultModel === null) {
|
|
560
|
+
if ("defaultModel" in doc) {
|
|
561
|
+
delete doc.defaultModel;
|
|
562
|
+
fileChanged = true;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else if (doc.defaultModel !== snapshot.defaultModel) {
|
|
566
|
+
doc.defaultModel = snapshot.defaultModel;
|
|
567
|
+
fileChanged = true;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (!fileChanged) {
|
|
571
|
+
// Preserve the file exactly if nothing changed.
|
|
572
|
+
}
|
|
573
|
+
else if (!snapshot.settingsExisted && isEmptyObject(doc)) {
|
|
574
|
+
changed = (await removeFileIfExists(GSD_SETTINGS_PATH)) || changed;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
await writeJsonFile(GSD_SETTINGS_PATH, doc);
|
|
578
|
+
changed = true;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
await removeFileIfExists(GSD_RESTORE_STATE_PATH);
|
|
582
|
+
return changed;
|
|
583
|
+
}
|
|
417
584
|
async function cleanupRooConfig() {
|
|
418
585
|
const snapshotRaw = await readFileIfExists(ROO_SETTINGS_STATE_PATH);
|
|
419
586
|
let changed = false;
|
|
@@ -773,6 +940,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
773
940
|
let updatedCodexConfig = false;
|
|
774
941
|
let updatedContinueConfig = false;
|
|
775
942
|
let updatedClineConfig = false;
|
|
943
|
+
let updatedGsdConfig = false;
|
|
776
944
|
let updatedOpenClawConfig = false;
|
|
777
945
|
let updatedOpenCodeConfig = false;
|
|
778
946
|
let updatedKiloConfig = false;
|
|
@@ -840,6 +1008,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
840
1008
|
updatedContinueConfig = await cleanupContinueConfig();
|
|
841
1009
|
progress.update("Reverting Cline");
|
|
842
1010
|
updatedClineConfig = await cleanupClineConfig();
|
|
1011
|
+
progress.update("Reverting GSD");
|
|
1012
|
+
updatedGsdConfig = await cleanupGsdConfig();
|
|
843
1013
|
progress.update("Reverting OpenClaw");
|
|
844
1014
|
updatedOpenClawConfig = await cleanupOpenClawConfig();
|
|
845
1015
|
progress.update("Reverting OpenCode");
|
|
@@ -881,6 +1051,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
881
1051
|
revertedTargets.push("Continue");
|
|
882
1052
|
if (updatedClineConfig)
|
|
883
1053
|
revertedTargets.push("Cline");
|
|
1054
|
+
if (updatedGsdConfig)
|
|
1055
|
+
revertedTargets.push("GSD");
|
|
884
1056
|
if (updatedOpenClawConfig)
|
|
885
1057
|
revertedTargets.push("OpenClaw");
|
|
886
1058
|
if (updatedOpenCodeConfig)
|
|
@@ -981,6 +1153,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
981
1153
|
}
|
|
982
1154
|
this.log(`- Continue config cleaned: ${updatedContinueConfig ? "yes" : "no"}`);
|
|
983
1155
|
this.log(`- Cline config cleaned: ${updatedClineConfig ? "yes" : "no"}`);
|
|
1156
|
+
this.log(`- GSD config cleaned: ${updatedGsdConfig ? "yes" : "no"}`);
|
|
984
1157
|
this.log(`- OpenClaw config cleaned: ${updatedOpenClawConfig ? "yes" : "no"}`);
|
|
985
1158
|
this.log(`- OpenCode config cleaned: ${updatedOpenCodeConfig ? "yes" : "no"}`);
|
|
986
1159
|
this.log(`- Kilo config cleaned: ${updatedKiloConfig ? "yes" : "no"}`);
|
package/dist/commands/setup.js
CHANGED
|
@@ -41,12 +41,18 @@ const PREFERRED_MODELS = [...SUPPORTED_MODEL_IDS];
|
|
|
41
41
|
const ENV_KEY_NAME = "THECLAWBAY_API_KEY";
|
|
42
42
|
const CLAUDE_ENV_API_KEY_NAME = "ANTHROPIC_API_KEY";
|
|
43
43
|
const CLAUDE_ENV_BASE_URL_NAME = "ANTHROPIC_BASE_URL";
|
|
44
|
+
const CLAUDE_ENV_SIMPLE_MODE_NAME = "CLAUDE_CODE_SIMPLE";
|
|
44
45
|
const ENV_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "env");
|
|
45
46
|
const CONTINUE_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".continue", "config.yaml");
|
|
46
47
|
const CLINE_GLOBAL_STATE_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "globalState.json");
|
|
47
48
|
const CLINE_SECRETS_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "secrets.json");
|
|
48
49
|
const AIDER_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".aider.conf.yml");
|
|
50
|
+
const GSD_AGENT_DIR = node_path_1.default.join(node_os_1.default.homedir(), ".gsd", "agent");
|
|
51
|
+
const GSD_MODELS_PATH = node_path_1.default.join(GSD_AGENT_DIR, "models.json");
|
|
52
|
+
const GSD_AUTH_PATH = node_path_1.default.join(GSD_AGENT_DIR, "auth.json");
|
|
53
|
+
const GSD_SETTINGS_PATH = node_path_1.default.join(GSD_AGENT_DIR, "settings.json");
|
|
49
54
|
const CLINE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "cline.restore.json");
|
|
55
|
+
const GSD_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "gsd.restore.json");
|
|
50
56
|
const OPENCODE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "opencode.restore.json");
|
|
51
57
|
const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "kilo.restore.json");
|
|
52
58
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
@@ -61,7 +67,7 @@ const SHELL_END = "# theclawbay-shell-managed:end";
|
|
|
61
67
|
const OPENCLAW_PROVIDER_ID = DEFAULT_PROVIDER_ID;
|
|
62
68
|
const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set(["openai", "theclawbay-wan", DEFAULT_PROVIDER_ID]);
|
|
63
69
|
const HISTORY_PROVIDER_DB_MIGRATE_SOURCES = ["openai", "theclawbay-wan"];
|
|
64
|
-
const SETUP_CLIENT_IDS = ["codex", "claude", "continue", "cline", "openclaw", "opencode", "kilo", "roo", "trae", "aider", "zo"];
|
|
70
|
+
const SETUP_CLIENT_IDS = ["codex", "claude", "continue", "cline", "gsd", "openclaw", "opencode", "kilo", "roo", "trae", "aider", "zo"];
|
|
65
71
|
const LEGACY_THECLAWBAY_OPENAI_PROXY_SUFFIX = "/api/codex-auth/v1/proxy/v1";
|
|
66
72
|
const CANONICAL_THECLAWBAY_OPENAI_PROXY_SUFFIX = "/v1";
|
|
67
73
|
const CANONICAL_CODEX_NATIVE_PROXY_SUFFIX = "/backend-api/codex";
|
|
@@ -161,7 +167,7 @@ function logSetupCompactSummary(params) {
|
|
|
161
167
|
.filter((client) => params.selectedSetupClients.has(client.id))
|
|
162
168
|
.map((client) => client.summaryLabel);
|
|
163
169
|
const restartTargets = params.setupClients
|
|
164
|
-
.filter((client) => params.selectedSetupClients.has(client.id) && ["continue", "cline", "roo", "trae", "zo"].includes(client.id))
|
|
170
|
+
.filter((client) => params.selectedSetupClients.has(client.id) && ["continue", "cline", "gsd", "roo", "trae", "zo"].includes(client.id))
|
|
165
171
|
.map((client) => client.summaryLabel);
|
|
166
172
|
if (configured.length > 0) {
|
|
167
173
|
params.log(`Configured: ${formatSummaryList(configured)}`);
|
|
@@ -1119,6 +1125,21 @@ async function detectCodexClient() {
|
|
|
1119
1125
|
}
|
|
1120
1126
|
return false;
|
|
1121
1127
|
}
|
|
1128
|
+
async function detectGsdClient() {
|
|
1129
|
+
if (hasCommand("gsd"))
|
|
1130
|
+
return true;
|
|
1131
|
+
const candidates = [
|
|
1132
|
+
GSD_AGENT_DIR,
|
|
1133
|
+
GSD_MODELS_PATH,
|
|
1134
|
+
GSD_AUTH_PATH,
|
|
1135
|
+
GSD_SETTINGS_PATH,
|
|
1136
|
+
];
|
|
1137
|
+
for (const candidate of candidates) {
|
|
1138
|
+
if (await pathExists(candidate))
|
|
1139
|
+
return true;
|
|
1140
|
+
}
|
|
1141
|
+
return false;
|
|
1142
|
+
}
|
|
1122
1143
|
async function detectContinueClient() {
|
|
1123
1144
|
if (hasCommand("cn") || hasCommand("continue"))
|
|
1124
1145
|
return true;
|
|
@@ -1371,6 +1392,100 @@ async function writeClineConfig(params) {
|
|
|
1371
1392
|
await writeJsonObjectFile(CLINE_SECRETS_PATH, secrets, 0o600);
|
|
1372
1393
|
return [CLINE_GLOBAL_STATE_PATH, CLINE_SECRETS_PATH];
|
|
1373
1394
|
}
|
|
1395
|
+
function buildGsdModels(models) {
|
|
1396
|
+
const supportedModelMap = new Map((0, supported_models_1.getSupportedModels)().map((model) => [model.id, model]));
|
|
1397
|
+
return models
|
|
1398
|
+
.filter((model) => Boolean(model.id))
|
|
1399
|
+
.map((model) => {
|
|
1400
|
+
const pricing = supportedModelMap.get(model.id);
|
|
1401
|
+
return {
|
|
1402
|
+
id: model.id,
|
|
1403
|
+
name: model.name || model.id,
|
|
1404
|
+
reasoning: true,
|
|
1405
|
+
input: ["text", "image"],
|
|
1406
|
+
cost: {
|
|
1407
|
+
input: pricing?.inputPer1M ?? 0,
|
|
1408
|
+
output: pricing?.outputPer1M ?? 0,
|
|
1409
|
+
cacheRead: pricing?.cachedInputPer1M ?? 0,
|
|
1410
|
+
cacheWrite: pricing?.inputPer1M ?? 0,
|
|
1411
|
+
},
|
|
1412
|
+
contextWindow: modelContextLimit(model.id),
|
|
1413
|
+
maxTokens: modelOutputLimit(model.id),
|
|
1414
|
+
};
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
function normalizeGsdCredential(value) {
|
|
1418
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
1419
|
+
return null;
|
|
1420
|
+
return { ...value };
|
|
1421
|
+
}
|
|
1422
|
+
async function writeGsdConfig(params) {
|
|
1423
|
+
const existingModelsRaw = await readFileIfExists(GSD_MODELS_PATH);
|
|
1424
|
+
const existingAuthRaw = await readFileIfExists(GSD_AUTH_PATH);
|
|
1425
|
+
const existingSettingsRaw = await readFileIfExists(GSD_SETTINGS_PATH);
|
|
1426
|
+
const existingSnapshotRaw = await readFileIfExists(GSD_RESTORE_STATE_PATH);
|
|
1427
|
+
let modelsDoc = {};
|
|
1428
|
+
if (existingModelsRaw?.trim()) {
|
|
1429
|
+
try {
|
|
1430
|
+
modelsDoc = objectRecordOr(JSON.parse(existingModelsRaw), {});
|
|
1431
|
+
}
|
|
1432
|
+
catch {
|
|
1433
|
+
throw new Error(`invalid JSON in GSD config: ${GSD_MODELS_PATH}`);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
let authDoc = {};
|
|
1437
|
+
if (existingAuthRaw?.trim()) {
|
|
1438
|
+
try {
|
|
1439
|
+
authDoc = objectRecordOr(JSON.parse(existingAuthRaw), {});
|
|
1440
|
+
}
|
|
1441
|
+
catch {
|
|
1442
|
+
throw new Error(`invalid JSON in GSD auth: ${GSD_AUTH_PATH}`);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
let settingsDoc = {};
|
|
1446
|
+
if (existingSettingsRaw?.trim()) {
|
|
1447
|
+
try {
|
|
1448
|
+
settingsDoc = objectRecordOr(JSON.parse(existingSettingsRaw), {});
|
|
1449
|
+
}
|
|
1450
|
+
catch {
|
|
1451
|
+
throw new Error(`invalid JSON in GSD settings: ${GSD_SETTINGS_PATH}`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
if (!existingSnapshotRaw?.trim()) {
|
|
1455
|
+
const providersRoot = objectRecordOr(modelsDoc.providers, {});
|
|
1456
|
+
const snapshot = {
|
|
1457
|
+
version: 1,
|
|
1458
|
+
modelsExisted: existingModelsRaw !== null,
|
|
1459
|
+
providerConfig: objectRecordOr(providersRoot[DEFAULT_PROVIDER_ID], {}),
|
|
1460
|
+
authExisted: existingAuthRaw !== null,
|
|
1461
|
+
authEntry: normalizeGsdCredential(authDoc[DEFAULT_PROVIDER_ID]),
|
|
1462
|
+
settingsExisted: existingSettingsRaw !== null,
|
|
1463
|
+
defaultProvider: typeof settingsDoc.defaultProvider === "string" ? settingsDoc.defaultProvider : null,
|
|
1464
|
+
defaultModel: typeof settingsDoc.defaultModel === "string" ? settingsDoc.defaultModel : null,
|
|
1465
|
+
};
|
|
1466
|
+
if (Object.keys(snapshot.providerConfig ?? {}).length === 0)
|
|
1467
|
+
snapshot.providerConfig = null;
|
|
1468
|
+
await writeJsonObjectFile(GSD_RESTORE_STATE_PATH, snapshot, 0o600);
|
|
1469
|
+
}
|
|
1470
|
+
const providersRoot = objectRecordOr(modelsDoc.providers, {});
|
|
1471
|
+
providersRoot[DEFAULT_PROVIDER_ID] = {
|
|
1472
|
+
baseUrl: openAiCompatibleProxyUrl(params.backendUrl),
|
|
1473
|
+
apiKey: ENV_KEY_NAME,
|
|
1474
|
+
api: "openai-responses",
|
|
1475
|
+
models: buildGsdModels(params.models),
|
|
1476
|
+
};
|
|
1477
|
+
modelsDoc.providers = providersRoot;
|
|
1478
|
+
authDoc[DEFAULT_PROVIDER_ID] = {
|
|
1479
|
+
type: "api_key",
|
|
1480
|
+
key: params.apiKey,
|
|
1481
|
+
};
|
|
1482
|
+
settingsDoc.defaultProvider = DEFAULT_PROVIDER_ID;
|
|
1483
|
+
settingsDoc.defaultModel = params.model.trim() || DEFAULT_CODEX_MODEL;
|
|
1484
|
+
await writeJsonObjectFile(GSD_MODELS_PATH, modelsDoc);
|
|
1485
|
+
await writeJsonObjectFile(GSD_AUTH_PATH, authDoc, 0o600);
|
|
1486
|
+
await writeJsonObjectFile(GSD_SETTINGS_PATH, settingsDoc);
|
|
1487
|
+
return [GSD_MODELS_PATH, GSD_AUTH_PATH, GSD_SETTINGS_PATH];
|
|
1488
|
+
}
|
|
1374
1489
|
async function writeRooConfig(params) {
|
|
1375
1490
|
const hosts = await detectExtensionHosts(["rooveterinaryinc.roo-cline-"]);
|
|
1376
1491
|
if (hosts.length === 0) {
|
|
@@ -1448,7 +1563,7 @@ async function persistApiKeyEnv(params) {
|
|
|
1448
1563
|
`export ${ENV_KEY_NAME}=${shellQuote(params.apiKey)}`,
|
|
1449
1564
|
];
|
|
1450
1565
|
if (params.claudeEnabled) {
|
|
1451
|
-
envLines.push("", "# Official Claude Code CLI", `export ${CLAUDE_ENV_API_KEY_NAME}=${shellQuote(params.apiKey)}`, `export ${CLAUDE_ENV_BASE_URL_NAME}=${shellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`);
|
|
1566
|
+
envLines.push("", "# Official Claude Code CLI", `export ${CLAUDE_ENV_API_KEY_NAME}=${shellQuote(params.apiKey)}`, `export ${CLAUDE_ENV_BASE_URL_NAME}=${shellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`, `export ${CLAUDE_ENV_SIMPLE_MODE_NAME}=1`);
|
|
1452
1567
|
}
|
|
1453
1568
|
const envContents = `${envLines.join("\n")}\n`;
|
|
1454
1569
|
await promises_1.default.writeFile(ENV_FILE, envContents, "utf8");
|
|
@@ -1483,10 +1598,12 @@ async function persistApiKeyEnv(params) {
|
|
|
1483
1598
|
if (params.claudeEnabled) {
|
|
1484
1599
|
process.env[CLAUDE_ENV_API_KEY_NAME] = params.apiKey;
|
|
1485
1600
|
process.env[CLAUDE_ENV_BASE_URL_NAME] = anthropicCompatibleProxyUrl(params.backendUrl);
|
|
1601
|
+
process.env[CLAUDE_ENV_SIMPLE_MODE_NAME] = "1";
|
|
1486
1602
|
}
|
|
1487
1603
|
else {
|
|
1488
1604
|
delete process.env[CLAUDE_ENV_API_KEY_NAME];
|
|
1489
1605
|
delete process.env[CLAUDE_ENV_BASE_URL_NAME];
|
|
1606
|
+
delete process.env[CLAUDE_ENV_SIMPLE_MODE_NAME];
|
|
1490
1607
|
}
|
|
1491
1608
|
return updated;
|
|
1492
1609
|
}
|
|
@@ -1498,7 +1615,7 @@ async function persistFishEnv(params) {
|
|
|
1498
1615
|
`set -gx ${ENV_KEY_NAME} ${shellQuote(params.apiKey)}`,
|
|
1499
1616
|
];
|
|
1500
1617
|
if (params.claudeEnabled) {
|
|
1501
|
-
lines.push("", "# Official Claude Code CLI", `set -gx ${CLAUDE_ENV_API_KEY_NAME} ${shellQuote(params.apiKey)}`, `set -gx ${CLAUDE_ENV_BASE_URL_NAME} ${shellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`);
|
|
1618
|
+
lines.push("", "# Official Claude Code CLI", `set -gx ${CLAUDE_ENV_API_KEY_NAME} ${shellQuote(params.apiKey)}`, `set -gx ${CLAUDE_ENV_BASE_URL_NAME} ${shellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`, `set -gx ${CLAUDE_ENV_SIMPLE_MODE_NAME} 1`);
|
|
1502
1619
|
}
|
|
1503
1620
|
await promises_1.default.writeFile(fishConfPath, `${lines.join("\n")}\n`, "utf8");
|
|
1504
1621
|
return [fishConfPath];
|
|
@@ -1523,7 +1640,7 @@ async function persistPowerShellEnv(params) {
|
|
|
1523
1640
|
`$env:${ENV_KEY_NAME} = ${powerShellQuote(params.apiKey)}`,
|
|
1524
1641
|
];
|
|
1525
1642
|
if (params.claudeEnabled) {
|
|
1526
|
-
lines.push(`$env:${CLAUDE_ENV_API_KEY_NAME} = ${powerShellQuote(params.apiKey)}`, `$env:${CLAUDE_ENV_BASE_URL_NAME} = ${powerShellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`);
|
|
1643
|
+
lines.push(`$env:${CLAUDE_ENV_API_KEY_NAME} = ${powerShellQuote(params.apiKey)}`, `$env:${CLAUDE_ENV_BASE_URL_NAME} = ${powerShellQuote(anthropicCompatibleProxyUrl(params.backendUrl))}`, `$env:${CLAUDE_ENV_SIMPLE_MODE_NAME} = "1"`);
|
|
1527
1644
|
}
|
|
1528
1645
|
lines.push(SHELL_END);
|
|
1529
1646
|
const next = appendManagedBlock(cleaned, lines);
|
|
@@ -2012,11 +2129,12 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2012
2129
|
managed?.backendUrl ??
|
|
2013
2130
|
DEFAULT_BACKEND_URL;
|
|
2014
2131
|
const backendUrl = normalizeUrl(backendRaw, "--backend");
|
|
2015
|
-
const [codexDetected, claudeDetected, continueDetected, clineDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected] = await Promise.all([
|
|
2132
|
+
const [codexDetected, claudeDetected, continueDetected, clineDetected, gsdDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected] = await Promise.all([
|
|
2016
2133
|
detectCodexClient(),
|
|
2017
2134
|
detectClaudeCodeClient(),
|
|
2018
2135
|
detectContinueClient(),
|
|
2019
2136
|
detectClineClient(),
|
|
2137
|
+
detectGsdClient(),
|
|
2020
2138
|
detectKiloClient(),
|
|
2021
2139
|
detectRooClient(),
|
|
2022
2140
|
detectTraeClient(),
|
|
@@ -2060,6 +2178,15 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2060
2178
|
icon: "◈",
|
|
2061
2179
|
siteUrl: "https://cline.bot",
|
|
2062
2180
|
},
|
|
2181
|
+
{
|
|
2182
|
+
id: "gsd",
|
|
2183
|
+
label: "Get Shit Done 2",
|
|
2184
|
+
summaryLabel: "GSD",
|
|
2185
|
+
detected: gsdDetected,
|
|
2186
|
+
recommended: true,
|
|
2187
|
+
icon: "▣",
|
|
2188
|
+
siteUrl: "https://github.com/gsd-build/gsd-2",
|
|
2189
|
+
},
|
|
2063
2190
|
{
|
|
2064
2191
|
id: "openclaw",
|
|
2065
2192
|
label: "OpenClaw",
|
|
@@ -2179,6 +2306,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2179
2306
|
let modelCacheMigration = null;
|
|
2180
2307
|
let continueConfigPath = null;
|
|
2181
2308
|
let clineConfigPaths = [];
|
|
2309
|
+
let gsdConfigPaths = [];
|
|
2182
2310
|
let openClawConfigPath = null;
|
|
2183
2311
|
let openClawCliWarning = null;
|
|
2184
2312
|
let openCodeConfigPaths = [];
|
|
@@ -2200,6 +2328,8 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2200
2328
|
if (!resolved?.authRejected && claudeAccess.authRejected) {
|
|
2201
2329
|
throw new Error(describeCredentialRejection(authType, claudeAccess.failure));
|
|
2202
2330
|
}
|
|
2331
|
+
const claudeSelected = selectedSetupClients.has("claude");
|
|
2332
|
+
const claudeEnvEnabled = claudeSelected && claudeAccess.enabled;
|
|
2203
2333
|
progress.update("Saving shared machine config");
|
|
2204
2334
|
await (0, config_1.writeManagedConfig)({
|
|
2205
2335
|
backendUrl,
|
|
@@ -2211,17 +2341,17 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2211
2341
|
updatedShellFiles = await persistApiKeyEnv({
|
|
2212
2342
|
apiKey: authCredential,
|
|
2213
2343
|
backendUrl,
|
|
2214
|
-
claudeEnabled:
|
|
2344
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2215
2345
|
});
|
|
2216
2346
|
updatedFishFiles = await persistFishEnv({
|
|
2217
2347
|
apiKey: authCredential,
|
|
2218
2348
|
backendUrl,
|
|
2219
|
-
claudeEnabled:
|
|
2349
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2220
2350
|
});
|
|
2221
2351
|
updatedPowerShellProfiles = await persistPowerShellEnv({
|
|
2222
2352
|
apiKey: authCredential,
|
|
2223
2353
|
backendUrl,
|
|
2224
|
-
claudeEnabled:
|
|
2354
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2225
2355
|
});
|
|
2226
2356
|
if (selectedSetupClients.has("codex") || selectedSetupClients.has("claude")) {
|
|
2227
2357
|
updatedVsCodeEnvFiles = await persistVsCodeServerEnvSource();
|
|
@@ -2274,6 +2404,15 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2274
2404
|
apiKey: authCredential,
|
|
2275
2405
|
});
|
|
2276
2406
|
}
|
|
2407
|
+
if (selectedSetupClients.has("gsd")) {
|
|
2408
|
+
progress.update("Configuring GSD");
|
|
2409
|
+
gsdConfigPaths = await writeGsdConfig({
|
|
2410
|
+
backendUrl,
|
|
2411
|
+
model: resolved?.model ?? DEFAULT_CODEX_MODEL,
|
|
2412
|
+
models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
|
|
2413
|
+
apiKey: authCredential,
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2277
2416
|
if (selectedSetupClients.has("openclaw")) {
|
|
2278
2417
|
progress.update("Configuring OpenClaw");
|
|
2279
2418
|
const openClawResult = await setupOpenClaw({
|
|
@@ -2350,11 +2489,11 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2350
2489
|
const summaryNotes = new Set();
|
|
2351
2490
|
if (resolved?.note)
|
|
2352
2491
|
summaryNotes.add(resolved.note);
|
|
2353
|
-
if (claudeAccess?.enabled) {
|
|
2354
|
-
summaryNotes.add("Claude Code: exported ANTHROPIC_BASE_URL and
|
|
2355
|
-
summaryNotes.add("Claude Code
|
|
2492
|
+
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2493
|
+
summaryNotes.add("Claude Code: exported ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY, and CLAUDE_CODE_SIMPLE=1 for the official client.");
|
|
2494
|
+
summaryNotes.add("If Claude Code is already open, restart it so the custom-key env takes effect cleanly. `claude auth status` should show `authMethod: api_key` once the new env is loaded.");
|
|
2356
2495
|
}
|
|
2357
|
-
else if (claudeAccess?.note) {
|
|
2496
|
+
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
2358
2497
|
summaryNotes.add(claudeAccess.note);
|
|
2359
2498
|
}
|
|
2360
2499
|
if (selectedSetupClients.has("trae")) {
|
|
@@ -2406,11 +2545,10 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2406
2545
|
}
|
|
2407
2546
|
if (resolved?.note)
|
|
2408
2547
|
this.log(resolved.note);
|
|
2409
|
-
if (claudeAccess?.enabled) {
|
|
2548
|
+
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2410
2549
|
this.log(`- Claude Code base URL: ${anthropicCompatibleProxyUrl(backendUrl)}`);
|
|
2411
|
-
this.log(`- Claude Code selected: ${selectedSetupClients.has("claude") ? "yes" : "no"}`);
|
|
2412
2550
|
}
|
|
2413
|
-
else if (claudeAccess?.note) {
|
|
2551
|
+
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
2414
2552
|
this.log(`- Claude Code: ${claudeAccess.note}`);
|
|
2415
2553
|
}
|
|
2416
2554
|
this.log(`- Local credential env: ${ENV_FILE}`);
|
|
@@ -2496,6 +2634,16 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2496
2634
|
else {
|
|
2497
2635
|
this.log("- Cline: not detected (skipped)");
|
|
2498
2636
|
}
|
|
2637
|
+
if (selectedSetupClients.has("gsd")) {
|
|
2638
|
+
this.log(`- GSD: configured (${gsdConfigPaths.join(", ")})`);
|
|
2639
|
+
this.log("- GSD note: configured with the OpenAI Responses API so tool calling works reliably.");
|
|
2640
|
+
}
|
|
2641
|
+
else if (gsdDetected) {
|
|
2642
|
+
this.log("- GSD: detected but skipped");
|
|
2643
|
+
}
|
|
2644
|
+
else {
|
|
2645
|
+
this.log("- GSD: not detected (skipped)");
|
|
2646
|
+
}
|
|
2499
2647
|
const openClawDetected = setupClients.find((client) => client.id === "openclaw")?.detected ?? false;
|
|
2500
2648
|
if (selectedSetupClients.has("openclaw")) {
|
|
2501
2649
|
this.log(`- OpenClaw: configured (${openClawConfigPath})`);
|
|
@@ -2621,7 +2769,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2621
2769
|
});
|
|
2622
2770
|
}
|
|
2623
2771
|
}
|
|
2624
|
-
SetupCommand.description = "One-time setup: configure Codex, Claude Code, plus any detected Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Trae, Aider, or Zo installs to use The Claw Bay";
|
|
2772
|
+
SetupCommand.description = "One-time setup: configure Codex, Claude Code, plus any detected Continue, Cline, GSD, OpenClaw, OpenCode, Kilo, Roo Code, Trae, Aider, or Zo installs to use The Claw Bay";
|
|
2625
2773
|
SetupCommand.flags = {
|
|
2626
2774
|
backend: core_1.Flags.string({
|
|
2627
2775
|
required: false,
|
|
@@ -2639,7 +2787,7 @@ SetupCommand.flags = {
|
|
|
2639
2787
|
}),
|
|
2640
2788
|
clients: core_1.Flags.string({
|
|
2641
2789
|
required: false,
|
|
2642
|
-
description: "Detected local clients to configure: codex, claude, continue, cline, openclaw, opencode, kilo, roo, trae, aider, zo",
|
|
2790
|
+
description: "Detected local clients to configure: codex, claude, continue, cline, gsd, openclaw, opencode, kilo, roo, trae, aider, zo",
|
|
2643
2791
|
}),
|
|
2644
2792
|
yes: core_1.Flags.boolean({
|
|
2645
2793
|
required: false,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theclawbay",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "CLI for connecting Codex, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.",
|
|
3
|
+
"version": "0.3.55",
|
|
4
|
+
"description": "CLI for connecting Codex, Continue, Cline, GSD, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
7
7
|
"theclawbay": "dist/index.js"
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"api-key",
|
|
36
36
|
"continue",
|
|
37
37
|
"cline",
|
|
38
|
+
"gsd",
|
|
38
39
|
"openclaw",
|
|
39
40
|
"opencode",
|
|
40
41
|
"kilo",
|