@vibead/cli 0.0.0-stage → 0.1.0-beta.12
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 +31 -2
- package/THIRD-PARTY-NOTICES.txt +3135 -0
- package/bin/vibead.mjs +25 -0
- package/lib/install.mjs +70 -0
- package/package.json +15 -4
- package/releases.json +8 -0
package/bin/vibead.mjs
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { ensureInstalled, release } from '../lib/install.mjs';
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
if (args.length === 1 && (args[0] === '--version' || args[0] === '-v')) {
|
|
8
|
+
console.log(release.version);
|
|
9
|
+
} else {
|
|
10
|
+
const executable = await ensureInstalled();
|
|
11
|
+
const child = spawn(executable, args, { stdio: 'inherit' });
|
|
12
|
+
// Keep the wrapper alive until the native process finishes its cleanup.
|
|
13
|
+
const handlers = new Map(['SIGINT', 'SIGTERM', 'SIGHUP'].map(signal => [signal, () => child.kill(signal)]));
|
|
14
|
+
for (const [signal, handler] of handlers) process.on(signal, handler);
|
|
15
|
+
child.on('error', error => { console.error(`vibead: ${error.message}`); process.exitCode = 1; });
|
|
16
|
+
child.on('exit', (code, signal) => {
|
|
17
|
+
for (const [signal, handler] of handlers) process.removeListener(signal, handler);
|
|
18
|
+
if (signal) process.kill(process.pid, signal);
|
|
19
|
+
else process.exitCode = code ?? 1;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(`vibead: ${error.message}`);
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
package/lib/install.mjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
3
|
+
import { access, chmod, mkdir, mkdtemp, readFile, rename, rm } from 'node:fs/promises';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import { Readable } from 'node:stream';
|
|
7
|
+
import { pipeline } from 'node:stream/promises';
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
9
|
+
import { promisify } from 'node:util';
|
|
10
|
+
|
|
11
|
+
const execute = promisify(execFile);
|
|
12
|
+
export const release = JSON.parse(await readFile(new URL('../releases.json', import.meta.url), 'utf8'));
|
|
13
|
+
|
|
14
|
+
export function platformKey(platform = process.platform, arch = process.arch) {
|
|
15
|
+
const key = `${platform}-${arch}`;
|
|
16
|
+
if (!release.platforms[key]) throw new Error(`Unsupported platform ${key}. Supported: macOS arm64/x64 and Linux x64 (glibc >= 2.34).`);
|
|
17
|
+
return key;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function verifyChecksum(file, expected) {
|
|
21
|
+
const hash = createHash('sha256');
|
|
22
|
+
for await (const chunk of createReadStream(file)) hash.update(chunk);
|
|
23
|
+
const actual = hash.digest('hex');
|
|
24
|
+
if (actual !== expected) throw new Error(`Release checksum mismatch. Expected ${expected}, received ${actual}.`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function download(url, destination) {
|
|
28
|
+
const proxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.ALL_PROXY || process.env.all_proxy;
|
|
29
|
+
if (proxy) {
|
|
30
|
+
try {
|
|
31
|
+
await execute('curl', ['--fail', '--location', '--silent', '--show-error', '--retry', '2', '--max-time', '300', '--proto', '=https', '--proto-redir', '=https', '--output', destination, url]);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new Error(error.code === 'ENOENT' ? 'curl is required to download through your configured HTTPS proxy.' : 'Release download through the configured proxy failed. Check your network and retry.');
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(300_000) });
|
|
38
|
+
if (!response.ok || !response.body) throw new Error(`Release download failed: HTTP ${response.status}.`);
|
|
39
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(destination, { mode: 0o600 }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function ensureInstalled() {
|
|
43
|
+
const key = platformKey();
|
|
44
|
+
const cache = resolve(process.env.VIBEAD_CACHE_DIR || join(homedir(), '.cache', 'vibead'));
|
|
45
|
+
const target = join(cache, `${release.version}-${key}-${release.platforms[key].slice(0, 12)}`);
|
|
46
|
+
const executable = join(target, 'vibead-beta');
|
|
47
|
+
try { await access(executable); return executable; } catch {}
|
|
48
|
+
await mkdir(cache, { recursive: true, mode: 0o700 });
|
|
49
|
+
const staging = await mkdtemp(join(cache, '.install-'));
|
|
50
|
+
try {
|
|
51
|
+
console.error(`vibead: downloading verified ${release.version} for ${key} (first run only)…`);
|
|
52
|
+
const archive = join(staging, 'release.tar.gz');
|
|
53
|
+
const url = `https://github.com/vibead/cli/releases/download/v${release.version}/vibead-beta-${release.version}-${key}.tar.gz`;
|
|
54
|
+
await download(url, archive);
|
|
55
|
+
await verifyChecksum(archive, release.platforms[key]);
|
|
56
|
+
try { await execute('tar', ['-xzf', archive, '-C', staging]); }
|
|
57
|
+
catch (error) { throw new Error(error.code === 'ENOENT' ? 'tar is required to extract the official release.' : `Could not extract release: ${error.message}`); }
|
|
58
|
+
const extracted = join(staging, `vibead-beta-${key}`);
|
|
59
|
+
await chmod(join(extracted, 'vibead-beta'), 0o755);
|
|
60
|
+
try { await rename(extracted, target); }
|
|
61
|
+
catch (error) {
|
|
62
|
+
// A concurrent first invocation may have finished the same verified kit.
|
|
63
|
+
if (!['EEXIST', 'ENOTEMPTY'].includes(error.code)) throw error;
|
|
64
|
+
await access(executable);
|
|
65
|
+
}
|
|
66
|
+
return executable;
|
|
67
|
+
} finally {
|
|
68
|
+
await rm(staging, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibead/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-beta.12",
|
|
4
|
+
"description": "Vibead beta launcher for Claude Code, Codex, Gemini CLI and OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"repository": { "type": "git", "url": "git+https://github.com/vibead/cli.git", "directory": "npm" },
|
|
8
|
+
"homepage": "https://github.com/vibead/cli#readme",
|
|
9
|
+
"bugs": { "url": "https://github.com/vibead/cli/issues" },
|
|
10
|
+
"bin": { "vibead": "bin/vibead.mjs", "vibead-beta": "bin/vibead.mjs" },
|
|
11
|
+
"files": ["bin", "lib", "releases.json", "README.md", "THIRD-PARTY-NOTICES.txt"],
|
|
12
|
+
"engines": { "node": ">=20" },
|
|
13
|
+
"os": ["darwin", "linux"],
|
|
14
|
+
"cpu": ["arm64", "x64"],
|
|
15
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/", "tag": "latest" },
|
|
16
|
+
"scripts": { "test": "node --test", "prepublishOnly": "npm test" }
|
|
17
|
+
}
|
package/releases.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.1.0-beta.12",
|
|
3
|
+
"platforms": {
|
|
4
|
+
"darwin-arm64": "389e6591444c4fe4a0e0de97389ce7d27eb2401a8b5d232f3a15f00a72ade8a4",
|
|
5
|
+
"darwin-x64": "ae0dbfce66e971f04813d39d597541caa542fbad84ec2d07b41760822bcf4b0d",
|
|
6
|
+
"linux-x64": "940af00180c3534447a480aae1816b7da7f1b865cec73b4904f5a3b984737571"
|
|
7
|
+
}
|
|
8
|
+
}
|