clidesk 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  CliDesk is a local desktop dashboard for managing terminal sessions, files, and Git repositories — built with **Tauri v2** + **React** + **TypeScript** + **Rust**.
8
8
 
9
- This npm package is the launcher/downloader for the CliDesk desktop app.
9
+ This npm package contains the CliDesk desktop app binary and a native Windows launcher.
10
10
 
11
11
  ## Install
12
12
 
@@ -20,7 +20,7 @@ npm i -g clidesk
20
20
  clidesk
21
21
  ```
22
22
 
23
- The launcher will find and open the CliDesk desktop app.
23
+ The launcher copies the bundled binaries into a per-version runtime cache and opens CliDesk from there.
24
24
 
25
25
  ## Requirements
26
26
 
@@ -30,11 +30,11 @@ The launcher will find and open the CliDesk desktop app.
30
30
 
31
31
  ## How it works
32
32
 
33
- 1. During `npm i -g clidesk`, the postinstall script checks for the CliDesk binary in `vendor/clidesk.exe`.
34
- 2. If the binary is missing, instructions are shown to download it from GitHub Releases.
35
- 3. When you run `clidesk`, the launcher spawns the desktop app.
33
+ 1. During `npm i -g clidesk`, the postinstall script checks that `vendor/clidesk.exe` and `vendor/clidesk-launcher.exe` are bundled.
34
+ 2. When you run `clidesk`, the npm wrapper copies both binaries to `%LOCALAPPDATA%\CliDesk\npm-runtime\<version>\`.
35
+ 3. The native launcher starts CliDesk from that runtime directory, not from `node_modules`.
36
36
 
37
- This npm package is only the launcher. The CliDesk desktop app itself is a Tauri application built from the [source repository](https://github.com/vykelongthuong/CliDesk).
37
+ The CliDesk desktop app itself is a Tauri application built from the [source repository](https://github.com/vykelongthuong/CliDesk).
38
38
 
39
39
  ## License
40
40
 
package/bin/clidesk.js CHANGED
@@ -1,61 +1,166 @@
1
1
  #!/usr/bin/env node
2
- // CliDesk npm launcher — spawns the CliDesk desktop app
2
+ // CliDesk npm launcher.
3
3
  //
4
- // Usage:
5
- // clidesk → launch CliDesk
6
- //
7
- // Priority:
8
- // 1. vendor/clidesk-launcher.exe (native launcher with menu)
9
- // 2. vendor/clidesk.exe (direct app binary)
10
- //
11
- // The launcher offers interactive menu (hidden/visible terminal).
12
- // If the launcher is absent, the app is spawned directly.
4
+ // The package stores signed binaries in vendor/, but it never runs them from
5
+ // node_modules. Each package version is copied to a runtime cache first so npm
6
+ // can update or uninstall the global package without Windows keeping vendor/
7
+ // locked by a running desktop process.
13
8
 
14
- const { spawn } = require('child_process');
15
- const path = require('path');
16
9
  const fs = require('fs');
10
+ const path = require('path');
11
+ const { execFileSync, spawn } = require('child_process');
12
+
13
+ const args = process.argv.slice(2);
14
+ const debug = args.includes('--debug-launch');
15
+
16
+ const packageRoot = path.resolve(__dirname, '..');
17
+ const pkg = require(path.join(packageRoot, 'package.json'));
18
+ const version = pkg.version;
19
+
20
+ const vendorDir = path.join(packageRoot, 'vendor');
21
+ const runtimeBase = process.env.LOCALAPPDATA || process.env.TEMP;
17
22
 
18
- // ── Locate binaries ─────────────────────────────────────────────
19
- const vendorDir = path.join(__dirname, '..', 'vendor');
20
- const launcherPath = path.join(vendorDir, 'clidesk-launcher.exe');
21
- const appPath = path.join(vendorDir, 'clidesk.exe');
22
-
23
- let targetPath;
24
- let targetName;
25
-
26
- if (fs.existsSync(launcherPath)) {
27
- targetPath = launcherPath;
28
- targetName = 'clidesk-launcher.exe';
29
- } else if (fs.existsSync(appPath)) {
30
- targetPath = appPath;
31
- targetName = 'clidesk.exe';
32
- } else {
33
- console.error('[CliDesk] Binary not found.');
34
- console.error('[CliDesk] Try reinstalling: npm i -g clidesk');
35
- console.error('[CliDesk] Or download clidesk.exe from GitHub Releases');
36
- console.error('[CliDesk] and place it in: ' + vendorDir);
23
+ if (!runtimeBase) {
24
+ console.error('[CliDesk] Không thể xác định LOCALAPPDATA hoặc TEMP.');
37
25
  process.exit(1);
38
26
  }
39
27
 
40
- // ── Forward all args ────────────────────────────────────────────
41
- const args = process.argv.slice(2);
28
+ const runtimeDir = path.join(runtimeBase, 'CliDesk', 'npm-runtime', version);
42
29
 
43
- // ── Spawn ───────────────────────────────────────────────────────
44
- //
45
- // stdio: "inherit" — let the launcher/app use this terminal.
46
- // windowsHide: false don't suppress console windows.
47
- // The native launcher manages its own console window (hidden/visible).
30
+ const vendorApp = path.join(vendorDir, 'clidesk.exe');
31
+ const vendorLauncher = path.join(vendorDir, 'clidesk-launcher.exe');
32
+
33
+ const runtimeApp = path.join(runtimeDir, 'clidesk.exe');
34
+ const runtimeLauncher = path.join(runtimeDir, 'clidesk-launcher.exe');
35
+ const latestVersion = readLatestVersion();
36
+ const updateAvailable = latestVersion ? isVersionNewer(latestVersion, version) : false;
37
+
38
+ function ensureFileExists(filePath, label) {
39
+ if (!fs.existsSync(filePath)) {
40
+ throw new Error(`${label} không tồn tại: ${filePath}`);
41
+ }
42
+ }
43
+
44
+ function copyIfMissing(src, dest) {
45
+ ensureFileExists(src, 'Binary nguồn');
46
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
47
+
48
+ if (fs.existsSync(dest)) {
49
+ return;
50
+ }
51
+
52
+ const tmpDest = `${dest}.tmp-${process.pid}`;
53
+ try {
54
+ fs.copyFileSync(src, tmpDest);
55
+ fs.renameSync(tmpDest, dest);
56
+ } catch (err) {
57
+ try {
58
+ if (fs.existsSync(tmpDest)) {
59
+ fs.unlinkSync(tmpDest);
60
+ }
61
+ } catch (_) {
62
+ // Best-effort cleanup only.
63
+ }
64
+ throw err;
65
+ }
66
+ }
67
+
68
+ function printDebugInfo() {
69
+ console.log('[CliDesk] packageRoot:', packageRoot);
70
+ console.log('[CliDesk] vendorDir:', vendorDir);
71
+ console.log('[CliDesk] runtimeDir:', runtimeDir);
72
+ console.log('[CliDesk] launcherPath:', runtimeLauncher);
73
+ console.log('[CliDesk] appPath:', runtimeApp);
74
+ console.log('[CliDesk] version:', version);
75
+ console.log('[CliDesk] latestVersion:', latestVersion || '(unknown)');
76
+ console.log('[CliDesk] updateAvailable:', updateAvailable ? 'true' : 'false');
77
+ }
78
+
79
+ function readLatestVersion() {
80
+ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
81
+ try {
82
+ const output = execFileSync(npmCommand, ['view', 'clidesk', 'version', '--silent'], {
83
+ encoding: 'utf8',
84
+ timeout: 5000,
85
+ windowsHide: true,
86
+ stdio: ['ignore', 'pipe', 'ignore'],
87
+ });
88
+ const latest = output.trim();
89
+ return latest || null;
90
+ } catch (_) {
91
+ return null;
92
+ }
93
+ }
94
+
95
+ function isVersionNewer(latest, current) {
96
+ const latestParts = parseVersion(latest);
97
+ const currentParts = parseVersion(current);
98
+ for (let index = 0; index < 3; index += 1) {
99
+ if (latestParts[index] > currentParts[index]) {
100
+ return true;
101
+ }
102
+ if (latestParts[index] < currentParts[index]) {
103
+ return false;
104
+ }
105
+ }
106
+ return false;
107
+ }
108
+
109
+ function parseVersion(value) {
110
+ const parts = String(value)
111
+ .split(/[.+-]/)
112
+ .slice(0, 3)
113
+ .map((part) => {
114
+ const parsed = Number.parseInt(part, 10);
115
+ return Number.isFinite(parsed) ? parsed : 0;
116
+ });
48
117
 
49
- const child = spawn(targetPath, args, {
50
- stdio: 'inherit',
51
- windowsHide: false,
52
- });
118
+ while (parts.length < 3) {
119
+ parts.push(0);
120
+ }
53
121
 
54
- child.on('exit', (code) => {
55
- process.exit(code ?? 0);
56
- });
122
+ return parts;
123
+ }
124
+
125
+ function main() {
126
+ copyIfMissing(vendorApp, runtimeApp);
127
+ copyIfMissing(vendorLauncher, runtimeLauncher);
128
+
129
+ if (debug) {
130
+ printDebugInfo();
131
+ }
132
+
133
+ const child = spawn(runtimeLauncher, args, {
134
+ cwd: runtimeDir,
135
+ env: {
136
+ ...process.env,
137
+ CLIDESK_VERSION: version,
138
+ CLIDESK_LATEST_VERSION: latestVersion || '',
139
+ CLIDESK_UPDATE_AVAILABLE: updateAvailable ? '1' : '0',
140
+ CLIDESK_UPDATE_COMMAND: 'npm i -g clidesk',
141
+ },
142
+ stdio: 'inherit',
143
+ windowsHide: false,
144
+ });
57
145
 
58
- child.on('error', (err) => {
59
- console.error('[CliDesk] Failed to start:', err.message);
146
+ child.on('exit', (code) => {
147
+ process.exit(code ?? 0);
148
+ });
149
+
150
+ child.on('error', (err) => {
151
+ console.error('[CliDesk] Không thể chạy launcher:', err.message);
152
+ console.error('[CliDesk] Path:', runtimeLauncher);
153
+ process.exit(1);
154
+ });
155
+ }
156
+
157
+ try {
158
+ main();
159
+ } catch (err) {
160
+ console.error('[CliDesk] Không thể chuẩn bị runtime CliDesk.');
161
+ console.error('[CliDesk] Lỗi:', err && err.message ? err.message : err);
162
+ if (debug) {
163
+ printDebugInfo();
164
+ }
60
165
  process.exit(1);
61
- });
166
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clidesk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CliDesk desktop app launcher — install with npm i -g clidesk",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,66 +1,40 @@
1
- // CliDesk postinstall script
1
+ // CliDesk postinstall script.
2
2
  //
3
- // Responsibilities:
4
- // 1. Detect platform (win32 x64)
5
- // 2. Ensure vendor/ directory exists
6
- // 3. Check if vendor/clidesk.exe exists
7
- // 4. If not, provide clear download instructions
8
- //
9
- // No admin required. No process spawned. No downloads.
3
+ // It only validates that the package contains the Windows binaries needed by
4
+ // bin/clidesk.js. It does not launch the app, copy runtime files, download
5
+ // binaries, request admin rights, or use credentials.
10
6
 
11
7
  const fs = require('fs');
12
8
  const path = require('path');
13
9
 
14
- const VENDOR_DIR = path.join(__dirname, '..', 'vendor');
15
- const APP_BINARY = path.join(VENDOR_DIR, 'clidesk.exe');
10
+ const vendorDir = path.join(__dirname, '..', 'vendor');
11
+ const requiredBinaries = [
12
+ path.join(vendorDir, 'clidesk.exe'),
13
+ path.join(vendorDir, 'clidesk-launcher.exe'),
14
+ ];
16
15
 
17
16
  function main() {
18
- // ── Platform check ──────────────────────────────────────
19
17
  if (process.platform !== 'win32') {
20
18
  console.warn('[CliDesk] This package only supports Windows x64.');
21
- console.warn('[CliDesk] Skipping binary setup.');
22
19
  return;
23
20
  }
24
21
 
25
22
  if (process.arch !== 'x64') {
26
23
  console.warn('[CliDesk] This package only supports x64 architecture.');
27
- console.warn('[CliDesk] Skipping binary setup.');
28
24
  return;
29
25
  }
30
26
 
31
- // ── Ensure vendor directory ─────────────────────────────
32
- if (!fs.existsSync(VENDOR_DIR)) {
33
- fs.mkdirSync(VENDOR_DIR, { recursive: true });
34
- console.log('[CliDesk] Created vendor directory.');
35
- }
36
-
37
- // ── Check for existing binary ───────────────────────────
38
- if (fs.existsSync(APP_BINARY)) {
39
- console.log('[CliDesk] Binary found in vendor/.');
40
- return;
27
+ const missing = requiredBinaries.filter((filePath) => !fs.existsSync(filePath));
28
+ if (missing.length > 0) {
29
+ console.error('[CliDesk] Package is missing required binaries:');
30
+ for (const filePath of missing) {
31
+ console.error('[CliDesk] Missing:', filePath);
32
+ }
33
+ console.error('[CliDesk] Please reinstall with: npm i -g clidesk');
34
+ process.exit(1);
41
35
  }
42
36
 
43
- // ── Binary missing — instructions ───────────────────────
44
- console.log('');
45
- console.log('╔══════════════════════════════════════════════╗');
46
- console.log('║ CliDesk Binary Setup ║');
47
- console.log('╠══════════════════════════════════════════════╣');
48
- console.log('║ ║');
49
- console.log('║ CliDesk binary is not bundled yet. ║');
50
- console.log('║ ║');
51
- console.log('║ To complete setup: ║');
52
- console.log('║ ║');
53
- console.log('║ 1. Download clidesk.exe from: ║');
54
- console.log('║ GitHub Releases ║');
55
- console.log('║ https://github.com/vykelongthuong/CliDesk ║');
56
- console.log('║ ║');
57
- console.log('║ 2. Place it in: ║');
58
- console.log('║ ' + VENDOR_DIR.padEnd(42) + '║');
59
- console.log('║ ║');
60
- console.log('║ 3. Run: clidesk ║');
61
- console.log('║ ║');
62
- console.log('╚══════════════════════════════════════════════╝');
63
- console.log('');
37
+ console.log('[CliDesk] Vendor binaries found.');
64
38
  }
65
39
 
66
40
  main();
Binary file
Binary file