pudu-ai 0.2.10 → 0.2.11

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 +86 -60
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -851,7 +851,7 @@ var en = {
851
851
  setupLinkNow: "installed \u2192 press 1/2/3 to link this model",
852
852
  setupInstallAgent: "not installed \u2192 press 1/2/3 to install via ollama launch (if eligible)",
853
853
  setupKeys: "Enter/I = pull model 1 OpenCode 2 Hermes 3 OpenClaw Esc = back",
854
- setupCta: "[S] setup",
854
+ setupCta: "[S] Setup: install model + OpenCode / Hermes / OpenClaw",
855
855
  machine: "MACHINE",
856
856
  runtimes: "LOCAL AI RUNTIMES",
857
857
  installedModels: "INSTALLED MODELS",
@@ -1036,7 +1036,7 @@ var es = {
1036
1036
  setupLinkNow: "instalado \u2192 pulsa 1/2/3 para vincular este modelo",
1037
1037
  setupInstallAgent: "no instalado \u2192 pulsa 1/2/3 para instalar con ollama launch (si es elegible)",
1038
1038
  setupKeys: "Enter/I = descargar modelo 1 OpenCode 2 Hermes 3 OpenClaw Esc = atr\xE1s",
1039
- setupCta: "[S] setup",
1039
+ setupCta: "[S] Setup: instalar modelo + OpenCode / Hermes / OpenClaw",
1040
1040
  machine: "EQUIPO",
1041
1041
  runtimes: "RUNTIMES DE IA LOCAL",
1042
1042
  installedModels: "MODELOS INSTALADOS",
@@ -2035,37 +2035,40 @@ function sparkline(values, width = 24) {
2035
2035
  return slice.map((v) => glyphs[Math.min(glyphs.length - 1, Math.floor(v / max * (glyphs.length - 1)))]).join("").padStart(width, glyphs[0]);
2036
2036
  }
2037
2037
 
2038
+ // src/tui/width.ts
2039
+ import { useStdout } from "ink";
2040
+ function useCols() {
2041
+ const { stdout } = useStdout();
2042
+ const cols = stdout?.columns ?? 80;
2043
+ return Math.max(40, Math.min(cols - 2, 100));
2044
+ }
2045
+ function fit(text, width) {
2046
+ if (text.length <= width) return text;
2047
+ if (width <= 1) return "\u2026";
2048
+ return `${text.slice(0, width - 1)}\u2026`;
2049
+ }
2050
+
2038
2051
  // src/tui/views/Dashboard.tsx
2039
2052
  import { jsx, jsxs } from "react/jsx-runtime";
2040
2053
  function Dashboard({ session }) {
2054
+ const cols = useCols();
2041
2055
  const h = session.hardware;
2042
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2043
- /* @__PURE__ */ jsxs(Text, { children: [
2044
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: h.machineModel ?? t("unknownMachine") }),
2045
- /* @__PURE__ */ jsxs(Text, { children: [
2046
- " \xB7 ",
2047
- h.cpu.name ?? t("cpuNa")
2048
- ] }),
2049
- /* @__PURE__ */ jsxs(Text, { children: [
2050
- " \xB7 ",
2051
- h.cpu.physicalCores ?? "?",
2052
- "c"
2053
- ] }),
2054
- /* @__PURE__ */ jsxs(Text, { children: [
2055
- " ",
2056
- "\xB7 ",
2057
- formatBytes(h.memory.totalBytes, 0),
2058
- " ",
2059
- memoryLabel(h)
2060
- ] })
2061
- ] }),
2056
+ const line = fit(
2057
+ `${h.machineModel ?? t("unknownMachine")} \xB7 ${h.cpu.name ?? t("cpuNa")} \xB7 ${formatBytes(h.memory.totalBytes, 0)} ${memoryLabel(h)}`,
2058
+ cols
2059
+ );
2060
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: cols, children: [
2061
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: t("machine") }),
2062
+ /* @__PURE__ */ jsx(Text, { children: line }),
2062
2063
  /* @__PURE__ */ jsx(Text, { children: session.runtimes.map((r, i) => /* @__PURE__ */ jsxs(Text, { color: r.detected ? "green" : "gray", children: [
2063
- i ? " " : "",
2064
+ i ? " " : "",
2064
2065
  r.detected ? "\u2713" : "\u25CB",
2065
2066
  r.label
2066
2067
  ] }, r.id)) }),
