@frumu/tandem-tui 0.3.5 → 0.3.11
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 +1 -7
- package/bin/tandem-tui.js +91 -6
- package/package.json +26 -26
- package/scripts/install.js +149 -149
package/README.md
CHANGED
|
@@ -25,13 +25,7 @@ The installer downloads the release asset that matches this package version. Tag
|
|
|
25
25
|
|
|
26
26
|
## Quick Start
|
|
27
27
|
|
|
28
|
-
Start the
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
tandem-engine serve --hostname 127.0.0.1 --port 39731
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Start the TUI in another terminal:
|
|
28
|
+
Start the TUI in your terminal:
|
|
35
29
|
|
|
36
30
|
```bash
|
|
37
31
|
tandem-tui
|
package/bin/tandem-tui.js
CHANGED
|
@@ -1,17 +1,102 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require("path");
|
|
4
|
+
const https = require("https");
|
|
4
5
|
const { spawnSync } = require("child_process");
|
|
5
6
|
|
|
6
7
|
const binaryName = process.platform === "win32" ? "tandem-tui.exe" : "tandem-tui";
|
|
7
8
|
const binaryPath = path.join(__dirname, "native", binaryName);
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const packageInfo = require("../package.json");
|
|
11
|
+
const UPDATE_CHECK_TIMEOUT_MS = 1200;
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
function parseVersion(version) {
|
|
14
|
+
const core = String(version || "").split("-")[0];
|
|
15
|
+
return core.split(".").map((part) => {
|
|
16
|
+
const value = Number.parseInt(part, 10);
|
|
17
|
+
return Number.isFinite(value) ? value : 0;
|
|
18
|
+
});
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
function isNewerVersion(latest, current) {
|
|
22
|
+
const a = parseVersion(latest);
|
|
23
|
+
const b = parseVersion(current);
|
|
24
|
+
const length = Math.max(a.length, b.length);
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < length; i += 1) {
|
|
27
|
+
const left = a[i] || 0;
|
|
28
|
+
const right = b[i] || 0;
|
|
29
|
+
if (left > right) return true;
|
|
30
|
+
if (left < right) return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function fetchLatestVersion(packageName, timeoutMs) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const encodedName = encodeURIComponent(packageName);
|
|
39
|
+
const url = `https://registry.npmjs.org/${encodedName}/latest`;
|
|
40
|
+
const request = https.get(url, { headers: { Accept: "application/json" } }, (response) => {
|
|
41
|
+
if (response.statusCode !== 200) {
|
|
42
|
+
response.resume();
|
|
43
|
+
resolve(null);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let body = "";
|
|
48
|
+
response.setEncoding("utf8");
|
|
49
|
+
response.on("data", (chunk) => {
|
|
50
|
+
body += chunk;
|
|
51
|
+
});
|
|
52
|
+
response.on("end", () => {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(body);
|
|
55
|
+
resolve(typeof parsed.version === "string" ? parsed.version : null);
|
|
56
|
+
} catch {
|
|
57
|
+
resolve(null);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
request.on("error", () => resolve(null));
|
|
63
|
+
request.setTimeout(timeoutMs, () => {
|
|
64
|
+
request.destroy();
|
|
65
|
+
resolve(null);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function notifyIfUpdateAvailable() {
|
|
71
|
+
const latestVersion = await fetchLatestVersion(packageInfo.name, UPDATE_CHECK_TIMEOUT_MS);
|
|
72
|
+
if (!latestVersion || !isNewerVersion(latestVersion, packageInfo.version)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.error(`[${packageInfo.name}] Update available: ${packageInfo.version} -> ${latestVersion}`);
|
|
77
|
+
console.error(`Run: npm i -g ${packageInfo.name}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function main() {
|
|
81
|
+
await notifyIfUpdateAvailable();
|
|
82
|
+
|
|
83
|
+
const child = spawnSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
|
84
|
+
|
|
85
|
+
if (child.error) {
|
|
86
|
+
console.error("tandem-tui binary is missing. Reinstall with: npm i -g @frumu/tandem-tui");
|
|
87
|
+
console.error(child.error.message);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
process.exit(child.status ?? 1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main().catch(() => {
|
|
95
|
+
const child = spawnSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
|
96
|
+
if (child.error) {
|
|
97
|
+
console.error("tandem-tui binary is missing. Reinstall with: npm i -g @frumu/tandem-tui");
|
|
98
|
+
console.error(child.error.message);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
process.exit(child.status ?? 1);
|
|
102
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@frumu/tandem-tui",
|
|
3
|
-
"version": "0.3.
|
|
1
|
+
{
|
|
2
|
+
"name": "@frumu/tandem-tui",
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "Tandem TUI binary distribution",
|
|
5
5
|
"homepage": "https://tandem.frumu.ai",
|
|
6
6
|
"bin": {
|
|
@@ -9,26 +9,26 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"postinstall": "node scripts/install.js"
|
|
11
11
|
},
|
|
12
|
-
"files": [
|
|
13
|
-
"bin",
|
|
14
|
-
"scripts"
|
|
15
|
-
],
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/frumu-ai/tandem.git"
|
|
19
|
-
},
|
|
20
|
-
"author": "Frumu Ltd",
|
|
21
|
-
"license": "MIT OR Apache-2.0",
|
|
22
|
-
"publishConfig": {
|
|
23
|
-
"access": "public"
|
|
24
|
-
},
|
|
25
|
-
"os": [
|
|
26
|
-
"darwin",
|
|
27
|
-
"linux",
|
|
28
|
-
"win32"
|
|
29
|
-
],
|
|
30
|
-
"cpu": [
|
|
31
|
-
"x64",
|
|
32
|
-
"arm64"
|
|
33
|
-
]
|
|
34
|
-
}
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"scripts"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/frumu-ai/tandem.git"
|
|
19
|
+
},
|
|
20
|
+
"author": "Frumu Ltd",
|
|
21
|
+
"license": "MIT OR Apache-2.0",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"os": [
|
|
26
|
+
"darwin",
|
|
27
|
+
"linux",
|
|
28
|
+
"win32"
|
|
29
|
+
],
|
|
30
|
+
"cpu": [
|
|
31
|
+
"x64",
|
|
32
|
+
"arm64"
|
|
33
|
+
]
|
|
34
|
+
}
|
package/scripts/install.js
CHANGED
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const https = require('https');
|
|
4
|
-
const { execSync } = require('child_process');
|
|
5
|
-
|
|
6
|
-
const REPO = "frumu-ai/tandem";
|
|
7
|
-
const MIN_SIZE = 1024 * 1024;
|
|
8
|
-
|
|
9
|
-
const PLATFORM_MAP = {
|
|
10
|
-
'win32': { os: 'windows', ext: '.exe' },
|
|
11
|
-
'darwin': { os: 'darwin', ext: '' },
|
|
12
|
-
'linux': { os: 'linux', ext: '' }
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const ARCH_MAP = {
|
|
16
|
-
'x64': 'x64',
|
|
17
|
-
'arm64': 'arm64'
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function getArtifactInfo() {
|
|
21
|
-
const platform = PLATFORM_MAP[process.platform];
|
|
22
|
-
const arch = ARCH_MAP[process.arch];
|
|
23
|
-
|
|
24
|
-
if (!platform || !arch) {
|
|
25
|
-
throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let artifactName = `tandem-tui-${platform.os}-${arch}`;
|
|
29
|
-
if (platform.os === 'windows') {
|
|
30
|
-
artifactName += '.zip';
|
|
31
|
-
} else if (platform.os === 'darwin') {
|
|
32
|
-
artifactName += '.zip';
|
|
33
|
-
} else {
|
|
34
|
-
artifactName += '.tar.gz';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
artifactName,
|
|
39
|
-
binaryName: `tandem-tui${platform.ext}`,
|
|
40
|
-
isWindows: platform.os === 'windows'
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const { artifactName, binaryName, isWindows } = getArtifactInfo();
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const REPO = "frumu-ai/tandem";
|
|
7
|
+
const MIN_SIZE = 1024 * 1024;
|
|
8
|
+
|
|
9
|
+
const PLATFORM_MAP = {
|
|
10
|
+
'win32': { os: 'windows', ext: '.exe' },
|
|
11
|
+
'darwin': { os: 'darwin', ext: '' },
|
|
12
|
+
'linux': { os: 'linux', ext: '' }
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ARCH_MAP = {
|
|
16
|
+
'x64': 'x64',
|
|
17
|
+
'arm64': 'arm64'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function getArtifactInfo() {
|
|
21
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
22
|
+
const arch = ARCH_MAP[process.arch];
|
|
23
|
+
|
|
24
|
+
if (!platform || !arch) {
|
|
25
|
+
throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let artifactName = `tandem-tui-${platform.os}-${arch}`;
|
|
29
|
+
if (platform.os === 'windows') {
|
|
30
|
+
artifactName += '.zip';
|
|
31
|
+
} else if (platform.os === 'darwin') {
|
|
32
|
+
artifactName += '.zip';
|
|
33
|
+
} else {
|
|
34
|
+
artifactName += '.tar.gz';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
artifactName,
|
|
39
|
+
binaryName: `tandem-tui${platform.ext}`,
|
|
40
|
+
isWindows: platform.os === 'windows'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { artifactName, binaryName, isWindows } = getArtifactInfo();
|
|
45
45
|
const binDir = path.join(__dirname, '..', 'bin', 'native');
|
|
46
46
|
const destPath = path.join(binDir, binaryName);
|
|
47
|
-
|
|
48
|
-
if (!fs.existsSync(binDir)) {
|
|
49
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (fs.existsSync(destPath)) {
|
|
53
|
-
console.log("Binary already present.");
|
|
54
|
-
process.exit(0);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function fetchJson(url) {
|
|
58
|
-
return new Promise((resolve, reject) => {
|
|
59
|
-
https.get(url, { headers: { 'User-Agent': 'tandem-tui-installer' } }, (res) => {
|
|
60
|
-
if (res.statusCode !== 200) {
|
|
61
|
-
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
62
|
-
return fetchJson(res.headers.location).then(resolve).catch(reject);
|
|
63
|
-
}
|
|
64
|
-
return reject(new Error(`GitHub API HTTP ${res.statusCode}`));
|
|
65
|
-
}
|
|
66
|
-
let data = '';
|
|
67
|
-
res.on('data', chunk => data += chunk);
|
|
68
|
-
res.on('end', () => {
|
|
69
|
-
try { resolve(JSON.parse(data)); } catch (e) { reject(e); }
|
|
70
|
-
});
|
|
71
|
-
}).on('error', reject);
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function download() {
|
|
76
|
-
console.log(`Checking releases for ${REPO}...`);
|
|
77
|
-
const releases = await fetchJson(`https://api.github.com/repos/${REPO}/releases`);
|
|
78
|
-
|
|
79
|
-
const packageVersion = require('../package.json').version;
|
|
80
|
-
const targetTag = `v${packageVersion}`;
|
|
81
|
-
|
|
82
|
-
console.log(`Filtering releases for ${REPO} (Target: ${targetTag})...`);
|
|
83
|
-
let release = releases.find(r => r.tag_name === targetTag);
|
|
84
|
-
|
|
85
|
-
if (!release) {
|
|
86
|
-
console.warn(`Warning: No release found for tag ${targetTag}. Checking for latest compatible assets...`);
|
|
87
|
-
release = releases.find(r => r.assets.some(a => a.name === artifactName));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!release) {
|
|
91
|
-
console.error(`Status: No release found with asset ${artifactName}`);
|
|
92
|
-
console.error("Available assets in latest:", releases[0]?.assets?.map(a => a.name));
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const asset = release.assets.find(a => a.name === artifactName);
|
|
97
|
-
console.log(`Downloading ${asset.name} from ${release.tag_name}...`);
|
|
98
|
-
|
|
99
|
-
const file = fs.createWriteStream(path.join(binDir, artifactName));
|
|
100
|
-
|
|
101
|
-
return new Promise((resolve, reject) => {
|
|
102
|
-
const downloadUrl = asset.browser_download_url;
|
|
103
|
-
|
|
104
|
-
const request = (url) => {
|
|
105
|
-
https.get(url, { headers: { 'User-Agent': 'tandem-tui-installer' } }, (res) => {
|
|
106
|
-
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
107
|
-
return request(res.headers.location);
|
|
108
|
-
}
|
|
109
|
-
if (res.statusCode !== 200) return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
110
|
-
res.pipe(file);
|
|
111
|
-
file.on('finish', () => {
|
|
112
|
-
file.close();
|
|
113
|
-
resolve(path.join(binDir, artifactName));
|
|
114
|
-
});
|
|
115
|
-
}).on('error', err => {
|
|
116
|
-
fs.unlink(path.join(binDir, artifactName), () => { });
|
|
117
|
-
reject(err);
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
request(downloadUrl);
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function extract(archivePath) {
|
|
125
|
-
console.log("Extracting...");
|
|
126
|
-
if (isWindows) {
|
|
127
|
-
execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${binDir}' -Force"`);
|
|
128
|
-
} else {
|
|
129
|
-
if (artifactName.endsWith('.zip')) {
|
|
130
|
-
execSync(`unzip -o "${archivePath}" -d "${binDir}"`);
|
|
131
|
-
} else {
|
|
132
|
-
execSync(`tar -xzf "${archivePath}" -C "${binDir}"`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
fs.unlinkSync(archivePath);
|
|
137
|
-
|
|
138
|
-
if (fs.existsSync(destPath)) {
|
|
139
|
-
console.log("Verified binary extracted.");
|
|
140
|
-
if (!isWindows) fs.chmodSync(destPath, 0o755);
|
|
141
|
-
} else {
|
|
142
|
-
console.error("Binary not found at expected path:", destPath);
|
|
143
|
-
console.log("Files in bin:", fs.readdirSync(binDir));
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
download().then(extract).catch(err => {
|
|
149
|
-
console.error("Install failed:", err);
|
|
150
|
-
process.exit(1);
|
|
151
|
-
});
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(binDir)) {
|
|
49
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (fs.existsSync(destPath)) {
|
|
53
|
+
console.log("Binary already present.");
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function fetchJson(url) {
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
https.get(url, { headers: { 'User-Agent': 'tandem-tui-installer' } }, (res) => {
|
|
60
|
+
if (res.statusCode !== 200) {
|
|
61
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
62
|
+
return fetchJson(res.headers.location).then(resolve).catch(reject);
|
|
63
|
+
}
|
|
64
|
+
return reject(new Error(`GitHub API HTTP ${res.statusCode}`));
|
|
65
|
+
}
|
|
66
|
+
let data = '';
|
|
67
|
+
res.on('data', chunk => data += chunk);
|
|
68
|
+
res.on('end', () => {
|
|
69
|
+
try { resolve(JSON.parse(data)); } catch (e) { reject(e); }
|
|
70
|
+
});
|
|
71
|
+
}).on('error', reject);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function download() {
|
|
76
|
+
console.log(`Checking releases for ${REPO}...`);
|
|
77
|
+
const releases = await fetchJson(`https://api.github.com/repos/${REPO}/releases`);
|
|
78
|
+
|
|
79
|
+
const packageVersion = require('../package.json').version;
|
|
80
|
+
const targetTag = `v${packageVersion}`;
|
|
81
|
+
|
|
82
|
+
console.log(`Filtering releases for ${REPO} (Target: ${targetTag})...`);
|
|
83
|
+
let release = releases.find(r => r.tag_name === targetTag);
|
|
84
|
+
|
|
85
|
+
if (!release) {
|
|
86
|
+
console.warn(`Warning: No release found for tag ${targetTag}. Checking for latest compatible assets...`);
|
|
87
|
+
release = releases.find(r => r.assets.some(a => a.name === artifactName));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!release) {
|
|
91
|
+
console.error(`Status: No release found with asset ${artifactName}`);
|
|
92
|
+
console.error("Available assets in latest:", releases[0]?.assets?.map(a => a.name));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const asset = release.assets.find(a => a.name === artifactName);
|
|
97
|
+
console.log(`Downloading ${asset.name} from ${release.tag_name}...`);
|
|
98
|
+
|
|
99
|
+
const file = fs.createWriteStream(path.join(binDir, artifactName));
|
|
100
|
+
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const downloadUrl = asset.browser_download_url;
|
|
103
|
+
|
|
104
|
+
const request = (url) => {
|
|
105
|
+
https.get(url, { headers: { 'User-Agent': 'tandem-tui-installer' } }, (res) => {
|
|
106
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
107
|
+
return request(res.headers.location);
|
|
108
|
+
}
|
|
109
|
+
if (res.statusCode !== 200) return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
110
|
+
res.pipe(file);
|
|
111
|
+
file.on('finish', () => {
|
|
112
|
+
file.close();
|
|
113
|
+
resolve(path.join(binDir, artifactName));
|
|
114
|
+
});
|
|
115
|
+
}).on('error', err => {
|
|
116
|
+
fs.unlink(path.join(binDir, artifactName), () => { });
|
|
117
|
+
reject(err);
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
request(downloadUrl);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function extract(archivePath) {
|
|
125
|
+
console.log("Extracting...");
|
|
126
|
+
if (isWindows) {
|
|
127
|
+
execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${binDir}' -Force"`);
|
|
128
|
+
} else {
|
|
129
|
+
if (artifactName.endsWith('.zip')) {
|
|
130
|
+
execSync(`unzip -o "${archivePath}" -d "${binDir}"`);
|
|
131
|
+
} else {
|
|
132
|
+
execSync(`tar -xzf "${archivePath}" -C "${binDir}"`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fs.unlinkSync(archivePath);
|
|
137
|
+
|
|
138
|
+
if (fs.existsSync(destPath)) {
|
|
139
|
+
console.log("Verified binary extracted.");
|
|
140
|
+
if (!isWindows) fs.chmodSync(destPath, 0o755);
|
|
141
|
+
} else {
|
|
142
|
+
console.error("Binary not found at expected path:", destPath);
|
|
143
|
+
console.log("Files in bin:", fs.readdirSync(binDir));
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
download().then(extract).catch(err => {
|
|
149
|
+
console.error("Install failed:", err);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
});
|