theclawbay 0.3.25 → 0.3.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/dist/commands/logout.js +218 -1
- package/dist/commands/setup.js +676 -128
- package/dist/lib/config/paths.d.ts +2 -0
- package/dist/lib/config/paths.js +3 -1
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# theclawbay
|
|
2
2
|
|
|
3
|
-
CLI for connecting Codex
|
|
3
|
+
CLI for connecting Codex, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, and experimental Trae to The Claw Bay.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -16,9 +16,16 @@ Get your API key from `https://theclawbay.com/dashboard`.
|
|
|
16
16
|
theclawbay setup --api-key <apiKey>
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
In an interactive terminal, setup shows one picker for Codex, Continue, Cline, OpenClaw, OpenCode, Kilo, Roo Code, Aider, and Windows Trae.
|
|
20
|
+
Detected integrations are preselected when recommended, undetected ones stay visible but cannot be selected,
|
|
21
|
+
and you can toggle items with arrow keys plus `Enter` or by pressing their number.
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
History notes:
|
|
24
|
+
|
|
25
|
+
- Continue setup only updates `~/.continue/config.yaml` and leaves `~/.continue/sessions` untouched.
|
|
26
|
+
- Cline setup only updates `~/.cline/data/globalState.json` and `~/.cline/data/secrets.json`; task history stays in `~/.cline/state` and `~/.cline/tasks`.
|
|
27
|
+
- Roo Code setup uses a managed auto-import file plus editor settings and does not touch task history. Imported Roo profiles can persist inside Roo after first launch.
|
|
28
|
+
- Aider setup appends a managed block to `~/.aider.conf.yml` and enables `restore-chat-history: true` without touching `.aider.chat.history.md`.
|
|
22
29
|
|
|
23
30
|
## Optional
|
|
24
31
|
|
package/dist/commands/logout.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const yaml_1 = require("yaml");
|
|
9
10
|
const base_command_1 = require("../lib/base-command");
|
|
10
11
|
const codex_auth_seeding_1 = require("../lib/codex-auth-seeding");
|
|
11
12
|
const codex_history_migration_1 = require("../lib/codex-history-migration");
|
|
@@ -16,10 +17,19 @@ const DEFAULT_PROVIDER_ID = "theclawbay";
|
|
|
16
17
|
const WAN_PROVIDER_ID = "theclawbay-wan";
|
|
17
18
|
const MANAGED_START = "# theclawbay-managed:start";
|
|
18
19
|
const MANAGED_END = "# theclawbay-managed:end";
|
|
20
|
+
const AIDER_MANAGED_START = "# theclawbay-aider-managed:start";
|
|
21
|
+
const AIDER_MANAGED_END = "# theclawbay-aider-managed:end";
|
|
19
22
|
const SHELL_START = "# theclawbay-shell-managed:start";
|
|
20
23
|
const SHELL_END = "# theclawbay-shell-managed:end";
|
|
21
|
-
const ENV_FILE = node_path_1.default.join(
|
|
24
|
+
const ENV_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "env");
|
|
22
25
|
const ENV_KEY_NAME = "THECLAWBAY_API_KEY";
|
|
26
|
+
const CONTINUE_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".continue", "config.yaml");
|
|
27
|
+
const CLINE_GLOBAL_STATE_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "globalState.json");
|
|
28
|
+
const CLINE_SECRETS_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".cline", "data", "secrets.json");
|
|
29
|
+
const AIDER_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".aider.conf.yml");
|
|
30
|
+
const CLINE_RESTORE_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "cline.restore.json");
|
|
31
|
+
const ROO_SETTINGS_STATE_PATH = node_path_1.default.join(paths_1.theclawbayStateDir, "roo-settings.restore.json");
|
|
32
|
+
const ROO_IMPORT_FILE = node_path_1.default.join(paths_1.theclawbayConfigDir, "roo-code-settings.json");
|
|
23
33
|
const MIGRATION_STATE_FILE = node_path_1.default.join(paths_1.codexDir, "theclawbay.migration.json");
|
|
24
34
|
const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set([
|
|
25
35
|
OPENAI_PROVIDER_ID,
|
|
@@ -27,6 +37,8 @@ const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set([
|
|
|
27
37
|
DEFAULT_PROVIDER_ID,
|
|
28
38
|
]);
|
|
29
39
|
const HISTORY_PROVIDER_DB_MIGRATE_SOURCES = [DEFAULT_PROVIDER_ID, WAN_PROVIDER_ID];
|
|
40
|
+
const THECLAWBAY_OPENAI_PROXY_SUFFIX = "/api/codex-auth/v1/proxy/v1";
|
|
41
|
+
const CONTINUE_MODEL_NAME = "The Claw Bay";
|
|
30
42
|
const TRAE_PATCH_MARKER = "theclawbay-trae-patch";
|
|
31
43
|
const TRAE_BUNDLE_BACKUP_SUFFIX = ".theclawbay-managed-backup";
|
|
32
44
|
function removeManagedBlock(source, start, end) {
|
|
@@ -125,6 +137,61 @@ function objectRecordOr(value, fallback) {
|
|
|
125
137
|
return { ...value };
|
|
126
138
|
return fallback;
|
|
127
139
|
}
|
|
140
|
+
function isTheClawBayOpenAiCompatibleBaseUrl(value) {
|
|
141
|
+
return typeof value === "string" && value.trim().endsWith(THECLAWBAY_OPENAI_PROXY_SUFFIX);
|
|
142
|
+
}
|
|
143
|
+
async function readJsonObjectFile(filePath) {
|
|
144
|
+
const existingRaw = await readFileIfExists(filePath);
|
|
145
|
+
if (existingRaw === null || !existingRaw.trim())
|
|
146
|
+
return {};
|
|
147
|
+
try {
|
|
148
|
+
return objectRecordOr(JSON.parse(existingRaw), {});
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function writeJsonFile(filePath, value, mode) {
|
|
155
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(filePath), { recursive: true });
|
|
156
|
+
await promises_1.default.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
157
|
+
if (mode !== undefined)
|
|
158
|
+
await promises_1.default.chmod(filePath, mode);
|
|
159
|
+
}
|
|
160
|
+
function roamingAppDataDir() {
|
|
161
|
+
if (process.env.APPDATA?.trim())
|
|
162
|
+
return process.env.APPDATA;
|
|
163
|
+
return node_path_1.default.join(node_os_1.default.homedir(), "AppData", "Roaming");
|
|
164
|
+
}
|
|
165
|
+
function editorSettingsCandidates() {
|
|
166
|
+
const home = node_os_1.default.homedir();
|
|
167
|
+
if (node_os_1.default.platform() === "darwin") {
|
|
168
|
+
const appSupport = node_path_1.default.join(home, "Library", "Application Support");
|
|
169
|
+
return [
|
|
170
|
+
node_path_1.default.join(appSupport, "Code", "User", "settings.json"),
|
|
171
|
+
node_path_1.default.join(appSupport, "Code - Insiders", "User", "settings.json"),
|
|
172
|
+
node_path_1.default.join(appSupport, "Cursor", "User", "settings.json"),
|
|
173
|
+
node_path_1.default.join(appSupport, "Windsurf", "User", "settings.json"),
|
|
174
|
+
node_path_1.default.join(appSupport, "VSCodium", "User", "settings.json"),
|
|
175
|
+
];
|
|
176
|
+
}
|
|
177
|
+
if (node_os_1.default.platform() === "win32") {
|
|
178
|
+
const appData = roamingAppDataDir();
|
|
179
|
+
return [
|
|
180
|
+
node_path_1.default.join(appData, "Code", "User", "settings.json"),
|
|
181
|
+
node_path_1.default.join(appData, "Code - Insiders", "User", "settings.json"),
|
|
182
|
+
node_path_1.default.join(appData, "Cursor", "User", "settings.json"),
|
|
183
|
+
node_path_1.default.join(appData, "Windsurf", "User", "settings.json"),
|
|
184
|
+
node_path_1.default.join(appData, "VSCodium", "User", "settings.json"),
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
return [
|
|
188
|
+
node_path_1.default.join(home, ".config", "Code", "User", "settings.json"),
|
|
189
|
+
node_path_1.default.join(home, ".config", "Code - Insiders", "User", "settings.json"),
|
|
190
|
+
node_path_1.default.join(home, ".config", "Cursor", "User", "settings.json"),
|
|
191
|
+
node_path_1.default.join(home, ".config", "Windsurf", "User", "settings.json"),
|
|
192
|
+
node_path_1.default.join(home, ".config", "VSCodium", "User", "settings.json"),
|
|
193
|
+
];
|
|
194
|
+
}
|
|
128
195
|
async function cleanupCodexConfig() {
|
|
129
196
|
const configPath = node_path_1.default.join(paths_1.codexDir, "config.toml");
|
|
130
197
|
const existing = await readFileIfExists(configPath);
|
|
@@ -136,6 +203,148 @@ async function cleanupCodexConfig() {
|
|
|
136
203
|
next = removeTopLevelProviderSelection(next);
|
|
137
204
|
return writeIfChanged(configPath, next, existing);
|
|
138
205
|
}
|
|
206
|
+
async function cleanupContinueConfig() {
|
|
207
|
+
const existing = await readFileIfExists(CONTINUE_CONFIG_PATH);
|
|
208
|
+
if (existing === null || !existing.trim())
|
|
209
|
+
return false;
|
|
210
|
+
try {
|
|
211
|
+
const doc = (0, yaml_1.parseDocument)(existing);
|
|
212
|
+
const root = objectRecordOr(doc.toJS(), {});
|
|
213
|
+
const models = Array.isArray(root.models) ? root.models : [];
|
|
214
|
+
const filtered = models.filter((entry) => {
|
|
215
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
216
|
+
return true;
|
|
217
|
+
const candidate = entry;
|
|
218
|
+
return !(candidate.provider === "openai" &&
|
|
219
|
+
candidate.name === CONTINUE_MODEL_NAME &&
|
|
220
|
+
isTheClawBayOpenAiCompatibleBaseUrl(candidate.apiBase));
|
|
221
|
+
});
|
|
222
|
+
if (filtered.length === models.length)
|
|
223
|
+
return false;
|
|
224
|
+
doc.set("models", filtered);
|
|
225
|
+
await promises_1.default.writeFile(CONTINUE_CONFIG_PATH, doc.toString(), "utf8");
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function cleanupClineConfig() {
|
|
233
|
+
const globalState = await readJsonObjectFile(CLINE_GLOBAL_STATE_PATH);
|
|
234
|
+
const secrets = await readJsonObjectFile(CLINE_SECRETS_PATH);
|
|
235
|
+
const snapshotRaw = await readFileIfExists(CLINE_RESTORE_STATE_PATH);
|
|
236
|
+
let changed = false;
|
|
237
|
+
if (snapshotRaw?.trim()) {
|
|
238
|
+
try {
|
|
239
|
+
const snapshot = JSON.parse(snapshotRaw);
|
|
240
|
+
for (const [key, value] of Object.entries(snapshot.globalState ?? {})) {
|
|
241
|
+
if (value === null) {
|
|
242
|
+
if (key in globalState) {
|
|
243
|
+
delete globalState[key];
|
|
244
|
+
changed = true;
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (globalState[key] !== value) {
|
|
249
|
+
globalState[key] = value;
|
|
250
|
+
changed = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
for (const [key, value] of Object.entries(snapshot.secrets ?? {})) {
|
|
254
|
+
if (value === null) {
|
|
255
|
+
if (key in secrets) {
|
|
256
|
+
delete secrets[key];
|
|
257
|
+
changed = true;
|
|
258
|
+
}
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (secrets[key] !== value) {
|
|
262
|
+
secrets[key] = value;
|
|
263
|
+
changed = true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
// Fall through to best-effort cleanup below.
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
if (globalState.planModeApiProvider === OPENAI_PROVIDER_ID) {
|
|
273
|
+
delete globalState.planModeApiProvider;
|
|
274
|
+
changed = true;
|
|
275
|
+
}
|
|
276
|
+
if (globalState.actModeApiProvider === OPENAI_PROVIDER_ID) {
|
|
277
|
+
delete globalState.actModeApiProvider;
|
|
278
|
+
changed = true;
|
|
279
|
+
}
|
|
280
|
+
if (isTheClawBayOpenAiCompatibleBaseUrl(globalState.openAiBaseUrl)) {
|
|
281
|
+
delete globalState.openAiBaseUrl;
|
|
282
|
+
changed = true;
|
|
283
|
+
}
|
|
284
|
+
for (const key of ["planModeOpenAiModelId", "actModeOpenAiModelId"]) {
|
|
285
|
+
if (typeof globalState[key] === "string") {
|
|
286
|
+
delete globalState[key];
|
|
287
|
+
changed = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (typeof secrets.openAiApiKey === "string") {
|
|
291
|
+
delete secrets.openAiApiKey;
|
|
292
|
+
changed = true;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (changed) {
|
|
296
|
+
await writeJsonFile(CLINE_GLOBAL_STATE_PATH, globalState);
|
|
297
|
+
await writeJsonFile(CLINE_SECRETS_PATH, secrets, 0o600);
|
|
298
|
+
}
|
|
299
|
+
await removeFileIfExists(CLINE_RESTORE_STATE_PATH);
|
|
300
|
+
return changed;
|
|
301
|
+
}
|
|
302
|
+
async function cleanupRooConfig() {
|
|
303
|
+
const snapshotRaw = await readFileIfExists(ROO_SETTINGS_STATE_PATH);
|
|
304
|
+
let changed = false;
|
|
305
|
+
if (snapshotRaw?.trim()) {
|
|
306
|
+
try {
|
|
307
|
+
const entries = JSON.parse(snapshotRaw);
|
|
308
|
+
for (const entry of entries) {
|
|
309
|
+
const settings = await readJsonObjectFile(entry.settingsPath);
|
|
310
|
+
const currentValue = settings["roo-cline.autoImportSettingsPath"];
|
|
311
|
+
if (currentValue !== ROO_IMPORT_FILE)
|
|
312
|
+
continue;
|
|
313
|
+
if (entry.previousValue === null) {
|
|
314
|
+
delete settings["roo-cline.autoImportSettingsPath"];
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
settings["roo-cline.autoImportSettingsPath"] = entry.previousValue;
|
|
318
|
+
}
|
|
319
|
+
await writeJsonFile(entry.settingsPath, settings);
|
|
320
|
+
changed = true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// Fall back to common editor settings paths below.
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (!changed) {
|
|
328
|
+
for (const settingsPath of editorSettingsCandidates()) {
|
|
329
|
+
const settings = await readJsonObjectFile(settingsPath);
|
|
330
|
+
if (settings["roo-cline.autoImportSettingsPath"] !== ROO_IMPORT_FILE)
|
|
331
|
+
continue;
|
|
332
|
+
delete settings["roo-cline.autoImportSettingsPath"];
|
|
333
|
+
await writeJsonFile(settingsPath, settings);
|
|
334
|
+
changed = true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const removedImport = await removeFileIfExists(ROO_IMPORT_FILE);
|
|
338
|
+
await removeFileIfExists(ROO_SETTINGS_STATE_PATH);
|
|
339
|
+
return changed || removedImport;
|
|
340
|
+
}
|
|
341
|
+
async function cleanupAiderConfig() {
|
|
342
|
+
const existing = await readFileIfExists(AIDER_CONFIG_PATH);
|
|
343
|
+
if (existing === null)
|
|
344
|
+
return false;
|
|
345
|
+
const next = removeManagedBlock(existing, AIDER_MANAGED_START, AIDER_MANAGED_END);
|
|
346
|
+
return writeIfChanged(AIDER_CONFIG_PATH, next, existing);
|
|
347
|
+
}
|
|
139
348
|
async function cleanupShellFiles() {
|
|
140
349
|
const updated = [];
|
|
141
350
|
const shellRcPaths = [".bashrc", ".zshrc", ".profile"].map((name) => node_path_1.default.join(node_os_1.default.homedir(), name));
|
|
@@ -296,10 +505,14 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
296
505
|
const updatedShellFiles = await cleanupShellFiles();
|
|
297
506
|
const updatedVsCodeHooks = await cleanupVsCodeHooks();
|
|
298
507
|
const updatedCodexConfig = await cleanupCodexConfig();
|
|
508
|
+
const updatedContinueConfig = await cleanupContinueConfig();
|
|
509
|
+
const updatedClineConfig = await cleanupClineConfig();
|
|
299
510
|
const updatedOpenClawConfig = await cleanupOpenClawConfig();
|
|
300
511
|
const updatedOpenCodeConfig = await cleanupOpenCodeConfig();
|
|
301
512
|
const updatedKiloConfig = await cleanupKiloConfig();
|
|
513
|
+
const updatedRooConfig = await cleanupRooConfig();
|
|
302
514
|
const updatedTraeBundle = await cleanupTraeBundle();
|
|
515
|
+
const updatedAiderConfig = await cleanupAiderConfig();
|
|
303
516
|
const sessionMigration = await (0, codex_history_migration_1.migrateSessionProviders)({
|
|
304
517
|
codexHome: paths_1.codexDir,
|
|
305
518
|
migrationStateFile: MIGRATION_STATE_FILE,
|
|
@@ -368,10 +581,14 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
368
581
|
else {
|
|
369
582
|
this.log("- Codex model cache: no cleanup needed.");
|
|
370
583
|
}
|
|
584
|
+
this.log(`- Continue config cleaned: ${updatedContinueConfig ? "yes" : "no"}`);
|
|
585
|
+
this.log(`- Cline config cleaned: ${updatedClineConfig ? "yes" : "no"}`);
|
|
371
586
|
this.log(`- OpenClaw config cleaned: ${updatedOpenClawConfig ? "yes" : "no"}`);
|
|
372
587
|
this.log(`- OpenCode config cleaned: ${updatedOpenCodeConfig ? "yes" : "no"}`);
|
|
373
588
|
this.log(`- Kilo config cleaned: ${updatedKiloConfig ? "yes" : "no"}`);
|
|
589
|
+
this.log(`- Roo Code setup hook cleaned: ${updatedRooConfig ? "yes" : "no"}`);
|
|
374
590
|
this.log(`- Trae experimental patch cleaned: ${updatedTraeBundle ? "yes" : "no"}`);
|
|
591
|
+
this.log(`- Aider config cleaned: ${updatedAiderConfig ? "yes" : "no"}`);
|
|
375
592
|
this.log("Note: restart terminals/VS Code windows to clear already-loaded shell environment.");
|
|
376
593
|
});
|
|
377
594
|
}
|