2067
- session.rows.slice(0, 5).map((row) => /* @__PURE__ */ jsxs(Text, { children: [
2068
- /* @__PURE__ */ jsx(Text, { color: "green", children: row.local.name }),
2068
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: t("installedModels") }),
2069
+ session.rows.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: t("noModels") }),
2070
+ session.rows.slice(0, 6).map((row) => /* @__PURE__ */ jsxs(Text, { children: [
2071
+ /* @__PURE__ */ jsx(Text, { color: "green", children: fit(row.local.name, 18) }),
2069
2072
  /* @__PURE__ */ jsx(Text, { children: " " }),
2070
2073
  /* @__PURE__ */ jsx(Text, { color: gradeColor(row.compatibility?.grade), children: row.compatibility?.grade ?? "\u2014" }),
2071
2074
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -2073,16 +2076,17 @@ function Dashboard({ session }) {
2073
2076
  row.lastBenchmark?.benchmark.generationTokensPerSecond ? formatTokensPerSec(row.lastBenchmark.benchmark.generationTokensPerSecond) : t("notTested")
2074
2077
  ] })
2075
2078
  ] }, row.local.id)),
2079
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: t("recommended") }),
2076
2080
  session.recommendations.slice(0, 4).map((rec) => /* @__PURE__ */ jsxs(Text, { children: [
2077
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: rec.useCase }),
2081
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: fit(rec.useCase, 10) }),
2078
2082
  /* @__PURE__ */ jsxs(Text, { children: [
2079
2083
  " ",
2080
- rec.model.name,
2084
+ fit(rec.model.name, 22),
2081
2085
  " "
2082
2086
  ] }),
2083
2087
  /* @__PURE__ */ jsx(Text, { color: gradeColor(rec.grade), children: rec.grade })
2084
2088
  ] }, `${rec.useCase}-${rec.model.id}`)),
2085
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: t("setupCta") })
2089
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: fit(t("setupCta"), cols) })
2086
2090
  ] });
2087
2091
  }
2088
2092
 
