@orionops/cli 0.1.0-beta.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/install.js +165 -0
- package/package.json +37 -0
package/install.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// OrionOps CLI — npm binary installer
|
|
3
|
+
// Copyright (c) 2026 Perseusoft. All rights reserved.
|
|
4
|
+
// https://orionops.tech
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
const crypto = require("crypto");
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const https = require("https");
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const { createWriteStream } = require("fs");
|
|
14
|
+
|
|
15
|
+
const REPO = "Perseusoft/orion";
|
|
16
|
+
const BINARY_NAME = "orion-cli";
|
|
17
|
+
const CHECKSUMS_FILE = "checksums.txt";
|
|
18
|
+
const VERSION = require("./package.json").version;
|
|
19
|
+
|
|
20
|
+
const TRUSTED_DOMAINS = [
|
|
21
|
+
"github.com",
|
|
22
|
+
"objects.githubusercontent.com",
|
|
23
|
+
"github-releases.githubusercontent.com",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function isTrustedUrl(url) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = new URL(url);
|
|
29
|
+
return TRUSTED_DOMAINS.some(
|
|
30
|
+
(d) => parsed.hostname === d || parsed.hostname.endsWith("." + d)
|
|
31
|
+
);
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getPlatform() {
|
|
38
|
+
const platform = os.platform();
|
|
39
|
+
switch (platform) {
|
|
40
|
+
case "darwin":
|
|
41
|
+
return "darwin";
|
|
42
|
+
case "linux":
|
|
43
|
+
return "linux";
|
|
44
|
+
case "win32":
|
|
45
|
+
return "windows";
|
|
46
|
+
default:
|
|
47
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getArch() {
|
|
52
|
+
const arch = os.arch();
|
|
53
|
+
switch (arch) {
|
|
54
|
+
case "x64":
|
|
55
|
+
return "amd64";
|
|
56
|
+
case "arm64":
|
|
57
|
+
return "arm64";
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture: ${arch}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function download(url) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const follow = (url, redirects = 0) => {
|
|
66
|
+
if (redirects > 5) return reject(new Error("Too many redirects"));
|
|
67
|
+
if (!isTrustedUrl(url)) {
|
|
68
|
+
return reject(
|
|
69
|
+
new Error(`Redirect to untrusted domain blocked: ${url}`)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
https
|
|
73
|
+
.get(url, (res) => {
|
|
74
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
75
|
+
return follow(res.headers.location, redirects + 1);
|
|
76
|
+
}
|
|
77
|
+
if (res.statusCode !== 200) {
|
|
78
|
+
return reject(new Error(`HTTP ${res.statusCode} from ${url}`));
|
|
79
|
+
}
|
|
80
|
+
const chunks = [];
|
|
81
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
82
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
83
|
+
res.on("error", reject);
|
|
84
|
+
})
|
|
85
|
+
.on("error", reject);
|
|
86
|
+
};
|
|
87
|
+
follow(url);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function main() {
|
|
92
|
+
const platform = getPlatform();
|
|
93
|
+
const arch = getArch();
|
|
94
|
+
const ext = platform === "windows" ? "zip" : "tar.gz";
|
|
95
|
+
const tag = `cli/v${VERSION}`;
|
|
96
|
+
const archiveName = `${BINARY_NAME}_${platform}_${arch}.${ext}`;
|
|
97
|
+
const url = `https://github.com/${REPO}/releases/download/${tag}/${archiveName}`;
|
|
98
|
+
|
|
99
|
+
const binDir = path.join(__dirname, "bin");
|
|
100
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
101
|
+
|
|
102
|
+
const binaryName = platform === "windows" ? "orion.exe" : "orion";
|
|
103
|
+
const binaryPath = path.join(binDir, binaryName);
|
|
104
|
+
|
|
105
|
+
console.log(`Downloading Orion CLI v${VERSION} for ${platform}/${arch}...`);
|
|
106
|
+
|
|
107
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "orion-cli-"));
|
|
108
|
+
const archivePath = path.join(tmpDir, archiveName);
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const archiveData = await download(url);
|
|
112
|
+
|
|
113
|
+
// Verify SHA-256 checksum against the published checksums file (F-02)
|
|
114
|
+
const checksumsUrl = `https://github.com/${REPO}/releases/download/${tag}/${CHECKSUMS_FILE}`;
|
|
115
|
+
const checksumsData = await download(checksumsUrl);
|
|
116
|
+
const checksumsText = checksumsData.toString("utf8");
|
|
117
|
+
const expectedLine = checksumsText
|
|
118
|
+
.split("\n")
|
|
119
|
+
.find((l) => l.includes(archiveName));
|
|
120
|
+
if (!expectedLine) {
|
|
121
|
+
console.error(`Checksum entry not found for ${archiveName}`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const expectedHash = expectedLine.split(/\s+/)[0];
|
|
125
|
+
const actualHash = crypto
|
|
126
|
+
.createHash("sha256")
|
|
127
|
+
.update(archiveData)
|
|
128
|
+
.digest("hex");
|
|
129
|
+
if (expectedHash !== actualHash) {
|
|
130
|
+
console.error(`Checksum verification FAILED!`);
|
|
131
|
+
console.error(` Expected: ${expectedHash}`);
|
|
132
|
+
console.error(` Got: ${actualHash}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
console.log("Checksum verified (SHA-256)");
|
|
136
|
+
|
|
137
|
+
fs.writeFileSync(archivePath, archiveData);
|
|
138
|
+
|
|
139
|
+
// Extract
|
|
140
|
+
if (ext === "tar.gz") {
|
|
141
|
+
execSync(`tar xzf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
142
|
+
} else {
|
|
143
|
+
execSync(`unzip -q "${archivePath}" -d "${tmpDir}"`, { stdio: "pipe" });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Find and copy binary
|
|
147
|
+
const extracted = path.join(tmpDir, binaryName);
|
|
148
|
+
if (!fs.existsSync(extracted)) {
|
|
149
|
+
throw new Error(`Binary not found in archive at ${extracted}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
fs.copyFileSync(extracted, binaryPath);
|
|
153
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
154
|
+
|
|
155
|
+
console.log(`Installed orion to ${binaryPath}`);
|
|
156
|
+
} finally {
|
|
157
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
main().catch((err) => {
|
|
162
|
+
console.error(`Failed to install Orion CLI: ${err.message}`);
|
|
163
|
+
console.error("You can install manually: https://orionops.tech/docs/cli");
|
|
164
|
+
process.exit(1);
|
|
165
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@orionops/cli",
|
|
3
|
+
"version": "0.1.0-beta.6",
|
|
4
|
+
"description": "OrionOps CLI — Specialized AI agents for code generation",
|
|
5
|
+
"homepage": "https://orionops.tech",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Perseusoft/orion.git",
|
|
9
|
+
"directory": "orion-cli"
|
|
10
|
+
},
|
|
11
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
12
|
+
"bin": {
|
|
13
|
+
"orion": "bin/orion"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"postinstall": "node install.js"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"orionops",
|
|
20
|
+
"cli",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"code-generation",
|
|
23
|
+
"mcp"
|
|
24
|
+
],
|
|
25
|
+
"os": [
|
|
26
|
+
"darwin",
|
|
27
|
+
"linux",
|
|
28
|
+
"win32"
|
|
29
|
+
],
|
|
30
|
+
"cpu": [
|
|
31
|
+
"x64",
|
|
32
|
+
"arm64"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16"
|
|
36
|
+
}
|
|
37
|
+
}
|