theclawbay 0.3.67 → 0.3.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/logout.js +2 -2
- package/dist/commands/setup.js +6 -1
- package/dist/lib/codex-desktop-model-picker.js +57 -22
- package/dist/lib/codex-model-cache-migration.js +105 -174
- package/dist/lib/codex-model-catalog.d.ts +5 -0
- package/dist/lib/codex-model-catalog.js +46 -0
- package/package.json +2 -1
- package/theclawbay-codex-model-catalog.json +644 -0
package/dist/commands/logout.js
CHANGED
|
@@ -1548,10 +1548,10 @@ class LogoutCommand extends base_command_1.BaseCommand {
|
|
|
1548
1548
|
this.log("- Codex login state: no cleanup needed.");
|
|
1549
1549
|
}
|
|
1550
1550
|
if (modelCacheCleanup.action === "removed") {
|
|
1551
|
-
this.log("- Codex model cache: removed the Claw Bay
|
|
1551
|
+
this.log("- Codex model cache: removed the Claw Bay managed model catalog.");
|
|
1552
1552
|
}
|
|
1553
1553
|
else if (modelCacheCleanup.action === "preserved") {
|
|
1554
|
-
this.log("- Codex model cache: preserved an existing
|
|
1554
|
+
this.log("- Codex model cache: preserved an existing model catalog entry.");
|
|
1555
1555
|
}
|
|
1556
1556
|
else if (modelCacheCleanup.warning) {
|
|
1557
1557
|
this.log(`- Codex model cache: ${modelCacheCleanup.warning}`);
|
package/dist/commands/setup.js
CHANGED
|
@@ -28,7 +28,9 @@ const DEFAULT_PROVIDER_ID = "theclawbay";
|
|
|
28
28
|
const CLI_HTTP_USER_AGENT = "theclawbay-cli";
|
|
29
29
|
const SUPPORTED_MODEL_IDS = (0, supported_models_1.getSupportedModelIds)();
|
|
30
30
|
const MODEL_DISPLAY_NAMES = (0, supported_models_1.getSupportedModelDisplayNames)();
|
|
31
|
-
const DEFAULT_CODEX_MODEL =
|
|
31
|
+
const DEFAULT_CODEX_MODEL = (["gpt-5.5", "gpt-5.4"].find((modelId) => SUPPORTED_MODEL_IDS.includes(modelId)) ??
|
|
32
|
+
SUPPORTED_MODEL_IDS[0] ??
|
|
33
|
+
"gpt-5.4");
|
|
32
34
|
const DEFAULT_CONTINUE_MODEL = DEFAULT_CODEX_MODEL;
|
|
33
35
|
const DEFAULT_CLINE_MODEL = DEFAULT_CODEX_MODEL;
|
|
34
36
|
const DEFAULT_OPENCLAW_MODEL = DEFAULT_CODEX_MODEL;
|
|
@@ -3245,6 +3247,9 @@ class SetupCommand extends base_command_1.BaseCommand {
|
|
|
3245
3247
|
if (desktopModelPickerMigration?.action === "patched") {
|
|
3246
3248
|
summaryNotes.add("Desktop model pickers were refreshed so current VS Code and Codex app builds stop labeling supported The Claw Bay models like GPT-5.5 as Custom.");
|
|
3247
3249
|
}
|
|
3250
|
+
if (selectedSetupClients.has("codex")) {
|
|
3251
|
+
summaryNotes.add("If Codex updates later, rerun `theclawbay setup` once to refresh its local model catalog.");
|
|
3252
|
+
}
|
|
3248
3253
|
if (selectedSetupClients.has("codex") && !migrateCodexConversations) {
|
|
3249
3254
|
summaryNotes.add("Left existing Codex conversations untouched.");
|
|
3250
3255
|
}
|
|
@@ -9,8 +9,8 @@ const promises_1 = __importDefault(require("node:fs/promises"));
|
|
|
9
9
|
const node_os_1 = __importDefault(require("node:os"));
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
const paths_1 = require("./config/paths");
|
|
12
|
-
const
|
|
13
|
-
const DESKTOP_MODEL_IDS = Array.from(new Set((0,
|
|
12
|
+
const codex_model_catalog_1 = require("./codex-model-catalog");
|
|
13
|
+
const DESKTOP_MODEL_IDS = Array.from(new Set((0, codex_model_catalog_1.getVisibleHardcodedCodexModelIds)()));
|
|
14
14
|
const STATSIG_MODEL_PICKER_CONFIG_ID = "107580212";
|
|
15
15
|
function uniqueStrings(values) {
|
|
16
16
|
return Array.from(new Set(values.filter((value) => Boolean(value))));
|
|
@@ -40,6 +40,16 @@ function readWindowsCommandStdout(command) {
|
|
|
40
40
|
const output = result.stdout.replace(/\r/g, "").trim();
|
|
41
41
|
return output || null;
|
|
42
42
|
}
|
|
43
|
+
function desktopClientsLikelyRunning() {
|
|
44
|
+
if (node_os_1.default.platform() === "win32" || isWslInteropRuntime()) {
|
|
45
|
+
const running = readWindowsCommandStdout("Get-Process Code,Codex -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProcessName");
|
|
46
|
+
return Boolean(running);
|
|
47
|
+
}
|
|
48
|
+
const result = (0, node_child_process_1.spawnSync)("sh", ["-lc", "pgrep -if '(^|/)(code|codex)$' >/dev/null"], {
|
|
49
|
+
stdio: "ignore",
|
|
50
|
+
});
|
|
51
|
+
return result.status === 0;
|
|
52
|
+
}
|
|
43
53
|
function resolveWindowsPathForHost(input) {
|
|
44
54
|
if (!input)
|
|
45
55
|
return null;
|
|
@@ -333,31 +343,18 @@ function buildStatsigPatchScript() {
|
|
|
333
343
|
" finally:",
|
|
334
344
|
" db.close()",
|
|
335
345
|
" print(json.dumps(result))",
|
|
336
|
-
].join("
|
|
346
|
+
].join("\n");
|
|
337
347
|
}
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
if (dbDirs.length === 0)
|
|
341
|
-
return { patched: 0, warnings: [] };
|
|
342
|
-
const python = await ensureLocalPythonWithLevelDbSupport();
|
|
343
|
-
if (!python) {
|
|
344
|
-
return {
|
|
345
|
-
patched: 0,
|
|
346
|
-
warnings: [
|
|
347
|
-
"Could not install the local desktop model-picker helper, so Codex app model labels may stay stale until the next supported cache refresh.",
|
|
348
|
-
],
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
const run = (0, node_child_process_1.spawnSync)(python.command, [...python.args, "-c", buildStatsigPatchScript(), JSON.stringify(DESKTOP_MODEL_IDS), ...dbDirs], {
|
|
348
|
+
function patchStatsigCache(python, dbDir) {
|
|
349
|
+
const run = (0, node_child_process_1.spawnSync)(python.command, [...python.args, "-c", buildStatsigPatchScript(), JSON.stringify(DESKTOP_MODEL_IDS), dbDir], {
|
|
352
350
|
encoding: "utf8",
|
|
353
351
|
stdio: ["ignore", "pipe", "pipe"],
|
|
354
352
|
});
|
|
355
353
|
if (run.status !== 0) {
|
|
354
|
+
const detail = (run.stderr || run.stdout || "").trim();
|
|
356
355
|
return {
|
|
357
356
|
patched: 0,
|
|
358
|
-
|
|
359
|
-
"Could not refresh the desktop model-picker cache. Close Codex app / VS Code and rerun setup if the picker still shows Custom.",
|
|
360
|
-
],
|
|
357
|
+
warning: detail ? `${dbDir}: ${detail}` : `${dbDir}: desktop cache helper exited with status ${run.status}`,
|
|
361
358
|
};
|
|
362
359
|
}
|
|
363
360
|
let patched = 0;
|
|
@@ -368,7 +365,7 @@ async function patchDesktopStatsigCaches() {
|
|
|
368
365
|
const parsed = JSON.parse(line);
|
|
369
366
|
patched += typeof parsed.patched === "number" ? parsed.patched : 0;
|
|
370
367
|
if (typeof parsed.error === "string" && parsed.error.trim()) {
|
|
371
|
-
const dbLabel = typeof parsed.db === "string" ? parsed.db :
|
|
368
|
+
const dbLabel = typeof parsed.db === "string" ? parsed.db : dbDir;
|
|
372
369
|
warnings.push(`${dbLabel}: ${parsed.error.trim()}`);
|
|
373
370
|
}
|
|
374
371
|
}
|
|
@@ -376,7 +373,45 @@ async function patchDesktopStatsigCaches() {
|
|
|
376
373
|
continue;
|
|
377
374
|
}
|
|
378
375
|
}
|
|
379
|
-
return { patched, warnings };
|
|
376
|
+
return { patched, warning: warnings.length > 0 ? warnings.join(" ") : undefined };
|
|
377
|
+
}
|
|
378
|
+
async function patchDesktopStatsigCaches() {
|
|
379
|
+
const dbDirs = await desktopStatsigLevelDbCandidates();
|
|
380
|
+
if (dbDirs.length === 0)
|
|
381
|
+
return { patched: 0, warnings: [] };
|
|
382
|
+
const python = await ensureLocalPythonWithLevelDbSupport();
|
|
383
|
+
if (!python) {
|
|
384
|
+
return {
|
|
385
|
+
patched: 0,
|
|
386
|
+
warnings: [
|
|
387
|
+
"Could not install the local desktop model-picker helper, so Codex app model labels may stay stale until the next supported cache refresh.",
|
|
388
|
+
],
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
let patched = 0;
|
|
392
|
+
const warnings = [];
|
|
393
|
+
for (const dbDir of dbDirs) {
|
|
394
|
+
const result = patchStatsigCache(python, dbDir);
|
|
395
|
+
patched += result.patched;
|
|
396
|
+
if (result.warning)
|
|
397
|
+
warnings.push(result.warning);
|
|
398
|
+
}
|
|
399
|
+
if (patched === 0 && warnings.length > 0) {
|
|
400
|
+
const prefix = desktopClientsLikelyRunning()
|
|
401
|
+
? "Could not refresh the desktop model-picker cache because VS Code or Codex app is still running."
|
|
402
|
+
: "Could not refresh the desktop model-picker cache.";
|
|
403
|
+
return {
|
|
404
|
+
patched,
|
|
405
|
+
warnings: [`${prefix} ${warnings.join(" ")}`],
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (patched > 0 && warnings.length > 0) {
|
|
409
|
+
const filteredWarnings = warnings.filter((warning) => !/does not exist|No such file/i.test(warning));
|
|
410
|
+
if (filteredWarnings.length > 0) {
|
|
411
|
+
return { patched, warnings: filteredWarnings };
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return { patched, warnings: [] };
|
|
380
415
|
}
|
|
381
416
|
async function ensureCodexDesktopModelPickerSupport() {
|
|
382
417
|
try {
|
|
@@ -10,36 +10,22 @@ const promises_1 = __importDefault(require("node:fs/promises"));
|
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
const node_child_process_1 = require("node:child_process");
|
|
12
12
|
const node_os_1 = __importDefault(require("node:os"));
|
|
13
|
+
const codex_model_catalog_1 = require("./codex-model-catalog");
|
|
13
14
|
const supported_models_1 = require("./supported-models");
|
|
14
15
|
const MODELS_CACHE_FILE = "models_cache.json";
|
|
15
16
|
const MODELS_CACHE_STATE_FILE = "theclawbay.models-cache.json";
|
|
16
17
|
const STATE_DB_FILE_PATTERN = /^state_\d+\.sqlite$/;
|
|
17
|
-
const
|
|
18
|
+
const CATALOG_MODELS = (0, codex_model_catalog_1.getHardcodedCodexModelCatalog)();
|
|
19
|
+
const CATALOG_MODEL_IDS = (0, codex_model_catalog_1.getHardcodedCodexModelIds)();
|
|
18
20
|
const LEGACY_REMOVED_MODEL_IDS = (0, supported_models_1.getLegacyRemovedModelIds)();
|
|
19
|
-
const
|
|
20
|
-
const TRACKED_MODEL_ID_SET = new Set([...
|
|
21
|
+
const CATALOG_MODEL_ID_SET = new Set(CATALOG_MODEL_IDS);
|
|
22
|
+
const TRACKED_MODEL_ID_SET = new Set([...CATALOG_MODEL_IDS, ...LEGACY_REMOVED_MODEL_IDS]);
|
|
21
23
|
const LEGACY_REMOVED_MODEL_ID_SET = new Set(LEGACY_REMOVED_MODEL_IDS);
|
|
22
24
|
const SEED_MARKER_KEY = "_theclawbay_seeded";
|
|
23
25
|
// Older releases stored the model id as the marker value; accept those so cleanup still works.
|
|
24
26
|
const SEED_MARKER_VALUE = "theclawbay";
|
|
25
27
|
const LEGACY_SEED_MARKER_VALUES = new Set([...TRACKED_MODEL_ID_SET, SEED_MARKER_VALUE, true]);
|
|
26
|
-
const
|
|
27
|
-
const SUPPORTED_MODEL_CONFIG = new Map(SUPPORTED_MODELS.map((model) => [model.id, model]));
|
|
28
|
-
const TEMPLATE_MODEL_IDS = TARGET_MODEL_IDS;
|
|
29
|
-
const DEFAULT_REASONING_LEVELS = [
|
|
30
|
-
{ effort: "low", description: "Fast responses with lighter reasoning" },
|
|
31
|
-
{ effort: "medium", description: "Balances speed and reasoning depth for everyday tasks" },
|
|
32
|
-
{ effort: "high", description: "Greater reasoning depth for complex problems" },
|
|
33
|
-
{ effort: "xhigh", description: "Extra high reasoning depth for complex problems" },
|
|
34
|
-
];
|
|
35
|
-
const FALLBACK_BASE_INSTRUCTIONS = `You are Codex, a coding agent based on GPT-5. You and the user share the same workspace and collaborate to achieve the user's goals.
|
|
36
|
-
|
|
37
|
-
## General
|
|
38
|
-
|
|
39
|
-
- Prefer rg or rg --files for search when available.
|
|
40
|
-
- Make safe, minimal code changes that preserve user work.
|
|
41
|
-
- Explain what changed and any remaining risk clearly.`;
|
|
42
|
-
const SEEDED_CACHE_FRESHNESS_YEARS = 10;
|
|
28
|
+
const SEEDED_CACHE_FRESHNESS_ISO = "2099-12-31T23:59:59.000Z";
|
|
43
29
|
function objectRecordOr(value) {
|
|
44
30
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
45
31
|
return value;
|
|
@@ -148,7 +134,7 @@ async function readPatchState(statePath) {
|
|
|
148
134
|
}
|
|
149
135
|
async function writePatchState(statePath, fingerprints) {
|
|
150
136
|
await promises_1.default.mkdir(node_path_1.default.dirname(statePath), { recursive: true });
|
|
151
|
-
const models =
|
|
137
|
+
const models = CATALOG_MODEL_IDS.flatMap((modelId) => {
|
|
152
138
|
const fingerprint = fingerprints[modelId];
|
|
153
139
|
if (!fingerprint)
|
|
154
140
|
return [];
|
|
@@ -166,93 +152,43 @@ function findModel(models, slug) {
|
|
|
166
152
|
function hasSeedMarker(model) {
|
|
167
153
|
return LEGACY_SEED_MARKER_VALUES.has(model[SEED_MARKER_KEY]);
|
|
168
154
|
}
|
|
169
|
-
function
|
|
155
|
+
function stripSeedMarker(model) {
|
|
156
|
+
if (!(SEED_MARKER_KEY in model))
|
|
157
|
+
return cloneJson(model);
|
|
170
158
|
const next = cloneJson(model);
|
|
171
|
-
next[SEED_MARKER_KEY]
|
|
159
|
+
delete next[SEED_MARKER_KEY];
|
|
172
160
|
return next;
|
|
173
161
|
}
|
|
174
|
-
function
|
|
175
|
-
return
|
|
162
|
+
function buildCatalogModels() {
|
|
163
|
+
return cloneJson(CATALOG_MODELS).map((model) => stripSeedMarker(model));
|
|
176
164
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
seed.description = seedDescription(modelId);
|
|
183
|
-
if (typeof seed.default_reasoning_level !== "string") {
|
|
184
|
-
seed.default_reasoning_level = "medium";
|
|
185
|
-
}
|
|
186
|
-
if (!Array.isArray(seed.supported_reasoning_levels) || seed.supported_reasoning_levels.length === 0) {
|
|
187
|
-
seed.supported_reasoning_levels = cloneJson(DEFAULT_REASONING_LEVELS);
|
|
188
|
-
}
|
|
189
|
-
if (typeof seed.shell_type !== "string") {
|
|
190
|
-
seed.shell_type = "shell_command";
|
|
191
|
-
}
|
|
192
|
-
seed.visibility = "list";
|
|
193
|
-
seed.supported_in_api = true;
|
|
194
|
-
seed.priority = 0;
|
|
195
|
-
seed.upgrade = null;
|
|
196
|
-
if (typeof seed.base_instructions !== "string" || !seed.base_instructions.trim()) {
|
|
197
|
-
seed.base_instructions = FALLBACK_BASE_INSTRUCTIONS;
|
|
198
|
-
}
|
|
199
|
-
if (typeof seed.supports_reasoning_summaries !== "boolean") {
|
|
200
|
-
seed.supports_reasoning_summaries = true;
|
|
201
|
-
}
|
|
202
|
-
if (typeof seed.support_verbosity !== "boolean") {
|
|
203
|
-
seed.support_verbosity = true;
|
|
204
|
-
}
|
|
205
|
-
if (seed.default_verbosity === undefined) {
|
|
206
|
-
seed.default_verbosity = "low";
|
|
207
|
-
}
|
|
208
|
-
if (seed.apply_patch_tool_type === undefined) {
|
|
209
|
-
seed.apply_patch_tool_type = "freeform";
|
|
210
|
-
}
|
|
211
|
-
const truncationPolicy = objectRecordOr(seed.truncation_policy);
|
|
212
|
-
if (!truncationPolicy || typeof truncationPolicy.mode !== "string" || typeof truncationPolicy.limit !== "number") {
|
|
213
|
-
seed.truncation_policy = { mode: "tokens", limit: 10000 };
|
|
214
|
-
}
|
|
215
|
-
if (typeof seed.supports_parallel_tool_calls !== "boolean") {
|
|
216
|
-
seed.supports_parallel_tool_calls = true;
|
|
217
|
-
}
|
|
218
|
-
if (typeof seed.context_window !== "number") {
|
|
219
|
-
seed.context_window = 272000;
|
|
220
|
-
}
|
|
221
|
-
if (typeof seed.effective_context_window_percent !== "number") {
|
|
222
|
-
seed.effective_context_window_percent = 95;
|
|
223
|
-
}
|
|
224
|
-
if (!Array.isArray(seed.experimental_supported_tools)) {
|
|
225
|
-
seed.experimental_supported_tools = [];
|
|
226
|
-
}
|
|
227
|
-
if (!Array.isArray(seed.input_modalities) || seed.input_modalities.length === 0) {
|
|
228
|
-
seed.input_modalities = ["text", "image"];
|
|
229
|
-
}
|
|
230
|
-
if (typeof seed.prefer_websockets !== "boolean") {
|
|
231
|
-
seed.prefer_websockets = true;
|
|
232
|
-
}
|
|
233
|
-
return seed;
|
|
165
|
+
function buildCatalogModelMap() {
|
|
166
|
+
return new Map(buildCatalogModels().flatMap((model) => {
|
|
167
|
+
const slug = typeof model.slug === "string" ? model.slug : "";
|
|
168
|
+
return slug ? [[slug, model]] : [];
|
|
169
|
+
}));
|
|
234
170
|
}
|
|
235
|
-
function
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return normalizeSeedModel(null, modelId);
|
|
171
|
+
function sameFingerprintMaps(left, right) {
|
|
172
|
+
const leftKeys = Object.keys(left).sort();
|
|
173
|
+
const rightKeys = Object.keys(right).sort();
|
|
174
|
+
if (leftKeys.length !== rightKeys.length)
|
|
175
|
+
return false;
|
|
176
|
+
return leftKeys.every((key, index) => key === rightKeys[index] && left[key] === right[key]);
|
|
242
177
|
}
|
|
243
|
-
function
|
|
244
|
-
return models.some((model) =>
|
|
178
|
+
function hasCatalogModels(models) {
|
|
179
|
+
return models.some((model) => {
|
|
180
|
+
const slug = typeof model.slug === "string" ? model.slug : "";
|
|
181
|
+
return Boolean(slug) && CATALOG_MODEL_ID_SET.has(slug);
|
|
182
|
+
});
|
|
245
183
|
}
|
|
246
184
|
function nextFetchedAtIsoForDocument(doc) {
|
|
247
|
-
if (!
|
|
185
|
+
if (!hasCatalogModels(doc.models)) {
|
|
248
186
|
return new Date().toISOString();
|
|
249
187
|
}
|
|
250
|
-
// Current
|
|
251
|
-
// catalogs in API-key mode
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
next.setUTCFullYear(next.getUTCFullYear() + SEEDED_CACHE_FRESHNESS_YEARS);
|
|
255
|
-
return next.toISOString();
|
|
188
|
+
// Current Codex builds only consult models_cache.json for custom-provider
|
|
189
|
+
// catalogs in API-key mode. Pin the cache freshness far into the future so
|
|
190
|
+
// setup can refresh the catalog on demand without the five-minute TTL.
|
|
191
|
+
return SEEDED_CACHE_FRESHNESS_ISO;
|
|
256
192
|
}
|
|
257
193
|
function setCacheFreshnessMetadata(doc, clientVersion) {
|
|
258
194
|
let changed = false;
|
|
@@ -562,22 +498,22 @@ async function ensureCodexModelCacheHasGpt54(params) {
|
|
|
562
498
|
try {
|
|
563
499
|
const existingState = await readPatchState(statePath);
|
|
564
500
|
const parsed = await readJsonIfExists(cachePath);
|
|
501
|
+
const catalogModels = buildCatalogModels();
|
|
502
|
+
const catalogModelMap = buildCatalogModelMap();
|
|
565
503
|
if (parsed === null) {
|
|
566
504
|
const clientVersion = await inferCodexClientVersion(params.codexHome);
|
|
567
505
|
if (!clientVersion) {
|
|
568
506
|
await removeFileIfExists(statePath);
|
|
569
507
|
return {
|
|
570
508
|
action: "skipped",
|
|
571
|
-
warning: "Codex models cache was not found, and Codex version could not be inferred for a safe The Claw Bay model
|
|
509
|
+
warning: "Codex models cache was not found, and Codex version could not be inferred for a safe The Claw Bay model catalog refresh.",
|
|
572
510
|
};
|
|
573
511
|
}
|
|
574
|
-
const docModels =
|
|
575
|
-
const nextState = {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
nextState[modelId] = fingerprintModel(seed);
|
|
580
|
-
}
|
|
512
|
+
const docModels = cloneJson(catalogModels);
|
|
513
|
+
const nextState = Object.fromEntries(docModels.flatMap((model) => {
|
|
514
|
+
const slug = typeof model.slug === "string" ? model.slug : "";
|
|
515
|
+
return slug ? [[slug, fingerprintModel(model)]] : [];
|
|
516
|
+
}));
|
|
581
517
|
const doc = {
|
|
582
518
|
fetched_at: nextFetchedAtIsoForDocument({ models: docModels }),
|
|
583
519
|
client_version: clientVersion,
|
|
@@ -592,105 +528,92 @@ async function ensureCodexModelCacheHasGpt54(params) {
|
|
|
592
528
|
if (!doc) {
|
|
593
529
|
return {
|
|
594
530
|
action: "skipped",
|
|
595
|
-
warning: "Codex models cache exists but is not valid JSON in the expected format; skipped The Claw Bay model
|
|
531
|
+
warning: "Codex models cache exists but is not valid JSON in the expected format; skipped The Claw Bay model catalog refresh.",
|
|
596
532
|
};
|
|
597
533
|
}
|
|
598
534
|
const clientVersion = (await inferCodexClientVersion(params.codexHome)) ??
|
|
599
535
|
(typeof doc.client_version === "string" && doc.client_version ? doc.client_version : null);
|
|
600
536
|
let changed = false;
|
|
601
537
|
let seeded = false;
|
|
602
|
-
|
|
603
|
-
const
|
|
604
|
-
const
|
|
605
|
-
doc.models = doc.models.filter((entry) => {
|
|
538
|
+
const currentCatalogEntries = new Map();
|
|
539
|
+
const rest = [];
|
|
540
|
+
for (const entry of doc.models) {
|
|
606
541
|
const slug = typeof entry.slug === "string" ? entry.slug : "";
|
|
607
|
-
if (!slug
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
for (const modelId of TARGET_MODEL_IDS) {
|
|
619
|
-
const existingModel = findModel(doc.models, modelId);
|
|
620
|
-
const trackedFingerprint = existingState[modelId];
|
|
621
|
-
if (existingModel) {
|
|
622
|
-
const currentFingerprint = fingerprintModel(existingModel);
|
|
623
|
-
if (hasSeedMarker(existingModel)) {
|
|
624
|
-
if (!trackedFingerprint || trackedFingerprint !== currentFingerprint) {
|
|
625
|
-
nextState[modelId] = currentFingerprint;
|
|
626
|
-
stateChanged = true;
|
|
627
|
-
}
|
|
628
|
-
continue;
|
|
542
|
+
if (!slug) {
|
|
543
|
+
rest.push(entry);
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (LEGACY_REMOVED_MODEL_ID_SET.has(slug) && hasSeedMarker(entry)) {
|
|
547
|
+
changed = true;
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (CATALOG_MODEL_ID_SET.has(slug)) {
|
|
551
|
+
if (!currentCatalogEntries.has(slug)) {
|
|
552
|
+
currentCatalogEntries.set(slug, entry);
|
|
629
553
|
}
|
|
630
|
-
|
|
631
|
-
const seededModel = applySeedMarker(existingModel);
|
|
632
|
-
doc.models = doc.models.map((entry) => (entry.slug === modelId ? seededModel : entry));
|
|
633
|
-
nextState[modelId] = fingerprintModel(seededModel);
|
|
634
|
-
seeded = true;
|
|
554
|
+
else {
|
|
635
555
|
changed = true;
|
|
636
|
-
stateChanged = true;
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (trackedFingerprint && trackedFingerprint !== currentFingerprint) {
|
|
640
|
-
delete nextState[modelId];
|
|
641
|
-
stateChanged = true;
|
|
642
556
|
}
|
|
643
557
|
continue;
|
|
644
558
|
}
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
stateChanged = true;
|
|
559
|
+
const normalized = stripSeedMarker(entry);
|
|
560
|
+
if (fingerprintModel(normalized) !== fingerprintModel(entry)) {
|
|
561
|
+
changed = true;
|
|
562
|
+
}
|
|
563
|
+
rest.push(normalized);
|
|
651
564
|
}
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
565
|
+
const orderedCatalog = [];
|
|
566
|
+
const nextState = {};
|
|
567
|
+
for (const modelId of CATALOG_MODEL_IDS) {
|
|
568
|
+
const desiredModel = catalogModelMap.get(modelId);
|
|
569
|
+
if (!desiredModel)
|
|
570
|
+
continue;
|
|
571
|
+
const desiredFingerprint = fingerprintModel(desiredModel);
|
|
572
|
+
const trackedFingerprint = existingState[modelId];
|
|
573
|
+
const existingModel = currentCatalogEntries.get(modelId);
|
|
574
|
+
if (!existingModel) {
|
|
575
|
+
orderedCatalog.push(cloneJson(desiredModel));
|
|
576
|
+
nextState[modelId] = desiredFingerprint;
|
|
577
|
+
changed = true;
|
|
578
|
+
seeded = true;
|
|
659
579
|
continue;
|
|
660
580
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
581
|
+
const normalizedExisting = stripSeedMarker(existingModel);
|
|
582
|
+
const existingFingerprint = fingerprintModel(normalizedExisting);
|
|
583
|
+
if (existingFingerprint === desiredFingerprint && !hasSeedMarker(existingModel)) {
|
|
584
|
+
orderedCatalog.push(normalizedExisting);
|
|
585
|
+
if (trackedFingerprint === desiredFingerprint) {
|
|
586
|
+
nextState[modelId] = trackedFingerprint;
|
|
587
|
+
}
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
orderedCatalog.push(cloneJson(desiredModel));
|
|
591
|
+
nextState[modelId] = desiredFingerprint;
|
|
592
|
+
changed = true;
|
|
593
|
+
seeded = true;
|
|
668
594
|
}
|
|
669
|
-
doc.models = [...
|
|
595
|
+
doc.models = [...orderedCatalog, ...rest];
|
|
670
596
|
if (setCacheFreshnessMetadata(doc, clientVersion)) {
|
|
671
597
|
changed = true;
|
|
672
598
|
}
|
|
599
|
+
const stateChanged = !sameFingerprintMaps(existingState, nextState);
|
|
673
600
|
if (changed) {
|
|
674
601
|
await promises_1.default.writeFile(cachePath, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
|
|
675
602
|
}
|
|
676
|
-
const hasAnyTracked =
|
|
603
|
+
const hasAnyTracked = CATALOG_MODEL_IDS.some((id) => Boolean(nextState[id]));
|
|
677
604
|
if (!hasAnyTracked) {
|
|
678
605
|
if (Object.keys(existingState).length > 0) {
|
|
679
606
|
await removeFileIfExists(statePath);
|
|
680
607
|
}
|
|
681
608
|
}
|
|
682
|
-
else if (stateChanged
|
|
609
|
+
else if (stateChanged) {
|
|
683
610
|
await writePatchState(statePath, nextState);
|
|
684
611
|
}
|
|
685
612
|
if (seeded)
|
|
686
613
|
return { action: "seeded" };
|
|
687
614
|
if (changed || stateChanged)
|
|
688
615
|
return { action: "refreshed" };
|
|
689
|
-
|
|
690
|
-
const model = findModel(doc.models, id);
|
|
691
|
-
return Boolean(model && hasSeedMarker(model));
|
|
692
|
-
});
|
|
693
|
-
return { action: allSeeded ? "already_seeded" : "already_present" };
|
|
616
|
+
return { action: hasAnyTracked ? "already_seeded" : "already_present" };
|
|
694
617
|
}
|
|
695
618
|
catch (error) {
|
|
696
619
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -724,9 +647,17 @@ async function cleanupSeededCodexModelCache(params) {
|
|
|
724
647
|
let preserved = 0;
|
|
725
648
|
doc.models = doc.models.filter((entry) => {
|
|
726
649
|
const slug = typeof entry.slug === "string" ? entry.slug : "";
|
|
727
|
-
if (!slug
|
|
650
|
+
if (!slug)
|
|
651
|
+
return true;
|
|
652
|
+
if (LEGACY_REMOVED_MODEL_ID_SET.has(slug) && hasSeedMarker(entry)) {
|
|
653
|
+
removed += 1;
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
const trackedFingerprint = state[slug];
|
|
657
|
+
if (!trackedFingerprint)
|
|
728
658
|
return true;
|
|
729
|
-
|
|
659
|
+
const normalized = stripSeedMarker(entry);
|
|
660
|
+
if (fingerprintModel(normalized) !== trackedFingerprint) {
|
|
730
661
|
preserved += 1;
|
|
731
662
|
return true;
|
|
732
663
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getHardcodedCodexModelCatalog = getHardcodedCodexModelCatalog;
|
|
7
|
+
exports.getHardcodedCodexModelIds = getHardcodedCodexModelIds;
|
|
8
|
+
exports.getVisibleHardcodedCodexModelIds = getVisibleHardcodedCodexModelIds;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_fs_1 = require("node:fs");
|
|
11
|
+
function configPath() {
|
|
12
|
+
return node_path_1.default.resolve(__dirname, "..", "..", "theclawbay-codex-model-catalog.json");
|
|
13
|
+
}
|
|
14
|
+
function parseCodexModelCatalog(raw) {
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
if (!Array.isArray(parsed)) {
|
|
17
|
+
throw new Error("codex model catalog must be an array");
|
|
18
|
+
}
|
|
19
|
+
return parsed.map((entry) => {
|
|
20
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
21
|
+
throw new Error("codex model catalog contains an invalid entry");
|
|
22
|
+
}
|
|
23
|
+
return entry;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function cloneJson(value) {
|
|
27
|
+
return JSON.parse(JSON.stringify(value));
|
|
28
|
+
}
|
|
29
|
+
let cachedCatalog = null;
|
|
30
|
+
function getHardcodedCodexModelCatalog() {
|
|
31
|
+
if (!cachedCatalog) {
|
|
32
|
+
cachedCatalog = parseCodexModelCatalog((0, node_fs_1.readFileSync)(configPath(), "utf8"));
|
|
33
|
+
}
|
|
34
|
+
return cloneJson(cachedCatalog);
|
|
35
|
+
}
|
|
36
|
+
function getHardcodedCodexModelIds() {
|
|
37
|
+
return getHardcodedCodexModelCatalog()
|
|
38
|
+
.map((model) => (typeof model.slug === "string" ? model.slug.trim() : ""))
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
function getVisibleHardcodedCodexModelIds() {
|
|
42
|
+
return getHardcodedCodexModelCatalog()
|
|
43
|
+
.filter((model) => model.visibility === "list")
|
|
44
|
+
.map((model) => (typeof model.slug === "string" ? model.slug.trim() : ""))
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theclawbay",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.69",
|
|
4
4
|
"description": "CLI for connecting Codex, Continue, Cline, GSD, OpenClaw, OpenCode, Kilo, Roo Code, Aider, experimental Trae, and experimental Zo to The Claw Bay.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
|
+
"theclawbay-codex-model-catalog.json",
|
|
30
31
|
"theclawbay-supported-models.json",
|
|
31
32
|
"README.md",
|
|
32
33
|
"LICENSE"
|