bunosh 0.4.14 → 0.5.6

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/upgrade.js CHANGED
@@ -1,4 +1,4 @@
1
- import { exec, execSync } from 'child_process';
1
+ import { exec, execSync, spawn } from 'child_process';
2
2
  import { readFileSync, writeFileSync, existsSync } from 'fs';
3
3
  import { platform } from 'os';
4
4
  import { homedir } from 'os';
@@ -13,18 +13,44 @@ export async function upgradeCommand(options = {}) {
13
13
  const installMethod = detectInstallMethod();
14
14
  console.log(`Bunosh is installed via: ${color.bold(installMethod)}`);
15
15
 
16
- if (installMethod === 'bun') {
17
- if (!check) {
16
+ if (installMethod === 'bun' || installMethod === 'npm') {
17
+ const currentVersion = getCurrentVersion();
18
+ let latestVersion = null;
19
+ try {
20
+ latestVersion = await getLatestNpmVersion();
21
+ } catch (e) {
22
+ }
23
+
24
+ console.log(`Current version: ${color.bold(currentVersion)}`);
25
+ if (latestVersion) {
26
+ console.log(`Latest version: ${color.bold(latestVersion)}`);
27
+ }
28
+
29
+ if (latestVersion && !force && !isNewerVersion(latestVersion, currentVersion)) {
30
+ console.log(color.green('You are already on the latest version!'));
31
+ if (!force) {
32
+ console.log(` Use ${color.bold('--force')} to reinstall the current version.`);
33
+ }
34
+ return;
35
+ }
36
+
37
+ const upgradeCmd = installMethod === 'bun'
38
+ ? 'bun add -g bunosh@latest --force'
39
+ : 'npm install -g bunosh@latest';
40
+
41
+ if (check) {
42
+ console.log('Will upgrade with: ' + color.bold(upgradeCmd));
43
+ return;
44
+ }
45
+
46
+ if (installMethod === 'bun') {
18
47
  await upgradeWithBun();
19
48
  } else {
20
- console.log('Will upgrade with: ' + color.bold('bun add -g bunosh'));
21
- }
22
- } else if (installMethod === 'npm') {
23
- if (!check) {
24
49
  await upgradeWithNpm();
25
- } else {
26
- console.log('Will upgrade with: ' + color.bold('npm update -g bunosh'));
27
50
  }
51
+
52
+ console.log();
53
+ console.log(`Run ${color.bold('bunosh --version')} to verify the new version.`);
28
54
  } else if (installMethod === 'executable') {
29
55
  await upgradeExecutable({ force, check });
30
56
  } else {
@@ -101,36 +127,115 @@ function detectInstallMethod() {
101
127
  return 'unknown';
102
128
  }
103
129
 
104
- async function upgradeWithBun() {
105
- console.log('Upgrading with Bun...');
106
-
130
+ function runStreaming(command, args) {
107
131
  return new Promise((resolve, reject) => {
108
- exec('bun add -g bunosh', (error, stdout, stderr) => {
109
- if (error) {
110
- reject(new Error(`Bun upgrade failed: ${stderr || error.message}`));
132
+ const child = spawn(command, args, { stdio: 'inherit' });
133
+ child.on('error', (error) => reject(new Error(`${command} not available: ${error.message}`)));
134
+ child.on('close', (code) => {
135
+ if (code === 0) {
136
+ resolve();
111
137
  return;
112
138
  }
113
- console.log(stdout);
114
- console.log(color.green('Upgrade successful!'));
115
- resolve();
139
+ reject(new Error(`${command} ${args.join(' ')} exited with code ${code}`));
116
140
  });
117
141
  });
118
142
  }
119
143
 
144
+ async function upgradeWithBun() {
145
+ console.log('Upgrading with Bun...');
146
+
147
+ try {
148
+ await runStreaming('bun', ['add', '-g', 'bunosh@latest', '--force']);
149
+ console.log(color.green('Upgrade successful!'));
150
+ return;
151
+ } catch (error) {
152
+ console.warn(color.yellow(`Bun upgrade failed: ${error.message}`));
153
+ console.warn(color.yellow('Falling back to npm (a known Bun global-install bug)...'));
154
+ }
155
+
156
+ await upgradeWithNpm();
157
+ }
158
+
120
159
  async function upgradeWithNpm() {
121
160
  console.log('Upgrading with npm...');
122
-
123
- return new Promise((resolve, reject) => {
124
- exec('npm update -g bunosh', (error, stdout, stderr) => {
125
- if (error) {
126
- reject(new Error(`npm upgrade failed: ${stderr || error.message}`));
127
- return;
128
- }
129
- console.log(stdout);
130
- console.log(color.green('Upgrade successful!'));
131
- resolve();
161
+
162
+ await runStreaming('npm', ['install', '-g', 'bunosh@latest']);
163
+ console.log(color.green('Upgrade successful!'));
164
+ }
165
+
166
+ export async function getLatestNpmVersion(timeoutMs = 3000) {
167
+ const controller = new AbortController();
168
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
169
+
170
+ try {
171
+ const response = await fetch('https://registry.npmjs.org/bunosh/latest', {
172
+ headers: { 'User-Agent': 'bunosh' },
173
+ signal: controller.signal,
132
174
  });
133
- });
175
+
176
+ if (!response.ok) {
177
+ throw new Error(`npm registry error: ${response.status}`);
178
+ }
179
+
180
+ const data = await response.json();
181
+ return data.version;
182
+ } finally {
183
+ clearTimeout(timer);
184
+ }
185
+ }
186
+
187
+ async function getCachedLatestNpmVersion() {
188
+ const cacheDir = join(homedir(), '.bunosh');
189
+ const cacheFile = join(cacheDir, 'version-check.json');
190
+ const TTL = 12 * 60 * 60 * 1000;
191
+
192
+ try {
193
+ if (existsSync(cacheFile)) {
194
+ const cache = JSON.parse(readFileSync(cacheFile, 'utf8'));
195
+ if (cache.latest && cache.checkedAt && Date.now() - cache.checkedAt < TTL) {
196
+ return cache.latest;
197
+ }
198
+ }
199
+ } catch (e) {
200
+ }
201
+
202
+ let latest = null;
203
+ try {
204
+ latest = await getLatestNpmVersion(2000);
205
+ } catch (e) {
206
+ return null;
207
+ }
208
+
209
+ try {
210
+ await mkdir(cacheDir, { recursive: true });
211
+ writeFileSync(cacheFile, JSON.stringify({ checkedAt: Date.now(), latest }));
212
+ } catch (e) {
213
+ }
214
+
215
+ return latest;
216
+ }
217
+
218
+ export async function printUpgradeNoticeIfAvailable() {
219
+ if (process.env.NODE_ENV === 'test' || process.env.VITEST_WORKER_ID !== undefined) {
220
+ return;
221
+ }
222
+
223
+ try {
224
+ const currentVersion = getCurrentVersion();
225
+ if (!currentVersion || currentVersion === 'unknown') {
226
+ return;
227
+ }
228
+
229
+ const latestVersion = await getCachedLatestNpmVersion();
230
+ if (!latestVersion || !isNewerVersion(latestVersion, currentVersion)) {
231
+ return;
232
+ }
233
+
234
+ console.log();
235
+ console.log(color.yellow(`🦾 A new version of Bunosh is available: ${color.bold(currentVersion)} → ${color.bold(latestVersion)}`));
236
+ console.log(color.dim(` Run ${color.bold('bunosh upgrade')} to update.`));
237
+ } catch (e) {
238
+ }
134
239
  }
135
240
 
136
241
  export async function upgradeExecutable(options = {}) {
@@ -199,7 +304,7 @@ function getCurrentVersion() {
199
304
  }
200
305
 
201
306
  async function getLatestRelease() {
202
- const response = await fetch('https://api.github.com/repos/davertmik/bunosh/releases/latest', {
307
+ const response = await fetch('https://api.github.com/repos/DavertMik/bunosh/releases/latest', {
203
308
  headers: {
204
309
  'User-Agent': 'bunosh'
205
310
  }