pudu-ai 0.2.13 → 0.2.14

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +95 -49
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -836,6 +836,10 @@ var en = {
836
836
  aboutTasks: "Asks what you want (code, video, image, transcription, chat) and returns small OpenCode-style harnesses per model, in this language. Use it to try a model on one concrete job.",
837
837
  aboutBenchmark: "Runs llama-bench on a local GGUF and records measured t/s plus system telemetry. Use it when you need real numbers, not estimates.",
838
838
  aboutCompare: "Compares saved measured runs (speed, memory, power). Quality is never inferred from speed. Use it after two or more benchmarks.",
839
+ compareHow: "[C] Compare needs two measured llama-bench runs of different models. Press [B], pick a model, wait; repeat with another; then [C]. Quality is not a speed score.",
840
+ compareNeedBench: "Need 2+ measured models. Press [B] to benchmark first.",
841
+ reqOllama: "install: https://ollama.com/download or brew install ollama",
842
+ reqLmStudio: "install: https://lmstudio.ai",
839
843
  aboutHistory: "Shows local benchmark files in ~/.pudu-ai/benchmarks. Use it to replay what this machine actually did.",
840
844
  aboutDoctor: "Checks Node, Apple Silicon/Metal, Ollama, llama-bench, and the CanIRun API. Use it to see what is missing before a bench or launch.",
841
845
  aboutReport: "Writes the latest measured run as Markdown. Use it to paste results into GitHub or notes.",
@@ -1021,6 +1025,10 @@ var es = {
1021
1025
  aboutTasks: "Pregunta qu\xE9 quieres (c\xF3digo, v\xEDdeo, imagen, transcripci\xF3n, chat) y devuelve harnesses peque\xF1os estilo OpenCode por modelo, en este idioma. Sirve para probar un modelo en una tarea concreta.",
1022
1026
  aboutBenchmark: "Ejecuta llama-bench sobre un GGUF local y guarda t/s medidos m\xE1s telemetr\xEDa. Sirve cuando necesitas n\xFAmeros reales, no estimaciones.",
1023
1027
  aboutCompare: "Compara corridas medidas (velocidad, memoria, potencia). La calidad no se infiere de la velocidad. Sirve despu\xE9s de dos o m\xE1s benchmarks.",
1028
+ compareHow: "[C] Comparar necesita dos corridas medidas de llama-bench en modelos distintos. Pulsa [B], elige un modelo, espera; repite con otro; luego [C]. La calidad no es un score de velocidad.",
1029
+ compareNeedBench: "Hacen falta 2+ modelos medidos. Pulsa [B] para hacer un benchmark primero.",
1030
+ reqOllama: "instalar: https://ollama.com/download o brew install ollama",
1031
+ reqLmStudio: "instalar: https://lmstudio.ai",
1024
1032
  aboutHistory: "Muestra los JSON locales en ~/.pudu-ai/benchmarks. Sirve para ver qu\xE9 hizo realmente esta m\xE1quina.",
1025
1033
  aboutDoctor: "Revisa Node, Apple Silicon/Metal, Ollama, llama-bench y la API de CanIRun. Sirve para ver qu\xE9 falta antes de un bench o un launch.",
1026
1034
  aboutReport: "Exporta la \xFAltima corrida medida en Markdown. Sirve para pegar resultados en GitHub o notas.",
@@ -1441,9 +1449,27 @@ async function listBenchmarks() {
1441
1449
 
1442
1450
  // src/integrations/agents.ts
1443
1451
  var AGENTS = [
1444
- { id: "opencode", label: "OpenCode", bin: "opencode" },
1445
- { id: "hermes", label: "Hermes", bin: "hermes" },
1446
- { id: "openclaw", label: "OpenClaw", bin: "openclaw" }
1452
+ {
1453
+ id: "opencode",
1454
+ label: "OpenCode",
1455
+ bin: "opencode",
1456
+ launch: "ollama launch opencode",
1457
+ docs: "https://docs.ollama.com/integrations/opencode"
1458
+ },
1459
+ {
1460
+ id: "hermes",
1461
+ label: "Hermes",
1462
+ bin: "hermes",
1463
+ launch: "ollama launch hermes",
1464
+ docs: "https://docs.ollama.com/integrations/hermes"
1465
+ },
1466
+ {
1467
+ id: "openclaw",
1468
+ label: "OpenClaw",
1469
+ bin: "openclaw",
1470
+ launch: "ollama launch openclaw",
1471
+ docs: "https://docs.ollama.com/integrations/openclaw"
1472
+ }
1447
1473
  ];
1448
1474
  async function detectAgents() {
1449
1475
  const out = [];
@@ -2119,6 +2145,11 @@ function Dashboard({ session }) {
2119
2145
  ] }),
2120
2146
  /* @__PURE__ */ jsx2(Text2, { color: gradeColor(rec.grade), children: rec.grade })
2121
2147
  ] }, `${rec.useCase}-${rec.model.id}`)),
