pudu-ai 0.2.5 → 0.2.7
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 +1 -0
- package/dist/cli/index.js +155 -45
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -17,7 +17,8 @@ function parseArgs(argv) {
|
|
|
17
17
|
"doctor",
|
|
18
18
|
"report",
|
|
19
19
|
"tasks",
|
|
20
|
-
"launch"
|
|
20
|
+
"launch",
|
|
21
|
+
"setup"
|
|
21
22
|
];
|
|
22
23
|
const isKnown = known.includes(command);
|
|
23
24
|
let addPath;
|
|
@@ -827,6 +828,7 @@ async function loadCatalogCache() {
|
|
|
827
828
|
var en = {
|
|
828
829
|
appTitle: "PUDU-AI",
|
|
829
830
|
appSubtitle: "Local AI Hardware & Benchmark Lab",
|
|
831
|
+
byline: "by devjaime",
|
|
830
832
|
aboutDashboard: "Opens the live lab: your machine, installed models, and estimates. Use it to see what can run here before you benchmark or launch a tool.",
|
|
831
833
|
aboutHardware: "Detects CPU, GPU, and Unified Memory/RAM. Use it to know what this computer can host before pulling a model.",
|
|
832
834
|
aboutModels: "Lists installed models vs catalog fits. FIT/EST. SPEED are estimated (CanIRun.ai by midudev); MEASURED is llama-bench history. Use it to separate \u201Calready here\u201D from \u201Cmight run\u201D.",
|
|
@@ -839,7 +841,17 @@ var en = {
|
|
|
839
841
|
aboutReport: "Writes the latest measured run as Markdown. Use it to paste results into GitHub or notes.",
|
|
840
842
|
aboutLaunch: "Explains Ollama integrations (OpenCode, OpenClaw, Hermes, Claude Code). Pull/launch only with --yes if the model grade is S\u2013B and speed is enough. Use it to wire a coding agent only when this hardware can carry it.",
|
|
841
843
|
aboutAddPath: "Adds a GGUF folder to scan (not the whole disk). Use it so llama-bench can find models outside Ollama.",
|
|
842
|
-
nav: "[B] Benchmark [M] Models [R] Recommend [T] Tasks [H] Hardware [C] Compare [L] History [Q] Quit",
|
|
844
|
+
nav: "[S] Setup/Install [B] Benchmark [M] Models [R] Recommend [T] Tasks [H] Hardware [C] Compare [L] History [Q] Quit",
|
|
845
|
+
setupTitle: "SETUP \u2014 INSTALL MODELS & AGENTS",
|
|
846
|
+
setupIntro: "Pick a recommended model (grade S\u2013B), install it with Ollama, then link or install OpenCode, Hermes, or OpenClaw.",
|
|
847
|
+
setupStep1: "1. Recommended models (\u2191\u2193 to choose)",
|
|
848
|
+
setupStep2: "2. Install the selected model",
|
|
849
|
+
setupInstallModel: "Press Enter or I \u2192 ollama pull (only if grade is S, A, or B)",
|
|
850
|
+
setupStep3: "3. Coding agent \u2014 link if present, install if missing",
|
|
851
|
+
setupLinkNow: "installed \u2192 press 1/2/3 to link this model",
|
|
852
|
+
setupInstallAgent: "not installed \u2192 press 1/2/3 to install via ollama launch (if eligible)",
|
|
853
|
+
setupKeys: "Enter/I = pull model 1 OpenCode 2 Hermes 3 OpenClaw Esc = back",
|
|
854
|
+
setupCta: "\u2192 Press [S] or [I] to INSTALL a recommended model and link OpenCode / Hermes / OpenClaw",
|
|
843
855
|
machine: "MACHINE",
|
|
844
856
|
runtimes: "LOCAL AI RUNTIMES",
|
|
845
857
|
installedModels: "INSTALLED MODELS",
|
|
@@ -960,6 +972,7 @@ Usage:
|
|
|
960
972
|
npx pudu-ai hardware
|
|
961
973
|
npx pudu-ai models
|
|
962
974
|
npx pudu-ai models add-path ~/Models
|
|
975
|
+
npx pudu-ai setup
|
|
963
976
|
npx pudu-ai recommend
|
|
964
977
|
npx pudu-ai recommend --install --yes
|
|
965
978
|
npx pudu-ai recommend --link opencode --yes
|
|
@@ -999,6 +1012,7 @@ Credits:
|
|
|
999
1012
|
var es = {
|
|
1000
1013
|
appTitle: "PUDU-AI",
|
|
1001
1014
|
appSubtitle: "Laboratorio local de hardware y benchmarks de IA",
|
|
1015
|
+
byline: "by devjaime",
|
|
1002
1016
|
aboutDashboard: "Abre el laboratorio en vivo: equipo, modelos instalados y estimaciones. Sirve para ver qu\xE9 puede correr aqu\xED antes de medir o lanzar una herramienta.",
|
|
1003
1017
|
aboutHardware: "Detecta CPU, GPU y memoria unificada/RAM. Sirve para saber qu\xE9 puede hospedar este equipo antes de descargar un modelo.",
|
|
1004
1018
|
aboutModels: "Lista instalados frente al cat\xE1logo. FIT/EST. SPEED son estimados (CanIRun.ai de midudev); MEASURED es historial de llama-bench. Sirve para separar \u201Cya est\xE1\u201D de \u201Cpodr\xEDa correr\u201D.",
|
|
@@ -1011,7 +1025,17 @@ var es = {
|
|
|
1011
1025
|
aboutReport: "Exporta la \xFAltima corrida medida en Markdown. Sirve para pegar resultados en GitHub o notas.",
|
|
1012
1026
|
aboutLaunch: "Explica las integraciones de Ollama (OpenCode, OpenClaw, Hermes, Claude Code). Pull/launch solo con --yes si la nota es S\u2013B y hay velocidad suficiente. Sirve para conectar un agente de c\xF3digo solo cuando el hardware lo aguanta.",
|
|
1013
1027
|
aboutAddPath: "A\xF1ade una carpeta GGUF a escanear (no todo el disco). Sirve para que llama-bench encuentre modelos fuera de Ollama.",
|
|
1014
|
-
nav: "[B] Benchmark [M] Modelos [R] Recomendaciones [T] Tareas [H] Hardware [C] Comparar [L] Historial [Q] Salir",
|
|
1028
|
+
nav: "[S] Setup/Instalar [B] Benchmark [M] Modelos [R] Recomendaciones [T] Tareas [H] Hardware [C] Comparar [L] Historial [Q] Salir",
|
|
1029
|
+
setupTitle: "SETUP \u2014 INSTALAR MODELOS Y AGENTES",
|
|
1030
|
+
setupIntro: "Elige un modelo recomendado (nota S\u2013B), inst\xE1lalo con Ollama y luego vincula o instala OpenCode, Hermes u OpenClaw.",
|
|
1031
|
+
setupStep1: "1. Modelos recomendados (\u2191\u2193 para elegir)",
|
|
1032
|
+
setupStep2: "2. Instalar el modelo seleccionado",
|
|
1033
|
+
setupInstallModel: "Enter o I \u2192 ollama pull (solo si la nota es S, A o B)",
|
|
1034
|
+
setupStep3: "3. Agente de c\xF3digo \u2014 vincular si existe, instalar si falta",
|
|
1035
|
+
setupLinkNow: "instalado \u2192 pulsa 1/2/3 para vincular este modelo",
|
|
1036
|
+
setupInstallAgent: "no instalado \u2192 pulsa 1/2/3 para instalar con ollama launch (si es elegible)",
|
|
1037
|
+
setupKeys: "Enter/I = descargar modelo 1 OpenCode 2 Hermes 3 OpenClaw Esc = atr\xE1s",
|
|
1038
|
+
setupCta: "\u2192 Pulsa [S] o [I] para INSTALAR un modelo recomendado y vincular OpenCode / Hermes / OpenClaw",
|
|
1015
1039
|
machine: "EQUIPO",
|
|
1016
1040
|
runtimes: "RUNTIMES DE IA LOCAL",
|
|
1017
1041
|
installedModels: "MODELOS INSTALADOS",
|
|
@@ -1132,6 +1156,7 @@ Uso:
|
|
|
1132
1156
|
npx pudu-ai hardware
|
|
1133
1157
|
npx pudu-ai models
|
|
1134
1158
|
npx pudu-ai models add-path ~/Models
|
|
1159
|
+
npx pudu-ai setup
|
|
1135
1160
|
npx pudu-ai recommend
|
|
1136
1161
|
npx pudu-ai recommend --install --yes
|
|
1137
1162
|
npx pudu-ai recommend --link opencode --yes
|
|
@@ -1927,7 +1952,7 @@ function setLogLevel(next) {
|
|
|
1927
1952
|
import { render } from "ink";
|
|
1928
1953
|
|
|
1929
1954
|
// src/tui/App.tsx
|
|
1930
|
-
import { Box as
|
|
1955
|
+
import { Box as Box10, useApp as useApp2, useInput as useInput4 } from "ink";
|
|
1931
1956
|
import { useMemo as useMemo2, useState as useState4 } from "react";
|
|
1932
1957
|
|
|
1933
1958
|
// src/tui/views/Dashboard.tsx
|
|
@@ -1992,11 +2017,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
1992
2017
|
function Dashboard({ session }) {
|
|
1993
2018
|
const h = session.hardware;
|
|
1994
2019
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1995
|
-
/* @__PURE__ */
|
|
1996
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: t("appTitle") }),
|
|
1997
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: t("appSubtitle") }),
|
|
1998
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: t("aboutDashboard") })
|
|
1999
|
-
] }),
|
|
2020
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: t("aboutDashboard") }),
|
|
2000
2021
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: t("machine") }),
|
|
2001
2022
|
/* @__PURE__ */ jsx(Text, { children: h.machineModel ?? t("unknownMachine") }),
|
|
2002
2023
|
/* @__PURE__ */ jsx(Text, { children: h.cpu.name ?? t("cpuNa") }),
|
|
@@ -2059,7 +2080,8 @@ function Dashboard({ session }) {
|
|
|
2059
2080
|
" ",
|
|
2060
2081
|
GRADE_MEANING[rec.grade]
|
|
2061
2082
|
] }, `${rec.useCase}-${rec.model.id}`)),
|
|
2062
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: t("credits") })
|
|
2083
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: t("credits") }),
|
|
2084
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: t("setupCta") })
|
|
2063
2085
|
] })
|
|
2064
2086
|
] });
|
|
2065
2087
|
}
|
|
@@ -2263,7 +2285,7 @@ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
|
2263
2285
|
function ModelsView({ session }) {
|
|
2264
2286
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
2265
2287
|
/* @__PURE__ */ jsx2(Text2, { children: modelsText(session) }),
|
|
2266
|
-
/* @__PURE__ */ jsx2(Text2, {
|
|
2288
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: t("modelsHint") })
|
|
2267
2289
|
] });
|
|
2268
2290
|
}
|
|
2269
2291
|
|
|
@@ -2274,7 +2296,7 @@ function HardwareView({ session }) {
|
|
|
2274
2296
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
2275
2297
|
/* @__PURE__ */ jsx3(Text3, { children: hardwareText(session) }),
|
|
2276
2298
|
/* @__PURE__ */ jsx3(Text3, { children: runtimesText(session) }),
|
|
2277
|
-
/* @__PURE__ */ jsx3(Text3, {
|
|
2299
|
+
/* @__PURE__ */ jsx3(Text3, { color: "yellow", children: t("hardwareHint") })
|
|
2278
2300
|
] });
|
|
2279
2301
|
}
|
|
2280
2302
|
|
|
@@ -2471,19 +2493,23 @@ async function pullOllamaModel(modelId) {
|
|
|
2471
2493
|
|
|
2472
2494
|
// src/tui/views/Recommend.tsx
|
|
2473
2495
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2496
|
+
var TOOLS = [
|
|
2497
|
+
{ key: "1", id: "opencode", label: "OpenCode" },
|
|
2498
|
+
{ key: "2", id: "hermes", label: "Hermes" },
|
|
2499
|
+
{ key: "3", id: "openclaw", label: "OpenClaw" }
|
|
2500
|
+
];
|
|
2474
2501
|
function RecommendView({ session }) {
|
|
2475
2502
|
const { exit } = useApp();
|
|
2476
2503
|
const [cursor, setCursor] = useState(0);
|
|
2477
2504
|
const [log, setLog] = useState("");
|
|
2478
2505
|
const [busy, setBusy] = useState(false);
|
|
2479
2506
|
const recs = session.recommendations;
|
|
2507
|
+
const rec = recs[cursor];
|
|
2480
2508
|
useInput((input, key) => {
|
|
2481
2509
|
if (busy) return;
|
|
2482
|
-
if (key.escape) return;
|
|
2483
2510
|
if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
|
|
2484
2511
|
if (key.downArrow) setCursor((c) => Math.min(Math.max(recs.length - 1, 0), c + 1));
|
|
2485
|
-
|
|
2486
|
-
if (input.toLowerCase() === "i" && rec) {
|
|
2512
|
+
if ((input.toLowerCase() === "i" || key.return) && rec) {
|
|
2487
2513
|
if (!canInstallGrade(rec.grade)) {
|
|
2488
2514
|
setLog(t("installGradeBlock", { grade: rec.grade }));
|
|
2489
2515
|
return;
|
|
@@ -2495,8 +2521,7 @@ function RecommendView({ session }) {
|
|
|
2495
2521
|
setBusy(false);
|
|
2496
2522
|
});
|
|
2497
2523
|
}
|
|
2498
|
-
const
|
|
2499
|
-
const tool = map[input.toLowerCase()];
|
|
2524
|
+
const tool = TOOLS.find((item) => item.key === input)?.id;
|
|
2500
2525
|
if (tool && rec) {
|
|
2501
2526
|
const decision = decideLaunch(session, tool);
|
|
2502
2527
|
if (!decision.eligible) {
|
|
@@ -2513,29 +2538,40 @@ function RecommendView({ session }) {
|
|
|
2513
2538
|
}
|
|
2514
2539
|
});
|
|
2515
2540
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
2516
|
-
/* @__PURE__ */
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2541
|
+
/* @__PURE__ */ jsxs4(Box4, { borderStyle: "round", borderColor: "yellow", flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
2542
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "yellow", children: t("setupTitle") }),
|
|
2543
|
+
/* @__PURE__ */ jsx4(Text4, { children: t("setupIntro") })
|
|
2544
|
+
] }),
|
|
2545
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: t("setupStep1") }),
|
|
2546
|
+
recs.length === 0 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: t("installNone") }),
|
|
2547
|
+
recs.map((item, i) => /* @__PURE__ */ jsxs4(Text4, { color: i === cursor ? "cyan" : void 0, children: [
|
|
2520
2548
|
i === cursor ? "\u276F " : " ",
|
|
2521
|
-
/* @__PURE__ */ jsx4(Text4, { color: "magenta", children:
|
|
2522
|
-
|
|
2549
|
+
/* @__PURE__ */ jsx4(Text4, { color: "magenta", children: item.useCase.padEnd(12) }),
|
|
2550
|
+
item.model.name.padEnd(22),
|
|
2523
2551
|
" ",
|
|
2524
|
-
/* @__PURE__ */ jsx4(Text4, { color: gradeColor(
|
|
2552
|
+
/* @__PURE__ */ jsx4(Text4, { color: gradeColor(item.grade), bold: true, children: item.grade }),
|
|
2525
2553
|
" ",
|
|
2526
|
-
GRADE_MEANING[
|
|
2527
|
-
] }, `${
|
|
2554
|
+
GRADE_MEANING[item.grade]
|
|
2555
|
+
] }, `${item.useCase}-${item.model.id}`)),
|
|
2528
2556
|
/* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
2529
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "
|
|
2530
|
-
|
|
2557
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "green", children: t("setupStep2") }),
|
|
2558
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: t("setupInstallModel") })
|
|
2559
|
+
] }),
|
|
2560
|
+
/* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
2561
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "yellow", children: t("setupStep3") }),
|
|
2562
|
+
session.agents.map((agent, index) => /* @__PURE__ */ jsxs4(Text4, { color: agent.detected ? "green" : "yellow", children: [
|
|
2563
|
+
"[",
|
|
2564
|
+
index + 1,
|
|
2565
|
+
"] ",
|
|
2531
2566
|
agent.detected ? "\u2713" : "\u25CB",
|
|
2532
2567
|
" ",
|
|
2533
2568
|
agent.label.padEnd(12),
|
|
2534
2569
|
" ",
|
|
2535
|
-
agent.detected ? t("
|
|
2570
|
+
agent.detected ? t("setupLinkNow") : t("setupInstallAgent")
|
|
2536
2571
|
] }, agent.id))
|
|
2537
2572
|
] }),
|
|
2538
|
-
|
|
2573
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: t("setupKeys") }) }),
|
|
2574
|
+
log ? /* @__PURE__ */ jsx4(Text4, { color: "green", children: log }) : null
|
|
2539
2575
|
] });
|
|
2540
2576
|
}
|
|
2541
2577
|
|
|
@@ -3016,15 +3052,81 @@ function handleAppKey(screen, input, key) {
|
|
|
3016
3052
|
if (letter === "c") return { type: "screen", screen: "compare" };
|
|
3017
3053
|
if (letter === "l") return { type: "screen", screen: "history" };
|
|
3018
3054
|
if (letter === "t") return { type: "screen", screen: "tasks" };
|
|
3055
|
+
if (letter === "s" || letter === "i") return { type: "screen", screen: "recommend" };
|
|
3019
3056
|
if (key.return && screen === "home") return { type: "screen", screen: "benchmark" };
|
|
3020
3057
|
return { type: "ignore" };
|
|
3021
3058
|
}
|
|
3022
3059
|
|
|
3023
|
-
// src/tui/
|
|
3060
|
+
// src/tui/Welcome.tsx
|
|
3061
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
3024
3062
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3063
|
+
function Welcome({ compact = false }) {
|
|
3064
|
+
if (compact) {
|
|
3065
|
+
return /* @__PURE__ */ jsxs8(Box9, { marginBottom: 1, children: [
|
|
3066
|
+
/* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "\u{1F98C} " }),
|
|
3067
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "cyan", children: t("appTitle") }),
|
|
3068
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "magenta", children: [
|
|
3069
|
+
" ",
|
|
3070
|
+
t("byline")
|
|
3071
|
+
] })
|
|
3072
|
+
] });
|
|
3073
|
+
}
|
|
3074
|
+
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", marginBottom: 1, children: [
|
|
3075
|
+
/* @__PURE__ */ jsx9(Text9, { color: "yellow", children: " \\/ \\/" }),
|
|
3076
|
+
/* @__PURE__ */ jsxs8(Text9, { children: [
|
|
3077
|
+
/* @__PURE__ */ jsx9(Text9, { color: "yellow", children: " " }),
|
|
3078
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " (\\_ _/)" })
|
|
3079
|
+
] }),
|
|
3080
|
+
/* @__PURE__ */ jsxs8(Text9, { children: [
|
|
3081
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " / " }),
|
|
3082
|
+
/* @__PURE__ */ jsx9(Text9, { color: "white", children: "o o" }),
|
|
3083
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " \\" }),
|
|
3084
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
3085
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "green", children: t("appTitle") })
|
|
3086
|
+
] }),
|
|
3087
|
+
/* @__PURE__ */ jsxs8(Text9, { children: [
|
|
3088
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " \\ " }),
|
|
3089
|
+
/* @__PURE__ */ jsx9(Text9, { color: "red", children: "^" }),
|
|
3090
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " /" }),
|
|
3091
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
3092
|
+
/* @__PURE__ */ jsx9(Text9, { color: "white", children: t("appSubtitle") })
|
|
3093
|
+
] }),
|
|
3094
|
+
/* @__PURE__ */ jsxs8(Text9, { children: [
|
|
3095
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", children: " /| |\\" }),
|
|
3096
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
3097
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "magenta", children: t("byline") })
|
|
3098
|
+
] }),
|
|
3099
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", children: " U U" })
|
|
3100
|
+
] });
|
|
3101
|
+
}
|
|
3102
|
+
function ColorNav() {
|
|
3103
|
+
return /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text9, { children: [
|
|
3104
|
+
/* @__PURE__ */ jsx9(Text9, { color: "yellow", bold: true, children: "[S]" }),
|
|
3105
|
+
/* @__PURE__ */ jsx9(Text9, { color: "yellow", children: " Setup " }),
|
|
3106
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", bold: true, children: "[B]" }),
|
|
3107
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", children: " Bench " }),
|
|
3108
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "[M]" }),
|
|
3109
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " Models " }),
|
|
3110
|
+
/* @__PURE__ */ jsx9(Text9, { color: "magenta", bold: true, children: "[R]" }),
|
|
3111
|
+
/* @__PURE__ */ jsx9(Text9, { color: "magenta", children: " Rec " }),
|
|
3112
|
+
/* @__PURE__ */ jsx9(Text9, { color: "blue", bold: true, children: "[T]" }),
|
|
3113
|
+
/* @__PURE__ */ jsx9(Text9, { color: "blue", children: " Tasks " }),
|
|
3114
|
+
/* @__PURE__ */ jsx9(Text9, { color: "white", bold: true, children: "[H]" }),
|
|
3115
|
+
/* @__PURE__ */ jsx9(Text9, { children: " HW " }),
|
|
3116
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", bold: true, children: "[C]" }),
|
|
3117
|
+
/* @__PURE__ */ jsx9(Text9, { color: "green", children: " Cmp " }),
|
|
3118
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "[L]" }),
|
|
3119
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: " Log " }),
|
|
3120
|
+
/* @__PURE__ */ jsx9(Text9, { color: "red", bold: true, children: "[Q]" }),
|
|
3121
|
+
/* @__PURE__ */ jsx9(Text9, { color: "red", children: " Quit" })
|
|
3122
|
+
] }) });
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
// src/tui/App.tsx
|
|
3126
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3025
3127
|
function App(props) {
|
|
3026
3128
|
const { exit } = useApp2();
|
|
3027
|
-
const [screen, setScreen] = useState4("home");
|
|
3129
|
+
const [screen, setScreen] = useState4(props.start ?? "home");
|
|
3028
3130
|
const [selected, setSelected] = useState4(0);
|
|
3029
3131
|
const benchable = useMemo2(
|
|
3030
3132
|
() => props.session.models.filter((m) => Boolean(m.artifactPath)),
|
|
@@ -3036,15 +3138,16 @@ function App(props) {
|
|
|
3036
3138
|
if (result.type === "home") setScreen("home");
|
|
3037
3139
|
if (result.type === "screen") setScreen(result.screen);
|
|
3038
3140
|
});
|
|
3039
|
-
return /* @__PURE__ */
|
|
3040
|
-
screen
|
|
3041
|
-
screen === "
|
|
3042
|
-
screen === "
|
|
3043
|
-
screen === "
|
|
3044
|
-
screen === "
|
|
3045
|
-
screen === "
|
|
3046
|
-
screen === "
|
|
3047
|
-
screen === "
|
|
3141
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", padding: 1, children: [
|
|
3142
|
+
screen !== "benchmark" && /* @__PURE__ */ jsx10(Welcome, { compact: screen !== "home" }),
|
|
3143
|
+
screen === "home" && /* @__PURE__ */ jsx10(Dashboard, { session: props.session }),
|
|
3144
|
+
screen === "models" && /* @__PURE__ */ jsx10(ModelsView, { session: props.session }),
|
|
3145
|
+
screen === "hardware" && /* @__PURE__ */ jsx10(HardwareView, { session: props.session }),
|
|
3146
|
+
screen === "recommend" && /* @__PURE__ */ jsx10(RecommendView, { session: props.session }),
|
|
3147
|
+
screen === "compare" && /* @__PURE__ */ jsx10(CompareView, { session: props.session }),
|
|
3148
|
+
screen === "history" && /* @__PURE__ */ jsx10(HistoryView, { session: props.session }),
|
|
3149
|
+
screen === "tasks" && /* @__PURE__ */ jsx10(TasksView, { session: props.session }),
|
|
3150
|
+
screen === "benchmark" && /* @__PURE__ */ jsx10(
|
|
3048
3151
|
BenchmarkView,
|
|
3049
3152
|
{
|
|
3050
3153
|
session: props.session,
|
|
@@ -3055,14 +3158,14 @@ function App(props) {
|
|
|
3055
3158
|
onBack: () => setScreen("home")
|
|
3056
3159
|
}
|
|
3057
3160
|
),
|
|
3058
|
-
screen !== "benchmark" && /* @__PURE__ */
|
|
3161
|
+
screen !== "benchmark" && /* @__PURE__ */ jsx10(ColorNav, {})
|
|
3059
3162
|
] });
|
|
3060
3163
|
}
|
|
3061
3164
|
|
|
3062
3165
|
// src/tui/render.tsx
|
|
3063
|
-
import { jsx as
|
|
3064
|
-
async function renderDashboard(session, preset) {
|
|
3065
|
-
const instance = render(/* @__PURE__ */
|
|
3166
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
3167
|
+
async function renderDashboard(session, preset, start) {
|
|
3168
|
+
const instance = render(/* @__PURE__ */ jsx11(App, { session, preset, start }));
|
|
3066
3169
|
await instance.waitUntilExit();
|
|
3067
3170
|
}
|
|
3068
3171
|
|
|
@@ -3124,6 +3227,13 @@ ${runtimesText(session)}`),
|
|
|
3124
3227
|
case "models":
|
|
3125
3228
|
print(args2.json ? session.rows : explained("aboutModels", modelsText(session)), args2.json);
|
|
3126
3229
|
return 0;
|
|
3230
|
+
case "setup":
|
|
3231
|
+
if (args2.json) {
|
|
3232
|
+
print({ recommendations: session.recommendations, agents: session.agents }, true);
|
|
3233
|
+
return 0;
|
|
3234
|
+
}
|
|
3235
|
+
await renderDashboard(session, args2.preset, "recommend");
|
|
3236
|
+
return 0;
|
|
3127
3237
|
case "recommend": {
|
|
3128
3238
|
if (args2.install && args2.yes) {
|
|
3129
3239
|
const rec = session.recommendations.find((r) => canInstallGrade(r.grade));
|