@gentbajko/slopify 1.1.0 → 1.1.1
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.
|
@@ -25,6 +25,7 @@ const responseSchema = z.object({
|
|
|
25
25
|
models: z
|
|
26
26
|
.array(z.object({
|
|
27
27
|
value: modelId,
|
|
28
|
+
resolvedModel: modelId.optional(),
|
|
28
29
|
displayName: modelName,
|
|
29
30
|
supportedEffortLevels: z.array(z.string()).max(10).optional(),
|
|
30
31
|
}))
|
|
@@ -72,14 +73,24 @@ function choices(event, requestId) {
|
|
|
72
73
|
throw unavailable();
|
|
73
74
|
const models = new Map();
|
|
74
75
|
for (const row of parsed.data.response.response.models) {
|
|
75
|
-
if (models.has(row.value))
|
|
76
|
-
continue;
|
|
77
76
|
const modes = row.supportedEffortLevels?.filter((value) => supportedEfforts.includes(value));
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
const thinking = modes?.length ? { thinkingModes: modes } : {};
|
|
78
|
+
if (!models.has(row.value))
|
|
79
|
+
models.set(row.value, {
|
|
80
|
+
id: row.value,
|
|
81
|
+
name: row.resolvedModel === undefined || row.resolvedModel === row.value
|
|
82
|
+
? row.displayName
|
|
83
|
+
: `${row.displayName} → ${row.resolvedModel}`,
|
|
84
|
+
...thinking,
|
|
85
|
+
});
|
|
86
|
+
// Claude advertises stable aliases and their current concrete targets.
|
|
87
|
+
// Offer both so the user can choose a moving alias or pin a version.
|
|
88
|
+
if (row.resolvedModel !== undefined && !models.has(row.resolvedModel))
|
|
89
|
+
models.set(row.resolvedModel, {
|
|
90
|
+
id: row.resolvedModel,
|
|
91
|
+
name: `${row.resolvedModel} (exact model)`,
|
|
92
|
+
...thinking,
|
|
93
|
+
});
|
|
83
94
|
}
|
|
84
95
|
return [...models.values()];
|
|
85
96
|
}
|
|
@@ -30,20 +30,49 @@ export async function nodeGeminiModels(binary) {
|
|
|
30
30
|
// A candidate is an optional package layout, not the final discovery result.
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
// Recent Gemini CLI releases ship only bundled chunks. Follow the entry
|
|
34
|
+
// point's literal chunk imports and read their model constants as text.
|
|
35
|
+
const bundled = await bundledModels(entry);
|
|
36
|
+
if (bundled.length > 1)
|
|
37
|
+
return bundled;
|
|
33
38
|
throw new Error("No installed model metadata");
|
|
34
39
|
}
|
|
35
40
|
catch {
|
|
36
41
|
throw new Error("Gemini CLI model metadata is unavailable. Use a documented CLI alias or enter a custom model ID.");
|
|
37
42
|
}
|
|
38
43
|
}
|
|
44
|
+
async function bundledModels(entry) {
|
|
45
|
+
const source = await readCatalogueFile(entry, 256 * 1024);
|
|
46
|
+
const imports = new Set();
|
|
47
|
+
for (const match of source.matchAll(/\b(?:from\s+|import\s*)["']\.\/(chunk-[A-Za-z0-9-]+\.js)["']/g)) {
|
|
48
|
+
if (match[1] !== undefined)
|
|
49
|
+
imports.add(match[1]);
|
|
50
|
+
}
|
|
51
|
+
if (imports.size === 0 || imports.size > 32)
|
|
52
|
+
return [];
|
|
53
|
+
for (const name of imports) {
|
|
54
|
+
try {
|
|
55
|
+
const source = await readCatalogueFile(join(dirname(entry), name), 24 * 1024 * 1024);
|
|
56
|
+
if (!source.includes("packages/core/dist/src/config/models.js"))
|
|
57
|
+
continue;
|
|
58
|
+
const models = parseGeminiModels(source);
|
|
59
|
+
if (models.length > 1)
|
|
60
|
+
return models;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Other chunks can be absent or too large; do not execute them.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
39
68
|
function parseGeminiModels(source) {
|
|
40
69
|
const models = new Map();
|
|
41
70
|
let pro = false;
|
|
42
71
|
let flash = false;
|
|
43
72
|
let flashLite = false;
|
|
44
|
-
// Read literal
|
|
73
|
+
// Read literal model constants only. Never import or execute an
|
|
45
74
|
// installed package, parse comments as entries, or inspect login/settings.
|
|
46
|
-
const declarations = /^export
|
|
75
|
+
const declarations = /^(?:export\s+)?(?:const|let|var)\s+([A-Z][A-Z0-9_]*)\s*=\s*(['"])([^'"\r\n]+)\2\s*;/gm;
|
|
47
76
|
const uncommented = source.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
48
77
|
for (const match of uncommented.matchAll(declarations)) {
|
|
49
78
|
const name = match[1];
|