@dean0x/mino 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/bin/mino.js +132 -0
- package/install.js +214 -0
- package/package.json +42 -0
package/bin/mino.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
7
|
+
const BINARY_NAME = process.platform === "win32" ? "mino.exe" : "mino";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Platform-specific package mapping
|
|
11
|
+
*/
|
|
12
|
+
const PLATFORM_PACKAGES = {
|
|
13
|
+
"darwin-x64": "@dean0x/mino-darwin-x64",
|
|
14
|
+
"darwin-arm64": "@dean0x/mino-darwin-arm64",
|
|
15
|
+
"linux-x64": "@dean0x/mino-linux-x64",
|
|
16
|
+
"linux-arm64": "@dean0x/mino-linux-arm64",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the platform key for the current system
|
|
21
|
+
* @returns {string | null}
|
|
22
|
+
*/
|
|
23
|
+
function getPlatformKey() {
|
|
24
|
+
const platform = process.platform;
|
|
25
|
+
const arch = process.arch;
|
|
26
|
+
|
|
27
|
+
if (platform === "darwin" && arch === "x64") return "darwin-x64";
|
|
28
|
+
if (platform === "darwin" && arch === "arm64") return "darwin-arm64";
|
|
29
|
+
if (platform === "linux" && arch === "x64") return "linux-x64";
|
|
30
|
+
if (platform === "linux" && arch === "arm64") return "linux-arm64";
|
|
31
|
+
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Try to resolve binary from optional dependencies
|
|
37
|
+
* @returns {string | null}
|
|
38
|
+
*/
|
|
39
|
+
function resolveBinaryFromOptionalDeps() {
|
|
40
|
+
const platformKey = getPlatformKey();
|
|
41
|
+
if (!platformKey) return null;
|
|
42
|
+
|
|
43
|
+
const packageName = PLATFORM_PACKAGES[platformKey];
|
|
44
|
+
if (!packageName) return null;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const packagePath = require.resolve(`${packageName}/package.json`);
|
|
48
|
+
const packageDir = path.dirname(packagePath);
|
|
49
|
+
const binaryPath = path.join(packageDir, "bin", BINARY_NAME);
|
|
50
|
+
|
|
51
|
+
if (fs.existsSync(binaryPath)) {
|
|
52
|
+
return binaryPath;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
// Package not installed (expected on non-matching platforms)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Try to resolve binary from postinstall fallback location
|
|
63
|
+
* @returns {string | null}
|
|
64
|
+
*/
|
|
65
|
+
function resolveBinaryFromFallback() {
|
|
66
|
+
const fallbackPath = path.join(__dirname, "..", ".binary", BINARY_NAME);
|
|
67
|
+
if (fs.existsSync(fallbackPath)) {
|
|
68
|
+
return fallbackPath;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Find the mino binary
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function findBinary() {
|
|
78
|
+
// Try optional dependencies first (fastest path)
|
|
79
|
+
const optionalDepsBinary = resolveBinaryFromOptionalDeps();
|
|
80
|
+
if (optionalDepsBinary) {
|
|
81
|
+
return optionalDepsBinary;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Try postinstall fallback location
|
|
85
|
+
const fallbackBinary = resolveBinaryFromFallback();
|
|
86
|
+
if (fallbackBinary) {
|
|
87
|
+
return fallbackBinary;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// No binary found
|
|
91
|
+
const platformKey = getPlatformKey();
|
|
92
|
+
if (!platformKey) {
|
|
93
|
+
console.error(
|
|
94
|
+
`Error: Unsupported platform: ${process.platform}-${process.arch}`
|
|
95
|
+
);
|
|
96
|
+
console.error("Mino supports: darwin-x64, darwin-arm64, linux-x64, linux-arm64");
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.error("Error: Could not find mino binary.");
|
|
101
|
+
console.error("");
|
|
102
|
+
console.error("This usually means:");
|
|
103
|
+
console.error(" 1. npm failed to install the platform-specific package");
|
|
104
|
+
console.error(" 2. The postinstall script failed to download the binary");
|
|
105
|
+
console.error("");
|
|
106
|
+
console.error("Try reinstalling: npm install -g @dean0x/mino");
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Main entry point
|
|
112
|
+
*/
|
|
113
|
+
function main() {
|
|
114
|
+
const binaryPath = findBinary();
|
|
115
|
+
const args = process.argv.slice(2);
|
|
116
|
+
|
|
117
|
+
const child = spawn(binaryPath, args, {
|
|
118
|
+
stdio: "inherit",
|
|
119
|
+
env: process.env,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
child.on("error", (err) => {
|
|
123
|
+
console.error(`Failed to execute mino: ${err.message}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
child.on("close", (code) => {
|
|
128
|
+
process.exit(code ?? 0);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
main();
|
package/install.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall fallback script for @dean0x/mino
|
|
5
|
+
*
|
|
6
|
+
* This script runs after npm install. If the platform-specific optional
|
|
7
|
+
* dependency was installed successfully, this script does nothing.
|
|
8
|
+
* Otherwise, it downloads the correct binary from the npm registry.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const https = require("https");
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const zlib = require("zlib");
|
|
15
|
+
const { execSync } = require("child_process");
|
|
16
|
+
|
|
17
|
+
const BINARY_NAME = "mino";
|
|
18
|
+
const PACKAGE_VERSION = require("./package.json").version;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Platform-specific package mapping
|
|
22
|
+
*/
|
|
23
|
+
const PLATFORM_PACKAGES = {
|
|
24
|
+
"darwin-x64": "@dean0x/mino-darwin-x64",
|
|
25
|
+
"darwin-arm64": "@dean0x/mino-darwin-arm64",
|
|
26
|
+
"linux-x64": "@dean0x/mino-linux-x64",
|
|
27
|
+
"linux-arm64": "@dean0x/mino-linux-arm64",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get the platform key for the current system
|
|
32
|
+
* @returns {string | null}
|
|
33
|
+
*/
|
|
34
|
+
function getPlatformKey() {
|
|
35
|
+
const platform = process.platform;
|
|
36
|
+
const arch = process.arch;
|
|
37
|
+
|
|
38
|
+
if (platform === "darwin" && arch === "x64") return "darwin-x64";
|
|
39
|
+
if (platform === "darwin" && arch === "arm64") return "darwin-arm64";
|
|
40
|
+
if (platform === "linux" && arch === "x64") return "linux-x64";
|
|
41
|
+
if (platform === "linux" && arch === "arm64") return "linux-arm64";
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if binary is already available from optional dependencies
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
function binaryAlreadyAvailable() {
|
|
51
|
+
const platformKey = getPlatformKey();
|
|
52
|
+
if (!platformKey) return false;
|
|
53
|
+
|
|
54
|
+
const packageName = PLATFORM_PACKAGES[platformKey];
|
|
55
|
+
if (!packageName) return false;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const packagePath = require.resolve(`${packageName}/package.json`);
|
|
59
|
+
const packageDir = path.dirname(packagePath);
|
|
60
|
+
const binaryPath = path.join(packageDir, "bin", BINARY_NAME);
|
|
61
|
+
return fs.existsSync(binaryPath);
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Download file from URL with redirect handling
|
|
69
|
+
* @param {string} url
|
|
70
|
+
* @returns {Promise<Buffer>}
|
|
71
|
+
*/
|
|
72
|
+
function download(url) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const request = https.get(url, (response) => {
|
|
75
|
+
// Handle redirects
|
|
76
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
77
|
+
download(response.headers.location).then(resolve).catch(reject);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (response.statusCode !== 200) {
|
|
82
|
+
reject(new Error(`HTTP ${response.statusCode}: ${url}`));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const chunks = [];
|
|
87
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
88
|
+
response.on("end", () => resolve(Buffer.concat(chunks)));
|
|
89
|
+
response.on("error", reject);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
request.on("error", reject);
|
|
93
|
+
request.setTimeout(60000, () => {
|
|
94
|
+
request.destroy();
|
|
95
|
+
reject(new Error("Download timeout"));
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Extract tarball and find the binary
|
|
102
|
+
* @param {Buffer} tarballBuffer
|
|
103
|
+
* @returns {Buffer}
|
|
104
|
+
*/
|
|
105
|
+
function extractBinaryFromTarball(tarballBuffer) {
|
|
106
|
+
// Decompress gzip
|
|
107
|
+
const tarBuffer = zlib.gunzipSync(tarballBuffer);
|
|
108
|
+
|
|
109
|
+
// Simple tar extraction - find the binary file
|
|
110
|
+
// tar format: 512-byte headers followed by file content
|
|
111
|
+
let offset = 0;
|
|
112
|
+
while (offset < tarBuffer.length) {
|
|
113
|
+
// Read header
|
|
114
|
+
const header = tarBuffer.subarray(offset, offset + 512);
|
|
115
|
+
|
|
116
|
+
// Check for end of archive (empty header)
|
|
117
|
+
if (header.every((b) => b === 0)) break;
|
|
118
|
+
|
|
119
|
+
// Extract filename (first 100 bytes, null-terminated)
|
|
120
|
+
let nameEnd = 0;
|
|
121
|
+
while (nameEnd < 100 && header[nameEnd] !== 0) nameEnd++;
|
|
122
|
+
const name = header.subarray(0, nameEnd).toString("utf8");
|
|
123
|
+
|
|
124
|
+
// Extract file size (octal string at offset 124, 12 bytes)
|
|
125
|
+
const sizeStr = header.subarray(124, 136).toString("utf8").trim();
|
|
126
|
+
const size = parseInt(sizeStr, 8) || 0;
|
|
127
|
+
|
|
128
|
+
offset += 512; // Move past header
|
|
129
|
+
|
|
130
|
+
// Check if this is the binary we're looking for
|
|
131
|
+
if (name.endsWith(`/bin/${BINARY_NAME}`) || name === `bin/${BINARY_NAME}`) {
|
|
132
|
+
return tarBuffer.subarray(offset, offset + size);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Skip to next file (rounded up to 512-byte boundary)
|
|
136
|
+
offset += Math.ceil(size / 512) * 512;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw new Error(`Binary not found in tarball`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Download and install the binary as fallback
|
|
144
|
+
*/
|
|
145
|
+
async function installFallback() {
|
|
146
|
+
const platformKey = getPlatformKey();
|
|
147
|
+
if (!platformKey) {
|
|
148
|
+
console.log(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
149
|
+
console.log("Skipping postinstall - binary must be installed manually.");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const packageName = PLATFORM_PACKAGES[platformKey];
|
|
154
|
+
|
|
155
|
+
console.log(`Downloading ${packageName}@${PACKAGE_VERSION}...`);
|
|
156
|
+
|
|
157
|
+
// Get package metadata from npm registry
|
|
158
|
+
const registryUrl = `https://registry.npmjs.org/${packageName}/${PACKAGE_VERSION}`;
|
|
159
|
+
const metadataBuffer = await download(registryUrl);
|
|
160
|
+
const metadata = JSON.parse(metadataBuffer.toString("utf8"));
|
|
161
|
+
|
|
162
|
+
const tarballUrl = metadata.dist.tarball;
|
|
163
|
+
if (!tarballUrl) {
|
|
164
|
+
throw new Error("Could not find tarball URL in package metadata");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Download tarball
|
|
168
|
+
console.log("Extracting binary...");
|
|
169
|
+
const tarballBuffer = await download(tarballUrl);
|
|
170
|
+
|
|
171
|
+
// Extract binary
|
|
172
|
+
const binaryBuffer = extractBinaryFromTarball(tarballBuffer);
|
|
173
|
+
|
|
174
|
+
// Write binary to local directory
|
|
175
|
+
const binaryDir = path.join(__dirname, ".binary");
|
|
176
|
+
const binaryPath = path.join(binaryDir, BINARY_NAME);
|
|
177
|
+
|
|
178
|
+
fs.mkdirSync(binaryDir, { recursive: true });
|
|
179
|
+
fs.writeFileSync(binaryPath, binaryBuffer, { mode: 0o755 });
|
|
180
|
+
|
|
181
|
+
console.log(`Installed ${BINARY_NAME} to ${binaryPath}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Main entry point
|
|
186
|
+
*/
|
|
187
|
+
async function main() {
|
|
188
|
+
// Skip if running in CI or if explicitly disabled
|
|
189
|
+
if (process.env.MINO_SKIP_INSTALL) {
|
|
190
|
+
console.log("MINO_SKIP_INSTALL is set, skipping postinstall");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Skip if binary already available from optional dependencies
|
|
195
|
+
if (binaryAlreadyAvailable()) {
|
|
196
|
+
console.log("Binary available from optional dependency, skipping fallback download");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
await installFallback();
|
|
202
|
+
} catch (error) {
|
|
203
|
+
// Don't fail the install - npm will have already printed warnings about
|
|
204
|
+
// optional dependencies. The user can still install manually.
|
|
205
|
+
console.error(`Warning: Failed to download fallback binary: ${error.message}`);
|
|
206
|
+
console.error("You may need to install the binary manually.");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
main().catch((error) => {
|
|
211
|
+
console.error(error);
|
|
212
|
+
// Exit 0 so npm install doesn't fail
|
|
213
|
+
process.exit(0);
|
|
214
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dean0x/mino",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Secure AI agent sandbox using rootless containers",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/dean0x/mino"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/dean0x/mino#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/dean0x/mino/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"sandbox",
|
|
16
|
+
"container",
|
|
17
|
+
"podman",
|
|
18
|
+
"security",
|
|
19
|
+
"ai",
|
|
20
|
+
"agent",
|
|
21
|
+
"cli"
|
|
22
|
+
],
|
|
23
|
+
"bin": {
|
|
24
|
+
"mino": "./bin/mino.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin",
|
|
28
|
+
"install.js"
|
|
29
|
+
],
|
|
30
|
+
"optionalDependencies": {
|
|
31
|
+
"@dean0x/mino-darwin-x64": "0.1.0",
|
|
32
|
+
"@dean0x/mino-darwin-arm64": "0.1.0",
|
|
33
|
+
"@dean0x/mino-linux-x64": "0.1.0",
|
|
34
|
+
"@dean0x/mino-linux-arm64": "0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"postinstall": "node install.js"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=16"
|
|
41
|
+
}
|
|
42
|
+
}
|