offgrid-ai 0.2.8 → 0.2.9

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 +51 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offgrid-ai",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
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
@@ -60,14 +60,40 @@ export async function mainFlow() {
60
60
  // Fall through — they can still use managed backends
61
61
  }
62
62
 
63
- // 4. No models found at all (but backends exist)
63
+ // 4. No models found at all (but backends may exist)
64
64
  if (!hasAnyModels && profiles.length === 0) {
65
65
  if (!process.stdin.isTTY) {
66
- throw new Error("No models found. Download one in LM Studio or start Ollama, then run offgrid-ai.");
66
+ throw new Error("No models found. Download a model, then run offgrid-ai.");
67
67
  }
68
68
  console.log(pc.yellow("No models found."));
69
- console.log(pc.dim("Download a model in LM Studio (https://lmstudio.ai), start Ollama, or install oMLX."));
70
- console.log(pc.dim("Then run offgrid-ai again."));
69
+ console.log(pc.dim("You need to download a model to use offgrid-ai.\n"));
70
+ // Detect which backends are installed
71
+ const ollamaInstalled = await hasOllamaInstalled();
72
+ const omlxInstalled = await hasOmlxInstalled();
73
+ const lmStudioInstalled = existsSync("/Applications/LM Studio.app");
74
+ const hasBackends = llamaBinary || ollamaInstalled || omlxInstalled || lmStudioInstalled;
75
+ if (hasBackends) {
76
+ console.log(pc.bold("Backend status:"));
77
+ console.log(` ${lmStudioInstalled ? pc.green("✓") : pc.red("✗")} LM Studio ${lmStudioInstalled ? "— installed" : "— not installed"}`);
78
+ console.log(` ${ollamaInstalled ? pc.green("✓") : pc.red("✗")} Ollama ${ollamaInstalled ? "— installed" : "— not installed"}`);
79
+ console.log(` ${omlxInstalled ? pc.green("✓") : pc.red("✗")} oMLX ${omlxInstalled ? "— installed" : "— not installed"}`);
80
+ console.log(` ${llamaBinary ? pc.green("✓") : pc.red("✗")} llama-server ${llamaBinary ? "— installed" : "— not installed"}`);
81
+ console.log();
82
+ const model = recommendedModel();
83
+ console.log(pc.bold("Next step — download a model:"));
84
+ if (lmStudioInstalled) {
85
+ console.log(" Open LM Studio → browse models → download");
86
+ console.log(pc.dim(` Recommended: ${model.label}`));
87
+ }
88
+ if (ollamaInstalled) {
89
+ console.log(pc.bold(` ollama pull ${model.ollama}`));
90
+ }
91
+ if (omlxInstalled) {
92
+ console.log(pc.bold(" omlx start"));
93
+ }
94
+ } else {
95
+ console.log(pc.dim("Run offgrid-ai to install a backend and download a model."));
96
+ }
71
97
  return;
72
98
  }
73
99
 
@@ -629,9 +655,8 @@ async function onboardFlow() {
629
655
  try {
630
656
  await run("brew", ["install", "--cask", "lm-studio"], "LM Studio");
631
657
  console.log(pc.green("✓ LM Studio installed"));
632
- console.log(pc.yellow("\nOpen LM Studio, set up the app, and download a model."));
658
+ console.log(pc.yellow("\nOpen LM Studio and download a model to get started."));
633
659
  console.log(pc.dim(`Recommended for your machine: ${model.label}`));
634
- console.log(pc.bold(` lms get ${model.lms}`));
635
660
  console.log(pc.dim("Then run offgrid-ai again to pick and run a model."));
636
661
  } catch {
637
662
  console.log(pc.red("✗ LM Studio installation failed."));
@@ -693,18 +718,7 @@ async function onboardFlow() {
693
718
  }
694
719
  if (installed.length > 0) {
695
720
  console.log(pc.green(`\n✓ Installed: ${installed.join(", ")}`));
696
- console.log(pc.yellow("\nDownload a model to get started:"));
697
721
  console.log(pc.dim(`Recommended for your machine (${(totalmem() / (1024 ** 3)).toFixed(0)}GB RAM): ${model.label}`));
698
- if (installed.includes("LM Studio")) {
699
- console.log(pc.bold(` LM Studio → lms get ${model.lms}`));
700
- }
701
- if (installed.includes("Ollama")) {
702
- console.log(pc.bold(` Ollama → ollama pull ${model.ollama}`));
703
- }
704
- if (installed.includes("oMLX")) {
705
- console.log(pc.bold(" oMLX → omlx start"));
706
- }
707
- console.log(pc.dim("Then run offgrid-ai again to pick and run a model."));
708
722
  }
709
723
  } else {
710
724
  console.log(pc.dim("Run offgrid-ai again when you've set up a model backend."));
@@ -814,6 +828,26 @@ async function removeSelf() {
814
828
  }
815
829
  }
816
830
 
831
+ // ── Backend install detection (for status display) ────────────────────────
832
+
833
+ async function hasOllamaInstalled() {
834
+ try {
835
+ const { promisify } = await import("node:util");
836
+ const { execFile } = await import("node:child_process");
837
+ await promisify(execFile)("which", ["ollama"]);
838
+ return true;
839
+ } catch { return false; }
840
+ }
841
+
842
+ async function hasOmlxInstalled() {
843
+ try {
844
+ const { promisify } = await import("node:util");
845
+ const { execFile } = await import("node:child_process");
846
+ await promisify(execFile)("which", ["omlx"]);
847
+ return true;
848
+ } catch { return false; }
849
+ }
850
+
817
851
  // ── Helpers ─────────────────────────────────────────────────────────────────
818
852
 
819
853
  async function scanManagedModels() {