rainbo-cli 0.1.4

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rainbo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # rainbo-cli
2
+
3
+ Rainbo command line tools for data migration workflows.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 16+
8
+ - R with `Rscript` available on `PATH`
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install -g rainbo-cli
14
+ rainbo-cli --version
15
+ ```
16
+
17
+ ## Development
18
+
19
+ ```bash
20
+ Rscript src/rainbo-cli.R --version
21
+ npm run build:release
22
+ node scripts/run.js help
23
+ ```
24
+
25
+ ## Release
26
+
27
+ 1. Update `package.json` version.
28
+ 2. Commit the change.
29
+ 3. Run:
30
+
31
+ ```bash
32
+ bash scripts/tag-release.sh
33
+ ```
34
+
35
+ Pushing the `vX.Y.Z` tag triggers GitHub Actions to create GitHub Release
36
+ archives and publish the npm wrapper package.
37
+
38
+ Required repository secret:
39
+
40
+ - `NPM_TOKEN`: npm automation token with publish permission for `rainbo-cli`.
41
+
package/checksums.txt ADDED
@@ -0,0 +1,6 @@
1
+ cb7e4a240e532b2c52dbdd37596ccf3540ca9c9cfd54e2f0a5e5edb4ea8454c9 rainbo-cli-0.1.4-darwin-amd64.tar.gz
2
+ 608c5002eb6e4ab1b319562cb1433d549e57788aee5dbba249ce0afcfaf7912a rainbo-cli-0.1.4-darwin-arm64.tar.gz
3
+ 70230ae663d06aafe66c36d9f9e890fdaf3110c01f2369786062803904e8120c rainbo-cli-0.1.4-linux-amd64.tar.gz
4
+ 32e430c0d39775ffcdb433a0e1998f394509f581d9e4e0f19b9bbc73e65c6323 rainbo-cli-0.1.4-linux-arm64.tar.gz
5
+ 0adf480f6151eee0c2482454bfc74af4875aa14036d68254424068012bbc3ecc rainbo-cli-0.1.4-windows-amd64.zip
6
+ 0adf480f6151eee0c2482454bfc74af4875aa14036d68254424068012bbc3ecc rainbo-cli-0.1.4-windows-arm64.zip
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "rainbo-cli",
3
+ "version": "0.1.4",
4
+ "description": "Rainbo command line tools for data migration workflows",
5
+ "bin": {
6
+ "rainbo-cli": "scripts/run.js"
7
+ },
8
+ "scripts": {
9
+ "build:release": "bash scripts/build-release.sh",
10
+ "postinstall": "node scripts/install.js",
11
+ "test": "node scripts/run.js --version && node scripts/run.js help"
12
+ },
13
+ "os": [
14
+ "darwin",
15
+ "linux",
16
+ "win32"
17
+ ],
18
+ "cpu": [
19
+ "x64",
20
+ "arm64"
21
+ ],
22
+ "engines": {
23
+ "node": ">=16"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/work2a/rainbo-cli.git"
28
+ },
29
+ "license": "MIT",
30
+ "files": [
31
+ "scripts/install.js",
32
+ "scripts/run.js",
33
+ "checksums.txt",
34
+ "README.md",
35
+ "LICENSE"
36
+ ]
37
+ }
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+
3
+ const crypto = require("crypto");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const path = require("path");
7
+ const { execFileSync } = require("child_process");
8
+
9
+ const VERSION = require("../package.json").version.replace(/-.*$/, "");
10
+ const REPO = "work2a/rainbo-cli";
11
+ const NAME = "rainbo-cli";
12
+
13
+ const PLATFORM_MAP = {
14
+ darwin: "darwin",
15
+ linux: "linux",
16
+ win32: "windows",
17
+ };
18
+
19
+ const ARCH_MAP = {
20
+ x64: "amd64",
21
+ arm64: "arm64",
22
+ };
23
+
24
+ const platform = PLATFORM_MAP[process.platform];
25
+ const arch = ARCH_MAP[process.arch];
26
+ const isWindows = process.platform === "win32";
27
+ const ext = isWindows ? ".zip" : ".tar.gz";
28
+ const archiveName = `${NAME}-${VERSION}-${platform}-${arch}${ext}`;
29
+ const githubUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
30
+ const vendorDir = path.join(__dirname, "..", "vendor");
31
+ const installDir = path.join(vendorDir, NAME);
32
+
33
+ function download(url, destPath) {
34
+ execFileSync("curl", [
35
+ "--fail",
36
+ "--location",
37
+ "--silent",
38
+ "--show-error",
39
+ "--connect-timeout",
40
+ "10",
41
+ "--max-time",
42
+ "120",
43
+ "--max-redirs",
44
+ "3",
45
+ "--output",
46
+ destPath,
47
+ url,
48
+ ], { stdio: ["ignore", "ignore", "pipe"] });
49
+ }
50
+
51
+ function getExpectedChecksum(archive) {
52
+ const checksumsPath = path.join(__dirname, "..", "checksums.txt");
53
+ if (!fs.existsSync(checksumsPath)) {
54
+ console.error("[WARN] checksums.txt not found, skipping checksum verification");
55
+ return null;
56
+ }
57
+
58
+ const content = fs.readFileSync(checksumsPath, "utf8");
59
+ for (const line of content.split("\n")) {
60
+ const trimmed = line.trim();
61
+ if (!trimmed) continue;
62
+ const idx = trimmed.indexOf(" ");
63
+ if (idx === -1) continue;
64
+ if (trimmed.slice(idx + 2) === archive) return trimmed.slice(0, idx);
65
+ }
66
+
67
+ throw new Error(`Checksum entry not found for ${archive}`);
68
+ }
69
+
70
+ function verifyChecksum(archivePath, expectedHash) {
71
+ if (expectedHash === null) return;
72
+
73
+ const actual = crypto.createHash("sha256")
74
+ .update(fs.readFileSync(archivePath))
75
+ .digest("hex");
76
+
77
+ if (actual.toLowerCase() !== expectedHash.toLowerCase()) {
78
+ throw new Error(`Checksum mismatch for ${path.basename(archivePath)}`);
79
+ }
80
+ }
81
+
82
+ function extractArchive(archivePath, destDir) {
83
+ fs.rmSync(destDir, { recursive: true, force: true });
84
+ fs.mkdirSync(destDir, { recursive: true });
85
+
86
+ if (isWindows) {
87
+ const psCommand =
88
+ "$ErrorActionPreference='Stop';" +
89
+ "Expand-Archive -LiteralPath $env:RAINBO_CLI_ARCHIVE -DestinationPath $env:RAINBO_CLI_DEST -Force";
90
+ execFileSync("powershell.exe", [
91
+ "-NoProfile",
92
+ "-ExecutionPolicy",
93
+ "Bypass",
94
+ "-Command",
95
+ psCommand,
96
+ ], {
97
+ stdio: "inherit",
98
+ env: {
99
+ ...process.env,
100
+ RAINBO_CLI_ARCHIVE: archivePath,
101
+ RAINBO_CLI_DEST: destDir,
102
+ },
103
+ });
104
+ } else {
105
+ execFileSync("tar", ["-xzf", archivePath, "-C", destDir, "--strip-components", "1"], {
106
+ stdio: "inherit",
107
+ });
108
+ }
109
+ }
110
+
111
+ function install() {
112
+ if (!platform || !arch) {
113
+ throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`);
114
+ }
115
+
116
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `${NAME}-`));
117
+ const archivePath = path.join(tmpDir, archiveName);
118
+
119
+ try {
120
+ download(githubUrl, archivePath);
121
+ verifyChecksum(archivePath, getExpectedChecksum(archiveName));
122
+ extractArchive(archivePath, installDir);
123
+ console.log(`${NAME} v${VERSION} installed successfully`);
124
+ } finally {
125
+ fs.rmSync(tmpDir, { recursive: true, force: true });
126
+ }
127
+ }
128
+
129
+ if (require.main === module) {
130
+ const isNpxPostinstall = process.env.npm_command === "exec" && !process.env.RAINBO_CLI_RUN;
131
+ if (isNpxPostinstall) process.exit(0);
132
+
133
+ try {
134
+ install();
135
+ } catch (err) {
136
+ console.error(`Failed to install ${NAME}: ${err.message}`);
137
+ console.error(`Make sure the v${VERSION} GitHub Release exists and Rscript is installed.`);
138
+ process.exit(1);
139
+ }
140
+ }
141
+
142
+ module.exports = { getExpectedChecksum, verifyChecksum };
143
+
package/scripts/run.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("child_process");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const isWindows = process.platform === "win32";
8
+ const launcher = path.join(
9
+ __dirname,
10
+ "..",
11
+ "vendor",
12
+ "rainbo-cli",
13
+ isWindows ? "rainbo-cli.cmd" : "rainbo-cli"
14
+ );
15
+ const sourceEntry = path.join(__dirname, "..", "src", "rainbo-cli.R");
16
+
17
+ function installIfMissing() {
18
+ if (fs.existsSync(launcher)) return;
19
+ if (fs.existsSync(sourceEntry)) return;
20
+
21
+ const result = spawnSync(process.execPath, [path.join(__dirname, "install.js")], {
22
+ stdio: "inherit",
23
+ env: { ...process.env, RAINBO_CLI_RUN: "true" },
24
+ });
25
+
26
+ if (result.status !== 0) {
27
+ process.exit(result.status || 1);
28
+ }
29
+ }
30
+
31
+ installIfMissing();
32
+
33
+ const useSource = fs.existsSync(sourceEntry);
34
+ const command = useSource ? "Rscript" : launcher;
35
+ const args = useSource ? [sourceEntry, ...process.argv.slice(2)] : process.argv.slice(2);
36
+
37
+ const result = spawnSync(command, args, { stdio: "inherit", shell: isWindows });
38
+
39
+ if (result.error) {
40
+ console.error(result.error.message);
41
+ process.exit(1);
42
+ }
43
+
44
+ process.exit(result.status || 0);