@s16e/hort 0.1.5
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 +114 -0
- package/package.json +30 -0
- package/run.js +14 -0
package/install.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { createWriteStream, mkdirSync, chmodSync, existsSync, unlinkSync } = require("fs");
|
|
5
|
+
const { execSync } = require("child_process");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const https = require("https");
|
|
8
|
+
const os = require("os");
|
|
9
|
+
|
|
10
|
+
const VERSION = require("./package.json").version;
|
|
11
|
+
const REPO = "sebastian-breitzke/hort";
|
|
12
|
+
|
|
13
|
+
const PLATFORM_MAP = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
14
|
+
const ARCH_MAP = { x64: "amd64", arm64: "arm64" };
|
|
15
|
+
|
|
16
|
+
function getBinaryName() {
|
|
17
|
+
return process.platform === "win32" ? "hort.exe" : "hort";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getArchiveUrl() {
|
|
21
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
22
|
+
const arch = ARCH_MAP[process.arch];
|
|
23
|
+
|
|
24
|
+
if (!platform || !arch) {
|
|
25
|
+
throw new Error(`Unsupported platform: ${process.platform}/${process.arch}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const ext = process.platform === "win32" ? "zip" : "tar.gz";
|
|
29
|
+
return `https://github.com/${REPO}/releases/download/v${VERSION}/hort_${VERSION}_${platform}_${arch}.${ext}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function download(url) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const follow = (url, redirects) => {
|
|
35
|
+
if (redirects > 5) return reject(new Error("Too many redirects"));
|
|
36
|
+
|
|
37
|
+
https.get(url, { headers: { "User-Agent": "hort-npm" } }, (res) => {
|
|
38
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
39
|
+
return follow(res.headers.location, redirects + 1);
|
|
40
|
+
}
|
|
41
|
+
if (res.statusCode !== 200) {
|
|
42
|
+
return reject(new Error(`Download failed: HTTP ${res.statusCode} from ${url}`));
|
|
43
|
+
}
|
|
44
|
+
resolve(res);
|
|
45
|
+
}).on("error", reject);
|
|
46
|
+
};
|
|
47
|
+
follow(url, 0);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function extractTarGz(stream, destDir) {
|
|
52
|
+
// All paths are script-controlled constants, no user input
|
|
53
|
+
const tmpFile = path.join(os.tmpdir(), `hort-${Date.now()}.tar.gz`);
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
const out = createWriteStream(tmpFile);
|
|
56
|
+
stream.pipe(out);
|
|
57
|
+
out.on("finish", resolve);
|
|
58
|
+
out.on("error", reject);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
execSync(`tar -xzf "${tmpFile}" -C "${destDir}" ${getBinaryName()}`, { stdio: "ignore" });
|
|
62
|
+
unlinkSync(tmpFile);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function extractZip(stream, destDir) {
|
|
66
|
+
// All paths are script-controlled constants, no user input
|
|
67
|
+
const tmpFile = path.join(os.tmpdir(), `hort-${Date.now()}.zip`);
|
|
68
|
+
await new Promise((resolve, reject) => {
|
|
69
|
+
const out = createWriteStream(tmpFile);
|
|
70
|
+
stream.pipe(out);
|
|
71
|
+
out.on("finish", resolve);
|
|
72
|
+
out.on("error", reject);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (process.platform === "win32") {
|
|
76
|
+
execSync(
|
|
77
|
+
`powershell -Command "Expand-Archive -Path '${tmpFile}' -DestinationPath '${destDir}' -Force"`,
|
|
78
|
+
{ stdio: "ignore" }
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
execSync(`unzip -o "${tmpFile}" ${getBinaryName()} -d "${destDir}"`, { stdio: "ignore" });
|
|
82
|
+
}
|
|
83
|
+
unlinkSync(tmpFile);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function main() {
|
|
87
|
+
const binDir = path.join(__dirname, "bin");
|
|
88
|
+
const binaryPath = path.join(binDir, getBinaryName());
|
|
89
|
+
|
|
90
|
+
if (existsSync(binaryPath)) {
|
|
91
|
+
return; // Already installed
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const url = getArchiveUrl();
|
|
95
|
+
console.log(`Downloading hort v${VERSION}...`);
|
|
96
|
+
|
|
97
|
+
mkdirSync(binDir, { recursive: true });
|
|
98
|
+
|
|
99
|
+
const stream = await download(url);
|
|
100
|
+
|
|
101
|
+
if (process.platform === "win32") {
|
|
102
|
+
await extractZip(stream, binDir);
|
|
103
|
+
} else {
|
|
104
|
+
await extractTarGz(stream, binDir);
|
|
105
|
+
chmodSync(binaryPath, 0o755);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log("hort installed successfully.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main().catch((err) => {
|
|
112
|
+
console.error(`Failed to install hort: ${err.message}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@s16e/hort",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Local secret and config store for humans and AI agents",
|
|
5
|
+
"keywords": ["secrets", "vault", "config", "cli", "ai-agents"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Sebastian Breitzke",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/sebastian-breitzke/hort.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/sebastian-breitzke/hort",
|
|
13
|
+
"bin": {
|
|
14
|
+
"hort": "run.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"postinstall": "node install.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"install.js",
|
|
21
|
+
"run.js",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"os": ["darwin", "linux", "win32"],
|
|
26
|
+
"cpu": ["x64", "arm64"],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=16"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/run.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const binaryName = process.platform === "win32" ? "hort.exe" : "hort";
|
|
8
|
+
const binaryPath = path.join(__dirname, "bin", binaryName);
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
execFileSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
|
12
|
+
} catch (err) {
|
|
13
|
+
process.exit(err.status || 1);
|
|
14
|
+
}
|