theclawbay 0.3.54 → 0.3.56
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 +268 -3
- package/dist/commands/setup.js +335 -14
- package/package.json +1 -1
package/dist/commands/logout.js
CHANGED
|
@@ -27,6 +27,13 @@ const SHELL_START = "# theclawbay-shell-managed:start";
|
|
|
27
27
|
const SHELL_END = "# theclawbay-shell-managed:end";
|
|
28
28
|
const ENV_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "env");
|
|
29
29
|
const ENV_KEY_NAME = "THECLAWBAY_API_KEY";
|
|
30
|
+
const CLAUDE_ENV_API_KEY_NAME = "ANTHROPIC_API_KEY";
|
|
31
|
+
const CLAUDE_ENV_BASE_URL_NAME = "ANTHROPIC_BASE_URL";
|
|
32
|
+
const CLAUDE_ENV_SIMPLE_MODE_NAME = "CLAUDE_CODE_SIMPLE";
|
|
33
|
+
const CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME = "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC";
|
|
34
|
+
const CLAUDE_ENV_ENABLE_TELEMETRY_NAME = "CLAUDE_CODE_ENABLE_TELEMETRY";
|
|
35
|
+
const CLAUDE_CODE_EDITOR_ENV_SETTING = "claudeCode.environmentVariables";
|
|
36
|
+
const CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING = "claudeCode.disableLoginPrompt";
|
|
30
37
|
const CONTINUE_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".continue", "config.yaml");
|
|
31
38
|
const CLINE_GLOBAL_STATE_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "globalState.json");
|
|
32
39
|
const CLINE_SECRETS_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "secrets.json");
|
|
@@ -40,6 +47,9 @@ const GSD_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateD
|
|
|
40
47
|
const OPENCODE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "opencode.restore.json");
|
|
41
48
|
const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "kilo.restore.json");
|
|
42
49
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
50
|
+
const EDITOR_TERMINAL_ENV_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "editor-terminal-env.restore.json");
|
|
51
|
+
const CLAUDE_EDITOR_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-editor-settings.restore.json");
|
|
52
|
+
const CODEX_FEATURE_FLAGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "codex-features.restore.json");
|
|
43
53
|
const ROO_IMPORT_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "roo-code-settings.json");
|
|
44
54
|
const MIGRATION_STATE_FILE = node_path_1.default.join(paths_1.codexDir, "theclawbay.migration.json");
|
|
45
55
|
const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set([
|
|
@@ -126,6 +136,118 @@ function removeTopLevelProviderSelection(source) {
|
|
|
126
136
|
}
|
|
127
137
|
return `${filtered.join("\n").trimEnd()}\n`;
|
|
128
138
|
}
|
|
139
|
+
function removeTopLevelKeyLineIf(source, key, shouldRemove) {
|
|
140
|
+
const lines = source.split(/\r?\n/);
|
|
141
|
+
const filtered = [];
|
|
142
|
+
let removed = false;
|
|
143
|
+
for (let i = 0; i < lines.length; i++) {
|
|
144
|
+
const line = lines[i] ?? "";
|
|
145
|
+
if (/^\s*\[/.test(line)) {
|
|
146
|
+
filtered.push(...lines.slice(i));
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
if (/^\s*#/.test(line) || !line.trim()) {
|
|
150
|
+
filtered.push(line);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const match = line.match(new RegExp(`^\\s*${key}\\s*=\\s*\"([^\"]*)\"\\s*$`));
|
|
154
|
+
if (!match) {
|
|
155
|
+
filtered.push(line);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (shouldRemove(match[1] ?? "")) {
|
|
159
|
+
removed = true;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
filtered.push(line);
|
|
163
|
+
}
|
|
164
|
+
if (!removed)
|
|
165
|
+
return source;
|
|
166
|
+
return `${filtered.join("\n").trimEnd()}\n`;
|
|
167
|
+
}
|
|
168
|
+
function setTopLevelTableKey(source, tableName, key, tomlValue) {
|
|
169
|
+
const header = `[${tableName}]`;
|
|
170
|
+
const lines = source.split(/\r?\n/);
|
|
171
|
+
let tableStart = -1;
|
|
172
|
+
for (let i = 0; i < lines.length; i++) {
|
|
173
|
+
if ((lines[i] ?? "").trim() === header) {
|
|
174
|
+
tableStart = i;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (tableStart < 0) {
|
|
179
|
+
const block = `${header}\n${key} = ${tomlValue}\n`;
|
|
180
|
+
if (!source.trim())
|
|
181
|
+
return block;
|
|
182
|
+
return `${source.trimEnd()}\n\n${block}`;
|
|
183
|
+
}
|
|
184
|
+
let tableEnd = lines.length;
|
|
185
|
+
for (let i = tableStart + 1; i < lines.length; i++) {
|
|
186
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[i] ?? "")) {
|
|
187
|
+
tableEnd = i;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (let i = tableStart + 1; i < tableEnd; i++) {
|
|
192
|
+
const line = lines[i] ?? "";
|
|
193
|
+
if (/^\s*#/.test(line))
|
|
194
|
+
continue;
|
|
195
|
+
if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
|
|
196
|
+
lines[i] = `${key} = ${tomlValue}`;
|
|
197
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
lines.splice(tableEnd, 0, `${key} = ${tomlValue}`);
|
|
201
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
202
|
+
}
|
|
203
|
+
function removeTopLevelTableKey(source, tableName, key) {
|
|
204
|
+
const header = `[${tableName}]`;
|
|
205
|
+
const lines = source.split(/\r?\n/);
|
|
206
|
+
let tableStart = -1;
|
|
207
|
+
for (let i = 0; i < lines.length; i++) {
|
|
208
|
+
if ((lines[i] ?? "").trim() === header) {
|
|
209
|
+
tableStart = i;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (tableStart < 0)
|
|
214
|
+
return source;
|
|
215
|
+
let tableEnd = lines.length;
|
|
216
|
+
for (let i = tableStart + 1; i < lines.length; i++) {
|
|
217
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[i] ?? "")) {
|
|
218
|
+
tableEnd = i;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
let removed = false;
|
|
223
|
+
const nextLines = [...lines];
|
|
224
|
+
for (let i = tableStart + 1; i < tableEnd; i++) {
|
|
225
|
+
const line = nextLines[i] ?? "";
|
|
226
|
+
if (/^\s*#/.test(line))
|
|
227
|
+
continue;
|
|
228
|
+
if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
|
|
229
|
+
nextLines.splice(i, 1);
|
|
230
|
+
removed = true;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!removed)
|
|
235
|
+
return source;
|
|
236
|
+
return `${nextLines.join("\n").trimEnd()}\n`;
|
|
237
|
+
}
|
|
238
|
+
function isTheClawBayChatgptBaseUrl(value) {
|
|
239
|
+
const trimmed = value.trim().replace(/\/+$/g, "");
|
|
240
|
+
if (!trimmed)
|
|
241
|
+
return false;
|
|
242
|
+
try {
|
|
243
|
+
const parsed = new URL(trimmed);
|
|
244
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
245
|
+
return hostname === THECLAWBAY_CANONICAL_API_HOST || THECLAWBAY_WEBSITE_HOSTS.has(hostname);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
129
251
|
async function readFileIfExists(filePath) {
|
|
130
252
|
try {
|
|
131
253
|
return await promises_1.default.readFile(filePath, "utf8");
|
|
@@ -321,6 +443,7 @@ async function cleanupCodexConfig() {
|
|
|
321
443
|
next = removeManagedBlock(next, MANAGED_START, MANAGED_END);
|
|
322
444
|
next = removeProviderTable(next, DEFAULT_PROVIDER_ID);
|
|
323
445
|
next = removeTopLevelProviderSelection(next);
|
|
446
|
+
next = removeTopLevelKeyLineIf(next, "chatgpt_base_url", isTheClawBayChatgptBaseUrl);
|
|
324
447
|
return writeIfChanged(configPath, next, existing);
|
|
325
448
|
}
|
|
326
449
|
async function cleanupContinueConfig() {
|
|
@@ -675,6 +798,131 @@ async function cleanupVsCodeHooks() {
|
|
|
675
798
|
}
|
|
676
799
|
return updated;
|
|
677
800
|
}
|
|
801
|
+
function terminalIntegratedEnvSettingsKey() {
|
|
802
|
+
if (node_os_1.default.platform() === "darwin")
|
|
803
|
+
return "terminal.integrated.env.osx";
|
|
804
|
+
if (node_os_1.default.platform() === "win32")
|
|
805
|
+
return "terminal.integrated.env.windows";
|
|
806
|
+
return "terminal.integrated.env.linux";
|
|
807
|
+
}
|
|
808
|
+
async function cleanupEditorTerminalEnvSettings() {
|
|
809
|
+
const snapshotRaw = await readFileIfExists(EDITOR_TERMINAL_ENV_STATE_PATH);
|
|
810
|
+
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
811
|
+
return [];
|
|
812
|
+
let entries = [];
|
|
813
|
+
try {
|
|
814
|
+
entries = JSON.parse(snapshotRaw);
|
|
815
|
+
}
|
|
816
|
+
catch {
|
|
817
|
+
return [];
|
|
818
|
+
}
|
|
819
|
+
const settingsKey = terminalIntegratedEnvSettingsKey();
|
|
820
|
+
const updated = [];
|
|
821
|
+
for (const entry of entries) {
|
|
822
|
+
const settings = await readJsonObjectFile(entry.settingsPath);
|
|
823
|
+
if (!entry.hadKey) {
|
|
824
|
+
if (Object.prototype.hasOwnProperty.call(settings, settingsKey)) {
|
|
825
|
+
delete settings[settingsKey];
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
else {
|
|
829
|
+
settings[settingsKey] = entry.previousValue;
|
|
830
|
+
}
|
|
831
|
+
if (entry.existed || Object.keys(settings).length > 0) {
|
|
832
|
+
const next = `${JSON.stringify(settings, null, 2)}\n`;
|
|
833
|
+
const existing = await readFileIfExists(entry.settingsPath);
|
|
834
|
+
if (existing !== next) {
|
|
835
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(entry.settingsPath), { recursive: true });
|
|
836
|
+
await promises_1.default.writeFile(entry.settingsPath, next, "utf8");
|
|
837
|
+
updated.push(entry.settingsPath);
|
|
838
|
+
}
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
if (await removeFileIfExists(entry.settingsPath)) {
|
|
842
|
+
updated.push(entry.settingsPath);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
await removeFileIfExists(EDITOR_TERMINAL_ENV_STATE_PATH);
|
|
846
|
+
return updated;
|
|
847
|
+
}
|
|
848
|
+
async function cleanupClaudeEditorSettings() {
|
|
849
|
+
const snapshotRaw = await readFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
|
|
850
|
+
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
851
|
+
return [];
|
|
852
|
+
let entries = [];
|
|
853
|
+
try {
|
|
854
|
+
entries = JSON.parse(snapshotRaw);
|
|
855
|
+
}
|
|
856
|
+
catch {
|
|
857
|
+
return [];
|
|
858
|
+
}
|
|
859
|
+
const updated = [];
|
|
860
|
+
for (const entry of entries) {
|
|
861
|
+
const settings = await readJsonObjectFile(entry.settingsPath);
|
|
862
|
+
if (!entry.envHadKey) {
|
|
863
|
+
delete settings[CLAUDE_CODE_EDITOR_ENV_SETTING];
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
settings[CLAUDE_CODE_EDITOR_ENV_SETTING] = entry.envPreviousValue;
|
|
867
|
+
}
|
|
868
|
+
if (!entry.disableLoginPromptHadKey) {
|
|
869
|
+
delete settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING];
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING] = entry.disableLoginPromptPreviousValue;
|
|
873
|
+
}
|
|
874
|
+
if (entry.existed || Object.keys(settings).length > 0) {
|
|
875
|
+
const next = `${JSON.stringify(settings, null, 2)}\n`;
|
|
876
|
+
const existing = await readFileIfExists(entry.settingsPath);
|
|
877
|
+
if (existing !== next) {
|
|
878
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(entry.settingsPath), { recursive: true });
|
|
879
|
+
await promises_1.default.writeFile(entry.settingsPath, next, "utf8");
|
|
880
|
+
updated.push(entry.settingsPath);
|
|
881
|
+
}
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
if (await removeFileIfExists(entry.settingsPath)) {
|
|
885
|
+
updated.push(entry.settingsPath);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
await removeFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
|
|
889
|
+
return updated;
|
|
890
|
+
}
|
|
891
|
+
async function cleanupCodexFeatureFlags() {
|
|
892
|
+
const snapshotRaw = await readFileIfExists(CODEX_FEATURE_FLAGS_STATE_PATH);
|
|
893
|
+
if (snapshotRaw === null || !snapshotRaw.trim())
|
|
894
|
+
return false;
|
|
895
|
+
let snapshot = null;
|
|
896
|
+
try {
|
|
897
|
+
snapshot = JSON.parse(snapshotRaw);
|
|
898
|
+
}
|
|
899
|
+
catch {
|
|
900
|
+
snapshot = null;
|
|
901
|
+
}
|
|
902
|
+
if (!snapshot)
|
|
903
|
+
return false;
|
|
904
|
+
const configPath = node_path_1.default.join(paths_1.codexDir, "config.toml");
|
|
905
|
+
const existing = await readFileIfExists(configPath);
|
|
906
|
+
if (existing === null) {
|
|
907
|
+
await removeFileIfExists(CODEX_FEATURE_FLAGS_STATE_PATH);
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
let next = existing;
|
|
911
|
+
if (snapshot.appsHadKey && snapshot.appsPreviousValue !== null) {
|
|
912
|
+
next = setTopLevelTableKey(next, "features", "apps", snapshot.appsPreviousValue);
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
next = removeTopLevelTableKey(next, "features", "apps");
|
|
916
|
+
}
|
|
917
|
+
if (snapshot.appsMcpGatewayHadKey && snapshot.appsMcpGatewayPreviousValue !== null) {
|
|
918
|
+
next = setTopLevelTableKey(next, "features", "apps_mcp_gateway", snapshot.appsMcpGatewayPreviousValue);
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
next = removeTopLevelTableKey(next, "features", "apps_mcp_gateway");
|
|
922
|
+
}
|
|
923
|
+
await removeFileIfExists(CODEX_FEATURE_FLAGS_STATE_PATH);
|
|
924
|
+
return writeIfChanged(configPath, next, existing);
|
|
925
|
+
}
|
|
678
926
|
async function cleanupOpenClawConfig() {
|
|
679
927
|
const configPath = node_path_1.default.join(node_os_1.default.homedir(), ".openclaw", "openclaw.json");
|
|
680
928
|
const existingRaw = await readFileIfExists(configPath);
|
|
@@ -937,7 +1185,10 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
937
1185
|
let updatedShellFiles = [];
|
|
938
1186
|
let updatedPowerShellProfiles = [];
|
|
939
1187
|
let updatedVsCodeHooks = [];
|
|
1188
|
+
let updatedEditorTerminalSettings = [];
|
|
1189
|
+
let updatedClaudeEditorSettings = [];
|
|
940
1190
|
let updatedCodexConfig = false;
|
|
1191
|
+
let updatedCodexFeatures = false;
|
|
941
1192
|
let updatedContinueConfig = false;
|
|
942
1193
|
let updatedClineConfig = false;
|
|
943
1194
|
let updatedGsdConfig = false;
|
|
@@ -986,8 +1237,11 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
986
1237
|
updatedShellFiles = await cleanupShellFiles();
|
|
987
1238
|
updatedPowerShellProfiles = await cleanupPowerShellProfiles();
|
|
988
1239
|
updatedVsCodeHooks = await cleanupVsCodeHooks();
|
|
1240
|
+
updatedEditorTerminalSettings = await cleanupEditorTerminalEnvSettings();
|
|
1241
|
+
updatedClaudeEditorSettings = await cleanupClaudeEditorSettings();
|
|
989
1242
|
progress.update("Reverting Codex");
|
|
990
1243
|
updatedCodexConfig = await cleanupCodexConfig();
|
|
1244
|
+
updatedCodexFeatures = await cleanupCodexFeatureFlags();
|
|
991
1245
|
sessionMigration = await (0, codex_history_migration_1.migrateSessionProviders)({
|
|
992
1246
|
codexHome: paths_1.codexDir,
|
|
993
1247
|
migrationStateFile: MIGRATION_STATE_FILE,
|
|
@@ -1028,8 +1282,11 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1028
1282
|
throw error;
|
|
1029
1283
|
}
|
|
1030
1284
|
delete process.env[ENV_KEY_NAME];
|
|
1031
|
-
delete process.env
|
|
1032
|
-
delete process.env
|
|
1285
|
+
delete process.env[CLAUDE_ENV_API_KEY_NAME];
|
|
1286
|
+
delete process.env[CLAUDE_ENV_BASE_URL_NAME];
|
|
1287
|
+
delete process.env[CLAUDE_ENV_SIMPLE_MODE_NAME];
|
|
1288
|
+
delete process.env[CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME];
|
|
1289
|
+
delete process.env[CLAUDE_ENV_ENABLE_TELEMETRY_NAME];
|
|
1033
1290
|
if (!debugOutput && process.stdout.isTTY) {
|
|
1034
1291
|
progress.succeed("Logout complete");
|
|
1035
1292
|
}
|
|
@@ -1038,7 +1295,10 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1038
1295
|
}
|
|
1039
1296
|
const revertedTargets = [];
|
|
1040
1297
|
const codexChanged = updatedCodexConfig ||
|
|
1298
|
+
updatedCodexFeatures ||
|
|
1041
1299
|
updatedVsCodeHooks.length > 0 ||
|
|
1300
|
+
updatedEditorTerminalSettings.length > 0 ||
|
|
1301
|
+
updatedClaudeEditorSettings.length > 0 ||
|
|
1042
1302
|
sessionMigration.rewritten > 0 ||
|
|
1043
1303
|
sessionMigration.retimed > 0 ||
|
|
1044
1304
|
stateDbMigration.updated > 0 ||
|
|
@@ -1086,7 +1346,9 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1086
1346
|
removedEnvFile ||
|
|
1087
1347
|
updatedShellFiles.length > 0 ||
|
|
1088
1348
|
updatedPowerShellProfiles.length > 0 ||
|
|
1089
|
-
updatedVsCodeHooks.length > 0
|
|
1349
|
+
updatedVsCodeHooks.length > 0 ||
|
|
1350
|
+
updatedEditorTerminalSettings.length > 0 ||
|
|
1351
|
+
updatedClaudeEditorSettings.length > 0,
|
|
1090
1352
|
notes: Array.from(summaryNotes),
|
|
1091
1353
|
});
|
|
1092
1354
|
return;
|
|
@@ -1102,7 +1364,10 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1102
1364
|
this.log(`- Shell profiles updated: ${updatedShellFiles.length ? updatedShellFiles.join(", ") : "none"}`);
|
|
1103
1365
|
this.log(`- PowerShell profiles updated: ${updatedPowerShellProfiles.length ? updatedPowerShellProfiles.join(", ") : "none"}`);
|
|
1104
1366
|
this.log(`- VS Code env hooks updated: ${updatedVsCodeHooks.length ? updatedVsCodeHooks.join(", ") : "none"}`);
|
|
1367
|
+
this.log(`- Editor terminal env updated: ${updatedEditorTerminalSettings.length ? updatedEditorTerminalSettings.join(", ") : "none"}`);
|
|
1368
|
+
this.log(`- Claude editor settings updated: ${updatedClaudeEditorSettings.length ? updatedClaudeEditorSettings.join(", ") : "none"}`);
|
|
1105
1369
|
this.log(`- Codex config cleaned: ${updatedCodexConfig ? "yes" : "no"}`);
|
|
1370
|
+
this.log(`- Codex Apps feature flags restored: ${updatedCodexFeatures ? "yes" : "no"}`);
|
|
1106
1371
|
if (sessionMigration.rewritten > 0) {
|
|
1107
1372
|
this.log(`- Conversations: updated ${sessionMigration.rewritten}/${sessionMigration.scanned} local sessions for cross-provider visibility.`);
|
|
1108
1373
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -42,6 +42,18 @@ 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
44
|
const CLAUDE_ENV_SIMPLE_MODE_NAME = "CLAUDE_CODE_SIMPLE";
|
|
45
|
+
const CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME = "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC";
|
|
46
|
+
const CLAUDE_ENV_ENABLE_TELEMETRY_NAME = "CLAUDE_CODE_ENABLE_TELEMETRY";
|
|
47
|
+
const CLAUDE_CODE_EDITOR_ENV_SETTING = "claudeCode.environmentVariables";
|
|
48
|
+
const CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING = "claudeCode.disableLoginPrompt";
|
|
49
|
+
const MANAGED_EDITOR_TERMINAL_ENV_NAMES = [
|
|
50
|
+
ENV_KEY_NAME,
|
|
51
|
+
CLAUDE_ENV_API_KEY_NAME,
|
|
52
|
+
CLAUDE_ENV_BASE_URL_NAME,
|
|
53
|
+
CLAUDE_ENV_SIMPLE_MODE_NAME,
|
|
54
|
+
CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME,
|
|
55
|
+
CLAUDE_ENV_ENABLE_TELEMETRY_NAME,
|
|
56
|
+
];
|
|
45
57
|
const ENV_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "env");
|
|
46
58
|
const CONTINUE_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".continue", "config.yaml");
|
|
47
59
|
const CLINE_GLOBAL_STATE_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "globalState.json");
|
|
@@ -56,6 +68,9 @@ const GSD_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateD
|
|
|
56
68
|
const OPENCODE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "opencode.restore.json");
|
|
57
69
|
const KILO_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "kilo.restore.json");
|
|
58
70
|
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
71
|
+
const EDITOR_TERMINAL_ENV_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "editor-terminal-env.restore.json");
|
|
72
|
+
const CLAUDE_EDITOR_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "claude-editor-settings.restore.json");
|
|
73
|
+
const CODEX_FEATURE_FLAGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "codex-features.restore.json");
|
|
59
74
|
const ROO_IMPORT_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "roo-code-settings.json");
|
|
60
75
|
const MIGRATION_STATE_FILE = node_path_1.default.join(paths_1.codexDir, "theclawbay.migration.json");
|
|
61
76
|
const MANAGED_START = "# theclawbay-managed:start";
|
|
@@ -455,6 +470,99 @@ function upsertFirstKeyLine(source, key, tomlValue) {
|
|
|
455
470
|
}
|
|
456
471
|
return `${`${key} = ${tomlValue}\n${source}`.trimEnd()}\n`;
|
|
457
472
|
}
|
|
473
|
+
function parseTomlScalarValue(line) {
|
|
474
|
+
const match = line.match(/^\s*[A-Za-z0-9_.-]+\s*=\s*(.+?)\s*$/);
|
|
475
|
+
return match?.[1]?.trim() ?? null;
|
|
476
|
+
}
|
|
477
|
+
function upsertTopLevelTableKey(source, tableName, key, tomlValue) {
|
|
478
|
+
const header = `[${tableName}]`;
|
|
479
|
+
const lines = source.split(/\r?\n/);
|
|
480
|
+
let tableStart = -1;
|
|
481
|
+
for (let i = 0; i < lines.length; i++) {
|
|
482
|
+
if ((lines[i] ?? "").trim() === header) {
|
|
483
|
+
tableStart = i;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (tableStart < 0) {
|
|
488
|
+
const block = `${header}\n${key} = ${tomlValue}\n`;
|
|
489
|
+
if (!source.trim())
|
|
490
|
+
return block;
|
|
491
|
+
return `${source.trimEnd()}\n\n${block}`;
|
|
492
|
+
}
|
|
493
|
+
let tableEnd = lines.length;
|
|
494
|
+
for (let i = tableStart + 1; i < lines.length; i++) {
|
|
495
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[i] ?? "")) {
|
|
496
|
+
tableEnd = i;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
for (let i = tableStart + 1; i < tableEnd; i++) {
|
|
501
|
+
const line = lines[i] ?? "";
|
|
502
|
+
if (/^\s*#/.test(line))
|
|
503
|
+
continue;
|
|
504
|
+
if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
|
|
505
|
+
lines[i] = `${key} = ${tomlValue}`;
|
|
506
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
lines.splice(tableEnd, 0, `${key} = ${tomlValue}`);
|
|
510
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
511
|
+
}
|
|
512
|
+
function readTopLevelTableKeyValue(source, tableName, key) {
|
|
513
|
+
const header = `[${tableName}]`;
|
|
514
|
+
const lines = source.split(/\r?\n/);
|
|
515
|
+
let tableStart = -1;
|
|
516
|
+
for (let i = 0; i < lines.length; i++) {
|
|
517
|
+
if ((lines[i] ?? "").trim() === header) {
|
|
518
|
+
tableStart = i;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (tableStart < 0) {
|
|
523
|
+
return { hadTable: false, hadKey: false, value: null };
|
|
524
|
+
}
|
|
525
|
+
for (let i = tableStart + 1; i < lines.length; i++) {
|
|
526
|
+
const line = lines[i] ?? "";
|
|
527
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(line))
|
|
528
|
+
break;
|
|
529
|
+
if (/^\s*#/.test(line) || !line.trim())
|
|
530
|
+
continue;
|
|
531
|
+
if (new RegExp(`^\\s*${key}\\s*=`).test(line)) {
|
|
532
|
+
return { hadTable: true, hadKey: true, value: parseTomlScalarValue(line) };
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return { hadTable: true, hadKey: false, value: null };
|
|
536
|
+
}
|
|
537
|
+
function removeTopLevelKeyLineIf(source, key, shouldRemove) {
|
|
538
|
+
const lines = source.split(/\r?\n/);
|
|
539
|
+
const filtered = [];
|
|
540
|
+
let removed = false;
|
|
541
|
+
for (let i = 0; i < lines.length; i++) {
|
|
542
|
+
const line = lines[i] ?? "";
|
|
543
|
+
if (/^\s*\[/.test(line)) {
|
|
544
|
+
filtered.push(...lines.slice(i));
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
if (/^\s*#/.test(line) || !line.trim()) {
|
|
548
|
+
filtered.push(line);
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
const match = line.match(new RegExp(`^\\s*${key}\\s*=\\s*\"([^\"]*)\"\\s*$`));
|
|
552
|
+
if (!match) {
|
|
553
|
+
filtered.push(line);
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (shouldRemove(match[1] ?? "")) {
|
|
557
|
+
removed = true;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
filtered.push(line);
|
|
561
|
+
}
|
|
562
|
+
if (!removed)
|
|
563
|
+
return source;
|
|
564
|
+
return `${filtered.join("\n").trimEnd()}\n`;
|
|
565
|
+
}
|
|
458
566
|
function shellQuote(value) {
|
|
459
567
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
460
568
|
}
|
|
@@ -480,6 +588,19 @@ function publicApiOriginForBackendUrl(backendUrl) {
|
|
|
480
588
|
return trimmed;
|
|
481
589
|
}
|
|
482
590
|
}
|
|
591
|
+
function isTheClawBayChatgptBaseUrl(value) {
|
|
592
|
+
const trimmed = trimTrailingSlash(value.trim());
|
|
593
|
+
if (!trimmed)
|
|
594
|
+
return false;
|
|
595
|
+
try {
|
|
596
|
+
const parsed = new URL(trimmed);
|
|
597
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
598
|
+
return hostname === THECLAWBAY_CANONICAL_API_HOST || THECLAWBAY_WEBSITE_HOSTS.has(hostname);
|
|
599
|
+
}
|
|
600
|
+
catch {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
483
604
|
function openAiCompatibleProxyUrl(backendUrl) {
|
|
484
605
|
return `${publicApiOriginForBackendUrl(backendUrl)}${CANONICAL_THECLAWBAY_OPENAI_PROXY_SUFFIX}`;
|
|
485
606
|
}
|
|
@@ -1305,7 +1426,22 @@ async function writeCodexConfig(params) {
|
|
|
1305
1426
|
next = removeProviderTable(next, DEFAULT_PROVIDER_ID);
|
|
1306
1427
|
next = upsertFirstKeyLine(next, "model_provider", `"${DEFAULT_PROVIDER_ID}"`);
|
|
1307
1428
|
next = upsertFirstKeyLine(next, "model", `"${params.model}"`);
|
|
1308
|
-
next =
|
|
1429
|
+
next = removeTopLevelKeyLineIf(next, "chatgpt_base_url", isTheClawBayChatgptBaseUrl);
|
|
1430
|
+
const existingFeatureSnapshot = await readFileIfExists(CODEX_FEATURE_FLAGS_STATE_PATH);
|
|
1431
|
+
if (!existingFeatureSnapshot?.trim()) {
|
|
1432
|
+
const appsState = readTopLevelTableKeyValue(next, "features", "apps");
|
|
1433
|
+
const appsMcpGatewayState = readTopLevelTableKeyValue(next, "features", "apps_mcp_gateway");
|
|
1434
|
+
const snapshot = {
|
|
1435
|
+
hadFeaturesTable: appsState.hadTable || appsMcpGatewayState.hadTable,
|
|
1436
|
+
appsHadKey: appsState.hadKey,
|
|
1437
|
+
appsPreviousValue: appsState.value,
|
|
1438
|
+
appsMcpGatewayHadKey: appsMcpGatewayState.hadKey,
|
|
1439
|
+
appsMcpGatewayPreviousValue: appsMcpGatewayState.value,
|
|
1440
|
+
};
|
|
1441
|
+
await writeJsonObjectFile(CODEX_FEATURE_FLAGS_STATE_PATH, snapshot, 0o600);
|
|
1442
|
+
}
|
|
1443
|
+
next = upsertTopLevelTableKey(next, "features", "apps", "false");
|
|
1444
|
+
next = upsertTopLevelTableKey(next, "features", "apps_mcp_gateway", "false");
|
|
1309
1445
|
const managedBlock = appendManagedBlock("", [
|
|
1310
1446
|
MANAGED_START,
|
|
1311
1447
|
`[model_providers.${DEFAULT_PROVIDER_ID}]`,
|
|
@@ -1563,7 +1699,7 @@ async function persistApiKeyEnv(params) {
|
|
|
1563
1699
|
`export ${ENV_KEY_NAME}=${shellQuote(params.apiKey)}`,
|
|
1564
1700
|
];
|
|
1565
1701
|
if (params.claudeEnabled) {
|
|
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`);
|
|
1702
|
+
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`, `export ${CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME}=1`, `export ${CLAUDE_ENV_ENABLE_TELEMETRY_NAME}=0`);
|
|
1567
1703
|
}
|
|
1568
1704
|
const envContents = `${envLines.join("\n")}\n`;
|
|
1569
1705
|
await promises_1.default.writeFile(ENV_FILE, envContents, "utf8");
|
|
@@ -1599,11 +1735,15 @@ async function persistApiKeyEnv(params) {
|
|
|
1599
1735
|
process.env[CLAUDE_ENV_API_KEY_NAME] = params.apiKey;
|
|
1600
1736
|
process.env[CLAUDE_ENV_BASE_URL_NAME] = anthropicCompatibleProxyUrl(params.backendUrl);
|
|
1601
1737
|
process.env[CLAUDE_ENV_SIMPLE_MODE_NAME] = "1";
|
|
1738
|
+
process.env[CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME] = "1";
|
|
1739
|
+
process.env[CLAUDE_ENV_ENABLE_TELEMETRY_NAME] = "0";
|
|
1602
1740
|
}
|
|
1603
1741
|
else {
|
|
1604
1742
|
delete process.env[CLAUDE_ENV_API_KEY_NAME];
|
|
1605
1743
|
delete process.env[CLAUDE_ENV_BASE_URL_NAME];
|
|
1606
1744
|
delete process.env[CLAUDE_ENV_SIMPLE_MODE_NAME];
|
|
1745
|
+
delete process.env[CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME];
|
|
1746
|
+
delete process.env[CLAUDE_ENV_ENABLE_TELEMETRY_NAME];
|
|
1607
1747
|
}
|
|
1608
1748
|
return updated;
|
|
1609
1749
|
}
|
|
@@ -1615,7 +1755,7 @@ async function persistFishEnv(params) {
|
|
|
1615
1755
|
`set -gx ${ENV_KEY_NAME} ${shellQuote(params.apiKey)}`,
|
|
1616
1756
|
];
|
|
1617
1757
|
if (params.claudeEnabled) {
|
|
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`);
|
|
1758
|
+
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`, `set -gx ${CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME} 1`, `set -gx ${CLAUDE_ENV_ENABLE_TELEMETRY_NAME} 0`);
|
|
1619
1759
|
}
|
|
1620
1760
|
await promises_1.default.writeFile(fishConfPath, `${lines.join("\n")}\n`, "utf8");
|
|
1621
1761
|
return [fishConfPath];
|
|
@@ -1640,7 +1780,7 @@ async function persistPowerShellEnv(params) {
|
|
|
1640
1780
|
`$env:${ENV_KEY_NAME} = ${powerShellQuote(params.apiKey)}`,
|
|
1641
1781
|
];
|
|
1642
1782
|
if (params.claudeEnabled) {
|
|
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"`);
|
|
1783
|
+
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"`, `$env:${CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME} = "1"`, `$env:${CLAUDE_ENV_ENABLE_TELEMETRY_NAME} = "0"`);
|
|
1644
1784
|
}
|
|
1645
1785
|
lines.push(SHELL_END);
|
|
1646
1786
|
const next = appendManagedBlock(cleaned, lines);
|
|
@@ -1677,6 +1817,165 @@ async function persistVsCodeServerEnvSource() {
|
|
|
1677
1817
|
}
|
|
1678
1818
|
return updated;
|
|
1679
1819
|
}
|
|
1820
|
+
function terminalIntegratedEnvSettingsKey() {
|
|
1821
|
+
if (node_os_1.default.platform() === "darwin")
|
|
1822
|
+
return "terminal.integrated.env.osx";
|
|
1823
|
+
if (node_os_1.default.platform() === "win32")
|
|
1824
|
+
return "terminal.integrated.env.windows";
|
|
1825
|
+
return "terminal.integrated.env.linux";
|
|
1826
|
+
}
|
|
1827
|
+
function buildManagedEditorTerminalEnv(params) {
|
|
1828
|
+
const env = {
|
|
1829
|
+
[ENV_KEY_NAME]: params.apiKey,
|
|
1830
|
+
};
|
|
1831
|
+
if (params.claudeEnabled) {
|
|
1832
|
+
env[CLAUDE_ENV_API_KEY_NAME] = params.apiKey;
|
|
1833
|
+
env[CLAUDE_ENV_BASE_URL_NAME] = anthropicCompatibleProxyUrl(params.backendUrl);
|
|
1834
|
+
env[CLAUDE_ENV_SIMPLE_MODE_NAME] = "1";
|
|
1835
|
+
env[CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME] = "1";
|
|
1836
|
+
env[CLAUDE_ENV_ENABLE_TELEMETRY_NAME] = "0";
|
|
1837
|
+
}
|
|
1838
|
+
return env;
|
|
1839
|
+
}
|
|
1840
|
+
function buildManagedClaudeEditorEnv(params) {
|
|
1841
|
+
return {
|
|
1842
|
+
[CLAUDE_ENV_API_KEY_NAME]: params.apiKey,
|
|
1843
|
+
[CLAUDE_ENV_BASE_URL_NAME]: anthropicCompatibleProxyUrl(params.backendUrl),
|
|
1844
|
+
[CLAUDE_ENV_SIMPLE_MODE_NAME]: "1",
|
|
1845
|
+
[CLAUDE_ENV_DISABLE_NONESSENTIAL_TRAFFIC_NAME]: "1",
|
|
1846
|
+
[CLAUDE_ENV_ENABLE_TELEMETRY_NAME]: "0",
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
async function persistEditorTerminalEnvSettings(params) {
|
|
1850
|
+
const settingsKey = terminalIntegratedEnvSettingsKey();
|
|
1851
|
+
const desiredEnv = buildManagedEditorTerminalEnv(params);
|
|
1852
|
+
const existingSnapshotRaw = await readFileIfExists(EDITOR_TERMINAL_ENV_STATE_PATH);
|
|
1853
|
+
let existingSnapshot = [];
|
|
1854
|
+
if (existingSnapshotRaw?.trim()) {
|
|
1855
|
+
try {
|
|
1856
|
+
existingSnapshot = JSON.parse(existingSnapshotRaw);
|
|
1857
|
+
}
|
|
1858
|
+
catch {
|
|
1859
|
+
existingSnapshot = [];
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
const snapshotByPath = new Map(existingSnapshot.map((entry) => [entry.settingsPath, entry]));
|
|
1863
|
+
const managedPaths = [];
|
|
1864
|
+
for (const host of editorHosts()) {
|
|
1865
|
+
const settingsPath = host.userSettingsPath;
|
|
1866
|
+
const hostPresent = (await pathExists(host.extensionDir)) ||
|
|
1867
|
+
(await pathExists(settingsPath)) ||
|
|
1868
|
+
(await pathExists(node_path_1.default.dirname(settingsPath)));
|
|
1869
|
+
if (!hostPresent)
|
|
1870
|
+
continue;
|
|
1871
|
+
const existed = await pathExists(settingsPath);
|
|
1872
|
+
const settings = await readJsonObjectFile(settingsPath);
|
|
1873
|
+
const currentValue = settings[settingsKey];
|
|
1874
|
+
const currentEnv = typeof currentValue === "object" && currentValue !== null && !Array.isArray(currentValue)
|
|
1875
|
+
? { ...currentValue }
|
|
1876
|
+
: {};
|
|
1877
|
+
let changed = false;
|
|
1878
|
+
for (const [name, value] of Object.entries(desiredEnv)) {
|
|
1879
|
+
if (currentEnv[name] === value)
|
|
1880
|
+
continue;
|
|
1881
|
+
currentEnv[name] = value;
|
|
1882
|
+
changed = true;
|
|
1883
|
+
}
|
|
1884
|
+
for (const name of MANAGED_EDITOR_TERMINAL_ENV_NAMES) {
|
|
1885
|
+
if (name in desiredEnv || !(name in currentEnv))
|
|
1886
|
+
continue;
|
|
1887
|
+
delete currentEnv[name];
|
|
1888
|
+
changed = true;
|
|
1889
|
+
}
|
|
1890
|
+
if (!changed)
|
|
1891
|
+
continue;
|
|
1892
|
+
if (!snapshotByPath.has(settingsPath)) {
|
|
1893
|
+
snapshotByPath.set(settingsPath, {
|
|
1894
|
+
settingsPath,
|
|
1895
|
+
existed,
|
|
1896
|
+
hadKey: Object.prototype.hasOwnProperty.call(settings, settingsKey),
|
|
1897
|
+
previousValue: currentValue ?? null,
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
settings[settingsKey] = currentEnv;
|
|
1901
|
+
await writeJsonObjectFile(settingsPath, settings);
|
|
1902
|
+
managedPaths.push(settingsPath);
|
|
1903
|
+
}
|
|
1904
|
+
await writeJsonObjectFile(EDITOR_TERMINAL_ENV_STATE_PATH, Array.from(snapshotByPath.values()), 0o600);
|
|
1905
|
+
return managedPaths;
|
|
1906
|
+
}
|
|
1907
|
+
async function persistClaudeEditorSettings(params) {
|
|
1908
|
+
const existingSnapshotRaw = await readFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
|
|
1909
|
+
let existingSnapshot = [];
|
|
1910
|
+
if (existingSnapshotRaw?.trim()) {
|
|
1911
|
+
try {
|
|
1912
|
+
existingSnapshot = JSON.parse(existingSnapshotRaw);
|
|
1913
|
+
}
|
|
1914
|
+
catch {
|
|
1915
|
+
existingSnapshot = [];
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
const snapshotByPath = new Map(existingSnapshot.map((entry) => [entry.settingsPath, entry]));
|
|
1919
|
+
const managedPaths = [];
|
|
1920
|
+
const desiredEnv = params.claudeEnabled
|
|
1921
|
+
? buildManagedClaudeEditorEnv({ apiKey: params.apiKey, backendUrl: params.backendUrl })
|
|
1922
|
+
: null;
|
|
1923
|
+
for (const host of editorHosts()) {
|
|
1924
|
+
const settingsPath = host.userSettingsPath;
|
|
1925
|
+
const hostPresent = (await pathExists(host.extensionDir)) ||
|
|
1926
|
+
(await pathExists(settingsPath)) ||
|
|
1927
|
+
(await pathExists(node_path_1.default.dirname(settingsPath)));
|
|
1928
|
+
if (!hostPresent)
|
|
1929
|
+
continue;
|
|
1930
|
+
const existed = await pathExists(settingsPath);
|
|
1931
|
+
const settings = await readJsonObjectFile(settingsPath);
|
|
1932
|
+
const currentEnvValue = settings[CLAUDE_CODE_EDITOR_ENV_SETTING];
|
|
1933
|
+
const currentEnv = typeof currentEnvValue === "object" && currentEnvValue !== null && !Array.isArray(currentEnvValue)
|
|
1934
|
+
? { ...currentEnvValue }
|
|
1935
|
+
: {};
|
|
1936
|
+
let changed = false;
|
|
1937
|
+
if (!snapshotByPath.has(settingsPath)) {
|
|
1938
|
+
snapshotByPath.set(settingsPath, {
|
|
1939
|
+
settingsPath,
|
|
1940
|
+
existed,
|
|
1941
|
+
envHadKey: Object.prototype.hasOwnProperty.call(settings, CLAUDE_CODE_EDITOR_ENV_SETTING),
|
|
1942
|
+
envPreviousValue: currentEnvValue ?? null,
|
|
1943
|
+
disableLoginPromptHadKey: Object.prototype.hasOwnProperty.call(settings, CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING),
|
|
1944
|
+
disableLoginPromptPreviousValue: settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING] ?? null,
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
if (desiredEnv) {
|
|
1948
|
+
const nextEnv = { ...currentEnv };
|
|
1949
|
+
for (const [name, value] of Object.entries(desiredEnv)) {
|
|
1950
|
+
if (nextEnv[name] === value)
|
|
1951
|
+
continue;
|
|
1952
|
+
nextEnv[name] = value;
|
|
1953
|
+
changed = true;
|
|
1954
|
+
}
|
|
1955
|
+
settings[CLAUDE_CODE_EDITOR_ENV_SETTING] = nextEnv;
|
|
1956
|
+
if (settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING] !== true) {
|
|
1957
|
+
settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING] = true;
|
|
1958
|
+
changed = true;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
else {
|
|
1962
|
+
if (Object.prototype.hasOwnProperty.call(settings, CLAUDE_CODE_EDITOR_ENV_SETTING)) {
|
|
1963
|
+
delete settings[CLAUDE_CODE_EDITOR_ENV_SETTING];
|
|
1964
|
+
changed = true;
|
|
1965
|
+
}
|
|
1966
|
+
if (Object.prototype.hasOwnProperty.call(settings, CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING)) {
|
|
1967
|
+
delete settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING];
|
|
1968
|
+
changed = true;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (!changed)
|
|
1972
|
+
continue;
|
|
1973
|
+
await writeJsonObjectFile(settingsPath, settings);
|
|
1974
|
+
managedPaths.push(settingsPath);
|
|
1975
|
+
}
|
|
1976
|
+
await writeJsonObjectFile(CLAUDE_EDITOR_SETTINGS_STATE_PATH, Array.from(snapshotByPath.values()), 0o600);
|
|
1977
|
+
return managedPaths;
|
|
1978
|
+
}
|
|
1680
1979
|
function runOpenClawConfigCommand(args) {
|
|
1681
1980
|
const run = (0, node_child_process_1.spawnSync)("openclaw", args, {
|
|
1682
1981
|
encoding: "utf8",
|
|
@@ -2017,6 +2316,7 @@ async function writeOpenCodeFamilyConfig(params) {
|
|
|
2017
2316
|
const optionsRoot = objectRecordOr(managedOpenAiProvider.options, {});
|
|
2018
2317
|
optionsRoot.baseURL = openAiCompatibleProxyUrl(params.backendUrl);
|
|
2019
2318
|
optionsRoot.apiKey = params.apiKey;
|
|
2319
|
+
optionsRoot.setCacheKey = true;
|
|
2020
2320
|
managedOpenAiProvider.options = optionsRoot;
|
|
2021
2321
|
managedOpenAiProvider.models = buildOpenCodeModelsObject(params.models);
|
|
2022
2322
|
managedOpenAiProvider.whitelist = params.models.map((entry) => entry.id).filter(Boolean);
|
|
@@ -2144,7 +2444,7 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2144
2444
|
const setupClients = [
|
|
2145
2445
|
{
|
|
2146
2446
|
id: "codex",
|
|
2147
|
-
label: "Codex CLI
|
|
2447
|
+
label: "Codex CLI and VS Code extension",
|
|
2148
2448
|
summaryLabel: "Codex",
|
|
2149
2449
|
detected: codexDetected,
|
|
2150
2450
|
recommended: true,
|
|
@@ -2299,6 +2599,8 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2299
2599
|
let updatedPowerShellProfiles = [];
|
|
2300
2600
|
let codexConfigPath = null;
|
|
2301
2601
|
let updatedVsCodeEnvFiles = [];
|
|
2602
|
+
let updatedEditorTerminalSettings = [];
|
|
2603
|
+
let updatedClaudeEditorSettings = [];
|
|
2302
2604
|
let sessionMigration = null;
|
|
2303
2605
|
let authSeed = null;
|
|
2304
2606
|
let authSeedCleanup = null;
|
|
@@ -2328,6 +2630,8 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2328
2630
|
if (!resolved?.authRejected && claudeAccess.authRejected) {
|
|
2329
2631
|
throw new Error(describeCredentialRejection(authType, claudeAccess.failure));
|
|
2330
2632
|
}
|
|
2633
|
+
const claudeSelected = selectedSetupClients.has("claude");
|
|
2634
|
+
const claudeEnvEnabled = claudeSelected && claudeAccess.enabled;
|
|
2331
2635
|
progress.update("Saving shared machine config");
|
|
2332
2636
|
await (0, config_1.writeManagedConfig)({
|
|
2333
2637
|
backendUrl,
|
|
@@ -2339,20 +2643,32 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2339
2643
|
updatedShellFiles = await persistApiKeyEnv({
|
|
2340
2644
|
apiKey: authCredential,
|
|
2341
2645
|
backendUrl,
|
|
2342
|
-
claudeEnabled:
|
|
2646
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2343
2647
|
});
|
|
2344
2648
|
updatedFishFiles = await persistFishEnv({
|
|
2345
2649
|
apiKey: authCredential,
|
|
2346
2650
|
backendUrl,
|
|
2347
|
-
claudeEnabled:
|
|
2651
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2348
2652
|
});
|
|
2349
2653
|
updatedPowerShellProfiles = await persistPowerShellEnv({
|
|
2350
2654
|
apiKey: authCredential,
|
|
2351
2655
|
backendUrl,
|
|
2352
|
-
claudeEnabled:
|
|
2656
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2353
2657
|
});
|
|
2354
2658
|
if (selectedSetupClients.has("codex") || selectedSetupClients.has("claude")) {
|
|
2355
2659
|
updatedVsCodeEnvFiles = await persistVsCodeServerEnvSource();
|
|
2660
|
+
updatedEditorTerminalSettings = await persistEditorTerminalEnvSettings({
|
|
2661
|
+
apiKey: authCredential,
|
|
2662
|
+
backendUrl,
|
|
2663
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2664
|
+
});
|
|
2665
|
+
if (selectedSetupClients.has("claude")) {
|
|
2666
|
+
updatedClaudeEditorSettings = await persistClaudeEditorSettings({
|
|
2667
|
+
apiKey: authCredential,
|
|
2668
|
+
backendUrl,
|
|
2669
|
+
claudeEnabled: claudeEnvEnabled,
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2356
2672
|
}
|
|
2357
2673
|
if (selectedSetupClients.has("codex")) {
|
|
2358
2674
|
progress.update("Configuring Codex");
|
|
@@ -2487,11 +2803,11 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2487
2803
|
const summaryNotes = new Set();
|
|
2488
2804
|
if (resolved?.note)
|
|
2489
2805
|
summaryNotes.add(resolved.note);
|
|
2490
|
-
if (claudeAccess?.enabled) {
|
|
2491
|
-
summaryNotes.add("Claude Code: exported ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY,
|
|
2806
|
+
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2807
|
+
summaryNotes.add("Claude Code: exported ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY, CLAUDE_CODE_SIMPLE=1, disabled nonessential traffic, and disabled telemetry.");
|
|
2492
2808
|
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.");
|
|
2493
2809
|
}
|
|
2494
|
-
else if (claudeAccess?.note) {
|
|
2810
|
+
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
2495
2811
|
summaryNotes.add(claudeAccess.note);
|
|
2496
2812
|
}
|
|
2497
2813
|
if (selectedSetupClients.has("trae")) {
|
|
@@ -2543,11 +2859,10 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2543
2859
|
}
|
|
2544
2860
|
if (resolved?.note)
|
|
2545
2861
|
this.log(resolved.note);
|
|
2546
|
-
if (claudeAccess?.enabled) {
|
|
2862
|
+
if (selectedSetupClients.has("claude") && claudeAccess?.enabled) {
|
|
2547
2863
|
this.log(`- Claude Code base URL: ${anthropicCompatibleProxyUrl(backendUrl)}`);
|
|
2548
|
-
this.log(`- Claude Code selected: ${selectedSetupClients.has("claude") ? "yes" : "no"}`);
|
|
2549
2864
|
}
|
|
2550
|
-
else if (claudeAccess?.note) {
|
|
2865
|
+
else if (selectedSetupClients.has("claude") && claudeAccess?.note) {
|
|
2551
2866
|
this.log(`- Claude Code: ${claudeAccess.note}`);
|
|
2552
2867
|
}
|
|
2553
2868
|
this.log(`- Local credential env: ${ENV_FILE}`);
|
|
@@ -2558,6 +2873,12 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
2558
2873
|
if (updatedPowerShellProfiles.length > 0) {
|
|
2559
2874
|
this.log(`- PowerShell profiles updated: ${updatedPowerShellProfiles.join(", ")}`);
|
|
2560
2875
|
}
|
|
2876
|
+
if (updatedEditorTerminalSettings.length > 0) {
|
|
2877
|
+
this.log(`- Editor terminal env updated: ${updatedEditorTerminalSettings.join(", ")}`);
|
|
2878
|
+
}
|
|
2879
|
+
if (updatedClaudeEditorSettings.length > 0) {
|
|
2880
|
+
this.log(`- Claude editor settings updated: ${updatedClaudeEditorSettings.join(", ")}`);
|
|
2881
|
+
}
|
|
2561
2882
|
if (selectedSetupClients.has("codex")) {
|
|
2562
2883
|
this.log(`- Codex: configured (${codexConfigPath})`);
|
|
2563
2884
|
if (resolved)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theclawbay",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.56",
|
|
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": {
|