theclawbay 0.3.59 → 0.3.61

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
@@ -29,3 +29,7 @@ Saves the API key without writing local client config.
29
29
  `theclawbay logout`
30
30
 
31
31
  Removes The Claw Bay-managed local config from this machine.
32
+
33
+ `theclawbay usage`
34
+
35
+ Shows your current shared 5-hour and weekly usage windows.
@@ -27,7 +27,7 @@ const DEFAULT_PROVIDER_ID = "theclawbay";
27
27
  const CLI_HTTP_USER_AGENT = "theclawbay-cli";
28
28
  const SUPPORTED_MODEL_IDS = (0, supported_models_1.getSupportedModelIds)();
29
29
  const MODEL_DISPLAY_NAMES = (0, supported_models_1.getSupportedModelDisplayNames)();
30
- const DEFAULT_CODEX_MODEL = SUPPORTED_MODEL_IDS[0] ?? "gpt-5.4";
30
+ const DEFAULT_CODEX_MODEL = SUPPORTED_MODEL_IDS.includes("gpt-5.4") ? "gpt-5.4" : (SUPPORTED_MODEL_IDS[0] ?? "gpt-5.4");
31
31
  const DEFAULT_CONTINUE_MODEL = DEFAULT_CODEX_MODEL;
32
32
  const DEFAULT_CLINE_MODEL = DEFAULT_CODEX_MODEL;
33
33
  const DEFAULT_OPENCLAW_MODEL = DEFAULT_CODEX_MODEL;
@@ -37,7 +37,7 @@ const DEFAULT_TRAE_MODEL = DEFAULT_CODEX_MODEL;
37
37
  const DEFAULT_AIDER_MODEL = DEFAULT_CODEX_MODEL;
38
38
  const DEFAULT_ZO_MODEL = DEFAULT_CODEX_MODEL;
39
39
  const DEFAULT_MODELS = [...SUPPORTED_MODEL_IDS];
40
- const PREFERRED_MODELS = [...SUPPORTED_MODEL_IDS];
40
+ const PREFERRED_MODELS = Array.from(new Set(["gpt-5.5", ...SUPPORTED_MODEL_IDS]));
41
41
  const ENV_KEY_NAME = "THECLAWBAY_API_KEY";
42
42
  const CLAUDE_ENV_API_KEY_NAME = "ANTHROPIC_API_KEY";
43
43
  const CLAUDE_ENV_BASE_URL_NAME = "ANTHROPIC_BASE_URL";
@@ -49,6 +49,8 @@ const CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING = "claudeCode.disableLogin
49
49
  const ANTHROPIC_PROVIDER_ID = "anthropic";
50
50
  const MANAGED_EDITOR_TERMINAL_ENV_NAMES = [
51
51
  ENV_KEY_NAME,
52
+ ];
53
+ const MANAGED_CLAUDE_ENV_NAMES = [
52
54
  CLAUDE_ENV_API_KEY_NAME,
53
55
  CLAUDE_ENV_BASE_URL_NAME,
54
56
  CLAUDE_ENV_SIMPLE_MODE_NAME,
@@ -736,6 +738,18 @@ async function readFileIfExists(filePath) {
736
738
  throw error;
737
739
  }
738
740
  }
