@iliasalmerekov/aegis 0.5.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/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @iliasalmerekov/aegis
2
+
3
+ NPM distribution wrapper for Aegis.
4
+
5
+ ```bash
6
+ npm i -g @iliasalmerekov/aegis
7
+ ```
8
+
9
+ The package downloads the correct Aegis GitHub Release binary for the current
10
+ Linux/macOS x64/arm64 host during `postinstall`, verifies SHA256, and exposes
11
+ the `aegis` command.
12
+
13
+ NPM installs the binary only. It does not edit `.bashrc`, `.zshrc`, Codex
14
+ configuration, or Claude configuration. After installation, run
15
+ `aegis install-hooks --all` if you want supported agent hooks, or configure
16
+ `SHELL` and `AEGIS_REAL_SHELL` explicitly for shell-proxy usage.
17
+
18
+ Native Windows shells are not supported; use Aegis from WSL2 on Windows.
package/bin/aegis.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawnSync } = require("node:child_process");
5
+ const path = require("node:path");
6
+
7
+ const binary = path.join(__dirname, "..", "vendor", process.platform === "win32" ? "aegis.exe" : "aegis");
8
+ const result = spawnSync(binary, process.argv.slice(2), {
9
+ stdio: "inherit"
10
+ });
11
+
12
+ if (result.error) {
13
+ console.error(`failed to run ${binary}: ${result.error.message}`);
14
+ process.exit(127);
15
+ }
16
+
17
+ if (result.signal) {
18
+ process.kill(process.pid, result.signal);
19
+ }
20
+
21
+ process.exit(result.status === null ? 1 : result.status);
package/checksums.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "release": "v0.5.6",
3
+ "repo": "IliasAlmerekov/aegis",
4
+ "assets": {
5
+ "aegis-linux-x86_64": "3af320804df191d3a10637e3da103dc306a5d573a85f1d740726d62c0826f683",
6
+ "aegis-linux-aarch64": "5e900632230750dff271d5816bd7c81a53158005d88c30ec439e59df871d0e31",
7
+ "aegis-macos-x86_64": "092d91e7b22800e68df8290707031beac531feb44bd02ddb0356ff082299ff2e",
8
+ "aegis-macos-aarch64": "8768865f2456c115788967ab29db790106e8a87fea8aa654561f8e942ec172b0"
9
+ }
10
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@iliasalmerekov/aegis",
3
+ "version": "0.5.6",
4
+ "description": "Terminal proxy that intercepts AI agent shell commands and requires human confirmation before destructive operations",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/IliasAlmerekov/aegis",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/IliasAlmerekov/aegis.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/IliasAlmerekov/aegis/issues"
13
+ },
14
+ "bin": {
15
+ "aegis": "bin/aegis.js"
16
+ },
17
+ "scripts": {
18
+ "postinstall": "node scripts/install.js",
19
+ "smoke": "node scripts/smoke.js"
20
+ },
21
+ "os": [
22
+ "darwin",
23
+ "linux"
24
+ ],
25
+ "cpu": [
26
+ "x64",
27
+ "arm64"
28
+ ],
29
+ "files": [
30
+ "bin/",
31
+ "scripts/",
32
+ "checksums.json",
33
+ "README.md"
34
+ ],
35
+ "keywords": [
36
+ "aegis",
37
+ "security",
38
+ "ai",
39
+ "shell",
40
+ "cli",
41
+ "safety"
42
+ ]
43
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+
3
+ const crypto = require("node:crypto");
4
+ const fs = require("node:fs");
5
+ const https = require("node:https");
6
+ const path = require("node:path");
7
+
8
+ const packageRoot = path.join(__dirname, "..");
9
+ const vendorDir = path.join(packageRoot, "vendor");
10
+ const binaryPath = path.join(vendorDir, "aegis");
11
+ const checksumsPath = path.join(packageRoot, "checksums.json");
12
+
13
+ const platform = process.env.AEGIS_NPM_PLATFORM || process.platform;
14
+ const arch = process.env.AEGIS_NPM_ARCH || process.arch;
15
+
16
+ const assets = {
17
+ "linux:x64": "aegis-linux-x86_64",
18
+ "linux:arm64": "aegis-linux-aarch64",
19
+ "darwin:x64": "aegis-macos-x86_64",
20
+ "darwin:arm64": "aegis-macos-aarch64"
21
+ };
22
+
23
+ function fail(message) {
24
+ console.error(message);
25
+ process.exit(1);
26
+ }
27
+
28
+ function readChecksums() {
29
+ const raw = fs.readFileSync(checksumsPath, "utf8");
30
+ return JSON.parse(raw);
31
+ }
32
+
33
+ function selectedAsset() {
34
+ const asset = assets[`${platform}:${arch}`];
35
+ if (!asset) {
36
+ fail(`Unsupported platform or architecture: ${platform}/${arch}`);
37
+ }
38
+ return asset;
39
+ }
40
+
41
+ function releaseUrl(checksums, asset) {
42
+ const repo = process.env.AEGIS_NPM_REPO || checksums.repo;
43
+ const release = process.env.AEGIS_NPM_RELEASE || checksums.release;
44
+ const baseUrl = process.env.AEGIS_NPM_BASE_URL || `https://github.com/${repo}/releases/download/${release}`;
45
+ return `${baseUrl}/${asset}`;
46
+ }
47
+
48
+ const MAX_REDIRECTS = 5;
49
+
50
+ function download(url, destination, redirects = 0) {
51
+ return new Promise((resolve, reject) => {
52
+ if (redirects > MAX_REDIRECTS) {
53
+ reject(new Error(`too many redirects for ${url}`));
54
+ return;
55
+ }
56
+
57
+ https.get(url, response => {
58
+ const status = response.statusCode;
59
+
60
+ // GitHub release asset URLs respond with 301/302/303/307/308 and a
61
+ // Location header pointing at release-assets.githubusercontent.com. Node's
62
+ // https.get does not follow redirects automatically, so follow them here.
63
+ if (status === 301 || status === 302 || status === 303 || status === 307 || status === 308) {
64
+ const location = response.headers.location;
65
+ response.resume();
66
+ if (!location) {
67
+ reject(new Error(`redirect ${status} without Location header from ${url}`));
68
+ return;
69
+ }
70
+ const nextUrl = new URL(location, url).toString();
71
+ download(nextUrl, destination, redirects + 1).then(resolve, reject);
72
+ return;
73
+ }
74
+
75
+ if (status !== 200) {
76
+ response.resume();
77
+ reject(new Error(`download failed with HTTP ${status}: ${url}`));
78
+ return;
79
+ }
80
+
81
+ const file = fs.createWriteStream(destination, { mode: 0o755 });
82
+ response.pipe(file);
83
+ file.on("finish", () => {
84
+ file.close(resolve);
85
+ });
86
+ file.on("error", error => {
87
+ fs.rmSync(destination, { force: true });
88
+ reject(error);
89
+ });
90
+ }).on("error", error => {
91
+ reject(error);
92
+ });
93
+ });
94
+ }
95
+
96
+ function sha256(filePath) {
97
+ const hash = crypto.createHash("sha256");
98
+ hash.update(fs.readFileSync(filePath));
99
+ return hash.digest("hex");
100
+ }
101
+
102
+ async function main() {
103
+ const checksums = readChecksums();
104
+ const asset = selectedAsset();
105
+ const expected = checksums.assets[asset];
106
+ if (!expected) {
107
+ fail(`missing SHA256 for ${asset}`);
108
+ }
109
+
110
+ fs.mkdirSync(vendorDir, { recursive: true });
111
+
112
+ if (process.env.AEGIS_NPM_SKIP_DOWNLOAD === "1") {
113
+ fs.writeFileSync(binaryPath, "#!/bin/sh\nprintf 'aegis test binary\\n'\n", { mode: 0o755 });
114
+ return;
115
+ }
116
+
117
+ const tmpPath = `${binaryPath}.tmp`;
118
+ await download(releaseUrl(checksums, asset), tmpPath);
119
+
120
+ const actual = sha256(tmpPath);
121
+ if (actual !== expected.toLowerCase()) {
122
+ fs.rmSync(tmpPath, { force: true });
123
+ fail(`SHA256 mismatch for ${asset}: expected ${expected}, got ${actual}`);
124
+ }
125
+
126
+ fs.renameSync(tmpPath, binaryPath);
127
+ fs.chmodSync(binaryPath, 0o755);
128
+ }
129
+
130
+ main().catch(error => {
131
+ fail(error.message);
132
+ });
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const path = require("node:path");
5
+
6
+ const shim = path.join(__dirname, "..", "bin", "aegis.js");
7
+ const result = spawnSync(process.execPath, [shim, "--version"], {
8
+ encoding: "utf8"
9
+ });
10
+
11
+ if (result.status !== 0) {
12
+ process.stderr.write(result.stderr);
13
+ process.stdout.write(result.stdout);
14
+ process.exit(result.status === null ? 1 : result.status);
15
+ }
16
+
17
+ if (!result.stdout.includes("aegis")) {
18
+ process.stderr.write(`expected aegis version output, got: ${result.stdout}`);
19
+ process.exit(1);
20
+ }