offgrid-ai 0.2.2 → 0.2.3
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/README.md +5 -1
- package/package.json +1 -1
- package/src/cli.mjs +53 -26
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@ curl -fsSL https://raw.githubusercontent.com/eeshansrivastava89/offgrid-ai/main/
|
|
|
59
59
|
|
|
60
60
|
| Backend | Type | Auto-detected |
|
|
61
61
|
|---|---|---|
|
|
62
|
+
| **LM Studio** | Visual model browser + CLI (`lms`) | ✓ models in `~/.lmstudio/models/` |
|
|
62
63
|
| **llama.cpp** | Local server | ✓ GGUF models in `~/.lmstudio/models/` |
|
|
63
64
|
| **llama.cpp MTP** | Local server (speculative decoding) | ✓ MTP detected from model metadata |
|
|
64
65
|
| **Ollama** | Managed server | ✓ via `localhost:11434` |
|
|
@@ -70,7 +71,10 @@ When you run `offgrid-ai` for the first time on a fresh machine:
|
|
|
70
71
|
|
|
71
72
|
1. **Homebrew** — Required. Offered to install if missing.
|
|
72
73
|
2. **llama-server** — Required for GGUF models. Offered to install via Homebrew.
|
|
73
|
-
3. **Model backend** — At least one is needed
|
|
74
|
+
3. **Model backend** — At least one is needed (LM Studio recommended):
|
|
75
|
+
- **LM Studio** — visual model browser + `lms` CLI, download models with `lms get qwen/qwen3.5-9b`
|
|
76
|
+
- **Ollama** — models download on demand with `ollama pull`
|
|
77
|
+
- **oMLX** — Apple Silicon optimized
|
|
74
78
|
4. **Models** — If no models found, tells you where to get them.
|
|
75
79
|
|
|
76
80
|
Subsequent runs skip everything that's already installed.
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
-
import { existsSync, statSync, rmSync } from "node:fs";
|
|
2
|
+
import { existsSync, statSync, rmSync, readFileSync, appendFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { ensureDirs, findLlamaServer, hasHomebrew, DATA_DIR } from "./config.mjs";
|
|
5
5
|
import { scanGgufModels } from "./scan.mjs";
|
|
@@ -577,17 +577,45 @@ async function onboardFlow() {
|
|
|
577
577
|
console.log(pc.dim("You need at least one model backend to use offgrid-ai.\n"));
|
|
578
578
|
|
|
579
579
|
const backendChoice = await prompt.choice("Install a model backend?", [
|
|
580
|
+
{ value: "lmstudio", label: "LM Studio (recommended)", hint: "brew install --cask lm-studio — visual model browser + CLI" },
|
|
580
581
|
{ value: "ollama", label: "Ollama", hint: "brew install ollama — models download on demand" },
|
|
581
|
-
{ value: "lmstudio", label: "LM Studio", hint: "brew install --cask lm-studio — visual model browser" },
|
|
582
582
|
{ value: "omlx", label: "oMLX", hint: "brew tap jundot/omlx && brew install omlx — Apple Silicon optimized" },
|
|
583
|
-
{ value: "all", label: "Install all three", hint: "
|
|
583
|
+
{ value: "all", label: "Install all three", hint: "LM Studio + Ollama + oMLX" },
|
|
584
584
|
{ value: "skip", label: "Skip for now", hint: "I'll set up models myself" },
|
|
585
|
-
], "
|
|
585
|
+
], "lmstudio");
|
|
586
586
|
|
|
587
587
|
const { execFile } = await import("node:child_process");
|
|
588
588
|
const { promisify } = await import("node:util");
|
|
589
589
|
|
|
590
|
-
|
|
590
|
+
const ensureLmsOnPath = () => {
|
|
591
|
+
const lmsBin = join(homedir(), ".lmstudio", "bin");
|
|
592
|
+
if (!existsSync(join(lmsBin, "lms"))) return;
|
|
593
|
+
if (process.env.PATH.split(":").includes(lmsBin)) return;
|
|
594
|
+
process.env.PATH = `${lmsBin}:${process.env.PATH}`;
|
|
595
|
+
const profileFiles = [join(homedir(), ".zshrc"), join(homedir(), ".bash_profile")];
|
|
596
|
+
const line = `export PATH="$PATH:$HOME/.lmstudio/bin"`;
|
|
597
|
+
for (const f of profileFiles) {
|
|
598
|
+
if (!existsSync(f)) continue;
|
|
599
|
+
const content = readFileSync(f, "utf8");
|
|
600
|
+
if (content.includes(".lmstudio/bin")) continue;
|
|
601
|
+
appendFileSync(f, `\n${line}\n`);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
if (backendChoice === "lmstudio") {
|
|
606
|
+
console.log(pc.cyan("Installing LM Studio via Homebrew..."));
|
|
607
|
+
try {
|
|
608
|
+
await promisify(execFile)("brew", ["install", "--cask", "lm-studio"], { stdio: "inherit" });
|
|
609
|
+
ensureLmsOnPath();
|
|
610
|
+
console.log(pc.green("✓ LM Studio installed"));
|
|
611
|
+
console.log(pc.yellow("\nDownload your first model:"));
|
|
612
|
+
console.log(pc.bold(" lms get qwen/qwen3.5-9b"));
|
|
613
|
+
console.log(pc.dim("Then run offgrid-ai again to pick and run a model."));
|
|
614
|
+
} catch (err) {
|
|
615
|
+
console.log(pc.red(`Failed to install LM Studio: ${err.message}`));
|
|
616
|
+
console.log(pc.dim("Download it manually from https://lmstudio.ai"));
|
|
617
|
+
}
|
|
618
|
+
} else if (backendChoice === "ollama") {
|
|
591
619
|
console.log(pc.cyan("Installing Ollama via Homebrew..."));
|
|
592
620
|
try {
|
|
593
621
|
await promisify(execFile)("brew", ["install", "ollama"], { stdio: "inherit" });
|
|
@@ -605,16 +633,6 @@ async function onboardFlow() {
|
|
|
605
633
|
console.log(pc.red(`Failed to install Ollama: ${err.message}`));
|
|
606
634
|
console.log(pc.dim("Install it manually from https://ollama.com"));
|
|
607
635
|
}
|
|
608
|
-
} else if (backendChoice === "lmstudio") {
|
|
609
|
-
console.log(pc.cyan("Installing LM Studio via Homebrew..."));
|
|
610
|
-
try {
|
|
611
|
-
await promisify(execFile)("brew", ["install", "--cask", "lm-studio"], { stdio: "inherit" });
|
|
612
|
-
console.log(pc.green("✓ LM Studio installed"));
|
|
613
|
-
console.log(pc.yellow("\nOpen LM Studio to browse and download models, then run offgrid-ai again."));
|
|
614
|
-
} catch (err) {
|
|
615
|
-
console.log(pc.red(`Failed to install LM Studio: ${err.message}`));
|
|
616
|
-
console.log(pc.dim("Download it manually from https://lmstudio.ai"));
|
|
617
|
-
}
|
|
618
636
|
} else if (backendChoice === "omlx") {
|
|
619
637
|
console.log(pc.cyan("Installing oMLX via Homebrew..."));
|
|
620
638
|
try {
|
|
@@ -630,22 +648,23 @@ async function onboardFlow() {
|
|
|
630
648
|
}
|
|
631
649
|
} else if (backendChoice === "all") {
|
|
632
650
|
let installed = [];
|
|
633
|
-
// Ollama
|
|
634
|
-
console.log(pc.cyan("Installing Ollama via Homebrew..."));
|
|
635
|
-
try {
|
|
636
|
-
await promisify(execFile)("brew", ["install", "ollama"], { stdio: "inherit" });
|
|
637
|
-
installed.push("Ollama");
|
|
638
|
-
} catch {
|
|
639
|
-
console.log(pc.yellow("Ollama installation failed. Install manually from https://ollama.com"));
|
|
640
|
-
}
|
|
641
651
|
// LM Studio
|
|
642
652
|
console.log(pc.cyan("Installing LM Studio via Homebrew..."));
|
|
643
653
|
try {
|
|
644
654
|
await promisify(execFile)("brew", ["install", "--cask", "lm-studio"], { stdio: "inherit" });
|
|
655
|
+
ensureLmsOnPath();
|
|
645
656
|
installed.push("LM Studio");
|
|
646
657
|
} catch {
|
|
647
658
|
console.log(pc.yellow("LM Studio installation failed. Download from https://lmstudio.ai"));
|
|
648
659
|
}
|
|
660
|
+
// Ollama
|
|
661
|
+
console.log(pc.cyan("Installing Ollama via Homebrew..."));
|
|
662
|
+
try {
|
|
663
|
+
await promisify(execFile)("brew", ["install", "ollama"], { stdio: "inherit" });
|
|
664
|
+
installed.push("Ollama");
|
|
665
|
+
} catch {
|
|
666
|
+
console.log(pc.yellow("Ollama installation failed. Install manually from https://ollama.com"));
|
|
667
|
+
}
|
|
649
668
|
// oMLX
|
|
650
669
|
console.log(pc.cyan("Installing oMLX via Homebrew..."));
|
|
651
670
|
try {
|
|
@@ -657,9 +676,17 @@ async function onboardFlow() {
|
|
|
657
676
|
}
|
|
658
677
|
if (installed.length > 0) {
|
|
659
678
|
console.log(pc.green(`\n✓ Installed: ${installed.join(", ")}`));
|
|
660
|
-
console.log(pc.yellow("Next steps:"));
|
|
661
|
-
|
|
662
|
-
|
|
679
|
+
console.log(pc.yellow("Next steps — download your first model:"));
|
|
680
|
+
if (installed.includes("LM Studio")) {
|
|
681
|
+
console.log(pc.bold(" lms get qwen/qwen3.5-9b"));
|
|
682
|
+
}
|
|
683
|
+
if (installed.includes("Ollama")) {
|
|
684
|
+
console.log(pc.bold(" ollama pull gemma3:4b"));
|
|
685
|
+
}
|
|
686
|
+
if (installed.includes("oMLX")) {
|
|
687
|
+
console.log(pc.bold(" omlx start"));
|
|
688
|
+
}
|
|
689
|
+
console.log(pc.dim("Then run offgrid-ai again to pick and run a model."));
|
|
663
690
|
}
|
|
664
691
|
} else {
|
|
665
692
|
console.log(pc.dim("Run offgrid-ai again when you've set up a model backend."));
|