codemaxxing 0.4.15 → 0.4.16
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/index.js +57 -4
- package/package.json +1 -1
- package/src/index.tsx +72 -3
package/dist/index.js
CHANGED
|
@@ -156,6 +156,8 @@ function App() {
|
|
|
156
156
|
const [ollamaDeletePickerIndex, setOllamaDeletePickerIndex] = useState(0);
|
|
157
157
|
const [ollamaPullPicker, setOllamaPullPicker] = useState(false);
|
|
158
158
|
const [ollamaPullPickerIndex, setOllamaPullPickerIndex] = useState(0);
|
|
159
|
+
const [modelPicker, setModelPicker] = useState(null);
|
|
160
|
+
const [modelPickerIndex, setModelPickerIndex] = useState(0);
|
|
159
161
|
const [wizardScreen, setWizardScreen] = useState(null);
|
|
160
162
|
const [wizardIndex, setWizardIndex] = useState(0);
|
|
161
163
|
const [wizardHardware, setWizardHardware] = useState(null);
|
|
@@ -901,10 +903,34 @@ function App() {
|
|
|
901
903
|
}
|
|
902
904
|
return;
|
|
903
905
|
}
|
|
904
|
-
if (trimmed
|
|
905
|
-
|
|
906
|
+
if (trimmed === "/model" || trimmed === "/models") {
|
|
907
|
+
// Show picker of available models
|
|
908
|
+
try {
|
|
909
|
+
const ollamaModels = await listInstalledModelsDetailed();
|
|
910
|
+
if (ollamaModels.length > 0) {
|
|
911
|
+
setModelPicker(ollamaModels.map(m => m.name));
|
|
912
|
+
setModelPickerIndex(0);
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
catch { }
|
|
917
|
+
// Fallback: try provider's model list
|
|
918
|
+
try {
|
|
919
|
+
const providerModels = await listModels(providerRef.current?.baseUrl || "", providerRef.current?.apiKey || "");
|
|
920
|
+
if (providerModels.length > 0) {
|
|
921
|
+
setModelPicker(providerModels.map((m) => m.id || m));
|
|
922
|
+
setModelPickerIndex(0);
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
catch { }
|
|
927
|
+
addMsg("info", `Current model: ${modelName}\n Usage: /model <model-name>`);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
if (trimmed.startsWith("/model ")) {
|
|
931
|
+
const newModel = trimmed.replace("/model ", "").trim();
|
|
906
932
|
if (!newModel) {
|
|
907
|
-
addMsg("info", `Current model: ${
|
|
933
|
+
addMsg("info", `Current model: ${modelName}\n Usage: /model <model-name>`);
|
|
908
934
|
return;
|
|
909
935
|
}
|
|
910
936
|
agent.switchModel(newModel);
|
|
@@ -1370,6 +1396,33 @@ function App() {
|
|
|
1370
1396
|
}
|
|
1371
1397
|
return;
|
|
1372
1398
|
}
|
|
1399
|
+
// ── Model picker ──
|
|
1400
|
+
if (modelPicker) {
|
|
1401
|
+
if (key.upArrow) {
|
|
1402
|
+
setModelPickerIndex((prev) => (prev - 1 + modelPicker.length) % modelPicker.length);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
if (key.downArrow) {
|
|
1406
|
+
setModelPickerIndex((prev) => (prev + 1) % modelPicker.length);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (key.escape) {
|
|
1410
|
+
setModelPicker(null);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (key.return) {
|
|
1414
|
+
const selected = modelPicker[modelPickerIndex];
|
|
1415
|
+
if (selected && agent) {
|
|
1416
|
+
agent.switchModel(selected);
|
|
1417
|
+
setModelName(selected);
|
|
1418
|
+
addMsg("info", `✅ Switched to: ${selected}`);
|
|
1419
|
+
refreshConnectionBanner();
|
|
1420
|
+
}
|
|
1421
|
+
setModelPicker(null);
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1373
1426
|
// ── Ollama delete picker ──
|
|
1374
1427
|
if (ollamaDeletePicker) {
|
|
1375
1428
|
if (key.upArrow) {
|
|
@@ -1960,7 +2013,7 @@ function App() {
|
|
|
1960
2013
|
})(), skillsPicker === "remove" && (() => {
|
|
1961
2014
|
const installed = listInstalledSkills();
|
|
1962
2015
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.error, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.error, children: "Remove a skill:" }), installed.map((s, i) => (_jsxs(Text, { children: [i === skillsPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsxs(Text, { color: i === skillsPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: [s.name, " \u2014 ", s.description] })] }, s.name))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter remove · Esc back" })] }));
|
|
1963
|
-
})(), themePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Choose a theme:" }), listThemes().map((key, i) => (_jsxs(Text, { children: [i === themePickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === themePickerIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: key }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", THEMES[key].description] }), key === theme.name.toLowerCase() ? _jsx(Text, { color: theme.colors.muted, children: " (current)" }) : null] }, key))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), sessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Resume a session:" }), sessionPicker.map((s, i) => (_jsxs(Text, { children: [i === sessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === sessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.error, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.error, children: "Delete a session:" }), deleteSessionPicker.map((s, i) => (_jsxs(Text, { children: [i === deleteSessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === deleteSessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionConfirm && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.warning, paddingX: 1, marginBottom: 0, children: [_jsxs(Text, { bold: true, color: theme.colors.warning, children: ["Delete session ", deleteSessionConfirm.id, "?"] }), _jsxs(Text, { color: theme.colors.muted, children: [" ", deleteSessionConfirm.display] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.colors.error, bold: true, children: " [y]" }), _jsx(Text, { children: "es " }), _jsx(Text, { color: theme.colors.success, bold: true, children: "[n]" }), _jsx(Text, { children: "o" })] })] })), ollamaDeletePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Delete which model?" }), _jsx(Text, { children: "" }), ollamaDeletePicker.models.map((m, i) => (_jsxs(Text, { children: [" ", i === ollamaDeletePickerIndex ? _jsx(Text, { color: theme.colors.primary, bold: true, children: "▸ " }) : " ", _jsx(Text, { color: i === ollamaDeletePickerIndex ? theme.colors.primary : undefined, children: m.name }), _jsxs(Text, { color: theme.colors.muted, children: [" (", (m.size / (1024 * 1024 * 1024)).toFixed(1), " GB)"] })] }, m.name))), _jsx(Text, { children: "" }), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter to delete · Esc cancel" })] })), ollamaPullPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Download which model?" }), _jsx(Text, { children: "" }), [
|
|
2016
|
+
})(), themePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Choose a theme:" }), listThemes().map((key, i) => (_jsxs(Text, { children: [i === themePickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === themePickerIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: key }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", THEMES[key].description] }), key === theme.name.toLowerCase() ? _jsx(Text, { color: theme.colors.muted, children: " (current)" }) : null] }, key))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), sessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Resume a session:" }), sessionPicker.map((s, i) => (_jsxs(Text, { children: [i === sessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === sessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.error, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.error, children: "Delete a session:" }), deleteSessionPicker.map((s, i) => (_jsxs(Text, { children: [i === deleteSessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === deleteSessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionConfirm && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.warning, paddingX: 1, marginBottom: 0, children: [_jsxs(Text, { bold: true, color: theme.colors.warning, children: ["Delete session ", deleteSessionConfirm.id, "?"] }), _jsxs(Text, { color: theme.colors.muted, children: [" ", deleteSessionConfirm.display] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.colors.error, bold: true, children: " [y]" }), _jsx(Text, { children: "es " }), _jsx(Text, { color: theme.colors.success, bold: true, children: "[n]" }), _jsx(Text, { children: "o" })] })] })), modelPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Switch model:" }), _jsx(Text, { children: "" }), modelPicker.map((m, i) => (_jsxs(Text, { children: [" ", i === modelPickerIndex ? _jsx(Text, { color: theme.colors.primary, bold: true, children: "▸ " }) : " ", _jsx(Text, { color: i === modelPickerIndex ? theme.colors.primary : undefined, children: m }), m === modelName ? _jsx(Text, { color: theme.colors.success, children: " (active)" }) : null] }, m))), _jsx(Text, { children: "" }), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter to switch · Esc cancel" })] })), ollamaDeletePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Delete which model?" }), _jsx(Text, { children: "" }), ollamaDeletePicker.models.map((m, i) => (_jsxs(Text, { children: [" ", i === ollamaDeletePickerIndex ? _jsx(Text, { color: theme.colors.primary, bold: true, children: "▸ " }) : " ", _jsx(Text, { color: i === ollamaDeletePickerIndex ? theme.colors.primary : undefined, children: m.name }), _jsxs(Text, { color: theme.colors.muted, children: [" (", (m.size / (1024 * 1024 * 1024)).toFixed(1), " GB)"] })] }, m.name))), _jsx(Text, { children: "" }), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter to delete · Esc cancel" })] })), ollamaPullPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Download which model?" }), _jsx(Text, { children: "" }), [
|
|
1964
2017
|
{ id: "qwen2.5-coder:7b", name: "Qwen 2.5 Coder 7B", size: "5 GB", desc: "Best balance of speed & quality" },
|
|
1965
2018
|
{ id: "qwen2.5-coder:14b", name: "Qwen 2.5 Coder 14B", size: "9 GB", desc: "Higher quality, needs 16GB+ RAM" },
|
|
1966
2019
|
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "\u26A0\uFE0F Basic \u2014 may struggle with tool calls" },
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -191,6 +191,8 @@ function App() {
|
|
|
191
191
|
const [ollamaDeletePickerIndex, setOllamaDeletePickerIndex] = useState(0);
|
|
192
192
|
const [ollamaPullPicker, setOllamaPullPicker] = useState(false);
|
|
193
193
|
const [ollamaPullPickerIndex, setOllamaPullPickerIndex] = useState(0);
|
|
194
|
+
const [modelPicker, setModelPicker] = useState<string[] | null>(null);
|
|
195
|
+
const [modelPickerIndex, setModelPickerIndex] = useState(0);
|
|
194
196
|
|
|
195
197
|
// ── Setup Wizard State ──
|
|
196
198
|
type WizardScreen = "connection" | "models" | "install-ollama" | "pulling" | null;
|
|
@@ -939,10 +941,32 @@ function App() {
|
|
|
939
941
|
}
|
|
940
942
|
return;
|
|
941
943
|
}
|
|
942
|
-
if (trimmed
|
|
943
|
-
|
|
944
|
+
if (trimmed === "/model" || trimmed === "/models") {
|
|
945
|
+
// Show picker of available models
|
|
946
|
+
try {
|
|
947
|
+
const ollamaModels = await listInstalledModelsDetailed();
|
|
948
|
+
if (ollamaModels.length > 0) {
|
|
949
|
+
setModelPicker(ollamaModels.map(m => m.name));
|
|
950
|
+
setModelPickerIndex(0);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
} catch {}
|
|
954
|
+
// Fallback: try provider's model list
|
|
955
|
+
try {
|
|
956
|
+
const providerModels = await listModels(providerRef.current?.baseUrl || "", providerRef.current?.apiKey || "");
|
|
957
|
+
if (providerModels.length > 0) {
|
|
958
|
+
setModelPicker(providerModels.map((m: any) => m.id || m));
|
|
959
|
+
setModelPickerIndex(0);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
} catch {}
|
|
963
|
+
addMsg("info", `Current model: ${modelName}\n Usage: /model <model-name>`);
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (trimmed.startsWith("/model ")) {
|
|
967
|
+
const newModel = trimmed.replace("/model ", "").trim();
|
|
944
968
|
if (!newModel) {
|
|
945
|
-
addMsg("info", `Current model: ${
|
|
969
|
+
addMsg("info", `Current model: ${modelName}\n Usage: /model <model-name>`);
|
|
946
970
|
return;
|
|
947
971
|
}
|
|
948
972
|
agent.switchModel(newModel);
|
|
@@ -1390,6 +1414,34 @@ function App() {
|
|
|
1390
1414
|
return;
|
|
1391
1415
|
}
|
|
1392
1416
|
|
|
1417
|
+
// ── Model picker ──
|
|
1418
|
+
if (modelPicker) {
|
|
1419
|
+
if (key.upArrow) {
|
|
1420
|
+
setModelPickerIndex((prev) => (prev - 1 + modelPicker.length) % modelPicker.length);
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
if (key.downArrow) {
|
|
1424
|
+
setModelPickerIndex((prev) => (prev + 1) % modelPicker.length);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (key.escape) {
|
|
1428
|
+
setModelPicker(null);
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
if (key.return) {
|
|
1432
|
+
const selected = modelPicker[modelPickerIndex];
|
|
1433
|
+
if (selected && agent) {
|
|
1434
|
+
agent.switchModel(selected);
|
|
1435
|
+
setModelName(selected);
|
|
1436
|
+
addMsg("info", `✅ Switched to: ${selected}`);
|
|
1437
|
+
refreshConnectionBanner();
|
|
1438
|
+
}
|
|
1439
|
+
setModelPicker(null);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1393
1445
|
// ── Ollama delete picker ──
|
|
1394
1446
|
if (ollamaDeletePicker) {
|
|
1395
1447
|
if (key.upArrow) {
|
|
@@ -2212,6 +2264,23 @@ function App() {
|
|
|
2212
2264
|
</Box>
|
|
2213
2265
|
)}
|
|
2214
2266
|
|
|
2267
|
+
{/* ═══ MODEL PICKER ═══ */}
|
|
2268
|
+
{modelPicker && (
|
|
2269
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
2270
|
+
<Text bold color={theme.colors.secondary}>Switch model:</Text>
|
|
2271
|
+
<Text>{""}</Text>
|
|
2272
|
+
{modelPicker.map((m, i) => (
|
|
2273
|
+
<Text key={m}>
|
|
2274
|
+
{" "}{i === modelPickerIndex ? <Text color={theme.colors.primary} bold>{"▸ "}</Text> : " "}
|
|
2275
|
+
<Text color={i === modelPickerIndex ? theme.colors.primary : undefined}>{m}</Text>
|
|
2276
|
+
{m === modelName ? <Text color={theme.colors.success}>{" (active)"}</Text> : null}
|
|
2277
|
+
</Text>
|
|
2278
|
+
))}
|
|
2279
|
+
<Text>{""}</Text>
|
|
2280
|
+
<Text dimColor>{" ↑↓ navigate · Enter to switch · Esc cancel"}</Text>
|
|
2281
|
+
</Box>
|
|
2282
|
+
)}
|
|
2283
|
+
|
|
2215
2284
|
{/* ═══ OLLAMA DELETE PICKER ═══ */}
|
|
2216
2285
|
{ollamaDeletePicker && (
|
|
2217
2286
|
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|