theclawbay 0.3.25 → 0.3.26

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # theclawbay
2
2
 
3
- CLI for connecting Codex to The Claw Bay and optionally linking detected OpenClaw, OpenCode, Kilo, or experimental Trae installs.
3
+ CLI for connecting Codex, OpenClaw, OpenCode, Kilo, and experimental Trae to The Claw Bay.
4
4
 
5
5
  ## Install
6
6
 
@@ -16,9 +16,9 @@ Get your API key from `https://theclawbay.com/dashboard`.
16
16
  theclawbay setup --api-key <apiKey>
17
17
  ```
18
18
 
19
- If OpenClaw, OpenCode, or Kilo are already installed, setup offers them as optional add-ons during the same flow.
20
-
21
- On Windows, detected Trae installs can also be patched experimentally through the same setup flow.
19
+ In an interactive terminal, setup shows one picker for Codex, OpenClaw, OpenCode, Kilo, 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.
22
22
 
23
23
  ## Optional
24
24
 
@@ -40,7 +40,7 @@ const SHELL_END = "# theclawbay-shell-managed:end";
40
40
  const OPENCLAW_PROVIDER_ID = DEFAULT_PROVIDER_ID;
41
41
  const HISTORY_PROVIDER_NEUTRALIZE_SOURCES = new Set(["openai", "theclawbay-wan", DEFAULT_PROVIDER_ID]);
42
42
  const HISTORY_PROVIDER_DB_MIGRATE_SOURCES = ["openai", "theclawbay-wan"];
43
- const OPTIONAL_SETUP_CLIENT_IDS = ["openclaw", "opencode", "kilo", "trae"];
43
+ const SETUP_CLIENT_IDS = ["codex", "openclaw", "opencode", "kilo", "trae"];
44
44
  const TRAE_PATCH_MARKER = "theclawbay-trae-patch";
45
45
  const TRAE_BUNDLE_BACKUP_SUFFIX = ".theclawbay-managed-backup";
46
46
  const TRAE_TARGET_FUNCTION_START = "async setOriginModelListMapAndCache(e,t=!0){";
@@ -175,7 +175,7 @@ function shellQuote(value) {
175
175
  function modelDisplayName(modelId) {
176
176
  return MODEL_DISPLAY_NAMES[modelId] ?? modelId;
177
177
  }
178
- function parseOptionalClientFlags(raw) {
178
+ function parseSetupClientFlags(raw) {
179
179
  if (!raw)
180
180
  return null;
181
181
  const parts = raw
@@ -184,46 +184,51 @@ function parseOptionalClientFlags(raw) {
184
184
  .filter(Boolean);
185
185
  const selected = new Set();
186
186
  for (const part of parts) {
187
- if (part === "codex")
188
- continue;
189
- if (OPTIONAL_SETUP_CLIENT_IDS.includes(part)) {
187
+ if (SETUP_CLIENT_IDS.includes(part)) {
190
188
  selected.add(part);
191
189
  continue;
192
190
  }
193
- throw new Error(`unknown client "${part}". Supported values: codex, openclaw, opencode, kilo, trae.`);
191
+ throw new Error(`unknown client "${part}". Supported values: ${SETUP_CLIENT_IDS.join(", ")}.`);
194
192
  }
195
193
  return selected;
196
194
  }
197
- async function promptForOptionalClients(clients) {
198
- const detected = clients.filter((client) => client.detected);
199
- const selected = new Set(detected.filter((client) => client.recommended).map((client) => client.id));
200
- if (detected.length === 0 || !process.stdin.isTTY || !process.stdout.isTTY) {
195
+ async function promptForSetupClients(clients) {
196
+ const selected = new Set(clients.filter((client) => client.detected && client.recommended).map((client) => client.id));
197
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
201
198
  return selected;
202
199
  }
203
- const options = detected.map((client) => ({
200
+ const options = clients.map((client) => ({
204
201
  ...client,
205
- checked: selected.has(client.id),
202
+ checked: client.detected && selected.has(client.id),
206
203
  }));
207
204
  return new Promise((resolve) => {
208
205
  let cursor = 0;
209
206
  let settled = false;
207
+ let hint = clients.some((client) => client.detected)
208
+ ? "Detected integrations are preselected. Undetected ones stay visible but disabled."
209
+ : "No supported local clients are detected yet. Continue will just save your managed config and API key env.";
210
210
  const stdin = process.stdin;
211
211
  const stdout = process.stdout;
212
212
  const wasRaw = stdin.isRaw;
213
+ const continueIndex = options.length;
213
214
  const clearScreen = () => {
214
215
  stdout.write("\x1b[2J\x1b[H");
215
216
  };
217
+ const selectedCount = () => options.filter((option) => option.checked).length;
216
218
  const render = () => {
217
219
  clearScreen();
218
- stdout.write("Optional local client setup\n");
219
- stdout.write("Use ↑/↓ to move, Space to toggle, Enter to continue.\n\n");
220
+ stdout.write("Choose local clients to configure\n");
221
+ stdout.write(`Use ↑/↓ to move, Enter to toggle the highlighted integration, or press 1-${options.length} to toggle directly.\n`);
222
+ stdout.write("Move to Continue and press Enter when you're ready.\n\n");
220
223
  for (const [index, option] of options.entries()) {
221
224
  const pointer = index === cursor ? ">" : " ";
222
- const mark = option.checked ? "[x]" : "[ ]";
223
- const badge = option.recommended ? "recommended" : "optional";
224
- stdout.write(`${pointer} ${mark} ${option.label} ${badge}\n`);
225
+ const mark = option.detected ? (option.checked ? "[x]" : "[ ]") : "[-]";
226
+ const badge = option.detected ? (option.recommended ? "recommended" : "optional") : "not detected";
227
+ stdout.write(`${pointer} ${index + 1}. ${mark} ${option.label} ${badge}\n`);
225
228
  }
226
- stdout.write("\n");
229
+ const continuePointer = cursor === continueIndex ? ">" : " ";
230
+ stdout.write(`${continuePointer} Continue with ${selectedCount()} selected integration${selectedCount() === 1 ? "" : "s"}\n`);
231
+ stdout.write(`\n${hint}\n`);
227
232
  };
228
233
  const finish = () => {
229
234
  if (settled)
@@ -238,34 +243,66 @@ async function promptForOptionalClients(clients) {
238
243
  const finalSelection = new Set(options.filter((option) => option.checked).map((option) => option.id));
239
244
  resolve(finalSelection);
240
245
  };
246
+ const toggleOption = (index) => {
247
+ const option = options[index];
248
+ if (!option)
249
+ return;
250
+ cursor = index;
251
+ if (!option.detected) {
252
+ hint = `${option.label} is not detected on this machine yet, so it cannot be selected.`;
253
+ render();
254
+ return;
255
+ }
256
+ option.checked = !option.checked;
257
+ hint = `${option.label} ${option.checked ? "selected" : "cleared"}.`;
258
+ render();
259
+ };
241
260
  const onKeypress = (_str, key) => {
242
261
  if (key.ctrl && key.name === "c") {
243
262
  stdout.write("\x1b[?25h");
244
263
  process.exit(130);
245
264
  }
246
265
  if (key.name === "up" || key.name === "k") {
247
- cursor = (cursor - 1 + options.length) % options.length;
266
+ cursor = (cursor - 1 + options.length + 1) % (options.length + 1);
248
267
  render();
249
268
  return;
250
269
  }
251
270
  if (key.name === "down" || key.name === "j") {
252
- cursor = (cursor + 1) % options.length;
271
+ cursor = (cursor + 1) % (options.length + 1);
253
272
  render();
254
273
  return;
255
274
  }
256
275
  if (key.name === "space") {
257
- options[cursor].checked = !options[cursor].checked;
258
- render();
276
+ if (cursor === continueIndex) {
277
+ finish();
278
+ return;
279
+ }
280
+ toggleOption(cursor);
281
+ return;
282
+ }
283
+ const directSelection = Number.parseInt(key.sequence ?? "", 10);
284
+ if (Number.isInteger(directSelection) && directSelection >= 1 && directSelection <= options.length) {
285
+ toggleOption(directSelection - 1);
259
286
  return;
260
287
  }
261
288
  if (key.name === "a") {
262
- const nextValue = options.some((option) => !option.checked);
263
- for (const option of options)
289
+ const detectedOptions = options.filter((option) => option.detected);
290
+ const nextValue = detectedOptions.some((option) => !option.checked);
291
+ for (const option of detectedOptions)
264
292
  option.checked = nextValue;
293
+ hint = `${nextValue ? "Selected" : "Cleared"} all detected integrations.`;
265
294
  render();
266
295
  return;
267
296
  }
268
297
  if (key.name === "return" || key.name === "enter") {
298
+ if (cursor === continueIndex) {
299
+ finish();
300
+ return;
301
+ }
302
+ toggleOption(cursor);
303
+ return;
304
+ }
305
+ if (key.name === "c") {
269
306
  finish();
270
307
  }
271
308
  };
@@ -277,10 +314,10 @@ async function promptForOptionalClients(clients) {
277
314
  render();
278
315
  });
279
316
  }
280
- function resolveOptionalClientSelection(params) {
281
- const { optionalClients, flagSelection, skipPrompt } = params;
317
+ function resolveSetupClientSelection(params) {
318
+ const { setupClients, flagSelection, skipPrompt } = params;
282
319
  if (flagSelection) {
283
- for (const client of optionalClients) {
320
+ for (const client of setupClients) {
284
321
  if (!flagSelection.has(client.id))
285
322
  continue;
286
323
  if (!client.detected) {
@@ -289,10 +326,10 @@ function resolveOptionalClientSelection(params) {
289
326
  }
290
327
  return Promise.resolve(flagSelection);
291
328
  }
292
- const defaults = new Set(optionalClients.filter((client) => client.detected && client.recommended).map((client) => client.id));
329
+ const defaults = new Set(setupClients.filter((client) => client.detected && client.recommended).map((client) => client.id));
293
330
  if (skipPrompt)
294
331
  return Promise.resolve(defaults);
295
- return promptForOptionalClients(optionalClients);
332
+ return promptForSetupClients(setupClients);
296
333
  }
297
334
  async function fetchBackendModelIds(backendUrl, apiKey) {
298
335
  const url = `${trimTrailingSlash(backendUrl)}/api/codex-auth/v1/proxy/v1/models`;
@@ -334,6 +371,21 @@ function kiloStorageCandidates() {
334
371
  }
335
372
  return candidates;
336
373
  }
374
+ async function detectCodexClient() {
375
+ if (hasCommand("codex"))
376
+ return true;
377
+ const candidates = [
378
+ node_path_1.default.join(paths_1.codexDir, "config.toml"),
379
+ node_path_1.default.join(paths_1.codexDir, "auth.json"),
380
+ node_path_1.default.join(paths_1.codexDir, "history.jsonl"),
381
+ node_path_1.default.join(paths_1.codexDir, "sessions"),
382
+ ];
383
+ for (const candidate of candidates) {
384
+ if (await pathExists(candidate))
385
+ return true;
386
+ }
387
+ return false;
388
+ }
337
389
  async function detectKiloClient() {
338
390
  if (hasCommand("kilo"))
339
391
  return true;
@@ -691,155 +743,184 @@ class SetupCommand extends base_command_1.BaseCommand {
691
743
  throw new Error('API key is required. Run "theclawbay setup --api-key <key>".');
692
744
  const backendRaw = flags.backend ?? (0, api_key_1.tryInferBackendUrlFromApiKey)(apiKey) ?? managed?.backendUrl ?? DEFAULT_BACKEND_URL;
693
745
  const backendUrl = normalizeUrl(backendRaw, "--backend");
694
- await (0, config_1.writeManagedConfig)({ backendUrl, apiKey });
695
- const resolved = await resolveModels(backendUrl, apiKey);
696
- const codexConfigPath = await writeCodexConfig({ backendUrl, model: resolved.model, apiKey });
697
- const updatedShellFiles = await persistApiKeyEnv(apiKey);
698
- const updatedVsCodeEnvFiles = await persistVsCodeServerEnvSource();
699
- const sessionMigration = await (0, codex_history_migration_1.migrateSessionProviders)({
700
- codexHome: paths_1.codexDir,
701
- migrationStateFile: MIGRATION_STATE_FILE,
702
- neutralizeSources: HISTORY_PROVIDER_NEUTRALIZE_SOURCES,
703
- });
704
- const authSeed = await (0, codex_auth_seeding_1.ensureCodexApiKeyAuth)({
705
- codexHome: paths_1.codexDir,
706
- apiKey,
707
- });
708
- const stateDbMigration = await (0, codex_history_migration_1.migrateStateDbProviders)({
709
- codexHome: paths_1.codexDir,
710
- targetProvider: DEFAULT_PROVIDER_ID,
711
- sourceProviders: HISTORY_PROVIDER_DB_MIGRATE_SOURCES,
712
- });
713
- const modelCacheMigration = await (0, codex_model_cache_migration_1.ensureCodexModelCacheHasGpt54)({
714
- codexHome: paths_1.codexDir,
715
- });
716
- const optionalClients = [
746
+ const [codexDetected, kiloDetected, traeDetected] = await Promise.all([
747
+ detectCodexClient(),
748
+ detectKiloClient(),
749
+ detectTraeClient(),
750
+ ]);
751
+ const setupClients = [
752
+ {
753
+ id: "codex",
754
+ label: "Codex CLI, VS Code extension, and Codex app",
755
+ detected: codexDetected,
756
+ recommended: true,
757
+ },
717
758
  {
718
759
  id: "openclaw",
719
760
  label: "OpenClaw",
720
761
  detected: hasCommand("openclaw"),
721
762
  recommended: true,
722
- command: "openclaw",
723
763
  },
724
764
  {
725
765
  id: "opencode",
726
766
  label: "OpenCode",
727
767
  detected: hasCommand("opencode"),
728
768
  recommended: true,
729
- command: "opencode",
730
769
  },
731
770
  {
732
771
  id: "kilo",
733
772
  label: "Kilo Code",
734
- detected: await detectKiloClient(),
773
+ detected: kiloDetected,
735
774
  recommended: true,
736
- command: "kilo",
737
775
  },
738
776
  {
739
777
  id: "trae",
740
778
  label: "Trae (experimental)",
741
- detected: await detectTraeClient(),
779
+ detected: traeDetected,
742
780
  recommended: false,
743
- command: "Trae",
744
781
  },
745
782
  ];
746
- const selectedOptionalClients = await resolveOptionalClientSelection({
747
- optionalClients,
748
- flagSelection: parseOptionalClientFlags(flags.clients),
783
+ const selectedSetupClients = await resolveSetupClientSelection({
784
+ setupClients,
785
+ flagSelection: parseSetupClientFlags(flags.clients),
749
786
  skipPrompt: flags.yes,
750
787
  });
788
+ let resolved = null;
789
+ if (selectedSetupClients.size > 0) {
790
+ resolved = await resolveModels(backendUrl, apiKey);
791
+ }
792
+ await (0, config_1.writeManagedConfig)({ backendUrl, apiKey });
793
+ const updatedShellFiles = await persistApiKeyEnv(apiKey);
794
+ let codexConfigPath = null;
795
+ let updatedVsCodeEnvFiles = [];
796
+ let sessionMigration = null;
797
+ let authSeed = null;
798
+ let stateDbMigration = null;
799
+ let modelCacheMigration = null;
751
800
  let openClawConfigPath = null;
752
801
  let openClawCliWarning = null;
753
802
  let openCodePath = null;
754
803
  let kiloConfigPath = null;
755
804
  let traeBundlePathPatched = null;
756
- if (selectedOptionalClients.has("openclaw")) {
805
+ if (selectedSetupClients.has("codex")) {
806
+ codexConfigPath = await writeCodexConfig({ backendUrl, model: resolved?.model ?? DEFAULT_CODEX_MODEL, apiKey });
807
+ updatedVsCodeEnvFiles = await persistVsCodeServerEnvSource();
808
+ sessionMigration = await (0, codex_history_migration_1.migrateSessionProviders)({
809
+ codexHome: paths_1.codexDir,
810
+ migrationStateFile: MIGRATION_STATE_FILE,
811
+ neutralizeSources: HISTORY_PROVIDER_NEUTRALIZE_SOURCES,
812
+ });
813
+ authSeed = await (0, codex_auth_seeding_1.ensureCodexApiKeyAuth)({
814
+ codexHome: paths_1.codexDir,
815
+ apiKey,
816
+ });
817
+ stateDbMigration = await (0, codex_history_migration_1.migrateStateDbProviders)({
818
+ codexHome: paths_1.codexDir,
819
+ targetProvider: DEFAULT_PROVIDER_ID,
820
+ sourceProviders: HISTORY_PROVIDER_DB_MIGRATE_SOURCES,
821
+ });
822
+ modelCacheMigration = await (0, codex_model_cache_migration_1.ensureCodexModelCacheHasGpt54)({
823
+ codexHome: paths_1.codexDir,
824
+ });
825
+ }
826
+ if (selectedSetupClients.has("openclaw")) {
757
827
  const openClawResult = await setupOpenClaw({
758
828
  backendUrl,
759
- model: resolved.model,
760
- models: resolved.models,
829
+ model: resolved?.model ?? DEFAULT_CODEX_MODEL,
830
+ models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
761
831
  apiKey,
762
832
  });
763
833
  openClawConfigPath = openClawResult.configPath;
764
834
  openClawCliWarning = openClawResult.cliWarning ?? null;
765
835
  }
766
- if (selectedOptionalClients.has("opencode")) {
836
+ if (selectedSetupClients.has("opencode")) {
767
837
  openCodePath = await writeOpenCodeConfig({
768
838
  backendUrl,
769
- model: resolved.model,
770
- models: resolved.models,
839
+ model: resolved?.model ?? DEFAULT_CODEX_MODEL,
840
+ models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
771
841
  apiKey,
772
842
  });
773
843
  }
774
- if (selectedOptionalClients.has("kilo")) {
844
+ if (selectedSetupClients.has("kilo")) {
775
845
  kiloConfigPath = await writeKiloConfig({
776
846
  backendUrl,
777
- model: resolved.model,
778
- models: resolved.models,
847
+ model: resolved?.model ?? DEFAULT_CODEX_MODEL,
848
+ models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
779
849
  apiKey,
780
850
  });
781
851
  }
782
- if (selectedOptionalClients.has("trae")) {
852
+ if (selectedSetupClients.has("trae")) {
783
853
  traeBundlePathPatched = await patchTraeBundle({
784
854
  backendUrl,
785
- model: resolved.model,
855
+ model: resolved?.model ?? DEFAULT_CODEX_MODEL,
786
856
  apiKey,
787
- models: resolved.models,
857
+ models: resolved?.models ?? [{ id: DEFAULT_CODEX_MODEL, name: modelDisplayName(DEFAULT_CODEX_MODEL) }],
788
858
  });
789
859
  }
790
860
  this.log("Setup complete");
791
861
  this.log(`- Managed config: ${paths_1.managedConfigPath}`);
792
862
  this.log(`- Backend: ${backendUrl}`);
793
- this.log(`- Codex config: ${codexConfigPath}`);
794
- this.log(`- Codex model: ${resolved.model}`);
795
- this.log("- Recommended base setup: Codex CLI, Codex VS Code extension, and the Codex app");
796
- if (resolved.note)
797
- this.log(resolved.note);
798
- if (sessionMigration.rewritten > 0) {
799
- this.log(`- Conversations: updated ${sessionMigration.rewritten}/${sessionMigration.scanned} local sessions for cross-provider visibility.`);
800
- }
801
- else if (sessionMigration.fastSkipped) {
802
- this.log("- Conversations: already migrated (fast check).");
803
- }
804
- else {
805
- this.log("- Conversations: no local sessions required migration.");
806
- }
807
- if (sessionMigration.retimed > 0) {
808
- this.log(`- Conversation ordering: repaired timestamps on ${sessionMigration.retimed} local sessions.`);
863
+ if (selectedSetupClients.size === 0) {
864
+ this.log("- Local clients: none selected; saved managed config and API key env only.");
809
865
  }
810
- if (stateDbMigration.updated > 0) {
811
- this.log(`- Conversation cache: relabeled ${stateDbMigration.updated} local Codex history rows for The Claw Bay.`);
812
- }
813
- else if (stateDbMigration.failed.length > 0) {
814
- const detail = stateDbMigration.warning ? ` ${stateDbMigration.warning}` : "";
815
- this.log(`- Conversation cache: could not update local Codex history DB.${detail}`);
816
- }
817
- if (modelCacheMigration.action === "seeded") {
818
- this.log("- Codex model cache: added GPT-5.4 to the local picker cache.");
819
- }
820
- else if (modelCacheMigration.action === "created") {
821
- this.log("- Codex model cache: created a local picker cache with GPT-5.4.");
822
- }
823
- else if (modelCacheMigration.action === "refreshed") {
824
- this.log("- Codex model cache: refreshed the local picker cache for GPT-5.4.");
825
- }
826
- else if (modelCacheMigration.action === "already_seeded") {
827
- this.log("- Codex model cache: GPT-5.4 was already seeded locally.");
828
- }
829
- else if (modelCacheMigration.action === "already_present") {
830
- this.log("- Codex model cache: GPT-5.4 already existed locally.");
831
- }
832
- else if (modelCacheMigration.warning) {
833
- this.log(`- Codex model cache: ${modelCacheMigration.warning}`);
866
+ if (resolved?.note)
867
+ this.log(resolved.note);
868
+ this.log(`- API key env: ${ENV_FILE}`);
869
+ this.log(`- Shell profiles updated: ${updatedShellFiles.join(", ")}`);
870
+ if (selectedSetupClients.has("codex")) {
871
+ this.log(`- Codex: configured (${codexConfigPath})`);
872
+ if (resolved)
873
+ this.log(`- Codex model: ${resolved.model}`);
874
+ this.log(`- VS Code env hooks updated: ${updatedVsCodeEnvFiles.join(", ")}`);
875
+ if (sessionMigration?.rewritten) {
876
+ this.log(`- Conversations: updated ${sessionMigration.rewritten}/${sessionMigration.scanned} local sessions for cross-provider visibility.`);
877
+ }
878
+ else if (sessionMigration?.fastSkipped) {
879
+ this.log("- Conversations: already migrated (fast check).");
880
+ }
881
+ else if (sessionMigration) {
882
+ this.log("- Conversations: no local sessions required migration.");
883
+ }
884
+ if ((sessionMigration?.retimed ?? 0) > 0) {
885
+ this.log(`- Conversation ordering: repaired timestamps on ${sessionMigration?.retimed ?? 0} local sessions.`);
886
+ }
887
+ if ((stateDbMigration?.updated ?? 0) > 0) {
888
+ this.log(`- Conversation cache: relabeled ${stateDbMigration?.updated ?? 0} local Codex history rows for The Claw Bay.`);
889
+ }
890
+ else if ((stateDbMigration?.failed.length ?? 0) > 0) {
891
+ const detail = stateDbMigration?.warning ? ` ${stateDbMigration.warning}` : "";
892
+ this.log(`- Conversation cache: could not update local Codex history DB.${detail}`);
893
+ }
894
+ if (modelCacheMigration?.action === "seeded") {
895
+ this.log("- Codex model cache: added GPT-5.4 to the local picker cache.");
896
+ }
897
+ else if (modelCacheMigration?.action === "created") {
898
+ this.log("- Codex model cache: created a local picker cache with GPT-5.4.");
899
+ }
900
+ else if (modelCacheMigration?.action === "refreshed") {
901
+ this.log("- Codex model cache: refreshed the local picker cache for GPT-5.4.");
902
+ }
903
+ else if (modelCacheMigration?.action === "already_seeded") {
904
+ this.log("- Codex model cache: GPT-5.4 was already seeded locally.");
905
+ }
906
+ else if (modelCacheMigration?.action === "already_present") {
907
+ this.log("- Codex model cache: GPT-5.4 already existed locally.");
908
+ }
909
+ else if (modelCacheMigration?.warning) {
910
+ this.log(`- Codex model cache: ${modelCacheMigration.warning}`);
911
+ }
912
+ else if (modelCacheMigration) {
913
+ this.log("- Codex model cache: no change.");
914
+ }
915
+ }
916
+ else if (codexDetected) {
917
+ this.log("- Codex: detected but skipped");
834
918
  }
835
919
  else {
836
- this.log("- Codex model cache: no change.");
920
+ this.log("- Codex: not detected (skipped)");
837
921
  }
838
- this.log(`- API key env: ${ENV_FILE}`);
839
- this.log(`- Shell profiles updated: ${updatedShellFiles.join(", ")}`);
840
- this.log(`- VS Code env hooks updated: ${updatedVsCodeEnvFiles.join(", ")}`);
841
- const openClawDetected = optionalClients.find((client) => client.id === "openclaw")?.detected ?? false;
842
- if (selectedOptionalClients.has("openclaw")) {
922
+ const openClawDetected = setupClients.find((client) => client.id === "openclaw")?.detected ?? false;
923
+ if (selectedSetupClients.has("openclaw")) {
843
924
  this.log(`- OpenClaw: configured (${openClawConfigPath})`);
844
925
  if (openClawCliWarning)
845
926
  this.log(`- OpenClaw: ${openClawCliWarning}`);
@@ -850,8 +931,8 @@ class SetupCommand extends base_command_1.BaseCommand {
850
931
  else {
851
932
  this.log("- OpenClaw: not detected (skipped)");
852
933
  }
853
- const openCodeDetected = optionalClients.find((client) => client.id === "opencode")?.detected ?? false;
854
- if (selectedOptionalClients.has("opencode")) {
934
+ const openCodeDetected = setupClients.find((client) => client.id === "opencode")?.detected ?? false;
935
+ if (selectedSetupClients.has("opencode")) {
855
936
  this.log(`- OpenCode: configured (${openCodePath})`);
856
937
  }
857
938
  else if (openCodeDetected) {
@@ -860,8 +941,7 @@ class SetupCommand extends base_command_1.BaseCommand {
860
941
  else {
861
942
  this.log("- OpenCode: not detected (skipped)");
862
943
  }
863
- const kiloDetected = optionalClients.find((client) => client.id === "kilo")?.detected ?? false;
864
- if (selectedOptionalClients.has("kilo")) {
944
+ if (selectedSetupClients.has("kilo")) {
865
945
  this.log(`- Kilo Code: configured (${kiloConfigPath})`);
866
946
  }
867
947
  else if (kiloDetected) {
@@ -870,10 +950,9 @@ class SetupCommand extends base_command_1.BaseCommand {
870
950
  else {
871
951
  this.log("- Kilo Code: not detected (skipped)");
872
952
  }
873
- const traeDetected = optionalClients.find((client) => client.id === "trae")?.detected ?? false;
874
- if (selectedOptionalClients.has("trae")) {
953
+ if (selectedSetupClients.has("trae")) {
875
954
  this.log(`- Trae: experimental bundle patch installed (${traeBundlePathPatched})`);
876
- this.log(`- Trae: replaced Builder and SoloCoder model lists with ${resolved.models.length} TheClawBay models.`);
955
+ this.log(`- Trae: replaced Builder and SoloCoder model lists with ${resolved?.models.length ?? 1} TheClawBay models.`);
877
956
  this.log(`- Trae: restart Trae and select a TheClawBay model inside Trae to test it.`);
878
957
  }
879
958
  else if (traeDetected) {
@@ -882,22 +961,22 @@ class SetupCommand extends base_command_1.BaseCommand {
882
961
  else {
883
962
  this.log("- Trae: not detected (skipped)");
884
963
  }
885
- if (authSeed.action === "seeded") {
964
+ if (authSeed?.action === "seeded") {
886
965
  this.log("- Codex login state: seeded local API-key auth for Codex UI.");
887
966
  }
888
- else if (authSeed.action === "updated") {
967
+ else if (authSeed?.action === "updated") {
889
968
  this.log("- Codex login state: refreshed the Claw Bay API-key auth seed.");
890
969
  }
891
- else if (authSeed.action === "already_seeded") {
970
+ else if (authSeed?.action === "already_seeded") {
892
971
  this.log("- Codex login state: the Claw Bay API-key auth was already seeded.");
893
972
  }
894
- else if (authSeed.action === "already_present") {
973
+ else if (authSeed?.action === "already_present") {
895
974
  this.log("- Codex login state: preserved existing local Codex auth.");
896
975
  }
897
- else if (authSeed.warning) {
976
+ else if (authSeed?.warning) {
898
977
  this.log(`- Codex login state: ${authSeed.warning}`);
899
978
  }
900
- else {
979
+ else if (authSeed) {
901
980
  this.log("- Codex login state: no change.");
902
981
  }
903
982
  this.log("Next: restart terminal/VS Code window only if you rely on the The Claw Bay API key in your own scripts.");
@@ -917,7 +996,7 @@ SetupCommand.flags = {
917
996
  }),
918
997
  clients: core_1.Flags.string({
919
998
  required: false,
920
- description: "Optional detected add-ons to configure: codex, openclaw, opencode, kilo, trae",
999
+ description: "Detected local clients to configure: codex, openclaw, opencode, kilo, trae",
921
1000
  }),
922
1001
  yes: core_1.Flags.boolean({
923
1002
  required: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "theclawbay",
3
- "version": "0.3.25",
3
+ "version": "0.3.26",
4
4
  "description": "CLI for connecting Codex, OpenClaw, OpenCode, Kilo, and experimental Trae to The Claw Bay.",
5
5
  "license": "MIT",
6
6
  "bin": {