offgrid-ai 0.3.5 → 0.3.7

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 (3) hide show
  1. package/install.sh +53 -18
  2. package/package.json +1 -1
  3. package/src/cli.mjs +49 -2
package/install.sh CHANGED
@@ -11,7 +11,8 @@
11
11
  # 1. Checks for Node.js
12
12
  # 2. If not found, installs it via nvm (no sudo needed)
13
13
  # 3. Installs offgrid-ai globally via npm
14
- # 4. Runs offgrid-ai
14
+ # 4. Adds npm global bin to PATH if needed
15
+ # 5. Runs offgrid-ai
15
16
  #
16
17
  # Flags:
17
18
  # --dry-run Show what would happen without making changes
@@ -108,7 +109,7 @@ echo ""
108
109
  printf "${BOLD}Installing offgrid-ai...${RESET}\n"
109
110
  dry npm install -g offgrid-ai
110
111
 
111
- # ── Verify ───────────────────────────────────────────────────────────────────
112
+ # ── Dry-run early exit ──────────────────────────────────────────────────────
112
113
 
113
114
  if $DRY_RUN; then
114
115
  ok "offgrid-ai installed (dry-run)"
@@ -122,23 +123,52 @@ if $DRY_RUN; then
122
123
  exit 0
123
124
  fi
124
125
 
125
- if command -v offgrid-ai &>/dev/null; then
126
- ok "offgrid-ai installed at $(command -v offgrid-ai)"
127
- else
128
- echo ""
129
- warn "offgrid-ai was installed but isn't on your PATH yet."
130
- echo " Restart your terminal and run: offgrid-ai"
131
- echo " Or run: source ~/.nvm/nvm.sh && offgrid-ai"
132
- echo ""
133
- printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
134
- printf "${BOLD}${GREEN} offgrid-ai is ready!${RESET}\n"
135
- printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
136
- echo ""
137
- echo " Run: offgrid-ai"
138
- echo ""
139
- exit 0
126
+ # ── Add npm global bin to PATH if needed ────────────────────────────────────
127
+
128
+ NPM_BIN="$(npm bin -g 2>/dev/null)"
129
+
130
+ if ! command -v offgrid-ai &>/dev/null; then
131
+ if [[ -n "$NPM_BIN" && -x "$NPM_BIN/offgrid-ai" ]]; then
132
+ # Add to current session
133
+ export PATH="$NPM_BIN:$PATH"
134
+ ok "Added $NPM_BIN to PATH for this session"
135
+
136
+ # Add to shell config for future sessions (pick first existing or .zshrc)
137
+ ADDED_TO_RC=false
138
+ for RC_FILE in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile"; do
139
+ if [[ -f "$RC_FILE" || "$RC_FILE" == "$HOME/.zshrc" ]]; then
140
+ if ! grep -qF "$NPM_BIN" "$RC_FILE" 2>/dev/null; then
141
+ echo '' >> "$RC_FILE"
142
+ echo '# Added by offgrid-ai installer' >> "$RC_FILE"
143
+ echo "export PATH=\"$NPM_BIN:\$PATH\"" >> "$RC_FILE"
144
+ ok "Added $NPM_BIN to $RC_FILE"
145
+ ADDED_TO_RC=true
146
+ # Only add to one rc file to avoid duplicates
147
+ break
148
+ fi
149
+ fi
150
+ done
151
+
152
+ if ! $ADDED_TO_RC; then
153
+ warn "$NPM_BIN is already in a shell config file — restart your terminal to use offgrid-ai"
154
+ fi
155
+ else
156
+ echo ""
157
+ warn "offgrid-ai was installed but the binary wasn't found."
158
+ echo " Restart your terminal and run: offgrid-ai"
159
+ echo ""
160
+ printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
161
+ printf "${BOLD}${GREEN} offgrid-ai is ready!${RESET}\n"
162
+ printf "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}\n"
163
+ echo ""
164
+ echo " Run: offgrid-ai"
165
+ echo ""
166
+ exit 0
167
+ fi
140
168
  fi
141
169
 
170
+ ok "offgrid-ai installed at $(command -v offgrid-ai)"
171
+
142
172
  # ── Done ─────────────────────────────────────────────────────────────────────
143
173
 
144
174
  echo ""
@@ -149,7 +179,12 @@ echo ""
149
179
  echo " First run will walk you through setting up everything you need"