2148
+ /* @__PURE__ */ jsxs2(Text2, { children: [
2149
+ /* @__PURE__ */ jsx2(Text2, { color: session.runtimes.find((r) => r.id === "ollama")?.detected ? "green" : "yellow", children: session.runtimes.find((r) => r.id === "ollama")?.detected ? "\u2713 Ollama" : `\u25CB Ollama ${t("reqOllama")}` }),
2150
+ /* @__PURE__ */ jsx2(Text2, { children: " " }),
2151
+ /* @__PURE__ */ jsx2(Text2, { color: session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "green" : "gray", children: session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "\u2713 LM Studio" : `\u25CB LM Studio ${t("reqLmStudio")}` })
2152
+ ] }),
2122
2153
  /* @__PURE__ */ jsx2(Typewriter, { text: fit(t("setupCta"), cols), ms: 18, color: "yellow" })
2123
2154
  ] });
2124
2155
  }
@@ -2247,7 +2278,11 @@ function doctorText(session) {
2247
2278
  `${session.hardware.gpu.metal ? "\u2713" : "\u25CB"} Metal`,
2248
2279
  ...session.runtimes.map((r) => `${r.detected ? "\u2713" : "\u25CB"} ${r.label.padEnd(14)} ${r.version ?? ""}`.trimEnd()),
2249
2280
  `${session.networkUsed ? "\u2713" : "\u25CB"} CanIRun.ai (midudev)`,
2250
- ...session.agents.map((a) => `${a.detected ? "\u2713" : "\u25CB"} ${a.label.padEnd(14)} ${a.detected ? t("detected") : t("agentMissing")}`),
2281
+ ...session.agents.map(
2282
+ (a) => `${a.detected ? "\u2713" : "\u25CB"} ${a.label.padEnd(14)} ${a.detected ? t("detected") : a.launch}`
2283
+ ),
2284
+ ...session.runtimes.find((r) => r.id === "ollama")?.detected ? [] : [`\u25CB Ollama ${t("reqOllama")}`],
2285
+ ...session.runtimes.find((r) => r.id === "lmstudio")?.detected ? [] : [`\u25CB LM Studio ${t("reqLmStudio")}`],
2251
2286
  "",
2252
2287
  session.llamaBench ? t("doctorReady", { count: session.models.filter((m) => m.artifactPath).length }) : t("doctorNoBench")
2253
2288
  ];
@@ -2627,14 +2662,19 @@ function SetupView({ session }) {
2627
2662
  resolveOllamaTag(item.model.id, item.model.name) ?? "\u2014"
2628
2663
  ] })
2629
2664
  ] }, `${item.useCase}-${item.model.id}`)),
