eidoncore 3.3.7 → 3.7.2
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 -38
- package/install.js +250 -199
- package/package.json +1 -1
package/bin.js
CHANGED
|
@@ -1,38 +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);
|
|
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
CHANGED
|
@@ -1,199 +1,250 @@
|
|
|
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
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
fs.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
console.log('
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
+
// Ed25519 public key (DER/SPKI, hex-encoded) — matches the private key stored in
|
|
25
|
+
// GitHub Actions secret MANIFEST_SIGNING_KEY. Together they ensure that even if
|
|
26
|
+
// releases.eidon.dev is fully compromised, an attacker cannot serve a fake manifest
|
|
27
|
+
// because they cannot forge a valid Ed25519 signature for the private key.
|
|
28
|
+
// To rotate: run scripts/gen-manifest-keypair.js, update this constant, and update
|
|
29
|
+
// the matching constant in src/cli/update.ts. Then set the new private key in
|
|
30
|
+
// GitHub Actions secrets before your next release.
|
|
31
|
+
const MANIFEST_PUBKEY_HEX = '302a300506032b657003210009880b8bfc7ae6dcc3a9e6dd207709b25df819bd19a94e5acb5b1b0d343dc5cd';
|
|
32
|
+
|
|
33
|
+
// ── Platform detection ────────────────────────────────────────────────────
|
|
34
|
+
function getPlatform() {
|
|
35
|
+
const p = process.platform;
|
|
36
|
+
const a = process.arch;
|
|
37
|
+
if (p === 'darwin') return 'macos-arm64'; // ARM64 binary runs on both Apple Silicon and Intel (Rosetta 2)
|
|
38
|
+
if (p === 'linux' && a === 'x64') return 'linux-x64';
|
|
39
|
+
if (p === 'linux' && a === 'arm64') return 'linux-arm64';
|
|
40
|
+
if (p === 'win32' && a === 'x64') return 'windows-x64';
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Eidon: unsupported platform ${p}/${a}.\n` +
|
|
43
|
+
`Please download manually from ${RELEASES_BASE}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ── HTTPS helpers (no external deps) ────────────────────────────────────
|
|
48
|
+
function fetchText(url) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
if (!url.startsWith('https://')) {
|
|
51
|
+
return reject(new Error(`Refusing non-HTTPS URL: ${url}`));
|
|
52
|
+
}
|
|
53
|
+
const req = https.get(url, { timeout: 15000 }, res => {
|
|
54
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
55
|
+
const loc = res.headers.location || '';
|
|
56
|
+
if (!loc.startsWith('https://')) {
|
|
57
|
+
return reject(new Error(`Redirect to non-HTTPS blocked: ${loc}`));
|
|
58
|
+
}
|
|
59
|
+
return fetchText(loc).then(resolve, reject);
|
|
60
|
+
}
|
|
61
|
+
if (res.statusCode !== 200) {
|
|
62
|
+
res.resume();
|
|
63
|
+
return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
|
|
64
|
+
}
|
|
65
|
+
const chunks = [];
|
|
66
|
+
res.on('data', chunk => chunks.push(chunk));
|
|
67
|
+
res.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
68
|
+
});
|
|
69
|
+
req.on('error', reject);
|
|
70
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timed out')); });
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Fetch + Ed25519 verify a manifest JSON.
|
|
75
|
+
// 1. Fetch <url> — raw manifest text (must be exactly what was signed)
|
|
76
|
+
// 2. Fetch <url>.sig — hex-encoded Ed25519 signature (soft-fail: warn if missing)
|
|
77
|
+
// 3. Verify signature — hard-fail if signature is present but invalid
|
|
78
|
+
// 4. Parse + return — JSON is only parsed after integrity is confirmed
|
|
79
|
+
async function fetchAndVerifyManifest(url) {
|
|
80
|
+
const manifestText = await fetchText(url);
|
|
81
|
+
|
|
82
|
+
// Attempt to fetch the signature (non-fatal if server doesn't have it yet)
|
|
83
|
+
let sigHex = null;
|
|
84
|
+
try { sigHex = (await fetchText(url + '.sig')).trim(); } catch { /* no sig file */ }
|
|
85
|
+
|
|
86
|
+
if (sigHex) {
|
|
87
|
+
try {
|
|
88
|
+
const pubKey = { key: Buffer.from(MANIFEST_PUBKEY_HEX, 'hex'), format: 'der', type: 'spki' };
|
|
89
|
+
const sig = Buffer.from(sigHex, 'hex');
|
|
90
|
+
const valid = crypto.verify(null, Buffer.from(manifestText), pubKey, sig);
|
|
91
|
+
if (!valid) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
'Ed25519 signature verification FAILED — manifest may be tampered.\n' +
|
|
94
|
+
'Refusing to install. Please report this at https://github.com/BAGADIR/Eidon/issues'
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
console.log(' Manifest signature verified ✓');
|
|
98
|
+
} catch (err) {
|
|
99
|
+
if (err.message.includes('signature verification FAILED')) throw err;
|
|
100
|
+
// Crypto error (bad key format, etc.) — log and continue with SHA-256 only
|
|
101
|
+
console.warn(` Warning: could not verify manifest signature (${err.message}). Proceeding with SHA-256 only.`);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
console.warn(' Warning: manifest signature not found (.sig). Proceeding with SHA-256 verification only.');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try { return JSON.parse(manifestText); }
|
|
108
|
+
catch (e) { throw new Error(`Failed to parse manifest JSON: ${e.message}`); }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function downloadFile(url, dest) {
|
|
112
|
+
return new Promise((resolve, reject) => {
|
|
113
|
+
const file = fs.createWriteStream(dest);
|
|
114
|
+
function follow(href) {
|
|
115
|
+
const req = https.get(href, { timeout: 120000 }, res => {
|
|
116
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
117
|
+
file.destroy();
|
|
118
|
+
return follow(res.headers.location);
|
|
119
|
+
}
|
|
120
|
+
if (res.statusCode !== 200) {
|
|
121
|
+
file.destroy();
|
|
122
|
+
fs.unlink(dest, () => {});
|
|
123
|
+
return reject(new Error(`HTTP ${res.statusCode} downloading binary`));
|
|
124
|
+
}
|
|
125
|
+
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
126
|
+
let received = 0;
|
|
127
|
+
let lastPct = -1;
|
|
128
|
+
res.on('data', chunk => {
|
|
129
|
+
received += chunk.length;
|
|
130
|
+
if (total > 0) {
|
|
131
|
+
const pct = Math.floor((received / total) * 20); // 20-char bar
|
|
132
|
+
if (pct !== lastPct) {
|
|
133
|
+
lastPct = pct;
|
|
134
|
+
const bar = '█'.repeat(pct) + '░'.repeat(20 - pct);
|
|
135
|
+
process.stdout.write(`\r [${bar}] ${Math.floor(received / 1024)}KB`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
res.pipe(file);
|
|
140
|
+
res.on('end', () => { process.stdout.write('\n'); });
|
|
141
|
+
file.on('finish', () => file.close(resolve));
|
|
142
|
+
file.on('error', err => { fs.unlink(dest, () => {}); reject(err); });
|
|
143
|
+
});
|
|
144
|
+
req.on('error', err => { fs.unlink(dest, () => {}); reject(err); });
|
|
145
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Download timed out')); });
|
|
146
|
+
}
|
|
147
|
+
follow(url);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ── SHA-256 verification ─────────────────────────────────────────────────
|
|
152
|
+
function sha256File(filePath) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
const hash = crypto.createHash('sha256');
|
|
155
|
+
const stream = fs.createReadStream(filePath);
|
|
156
|
+
stream.on('data', chunk => hash.update(chunk));
|
|
157
|
+
stream.on('end', () => resolve(hash.digest('hex')));
|
|
158
|
+
stream.on('error', reject);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Main ─────────────────────────────────────────────────────────────────
|
|
163
|
+
async function main() {
|
|
164
|
+
// Skip if binary already exists and matches (e.g. re-running postinstall)
|
|
165
|
+
if (fs.existsSync(BINARY_PATH)) {
|
|
166
|
+
try {
|
|
167
|
+
execFileSync(BINARY_PATH, ['--version'], { stdio: 'ignore' });
|
|
168
|
+
console.log(' Eidon binary already installed and working.');
|
|
169
|
+
return;
|
|
170
|
+
} catch {
|
|
171
|
+
// Binary exists but broken — re-download
|
|
172
|
+
fs.unlinkSync(BINARY_PATH);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log('\n Installing Eidon...');
|
|
177
|
+
|
|
178
|
+
const platform = getPlatform();
|
|
179
|
+
console.log(` Platform : ${platform}`);
|
|
180
|
+
|
|
181
|
+
// Allow pinning: EIDON_VERSION=3.2.0 npm install -g eidon
|
|
182
|
+
const requestedVersion = process.env.EIDON_VERSION || '';
|
|
183
|
+
const manifestUrl = requestedVersion
|
|
184
|
+
? `${RELEASES_BASE}/${requestedVersion}.json`
|
|
185
|
+
: `${RELEASES_BASE}/latest.json`;
|
|
186
|
+
|
|
187
|
+
console.log(' Fetching release manifest...');
|
|
188
|
+
const manifest = await fetchAndVerifyManifest(manifestUrl);
|
|
189
|
+
const version = manifest.version;
|
|
190
|
+
const asset = manifest.assets && manifest.assets[platform];
|
|
191
|
+
|
|
192
|
+
if (!asset || !asset.url || !asset.sha256) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`No release asset found for platform "${platform}" in manifest.\n` +
|
|
195
|
+
`Please download manually from ${RELEASES_BASE}`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log(` Version : v${version}`);
|
|
200
|
+
console.log(` Downloading binary...`);
|
|
201
|
+
|
|
202
|
+
const tmpPath = BINARY_PATH + '.download';
|
|
203
|
+
try {
|
|
204
|
+
await downloadFile(asset.url, tmpPath);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
fs.unlink(tmpPath, () => {});
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Verify SHA-256
|
|
211
|
+
console.log(' Verifying SHA-256...');
|
|
212
|
+
const actual = await sha256File(tmpPath);
|
|
213
|
+
const expected = asset.sha256.toLowerCase();
|
|
214
|
+
if (actual !== expected) {
|
|
215
|
+
fs.unlinkSync(tmpPath);
|
|
216
|
+
throw new Error(
|
|
217
|
+
`SHA-256 mismatch — aborting (possible tampered binary)\n` +
|
|
218
|
+
` Expected: ${expected}\n` +
|
|
219
|
+
` Got : ${actual}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
console.log(' SHA-256 verified.');
|
|
223
|
+
|
|
224
|
+
// Move into place and make executable
|
|
225
|
+
fs.renameSync(tmpPath, BINARY_PATH);
|
|
226
|
+
if (process.platform !== 'win32') fs.chmodSync(BINARY_PATH, 0o755);
|
|
227
|
+
|
|
228
|
+
// Smoke test
|
|
229
|
+
try {
|
|
230
|
+
const ver = execFileSync(BINARY_PATH, ['--version'], { encoding: 'utf8' }).trim();
|
|
231
|
+
console.log(` Verified : ${ver}`);
|
|
232
|
+
} catch {
|
|
233
|
+
console.warn(' WARNING: Binary installed but smoke test failed. Try running: eidon --version');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(`\n Eidon v${version} ready.\n`);
|
|
237
|
+
console.log(' Quick start:');
|
|
238
|
+
console.log(' eidon init # configure your LLM (one-time wizard)');
|
|
239
|
+
console.log(' eidon analyze # index your repo — run once');
|
|
240
|
+
console.log(' eidon install-mcp # connect Cursor, VS Code, Claude Code...');
|
|
241
|
+
console.log(' eidon doctor # health check before every session\n');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
main().catch(err => {
|
|
245
|
+
console.error(`\n Eidon install failed: ${err.message}\n`);
|
|
246
|
+
console.error(` Download manually: ${RELEASES_BASE}`);
|
|
247
|
+
// Exit 0 — don't block npm install for users who don't need the binary yet
|
|
248
|
+
// (e.g. CI installs that only need the package metadata)
|
|
249
|
+
process.exit(0);
|
|
250
|
+
});
|