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 +4 -0
- package/dist/commands/setup.js +189 -61
- package/dist/commands/usage.d.ts +10 -0
- package/dist/commands/usage.js +135 -0
- package/dist/lib/codex-auth-seeding.js +5 -6
- package/dist/lib/codex-model-cache-migration.js +11 -10
- package/package.json +5 -1
- package/theclawbay-supported-models.json +18 -0
package/README.md
CHANGED
package/dist/commands/setup.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
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 (
|
|
3094
|
-
summaryNotes.add("
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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 =
|
|
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([
|
|
23
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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",
|