pudu-ai 0.2.16 → 0.2.17

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 +91 -16
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -103,6 +103,7 @@ var init_which = __esm({
103
103
  // src/integrations/brew.ts
104
104
  var brew_exports = {};
105
105
  __export(brew_exports, {
106
+ brewInstall: () => brewInstall,
106
107
  brewInstallCask: () => brewInstallCask,
107
108
  dockerReady: () => dockerReady,
108
109
  ensureBrew: () => ensureBrew,
@@ -138,6 +139,16 @@ async function ensureBrew() {
138
139
  log: install.stderr || "Homebrew missing. Install: https://brew.sh"
139
140
  };
140
141
  }
142
+ async function brewInstall(args2) {
143
+ const ensured = await ensureBrew();
144
+ if (!ensured.ok || !ensured.brew) return { ok: false, log: ensured.log };
145
+ const result = await runCommand(ensured.brew, args2, { timeout: 15 * 6e4 });
146
+ return {
147
+ ok: result.exitCode === 0,
148
+ log: `${ensured.brew} ${args2.join(" ")}
149
+ ${result.stdout || result.stderr}`
150
+ };
151
+ }
141
152
  async function brewInstallCask(name) {
142
153
  const brew = await resolveBrew();
143
154
  if (!brew) {
@@ -959,6 +970,7 @@ var en = {
959
970
  dockerRunFail: "Docker daemon is not running. Open Docker Desktop, wait until it is idle, press 4 again.",
960
971
  dockerBrewInstall: "Installing Docker with Homebrew (brew install --cask docker)\u2026",
961
972
  dockerDesktopWait: "Starting Docker Desktop and waiting for the daemon\u2026",
973
+ brewInstalling: "Homebrew: installing {pkg}\u2026",
962
974
  aboutHistory: "Shows local benchmark files in ~/.pudu-ai/benchmarks. Use it to replay what this machine actually did.",
963
975
  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.",
964
976
  aboutReport: "Writes the latest measured run as Markdown. Use it to paste results into GitHub or notes.",
@@ -1155,6 +1167,7 @@ var es = {
1155
1167
  dockerRunFail: "El daemon de Docker no corre. Abre Docker Desktop, espera a que est\xE9 listo y pulsa 4 otra vez.",
1156
1168
  dockerBrewInstall: "Instalando Docker con Homebrew (brew install --cask docker)\u2026",
1157
1169
  dockerDesktopWait: "Arrancando Docker Desktop y esperando al daemon\u2026",
1170
+ brewInstalling: "Homebrew: instalando {pkg}\u2026",
1158
1171
  aboutHistory: "Muestra los JSON locales en ~/.pudu-ai/benchmarks. Sirve para ver qu\xE9 hizo realmente esta m\xE1quina.",
1159
1172
  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.",
1160
1173
  aboutReport: "Exporta la \xFAltima corrida medida en Markdown. Sirve para pegar resultados en GitHub o notas.",
@@ -2725,6 +2738,17 @@ ${launched.stderr || launched.stdout || t("launchExecFail")}`
2725
2738
  return { ok: true, log: `${lines.join("\n")}
2726
2739
  ${launched.stdout}`.trim() };
2727
2740
  }
2741
+ async function installWithBrew(kind) {
2742
+ const { brewInstall: brewInstall2 } = await Promise.resolve().then(() => (init_brew(), brew_exports));
2743
+ if (kind === "ollama") {
2744
+ const result = await brewInstall2(["install", "ollama"]);
2745
+ if (result.ok) {
2746
+ void runCommand("ollama", ["serve"], { timeout: 4e3 });
2747
+ }
2748
+ return result;
2749
+ }
2750
+ return brewInstall2(["install", "--cask", "lm-studio"]);
2751
+ }
2728
2752
  async function executeDockerOllama() {
2729
2753
  const { brewInstallCask: brewInstallCask2, dockerReady: dockerReady2, startDockerDesktop: startDockerDesktop2, waitForDocker: waitForDocker2 } = await Promise.resolve().then(() => (init_brew(), brew_exports));
2730
2754
  const notes = [];
@@ -2809,20 +2833,63 @@ function SetupView({ session }) {
2809
2833
  });
2810
2834
  return;
2811
2835
  }
2812
- const tool = TOOLS.find((item) => item.key === input)?.id;
2813
- if (tool && rec) {
2814
- const decision = decideLaunch(session, tool);
2815
- if (!decision.eligible) {
2816
- setLog(decision.reasons.join(" "));
2817
- return;
2818
- }
2836
+ if (input === "5") {
2837
+ setBusy(true);
2838
+ setLog(t("brewInstalling", { pkg: "ollama" }));
2839
+ void installWithBrew("ollama").then((result) => {
2840
+ setLog(result.log);
2841
+ setBusy(false);
2842
+ });
2843
+ return;
2844
+ }
2845
+ if (input === "6") {
2819
2846
  setBusy(true);
2820
- setLog(t("linkingTool", { tool, model: rec.model.id }));
2821
- void executeLaunch({ ...decision, ollamaTag: decision.ollamaTag, modelId: rec.model.id }).then((result) => {
2847
+ setLog(t("brewInstalling", { pkg: "lm-studio" }));
2848
+ void installWithBrew("lmstudio").then((result) => {
2822
2849
  setLog(result.log);
2823
2850
  setBusy(false);
2824
- if (result.ok) exit();
2825
2851
  });
2852
+ return;
2853
+ }
2854
+ const tool = TOOLS.find((item) => item.key === input)?.id;
2855
+ if (tool) {
2856
+ const ollama = session.runtimes.find((r) => r.id === "ollama")?.detected;
2857
+ const agent = session.agents.find((a) => a.id === tool);
2858
+ if (!ollama) {
2859
+ setBusy(true);
2860
+ setLog(t("brewInstalling", { pkg: "ollama" }));
2861
+ void installWithBrew("ollama").then((brewed) => {
2862
+ setLog(brewed.log);
2863
+ setBusy(false);
2864
+ });
2865
+ return;
2866
+ }
2867
+ if (agent && !agent.detected) {
2868
+ setBusy(true);
2869
+ setLog(t("linkingTool", { tool, model: rec?.model.id ?? "" }));
2870
+ const decision = decideLaunch(session, tool);
2871
+ void executeLaunch(
2872
+ decision.eligible ? decision : { ...decision, eligible: true, ollamaTag: decision.ollamaTag ?? "qwen3:8b", installed: false }
2873
+ ).then((result) => {
2874
+ setLog(result.log);
2875
+ setBusy(false);
2876
+ });
2877
+ return;
2878
+ }
2879
+ if (rec) {
2880
+ const decision = decideLaunch(session, tool);
2881
+ if (!decision.eligible) {
2882
+ setLog(decision.reasons.join(" "));
2883
+ return;
2884
+ }
2885
+ setBusy(true);
2886
+ setLog(t("linkingTool", { tool, model: rec.model.id }));
2887
+ void executeLaunch(decision).then((result) => {
2888
+ setLog(result.log);
2889
+ setBusy(false);
2890
+ if (result.ok) exit();
2891
+ });
2892
+ }
2826
2893
  }
2827
2894
  });
2828
2895
  const tag = rec ? resolveOllamaTag(rec.model.id, rec.model.name) : void 0;
@@ -2853,11 +2920,19 @@ function SetupView({ session }) {
2853
2920
  " Docker",
2854
2921
  session.runtimes.find((r) => r.id === "docker")?.detected ? ` \u2192 ${t("dockerHint")}` : ` \u2192 ${t("reqDocker")}`
2855
2922
  ] }),
2856
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: fit(
2857
- `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")}`,
2858
- cols
2859
- ) }),
2860
- /* @__PURE__ */ jsx6(Typewriter, { text: fit(`Enter=pull ${tag ?? ""} 1/2/3=agent Esc=back`, cols), ms: 14, dimColor: true }),
2923
+ /* @__PURE__ */ jsxs6(Text6, { color: session.runtimes.find((r) => r.id === "ollama")?.detected ? "green" : "yellow", children: [
2924
+ "[5] ",
2925
+ session.runtimes.find((r) => r.id === "ollama")?.detected ? "\u2713" : "\u25CB",
2926
+ " Ollama",
2927
+ session.runtimes.find((r) => r.id === "ollama")?.detected ? "" : " \u2192 brew install ollama"
2928
+ ] }),
2929
+ /* @__PURE__ */ jsxs6(Text6, { color: session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "green" : "yellow", children: [
2930
+ "[6] ",
2931
+ session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "\u2713" : "\u25CB",
2932
+ " LM Studio",
2933
+ session.runtimes.find((r) => r.id === "lmstudio")?.detected ? "" : " \u2192 brew install --cask lm-studio"
2934
+ ] }),
2935
+ /* @__PURE__ */ jsx6(Typewriter, { text: fit(`Enter=pull ${tag ?? ""} 1-3 agent 4 docker 5 ollama 6 LM Studio`, cols), ms: 14, dimColor: true }),
2861
2936
  log ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: fit(log, cols) }) : null
2862
2937
  ] });
2863
2938
  }
@@ -3346,7 +3421,7 @@ function handleAppKey(screen, input, key) {
3346
3421
  if (letter === "q") return { type: "quit" };
3347
3422
  if (key.escape) return screen === "home" ? { type: "quit" } : { type: "home" };
3348
3423
  if (screen === "setup") {
3349
- if (letter === "i" || letter === "1" || letter === "2" || letter === "3" || letter === "4") return { type: "ignore" };
3424
+ if ("i123456".includes(letter)) return { type: "ignore" };
3350
3425
  }
3351
3426
  const nav = globalNav(letter);
3352
3427
  if (nav) return nav;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pudu-ai",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Pudu-AI — local AI hardware & benchmark lab for the terminal",
5
5
  "keywords": [
6
6
  "ai",