@@ -2146,11 +2150,11 @@ function runtimesText(session) {
2146
2150
  function modelsText(session) {
2147
2151
  const lines = [bold(cyan(t("installedModels"))), dim("MODEL INSTALLED FIT EST. SPEED MEASURED")];
2148
2152
  for (const row of session.rows) {
2149
- const fit = row.compatibility?.grade ?? "\u2014";
2153
+ const fit2 = row.compatibility?.grade ?? "\u2014";
2150
2154
  const est = row.compatibility?.estimatedTokensPerSecond ? `~${formatNumber(row.compatibility.estimatedTokensPerSecond)} t/s` : "\u2014";
2151
2155
  const measured = row.lastBenchmark?.benchmark.generationTokensPerSecond ? formatTokensPerSec(row.lastBenchmark.benchmark.generationTokensPerSecond) : t("notTested");
2152
2156
  lines.push(
2153
- `${green(row.local.name.padEnd(22))} \u2713 ${gradeAnsi(fit).padEnd(9)} ${est.padEnd(14)} ${measured}`
2157
+ `${green(row.local.name.padEnd(22))} \u2713 ${gradeAnsi(fit2).padEnd(9)} ${est.padEnd(14)} ${measured}`
2154
2158
  );
2155
2159
  }
2156
2160
  lines.push("", t("compatible"));
@@ -2383,8 +2387,8 @@ function decideLaunch(session, id) {
2383
2387
  if (!candidates.length) {
2384
2388
  for (const model of session.catalog) {
2385
2389
  if (!useCaseOk(model.useCase, def.useCases)) continue;
2386
- const fit = localCompatibility(session.hardware, model);
2387
- if (!def.allowedGrades.includes(fit.grade)) continue;
2390
+ const fit2 = localCompatibility(session.hardware, model);
2391
+ if (!def.allowedGrades.includes(fit2.grade)) continue;
2388
2392
  const tag = resolveOllamaTag(model.id, model.name);
2389
2393
  if (!tag) continue;
2390
2394
  candidates.push({
@@ -2392,7 +2396,7 @@ function decideLaunch(session, id) {
2392
2396
  ollamaTag: tag,
2393
2397
  installed: false,
2394
2398
  origin: "estimated",
2395
- grade: fit.grade
2399
+ grade: fit2.grade
2396
2400
  });
2397
2401
  }
2398
2402
  }
@@ -2509,6 +2513,7 @@ var TOOLS = [
2509
2513
  { key: "3", id: "openclaw", label: "OpenClaw" }
2510
2514
  ];
2511
2515
  function RecommendView({ session }) {
2516
+ const cols = useCols();
2512
2517
  const { exit } = useApp();
2513
2518
  const [cursor, setCursor] = useState(0);
2514
2519
  const [log, setLog] = useState("");
@@ -2548,11 +2553,11 @@ function RecommendView({ session }) {
2548
2553
  }
2549
2554
  });
2550
2555
  const tag = rec ? resolveOllamaTag(rec.model.id, rec.model.name) : void 0;
2551
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
2552
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: "yellow", children: t("setupTitle") }),
2556
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", width: cols, children: [
2557
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: "yellow", children: fit(t("setupTitle"), cols) }),
2553
2558
  recs.map((item, i) => /* @__PURE__ */ jsxs4(Text4, { color: i === cursor ? "cyan" : void 0, children: [
2554
2559
  i === cursor ? "\u276F " : " ",
2555
- item.model.name,
2560
+ fit(item.model.name, 20),
2556
2561
  " ",
2557
2562
  /* @__PURE__ */ jsx4(Text4, { color: gradeColor(item.grade), children: item.grade }),
2558
2563
  /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
@@ -2568,12 +2573,8 @@ function RecommendView({ session }) {
2568
2573
  agent.detected ? "\u2713" : "\u25CB",
2569
2574
  agent.label
2570
2575
  ] }, agent.id)) }),
2571
- /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2572
- "Enter=pull ",
2573
- tag ?? "",
2574
- " \xB7 1/2/3=agent"
2575
- ] }),
2576
- log ? /* @__PURE__ */ jsx4(Text4, { color: "green", children: log }) : null
2576
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: fit(`Enter=pull ${tag ?? ""} 1/2/3=agent Esc=back`, cols) }),
2577
+ log ? /* @__PURE__ */ jsx4(Text4, { color: "green", children: fit(log, cols) }) : null
2577
2578
  ] });
2578
2579
  }
2579
2580
 
