sketchboard-app 1.0.6 → 1.0.8

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/bin/uninstall.js +69 -70
  2. package/package.json +1 -1
package/bin/uninstall.js CHANGED
@@ -2,96 +2,95 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const readline = require("readline");
6
- const fs = require("fs");
7
- const path = require("path");
8
- const os = require("os");
5
+ const { spawnSync } = require("child_process");
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const os = require("os");
9
9
 
10
10
  const DATA_DIR = process.env.SKETCHBOARD_DATA || path.join(os.homedir(), ".sketchboard");
11
11
  const exists = fs.existsSync(DATA_DIR);
12
12
 
13
- // Non-interactive environment (CI/pipe) — skip prompt, keep data
14
- if (!process.stdin.isTTY) {
15
- process.exit(0);
16
- }
17
-
18
- // ── Count saved drawings ──────────────────────────────────────────────────────
13
+ // Count saved drawings
19
14
  let drawingCount = 0;
20
15
  try {
21
- const drawingsDir = path.join(DATA_DIR, "drawings");
22
- if (fs.existsSync(drawingsDir)) {
23
- drawingCount = fs.readdirSync(drawingsDir).filter((f) => f.endsWith(".json")).length;
16
+ const dir = path.join(DATA_DIR, "drawings");
17
+ if (fs.existsSync(dir)) {
18
+ drawingCount = fs.readdirSync(dir).filter((f) => f.endsWith(".json")).length;
24
19
  }
25
20
  } catch { /* ignore */ }
26
21
 
27
- // ── Banner ────────────────────────────────────────────────────────────────────
28
- const shortPath = DATA_DIR.length > 46 ? "..." + DATA_DIR.slice(-43) : DATA_DIR;
22
+ const shortPath = DATA_DIR.length > 48 ? "..." + DATA_DIR.slice(-45) : DATA_DIR;
29
23
 
30
- console.log(`
31
- ╔════════════════════════════════════════════════════╗
32
- ║ SketchBoard Uninstaller ║
33
- ╠════════════════════════════════════════════════════╣`);
24
+ // ── Banner ────────────────────────────────────────────────────────────────────
25
+ process.stdout.write("\n");
26
+ process.stdout.write(" ╔════════════════════════════════════════════════════╗\n");
27
+ process.stdout.write(" ║ SketchBoard Uninstaller ║\n");
28
+ process.stdout.write(" ╠════════════════════════════════════════════════════╣\n");
34
29
 
35
30
  if (exists && drawingCount > 0) {
36
- console.log(` ║
37
- ║ You have ${String(drawingCount).padEnd(3)} saved drawing(s) at: ║
38
- ║ ${shortPath.padEnd(50)}
39
- ║ ║`);
31
+ const label = ` ║ ${drawingCount} drawing(s) saved at:`;
32
+ process.stdout.write(label.padEnd(54) + "║\n");
33
+ process.stdout.write(` ║ ${shortPath.padEnd(50)} ║\n`);
40
34
  } else if (exists) {
41
- console.log(` ║
42
- ║ Data folder exists (no drawings saved yet): ║
43
- ║ ${shortPath.padEnd(50)} ║
44
- ║ ║`);
35
+ process.stdout.write(` ║ Data folder: ${shortPath.padEnd(37)}║\n`);
45
36
  } else {
46
- console.log(`
47
- ║ No data folder found — nothing to delete. ║
48
- ║ ║`);
37
+ process.stdout.write(" No data folder found — nothing to delete. ║\n");
49
38
  }
50
39
 
51
- console.log(` ╚════════════════════════════════════════════════════╝
52
- `);
53
-
54
- console.log(" How would you like to uninstall?\n");
55
- console.log(" [1] Soft uninstall — remove the app, keep your drawings (default)");
56
- console.log(" [2] Full uninstall — remove the app AND delete all drawings\n");
57
-
58
- // ── Prompt ────────────────────────────────────────────────────────────────────
59
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
60
-
61
- // Safety timeout — if no answer in 30s, default to soft uninstall
62
- const timeout = setTimeout(() => {
63
- rl.close();
64
- console.log("\n (Timed out — defaulting to soft uninstall. Your drawings are safe.)\n");
65
- process.exit(0);
66
- }, 30_000);
67
-
68
- rl.question(" Your choice (1 or 2, press Enter for 1): ", (answer) => {
69
- clearTimeout(timeout);
70
- rl.close();
40
+ process.stdout.write(" ╚════════════════════════════════════════════════════╝\n");
41
+ process.stdout.write("\n");
42
+ process.stdout.write(" [1] Soft uninstall — keep your drawings (default)\n");
43
+ process.stdout.write(" [2] Full uninstall delete all drawings\n");
44
+ process.stdout.write("\n");
45
+ process.stdout.write(" Press 1 or 2 (auto-selects 1 after 30 s): ");
46
+
47
+ // ── Read a single keypress from the real console ──────────────────────────────
48
+ // `choice` on Windows reads directly from CONIN$ (bypasses npm's stdin pipe).
49
+ // `bash /dev/tty` on Unix does the same.
50
+ function readChoice() {
51
+ if (process.platform === "win32") {
52
+ const r = spawnSync(
53
+ "choice",
54
+ ["/c", "12", "/n", "/t", "30", "/d", "1"],
55
+ { stdio: ["inherit", "pipe", "inherit"], timeout: 35_000 },
56
+ );
57
+ // choice exits with code 1 for key '1', code 2 for key '2'
58
+ return r.status === 2 ? "2" : "1";
59
+ }
71
60
 
72
- const choice = answer.trim();
61
+ // Unix: read one char directly from /dev/tty
62
+ const r = spawnSync(
63
+ "bash",
64
+ ["-c", "IFS= read -r -n1 ans </dev/tty && printf '%s' \"$ans\""],
65
+ { stdio: ["inherit", "pipe", "inherit"], timeout: 35_000 },
66
+ );
67
+ const ch = (r.stdout || "").toString().trim();
68
+ return ch === "2" ? "2" : "1";
69
+ }
73
70
 
74
- if (choice === "2") {
75
- console.log();
76
- if (exists) {
77
- try {
78
- fs.rmSync(DATA_DIR, { recursive: true, force: true });
79
- console.log(` Deleted ${DATA_DIR}`);
80
- if (drawingCount > 0) {
81
- console.log(` ✓ ${drawingCount} drawing(s) removed`);
82
- }
83
- } catch (err) {
84
- console.error(` Could not delete ${DATA_DIR}: ${err.message}`);
85
- console.error(" You can delete it manually in File Explorer.\n");
71
+ const answer = readChoice();
72
+ process.stdout.write(answer + "\n\n");
73
+
74
+ // ── Act on choice ─────────────────────────────────────────────────────────────
75
+ if (answer === "2") {
76
+ if (exists) {
77
+ try {
78
+ fs.rmSync(DATA_DIR, { recursive: true, force: true });
79
+ process.stdout.write(` ✓ Deleted ${DATA_DIR}\n`);
80
+ if (drawingCount > 0) {
81
+ process.stdout.write(` ${drawingCount} drawing(s) permanently removed\n`);
86
82
  }
87
- } else {
88
- console.log(" (No data folder found nothing to delete)");
83
+ } catch (err) {
84
+ process.stderr.write(` Could not delete ${DATA_DIR}: ${err.message}\n`);
85
+ process.stderr.write(" Delete it manually in File Explorer.\n");
89
86
  }
90
- console.log("\n Proceeding with full uninstall...\n");
91
87
  } else {
92
- console.log("\n Your drawings are safe.");
93
- console.log(" Proceeding with soft uninstall...\n");
88
+ process.stdout.write(" (No data folder to delete)\n");
94
89
  }
90
+ process.stdout.write(" Proceeding with full uninstall...\n\n");
91
+ } else {
92
+ process.stdout.write(" Your drawings are safe.\n");
93
+ process.stdout.write(" Proceeding with soft uninstall...\n\n");
94
+ }
95
95
 
96
- process.exit(0);
97
- });
96
+ process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sketchboard-app",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "SketchBoard — local-first whiteboard app. Run with: npx sketchboard-app",
5
5
  "main": "server.js",
6
6
  "bin": {