offgrid-ai 0.3.9 → 0.3.10

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 +60 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offgrid-ai",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
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
@@ -11,10 +11,65 @@ import { tailFriendly } from "./logs.mjs";
11
11
  import { estimateMemory } from "./estimate.mjs";
12
12
  import { pc, formatBytes, renderRows, renderSection, startInteractive, createPrompt, parseOptions } from "./ui.mjs";
13
13
 
14
+ // ── Update check ────────────────────────────────────────────────────────────
15
+
16
+ const UPDATE_CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
17
+
18
+ async function checkForUpdate() {
19
+ if (process.env.OFFGRID_NO_UPDATE_CHECK) return null;
20
+ const { readFile, writeFile } = await import("node:fs/promises");
21
+ const { join } = await import("node:path");
22
+ const cacheFile = join(DATA_DIR, "update-cache.json");
23
+
24
+ // Read cached check
25
+ let cached;
26
+ try {
27
+ cached = JSON.parse(await readFile(cacheFile, "utf8"));
28
+ } catch { cached = null; }
29
+
30
+ // Skip if checked recently
31
+ if (cached?.lastChecked && Date.now() - cached.lastChecked < UPDATE_CHECK_INTERVAL) {
32
+ return cached.latestVersion && cached.latestVersion !== cached.currentVersion ? { current: cached.currentVersion, latest: cached.latestVersion } : null;
33
+ }
34
+
35
+ // Fetch latest version from npm registry
36
+ try {
37
+ const response = await fetch("https://registry.npmjs.org/offgrid-ai/latest", {
38
+ signal: AbortSignal.timeout(3000),
39
+ });
40
+ if (!response.ok) return null;
41
+ const body = await response.json();
42
+ const latestVersion = body.version;
43
+
44
+ // Get current version
45
+ const { readFileSync } = await import("node:fs");
46
+ const { dirname } = await import("node:path");
47
+ const { fileURLToPath } = await import("node:url");
48
+ const __dirname = dirname(fileURLToPath(import.meta.url));
49
+ const currentVersion = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")).version;
50
+
51
+ // Cache the result
52
+ await writeFile(cacheFile, JSON.stringify({ lastChecked: Date.now(), currentVersion, latestVersion }), "utf8");
53
+
54
+ return latestVersion !== currentVersion ? { current: currentVersion, latest: latestVersion } : null;
55
+ } catch {
56
+ // Network error or timeout — fail silently
57
+ return null;
58
+ }
59
+ }
60
+
14
61
  // ── Entry point ────────────────────────────────────────────────────────────
15
62
 
16
63
  export async function run(argv) {
17
- if (argv.length === 0) return mainFlow();
64
+ if (argv.length === 0) {
65
+ const update = await checkForUpdate();
66
+ if (update) {
67
+ console.log(pc.yellow(`\nUpdate available: ${update.latest}. You have v${update.current}.`));
68
+ console.log(pc.dim("Run: npm install -g offgrid-ai@latest"));
69
+ console.log();
70
+ }
71
+ return mainFlow();
72
+ }
18
73
  const [command] = argv;
19
74
 
20
75
  if (command === "help" || command === "--help" || command === "-h") return printHelp();
@@ -967,6 +1022,10 @@ async function printVersion() {
967
1022
  try {
968
1023
  const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
969
1024
  console.log(`offgrid-ai v${pkg.version}`);
1025
+ const update = await checkForUpdate();
1026
+ if (update) {
1027
+ console.log(pc.yellow(`Update available: ${update.latest}. Run: npm install -g offgrid-ai@latest`));
1028
+ }
970
1029
  } catch {
971
1030
  console.log("offgrid-ai v0.1.0");
972
1031
  }