@@ -2896,13 +2897,13 @@ function planTasks(session, answers) {
2896
2897
  const catalogExtras = answers.scope === "all" ? session.catalog.filter((model) => !session.rows.some((row) => idsLikelyMatch(row.local.id, model.id))).map((model) => {
2897
2898
  const useCases = model.useCase ?? [];
2898
2899
  const kinds = answers.kinds.filter((kind) => kindMatches(kind, useCases));
2899
- const fit = localCompatibility(session.hardware, model);
2900
+ const fit2 = localCompatibility(session.hardware, model);
2900
2901
  return {
2901
2902
  modelId: model.id,
2902
2903
  modelName: model.name,
2903
2904
  installed: false,
2904
2905
  origin: "estimated",
2905
- grade: fit.grade,
2906
+ grade: fit2.grade,
2906
2907
  useCases,
2907
2908
  kinds
2908
2909
  };
@@ -3066,24 +3067,49 @@ function handleAppKey(screen, input, key) {
3066
3067
 
3067
3068
  // src/tui/Welcome.tsx
3068
3069
  import { Box as Box9, Text as Text9 } from "ink";
3069
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3070
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3070
3071
  function Chrome() {
3071
- return /* @__PURE__ */ jsxs8(Box9, { children: [
3072
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: "cyan", children: t("appTitle") }),
3073
- /* @__PURE__ */ jsxs8(Text9, { color: "magenta", children: [
3074
- " ",
3075
- t("byline"),
3076
- " "
3072
+ const cols = useCols();
3073
+ const wide = cols >= 72;
3074
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", width: cols, marginBottom: 1, children: [
3075
+ /* @__PURE__ */ jsxs8(Text9, { children: [
3076
+ /* @__PURE__ */ jsx9(Text9, { bold: true, color: "cyan", children: t("appTitle") }),
3077
+ /* @__PURE__ */ jsx9(Text9, { color: "gray", children: " \xB7 " }),
3078
+ /* @__PURE__ */ jsx9(Text9, { color: "magenta", children: t("byline") }),
3079
+ wide ? /* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
3080
+ " \xB7 ",
3081
+ fit(t("appSubtitle"), cols - 28)
3082
+ ] }) : null
3077
3083
  ] }),
3078
- /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "[S]" }),
3079
- /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[B]" }),
3080
- /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[M]" }),
3081
- /* @__PURE__ */ jsx9(Text9, { color: "magenta", children: "[R]" }),
3082
- /* @__PURE__ */ jsx9(Text9, { color: "blue", children: "[T]" }),
3083
- /* @__PURE__ */ jsx9(Text9, { children: "[H]" }),
3084
- /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[C]" }),
3085
- /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[L]" }),
3086
- /* @__PURE__ */ jsx9(Text9, { color: "red", children: "[Q]" })
3084
+ /* @__PURE__ */ jsx9(Text9, { children: wide ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
3085
+ /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "[S] Setup" }),
3086
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3087
+ /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[B] Bench" }),
3088
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3089
+ /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[M] Models" }),
3090
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3091
+ /* @__PURE__ */ jsx9(Text9, { color: "magenta", children: "[R] Rec" }),
3092
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3093
+ /* @__PURE__ */ jsx9(Text9, { color: "blue", children: "[T] Tasks" }),
3094
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3095
+ /* @__PURE__ */ jsx9(Text9, { children: "[H] HW" }),
3096
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3097
+ /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[C] Cmp" }),
3098
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3099
+ /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[L] Log" }),
3100
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
3101
+ /* @__PURE__ */ jsx9(Text9, { color: "red", children: "[Q] Quit" })
3102
+ ] }) : /* @__PURE__ */ jsxs8(Fragment2, { children: [
3103
+ /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "[S]" }),
3104
+ /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[B]" }),
3105
+ /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[M]" }),
3106
+ /* @__PURE__ */ jsx9(Text9, { color: "magenta", children: "[R]" }),
3107
+ /* @__PURE__ */ jsx9(Text9, { color: "blue", children: "[T]" }),
3108
+ /* @__PURE__ */ jsx9(Text9, { children: "[H]" }),
3109
+ /* @__PURE__ */ jsx9(Text9, { color: "green", children: "[C]" }),
3110
+ /* @__PURE__ */ jsx9(Text9, { color: "cyan", children: "[L]" }),
3111
+ /* @__PURE__ */ jsx9(Text9, { color: "red", children: "[Q]" })
3112
+ ] }) })
3087
3113
  ] });
3088
3114
  }
3089
3115
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pudu-ai",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Pudu-AI — local AI hardware & benchmark lab for the terminal",
5
5
  "keywords": [
6
6
  "ai",