beltsh 1.14.19 → 1.14.20
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/install.js +80 -35
- package/package.json +1 -1
- package/run.js +11 -5
package/install.js
CHANGED
|
@@ -4,7 +4,7 @@ const https = require("https");
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const os = require("os");
|
|
7
|
-
const
|
|
7
|
+
const zlib = require("zlib");
|
|
8
8
|
const crypto = require("crypto");
|
|
9
9
|
|
|
10
10
|
const MANIFEST_URL = "https://dist.inference.sh/cli/manifest.json";
|
|
@@ -22,7 +22,6 @@ if (!PLATFORM || !ARCH) {
|
|
|
22
22
|
const KEY = `${PLATFORM}-${ARCH}`;
|
|
23
23
|
|
|
24
24
|
function getInstallDir() {
|
|
25
|
-
// Same logic as the curl installer
|
|
26
25
|
if (process.platform === "win32") {
|
|
27
26
|
return path.join(os.homedir(), ".local", "bin");
|
|
28
27
|
}
|
|
@@ -51,6 +50,74 @@ function fetch(url) {
|
|
|
51
50
|
});
|
|
52
51
|
}
|
|
53
52
|
|
|
53
|
+
// Extract a single file matching `prefix` from a .zip buffer.
|
|
54
|
+
// ZIP central directory is at the end of the file — parse it to find entries.
|
|
55
|
+
function extractFromZip(buf, prefix) {
|
|
56
|
+
// Find End of Central Directory record (signature 0x06054b50)
|
|
57
|
+
let eocdOffset = -1;
|
|
58
|
+
for (let i = buf.length - 22; i >= 0; i--) {
|
|
59
|
+
if (buf.readUInt32LE(i) === 0x06054b50) {
|
|
60
|
+
eocdOffset = i;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (eocdOffset === -1) throw new Error("invalid zip: EOCD not found");
|
|
65
|
+
|
|
66
|
+
const cdOffset = buf.readUInt32LE(eocdOffset + 16);
|
|
67
|
+
const cdEntries = buf.readUInt16LE(eocdOffset + 10);
|
|
68
|
+
|
|
69
|
+
let pos = cdOffset;
|
|
70
|
+
for (let i = 0; i < cdEntries; i++) {
|
|
71
|
+
if (buf.readUInt32LE(pos) !== 0x02014b50) throw new Error("invalid zip: bad central dir");
|
|
72
|
+
const nameLen = buf.readUInt16LE(pos + 28);
|
|
73
|
+
const extraLen = buf.readUInt16LE(pos + 30);
|
|
74
|
+
const commentLen = buf.readUInt16LE(pos + 32);
|
|
75
|
+
const localOffset = buf.readUInt32LE(pos + 42);
|
|
76
|
+
const name = buf.toString("utf8", pos + 46, pos + 46 + nameLen);
|
|
77
|
+
|
|
78
|
+
if (name.startsWith(prefix)) {
|
|
79
|
+
// Read local file header at localOffset (signature 0x04034b50)
|
|
80
|
+
const lh = localOffset;
|
|
81
|
+
const lhNameLen = buf.readUInt16LE(lh + 26);
|
|
82
|
+
const lhExtraLen = buf.readUInt16LE(lh + 28);
|
|
83
|
+
const compMethod = buf.readUInt16LE(lh + 8);
|
|
84
|
+
const compSize = buf.readUInt32LE(lh + 18);
|
|
85
|
+
const dataStart = lh + 30 + lhNameLen + lhExtraLen;
|
|
86
|
+
const compressed = buf.subarray(dataStart, dataStart + compSize);
|
|
87
|
+
|
|
88
|
+
if (compMethod === 0) return { name, data: compressed };
|
|
89
|
+
if (compMethod === 8) return { name, data: zlib.inflateRawSync(compressed) };
|
|
90
|
+
throw new Error(`unsupported zip compression method: ${compMethod}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
pos += 46 + nameLen + extraLen + commentLen;
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Extract a single file matching `prefix` from a .tar.gz buffer.
|
|
99
|
+
function extractFromTarGz(buf, prefix) {
|
|
100
|
+
const tar = zlib.gunzipSync(buf);
|
|
101
|
+
let offset = 0;
|
|
102
|
+
while (offset < tar.length - 512) {
|
|
103
|
+
const header = tar.subarray(offset, offset + 512);
|
|
104
|
+
if (header[0] === 0) break; // end of archive
|
|
105
|
+
|
|
106
|
+
const name = header.toString("utf8", 0, 100).replace(/\0.*/, "");
|
|
107
|
+
const sizeStr = header.toString("utf8", 124, 136).replace(/\0.*/, "").trim();
|
|
108
|
+
const size = parseInt(sizeStr, 8) || 0;
|
|
109
|
+
const dataStart = offset + 512;
|
|
110
|
+
|
|
111
|
+
if (name.startsWith(prefix)) {
|
|
112
|
+
return { name, data: tar.subarray(dataStart, dataStart + size) };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Advance past header + data (rounded up to 512-byte blocks)
|
|
116
|
+
offset = dataStart + Math.ceil(size / 512) * 512;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
54
121
|
async function main() {
|
|
55
122
|
const installDir = getInstallDir();
|
|
56
123
|
console.log(`Downloading belt for ${PLATFORM}/${ARCH}...`);
|
|
@@ -71,42 +138,25 @@ async function main() {
|
|
|
71
138
|
process.exit(1);
|
|
72
139
|
}
|
|
73
140
|
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Extract
|
|
79
|
-
if (archivePath.endsWith(".zip")) {
|
|
80
|
-
if (process.platform === "win32") {
|
|
81
|
-
// bsdtar ships with Windows 10+ and extracts zip natively; unzip does not exist on Windows
|
|
82
|
-
execSync(`tar -xf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
83
|
-
} else {
|
|
84
|
-
execSync(`unzip -o "${archivePath}" -d "${tmpDir}"`, { stdio: "pipe" });
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
execSync(`tar -xzf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
88
|
-
}
|
|
141
|
+
// Extract binary — pure Node, no shell commands, no MSYS path mangling
|
|
142
|
+
const entry = build.url.endsWith(".zip")
|
|
143
|
+
? extractFromZip(archive, "inferencesh-cli")
|
|
144
|
+
: extractFromTarGz(archive, "inferencesh-cli");
|
|
89
145
|
|
|
90
|
-
|
|
91
|
-
const ext = PLATFORM === "windows" ? ".exe" : "";
|
|
92
|
-
const files = fs.readdirSync(tmpDir).filter((f) => f.startsWith("inferencesh-cli"));
|
|
93
|
-
if (files.length === 0) {
|
|
146
|
+
if (!entry) {
|
|
94
147
|
console.error("Binary not found in archive");
|
|
95
148
|
process.exit(1);
|
|
96
149
|
}
|
|
97
150
|
|
|
98
151
|
// Install to persistent location
|
|
152
|
+
const ext = PLATFORM === "windows" ? ".exe" : "";
|
|
99
153
|
fs.mkdirSync(installDir, { recursive: true });
|
|
100
|
-
const src = path.join(tmpDir, files[0]);
|
|
101
154
|
const dest = path.join(installDir, `belt${ext}`);
|
|
102
155
|
|
|
103
156
|
// Remove any existing file/symlink first — copyFileSync follows symlinks,
|
|
104
157
|
// which corrupts installs where an older installer left belt as a symlink.
|
|
105
158
|
try { fs.unlinkSync(dest); } catch {}
|
|
106
|
-
fs.
|
|
107
|
-
if (PLATFORM !== "windows") {
|
|
108
|
-
fs.chmodSync(dest, 0o755);
|
|
109
|
-
}
|
|
159
|
+
fs.writeFileSync(dest, entry.data, { mode: PLATFORM === "windows" ? undefined : 0o755 });
|
|
110
160
|
|
|
111
161
|
// Create aliases (same as curl installer). Symlinks require elevation on
|
|
112
162
|
// Windows, so fall back to copying the binary there.
|
|
@@ -120,21 +170,16 @@ async function main() {
|
|
|
120
170
|
}
|
|
121
171
|
}
|
|
122
172
|
|
|
123
|
-
//
|
|
124
|
-
fs.rmSync(tmpDir, { recursive: true });
|
|
125
|
-
|
|
126
|
-
// Also install into npm bin/ so run.js works for npm install -g
|
|
173
|
+
// Also install into npm bin/ so run.js works for npx / npm install -g
|
|
127
174
|
const npmBin = path.join(__dirname, "bin");
|
|
128
175
|
fs.mkdirSync(npmBin, { recursive: true });
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
fs.chmodSync(path.join(npmBin, `belt${ext}`), 0o755);
|
|
132
|
-
}
|
|
176
|
+
const npmDest = path.join(npmBin, `belt${ext}`);
|
|
177
|
+
fs.writeFileSync(npmDest, entry.data, { mode: PLATFORM === "windows" ? undefined : 0o755 });
|
|
133
178
|
|
|
134
179
|
console.log(`Installed belt ${manifest.version} to ${installDir}`);
|
|
135
180
|
}
|
|
136
181
|
|
|
137
182
|
main().catch((err) => {
|
|
138
|
-
console.error("
|
|
183
|
+
console.error("belt installation failed:", err.message);
|
|
139
184
|
process.exit(1);
|
|
140
185
|
});
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { spawn } = require("child_process");
|
|
4
|
+
const { existsSync } = require("fs");
|
|
4
5
|
const path = require("path");
|
|
5
6
|
|
|
6
7
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
7
8
|
const bin = path.join(__dirname, "bin", `belt${ext}`);
|
|
8
9
|
|
|
10
|
+
if (!existsSync(bin)) {
|
|
11
|
+
console.error(
|
|
12
|
+
"belt binary not found at " + bin + "\n" +
|
|
13
|
+
"This can happen on Git Bash/MSYS — install directly instead:\n" +
|
|
14
|
+
" curl -fsSL https://dist.inference.sh/install.sh | sh"
|
|
15
|
+
);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
const child = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
10
20
|
child.on("error", (err) => {
|
|
11
|
-
|
|
12
|
-
console.error("belt binary not found. Try reinstalling: npm install @inferencesh/belt");
|
|
13
|
-
} else {
|
|
14
|
-
console.error(err.message);
|
|
15
|
-
}
|
|
21
|
+
console.error(err.message);
|
|
16
22
|
process.exit(1);
|
|
17
23
|
});
|
|
18
24
|
child.on("exit", (code) => process.exit(code ?? 1));
|