2630
- /* @__PURE__ */ jsx6(Text6, { children: session.agents.map((agent, index) => /* @__PURE__ */ jsxs6(Text6, { color: agent.detected ? "green" : "gray", children: [
2631
- index ? " " : "",
2665
+ session.agents.map((agent, index) => /* @__PURE__ */ jsxs6(Text6, { color: agent.detected ? "green" : "yellow", children: [
2632
2666
  "[",
2633
2667
  index + 1,
2634
- "]",
2668
+ "] ",
2635
2669
  agent.detected ? "\u2713" : "\u25CB",
2636
- agent.label
2637
- ] }, agent.id)) }),
2670
+ " ",
2671
+ agent.label,
2672
+ agent.detected ? "" : ` \u2192 ${agent.launch}`
2673
+ ] }, agent.id)),
2674
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: fit(
2675
+ `Ollama: ${session.runtimes.find((r) => r.id === "ollama")?.detected ? "\u2713" : t("reqOllama")} LM Studio: ${session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "\u2713" : t("reqLmStudio")}`,
2676
+ cols
2677
+ ) }),
2638
2678
  /* @__PURE__ */ jsx6(Typewriter, { text: fit(`Enter=pull ${tag ?? ""} 1/2/3=agent Esc=back`, cols), ms: 14, dimColor: true }),
2639
2679
  log ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: fit(log, cols) }) : null
2640
2680
  ] });
@@ -2642,15 +2682,21 @@ function SetupView({ session }) {
2642
2682
 
2643
2683
  // src/tui/views/Compare.tsx
2644
2684
  import { Box as Box6, Text as Text7 } from "ink";
2645
- import { jsx as jsx7 } from "react/jsx-runtime";
2685
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2646
2686
  function CompareView({ session }) {
2647
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsx7(Text7, { children: compareText(session.history) }) });
2687
+ const cols = useCols();
2688
+ const n = new Set(session.history.map((h) => h.model.id)).size;
2689
+ return /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", width: cols, children: [
2690
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: "green", children: t("compareTitle") }),
2691
+ /* @__PURE__ */ jsx7(Typewriter, { text: fit(t("compareHow"), cols), ms: 12, dimColor: true }),
2692
+ n < 2 ? /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: fit(t("compareNeedBench"), cols) }) : /* @__PURE__ */ jsx7(Text7, { children: compareText(session.history) })
2693
+ ] });
2648
2694
  }
2649
2695
 
2650
2696
  // src/tui/views/Benchmark.tsx
2651
2697
  import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
2652
2698
  import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
