nebula-ai 0.0.15 → 0.0.16
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/bin/nebula-ai.js +32 -68
- package/package.json +1 -1
package/bin/nebula-ai.js
CHANGED
|
@@ -46,6 +46,10 @@ import { homedir } from "node:os";
|
|
|
46
46
|
import { dirname, join } from "node:path";
|
|
47
47
|
import { pipeline } from "node:stream/promises";
|
|
48
48
|
import { fileURLToPath } from "node:url";
|
|
49
|
+
import { detectInstallMethod, getChannel, getUpdateCheckCachePath, getUpgradeCommand, isNewerVersion, isNpx, isUpdateCheckDisabled, UPDATE_CHECK_TTL_MS, } from "./update-check-lib.js";
|
|
50
|
+
// Re-export the pure update-check helpers so older tests / downstream
|
|
51
|
+
// importers that still reach for `./launcher.js` keep working.
|
|
52
|
+
export { detectInstallMethod, getChannel, getUpdateCheckCachePath, getUpgradeCommand, isNewerVersion, isNpx, isUpdateCheckDisabled, } from "./update-check-lib.js";
|
|
49
53
|
// The public half of the ed25519 key that signs `checksums.json`. The
|
|
50
54
|
// private half lives only in the `NEBULA_AI_SIGNING_PRIVATE_KEY` GitHub
|
|
51
55
|
// Actions secret.
|
|
@@ -66,68 +70,11 @@ const SUPPORTED_PLATFORMS = new Set([
|
|
|
66
70
|
"linux-arm64",
|
|
67
71
|
"win32-x64",
|
|
68
72
|
]);
|
|
69
|
-
// ─── update-check constants ────────────────────────────────────────────────
|
|
70
|
-
const UPDATE_CHECK_TTL = 4 * 60 * 60 * 1000; // 4 hours
|
|
71
73
|
// ─── pure helpers (exported for tests) ─────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*/
|
|
77
|
-
export function getUpdateCheckCachePath() {
|
|
78
|
-
const base = process.env.NEBULA_AI_CACHE_DIR ||
|
|
79
|
-
(process.platform === "win32"
|
|
80
|
-
? process.env.LOCALAPPDATA || join(homedir(), "AppData", "Local")
|
|
81
|
-
: process.env.XDG_CACHE_HOME || join(homedir(), ".cache"));
|
|
82
|
-
return join(base, "nebula-ai", "update-check.json");
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Determine the release channel from a version string.
|
|
86
|
-
* Dev versions look like `x.y.z-dev.YYYYMMDDHHMMSS.sha`.
|
|
87
|
-
*/
|
|
88
|
-
export function getChannel(version) {
|
|
89
|
-
return version.includes("-dev.") ? "dev" : "prod";
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Return true if `latest` is a newer semver than `current` (prod), or simply
|
|
93
|
-
* different (dev — timestamps are monotonically increasing).
|
|
94
|
-
*/
|
|
95
|
-
export function isNewerVersion(latest, current) {
|
|
96
|
-
if (current.includes("-dev.")) {
|
|
97
|
-
return latest !== current;
|
|
98
|
-
}
|
|
99
|
-
// Strip any prerelease suffix (e.g., "-beta.1") before parsing.
|
|
100
|
-
const clean = (v) => v.replace(/-.*$/, "");
|
|
101
|
-
const [a1, a2, a3] = clean(latest).split(".").map(Number);
|
|
102
|
-
const [b1, b2, b3] = clean(current).split(".").map(Number);
|
|
103
|
-
if (a1 !== b1)
|
|
104
|
-
return a1 > b1;
|
|
105
|
-
if (a2 !== b2)
|
|
106
|
-
return a2 > b2;
|
|
107
|
-
if (a3 !== b3)
|
|
108
|
-
return a3 > b3;
|
|
109
|
-
// Same numeric version: a stable release is newer than a prerelease
|
|
110
|
-
// (e.g. 1.0.0 is newer than 1.0.0-beta.1).
|
|
111
|
-
if (current.includes("-") && !latest.includes("-"))
|
|
112
|
-
return true;
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Return true when the update check should be suppressed entirely.
|
|
117
|
-
*/
|
|
118
|
-
export function isUpdateCheckDisabled() {
|
|
119
|
-
return (process.env.NEBULA_AI_NO_UPDATE_CHECK === "1" ||
|
|
120
|
-
process.env.NEBULA_AI_NO_UPDATE_CHECK === "true" ||
|
|
121
|
-
process.env.CI === "true" ||
|
|
122
|
-
!process.stderr.isTTY);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Return true when running under `npx` (which always fetches the latest
|
|
126
|
-
* wrapper, making the check redundant).
|
|
127
|
-
*/
|
|
128
|
-
export function isNpx() {
|
|
129
|
-
return process.env.npm_command === "exec";
|
|
130
|
-
}
|
|
74
|
+
//
|
|
75
|
+
// Version/update-check helpers live in ./update-check-lib.ts and are
|
|
76
|
+
// re-exported above. Supply-chain helpers remain here because they import
|
|
77
|
+
// node:crypto and aren't used outside the launcher.
|
|
131
78
|
export function sha256HexSync(buffer) {
|
|
132
79
|
return createHash("sha256").update(buffer).digest("hex");
|
|
133
80
|
}
|
|
@@ -288,7 +235,7 @@ function maybeSpawnUpdateCheck(currentVersion) {
|
|
|
288
235
|
const cachePath = getUpdateCheckCachePath();
|
|
289
236
|
// Skip if the cache is still fresh (stat is cheaper than read + parse).
|
|
290
237
|
try {
|
|
291
|
-
if (Date.now() - statSync(cachePath).mtimeMs <
|
|
238
|
+
if (Date.now() - statSync(cachePath).mtimeMs < UPDATE_CHECK_TTL_MS)
|
|
292
239
|
return;
|
|
293
240
|
}
|
|
294
241
|
catch {
|
|
@@ -331,16 +278,22 @@ function maybeSpawnUpdateCheck(currentVersion) {
|
|
|
331
278
|
/**
|
|
332
279
|
* Read the cached check result (written by a *previous* invocation's
|
|
333
280
|
* background process) and print a one-line update notification to stderr
|
|
334
|
-
* if a newer version is available.
|
|
281
|
+
* if a newer version is available. The suggested upgrade command is
|
|
282
|
+
* chosen based on the detected install method so pnpm/yarn/bun/brew users
|
|
283
|
+
* see an actually-applicable command.
|
|
335
284
|
*/
|
|
336
|
-
function maybeShowUpdateNotification(currentVersion) {
|
|
285
|
+
function maybeShowUpdateNotification(currentVersion, installMethod) {
|
|
337
286
|
try {
|
|
338
287
|
const raw = readFileSync(getUpdateCheckCachePath(), "utf8");
|
|
339
288
|
const cached = JSON.parse(raw);
|
|
340
289
|
if (cached.latest && isNewerVersion(cached.latest, currentVersion)) {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
290
|
+
const channel = getChannel(currentVersion);
|
|
291
|
+
// Fall back to the canonical npm command when the install method
|
|
292
|
+
// is unknown — matches the wrapper's install-time docs.
|
|
293
|
+
const cmd = getUpgradeCommand(installMethod, channel) ||
|
|
294
|
+
(channel === "dev"
|
|
295
|
+
? "npm install -g nebula-ai@dev"
|
|
296
|
+
: "npm install -g nebula-ai");
|
|
344
297
|
process.stderr.write(`\nnebula-ai: update available ${currentVersion} \u2192 ${cached.latest}\n` +
|
|
345
298
|
` Run: ${cmd}\n`);
|
|
346
299
|
}
|
|
@@ -404,12 +357,23 @@ async function main() {
|
|
|
404
357
|
if (!isUpdateCheckDisabled() && !isNpx()) {
|
|
405
358
|
maybeSpawnUpdateCheck(version);
|
|
406
359
|
}
|
|
360
|
+
// Figure out how the user installed us (npm/pnpm/yarn/bun/npx/...) from
|
|
361
|
+
// the wrapper's own launch path + env. We forward the result to the Bun
|
|
362
|
+
// binary via NEBULA_AI_INSTALL_METHOD so the in-TUI "What's new" banner
|
|
363
|
+
// can surface the right upgrade command without redoing the detection.
|
|
364
|
+
const installMethod = detectInstallMethod({
|
|
365
|
+
execPath: fileURLToPath(import.meta.url),
|
|
366
|
+
argv0: process.argv[0],
|
|
367
|
+
npmCommand: process.env.npm_command,
|
|
368
|
+
npmUserAgent: process.env.npm_config_user_agent,
|
|
369
|
+
});
|
|
407
370
|
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
408
371
|
stdio: "inherit",
|
|
372
|
+
env: { ...process.env, NEBULA_AI_INSTALL_METHOD: installMethod },
|
|
409
373
|
});
|
|
410
374
|
// Show update notification (reads PREVIOUS check's cached result).
|
|
411
375
|
if (!isUpdateCheckDisabled() && !isNpx()) {
|
|
412
|
-
maybeShowUpdateNotification(version);
|
|
376
|
+
maybeShowUpdateNotification(version, installMethod);
|
|
413
377
|
}
|
|
414
378
|
if (result.error) {
|
|
415
379
|
console.error(`nebula-ai: unable to start the application.\n` +
|