@frumu/tandem-tui 0.3.5 → 0.3.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/package.json +26 -26
- package/scripts/install.js +149 -149
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.6",
|
|
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
|
+
});
|