offgrid-ai 0.3.13 → 0.3.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/package.json +1 -1
  2. package/src/cli.mjs +52 -71
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offgrid-ai",
3
- "version": "0.3.13",
3
+ "version": "0.3.14",
4
4
  "description": "Privacy-first CLI for running local LLMs — discover, configure, run, benchmark",
5
5
  "author": "Eeshan Srivastava (https://eeshans.com)",
6
6
  "type": "module",
package/src/cli.mjs CHANGED
@@ -202,21 +202,15 @@ export async function mainFlow() {
202
202
  }
203
203
 
204
204
  // Pick what to do
205
- while (true) {
206
- const action = await prompt.choice("What next?", [
207
- { value: "run", label: "Run a model", hint: "Start server and launch Pi" },
208
- ...(profiles.length > 0 ? [{ value: "manage", label: "Manage profiles", hint: "Sync, remove, or inspect" }] : []),
209
- { value: "benchmark", label: "Benchmark", hint: "Run a benchmark prompt" },
210
- ], "run");
211
-
212
- if (action === "run") return await pickAndRun(prompt, profiles, newModels, managedItems);
213
- if (action === "manage") {
214
- const result = await manageProfiles(prompt, profiles);
215
- if (result === "back") continue;
216
- return result;
217
- }
218
- if (action === "benchmark") return await benchmarkFlow(prompt, profiles);
219
- }
205
+ const action = await prompt.choice("What next?", [
206
+ { value: "run", label: "Run a model", hint: "Start server and launch Pi" },
207
+ ...(profiles.length > 0 ? [{ value: "manage", label: "Manage profiles", hint: "Sync, remove, or inspect" }] : []),
208
+ { value: "benchmark", label: "Benchmark", hint: "Run a benchmark prompt" },
209
+ ], "run");
210
+
211
+ if (action === "run") return await pickAndRun(prompt, profiles, newModels, managedItems);
212
+ if (action === "manage") return await manageProfiles(prompt, profiles);
213
+ if (action === "benchmark") return await benchmarkFlow(prompt, profiles);
220
214
  } finally {
221
215
  prompt.close();
222
216
  }
@@ -391,64 +385,51 @@ async function runProfile(profile, options = {}) {
391
385
  // ── Manage profiles ─────────────────────────────────────────────────────────
392
386
 
393
387
  async function manageProfiles(prompt, profiles) {
394
- while (true) {
395
- const choices = profiles.map((p) => ({
396
- value: p.id,
397
- label: p.label,
398
- hint: `${p.modelAlias} · ${p.baseUrl}`,
399
- }));
400
- choices.push({ value: "__back", label: " Back" });
401
-
402
- const selected = await prompt.choice("Which profile?", choices, choices[0].value);
403
- if (selected === "__back") return "back";
404
-
405
- const profile = await readProfile(selected);
406
- const backend = backendFor(profile.backend);
407
- const isManaged = backend.type === "managed-server";
408
- const piConfigured = await hasPiModel(profile);
409
-
410
- // Show profile details
388
+ const choices = profiles.map((p) => ({
389
+ value: p.id,
390
+ label: p.label,
391
+ hint: `${p.modelAlias} · ${p.baseUrl}`,
392
+ }));
393
+
394
+ const selected = await prompt.choice("Which profile?", choices, choices[0].value);
395
+ const profile = await readProfile(selected);
396
+ const backend = backendFor(profile.backend);
397
+ const isManaged = backend.type === "managed-server";
398
+ const piConfigured = await hasPiModel(profile);
399
+
400
+ // Show profile details
401
+ console.log("");
402
+ console.log(renderSection("Profile", renderRows([
403
+ ["ID", pc.cyan(profile.id)],
404
+ ["Label", pc.bold(profile.label)],
405
+ ["Backend", backend.label],
406
+ ["Endpoint", pc.green(profile.baseUrl)],
407
+ ...(!isManaged ? [
408
+ ["Model", profile.modelPath ?? "unknown"],
409
+ ["MMProj", profile.mmprojPath ?? "none"],
410
+ ["Memory", existsSync(profile.modelPath) ? formatBytes(statSync(profile.modelPath).size) : "unknown"],
411
+ ] : []),
412
+ ["Alias", pc.cyan(profile.modelAlias)],
413
+ ["Pi", piConfigured ? pc.green("configured") : pc.yellow("not synced")],
414
+ ])));
415
+
416
+ if (!isManaged && profile.commandArgv) {
411
417
  console.log("");
412
- console.log(renderSection("Profile", renderRows([
413
- ["ID", pc.cyan(profile.id)],
414
- ["Label", pc.bold(profile.label)],
415
- ["Backend", backend.label],
416
- ["Endpoint", pc.green(profile.baseUrl)],
417
- ...(!isManaged ? [
418
- ["Model", profile.modelPath ?? "unknown"],
419
- ["MMProj", profile.mmprojPath ?? "none"],
420
- ["Memory", existsSync(profile.modelPath) ? formatBytes(statSync(profile.modelPath).size) : "unknown"],
421
- ] : []),
422
- ["Alias", pc.cyan(profile.modelAlias)],
423
- ["Pi", piConfigured ? pc.green("configured") : pc.yellow("not synced")],
424
- ])));
425
-
426
- if (!isManaged && profile.commandArgv) {
427
- console.log("");
428
- console.log(pc.bold("llama-server command"));
429
- console.log(pc.dim(buildPrettyCommand(profile)));
430
- }
431
-
432
- const action = await prompt.choice("Action", [
433
- { value: "sync", label: piConfigured ? `${pc.green("✓")} Pi config synced` : "Sync Pi config", hint: piConfigured ? "Already in ~/.pi/agent/models.json" : "Update ~/.pi/agent/models.json" },
434
- { value: "run", label: "Run", hint: "Start server + Pi" },
435
- ...(isManaged ? [] : [{ value: "server", label: "Server only", hint: "Start server, no harness" }]),
436
- { value: "remove", label: "Remove", hint: "Delete profile + Pi config" },
437
- { value: "__back", label: "← Back", hint: "Choose another profile" },
438
- ], "sync");
439
-
440
- if (action === "__back") continue;
441
- if (action === "sync") {
442
- await syncPiConfig(profile);
443
- continue;
444
- }
445
- if (action === "run") return await runProfile(profile);
446
- if (action === "server") return await runProfile(profile, { with: "server" });
447
- if (action === "remove") {
448
- await removeProfileInteractive(profile.id);
449
- return;
450
- }
418
+ console.log(pc.bold("llama-server command"));
419
+ console.log(pc.dim(buildPrettyCommand(profile)));
451
420
  }
421
+
422
+ const action = await prompt.choice("Action", [
423
+ { value: "sync", label: piConfigured ? `${pc.green("✓")} Pi config synced` : "Sync Pi config", hint: piConfigured ? "Already in ~/.pi/agent/models.json" : "Update ~/.pi/agent/models.json" },
424
+ { value: "run", label: "Run", hint: "Start server + Pi" },
425
+ ...(isManaged ? [] : [{ value: "server", label: "Server only", hint: "Start server, no harness" }]),
426
+ { value: "remove", label: "Remove", hint: "Delete profile + Pi config" },
427
+ ], "sync");
428
+
429
+ if (action === "sync") return await syncPiConfig(profile);
430
+ if (action === "run") return await runProfile(profile);
431
+ if (action === "server") return await runProfile(profile, { with: "server" });
432
+ if (action === "remove") return await removeProfileInteractive(profile.id);
452
433
  }
453
434
 
454
435
  async function removeProfileInteractive(id) {