pudu-ai 0.2.15 → 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.
- package/dist/cli/index.js +309 -97
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,4 +1,189 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res, err) => function __init() {
|
|
5
|
+
if (err) throw err[0];
|
|
6
|
+
try {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
throw err = [e], e;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/shared/process.ts
|
|
18
|
+
import { execa } from "execa";
|
|
19
|
+
function installSignalHandlers() {
|
|
20
|
+
if (installed) return;
|
|
21
|
+
installed = true;
|
|
22
|
+
const stop = () => {
|
|
23
|
+
void killAll("SIGTERM");
|
|
24
|
+
};
|
|
25
|
+
process.once("SIGINT", stop);
|
|
26
|
+
process.once("SIGTERM", stop);
|
|
27
|
+
}
|
|
28
|
+
function spawnTracked(file, args2 = [], options = {}) {
|
|
29
|
+
installSignalHandlers();
|
|
30
|
+
const subprocess = execa(file, args2, {
|
|
31
|
+
reject: false,
|
|
32
|
+
timeout: options.timeout ?? 3e4,
|
|
33
|
+
...options
|
|
34
|
+
});
|
|
35
|
+
children.add(subprocess);
|
|
36
|
+
void subprocess.finally(() => {
|
|
37
|
+
children.delete(subprocess);
|
|
38
|
+
});
|
|
39
|
+
return subprocess;
|
|
40
|
+
}
|
|
41
|
+
function toText(value) {
|
|
42
|
+
if (typeof value === "string") return value;
|
|
43
|
+
if (value instanceof Uint8Array) return Buffer.from(value).toString("utf8");
|
|
44
|
+
if (Array.isArray(value)) return value.map(String).join("\n");
|
|
45
|
+
if (value == null) return "";
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
async function runCommand(file, args2 = [], options = {}) {
|
|
49
|
+
const result = await spawnTracked(file, args2, options);
|
|
50
|
+
return {
|
|
51
|
+
stdout: toText(result.stdout),
|
|
52
|
+
stderr: toText(result.stderr),
|
|
53
|
+
exitCode: result.exitCode,
|
|
54
|
+
timedOut: Boolean(result.timedOut)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function killAll(signal = "SIGTERM") {
|
|
58
|
+
for (const child of [...children]) {
|
|
59
|
+
child.kill(signal);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
var children, installed;
|
|
63
|
+
var init_process = __esm({
|
|
64
|
+
"src/shared/process.ts"() {
|
|
65
|
+
"use strict";
|
|
66
|
+
children = /* @__PURE__ */ new Set();
|
|
67
|
+
installed = false;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// src/shared/which.ts
|
|
72
|
+
import { access } from "node:fs/promises";
|
|
73
|
+
import { constants } from "node:fs";
|
|
74
|
+
import path2 from "node:path";
|
|
75
|
+
async function commandExists(name) {
|
|
76
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
77
|
+
try {
|
|
78
|
+
await access(name, constants.X_OK);
|
|
79
|
+
return name;
|
|
80
|
+
} catch {
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const pathEnv = process.env.PATH ?? "";
|
|
85
|
+
const parts = pathEnv.split(path2.delimiter);
|
|
86
|
+
for (const dir of parts) {
|
|
87
|
+
const candidate = path2.join(dir, name);
|
|
88
|
+
try {
|
|
89
|
+
await access(candidate, constants.X_OK);
|
|
90
|
+
return candidate;
|
|
91
|
+
} catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return void 0;
|
|
96
|
+
}
|
|
97
|
+
var init_which = __esm({
|
|
98
|
+
"src/shared/which.ts"() {
|
|
99
|
+
"use strict";
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// src/integrations/brew.ts
|
|
104
|
+
var brew_exports = {};
|
|
105
|
+
__export(brew_exports, {
|
|
106
|
+
brewInstall: () => brewInstall,
|
|
107
|
+
brewInstallCask: () => brewInstallCask,
|
|
108
|
+
dockerReady: () => dockerReady,
|
|
109
|
+
ensureBrew: () => ensureBrew,
|
|
110
|
+
resolveBrew: () => resolveBrew,
|
|
111
|
+
startDockerDesktop: () => startDockerDesktop,
|
|
112
|
+
waitForDocker: () => waitForDocker
|
|
113
|
+
});
|
|
114
|
+
async function resolveBrew() {
|
|
115
|
+
for (const bin of BREW_CANDIDATES) {
|
|
116
|
+
const found = await commandExists(bin);
|
|
117
|
+
if (found) return found;
|
|
118
|
+
}
|
|
119
|
+
return void 0;
|
|
120
|
+
}
|
|
121
|
+
async function dockerReady() {
|
|
122
|
+
const docker = await commandExists("docker");
|
|
123
|
+
if (!docker) return false;
|
|
124
|
+
const info = await runCommand("docker", ["info"], { timeout: 8e3 });
|
|
125
|
+
return info.exitCode === 0;
|
|
126
|
+
}
|
|
127
|
+
async function ensureBrew() {
|
|
128
|
+
const existing = await resolveBrew();
|
|
129
|
+
if (existing) return { ok: true, brew: existing, log: existing };
|
|
130
|
+
const install = await runCommand(
|
|
131
|
+
"/bin/bash",
|
|
132
|
+
["-c", 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'],
|
|
133
|
+
{ timeout: 15 * 6e4 }
|
|
134
|
+
);
|
|
135
|
+
const after = await resolveBrew();
|
|
136
|
+
if (after) return { ok: true, brew: after, log: after };
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
log: install.stderr || "Homebrew missing. Install: https://brew.sh"
|
|
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
|
+
}
|
|
152
|
+
async function brewInstallCask(name) {
|
|
153
|
+
const brew = await resolveBrew();
|
|
154
|
+
if (!brew) {
|
|
155
|
+
const ensured = await ensureBrew();
|
|
156
|
+
if (!ensured.ok || !ensured.brew) return { ok: false, log: ensured.log };
|
|
157
|
+
const result2 = await runCommand(ensured.brew, ["install", "--cask", name], { timeout: 15 * 6e4 });
|
|
158
|
+
return { ok: result2.exitCode === 0, log: result2.stderr || result2.stdout };
|
|
159
|
+
}
|
|
160
|
+
const result = await runCommand(brew, ["install", "--cask", name], { timeout: 15 * 6e4 });
|
|
161
|
+
if (result.exitCode === 0) return { ok: true, log: result.stdout };
|
|
162
|
+
const formula = await runCommand(brew, ["install", name], { timeout: 15 * 6e4 });
|
|
163
|
+
return { ok: formula.exitCode === 0, log: formula.stderr || formula.stdout };
|
|
164
|
+
}
|
|
165
|
+
async function startDockerDesktop() {
|
|
166
|
+
if (process.platform === "darwin") {
|
|
167
|
+
await runCommand("open", ["-a", "Docker"], { timeout: 15e3 });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function waitForDocker(ms = 9e4) {
|
|
171
|
+
const start = Date.now();
|
|
172
|
+
while (Date.now() - start < ms) {
|
|
173
|
+
if (await dockerReady()) return true;
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 2500));
|
|
175
|
+
}
|
|
176
|
+
return dockerReady();
|
|
177
|
+
}
|
|
178
|
+
var BREW_CANDIDATES;
|
|
179
|
+
var init_brew = __esm({
|
|
180
|
+
"src/integrations/brew.ts"() {
|
|
181
|
+
"use strict";
|
|
182
|
+
init_which();
|
|
183
|
+
init_process();
|
|
184
|
+
BREW_CANDIDATES = ["/opt/homebrew/bin/brew", "/usr/local/bin/brew", "brew"];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
2
187
|
|
|
3
188
|
// src/cli/parse-args.ts
|
|
4
189
|
function parseArgs(argv) {
|
|
@@ -118,56 +303,9 @@ async function addModelPath(dir) {
|
|
|
118
303
|
import os5 from "node:os";
|
|
119
304
|
|
|
120
305
|
// src/platform/macos/hardware.ts
|
|
306
|
+
init_process();
|
|
121
307
|
import os2 from "node:os";
|
|
122
308
|
|
|
123
|
-
// src/shared/process.ts
|
|
124
|
-
import { execa } from "execa";
|
|
125
|
-
var children = /* @__PURE__ */ new Set();
|
|
126
|
-
var installed = false;
|
|
127
|
-
function installSignalHandlers() {
|
|
128
|
-
if (installed) return;
|
|
129
|
-
installed = true;
|
|
130
|
-
const stop = () => {
|
|
131
|
-
void killAll("SIGTERM");
|
|
132
|
-
};
|
|
133
|
-
process.once("SIGINT", stop);
|
|
134
|
-
process.once("SIGTERM", stop);
|
|
135
|
-
}
|
|
136
|
-
function spawnTracked(file, args2 = [], options = {}) {
|
|
137
|
-
installSignalHandlers();
|
|
138
|
-
const subprocess = execa(file, args2, {
|
|
139
|
-
reject: false,
|
|
140
|
-
timeout: options.timeout ?? 3e4,
|
|
141
|
-
...options
|
|
142
|
-
});
|
|
143
|
-
children.add(subprocess);
|
|
144
|
-
void subprocess.finally(() => {
|
|
145
|
-
children.delete(subprocess);
|
|
146
|
-
});
|
|
147
|
-
return subprocess;
|
|
148
|
-
}
|
|
149
|
-
function toText(value) {
|
|
150
|
-
if (typeof value === "string") return value;
|
|
151
|
-
if (value instanceof Uint8Array) return Buffer.from(value).toString("utf8");
|
|
152
|
-
if (Array.isArray(value)) return value.map(String).join("\n");
|
|
153
|
-
if (value == null) return "";
|
|
154
|
-
return String(value);
|
|
155
|
-
}
|
|
156
|
-
async function runCommand(file, args2 = [], options = {}) {
|
|
157
|
-
const result = await spawnTracked(file, args2, options);
|
|
158
|
-
return {
|
|
159
|
-
stdout: toText(result.stdout),
|
|
160
|
-
stderr: toText(result.stderr),
|
|
161
|
-
exitCode: result.exitCode,
|
|
162
|
-
timedOut: Boolean(result.timedOut)
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
async function killAll(signal = "SIGTERM") {
|
|
166
|
-
for (const child of [...children]) {
|
|
167
|
-
child.kill(signal);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
309
|
// src/shared/bytes.ts
|
|
172
310
|
var GiB = 1024 ** 3;
|
|
173
311
|
var MiB = 1024 ** 2;
|
|
@@ -377,32 +515,9 @@ async function detectHardware() {
|
|
|
377
515
|
import os7 from "node:os";
|
|
378
516
|
import path5 from "node:path";
|
|
379
517
|
|
|
380
|
-
// src/
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
import path2 from "node:path";
|
|
384
|
-
async function commandExists(name) {
|
|
385
|
-
if (name.includes("/") || name.includes("\\")) {
|
|
386
|
-
try {
|
|
387
|
-
await access(name, constants.X_OK);
|
|
388
|
-
return name;
|
|
389
|
-
} catch {
|
|
390
|
-
return void 0;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
const pathEnv = process.env.PATH ?? "";
|
|
394
|
-
const parts = pathEnv.split(path2.delimiter);
|
|
395
|
-
for (const dir of parts) {
|
|
396
|
-
const candidate = path2.join(dir, name);
|
|
397
|
-
try {
|
|
398
|
-
await access(candidate, constants.X_OK);
|
|
399
|
-
return candidate;
|
|
400
|
-
} catch {
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return void 0;
|
|
405
|
-
}
|
|
518
|
+
// src/adapters/ollama/index.ts
|
|
519
|
+
init_process();
|
|
520
|
+
init_which();
|
|
406
521
|
|
|
407
522
|
// src/adapters/ollama/parse.ts
|
|
408
523
|
function parseOllamaList(output) {
|
|
@@ -485,6 +600,7 @@ import path4 from "node:path";
|
|
|
485
600
|
import { access as access2 } from "node:fs/promises";
|
|
486
601
|
|
|
487
602
|
// src/adapters/llamacpp/index.ts
|
|
603
|
+
init_which();
|
|
488
604
|
import { readdir, stat } from "node:fs/promises";
|
|
489
605
|
import path3 from "node:path";
|
|
490
606
|
var BINARIES = ["llama-bench", "llama-cli", "llama-server"];
|
|
@@ -623,6 +739,7 @@ async function discoverLocalModels() {
|
|
|
623
739
|
}
|
|
624
740
|
|
|
625
741
|
// src/adapters/mlx/index.ts
|
|
742
|
+
init_which();
|
|
626
743
|
var mlxAdapter = {
|
|
627
744
|
id: "mlx",
|
|
628
745
|
label: "MLX",
|
|
@@ -644,6 +761,7 @@ var mlxAdapter = {
|
|
|
644
761
|
};
|
|
645
762
|
|
|
646
763
|
// src/runtimes/registry.ts
|
|
764
|
+
init_which();
|
|
647
765
|
var runtimes = [ollamaAdapter, llamaCppAdapter, lmStudioAdapter, mlxAdapter];
|
|
648
766
|
async function detectRuntimes() {
|
|
649
767
|
const llamaBench = Boolean(await commandExists("llama-bench"));
|
|
@@ -849,7 +967,10 @@ var en = {
|
|
|
849
967
|
dockerHint: "press 4 to run ollama/ollama in Docker",
|
|
850
968
|
dockerStarting: "Starting ollama/ollama container\u2026",
|
|
851
969
|
dockerRunOk: "Docker Ollama is up on port 11434 (name: pudu-ollama).",
|
|
852
|
-
dockerRunFail: "
|
|
970
|
+
dockerRunFail: "Docker daemon is not running. Open Docker Desktop, wait until it is idle, press 4 again.",
|
|
971
|
+
dockerBrewInstall: "Installing Docker with Homebrew (brew install --cask docker)\u2026",
|
|
972
|
+
dockerDesktopWait: "Starting Docker Desktop and waiting for the daemon\u2026",
|
|
973
|
+
brewInstalling: "Homebrew: installing {pkg}\u2026",
|
|
853
974
|
aboutHistory: "Shows local benchmark files in ~/.pudu-ai/benchmarks. Use it to replay what this machine actually did.",
|
|
854
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.",
|
|
855
976
|
aboutReport: "Writes the latest measured run as Markdown. Use it to paste results into GitHub or notes.",
|
|
@@ -1043,7 +1164,10 @@ var es = {
|
|
|
1043
1164
|
dockerHint: "pulsa 4 para correr ollama/ollama en Docker",
|
|
1044
1165
|
dockerStarting: "Arrancando contenedor ollama/ollama\u2026",
|
|
1045
1166
|
dockerRunOk: "Ollama en Docker est\xE1 en el puerto 11434 (nombre: pudu-ollama).",
|
|
1046
|
-
dockerRunFail: "
|
|
1167
|
+
dockerRunFail: "El daemon de Docker no corre. Abre Docker Desktop, espera a que est\xE9 listo y pulsa 4 otra vez.",
|
|
1168
|
+
dockerBrewInstall: "Instalando Docker con Homebrew (brew install --cask docker)\u2026",
|
|
1169
|
+
dockerDesktopWait: "Arrancando Docker Desktop y esperando al daemon\u2026",
|
|
1170
|
+
brewInstalling: "Homebrew: instalando {pkg}\u2026",
|
|
1047
1171
|
aboutHistory: "Muestra los JSON locales en ~/.pudu-ai/benchmarks. Sirve para ver qu\xE9 hizo realmente esta m\xE1quina.",
|
|
1048
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.",
|
|
1049
1173
|
aboutReport: "Exporta la \xFAltima corrida medida en Markdown. Sirve para pegar resultados en GitHub o notas.",
|
|
@@ -1462,7 +1586,11 @@ async function listBenchmarks() {
|
|
|
1462
1586
|
return records;
|
|
1463
1587
|
}
|
|
1464
1588
|
|
|
1589
|
+
// src/session/load.ts
|
|
1590
|
+
init_which();
|
|
1591
|
+
|
|
1465
1592
|
// src/integrations/agents.ts
|
|
1593
|
+
init_which();
|
|
1466
1594
|
var AGENTS = [
|
|
1467
1595
|
{
|
|
1468
1596
|
id: "opencode",
|
|
@@ -1531,7 +1659,12 @@ async function loadSession(options) {
|
|
|
1531
1659
|
};
|
|
1532
1660
|
}
|
|
1533
1661
|
|
|
1662
|
+
// src/benchmark/engine.ts
|
|
1663
|
+
init_process();
|
|
1664
|
+
init_which();
|
|
1665
|
+
|
|
1534
1666
|
// src/telemetry/macos.ts
|
|
1667
|
+
init_process();
|
|
1535
1668
|
import os9 from "node:os";
|
|
1536
1669
|
|
|
1537
1670
|
// src/telemetry/fallback.ts
|
|
@@ -2017,6 +2150,9 @@ function resourceFields(resources) {
|
|
|
2017
2150
|
};
|
|
2018
2151
|
}
|
|
2019
2152
|
|
|
2153
|
+
// src/cli/run.ts
|
|
2154
|
+
init_process();
|
|
2155
|
+
|
|
2020
2156
|
// src/shared/logger.ts
|
|
2021
2157
|
var level = "info";
|
|
2022
2158
|
function setLogLevel(next) {
|
|
@@ -2572,6 +2708,7 @@ function parseIntegration(raw) {
|
|
|
2572
2708
|
}
|
|
2573
2709
|
|
|
2574
2710
|
// src/integrations/execute.ts
|
|
2711
|
+
init_process();
|
|
2575
2712
|
async function executeLaunch(decision) {
|
|
2576
2713
|
if (!decision.eligible || !decision.ollamaTag) {
|
|
2577
2714
|
return { ok: false, log: t("launchBlocked") };
|
|
@@ -2601,7 +2738,35 @@ ${launched.stderr || launched.stdout || t("launchExecFail")}`
|
|
|
2601
2738
|
return { ok: true, log: `${lines.join("\n")}
|
|
2602
2739
|
${launched.stdout}`.trim() };
|
|
2603
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
|
+
}
|
|
2604
2752
|
async function executeDockerOllama() {
|
|
2753
|
+
const { brewInstallCask: brewInstallCask2, dockerReady: dockerReady2, startDockerDesktop: startDockerDesktop2, waitForDocker: waitForDocker2 } = await Promise.resolve().then(() => (init_brew(), brew_exports));
|
|
2754
|
+
const notes = [];
|
|
2755
|
+
if (!await dockerReady2()) {
|
|
2756
|
+
notes.push(t("dockerBrewInstall"));
|
|
2757
|
+
const installed2 = await brewInstallCask2("docker");
|
|
2758
|
+
if (!installed2.ok) {
|
|
2759
|
+
return { ok: false, log: `${t("reqDocker")}
|
|
2760
|
+
${installed2.log}` };
|
|
2761
|
+
}
|
|
2762
|
+
notes.push(t("dockerDesktopWait"));
|
|
2763
|
+
await startDockerDesktop2();
|
|
2764
|
+
const up = await waitForDocker2();
|
|
2765
|
+
if (!up) return { ok: false, log: `${notes.join("\n")}
|
|
2766
|
+
${t("dockerRunFail")}` };
|
|
2767
|
+
}
|
|
2768
|
+
const start = await runCommand("docker", ["start", "pudu-ollama"], { timeout: 3e4 });
|
|
2769
|
+
if (start.exitCode === 0) return { ok: true, log: t("dockerRunOk") };
|
|
2605
2770
|
const args2 = DOCKER_OLLAMA.split(" ").slice(1);
|
|
2606
2771
|
const result = await runCommand("docker", args2, { timeout: 10 * 6e4 });
|
|
2607
2772
|
if (result.exitCode !== 0) {
|
|
@@ -2611,6 +2776,7 @@ async function executeDockerOllama() {
|
|
|
2611
2776
|
}
|
|
2612
2777
|
|
|
2613
2778
|
// src/integrations/pull.ts
|
|
2779
|
+
init_process();
|
|
2614
2780
|
var INSTALLABLE = ["S", "A", "B"];
|
|
2615
2781
|
function canInstallGrade(grade) {
|
|
2616
2782
|
return Boolean(grade && INSTALLABLE.includes(grade));
|
|
@@ -2659,11 +2825,6 @@ function SetupView({ session }) {
|
|
|
2659
2825
|
});
|
|
2660
2826
|
}
|
|
2661
2827
|
if (input === "4") {
|
|
2662
|
-
const docker = session.runtimes.find((r) => r.id === "docker")?.detected;
|
|
2663
|
-
if (!docker) {
|
|
2664
|
-
setLog(t("reqDocker"));
|
|
2665
|
-
return;
|
|
2666
|
-
}
|
|
2667
2828
|
setBusy(true);
|
|
2668
2829
|
setLog(t("dockerStarting"));
|
|
2669
2830
|
void executeDockerOllama().then((result) => {
|
|
@@ -2672,20 +2833,63 @@ function SetupView({ session }) {
|
|
|
2672
2833
|
});
|
|
2673
2834
|
return;
|
|
2674
2835
|
}
|
|
2675
|
-
|
|
2676
|
-
if (tool && rec) {
|
|
2677
|
-
const decision = decideLaunch(session, tool);
|
|
2678
|
-
if (!decision.eligible) {
|
|
2679
|
-
setLog(decision.reasons.join(" "));
|
|
2680
|
-
return;
|
|
2681
|
-
}
|
|
2836
|
+
if (input === "5") {
|
|
2682
2837
|
setBusy(true);
|
|
2683
|
-
setLog(t("
|
|
2684
|
-
void
|
|
2838
|
+
setLog(t("brewInstalling", { pkg: "ollama" }));
|
|
2839
|
+
void installWithBrew("ollama").then((result) => {
|
|
2685
2840
|
setLog(result.log);
|
|
2686
2841
|
setBusy(false);
|
|
2687
|
-
if (result.ok) exit();
|
|
2688
2842
|
});
|
|
2843
|
+
return;
|
|
2844
|
+
}
|
|
2845
|
+
if (input === "6") {
|
|
2846
|
+
setBusy(true);
|
|
2847
|
+
setLog(t("brewInstalling", { pkg: "lm-studio" }));
|
|
2848
|
+
void installWithBrew("lmstudio").then((result) => {
|
|
2849
|
+
setLog(result.log);
|
|
2850
|
+
setBusy(false);
|
|
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
|
+
}
|
|
2689
2893
|
}
|
|
2690
2894
|
});
|
|
2691
2895
|
const tag = rec ? resolveOllamaTag(rec.model.id, rec.model.name) : void 0;
|
|
@@ -2716,11 +2920,19 @@ function SetupView({ session }) {
|
|
|
2716
2920
|
" Docker",
|
|
2717
2921
|
session.runtimes.find((r) => r.id === "docker")?.detected ? ` \u2192 ${t("dockerHint")}` : ` \u2192 ${t("reqDocker")}`
|
|
2718
2922
|
] }),
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
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 }),
|
|
2724
2936
|
log ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: fit(log, cols) }) : null
|
|
2725
2937
|
] });
|
|
2726
2938
|
}
|
|
@@ -3209,7 +3421,7 @@ function handleAppKey(screen, input, key) {
|
|
|
3209
3421
|
if (letter === "q") return { type: "quit" };
|
|
3210
3422
|
if (key.escape) return screen === "home" ? { type: "quit" } : { type: "home" };
|
|
3211
3423
|
if (screen === "setup") {
|
|
3212
|
-
if (
|
|
3424
|
+
if ("i123456".includes(letter)) return { type: "ignore" };
|
|
3213
3425
|
}
|
|
3214
3426
|
const nav = globalNav(letter);
|
|
3215
3427
|
if (nav) return nav;
|