cli-setu 0.1.0

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/src/update.js ADDED
@@ -0,0 +1,73 @@
1
+ // `setu --update` - checks the real npm registry for a newer published
2
+ // version, and if one exists, runs the real upgrade command on the
3
+ // user's behalf (confirmed directly: don't just tell them what to run,
4
+ // actually run it) so they don't have to remember/type
5
+ // `npm install -g cli-setu` themselves.
6
+ const { execFile } = require('child_process');
7
+ const { promisify } = require('util');
8
+ const execFileAsync = promisify(execFile);
9
+ const pkg = require('../package.json');
10
+
11
+ // A plain https GET against the real npm registry's own JSON API - no
12
+ // extra dependency needed just to read one field (dist-tags.latest),
13
+ // and this works the same whether or not the user has ever run `npm
14
+ // login` (checking the latest published version is a public, anonymous
15
+ // read, unlike actually publishing).
16
+ async function fetchLatestVersion() {
17
+ const res = await fetch(`https://registry.npmjs.org/${pkg.name}/latest`);
18
+ if (!res.ok) throw new Error(`npm registry returned ${res.status}`);
19
+ const data = await res.json();
20
+ return data.version;
21
+ }
22
+
23
+ // Plain, dependency-free semver comparison - good enough for this one
24
+ // use (comparing two real, well-formed "x.y.z" versions from package.json
25
+ // and the npm registry), not a general-purpose semver range parser.
26
+ function isNewer(latest, current) {
27
+ const a = latest.split('.').map(Number);
28
+ const b = current.split('.').map(Number);
29
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
30
+ const x = a[i] || 0;
31
+ const y = b[i] || 0;
32
+ if (x !== y) return x > y;
33
+ }
34
+ return false;
35
+ }
36
+
37
+ async function update() {
38
+ console.log(`[setu] Current version: ${pkg.version}`);
39
+ console.log('[setu] Checking for updates...');
40
+
41
+ let latest;
42
+ try {
43
+ latest = await fetchLatestVersion();
44
+ } catch (err) {
45
+ console.error(`[setu] Could not check for updates: ${err.message}`);
46
+ process.exit(1);
47
+ }
48
+
49
+ if (!isNewer(latest, pkg.version)) {
50
+ console.log(`[setu] Already on the latest version (${pkg.version}).`);
51
+ return;
52
+ }
53
+
54
+ console.log(`[setu] A newer version is available: ${latest} (you have ${pkg.version}).`);
55
+ console.log(`[setu] Installing ${pkg.name}@${latest}...`);
56
+ try {
57
+ // execFile (not exec) - no shell involved, consistent with this
58
+ // project's own established convention for anything that runs a
59
+ // real external command (see supervisor.js's own comment on exec vs
60
+ // execFile for the same reasoning).
61
+ const { stdout } = await execFileAsync('npm', ['install', '-g', `${pkg.name}@${latest}`], {
62
+ shell: process.platform === 'win32', // npm.cmd on Windows needs a shell to resolve; execFile alone can't find it otherwise
63
+ });
64
+ if (stdout) console.log(stdout.trim());
65
+ console.log(`[setu] ✓ Updated to ${latest}.`);
66
+ } catch (err) {
67
+ console.error(`[setu] Update failed: ${err.message}`);
68
+ console.error(`[setu] You can try running it yourself: npm install -g ${pkg.name}@${latest}`);
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ module.exports = { update };