restflow-cli 0.1.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 +30 -0
- package/bin/restflow +15 -0
- package/package.json +46 -0
- package/scripts/install.js +179 -0
- package/scripts/install.test.js +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# RestFlow CLI npm Package
|
|
2
|
+
|
|
3
|
+
This package provides the RestFlow CLI binary for multiple platforms.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g restflow-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
After installation, the `restflow` command will be available:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
restflow --help
|
|
17
|
+
restflow daemon start
|
|
18
|
+
restflow claude -p "Hello, world!"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Supported Platforms
|
|
22
|
+
|
|
23
|
+
- macOS (Intel & Apple Silicon)
|
|
24
|
+
- Linux (x64 & ARM64)
|
|
25
|
+
- Windows (x64)
|
|
26
|
+
|
|
27
|
+
## Links
|
|
28
|
+
|
|
29
|
+
- [GitHub Repository](https://github.com/lhwzds/restflow)
|
|
30
|
+
- [Documentation](https://docs.restflow.ai)
|
package/bin/restflow
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const binaryName = process.platform === "win32" ? "restflow.exe" : "restflow";
|
|
7
|
+
const binaryPath = path.join(__dirname, binaryName);
|
|
8
|
+
|
|
9
|
+
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
10
|
+
stdio: "inherit",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
child.on("exit", (code) => {
|
|
14
|
+
process.exit(code || 0);
|
|
15
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "restflow-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "RestFlow CLI - AI assistant that can execute workflows",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"workflow",
|
|
8
|
+
"cli",
|
|
9
|
+
"automation",
|
|
10
|
+
"agent",
|
|
11
|
+
"mcp"
|
|
12
|
+
],
|
|
13
|
+
"author": "Huaiwu Li",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/lhwzds/restflow.git"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/lhwzds/restflow",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/lhwzds/restflow/issues"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"restflow": "bin/restflow"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"postinstall": "node scripts/install.js",
|
|
28
|
+
"test": "node scripts/install.test.js"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=16"
|
|
32
|
+
},
|
|
33
|
+
"os": [
|
|
34
|
+
"darwin",
|
|
35
|
+
"linux",
|
|
36
|
+
"win32"
|
|
37
|
+
],
|
|
38
|
+
"cpu": [
|
|
39
|
+
"x64",
|
|
40
|
+
"arm64"
|
|
41
|
+
],
|
|
42
|
+
"files": [
|
|
43
|
+
"bin",
|
|
44
|
+
"scripts"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const crypto = require("crypto");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const VERSION = require("../package.json").version;
|
|
10
|
+
const REPO = "lhwzds/restflow";
|
|
11
|
+
|
|
12
|
+
const PLATFORM_MAP = {
|
|
13
|
+
darwin: {
|
|
14
|
+
x64: "x86_64-apple-darwin",
|
|
15
|
+
arm64: "aarch64-apple-darwin",
|
|
16
|
+
},
|
|
17
|
+
linux: {
|
|
18
|
+
x64: "x86_64-unknown-linux-gnu",
|
|
19
|
+
arm64: "aarch64-unknown-linux-gnu",
|
|
20
|
+
},
|
|
21
|
+
win32: {
|
|
22
|
+
x64: "x86_64-pc-windows-msvc",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function getPlatformTarget() {
|
|
27
|
+
const platform = process.platform;
|
|
28
|
+
const arch = process.arch;
|
|
29
|
+
|
|
30
|
+
const targets = PLATFORM_MAP[platform];
|
|
31
|
+
if (!targets) {
|
|
32
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const target = targets[arch];
|
|
36
|
+
if (!target) {
|
|
37
|
+
throw new Error(`Unsupported architecture: ${arch} on ${platform}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return target;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getDownloadUrl(target) {
|
|
44
|
+
const ext = process.platform === "win32" ? "zip" : "tar.gz";
|
|
45
|
+
return `https://github.com/${REPO}/releases/download/cli-v${VERSION}/restflow-${target}.${ext}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getChecksumUrl() {
|
|
49
|
+
return `https://github.com/${REPO}/releases/download/cli-v${VERSION}/checksums.txt`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function download(url) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
https
|
|
55
|
+
.get(url, (response) => {
|
|
56
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
57
|
+
download(response.headers.location).then(resolve).catch(reject);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (response.statusCode !== 200) {
|
|
62
|
+
reject(new Error(`Failed to download ${url}: ${response.statusCode}`));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const chunks = [];
|
|
67
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
68
|
+
response.on("end", () => resolve(Buffer.concat(chunks)));
|
|
69
|
+
response.on("error", reject);
|
|
70
|
+
})
|
|
71
|
+
.on("error", reject);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function computeSha256(buffer) {
|
|
76
|
+
return crypto.createHash("sha256").update(buffer).digest("hex");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseChecksums(text) {
|
|
80
|
+
const map = new Map();
|
|
81
|
+
for (const line of text.split("\n")) {
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
if (!trimmed) continue;
|
|
84
|
+
const parts = trimmed.split(/\s+/);
|
|
85
|
+
if (parts.length < 2) continue;
|
|
86
|
+
const hash = parts[0];
|
|
87
|
+
const filename = parts[1].replace(/^\*?/, "");
|
|
88
|
+
map.set(filename, hash);
|
|
89
|
+
}
|
|
90
|
+
return map;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function verifyChecksum(buffer, filename) {
|
|
94
|
+
const checksumUrl = getChecksumUrl();
|
|
95
|
+
const checksumText = (await download(checksumUrl)).toString("utf8");
|
|
96
|
+
const checksums = parseChecksums(checksumText);
|
|
97
|
+
const expected = checksums.get(filename);
|
|
98
|
+
if (!expected) {
|
|
99
|
+
throw new Error(`Checksum not found for ${filename}`);
|
|
100
|
+
}
|
|
101
|
+
const actual = computeSha256(buffer);
|
|
102
|
+
if (actual !== expected) {
|
|
103
|
+
throw new Error(`Checksum mismatch for ${filename}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function extractTarGz(buffer, destDir) {
|
|
108
|
+
const tmpFile = path.join(destDir, "tmp.tar.gz");
|
|
109
|
+
fs.writeFileSync(tmpFile, buffer);
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
execSync(`tar -xzf "${tmpFile}" -C "${destDir}"`, { stdio: "inherit" });
|
|
113
|
+
} finally {
|
|
114
|
+
fs.unlinkSync(tmpFile);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function extractZip(buffer, destDir) {
|
|
119
|
+
const tmpZip = path.join(destDir, "tmp.zip");
|
|
120
|
+
fs.writeFileSync(tmpZip, buffer);
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
if (process.platform === "win32") {
|
|
124
|
+
execSync(`powershell -command "Expand-Archive -Path '${tmpZip}' -DestinationPath '${destDir}' -Force"`, {
|
|
125
|
+
stdio: "inherit",
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
execSync(`unzip -o "${tmpZip}" -d "${destDir}"`, { stdio: "inherit" });
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
fs.unlinkSync(tmpZip);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function main() {
|
|
136
|
+
try {
|
|
137
|
+
const target = getPlatformTarget();
|
|
138
|
+
const url = getDownloadUrl(target);
|
|
139
|
+
const binDir = path.join(__dirname, "..", "bin");
|
|
140
|
+
const filename = path.basename(url);
|
|
141
|
+
|
|
142
|
+
console.log(`Downloading restflow for ${target}...`);
|
|
143
|
+
console.log(`URL: ${url}`);
|
|
144
|
+
|
|
145
|
+
const buffer = await download(url);
|
|
146
|
+
await verifyChecksum(buffer, filename);
|
|
147
|
+
|
|
148
|
+
if (!fs.existsSync(binDir)) {
|
|
149
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (process.platform === "win32") {
|
|
153
|
+
await extractZip(buffer, binDir);
|
|
154
|
+
} else {
|
|
155
|
+
await extractTarGz(buffer, binDir);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const binaryName = process.platform === "win32" ? "restflow.exe" : "restflow";
|
|
159
|
+
const binaryPath = path.join(binDir, binaryName);
|
|
160
|
+
|
|
161
|
+
if (process.platform !== "win32") {
|
|
162
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.log(`restflow installed successfully!`);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error(`Failed to install restflow: ${error.message}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (require.main === module) {
|
|
173
|
+
main();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
computeSha256,
|
|
178
|
+
parseChecksums,
|
|
179
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const assert = require("assert");
|
|
4
|
+
const { computeSha256, parseChecksums } = require("./install");
|
|
5
|
+
|
|
6
|
+
function testComputeSha256() {
|
|
7
|
+
const hash = computeSha256(Buffer.from("abc", "utf8"));
|
|
8
|
+
assert.strictEqual(
|
|
9
|
+
hash,
|
|
10
|
+
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function testParseChecksums() {
|
|
15
|
+
const text = `
|
|
16
|
+
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad restflow-x86_64-apple-darwin.tar.gz
|
|
17
|
+
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 restflow-x86_64-pc-windows-msvc.zip
|
|
18
|
+
`;
|
|
19
|
+
const map = parseChecksums(text);
|
|
20
|
+
assert.strictEqual(
|
|
21
|
+
map.get("restflow-x86_64-apple-darwin.tar.gz"),
|
|
22
|
+
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
|
23
|
+
);
|
|
24
|
+
assert.strictEqual(
|
|
25
|
+
map.get("restflow-x86_64-pc-windows-msvc.zip"),
|
|
26
|
+
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
testComputeSha256();
|
|
32
|
+
testParseChecksums();
|
|
33
|
+
console.log("install.js tests passed");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main();
|