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 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.startsWith("/model")) {
905
- const newModel = trimmed.replace("/model", "").trim();
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: ${agent.getModel()}\n Usage: /model <model-name>`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemaxxing",
3
- "version": "0.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Open-source terminal coding agent. Connect any LLM. Max your code.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
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.startsWith("/model")) {
943
- const newModel = trimmed.replace("/model", "").trim();
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: ${agent.getModel()}\n Usage: /model <model-name>`);
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}>