@workrail/cli 0.2.0
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 +7 -0
- package/bin/workrail.js +44 -0
- package/package.json +23 -0
- package/scripts/postinstall.mjs +129 -0
package/README.md
ADDED
package/bin/workrail.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { spawn } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
function resolveBinaryName() {
|
|
8
|
+
const platform = process.platform;
|
|
9
|
+
const arch = process.arch;
|
|
10
|
+
|
|
11
|
+
if (platform === "darwin" && arch === "arm64") return "workrail-darwin-arm64";
|
|
12
|
+
if (platform === "darwin" && arch === "x64") return "workrail-darwin-x64";
|
|
13
|
+
if (platform === "linux" && arch === "x64") return "workrail-linux-x64";
|
|
14
|
+
if (platform === "linux" && arch === "arm64") return "workrail-linux-arm64";
|
|
15
|
+
if (platform === "win32" && arch === "x64") return "workrail-windows-x64.exe";
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const binName = resolveBinaryName();
|
|
21
|
+
if (!binName) {
|
|
22
|
+
console.error(`Unsupported platform: ${process.platform} ${process.arch}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const binPath = path.join(__dirname, "native", binName);
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(binPath)) {
|
|
29
|
+
console.error("Workrail binary is not installed. Try reinstalling:");
|
|
30
|
+
console.error(" npm i -g @workrail/cli");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
35
|
+
|
|
36
|
+
child.on("error", (err) => {
|
|
37
|
+
console.error(`Failed to run Workrail binary: ${err.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
child.on("exit", (code, signal) => {
|
|
42
|
+
if (signal) process.exit(1);
|
|
43
|
+
process.exit(code ?? 1);
|
|
44
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workrail/cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Workrail CLI installer wrapper",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"bin": {
|
|
7
|
+
"workrail": "bin/workrail.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"postinstall": "node ./scripts/postinstall.mjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"scripts",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import https from "node:https";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const pkgPath = path.join(__dirname, "..", "package.json");
|
|
11
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
12
|
+
const version = pkg.version;
|
|
13
|
+
|
|
14
|
+
const baseUrl =
|
|
15
|
+
process.env.WORKRAIL_BINARY_BASE_URL ||
|
|
16
|
+
`https://cli.workrail.dev/workrail/v${version}`;
|
|
17
|
+
|
|
18
|
+
function resolveBinaryName() {
|
|
19
|
+
const platform = process.platform;
|
|
20
|
+
const arch = process.arch;
|
|
21
|
+
|
|
22
|
+
if (platform === "darwin" && arch === "arm64") return "workrail-darwin-arm64";
|
|
23
|
+
if (platform === "darwin" && arch === "x64") return "workrail-darwin-x64";
|
|
24
|
+
if (platform === "linux" && arch === "x64") return "workrail-linux-x64";
|
|
25
|
+
if (platform === "linux" && arch === "arm64") return "workrail-linux-arm64";
|
|
26
|
+
if (platform === "win32" && arch === "x64") return "workrail-windows-x64.exe";
|
|
27
|
+
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function downloadToFile(url, dest) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const file = fs.createWriteStream(dest);
|
|
34
|
+
https
|
|
35
|
+
.get(url, (res) => {
|
|
36
|
+
if (res.statusCode !== 200) {
|
|
37
|
+
reject(new Error(`Download failed (${res.statusCode}) for ${url}`));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
res.pipe(file);
|
|
41
|
+
file.on("finish", () => file.close(resolve));
|
|
42
|
+
})
|
|
43
|
+
.on("error", (err) => reject(err));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function downloadText(url) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
let data = "";
|
|
50
|
+
https
|
|
51
|
+
.get(url, (res) => {
|
|
52
|
+
if (res.statusCode !== 200) {
|
|
53
|
+
reject(new Error(`Download failed (${res.statusCode}) for ${url}`));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
res.setEncoding("utf8");
|
|
57
|
+
res.on("data", (chunk) => (data += chunk));
|
|
58
|
+
res.on("end", () => resolve(data));
|
|
59
|
+
})
|
|
60
|
+
.on("error", (err) => reject(err));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function sha256File(filePath) {
|
|
65
|
+
const hash = crypto.createHash("sha256");
|
|
66
|
+
const data = fs.readFileSync(filePath);
|
|
67
|
+
hash.update(data);
|
|
68
|
+
return hash.digest("hex");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function parseChecksums(text) {
|
|
72
|
+
const map = new Map();
|
|
73
|
+
for (const line of text.split("\n")) {
|
|
74
|
+
const trimmed = line.trim();
|
|
75
|
+
if (!trimmed) continue;
|
|
76
|
+
const parts = trimmed.split(/\s+/);
|
|
77
|
+
if (parts.length < 2) continue;
|
|
78
|
+
const hash = parts[0];
|
|
79
|
+
const file = parts[parts.length - 1];
|
|
80
|
+
map.set(file, hash);
|
|
81
|
+
}
|
|
82
|
+
return map;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function main() {
|
|
86
|
+
const binaryName = resolveBinaryName();
|
|
87
|
+
if (!binaryName) {
|
|
88
|
+
console.warn(
|
|
89
|
+
`[workrail] Unsupported platform (${process.platform} ${process.arch}). Skipping binary install.`,
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const nativeDir = path.join(__dirname, "..", "bin", "native");
|
|
95
|
+
fs.mkdirSync(nativeDir, { recursive: true });
|
|
96
|
+
|
|
97
|
+
const binUrl = `${baseUrl}/${binaryName}`;
|
|
98
|
+
const checksumsUrl = `${baseUrl}/checksums.txt`;
|
|
99
|
+
const targetPath = path.join(nativeDir, binaryName);
|
|
100
|
+
|
|
101
|
+
console.log(`[workrail] Downloading ${binaryName}...`);
|
|
102
|
+
await downloadToFile(binUrl, targetPath);
|
|
103
|
+
|
|
104
|
+
console.log("[workrail] Verifying checksum...");
|
|
105
|
+
const checksums = parseChecksums(await downloadText(checksumsUrl));
|
|
106
|
+
const expected = checksums.get(binaryName);
|
|
107
|
+
|
|
108
|
+
if (!expected) {
|
|
109
|
+
throw new Error(`No checksum entry found for ${binaryName}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const actual = sha256File(targetPath);
|
|
113
|
+
if (actual !== expected) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Checksum mismatch for ${binaryName}. expected=${expected} actual=${actual}`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (process.platform !== "win32") {
|
|
120
|
+
fs.chmodSync(targetPath, 0o755);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log("[workrail] Binary installed successfully.");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
main().catch((err) => {
|
|
127
|
+
console.error(`[workrail] postinstall failed: ${err.message}`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|