@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.
Files changed (3) hide show
  1. package/bin.js +38 -0
  2. package/install.js +199 -0
  3. 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
+ }