kandown 0.15.3 → 0.16.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/bin/kandown.js +65 -9
- package/dist/index.html +121 -121
- package/package.json +1 -1
package/bin/kandown.js
CHANGED
|
@@ -199,15 +199,14 @@ async function checkForUpdate(argv = process.argv) {
|
|
|
199
199
|
|
|
200
200
|
if (!latest || semverGt(current, latest) >= 0) return; // up to date or offline
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
log(`${c.yellow}⚡ Update available:${c.reset} kandown ${c.dim}${current}${c.reset} → ${c.green}${latest}${c.reset}`);
|
|
204
|
-
info('Auto-updating…');
|
|
202
|
+
tuiDone('⚡', `Update available: ${c.dim}kandown ${current}${c.reset} → ${c.green}${latest}${c.reset}`);
|
|
205
203
|
|
|
206
204
|
// 📖 Step 2: Create lock file to prevent concurrent updates.
|
|
207
205
|
try { writeFileSync(lockFile, `${process.pid}\n${now}`, 'utf8'); } catch { /* ignore */ }
|
|
208
206
|
|
|
209
|
-
// 📖 Step 3: Run the update via npm or pnpm.
|
|
210
|
-
|
|
207
|
+
// 📖 Step 3: Run the update via npm or pnpm with animated progress.
|
|
208
|
+
tuiProgress(`Updating to ${latest}…`, 25);
|
|
209
|
+
|
|
211
210
|
const updateOk = await new Promise((resolve) => {
|
|
212
211
|
const tryInstall = (cmd) => {
|
|
213
212
|
return new Promise((res) => {
|
|
@@ -233,7 +232,7 @@ async function checkForUpdate(argv = process.argv) {
|
|
|
233
232
|
try { if (existsSync(lockFile)) unlinkSync(lockFile); } catch { /* ignore */ }
|
|
234
233
|
|
|
235
234
|
if (!updateOk) {
|
|
236
|
-
|
|
235
|
+
tuiDone('✗', `${c.yellow}Auto-update failed${c.reset} — continuing with current version`);
|
|
237
236
|
log(` Run ${c.cyan}npm install -g kandown${c.reset} to upgrade manually`);
|
|
238
237
|
log('');
|
|
239
238
|
return;
|
|
@@ -257,14 +256,13 @@ async function checkForUpdate(argv = process.argv) {
|
|
|
257
256
|
});
|
|
258
257
|
|
|
259
258
|
if (!postVersion || semverGt(postVersion, latest) < 0) {
|
|
260
|
-
|
|
261
|
-
warn('Update did not apply — continuing with current version');
|
|
259
|
+
tuiDone('✗', `${c.yellow}Update did not apply${c.reset} — continuing with current version`);
|
|
262
260
|
log(` Run ${c.cyan}npm install -g kandown${c.reset} to upgrade manually`);
|
|
263
261
|
log('');
|
|
264
262
|
return;
|
|
265
263
|
}
|
|
266
264
|
|
|
267
|
-
|
|
265
|
+
tuiDone('✓', `${c.green}Updated to v${postVersion}${c.reset} — restarting…`);
|
|
268
266
|
log('');
|
|
269
267
|
|
|
270
268
|
// 📖 Step 5: Respawn with the new version.
|
|
@@ -309,6 +307,64 @@ const info = (msg) => log(`${c.cyan}→${c.reset} ${msg}`);
|
|
|
309
307
|
const warn = (msg) => log(`${c.yellow}⚠${c.reset} ${msg}`);
|
|
310
308
|
const err = (msg) => log(`${c.red}✗${c.reset} ${msg}`);
|
|
311
309
|
|
|
310
|
+
// ─── TUI spinner & progress bar ─────────────────────────────────────────────
|
|
311
|
+
// 📖 Lightweight terminal animation helpers for the auto-updater.
|
|
312
|
+
// Uses ANSI escape codes (carriage return + clear line) to redraw in-place.
|
|
313
|
+
// Only animate when stdout is a TTY; otherwise fall back to plain text.
|
|
314
|
+
|
|
315
|
+
const _SP_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
316
|
+
let _spTimer = null;
|
|
317
|
+
let _spIdx = 0;
|
|
318
|
+
const _isTTY = process.stdout.isTTY;
|
|
319
|
+
|
|
320
|
+
function _tuiClear() {
|
|
321
|
+
process.stdout.write('\r\x1b[K');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Start an animated spinner with the given text. */
|
|
325
|
+
function tuiSpinner(text) {
|
|
326
|
+
if (_spTimer) clearInterval(_spTimer);
|
|
327
|
+
_spIdx = 0;
|
|
328
|
+
_tuiClear();
|
|
329
|
+
if (!_isTTY) { process.stdout.write(` ${text}\n`); return; }
|
|
330
|
+
_spTimer = setInterval(() => {
|
|
331
|
+
process.stdout.write(`\r\x1b[K${_SP_FRAMES[_spIdx % _SP_FRAMES.length]} ${text}`);
|
|
332
|
+
_spIdx++;
|
|
333
|
+
}, 100);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 📖 Start a time-estimated progress bar + spinner.
|
|
338
|
+
* Shows a filling bar with percentage based on elapsed time.
|
|
339
|
+
* Caps at 95% until the caller calls tuiDone().
|
|
340
|
+
*/
|
|
341
|
+
function tuiProgress(text, estimateSec = 25, barWidth = 15) {
|
|
342
|
+
if (_spTimer) clearInterval(_spTimer);
|
|
343
|
+
_spIdx = 0;
|
|
344
|
+
_tuiClear();
|
|
345
|
+
if (!_isTTY) { process.stdout.write(` ${text}\n`); return; }
|
|
346
|
+
const start = Date.now();
|
|
347
|
+
_spTimer = setInterval(() => {
|
|
348
|
+
const elapsed = (Date.now() - start) / 1000;
|
|
349
|
+
const pct = Math.min(Math.round((elapsed / estimateSec) * 100), 95);
|
|
350
|
+
const filled = Math.round(barWidth * pct / 100);
|
|
351
|
+
const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(barWidth - filled);
|
|
352
|
+
process.stdout.write(`\r\x1b[K${_SP_FRAMES[_spIdx % _SP_FRAMES.length]} ${text} ${bar} ${pct}%`);
|
|
353
|
+
_spIdx++;
|
|
354
|
+
}, 120);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Stop the current animation and print a final status line. */
|
|
358
|
+
function tuiDone(symbol, text) {
|
|
359
|
+
if (_spTimer) { clearInterval(_spTimer); _spTimer = null; }
|
|
360
|
+
if (_isTTY) {
|
|
361
|
+
_tuiClear();
|
|
362
|
+
process.stdout.write(`${symbol} ${text}\n`);
|
|
363
|
+
} else {
|
|
364
|
+
log(`${symbol} ${text}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
312
368
|
function help() {
|
|
313
369
|
const v = getCurrentVersion() ?? '?';
|
|
314
370
|
log(`
|