741
+ async function removeFileIfExists(filePath) {
742
+ try {
743
+ await promises_1.default.unlink(filePath);
744
+ return true;
745
+ }
746
+ catch (error) {
747
+ const err = error;
748
+ if (err.code === "ENOENT")
749
+ return false;
750
+ throw error;
751
+ }
752
+ }
739
753
  async function readJsonObjectFile(filePath) {
740
754
  const existingRaw = await readFileIfExists(filePath);
741
755
  if (existingRaw === null || !existingRaw.trim())
@@ -1519,7 +1533,6 @@ async function writeCodexConfig(params) {
1519
1533
  'name = "OpenAI"',
1520
1534
  `base_url = "${nativeCodexBaseUrl}"`,
1521
1535
  'wire_api = "responses"',
1522
- "requires_openai_auth = true",
1523
1536
  "supports_websockets = true",
1524
1537
  `experimental_bearer_token = "${params.apiKey}"`,
1525
1538
  MANAGED_END,
@@ -1948,14 +1961,9 @@ function terminalIntegratedEnvSettingsKey() {
1948
1961
  return "terminal.integrated.env.linux";
1949
1962
  }
1950
1963
  function buildManagedEditorTerminalEnv(params) {
1951
- const env = {
1964
+ return {
1952
1965
  [ENV_KEY_NAME]: params.apiKey,
1953
1966
  };
1954
- if (params.claudeEnabled) {
1955
- env[CLAUDE_ENV_API_KEY_NAME] = params.apiKey;
1956
- env[CLAUDE_ENV_BASE_URL_NAME] = anthropicCompatibleProxyUrl(params.backendUrl);
1957
- }
1958
- return env;
1959
1967
  }
1960
1968
  function buildManagedClaudeEditorEnv(params) {
1961
1969
  return {
@@ -2069,7 +2077,7 @@ async function persistClaudeEditorSettings(params) {
2069
2077
  nextEnv[name] = value;
2070
2078
  changed = true;
2071
2079
  }
2072
- for (const name of MANAGED_EDITOR_TERMINAL_ENV_NAMES) {
2080
+ for (const name of MANAGED_CLAUDE_ENV_NAMES) {
2073
2081
  if (name in desiredEnv || !(name in nextEnv))
2074
2082
  continue;
2075
2083
  delete nextEnv[name];
@@ -2099,6 +2107,126 @@ async function persistClaudeEditorSettings(params) {
2099
2107
  await writeJsonObjectFile(CLAUDE_EDITOR_SETTINGS_STATE_PATH, Array.from(snapshotByPath.values()), 0o600);
2100
2108
  return managedPaths;
2101
2109
  }
2110
+ async function cleanupClaudeEditorSettings() {
2111
+ const snapshotRaw = await readFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
2112
+ if (snapshotRaw === null || !snapshotRaw.trim())
2113
+ return [];
2114
+ let entries = [];
2115
+ try {
2116
+ entries = JSON.parse(snapshotRaw);
2117
+ }
2118
+ catch {
2119
+ return [];
2120
+ }
2121
+ const updated = [];
2122
+ for (const entry of entries) {
2123
+ const settings = await readJsonObjectFile(entry.settingsPath);
2124
+ if (!entry.envHadKey) {
2125
+ delete settings[CLAUDE_CODE_EDITOR_ENV_SETTING];
2126
+ }
2127
+ else {
2128
+ settings[CLAUDE_CODE_EDITOR_ENV_SETTING] = entry.envPreviousValue;
2129
+ }
2130
+ if (!entry.disableLoginPromptHadKey) {
2131
+ delete settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING];
2132
+ }
2133
+ else {
2134
+ settings[CLAUDE_CODE_EDITOR_DISABLE_LOGIN_PROMPT_SETTING] = entry.disableLoginPromptPreviousValue;
2135
+ }
2136
+ if (entry.existed || Object.keys(settings).length > 0) {
2137
+ await writeJsonObjectFile(entry.settingsPath, settings);
2138
+ updated.push(entry.settingsPath);
2139
+ continue;
2140
+ }
2141
+ if (await removeFileIfExists(entry.settingsPath)) {
2142
+ updated.push(entry.settingsPath);
2143
+ }
2144
+ }
2145
+ await removeFileIfExists(CLAUDE_EDITOR_SETTINGS_STATE_PATH);
2146
+ return updated;
2147
+ }
2148
+ async function cleanupClaudeDesktop3pConfig() {
2149
+ const snapshotRaw = await readFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
2150
+ if (snapshotRaw === null || !snapshotRaw.trim())
2151
+ return false;
2152
+ let snapshot = null;
2153
+ try {
2154
+ snapshot = JSON.parse(snapshotRaw);
2155
+ }
2156
+ catch {
2157
+ snapshot = null;
2158
+ }
2159
+ if (!snapshot?.configPath) {
2160
+ await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
2161
+ return false;
2162
+ }
2163
+ if (!snapshot.existed) {
2164
+ const removed = await removeFileIfExists(snapshot.configPath);
2165
+ await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
2166
+ return removed;
2167
+ }
2168
+ const previousRaw = snapshot.previousRaw ?? "";
2169
+ const existingRaw = await readFileIfExists(snapshot.configPath);
2170
+ if (existingRaw === previousRaw) {
2171
+ await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
2172
+ return false;
2173
+ }
2174
+ await promises_1.default.mkdir(node_path_1.default.dirname(snapshot.configPath), { recursive: true });
2175
+ await promises_1.default.writeFile(snapshot.configPath, previousRaw, "utf8");
2176
+ await removeFileIfExists(CLAUDE_DESKTOP_3P_STATE_PATH);
2177
+ return true;
2178
+ }
2179
+ async function cleanupLegacyClaudeEditorTerminalEnvSettings(params) {
2180
+ const snapshotRaw = await readFileIfExists(EDITOR_TERMINAL_ENV_STATE_PATH);
2181
+ if (snapshotRaw === null || !snapshotRaw.trim())
2182
+ return [];
2183
+ let entries = [];
2184
+ try {
2185
+ entries = JSON.parse(snapshotRaw);
2186
+ }
2187
+ catch {
2188
+ return [];
2189
+ }
2190
+ const settingsKey = terminalIntegratedEnvSettingsKey();
2191
+ const managedClaudeEnv = {
2192
+ [CLAUDE_ENV_API_KEY_NAME]: params.apiKey,
2193
+ [CLAUDE_ENV_BASE_URL_NAME]: anthropicCompatibleProxyUrl(params.backendUrl),
2194
+ };
2195
+ const updated = [];
2196
+ for (const entry of entries) {
2197
+ const settings = await readJsonObjectFile(entry.settingsPath);
2198
+ const currentValue = settings[settingsKey];
2199
+ if (typeof currentValue !== "object" || currentValue === null || Array.isArray(currentValue))
2200
+ continue;
2201
+ const currentEnv = { ...currentValue };
2202
+ const previousEnv = typeof entry.previousValue === "object" &&
2203
+ entry.previousValue !== null &&
2204
+ !Array.isArray(entry.previousValue)
2205
+ ? { ...entry.previousValue }
2206
+ : {};
2207
+ let changed = false;
2208
+ for (const name of MANAGED_CLAUDE_ENV_NAMES) {
2209
+ const expectedManagedValue = managedClaudeEnv[name];
2210
+ const currentManagedValue = currentEnv[name];
2211
+ const currentMatchesManaged = typeof expectedManagedValue === "string" ? currentManagedValue === expectedManagedValue : false;
2212
+ if (!currentMatchesManaged)
2213
+ continue;
2214
+ if (Object.prototype.hasOwnProperty.call(previousEnv, name)) {
2215
+ currentEnv[name] = previousEnv[name];
2216
+ }
2217
+ else {
2218
+ delete currentEnv[name];
2219
+ }
2220
+ changed = true;
2221
+ }
2222
+ if (!changed)
2223
+ continue;
2224
+ settings[settingsKey] = currentEnv;
2225
+ await writeJsonObjectFile(entry.settingsPath, settings);
2226
+ updated.push(entry.settingsPath);
2227
+ }
2228
+ return updated;
2229
+ }
2102
2230
  function expandClaudeDesktopInferenceModels(modelIds) {
2103
2231
  const expanded = [];
2104
2232
  const add = (value) => {
@@ -2285,10 +2413,12 @@ function objectRecordOr(value, fallback) {
2285
2413
  function modelContextLimit(modelId) {
2286
2414
  if (modelId === "gpt-5.4")
2287
2415
  return 1050000;
2416
+ if (modelId === "gpt-5.5")
2417
+ return 1000000;
2288
2418
  return 272000;
2289
2419
  }
2290
2420
  function modelOutputLimit(modelId) {
2291
- if (modelId === "gpt-5.4")
2421
+ if (modelId === "gpt-5.4" || modelId === "gpt-5.5")
2292
2422
  return 128000;
2293
2423
  return 65536;
2294
2424
  }
@@ -2852,9 +2982,9 @@ class SetupCommand extends base_command_1.BaseCommand {
2852
2982
  let updatedVsCodeEnvFiles = [];
2853
2983
  let updatedEditorTerminalSettings = [];
2854
2984
  let updatedClaudeEditorSettings = [];
2985
+ let restoredClaudeDesktop3pConfig = false;
2855
2986
  let claudeDesktop3pConfigPathManaged = null;
2856
2987
  let sessionMigration = null;
2857
- let authSeed = null;
2858
2988
  let authSeedCleanup = null;
2859
2989
  let stateDbMigration = null;
2860
2990
  let modelCacheMigration = null;
@@ -2914,18 +3044,34 @@ class SetupCommand extends base_command_1.BaseCommand {
2914
3044
  backendUrl,
2915
3045
  claudeEnabled: claudeEnvEnabled,
2916
3046
  });
2917
- if (selectedSetupClients.has("claude")) {
2918
- updatedClaudeEditorSettings = await persistClaudeEditorSettings({
2919
- apiKey: authCredential,
2920
- backendUrl,
2921
- claudeEnabled: claudeEnvEnabled,
2922
- });
3047
+ }
3048
+ if (selectedSetupClients.has("claude")) {
3049
+ updatedClaudeEditorSettings = await persistClaudeEditorSettings({
3050
+ apiKey: authCredential,
3051
+ backendUrl,
3052
+ claudeEnabled: claudeEnvEnabled,
3053
+ });
3054
+ if (claudeEnvEnabled) {
2923
3055
  claudeDesktop3pConfigPathManaged = await writeClaudeDesktop3pConfig({
2924
3056
  backendUrl,
2925
3057
  apiKey: authCredential,
2926
3058
  claudeModels: claudeAccess?.enabled ? claudeAccess.models : [],
2927
3059
  });
2928
3060
  }
3061
+ else {
3062
+ restoredClaudeDesktop3pConfig = await cleanupClaudeDesktop3pConfig();
3063
+ }
3064
+ }
3065
+ else {
3066
+ updatedEditorTerminalSettings = [
3067
+ ...updatedEditorTerminalSettings,
3068
+ ...await cleanupLegacyClaudeEditorTerminalEnvSettings({
3069
+ apiKey: authCredential,
3070
+ backendUrl,
3071
+ }),
3072
+ ];
3073
+ updatedClaudeEditorSettings = await cleanupClaudeEditorSettings();
3074
+ restoredClaudeDesktop3pConfig = await cleanupClaudeDesktop3pConfig();
2929
3075
  }
2930
3076
  if (selectedSetupClients.has("codex")) {
2931
3077
  progress.update("Configuring Codex");
@@ -2944,10 +3090,6 @@ class SetupCommand extends base_command_1.BaseCommand {
2944
3090
  authSeedCleanup = await (0, codex_auth_seeding_1.cleanupSeededCodexAuth)({
2945
3091
  codexHome: paths_1.codexDir,
2946
3092
  });
2947
- authSeed = await (0, codex_auth_seeding_1.ensureCodexUsageLimitAuth)({
2948
- codexHome: paths_1.codexDir,
2949
- apiKey: authCredential,
2950
- });
2951
3093
  if (migrateCodexConversations) {
2952
3094
  stateDbMigration = await (0, codex_history_migration_1.migrateStateDbProviders)({
2953
3095
  codexHome: paths_1.codexDir,
@@ -3086,12 +3228,13 @@ class SetupCommand extends base_command_1.BaseCommand {
3086
3228
  }
3087
3229
  if (modelCacheMigration?.warning)
3088
3230
  summaryNotes.add(modelCacheMigration.warning);
3089
- if (authSeed?.warning)
3090
- summaryNotes.add(authSeed.warning);
3091
3231
  if (authSeedCleanup?.warning)
3092
3232
  summaryNotes.add(authSeedCleanup.warning);
3093
- if (authSeed?.replacedExistingAuth) {
3094
- summaryNotes.add("Codex usage visibility temporarily replaced your existing local Codex auth. `theclawbay logout` restores it.");
3233
+ if (authSeedCleanup?.action === "removed") {
3234
+ summaryNotes.add("Removed an older The Claw Bay Codex auth override that newer Codex releases now treat as invalid ChatGPT OAuth.");
3235
+ }
3236
+ else if (authSeedCleanup?.action === "restored_backup") {
3237
+ summaryNotes.add("Restored the Codex auth that existed before an older The Claw Bay auth override.");
3095
3238
  }
3096
3239
  if (selectedSetupClients.has("codex") && !migrateCodexConversations) {
3097
3240
  summaryNotes.add("Left existing Codex conversations untouched.");
@@ -3143,6 +3286,9 @@ class SetupCommand extends base_command_1.BaseCommand {
3143
3286
  if (updatedClaudeEditorSettings.length > 0) {
3144
3287
  this.log(`- Claude editor settings updated: ${updatedClaudeEditorSettings.join(", ")}`);
3145
3288
  }
3289
+ if (restoredClaudeDesktop3pConfig) {
3290
+ this.log("- Claude Desktop 3P config: restored the pre-The Claw Bay config.");
3291
+ }
3146
3292
  if (selectedSetupClients.has("codex")) {
3147
3293
  this.log(`- Codex: configured (${codexConfigPath})`);
3148
3294
  if (resolved)
@@ -3171,19 +3317,19 @@ class SetupCommand extends base_command_1.BaseCommand {
3171
3317
  this.log(`- Conversation cache: could not update local Codex history DB.${detail}`);
3172
3318
  }
3173
3319
  if (modelCacheMigration?.action === "seeded") {
3174
- this.log("- Codex model cache: added GPT-5.4 / GPT-5.4 Mini to the local picker cache.");
3320
+ this.log("- Codex model cache: added the current The Claw Bay model catalog to the local picker cache.");
3175
3321
  }
3176
3322
  else if (modelCacheMigration?.action === "created") {
3177
- this.log("- Codex model cache: created a local picker cache with GPT-5.4 / GPT-5.4 Mini.");
3323
+ this.log("- Codex model cache: created a local picker cache with the current The Claw Bay model catalog.");
3178
3324
  }
3179
3325
  else if (modelCacheMigration?.action === "refreshed") {
3180
- this.log("- Codex model cache: refreshed the local picker cache for GPT-5.4 / GPT-5.4 Mini.");
3326
+ this.log("- Codex model cache: refreshed the local picker cache for the current The Claw Bay model catalog.");
3181
3327
  }
3182
3328
  else if (modelCacheMigration?.action === "already_seeded") {
3183
- this.log("- Codex model cache: GPT-5.4 / GPT-5.4 Mini were already seeded locally.");
3329
+ this.log("- Codex model cache: the current The Claw Bay model catalog was already seeded locally.");
3184
3330
  }
3185
3331
  else if (modelCacheMigration?.action === "already_present") {
3186
- this.log("- Codex model cache: GPT-5.4 / GPT-5.4 Mini already existed locally.");
3332
+ this.log("- Codex model cache: the current The Claw Bay model catalog already existed locally.");
3187
3333
  }
3188
3334
  else if (modelCacheMigration?.warning) {
3189
3335
  this.log(`- Codex model cache: ${modelCacheMigration.warning}`);
@@ -3191,6 +3337,18 @@ class SetupCommand extends base_command_1.BaseCommand {
3191
3337
  else if (modelCacheMigration) {
3192
3338
  this.log("- Codex model cache: no change.");
3193
3339
  }
3340
+ if (authSeedCleanup?.action === "restored_backup") {
3341
+ this.log("- Codex login state: restored the auth that existed before an older The Claw Bay override.");
3342
+ }
3343
+ else if (authSeedCleanup?.action === "removed") {
3344
+ this.log("- Codex login state: removed the older The Claw Bay ChatGPT-token override for compatibility with current Codex releases.");
3345
+ }
3346
+ else if (authSeedCleanup?.warning) {
3347
+ this.log(`- Codex login state: ${authSeedCleanup.warning}`);
3348
+ }
3349
+ else {
3350
+ this.log("- Codex login state: using provider-scoped bearer auth only; no fake ChatGPT auth tokens were seeded.");
3351
+ }
3194
3352
  }
3195
3353
  else if (codexDetected) {
3196
3354
  this.log("- Codex: detected but skipped");
@@ -3319,36 +3477,6 @@ class SetupCommand extends base_command_1.BaseCommand {
3319
3477
  else {
3320
3478
  this.log("- Claude Code: not detected (skipped)");
3321
3479
  }
3322
- if (authSeed?.action === "seeded" && authSeed.mode === "chatgpt-auth-tokens") {
3323
- this.log("- Codex login state: seeded local Codex auth so remaining usage can be shown.");
3324
- }
3325
- else if (authSeed?.action === "updated" && authSeed.mode === "chatgpt-auth-tokens") {
3326
- this.log("- Codex login state: refreshed the local usage-limit auth seed.");
3327
- }
3328
- else if (authSeed?.action === "already_seeded" && authSeed.mode === "chatgpt-auth-tokens") {
3329
- this.log("- Codex login state: the local usage-limit auth seed was already present.");
3330
- }
3331
- else if (authSeed?.action === "seeded") {
3332
- this.log("- Codex login state: seeded local API-key auth.");
3333
- }
3334
- else if (authSeed?.action === "updated") {
3335
- this.log("- Codex login state: refreshed the local API-key auth seed.");
3336
- }
3337
- else if (authSeed?.action === "already_seeded") {
3338
- this.log("- Codex login state: the local API-key auth seed was already present.");
3339
- }
3340
- else if (authSeed?.action === "already_present") {
3341
- this.log("- Codex login state: preserved existing local Codex auth.");
3342
- }
3343
- else if (authSeed?.warning) {
3344
- this.log(`- Codex login state: ${authSeed.warning}`);
3345
- }
3346
- else if (authSeed) {
3347
- this.log("- Codex login state: no change.");
3348
- }
3349
- if (authSeedCleanup?.action === "restored_backup") {
3350
- this.log("- Codex login state: restored the auth that existed before an older The Claw Bay Codex auth override.");
3351
- }
3352
3480
  this.log("Next: restart Continue, Cline, Roo Code, Trae, or Zo only if they were already open during setup.");
3353
3481
  });
3354
3482
  }
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from "../lib/base-command";
2
+ export default class UsageCommand extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ backend: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ "api-key": import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../lib/base-command");
5
+ const api_key_1 = require("../lib/managed/api-key");
6
+ const config_1 = require("../lib/managed/config");
7
+ const errors_1 = require("../lib/managed/errors");
8
+ const DEFAULT_BACKEND_URL = "https://theclawbay.com";
9
+ function formatPercent(value) {
10
+ if (typeof value !== "number" || !Number.isFinite(value))
11
+ return "n/a";
12
+ return `${value.toFixed(value >= 10 ? 1 : 2).replace(/\.0+$/u, "").replace(/(\.\d*?)0+$/u, "$1")}%`;
13
+ }
14
+ function formatUsd(value) {
15
+ if (typeof value !== "number" || !Number.isFinite(value))
16
+ return "n/a";
17
+ return new Intl.NumberFormat("en-US", {
18
+ style: "currency",
19
+ currency: "USD",
20
+ minimumFractionDigits: 2,
21
+ maximumFractionDigits: 2,
22
+ }).format(value);
23
+ }
24
+ function formatTimestamp(value) {
25
+ if (!value)
26
+ return "n/a";
27
+ const parsed = Date.parse(value);
28
+ if (!Number.isFinite(parsed))
29
+ return value;
30
+ return new Date(parsed).toISOString();
31
+ }
32
+ function formatDuration(seconds) {
33
+ const totalSeconds = Math.max(0, Math.round(seconds));
34
+ const days = Math.floor(totalSeconds / 86400);
35
+ const hours = Math.floor((totalSeconds % 86400) / 3600);
36
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
37
+ const remainingSeconds = totalSeconds % 60;
38
+ const parts = [];
39
+ if (days > 0)
40
+ parts.push(`${days}d`);
41
+ if (hours > 0)
42
+ parts.push(`${hours}h`);
43
+ if (minutes > 0)
44
+ parts.push(`${minutes}m`);
45
+ if (parts.length === 0 || (parts.length < 2 && remainingSeconds > 0)) {
46
+ parts.push(`${remainingSeconds}s`);
47
+ }
48
+ return parts.slice(0, 2).join(" ");
49
+ }
50
+ function printWindow(log, label, window, showCosts) {
51
+ log(`${label}`);
52
+ log(` Used: ${formatPercent(window.progressPercentUsed ?? window.percentUsed)}`);
53
+ log(` Remaining: ${formatPercent(window.percentRemaining)}`);
54
+ log(` Requests: ${window.requestCount} total, ${window.successCount} succeeded, ${window.failedCount} failed`);
55
+ log(` Runtime: ${window.runtimeSecondsUsed.toFixed(1)}s`);
56
+ log(` Resets: ${formatDuration(window.secondsUntilReset)} (${formatTimestamp(window.windowEnd)})`);
57
+ if (showCosts) {
58
+ log(` Cost: ${formatUsd(window.estimatedCostUsdUsed)} used / ${formatUsd(window.costUsdLimit)} limit / ${formatUsd(window.costUsdRemaining)} remaining`);
59
+ }
60
+ log(` Last request: ${formatTimestamp(window.lastRequestAt)}`);
61
+ if (window.limitReached) {
62
+ log(" Status: limit reached");
63
+ }
64
+ }
65
+ class UsageCommand extends base_command_1.BaseCommand {
66
+ async run() {
67
+ await this.runSafe(async () => {
68
+ const { flags } = await this.parse(UsageCommand);
69
+ let managed = null;
70
+ try {
71
+ managed = await (0, config_1.readManagedConfig)();
72
+ }
73
+ catch (error) {
74
+ if (!(error instanceof errors_1.ManagedConfigMissingError))
75
+ throw error;
76
+ }
77
+ const credential = (flags["api-key"] ?? managed?.credential ?? "").trim();
78
+ if (!credential) {
79
+ this.error('No saved credential found. Run "theclawbay setup" or pass --api-key.');
80
+ }
81
+ const backendRaw = flags.backend ??
82
+ (0, api_key_1.tryInferBackendUrlFromApiKey)(credential) ??
83
+ managed?.backendUrl ??
84
+ DEFAULT_BACKEND_URL;
85
+ const backendUrl = backendRaw.replace(/\/+$/u, "");
86
+ const response = await fetch(`${backendUrl}/api/codex-auth/v1/quota`, {
87
+ headers: {
88
+ Authorization: `Bearer ${credential}`,
89
+ Accept: "application/json",
90
+ },
91
+ signal: AbortSignal.timeout(20000),
92
+ });
93
+ const body = (await response.json().catch(() => ({})));
94
+ if (!response.ok) {
95
+ this.error(body.error || `Failed to load usage (HTTP ${response.status})`);
96
+ }
97
+ if (flags.json) {
98
+ this.log(JSON.stringify(body, null, 2));
99
+ return;
100
+ }
101
+ const showCosts = body.usageLimitPresentation !== "percent_only";
102
+ this.log("The Claw Bay usage");
103
+ this.log(`Observed: ${formatTimestamp(body.observedAt)}`);
104
+ this.log(`Auth scope: ${body.pooled ? "shared pooled usage" : body.mode}`);
105
+ if (body.mode === "direct" && typeof body.planMultiplier === "number" && Number.isFinite(body.planMultiplier)) {
106
+ this.log(`Plan multiplier: ${body.planMultiplier}x`);
107
+ }
108
+ if (body.anyLimitReached) {
109
+ this.log("Status: at least one usage window has been reached");
110
+ }
111
+ this.log("");
112
+ printWindow((message) => this.log(message), "5-hour window", body.usage.fiveHour, showCosts);
113
+ this.log("");
114
+ printWindow((message) => this.log(message), "Weekly window", body.usage.weekly, showCosts);
115
+ });
116
+ }
117
+ }
118
+ UsageCommand.description = "Show your current The Claw Bay pooled 5-hour and weekly usage";
119
+ UsageCommand.flags = {
120
+ backend: core_1.Flags.string({
121
+ required: false,
122
+ description: "Backend base URL override (default: saved managed config or https://theclawbay.com)",
123
+ }),
124
+ "api-key": core_1.Flags.string({
125
+ required: false,
126
+ aliases: ["apiKey"],
127
+ description: "API key or linked device-session token override",
128
+ }),
129
+ json: core_1.Flags.boolean({
130
+ required: false,
131
+ default: false,
132
+ description: "Print the raw quota response as JSON",
133
+ }),
134
+ };
135
+ exports.default = UsageCommand;
@@ -240,12 +240,11 @@ async function ensureCodexApiKeyAuth(params) {
240
240
  });
241
241
  }
242
242
  async function ensureCodexUsageLimitAuth(params) {
243
- return ensureCodexAuth({
244
- codexHome: params.codexHome,
245
- apiKey: params.apiKey,
246
- mode: "chatgpt-auth-tokens",
247
- replaceExistingAuth: true,
248
- });
243
+ // Current Codex releases treat chatgptAuthTokens.access_token as a real
244
+ // ChatGPT JWT and use it against chatgpt.com. The Claw Bay credentials are
245
+ // provider-scoped bearer tokens, so the legacy fake-ChatGPT seed path is no
246
+ // longer safe to apply here.
247
+ return ensureCodexApiKeyAuth(params);
249
248
  }
250
249
  async function cleanupSeededCodexAuth(params) {
251
250
  const authPath = node_path_1.default.join(params.codexHome, AUTH_FILE);
@@ -14,13 +14,15 @@ const supported_models_1 = require("./supported-models");
14
14
  const MODELS_CACHE_FILE = "models_cache.json";
15
15
  const MODELS_CACHE_STATE_FILE = "theclawbay.models-cache.json";
16
16
  const STATE_DB_FILE_PATTERN = /^state_\d+\.sqlite$/;
17
- const TARGET_MODEL_IDS = ["gpt-5.4", "gpt-5.4-mini"];
17
+ const TARGET_MODEL_IDS = (0, supported_models_1.getSupportedModelIds)();
18
18
  const TARGET_MODEL_ID_SET = new Set(TARGET_MODEL_IDS);
19
19
  const SEED_MARKER_KEY = "_theclawbay_seeded";
20
20
  // Older releases stored the model id as the marker value; accept those so cleanup still works.
21
21
  const SEED_MARKER_VALUE = "theclawbay";
22
- const LEGACY_SEED_MARKER_VALUES = new Set(["gpt-5.4", SEED_MARKER_VALUE, true]);
23
- const TEMPLATE_MODEL_IDS = (0, supported_models_1.getSupportedModelIds)().filter((id) => !TARGET_MODEL_ID_SET.has(id));
22
+ const LEGACY_SEED_MARKER_VALUES = new Set([...TARGET_MODEL_IDS, SEED_MARKER_VALUE, true]);
23
+ const SUPPORTED_MODELS = (0, supported_models_1.getSupportedModels)();
24
+ const SUPPORTED_MODEL_CONFIG = new Map(SUPPORTED_MODELS.map((model) => [model.id, model]));
25
+ const TEMPLATE_MODEL_IDS = TARGET_MODEL_IDS;
24
26
  const DEFAULT_REASONING_LEVELS = [
25
27
  { effort: "low", description: "Fast responses with lighter reasoning" },
26
28
  { effort: "medium", description: "Balances speed and reasoning depth for everyday tasks" },
@@ -166,14 +168,13 @@ function applySeedMarker(model) {
166
168
  return next;
167
169
  }
168
170
  function seedDescription(modelId) {
169
- if (modelId === "gpt-5.4-mini")
170
- return "Smaller GPT-5.4 variant for quick iterations.";
171
- return "Latest frontier agentic coding model.";
171
+ return SUPPORTED_MODEL_CONFIG.get(modelId)?.note ?? "The Claw Bay model.";
172
172
  }
173
173
  function normalizeSeedModel(template, modelId) {
174
+ const modelConfig = SUPPORTED_MODEL_CONFIG.get(modelId);
174
175
  const seed = applySeedMarker(template ?? {});
175
176
  seed.slug = modelId;
176
- seed.display_name = modelId;
177
+ seed.display_name = modelConfig?.label ?? modelId;
177
178
  seed.description = seedDescription(modelId);
178
179
  if (typeof seed.default_reasoning_level !== "string") {
179
180
  seed.default_reasoning_level = "medium";
@@ -387,7 +388,7 @@ async function ensureCodexModelCacheHasGpt54(params) {
387
388
  await removeFileIfExists(statePath);
388
389
  return {
389
390
  action: "skipped",
390
- warning: "Codex models cache was not found, and Codex version could not be inferred for a safe GPT-5.4 / GPT-5.4 Mini seed.",
391
+ warning: "Codex models cache was not found, and Codex version could not be inferred for a safe The Claw Bay model seed.",
391
392
  };
392
393
  }
393
394
  const docModels = [];
@@ -411,7 +412,7 @@ async function ensureCodexModelCacheHasGpt54(params) {
411
412
  if (!doc) {
412
413
  return {
413
414
  action: "skipped",
414
- warning: "Codex models cache exists but is not valid JSON in the expected format; skipped GPT-5.4 / GPT-5.4 Mini seed.",
415
+ warning: "Codex models cache exists but is not valid JSON in the expected format; skipped The Claw Bay model seed.",
415
416
  };
416
417
  }
417
418
  const clientVersion = (await inferCodexClientVersion(params.codexHome)) ??
@@ -522,7 +523,7 @@ async function cleanupSeededCodexModelCache(params) {
522
523
  if (!doc) {
523
524
  return {
524
525
  action: "none",
525
- warning: "Codex models cache exists but is not valid JSON in the expected format; left GPT-5.4 / GPT-5.4 Mini cache patch state untouched.",
526
+ warning: "Codex models cache exists but is not valid JSON in the expected format; left The Claw Bay model cache patch state untouched.",
526
527
  };
527
528
  }
528
529
  let removed = 0;
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "theclawbay",
3
- "version": "0.3.59",
3
+ "version": "0.3.61",
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
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/RCRTCBHAL900/TheClawBay"
9
+ },
6
10
  "bin": {
7
11
  "theclawbay": "dist/index.js"
8
12
  },
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "id": "gpt-5.5",
4
+ "label": "GPT-5.5",
5
+ "note": "Newest Codex model for stronger coding and agentic work.",
6
+ "tone": "coral",
7
+ "inputPer1M": 5.0,
8
+ "cachedInputPer1M": 0.5,
9
+ "outputPer1M": 30.0
10
+ },
2
11
  {
3
12
  "id": "gpt-5.4",
4
13
  "label": "GPT-5.4",
@@ -17,6 +26,15 @@
17
26
  "cachedInputPer1M": 0.125,
18
27
  "outputPer1M": 10.0
19
28
  },
29
+ {
30
+ "id": "gpt-image-1.5",
31
+ "label": "GPT Image 1.5",
32
+ "note": "Native image generation model for direct image outputs.",
33
+ "tone": "coral",
34
+ "inputPer1M": 8.0,
35
+ "cachedInputPer1M": 2.0,
36
+ "outputPer1M": 32.0
37
+ },
20
38
  {
21
39
  "id": "gpt-5.3-codex",
22
40
  "label": "GPT-5.3 Codex",