150
180
  echo " (llama-server, model backends, Pi)."
151
181
  echo ""
152
- echo " Run: offgrid-ai"
182
+ if command -v offgrid-ai &>/dev/null; then
183
+ echo " Run: offgrid-ai"
184
+ else
185
+ echo " Run: source ~/.zshrc && offgrid-ai"
186
+ echo " (or open a new terminal)"
187
+ fi
153
188
  echo ""
154
189
 
155
190
  if [[ -t 0 ]] && ! $SKIP_RUN; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offgrid-ai",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
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
@@ -789,6 +789,7 @@ async function uninstallCommand(argv) {
789
789
  // Non-interactive / forced: remove everything
790
790
  await removeDataDir();
791
791
  await removeSelf();
792
+ await removeShellPath();
792
793
  return;
793
794
  }
794
795
 
@@ -825,7 +826,8 @@ async function uninstallCommand(argv) {
825
826
  // Remove the npm package
826
827
  const confirmUninstall = await prompt.yesNo("Uninstall offgrid-ai npm package?", true);
827
828
  if (confirmUninstall) {
828
- removeSelf();
829
+ await removeSelf();
830
+ await removeShellPath();
829
831
  } else {
830
832
  console.log(pc.dim("Cancelled."));
831
833
  }
@@ -849,6 +851,51 @@ async function removeDataDir() {
849
851
  }
850
852
  }
851
853
 
854
+ async function removeShellPath() {
855
+ const { readFile, writeFile } = await import("node:fs/promises");
856
+ const { homedir } = await import("node:os");
857
+ const { promisify } = await import("node:util");
858
+ const { execFile } = await import("node:child_process");
859
+ let npmBin;
860
+ try {
861
+ const { stdout } = await promisify(execFile)("npm", ["bin", "-g"]);
862
+ npmBin = stdout.trim();
863
+ } catch { return; }
864
+ if (!npmBin) return;
865
+
866
+ const marker = "# Added by offgrid-ai installer";
867
+ const pathLine = `export PATH="${npmBin}:$PATH"`;
868
+ const rcFiles = [`${homedir()}/.zshrc`, `${homedir()}/.bashrc`, `${homedir()}/.bash_profile`];
869
+ let cleaned = false;
870
+
871
+ for (const rcFile of rcFiles) {
872
+ if (!existsSync(rcFile)) continue;
873
+ let content;
874
+ try { content = await readFile(rcFile, "utf8"); } catch { continue; }
875
+ if (!content.includes(npmBin) && !content.includes(marker)) continue;
876
+
877
+ const lines = content.split("\n");
878
+ const filtered = lines.filter((line, i) => {
879
+ // Remove the marker comment line
880
+ if (line.trim() === marker) return false;
881
+ // Remove the PATH export line added by the installer
882
+ if (line.trim() === pathLine) return false;
883
+ // Also remove a blank line that immediately precedes the marker (formatter)
884
+ if (i + 1 < lines.length && lines[i + 1].trim() === marker && line.trim() === "") return false;
885
+ return true;
886
+ });
887
+
888
+ if (filtered.length !== lines.length) {
889
+ await writeFile(rcFile, filtered.join("\n").replace(/\n{3,}/g, "\n\n") + "\n", "utf8");
890
+ console.log(pc.green(`✓ Cleaned PATH from ${rcFile}`));
891
+ cleaned = true;
892
+ }
893
+ }
894
+ if (!cleaned) {
895
+ console.log(pc.dim("No offgrid-ai PATH entries found in shell configs."));
896
+ }
897
+ }
898
+
852
899
  async function removeSelf() {
853
900
  console.log(pc.cyan("\nUninstalling offgrid-ai..."));
854
901
  const { spawn: spawnUninstall } = await import("node:child_process");
@@ -932,7 +979,7 @@ Usage:
932
979
  offgrid-ai Pick a model and run it
933
980
  offgrid-ai status Show running local models
934
981
  offgrid-ai stop Stop a running server (or: offgrid-ai stop <id>)
935
- offgrid-ai uninstall Remove offgrid-ai (optionally keep profiles)
982
+ offgrid-ai uninstall Remove offgrid-ai, clean up PATH, optionally keep profiles
936
983
  offgrid-ai help Show this help
937
984
  offgrid-ai version Show version
938
985