theclawbay 0.3.56 → 0.3.57
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 +89 -5
- package/dist/commands/setup.js +222 -10
- package/package.json +1 -1
package/dist/commands/logout.js
CHANGED
|
@@ -17,6 +17,7 @@ const errors_1 = require("../lib/managed/errors");
|
|
|
17
17
|
const supported_models_1 = require("../lib/supported-models");
|
|
18
18
|
const paths_1 = require("../lib/config/paths");
|
|
19
19
|
const OPENAI_PROVIDER_ID = "openai";
|
|
20
|
+
const ANTHROPIC_PROVIDER_ID = "anthropic";
|
|
20
21
|
const DEFAULT_PROVIDER_ID = "theclawbay";
|
|
21
22
|
const WAN_PROVIDER_ID = "theclawbay-wan";
|
|
22
23
|
const MANAGED_START = "# theclawbay-managed:start";
|
|
@@ -49,6 +50,7 @@ const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayState
|
|
|
49
50
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
50
51
|
const EDITOR_TERMINAL_ENV_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "editor-terminal-env.restore.json");
|
|
51
52
|
const CLAUDE_EDITOR_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-editor-settings.restore.json");
|
|
53
|
+
const CLAUDE_DESKTOP_3P_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-desktop-3p.restore.json");
|
|
52
54
|
const CODEX_FEATURE_FLAGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "codex-features.restore.json");
|
|
53
55
|
const ROO_IMPORT_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "roo-code-settings.json");
|
|
54
56
|
const MIGRATION_STATE_FILE = node_path_1.default.join(paths_1.codexDir, "theclawbay.migration.json");
|
|
@@ -319,6 +321,22 @@ function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
|
319
321
|
return false;
|
|
320
322
|
}
|
|
321
323
|
}
|
|
324
|
+
function isTheClawBayAnthropicCompatibleBaseUrl(value) {
|
|
325
|
+
if (typeof value !== "string")
|
|
326
|
+
return false;
|
|
327
|
+
const normalized = value.trim();
|
|
328
|
+
if (!normalized)
|
|
329
|
+
return false;
|
|
330
|
+
try {
|
|
331
|
+
const parsed = new URL(normalized);
|
|
332
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
333
|
+
const pathname = parsed.pathname.replace(/\/+$/g, "");
|
|
334
|
+
return hostname === THECLAWBAY_CANONICAL_API_HOST && pathname === "/anthropic/v1";
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
322
340
|
function uniqueStrings(values) {
|
|
323
341
|
const output = [];
|
|
324
342
|
const seen = new Set();
|
|
@@ -348,6 +366,11 @@ function configDirCandidates(appName) {
|
|
|
348
366
|
}
|
|
349
367
|
return uniqueStrings(dirs);
|
|
350
368
|
}
|
|
369
|
+
function claudeDesktop3pConfigPath() {
|
|
370
|
+
if (node_os_1.default.platform() !== "darwin")
|
|
371
|
+
return null;
|
|
372
|
+
return node_path_1.default.join(node_os_1.default.homedir(), "Library", "Application Support", "Claude-3p", "claude_desktop_config.json");
|
|
373
|
+
}
|
|
351
374
|
function openCodeConfigCleanupTargets() {
|
|
352
375
|
const home = node_os_1.default.homedir();
|
|
353
376
|
const dirs = configDirCandidates("opencode");
|
|
@@ -399,6 +422,11 @@ function isManagedOpenCodeProvider(value) {
|
|
|
399
422
|
const options = objectRecordOr(provider.options, {});
|
|
400
423
|
return isTheClawBayOpenAiCompatibleBaseUrl(options.baseURL);
|
|
401
424
|
}
|
|
425
|
+
function isManagedOpenCodeAnthropicProvider(value) {
|
|
426
|
+
const provider = objectRecordOr(value, {});
|
|
427
|
+
const options = objectRecordOr(provider.options, {});
|
|
428
|
+
return isTheClawBayAnthropicCompatibleBaseUrl(options.baseURL);
|
|
429
|
+
}
|
|
402
430
|
function roamingAppDataDir() {
|
|
403
431
|
if (process.env.APPDATA?.trim())
|
|
404
432
|
return process.env.APPDATA;
|
|
@@ -888,6 +916,37 @@ async function cleanupClaudeEditorSettings() {
|
|
|
888
916
|
await removeFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
|
|
889
917
|
return updated;
|
|
890
918
|
}
|
|
919
|
+
async function cleanupClaudeDesktop3pConfig() {
|
|
920
|
+
const snapshotRaw = await readFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
921
|
+
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
922
|
+
return false;
|
|
923
|
+
let snapshot = null;
|
|
924
|
+
try {
|
|
925
|
+
snapshot = JSON.parse(snapshotRaw);
|
|
926
|
+
}
|
|
927
|
+
catch {
|
|
928
|
+
snapshot = null;
|
|
929
|
+
}
|
|
930
|
+
if (!snapshot?.configPath) {
|
|
931
|
+
await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
if (!snapshot.existed) {
|
|
935
|
+
const removed = await removeFileIfExists(snapshot.configPath);
|
|
936
|
+
await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
937
|
+
return removed;
|
|
938
|
+
}
|
|
939
|
+
const previousRaw = snapshot.previousRaw ?? "";
|
|
940
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(snapshot.configPath), { recursive: true });
|
|
941
|
+
const existingRaw = await readFileIfExists(snapshot.configPath);
|
|
942
|
+
if (existingRaw === previousRaw) {
|
|
943
|
+
await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
await promises_1.default.writeFile(snapshot.configPath, previousRaw, "utf8");
|
|
947
|
+
await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
948
|
+
return true;
|
|
949
|
+
}
|
|
891
950
|
async function cleanupCodexFeatureFlags() {
|
|
892
951
|
const snapshotRaw = await readFileIfExists(CODEX_FEATURE_FLAGS_STATE_PATH);
|
|
893
952
|
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
@@ -966,7 +1025,7 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
966
1025
|
if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot))
|
|
967
1026
|
return null;
|
|
968
1027
|
const obj = snapshot;
|
|
969
|
-
if (obj.version === 2 && Array.isArray(obj.targets)) {
|
|
1028
|
+
if ((obj.version === 2 || obj.version === 3) && Array.isArray(obj.targets)) {
|
|
970
1029
|
const targets = [];
|
|
971
1030
|
for (const entry of obj.targets) {
|
|
972
1031
|
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
@@ -983,6 +1042,11 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
983
1042
|
!Array.isArray(candidate.openAiProvider)
|
|
984
1043
|
? candidate.openAiProvider
|
|
985
1044
|
: null,
|
|
1045
|
+
anthropicProvider: typeof candidate.anthropicProvider === "object" &&
|
|
1046
|
+
candidate.anthropicProvider !== null &&
|
|
1047
|
+
!Array.isArray(candidate.anthropicProvider)
|
|
1048
|
+
? candidate.anthropicProvider
|
|
1049
|
+
: null,
|
|
986
1050
|
model: typeof candidate.model === "string" ? candidate.model : null,
|
|
987
1051
|
schema: typeof candidate.schema === "string" ? candidate.schema : null,
|
|
988
1052
|
plugin: "plugin" in candidate
|
|
@@ -992,13 +1056,13 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
992
1056
|
: undefined,
|
|
993
1057
|
});
|
|
994
1058
|
}
|
|
995
|
-
return { version:
|
|
1059
|
+
return { version: 3, targets };
|
|
996
1060
|
}
|
|
997
1061
|
const looksLikeV1 = "openAiProvider" in obj || "model" in obj || "schema" in obj;
|
|
998
1062
|
if (!looksLikeV1)
|
|
999
1063
|
return null;
|
|
1000
1064
|
return {
|
|
1001
|
-
version:
|
|
1065
|
+
version: 3,
|
|
1002
1066
|
targets: [
|
|
1003
1067
|
{
|
|
1004
1068
|
configPath: fallbackConfigPath,
|
|
@@ -1067,6 +1131,15 @@ async function cleanupOpenCodeFamilyConfigs(params) {
|
|
|
1067
1131
|
}
|
|
1068
1132
|
else if (OPENAI_PROVIDER_ID in providerRoot) {
|
|
1069
1133
|
delete providerRoot[OPENAI_PROVIDER_ID];
|
|
1134
|
+
changed = true;
|
|
1135
|
+
}
|
|
1136
|
+
if (target.anthropicProvider) {
|
|
1137
|
+
providerRoot[ANTHROPIC_PROVIDER_ID] = target.anthropicProvider;
|
|
1138
|
+
changed = true;
|
|
1139
|
+
}
|
|
1140
|
+
else if (ANTHROPIC_PROVIDER_ID in providerRoot) {
|
|
1141
|
+
delete providerRoot[ANTHROPIC_PROVIDER_ID];
|
|
1142
|
+
changed = true;
|
|
1070
1143
|
}
|
|
1071
1144
|
doc.provider = providerRoot;
|
|
1072
1145
|
if (target.model === null) {
|
|
@@ -1125,6 +1198,10 @@ async function cleanupOpenCodeFamilyConfigs(params) {
|
|
|
1125
1198
|
delete providerRoot[OPENAI_PROVIDER_ID];
|
|
1126
1199
|
fileChanged = true;
|
|
1127
1200
|
}
|
|
1201
|
+
if (isManagedOpenCodeAnthropicProvider(providerRoot[ANTHROPIC_PROVIDER_ID])) {
|
|
1202
|
+
delete providerRoot[ANTHROPIC_PROVIDER_ID];
|
|
1203
|
+
fileChanged = true;
|
|
1204
|
+
}
|
|
1128
1205
|
if (!fileChanged)
|
|
1129
1206
|
continue;
|
|
1130
1207
|
changed = true;
|
|
@@ -1187,6 +1264,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1187
1264
|
let updatedVsCodeHooks = [];
|
|
1188
1265
|
let updatedEditorTerminalSettings = [];
|
|
1189
1266
|
let updatedClaudeEditorSettings = [];
|
|
1267
|
+
let updatedClaudeDesktopConfig = false;
|
|
1190
1268
|
let updatedCodexConfig = false;
|
|
1191
1269
|
let updatedCodexFeatures = false;
|
|
1192
1270
|
let updatedContinueConfig = false;
|
|
@@ -1239,6 +1317,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1239
1317
|
updatedVsCodeHooks = await cleanupVsCodeHooks();
|
|
1240
1318
|
updatedEditorTerminalSettings = await cleanupEditorTerminalEnvSettings();
|
|
1241
1319
|
updatedClaudeEditorSettings = await cleanupClaudeEditorSettings();
|
|
1320
|
+
updatedClaudeDesktopConfig = await cleanupClaudeDesktop3pConfig();
|
|
1242
1321
|
progress.update("Reverting Codex");
|
|
1243
1322
|
updatedCodexConfig = await cleanupCodexConfig();
|
|
1244
1323
|
updatedCodexFeatures = await cleanupCodexFeatureFlags();
|
|
@@ -1294,11 +1373,12 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1294
1373
|
this.log("Logout complete");
|
|
1295
1374
|
}
|
|
1296
1375
|
const revertedTargets = [];
|
|
1376
|
+
const claudeChanged = updatedClaudeEditorSettings.length > 0 ||
|
|
1377
|
+
updatedClaudeDesktopConfig;
|
|
1297
1378
|
const codexChanged = updatedCodexConfig ||
|
|
1298
1379
|
updatedCodexFeatures ||
|
|
1299
1380
|
updatedVsCodeHooks.length > 0 ||
|
|
1300
1381
|
updatedEditorTerminalSettings.length > 0 ||
|
|
1301
|
-
updatedClaudeEditorSettings.length > 0 ||
|
|
1302
1382
|
sessionMigration.rewritten > 0 ||
|
|
1303
1383
|
sessionMigration.retimed > 0 ||
|
|
1304
1384
|
stateDbMigration.updated > 0 ||
|
|
@@ -1307,6 +1387,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1307
1387
|
modelCacheCleanup.action === "removed";
|
|
1308
1388
|
if (codexChanged)
|
|
1309
1389
|
revertedTargets.push("Codex");
|
|
1390
|
+
if (claudeChanged)
|
|
1391
|
+
revertedTargets.push("Claude");
|
|
1310
1392
|
if (updatedContinueConfig)
|
|
1311
1393
|
revertedTargets.push("Continue");
|
|
1312
1394
|
if (updatedClineConfig)
|
|
@@ -1348,7 +1430,8 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1348
1430
|
updatedPowerShellProfiles.length > 0 ||
|
|
1349
1431
|
updatedVsCodeHooks.length > 0 ||
|
|
1350
1432
|
updatedEditorTerminalSettings.length > 0 ||
|
|
1351
|
-
updatedClaudeEditorSettings.length > 0
|
|
1433
|
+
updatedClaudeEditorSettings.length > 0 ||
|
|
1434
|
+
updatedClaudeDesktopConfig,
|
|
1352
1435
|
notes: Array.from(summaryNotes),
|
|
1353
1436
|
});
|
|
1354
1437
|
return;
|
|
@@ -1366,6 +1449,7 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1366
1449
|
this.log(`- VS Code env hooks updated: ${updatedVsCodeHooks.length ? updatedVsCodeHooks.join(", ") : "none"}`);
|
|
1367
1450
|
this.log(`- Editor terminal env updated: ${updatedEditorTerminalSettings.length ? updatedEditorTerminalSettings.join(", ") : "none"}`);
|
|
1368
1451
|
this.log(`- Claude editor settings updated: ${updatedClaudeEditorSettings.length ? updatedClaudeEditorSettings.join(", ") : "none"}`);
|
|
1452
|
+
this.log(`- Claude Desktop 3P config cleaned: ${updatedClaudeDesktopConfig ? "yes" : "no"}`);
|
|
1369
1453
|
this.log(`- Codex config cleaned: ${updatedCodexConfig ? "yes" : "no"}`);
|
|
1370
1454
|
this.log(`- Codex Apps feature flags restored: ${updatedCodexFeatures ? "yes" : "no"}`);
|
|
1371
1455
|
if (sessionMigration.rewritten > 0) {
|
package/dist/commands/setup.js
CHANGED
|
@@ -46,6 +46,7 @@ const CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME = "CLAUDE_CODE_DISABLE_NONESS
|
|
|
46
46
|
const CLAUDE_ENV_ENABLE_TELEMETRY_NAME = "CLAUDE_CODE_ENABLE_TELEMETRY";
|
|
47
47
|
const CLAUDE_CODE_EDITOR_ENV_SETTING = "claudeCode.environmentVariables";
|
|
48
48
|
const CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING = "claudeCode.disableLoginPrompt";
|
|
49
|
+
const ANTHROPIC_PROVIDER_ID = "anthropic";
|
|
49
50
|
const MANAGED_EDITOR_TERMINAL_ENV_NAMES = [
|
|
50
51
|
ENV_KEY_NAME,
|
|
51
52
|
CLAUDE_ENV_API_KEY_NAME,
|
|
@@ -70,6 +71,7 @@ const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayState
|
|
|
70
71
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
71
72
|
const EDITOR_TERMINAL_ENV_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "editor-terminal-env.restore.json");
|
|
72
73
|
const CLAUDE_EDITOR_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-editor-settings.restore.json");
|
|
74
|
+
const CLAUDE_DESKTOP_3P_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-desktop-3p.restore.json");
|
|
73
75
|
const CODEX_FEATURE_FLAGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "codex-features.restore.json");
|
|
74
76
|
const ROO_IMPORT_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "roo-code-settings.json");
|
|
75
77
|
const MIGRATION_STATE_FILE = node_path_1.default.join(paths_1.codexDir, "theclawbay.migration.json");
|
|
@@ -607,6 +609,9 @@ function openAiCompatibleProxyUrl(backendUrl) {
|
|
|
607
609
|
function anthropicCompatibleProxyUrl(backendUrl) {
|
|
608
610
|
return `${publicApiOriginForBackendUrl(backendUrl)}/anthropic`;
|
|
609
611
|
}
|
|
612
|
+
function anthropicCompatibleProxyV1Url(backendUrl) {
|
|
613
|
+
return `${anthropicCompatibleProxyUrl(backendUrl)}/v1`;
|
|
614
|
+
}
|
|
610
615
|
function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
611
616
|
if (typeof value !== "string")
|
|
612
617
|
return false;
|
|
@@ -631,6 +636,22 @@ function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
|
631
636
|
return false;
|
|
632
637
|
}
|
|
633
638
|
}
|
|
639
|
+
function isTheClawBayAnthropicCompatibleBaseUrl(value) {
|
|
640
|
+
if (typeof value !== "string")
|
|
641
|
+
return false;
|
|
642
|
+
const normalized = value.trim();
|
|
643
|
+
if (!normalized)
|
|
644
|
+
return false;
|
|
645
|
+
try {
|
|
646
|
+
const parsed = new URL(normalized);
|
|
647
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
648
|
+
const pathname = trimTrailingSlash(parsed.pathname);
|
|
649
|
+
return hostname === THECLAWBAY_CANONICAL_API_HOST && pathname === "/anthropic/v1";
|
|
650
|
+
}
|
|
651
|
+
catch {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
634
655
|
function uniqueStrings(values) {
|
|
635
656
|
const output = [];
|
|
636
657
|
const seen = new Set();
|
|
@@ -681,6 +702,29 @@ function configDirCandidates(appName) {
|
|
|
681
702
|
}
|
|
682
703
|
return uniqueStrings(dirs);
|
|
683
704
|
}
|
|
705
|
+
function claudeDesktop3pConfigPath() {
|
|
706
|
+
if (node_os_1.default.platform() !== "darwin")
|
|
707
|
+
return null;
|
|
708
|
+
return node_path_1.default.join(node_os_1.default.homedir(), "Library", "Application Support", "Claude-3p", "claude_desktop_config.json");
|
|
709
|
+
}
|
|
710
|
+
function claudeDesktopLogCandidates() {
|
|
711
|
+
if (node_os_1.default.platform() !== "darwin")
|
|
712
|
+
return [];
|
|
713
|
+
const home = node_os_1.default.homedir();
|
|
714
|
+
return [
|
|
715
|
+
node_path_1.default.join(home, "Library", "Logs", "Claude-3p", "main.log"),
|
|
716
|
+
node_path_1.default.join(home, "Library", "Logs", "Claude", "main.log"),
|
|
717
|
+
];
|
|
718
|
+
}
|
|
719
|
+
function claudeDesktopAppCandidatePaths() {
|
|
720
|
+
if (node_os_1.default.platform() !== "darwin")
|
|
721
|
+
return [];
|
|
722
|
+
const home = node_os_1.default.homedir();
|
|
723
|
+
return uniqueStrings([
|
|
724
|
+
"/Applications/Claude.app",
|
|
725
|
+
node_path_1.default.join(home, "Applications", "Claude.app"),
|
|
726
|
+
]);
|
|
727
|
+
}
|
|
684
728
|
async function readFileIfExists(filePath) {
|
|
685
729
|
try {
|
|
686
730
|
return await promises_1.default.readFile(filePath, "utf8");
|
|
@@ -1289,6 +1333,33 @@ async function detectClaudeCodeClient() {
|
|
|
1289
1333
|
}
|
|
1290
1334
|
return false;
|
|
1291
1335
|
}
|
|
1336
|
+
async function detectClaudeClient() {
|
|
1337
|
+
if (await detectClaudeCodeClient())
|
|
1338
|
+
return true;
|
|
1339
|
+
if (claudeDesktopAppCandidatePaths().some((candidate) => (0, node_fs_1.existsSync)(candidate)))
|
|
1340
|
+
return true;
|
|
1341
|
+
const configPath = claudeDesktop3pConfigPath();
|
|
1342
|
+
if (!configPath)
|
|
1343
|
+
return false;
|
|
1344
|
+
return (await pathExists(configPath)) || (await pathExists(node_path_1.default.dirname(configPath)));
|
|
1345
|
+
}
|
|
1346
|
+
async function detectOpenCodeClient() {
|
|
1347
|
+
if (hasCommand("opencode"))
|
|
1348
|
+
return true;
|
|
1349
|
+
const candidates = [
|
|
1350
|
+
...resolveOpenCodeConfigTargets(),
|
|
1351
|
+
node_path_1.default.join(node_os_1.default.homedir(), ".opencode.json"),
|
|
1352
|
+
];
|
|
1353
|
+
if (node_os_1.default.platform() === "darwin") {
|
|
1354
|
+
candidates.push("/Applications/OpenCode.app");
|
|
1355
|
+
candidates.push(node_path_1.default.join(node_os_1.default.homedir(), "Applications", "OpenCode.app"));
|
|
1356
|
+
}
|
|
1357
|
+
for (const candidate of candidates) {
|
|
1358
|
+
if (await pathExists(candidate))
|
|
1359
|
+
return true;
|
|
1360
|
+
}
|
|
1361
|
+
return false;
|
|
1362
|
+
}
|
|
1292
1363
|
async function detectClineClient() {
|
|
1293
1364
|
if (hasCommand("cline"))
|
|
1294
1365
|
return true;
|
|
@@ -1976,6 +2047,110 @@ async function persistClaudeEditorSettings(params) {
|
|
|
1976
2047
|
await writeJsonObjectFile(CLAUDE_EDITOR_SETTINGS_STATE_PATH, Array.from(snapshotByPath.values()), 0o600);
|
|
1977
2048
|
return managedPaths;
|
|
1978
2049
|
}
|
|
2050
|
+
function expandClaudeDesktopInferenceModels(modelIds) {
|
|
2051
|
+
const expanded = [];
|
|
2052
|
+
const add = (value) => {
|
|
2053
|
+
const normalized = value.trim();
|
|
2054
|
+
if (!normalized || expanded.includes(normalized))
|
|
2055
|
+
return;
|
|
2056
|
+
expanded.push(normalized);
|
|
2057
|
+
};
|
|
2058
|
+
for (const modelId of modelIds) {
|
|
2059
|
+
add(modelId);
|
|
2060
|
+
const datedMatch = modelId.match(/^(claude-[a-z]+-\d+(?:-\d+)?)-(\d{8})$/);
|
|
2061
|
+
if (datedMatch?.[1])
|
|
2062
|
+
add(datedMatch[1]);
|
|
2063
|
+
const base = datedMatch?.[1] ?? modelId;
|
|
2064
|
+
const dottedMatch = base.match(/^(claude-[a-z]+-\d+)-(\d+)$/);
|
|
2065
|
+
if (dottedMatch?.[1] && dottedMatch?.[2]) {
|
|
2066
|
+
add(`${dottedMatch[1]}.${dottedMatch[2]}`);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
return expanded;
|
|
2070
|
+
}
|
|
2071
|
+
async function discoverClaudeDesktopDeploymentOrganizationUuid(existing) {
|
|
2072
|
+
const enterpriseConfig = objectRecordOr(existing.enterpriseConfig, {});
|
|
2073
|
+
const existingValue = enterpriseConfig.deploymentOrganizationUuid;
|
|
2074
|
+
if (typeof existingValue === "string" && existingValue.trim()) {
|
|
2075
|
+
return existingValue.trim();
|
|
2076
|
+
}
|
|
2077
|
+
const uuidPattern = /\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/i;
|
|
2078
|
+
const logPattern = /(deploymentOrganizationUuid|organizationUuid|organization uuid|org uuid)/i;
|
|
2079
|
+
for (const logPath of claudeDesktopLogCandidates()) {
|
|
2080
|
+
const logRaw = await readFileIfExists(logPath);
|
|
2081
|
+
if (!logRaw)
|
|
2082
|
+
continue;
|
|
2083
|
+
const tail = logRaw.slice(-200000);
|
|
2084
|
+
for (const line of tail.split(/\r?\n/).reverse()) {
|
|
2085
|
+
if (!logPattern.test(line))
|
|
2086
|
+
continue;
|
|
2087
|
+
const match = line.match(uuidPattern);
|
|
2088
|
+
if (match?.[0])
|
|
2089
|
+
return match[0];
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
return null;
|
|
2093
|
+
}
|
|
2094
|
+
async function writeClaudeDesktop3pConfig(params) {
|
|
2095
|
+
const configPath = claudeDesktop3pConfigPath();
|
|
2096
|
+
if (!configPath || params.claudeModels.length === 0)
|
|
2097
|
+
return null;
|
|
2098
|
+
const desktopPresent = claudeDesktopAppCandidatePaths().some((candidate) => (0, node_fs_1.existsSync)(candidate)) ||
|
|
2099
|
+
(await pathExists(configPath)) ||
|
|
2100
|
+
(await pathExists(node_path_1.default.dirname(configPath))) ||
|
|
2101
|
+
claudeDesktopLogCandidates().some((candidate) => (0, node_fs_1.existsSync)(candidate));
|
|
2102
|
+
if (!desktopPresent)
|
|
2103
|
+
return null;
|
|
2104
|
+
let existed = true;
|
|
2105
|
+
let existingRaw = "";
|
|
2106
|
+
try {
|
|
2107
|
+
existingRaw = await promises_1.default.readFile(configPath, "utf8");
|
|
2108
|
+
}
|
|
2109
|
+
catch (error) {
|
|
2110
|
+
const err = error;
|
|
2111
|
+
if (err.code !== "ENOENT")
|
|
2112
|
+
throw error;
|
|
2113
|
+
existed = false;
|
|
2114
|
+
}
|
|
2115
|
+
const existingSnapshotRaw = await readFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
|
|
2116
|
+
if (!existingSnapshotRaw?.trim()) {
|
|
2117
|
+
const snapshot = {
|
|
2118
|
+
version: 1,
|
|
2119
|
+
configPath,
|
|
2120
|
+
existed,
|
|
2121
|
+
previousRaw: existed ? existingRaw : null,
|
|
2122
|
+
};
|
|
2123
|
+
await writeJsonObjectFile(CLAUDE_DESKTOP_3P_STATE_PATH, snapshot, 0o600);
|
|
2124
|
+
}
|
|
2125
|
+
let doc = {};
|
|
2126
|
+
if (existingRaw.trim()) {
|
|
2127
|
+
try {
|
|
2128
|
+
doc = objectRecordOr(JSON.parse(existingRaw), {});
|
|
2129
|
+
}
|
|
2130
|
+
catch {
|
|
2131
|
+
throw new Error(`invalid JSON in Claude Desktop config: ${configPath}`);
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
const enterpriseConfig = objectRecordOr(doc.enterpriseConfig, {});
|
|
2135
|
+
enterpriseConfig.inferenceProvider = "gateway";
|
|
2136
|
+
enterpriseConfig.inferenceGatewayBaseUrl = anthropicCompatibleProxyUrl(params.backendUrl);
|
|
2137
|
+
enterpriseConfig.inferenceGatewayApiKey = params.apiKey;
|
|
2138
|
+
enterpriseConfig.inferenceModels = expandClaudeDesktopInferenceModels(params.claudeModels);
|
|
2139
|
+
enterpriseConfig.isDesktopExtensionEnabled = true;
|
|
2140
|
+
enterpriseConfig.isDesktopExtensionDirectoryEnabled = true;
|
|
2141
|
+
enterpriseConfig.isDesktopExtensionSignatureRequired = false;
|
|
2142
|
+
enterpriseConfig.isLocalDevMcpEnabled = true;
|
|
2143
|
+
enterpriseConfig.isClaudeCodeForDesktopEnabled = true;
|
|
2144
|
+
const deploymentOrganizationUuid = await discoverClaudeDesktopDeploymentOrganizationUuid(doc);
|
|
2145
|
+
if (deploymentOrganizationUuid) {
|
|
2146
|
+
enterpriseConfig.deploymentOrganizationUuid = deploymentOrganizationUuid;
|
|
2147
|
+
}
|
|
2148
|
+
doc.enterpriseConfig = enterpriseConfig;
|
|
2149
|
+
doc.isUsingBuiltInNodeForMcp = true;
|
|
2150
|
+
doc.isDxtAutoUpdatesEnabled = true;
|
|
2151
|
+
await writeJsonObjectFile(configPath, doc);
|
|
2152
|
+
return configPath;
|
|
2153
|
+
}
|
|
1979
2154
|
function runOpenClawConfigCommand(args) {
|
|
1980
2155
|
const run = (0, node_child_process_1.spawnSync)("openclaw", args, {
|
|
1981
2156
|
encoding: "utf8",
|
|
@@ -2117,7 +2292,7 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
2117
2292
|
if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot))
|
|
2118
2293
|
return null;
|
|
2119
2294
|
const obj = snapshot;
|
|
2120
|
-
if (obj.version === 2 && Array.isArray(obj.targets)) {
|
|
2295
|
+
if ((obj.version === 2 || obj.version === 3) && Array.isArray(obj.targets)) {
|
|
2121
2296
|
const targets = [];
|
|
2122
2297
|
for (const entry of obj.targets) {
|
|
2123
2298
|
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
@@ -2134,6 +2309,11 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
2134
2309
|
!Array.isArray(candidate.openAiProvider)
|
|
2135
2310
|
? candidate.openAiProvider
|
|
2136
2311
|
: null,
|
|
2312
|
+
anthropicProvider: typeof candidate.anthropicProvider === "object" &&
|
|
2313
|
+
candidate.anthropicProvider !== null &&
|
|
2314
|
+
!Array.isArray(candidate.anthropicProvider)
|
|
2315
|
+
? candidate.anthropicProvider
|
|
2316
|
+
: null,
|
|
2137
2317
|
model: typeof candidate.model === "string" ? candidate.model : null,
|
|
2138
2318
|
schema: typeof candidate.schema === "string" ? candidate.schema : null,
|
|
2139
2319
|
plugin: "plugin" in candidate
|
|
@@ -2143,13 +2323,13 @@ function normalizeOpenCodeRestoreSnapshot(snapshot, fallbackConfigPath) {
|
|
|
2143
2323
|
: undefined,
|
|
2144
2324
|
});
|
|
2145
2325
|
}
|
|
2146
|
-
return { version:
|
|
2326
|
+
return { version: 3, targets };
|
|
2147
2327
|
}
|
|
2148
2328
|
const looksLikeV1 = "openAiProvider" in obj || "model" in obj || "schema" in obj;
|
|
2149
2329
|
if (!looksLikeV1)
|
|
2150
2330
|
return null;
|
|
2151
2331
|
return {
|
|
2152
|
-
version:
|
|
2332
|
+
version: 3,
|
|
2153
2333
|
targets: [
|
|
2154
2334
|
{
|
|
2155
2335
|
configPath: fallbackConfigPath,
|
|
@@ -2240,6 +2420,10 @@ function isManagedOpenCodeProvider(provider) {
|
|
|
2240
2420
|
const options = objectRecordOr(provider.options, {});
|
|
2241
2421
|
return isTheClawBayOpenAiCompatibleBaseUrl(options.baseURL);
|
|
2242
2422
|
}
|
|
2423
|
+
function isManagedOpenCodeAnthropicProvider(provider) {
|
|
2424
|
+
const options = objectRecordOr(provider.options, {});
|
|
2425
|
+
return isTheClawBayAnthropicCompatibleBaseUrl(options.baseURL);
|
|
2426
|
+
}
|
|
2243
2427
|
function isManagedOpenCodeModel(value, supportedModelIds) {
|
|
2244
2428
|
if (typeof value !== "string")
|
|
2245
2429
|
return false;
|
|
@@ -2252,7 +2436,7 @@ async function writeOpenCodeFamilyConfig(params) {
|
|
|
2252
2436
|
const fallbackConfigPath = normalizedConfigPaths[0] ?? node_path_1.default.join(xdgConfigHomeDir(), "opencode", "opencode.json");
|
|
2253
2437
|
const restoreState = (await readOpenCodeRestoreSnapshot(params.restoreStatePath, fallbackConfigPath)) ??
|
|
2254
2438
|
{
|
|
2255
|
-
version:
|
|
2439
|
+
version: 3,
|
|
2256
2440
|
targets: [],
|
|
2257
2441
|
};
|
|
2258
2442
|
const supportedModelIds = new Set(params.models.map((entry) => entry.id).filter(Boolean));
|
|
@@ -2291,12 +2475,14 @@ async function writeOpenCodeFamilyConfig(params) {
|
|
|
2291
2475
|
}
|
|
2292
2476
|
const providerRoot = objectRecordOr(doc.provider, {});
|
|
2293
2477
|
const openAiProvider = objectRecordOr(providerRoot[OPENAI_PROVIDER_ID], {});
|
|
2478
|
+
const anthropicProvider = objectRecordOr(providerRoot[ANTHROPIC_PROVIDER_ID], {});
|
|
2294
2479
|
const alreadyManaged = isManagedOpenCodeProvider(openAiProvider) && isManagedOpenCodeModel(doc.model, supportedModelIds);
|
|
2295
2480
|
if (!alreadyManaged && !restoreHasTarget(configPath)) {
|
|
2296
2481
|
restoreState.targets.push({
|
|
2297
2482
|
configPath,
|
|
2298
2483
|
existed,
|
|
2299
2484
|
openAiProvider: Object.keys(openAiProvider).length > 0 ? openAiProvider : null,
|
|
2485
|
+
anthropicProvider: Object.keys(anthropicProvider).length > 0 ? anthropicProvider : null,
|
|
2300
2486
|
model: typeof doc.model === "string" && !doc.model.startsWith(`${DEFAULT_PROVIDER_ID}/`)
|
|
2301
2487
|
? doc.model
|
|
2302
2488
|
: null,
|
|
@@ -2324,6 +2510,18 @@ async function writeOpenCodeFamilyConfig(params) {
|
|
|
2324
2510
|
delete managedOpenAiProvider.blacklist;
|
|
2325
2511
|
}
|
|
2326
2512
|
providerRoot[OPENAI_PROVIDER_ID] = managedOpenAiProvider;
|
|
2513
|
+
if ((params.claudeModels?.length ?? 0) > 0) {
|
|
2514
|
+
const managedAnthropicProvider = objectRecordOr(providerRoot[ANTHROPIC_PROVIDER_ID], {});
|
|
2515
|
+
const anthropicOptions = objectRecordOr(managedAnthropicProvider.options, {});
|
|
2516
|
+
anthropicOptions.baseURL = anthropicCompatibleProxyV1Url(params.backendUrl);
|
|
2517
|
+
anthropicOptions.apiKey = params.apiKey;
|
|
2518
|
+
managedAnthropicProvider.options = anthropicOptions;
|
|
2519
|
+
managedAnthropicProvider.whitelist = uniqueStrings(params.claudeModels ?? []);
|
|
2520
|
+
if ("blacklist" in managedAnthropicProvider) {
|
|
2521
|
+
delete managedAnthropicProvider.blacklist;
|
|
2522
|
+
}
|
|
2523
|
+
providerRoot[ANTHROPIC_PROVIDER_ID] = managedAnthropicProvider;
|
|
2524
|
+
}
|
|
2327
2525
|
if (DEFAULT_PROVIDER_ID in providerRoot) {
|
|
2328
2526
|
delete providerRoot[DEFAULT_PROVIDER_ID];
|
|
2329
2527
|
}
|
|
@@ -2429,12 +2627,13 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2429
2627
|
managed?.backendUrl ??
|
|
2430
2628
|
DEFAULT_BACKEND_URL;
|
|
2431
2629
|
const backendUrl = normalizeUrl(backendRaw, "--backend");
|
|
2432
|
-
const [codexDetected, claudeDetected, continueDetected, clineDetected, gsdDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected] = await Promise.all([
|
|
2630
|
+
const [codexDetected, claudeDetected, continueDetected, clineDetected, gsdDetected, openCodeDetected, kiloDetected, rooDetected, traeDetected, aiderDetected, zoDetected] = await Promise.all([
|
|
2433
2631
|
detectCodexClient(),
|
|
2434
|
-
|
|
2632
|
+
detectClaudeClient(),
|
|
2435
2633
|
detectContinueClient(),
|
|
2436
2634
|
detectClineClient(),
|
|
2437
2635
|
detectGsdClient(),
|
|
2636
|
+
detectOpenCodeClient(),
|
|
2438
2637
|
detectKiloClient(),
|
|
2439
2638
|
detectRooClient(),
|
|
2440
2639
|
detectTraeClient(),
|
|
@@ -2453,8 +2652,8 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2453
2652
|
},
|
|
2454
2653
|
{
|
|
2455
2654
|
id: "claude",
|
|
2456
|
-
label: "Claude Code
|
|
2457
|
-
summaryLabel: "Claude
|
|
2655
|
+
label: "Claude Code / Claude Desktop",
|
|
2656
|
+
summaryLabel: "Claude",
|
|
2458
2657
|
detected: claudeDetected,
|
|
2459
2658
|
recommended: true,
|
|
2460
2659
|
icon: "✳",
|
|
@@ -2500,7 +2699,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2500
2699
|
id: "opencode",
|
|
2501
2700
|
label: "OpenCode",
|
|
2502
2701
|
summaryLabel: "OpenCode",
|
|
2503
|
-
detected:
|
|
2702
|
+
detected: openCodeDetected,
|
|
2504
2703
|
recommended: true,
|
|
2505
2704
|
icon: "⌘",
|
|
2506
2705
|
siteUrl: "https://opencode.ai",
|
|
@@ -2601,6 +2800,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2601
2800
|
let updatedVsCodeEnvFiles = [];
|
|
2602
2801
|
let updatedEditorTerminalSettings = [];
|
|
2603
2802
|
let updatedClaudeEditorSettings = [];
|
|
2803
|
+
let claudeDesktop3pConfigPathManaged = null;
|
|
2604
2804
|
let sessionMigration = null;
|
|
2605
2805
|
let authSeed = null;
|
|
2606
2806
|
let authSeedCleanup = null;
|
|
@@ -2668,6 +2868,11 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2668
2868
|
backendUrl,
|
|
2669
2869
|
claudeEnabled: claudeEnvEnabled,
|
|
2670
2870
|
});
|
|
2871
|
+
claudeDesktop3pConfigPathManaged = await writeClaudeDesktop3pConfig({
|
|
2872
|
+
backendUrl,
|
|
2873
|
+
apiKey: authCredential,
|
|
2874
|
+
claudeModels: claudeAccess?.enabled ? claudeAccess.models : [],
|
|
2875
|
+
});
|
|
2671
2876
|
}
|
|
2672
2877
|
}
|
|
2673
2878
|
if (selectedSetupClients.has("codex")) {
|
|
@@ -2744,6 +2949,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2744
2949
|
backendUrl,
|
|
2745
2950
|
model: resolved?.model ?? DEFAULT_CODEX_MODEL,
|
|
2746
2951
|
models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
|
|
2952
|
+
claudeModels: claudeAccess?.enabled ? claudeAccess.models : [],
|
|
2747
2953
|
apiKey: authCredential,
|
|
2748
2954
|
});
|
|
2749
2955
|
}
|
|
@@ -2805,6 +3011,9 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2805
3011
|
summaryNotes.add(resolved.note);
|
|
2806
3012
|
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2807
3013
|
summaryNotes.add("Claude Code: exported ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY, CLAUDE_CODE_SIMPLE=1, disabled nonessential traffic, and disabled telemetry.");
|
|
3014
|
+
if (claudeDesktop3pConfigPathManaged) {
|
|
3015
|
+
summaryNotes.add("Claude Desktop: configured hidden Claude-3p gateway mode with the /anthropic base URL for The Claw Bay.");
|
|
3016
|
+
}
|
|
2808
3017
|
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.");
|
|
2809
3018
|
}
|
|
2810
3019
|
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
@@ -2861,6 +3070,9 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2861
3070
|
this.log(resolved.note);
|
|
2862
3071
|
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2863
3072
|
this.log(`- Claude Code base URL: ${anthropicCompatibleProxyUrl(backendUrl)}`);
|
|
3073
|
+
if (claudeDesktop3pConfigPathManaged) {
|
|
3074
|
+
this.log(`- Claude Desktop 3P config: ${claudeDesktop3pConfigPathManaged}`);
|
|
3075
|
+
}
|
|
2864
3076
|
}
|
|
2865
3077
|
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
2866
3078
|
this.log(`- Claude Code: ${claudeAccess.note}`);
|
|
@@ -2976,9 +3188,9 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2976
3188
|
else {
|
|
2977
3189
|
this.log("- OpenClaw: not detected (skipped)");
|
|
2978
3190
|
}
|
|
2979
|
-
const openCodeDetected = setupClients.find((client) => client.id === "opencode")?.detected ?? false;
|
|
2980
3191
|
if (selectedSetupClients.has("opencode")) {
|
|
2981
3192
|
this.log(`- OpenCode: configured (${openCodeConfigPaths.join(", ")})`);
|
|
3193
|
+
this.log("- OpenCode note: configured the OpenAI-compatible /v1 route and, when Claude access is available, the Anthropic-compatible /anthropic/v1 route.");
|
|
2982
3194
|
this.log("- OpenCode note: plain OpenAI-compatible config is preferred. If you add a quota/auth plugin manually, use /api/codex-auth/v1/quota?format=legacy_codex for legacy Codex-style quota responses.");
|
|
2983
3195
|
const openCodeProjectConfig = findOpenCodeProjectConfigFile();
|
|
2984
3196
|
const openCodeConfigEnv = process.env.OPENCODE_CONFIG?.trim() || "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theclawbay",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.57",
|
|
4
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": {
|