@eidoncore/cli 3.3.7
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.js +38 -0
- package/install.js +199 -0
- package/package.json +34 -0
package/bin.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Eidon — bin shim
|
|
4
|
+
//
|
|
5
|
+
// This file is the `bin.eidon` entry point registered with npm.
|
|
6
|
+
// It locates the native binary that postinstall downloaded and
|
|
7
|
+
// spawns it with all arguments forwarded. Exit code is preserved.
|
|
8
|
+
//
|
|
9
|
+
// No npm dependencies — only Node.js built-ins.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const BINARY_NAME = process.platform === 'win32' ? 'eidon.exe' : 'eidon';
|
|
18
|
+
const BINARY_PATH = path.join(__dirname, BINARY_NAME);
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(BINARY_PATH)) {
|
|
21
|
+
console.error(
|
|
22
|
+
'\n Eidon binary not found.\n' +
|
|
23
|
+
' Run: npm install -g eidon (postinstall will re-download it)\n'
|
|
24
|
+
);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const result = spawnSync(BINARY_PATH, process.argv.slice(2), {
|
|
29
|
+
stdio: 'inherit',
|
|
30
|
+
env: process.env,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (result.error) {
|
|
34
|
+
console.error(`\n Failed to launch eidon: ${result.error.message}\n`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
process.exit(result.status ?? 0);
|
package/install.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Eidon — postinstall binary downloader
|
|
4
|
+
//
|
|
5
|
+
// Runs automatically after `npm install -g eidon`.
|
|
6
|
+
// Downloads the correct pre-compiled Eidon binary for the current platform,
|
|
7
|
+
// verifies its SHA-256 checksum, and saves it next to this file.
|
|
8
|
+
//
|
|
9
|
+
// No npm dependencies — only Node.js built-ins.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const https = require('https');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const crypto = require('crypto');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
const { execFileSync } = require('child_process');
|
|
19
|
+
|
|
20
|
+
const RELEASES_BASE = 'https://releases.eidon.dev';
|
|
21
|
+
const BINARY_NAME = process.platform === 'win32' ? 'eidon.exe' : 'eidon';
|
|
22
|
+
const BINARY_PATH = path.join(__dirname, BINARY_NAME);
|
|
23
|
+
|
|
24
|
+
// ── Platform detection ────────────────────────────────────────────────────
|
|
25
|
+
function getPlatform() {
|
|
26
|
+
const p = process.platform;
|
|
27
|
+
const a = process.arch;
|
|
28
|
+
if (p === 'darwin') return 'macos-arm64'; // ARM64 binary runs on both Apple Silicon and Intel (Rosetta 2)
|
|
29
|
+
if (p === 'linux' && a === 'x64') return 'linux-x64';
|
|
30
|
+
if (p === 'linux' && a === 'arm64') return 'linux-arm64';
|
|
31
|
+
if (p === 'win32' && a === 'x64') return 'windows-x64';
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Eidon: unsupported platform ${p}/${a}.\n` +
|
|
34
|
+
`Please download manually from ${RELEASES_BASE}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── HTTPS helpers (no external deps) ────────────────────────────────────
|
|
39
|
+
function fetchJson(url) {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const req = https.get(url, { timeout: 15000 }, res => {
|
|
42
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
43
|
+
return fetchJson(res.headers.location).then(resolve, reject);
|
|
44
|
+
}
|
|
45
|
+
if (res.statusCode !== 200) {
|
|
46
|
+
return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
|
|
47
|
+
}
|
|
48
|
+
let body = '';
|
|
49
|
+
res.on('data', chunk => { body += chunk; });
|
|
50
|
+
res.on('end', () => {
|
|
51
|
+
try { resolve(JSON.parse(body)); }
|
|
52
|
+
catch (e) { reject(new Error(`Failed to parse manifest JSON: ${e.message}`)); }
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
req.on('error', reject);
|
|
56
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timed out')); });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function downloadFile(url, dest) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const file = fs.createWriteStream(dest);
|
|
63
|
+
function follow(href) {
|
|
64
|
+
const req = https.get(href, { timeout: 120000 }, res => {
|
|
65
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
66
|
+
file.destroy();
|
|
67
|
+
return follow(res.headers.location);
|
|
68
|
+
}
|
|
69
|
+
if (res.statusCode !== 200) {
|
|
70
|
+
file.destroy();
|
|
71
|
+
fs.unlink(dest, () => {});
|
|
72
|
+
return reject(new Error(`HTTP ${res.statusCode} downloading binary`));
|
|
73
|
+
}
|
|
74
|
+
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
75
|
+
let received = 0;
|
|
76
|
+
let lastPct = -1;
|
|
77
|
+
res.on('data', chunk => {
|
|
78
|
+
received += chunk.length;
|
|
79
|
+
if (total > 0) {
|
|
80
|
+
const pct = Math.floor((received / total) * 20); // 20-char bar
|
|
81
|
+
if (pct !== lastPct) {
|
|
82
|
+
lastPct = pct;
|
|
83
|
+
const bar = '█'.repeat(pct) + '░'.repeat(20 - pct);
|
|
84
|
+
process.stdout.write(`\r [${bar}] ${Math.floor(received / 1024)}KB`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
res.pipe(file);
|
|
89
|
+
res.on('end', () => { process.stdout.write('\n'); });
|
|
90
|
+
file.on('finish', () => file.close(resolve));
|
|
91
|
+
file.on('error', err => { fs.unlink(dest, () => {}); reject(err); });
|
|
92
|
+
});
|
|
93
|
+
req.on('error', err => { fs.unlink(dest, () => {}); reject(err); });
|
|
94
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Download timed out')); });
|
|
95
|
+
}
|
|
96
|
+
follow(url);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ── SHA-256 verification ─────────────────────────────────────────────────
|
|
101
|
+
function sha256File(filePath) {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
const hash = crypto.createHash('sha256');
|
|
104
|
+
const stream = fs.createReadStream(filePath);
|
|
105
|
+
stream.on('data', chunk => hash.update(chunk));
|
|
106
|
+
stream.on('end', () => resolve(hash.digest('hex')));
|
|
107
|
+
stream.on('error', reject);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Main ─────────────────────────────────────────────────────────────────
|
|
112
|
+
async function main() {
|
|
113
|
+
// Skip if binary already exists and matches (e.g. re-running postinstall)
|
|
114
|
+
if (fs.existsSync(BINARY_PATH)) {
|
|
115
|
+
try {
|
|
116
|
+
execFileSync(BINARY_PATH, ['--version'], { stdio: 'ignore' });
|
|
117
|
+
console.log(' Eidon binary already installed and working.');
|
|
118
|
+
return;
|
|
119
|
+
} catch {
|
|
120
|
+
// Binary exists but broken — re-download
|
|
121
|
+
fs.unlinkSync(BINARY_PATH);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log('\n Installing Eidon...');
|
|
126
|
+
|
|
127
|
+
const platform = getPlatform();
|
|
128
|
+
console.log(` Platform : ${platform}`);
|
|
129
|
+
|
|
130
|
+
// Allow pinning: EIDON_VERSION=3.2.0 npm install -g eidon
|
|
131
|
+
const requestedVersion = process.env.EIDON_VERSION || '';
|
|
132
|
+
const manifestUrl = requestedVersion
|
|
133
|
+
? `${RELEASES_BASE}/${requestedVersion}.json`
|
|
134
|
+
: `${RELEASES_BASE}/latest.json`;
|
|
135
|
+
|
|
136
|
+
console.log(' Fetching release manifest...');
|
|
137
|
+
const manifest = await fetchJson(manifestUrl);
|
|
138
|
+
const version = manifest.version;
|
|
139
|
+
const asset = manifest.assets && manifest.assets[platform];
|
|
140
|
+
|
|
141
|
+
if (!asset || !asset.url || !asset.sha256) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`No release asset found for platform "${platform}" in manifest.\n` +
|
|
144
|
+
`Please download manually from ${RELEASES_BASE}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log(` Version : v${version}`);
|
|
149
|
+
console.log(` Downloading binary...`);
|
|
150
|
+
|
|
151
|
+
const tmpPath = BINARY_PATH + '.download';
|
|
152
|
+
try {
|
|
153
|
+
await downloadFile(asset.url, tmpPath);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
fs.unlink(tmpPath, () => {});
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Verify SHA-256
|
|
160
|
+
console.log(' Verifying SHA-256...');
|
|
161
|
+
const actual = await sha256File(tmpPath);
|
|
162
|
+
const expected = asset.sha256.toLowerCase();
|
|
163
|
+
if (actual !== expected) {
|
|
164
|
+
fs.unlinkSync(tmpPath);
|
|
165
|
+
throw new Error(
|
|
166
|
+
`SHA-256 mismatch — aborting (possible tampered binary)\n` +
|
|
167
|
+
` Expected: ${expected}\n` +
|
|
168
|
+
` Got : ${actual}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
console.log(' SHA-256 verified.');
|
|
172
|
+
|
|
173
|
+
// Move into place and make executable
|
|
174
|
+
fs.renameSync(tmpPath, BINARY_PATH);
|
|
175
|
+
if (process.platform !== 'win32') fs.chmodSync(BINARY_PATH, 0o755);
|
|
176
|
+
|
|
177
|
+
// Smoke test
|
|
178
|
+
try {
|
|
179
|
+
const ver = execFileSync(BINARY_PATH, ['--version'], { encoding: 'utf8' }).trim();
|
|
180
|
+
console.log(` Verified : ${ver}`);
|
|
181
|
+
} catch {
|
|
182
|
+
console.warn(' WARNING: Binary installed but smoke test failed. Try running: eidon --version');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
console.log(`\n Eidon v${version} ready.\n`);
|
|
186
|
+
console.log(' Quick start:');
|
|
187
|
+
console.log(' eidon init # configure your LLM (one-time wizard)');
|
|
188
|
+
console.log(' eidon analyze # index your repo — run once');
|
|
189
|
+
console.log(' eidon install-mcp # connect Cursor, VS Code, Claude Code...');
|
|
190
|
+
console.log(' eidon doctor # health check before every session\n');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
main().catch(err => {
|
|
194
|
+
console.error(`\n Eidon install failed: ${err.message}\n`);
|
|
195
|
+
console.error(` Download manually: ${RELEASES_BASE}`);
|
|
196
|
+
// Exit 0 — don't block npm install for users who don't need the binary yet
|
|
197
|
+
// (e.g. CI installs that only need the package metadata)
|
|
198
|
+
process.exit(0);
|
|
199
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eidoncore/cli",
|
|
3
|
+
"version": "3.3.7",
|
|
4
|
+
"description": "Your AI finally knows your whole codebase. Structural graph intelligence for every AI tool you use.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"mcp",
|
|
8
|
+
"codebase",
|
|
9
|
+
"graph",
|
|
10
|
+
"cursor",
|
|
11
|
+
"copilot",
|
|
12
|
+
"claude",
|
|
13
|
+
"analysis"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://eidon.dev",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/eidon-dev/eidon"
|
|
19
|
+
},
|
|
20
|
+
"license": "UNLICENSED",
|
|
21
|
+
"bin": {
|
|
22
|
+
"eidon": "./bin.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"postinstall": "node install.js"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin.js",
|
|
32
|
+
"install.js"
|
|
33
|
+
]
|
|
34
|
+
}
|