2653
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2699
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2654
2700
  function BenchmarkView(props) {
2655
2701
  const [phase, setPhase] = useState3(props.models.length ? "select" : "error");
2656
2702
  const [sample, setSample] = useState3();
@@ -2710,9 +2756,9 @@ function BenchmarkView(props) {
2710
2756
  const h = props.session.hardware;
2711
2757
  const model = props.models[props.selected];
2712
2758
  if (phase === "select") {
2713
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2759
+ return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
2714
2760
  /* @__PURE__ */ jsx8(Text8, { bold: true, children: t("selectBenchmark") }),
2715
- props.models.map((m, i) => /* @__PURE__ */ jsxs7(Text8, { color: i === props.selected ? "cyan" : void 0, children: [
2761
+ props.models.map((m, i) => /* @__PURE__ */ jsxs8(Text8, { color: i === props.selected ? "cyan" : void 0, children: [
2716
2762
  i === props.selected ? "\u276F " : " ",
2717
2763
  m.name
2718
2764
  ] }, m.id)),
@@ -2720,9 +2766,9 @@ function BenchmarkView(props) {
2720
2766
  ] });
2721
2767
  }
2722
2768
  if (phase === "done" && result) {
2723
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2769
+ return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
2724
2770
  /* @__PURE__ */ jsx8(Text8, { children: resultText(result.record, result.assessment) }),
2725
- /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
2771
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2726
2772
  t("saved"),
2727
2773
  " ",
2728
2774
  result.path
@@ -2736,11 +2782,11 @@ function BenchmarkView(props) {
2736
2782
  const gpu = sample?.gpu?.utilizationPercent;
2737
2783
  const memUsed = sample?.memory.usedBytes;
2738
2784
  const memTotal = h.memory.totalBytes;
2739
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2740
- /* @__PURE__ */ jsxs7(Box7, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, children: [
2785
+ return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
2786
+ /* @__PURE__ */ jsxs8(Box7, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, children: [
2741
2787
  /* @__PURE__ */ jsx8(Text8, { bold: true, children: t("benchmarkTitle") }),
2742
2788
  /* @__PURE__ */ jsx8(Text8, { children: model?.name }),
2743
- /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
2789
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2744
2790
  h.cpu.name,
2745
2791
  " \xB7 ",
2746
2792
  formatBytes(h.memory.totalBytes, 0),
@@ -2748,9 +2794,9 @@ function BenchmarkView(props) {
2748
2794
  memoryLabel(h)
2749
2795
  ] })
2750
2796
  ] }),
2751
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2797
+ /* @__PURE__ */ jsxs8(Box7, { marginTop: 1, flexDirection: "column", children: [
2752
2798
  /* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: t("performance") }),
2753
- /* @__PURE__ */ jsxs7(Text8, { children: [
2799
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2754
2800
  t("elapsed"),
2755
2801
  " ",
2756
2802
  elapsed.toFixed(1),
@@ -2758,21 +2804,21 @@ function BenchmarkView(props) {
2758
2804
  ] }),
2759
2805
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: t("measuredAfter") })
2760
2806
  ] }),
2761
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2807
+ /* @__PURE__ */ jsxs8(Box7, { marginTop: 1, flexDirection: "column", children: [
2762
2808
  /* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: t("system") }),
2763
- /* @__PURE__ */ jsxs7(Text8, { children: [
2809
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2764
2810
  "CPU ",
2765
2811
  bar(cpu),
2766
2812
  " ",
2767
2813
  formatPercent(cpu)
2768
2814
  ] }),
2769
- /* @__PURE__ */ jsxs7(Text8, { children: [
2815
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2770
2816
  "GPU ",
2771
2817
  bar(gpu),
2772
2818
  " ",
2773
2819
  formatPercent(gpu)
2774
2820
  ] }),
2775
- /* @__PURE__ */ jsxs7(Text8, { children: [
2821
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2776
2822
  "Memory ",
2777
2823
  bar(memUsed && memTotal ? memUsed / memTotal * 100 : void 0),
2778
2824
  " ",
@@ -2780,36 +2826,36 @@ function BenchmarkView(props) {
2780
2826
  " / ",
2781
2827
  formatBytes(memTotal, 0)
2782
2828
  ] }),
2783
- /* @__PURE__ */ jsxs7(Text8, { children: [
2829
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2784
2830
  "Swap ",
2785
2831
  bar(0),
2786
2832
  " ",
2787
2833
  sample ? formatBytes(sample.memory.swapUsedBytes) : "N/A"
2788
2834
  ] })
2789
2835
  ] }),
2790
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2836
+ /* @__PURE__ */ jsxs8(Box7, { marginTop: 1, flexDirection: "column", children: [
2791
2837
  /* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: t("powerThermals") }),
2792
- /* @__PURE__ */ jsxs7(Text8, { children: [
2838
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2793
2839
  "Package ",
2794
2840
  sample?.packagePowerWatts ?? "N/A",
2795
2841
  " W"
2796
2842
  ] }),
2797
- /* @__PURE__ */ jsxs7(Text8, { children: [
2843
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2798
2844
  "Temperature ",
2799
2845
  sample?.thermal?.temperatureC ?? "N/A",
2800
2846
  " \xB0C"
2801
2847
  ] }),
2802
- /* @__PURE__ */ jsxs7(Text8, { children: [
2848
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2803
2849
  "Thermal Pressure ",
2804
2850
  sample?.thermal?.pressure ?? "N/A"
2805
2851
  ] }),
2806
2852
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: t("permissionsHint") })
2807
2853
  ] }),
2808
- /* @__PURE__ */ jsxs7(Text8, { children: [
2854
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2809
2855
  sparkline(cpuHist.current),
2810
2856
  " CPU"
2811
2857
  ] }),
2812
- /* @__PURE__ */ jsxs7(Text8, { children: [
2858
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2813
2859
  sparkline(memHist.current.map((v) => v / 1024 ** 3)),
2814
2860
  " Memory"
2815
2861
  ] }),
@@ -2819,9 +2865,9 @@ function BenchmarkView(props) {
2819
2865
 
2820
2866
  // src/tui/views/History.tsx
2821
2867
  import { Box as Box8, Text as Text9 } from "ink";
2822
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2868
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2823
2869
  function HistoryView({ session }) {
2824
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2870
+ return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", children: [
2825
2871
  /* @__PURE__ */ jsx9(Text9, { bold: true, color: "cyan", children: t("measured") }),
2826
2872
  /* @__PURE__ */ jsx9(Text9, { children: historyText(session.history) })
2827
2873
  ] });
@@ -3024,7 +3070,7 @@ function tasksText(plans, answers) {
3024
3070
  }
3025
3071
 
3026
3072
  // src/tui/views/Tasks.tsx
3027
- import { Fragment, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
3073
+ import { Fragment, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
3028
3074
  var KIND_LABEL = {
3029
3075
  code: "tasksOptCode",
3030
3076
  video: "tasksOptVideo",
@@ -3067,11 +3113,11 @@ function TasksView({ session }) {
3067
3113
  if (step === 3) {
3068
3114
  return /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsx10(Text10, { children: tasksText(plans, { kinds, scope, priority }) }) });
3069
3115
  }
3070
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
3116
+ return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", children: [
3071
3117
  /* @__PURE__ */ jsx10(Text10, { bold: true, color: "cyan", children: t("tasksTitle") }),
3072
- step === 0 && /* @__PURE__ */ jsxs9(Fragment, { children: [
3118
+ step === 0 && /* @__PURE__ */ jsxs10(Fragment, { children: [
3073
3119
  /* @__PURE__ */ jsx10(Text10, { children: t("tasksQ1") }),
3074
- WORK_KINDS.map((kind, i) => /* @__PURE__ */ jsxs9(Text10, { color: i === cursor ? "cyan" : void 0, children: [
3120
+ WORK_KINDS.map((kind, i) => /* @__PURE__ */ jsxs10(Text10, { color: i === cursor ? "cyan" : void 0, children: [
3075
3121
  i === cursor ? "\u276F " : " ",
3076
3122
  "[",
3077
3123
  kinds.includes(kind) ? "x" : " ",
@@ -3079,20 +3125,20 @@ function TasksView({ session }) {
3079
3125
  t(KIND_LABEL[kind])
3080
3126
  ] }, kind))
3081
3127
  ] }),
3082
- step === 1 && /* @__PURE__ */ jsxs9(Fragment, { children: [
3128
+ step === 1 && /* @__PURE__ */ jsxs10(Fragment, { children: [
3083
3129
  /* @__PURE__ */ jsx10(Text10, { children: t("tasksQ2") }),
3084
- /* @__PURE__ */ jsxs9(Text10, { color: scope === "installed" ? "cyan" : void 0, children: [
3130
+ /* @__PURE__ */ jsxs10(Text10, { color: scope === "installed" ? "cyan" : void 0, children: [
3085
3131
  scope === "installed" ? "\u276F " : " ",
3086
3132
  t("tasksOptInstalled")
3087
3133
  ] }),
3088
- /* @__PURE__ */ jsxs9(Text10, { color: scope === "all" ? "cyan" : void 0, children: [
3134
+ /* @__PURE__ */ jsxs10(Text10, { color: scope === "all" ? "cyan" : void 0, children: [
3089
3135
  scope === "all" ? "\u276F " : " ",
3090
3136
  t("tasksOptAll")
3091
3137
  ] })
3092
3138
  ] }),
3093
- step === 2 && /* @__PURE__ */ jsxs9(Fragment, { children: [
3139
+ step === 2 && /* @__PURE__ */ jsxs10(Fragment, { children: [
3094
3140
  /* @__PURE__ */ jsx10(Text10, { children: t("tasksQ3") }),
3095
- ["speed", "balanced", "quality"].map((item) => /* @__PURE__ */ jsxs9(Text10, { color: priority === item ? "cyan" : void 0, children: [
3141
+ ["speed", "balanced", "quality"].map((item) => /* @__PURE__ */ jsxs10(Text10, { color: priority === item ? "cyan" : void 0, children: [
3096
3142
  priority === item ? "\u276F " : " ",
3097
3143
  item === "speed" ? t("tasksOptSpeed") : item === "quality" ? t("tasksOptQuality") : t("tasksOptBalanced")
3098
3144
  ] }, item))
@@ -3129,14 +3175,14 @@ function handleAppKey(screen, input, key) {
3129
3175
 
3130
3176
  // src/tui/Welcome.tsx
3131
3177
  import { Box as Box10, Text as Text11 } from "ink";
3132
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
3178
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3133
3179
  function Chrome() {
3134
3180
  const cols = useCols();
3135
3181
  const wide = cols >= 72;
3136
3182
  const brand = `${t("appTitle")} ${t("byline")}`;
3137
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", width: cols, marginBottom: 1, children: [
3183
+ return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "column", width: cols, marginBottom: 1, children: [
3138
3184
  /* @__PURE__ */ jsx11(Typewriter, { text: brand, ms: 28, color: "cyan", bold: true, once: true }),
3139
- /* @__PURE__ */ jsx11(Text11, { children: wide ? /* @__PURE__ */ jsxs10(Fragment2, { children: [
3185
+ /* @__PURE__ */ jsx11(Text11, { children: wide ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
3140
3186
  /* @__PURE__ */ jsx11(Text11, { color: "yellow", children: "[S] Setup" }),
3141
3187
  /* @__PURE__ */ jsx11(Text11, { children: " " }),
3142
3188
  /* @__PURE__ */ jsx11(Text11, { color: "green", children: "[B] Bench" }),
@@ -3154,7 +3200,7 @@ function Chrome() {
3154
3200
  /* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "[L] Log" }),
3155
3201
  /* @__PURE__ */ jsx11(Text11, { children: " " }),
3156
3202
  /* @__PURE__ */ jsx11(Text11, { color: "red", children: "[Q] Quit" })
3157
- ] }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
3203
+ ] }) : /* @__PURE__ */ jsxs11(Fragment2, { children: [
3158
3204
  /* @__PURE__ */ jsx11(Text11, { color: "yellow", children: "[S]" }),
3159
3205
  /* @__PURE__ */ jsx11(Text11, { color: "green", children: "[B]" }),
3160
3206
  /* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "[M]" }),
@@ -3169,7 +3215,7 @@ function Chrome() {
3169
3215
  }
3170
3216
 
3171
3217
  // src/tui/App.tsx
3172
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
3218
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
3173
3219
  function App(props) {
3174
3220
  const { exit } = useApp2();
3175
3221
  const [screen, setScreen] = useState5(props.start ?? "home");
@@ -3186,7 +3232,7 @@ function App(props) {
3186
3232
  if (result.type === "home") setScreen("home");
3187
3233
  if (result.type === "screen") setScreen(result.screen);
3188
3234
  });
3189
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, children: [
3235
+ return /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", paddingX: 1, children: [
3190
3236
  screen !== "benchmark" && /* @__PURE__ */ jsx12(Chrome, {}),
3191
3237
  screen === "home" && /* @__PURE__ */ jsx12(Dashboard, { session: props.session }),
3192
3238
  screen === "models" && /* @__PURE__ */ jsx12(ModelsView, { session: props.session }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pudu-ai",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "Pudu-AI — local AI hardware & benchmark lab for the terminal",
5
5
  "keywords": [
6
6
  "ai",