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.
- package/dist/cli/index.js +86 -60
- 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]
|
|
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]
|
|
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
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
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
|
-
|
|
2068
|
-
|
|
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
|
|
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(
|
|
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
|
|
2387
|
-
if (!def.allowedGrades.includes(
|
|
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:
|
|
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__ */
|
|
2572
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
t("
|
|
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, {
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
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
|
|