fix(windows): restore Bun auto-installation in smart-install.js
CRITICAL FIX: v7.1.0 Bun auto-install broken on Windows 11 Problem: - hooks.json calls `bun smart-install.js` but if Bun isn't installed, command fails immediately with "bun is not recognized" - smart-install.js never runs, so Bun never gets installed - Chicken-and-egg problem Root Cause: - v7.1.0 removed Bun/uv auto-installation logic from smart-install.js - Assumed Bun would already be available - Breaks fresh installations on all platforms Solution: 1. Changed SessionStart hook to use `node` for smart-install.js (Node.js always available in Claude Code) 2. Restored Bun auto-installation logic: - isBunInstalled() - check if Bun is in PATH - installBun() - auto-install via PowerShell (Windows) or curl (Unix/macOS) - Also restored uv auto-installation for Chroma After Fix: - smart-install.js runs with node (always available) - Detects if Bun is missing and auto-installs it - Subsequent hooks use bun successfully - Works on fresh Windows installations Fixes: User report from Discord - Windows 11 'bun' is not recognized 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/smart-install.js\" && bun \"${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js\"",
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/smart-install.js\" && bun \"${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js\"",
|
||||||
"timeout": 300
|
"timeout": 300
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+245
-236
@@ -1,272 +1,281 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Smart Install Script for claude-mem
|
* Smart Install Script for claude-mem
|
||||||
*
|
*
|
||||||
* Features:
|
* Ensures Bun runtime and uv (Python package manager) are installed
|
||||||
* - Detects execution context (cache vs marketplace directory)
|
* (auto-installs if missing) and handles dependency installation when needed.
|
||||||
* - Installs dependencies where the hooks actually run (cache directory)
|
|
||||||
* - Only runs npm install when necessary (version change or missing deps)
|
|
||||||
* - Caches installation state with version marker
|
|
||||||
* - Provides helpful Windows-specific error messages
|
|
||||||
* - Cross-platform compatible (pure Node.js)
|
|
||||||
* - Fast when already installed (just version check)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||||
import { execSync } from 'child_process';
|
import { execSync, spawnSync } from 'child_process';
|
||||||
import { join, dirname } from 'path';
|
import { join } from 'path';
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
// Determine the directory where THIS script is running from
|
const ROOT = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
|
||||||
// This could be either:
|
const MARKER = join(ROOT, '.install-version');
|
||||||
// 1. Cache: ~/.claude/plugins/cache/thedotmack/claude-mem/X.X.X/scripts/
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
// 2. Marketplace: ~/.claude/plugins/marketplaces/thedotmack/plugin/scripts/
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
||||||
const SCRIPT_ROOT = dirname(__dirname); // Parent of scripts/ directory
|
|
||||||
|
|
||||||
// Detect if running from cache directory (has version number in path)
|
/**
|
||||||
const CACHE_PATTERN = /[/\\]cache[/\\]thedotmack[/\\]claude-mem[/\\]\d+\.\d+\.\d+/;
|
* Check if Bun is installed and accessible
|
||||||
const IS_RUNNING_FROM_CACHE = CACHE_PATTERN.test(__dirname);
|
*/
|
||||||
|
function isBunInstalled() {
|
||||||
// Set PLUGIN_ROOT based on where we're running
|
try {
|
||||||
// If from cache, install dependencies IN the cache directory (where hooks run)
|
const result = spawnSync('bun', ['--version'], {
|
||||||
// If from marketplace, use marketplace directory
|
encoding: 'utf-8',
|
||||||
const PLUGIN_ROOT = IS_RUNNING_FROM_CACHE
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
? SCRIPT_ROOT // Cache directory (e.g., ~/.claude/plugins/cache/thedotmack/claude-mem/7.0.3/)
|
shell: IS_WINDOWS
|
||||||
: join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
|
});
|
||||||
|
return result.status === 0;
|
||||||
const PACKAGE_JSON_PATH = join(PLUGIN_ROOT, 'package.json');
|
} catch {
|
||||||
const VERSION_MARKER_PATH = join(PLUGIN_ROOT, '.install-version');
|
return false;
|
||||||
const NODE_MODULES_PATH = join(PLUGIN_ROOT, 'node_modules');
|
}
|
||||||
|
|
||||||
// Colors for output
|
|
||||||
const colors = {
|
|
||||||
reset: '\x1b[0m',
|
|
||||||
bright: '\x1b[1m',
|
|
||||||
green: '\x1b[32m',
|
|
||||||
yellow: '\x1b[33m',
|
|
||||||
red: '\x1b[31m',
|
|
||||||
cyan: '\x1b[36m',
|
|
||||||
dim: '\x1b[2m',
|
|
||||||
};
|
|
||||||
|
|
||||||
function log(message, color = colors.reset) {
|
|
||||||
console.error(`${color}${message}${colors.reset}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPackageVersion() {
|
/**
|
||||||
|
* Get Bun version if installed
|
||||||
|
*/
|
||||||
|
function getBunVersion() {
|
||||||
try {
|
try {
|
||||||
const packageJson = JSON.parse(readFileSync(PACKAGE_JSON_PATH, 'utf-8'));
|
const result = spawnSync('bun', ['--version'], {
|
||||||
return packageJson.version;
|
encoding: 'utf-8',
|
||||||
} catch (error) {
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
log(`⚠️ Failed to read package.json: ${error.message}`, colors.yellow);
|
shell: IS_WINDOWS
|
||||||
|
});
|
||||||
|
return result.status === 0 ? result.stdout.trim() : null;
|
||||||
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeVersion() {
|
/**
|
||||||
return process.version; // e.g., "v22.21.1"
|
* Check if uv is installed and accessible
|
||||||
}
|
*/
|
||||||
|
function isUvInstalled() {
|
||||||
function getInstalledVersion() {
|
|
||||||
try {
|
try {
|
||||||
if (existsSync(VERSION_MARKER_PATH)) {
|
const result = spawnSync('uv', ['--version'], {
|
||||||
const content = readFileSync(VERSION_MARKER_PATH, 'utf-8').trim();
|
encoding: 'utf-8',
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
// Try parsing as JSON (new format)
|
shell: IS_WINDOWS
|
||||||
try {
|
});
|
||||||
const marker = JSON.parse(content);
|
return result.status === 0;
|
||||||
return {
|
} catch {
|
||||||
packageVersion: marker.packageVersion,
|
return false;
|
||||||
nodeVersion: marker.nodeVersion,
|
|
||||||
installedAt: marker.installedAt
|
|
||||||
};
|
|
||||||
} catch {
|
|
||||||
// Fallback: old format (plain text version string)
|
|
||||||
return {
|
|
||||||
packageVersion: content,
|
|
||||||
nodeVersion: null, // Unknown
|
|
||||||
installedAt: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Marker doesn't exist or can't be read
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInstalledVersion(packageVersion, nodeVersion) {
|
/**
|
||||||
|
* Get uv version if installed
|
||||||
|
*/
|
||||||
|
function getUvVersion() {
|
||||||
try {
|
try {
|
||||||
const marker = {
|
const result = spawnSync('uv', ['--version'], {
|
||||||
packageVersion,
|
encoding: 'utf-8',
|
||||||
nodeVersion,
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
installedAt: new Date().toISOString()
|
shell: IS_WINDOWS
|
||||||
};
|
});
|
||||||
writeFileSync(VERSION_MARKER_PATH, JSON.stringify(marker, null, 2), 'utf-8');
|
return result.status === 0 ? result.stdout.trim() : null;
|
||||||
} catch (error) {
|
} catch {
|
||||||
log(`⚠️ Failed to write version marker: ${error.message}`, colors.yellow);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function needsInstall() {
|
/**
|
||||||
// Check if package.json exists (required for npm install)
|
* Install Bun automatically based on platform
|
||||||
if (!existsSync(PACKAGE_JSON_PATH)) {
|
*/
|
||||||
log(`⚠️ No package.json found at ${PLUGIN_ROOT}`, colors.yellow);
|
function installBun() {
|
||||||
return false; // Can't install without package.json
|
console.error('🔧 Bun not found. Installing Bun runtime...');
|
||||||
}
|
|
||||||
|
|
||||||
// Check if node_modules exists
|
try {
|
||||||
if (!existsSync(NODE_MODULES_PATH)) {
|
if (IS_WINDOWS) {
|
||||||
log('📦 Dependencies not found - first time setup', colors.cyan);
|
// Windows: Use PowerShell installer
|
||||||
return true;
|
console.error(' Installing via PowerShell...');
|
||||||
}
|
execSync('powershell -c "irm bun.sh/install.ps1 | iex"', {
|
||||||
|
stdio: 'inherit',
|
||||||
// Check version marker
|
shell: true
|
||||||
const currentPackageVersion = getPackageVersion();
|
|
||||||
const currentNodeVersion = getNodeVersion();
|
|
||||||
const installed = getInstalledVersion();
|
|
||||||
|
|
||||||
if (!installed) {
|
|
||||||
log('📦 No version marker found - installing', colors.cyan);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check package version
|
|
||||||
if (currentPackageVersion !== installed.packageVersion) {
|
|
||||||
log(`📦 Version changed (${installed.packageVersion} → ${currentPackageVersion}) - updating`, colors.cyan);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Node.js version
|
|
||||||
if (installed.nodeVersion && currentNodeVersion !== installed.nodeVersion) {
|
|
||||||
log(`📦 Node.js version changed (${installed.nodeVersion} → ${currentNodeVersion}) - rebuilding native modules`, colors.cyan);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If old format (no nodeVersion), assume needs install
|
|
||||||
if (!installed.nodeVersion) {
|
|
||||||
log('📦 Old version marker format - updating', colors.cyan);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All good - no install needed
|
|
||||||
log(`✓ Dependencies already installed (v${currentPackageVersion})`, colors.dim);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runNpmInstall() {
|
|
||||||
const isWindows = process.platform === 'win32';
|
|
||||||
|
|
||||||
log('', colors.cyan);
|
|
||||||
log(`🔨 Installing dependencies in ${IS_RUNNING_FROM_CACHE ? 'cache' : 'marketplace'}...`, colors.bright);
|
|
||||||
log(` ${PLUGIN_ROOT}`, colors.dim);
|
|
||||||
log('', colors.reset);
|
|
||||||
|
|
||||||
// Try normal install first, then retry with force if it fails
|
|
||||||
const strategies = [
|
|
||||||
{ command: 'npm install', label: 'normal' },
|
|
||||||
{ command: 'npm install --force', label: 'with force flag' },
|
|
||||||
];
|
|
||||||
|
|
||||||
let lastError = null;
|
|
||||||
|
|
||||||
for (const { command, label } of strategies) {
|
|
||||||
try {
|
|
||||||
log(`Attempting install ${label}...`, colors.dim);
|
|
||||||
|
|
||||||
// Run npm install silently
|
|
||||||
execSync(command, {
|
|
||||||
cwd: PLUGIN_ROOT,
|
|
||||||
stdio: 'pipe', // Silent output unless error
|
|
||||||
encoding: 'utf-8',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const packageVersion = getPackageVersion();
|
|
||||||
const nodeVersion = getNodeVersion();
|
|
||||||
setInstalledVersion(packageVersion, nodeVersion);
|
|
||||||
|
|
||||||
log('', colors.green);
|
|
||||||
log('✅ Dependencies installed successfully!', colors.bright);
|
|
||||||
log(` Package version: ${packageVersion}`, colors.dim);
|
|
||||||
log(` Node.js version: ${nodeVersion}`, colors.dim);
|
|
||||||
log('', colors.reset);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
lastError = error;
|
|
||||||
// Continue to next strategy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All strategies failed - show error
|
|
||||||
log('', colors.red);
|
|
||||||
log('❌ Installation failed after retrying!', colors.bright);
|
|
||||||
log('', colors.reset);
|
|
||||||
|
|
||||||
// Show generic error info with troubleshooting steps
|
|
||||||
if (lastError) {
|
|
||||||
if (lastError.stderr) {
|
|
||||||
log('Error output:', colors.dim);
|
|
||||||
log(lastError.stderr.toString(), colors.red);
|
|
||||||
} else if (lastError.message) {
|
|
||||||
log(lastError.message, colors.red);
|
|
||||||
}
|
|
||||||
|
|
||||||
log('', colors.yellow);
|
|
||||||
log('📋 Troubleshooting Steps:', colors.bright);
|
|
||||||
log('', colors.reset);
|
|
||||||
log('1. Check your internet connection', colors.yellow);
|
|
||||||
log('2. Try running: npm cache clean --force', colors.yellow);
|
|
||||||
log('3. Try running: npm install (in plugin directory)', colors.yellow);
|
|
||||||
log('4. Check npm version: npm --version (requires npm 7+)', colors.yellow);
|
|
||||||
log('5. Try updating npm: npm install -g npm@latest', colors.yellow);
|
|
||||||
log('', colors.reset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
try {
|
|
||||||
// Log execution context for debugging
|
|
||||||
if (IS_RUNNING_FROM_CACHE) {
|
|
||||||
log('📍 Running from cache directory', colors.dim);
|
|
||||||
} else {
|
} else {
|
||||||
log('📍 Running from marketplace directory', colors.dim);
|
// Unix/macOS: Use curl installer
|
||||||
|
console.error(' Installing via curl...');
|
||||||
|
execSync('curl -fsSL https://bun.sh/install | bash', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we need to install dependencies
|
// Verify installation
|
||||||
const installNeeded = needsInstall();
|
if (isBunInstalled()) {
|
||||||
|
const version = getBunVersion();
|
||||||
|
console.error(`✅ Bun ${version} installed successfully`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Bun may be installed but not in PATH yet for this session
|
||||||
|
// Try common installation paths
|
||||||
|
const bunPaths = IS_WINDOWS
|
||||||
|
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
||||||
|
: [join(homedir(), '.bun', 'bin', 'bun'), '/usr/local/bin/bun'];
|
||||||
|
|
||||||
if (installNeeded) {
|
for (const bunPath of bunPaths) {
|
||||||
// Run installation (now async)
|
if (existsSync(bunPath)) {
|
||||||
const installSuccess = await runNpmInstall();
|
console.error(`✅ Bun installed at ${bunPath}`);
|
||||||
|
console.error('⚠️ Please restart your terminal or add Bun to PATH:');
|
||||||
if (!installSuccess) {
|
if (IS_WINDOWS) {
|
||||||
log('', colors.red);
|
console.error(` $env:Path += ";${join(homedir(), '.bun', 'bin')}"`);
|
||||||
log('⚠️ Installation failed', colors.yellow);
|
} else {
|
||||||
log('', colors.reset);
|
console.error(` export PATH="$HOME/.bun/bin:$PATH"`);
|
||||||
process.exit(1);
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new Error('Bun installation completed but binary not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Worker auto-start disabled in smart-install.js
|
|
||||||
// The context-hook.js calls ensureWorkerRunning() which handles worker startup
|
|
||||||
// This avoids potential process management conflicts during plugin initialization
|
|
||||||
log('✅ Installation complete', colors.green);
|
|
||||||
|
|
||||||
// Success - dependencies installed (if needed)
|
|
||||||
process.exit(0);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log(`❌ Unexpected error: ${error.message}`, colors.red);
|
console.error('❌ Failed to install Bun automatically');
|
||||||
log('', colors.reset);
|
console.error(' Please install manually:');
|
||||||
process.exit(1);
|
if (IS_WINDOWS) {
|
||||||
|
console.error(' - winget install Oven-sh.Bun');
|
||||||
|
console.error(' - Or: powershell -c "irm bun.sh/install.ps1 | iex"');
|
||||||
|
} else {
|
||||||
|
console.error(' - curl -fsSL https://bun.sh/install | bash');
|
||||||
|
console.error(' - Or: brew install oven-sh/bun/bun');
|
||||||
|
}
|
||||||
|
console.error(' Then restart your terminal and try again.');
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
/**
|
||||||
|
* Install uv automatically based on platform
|
||||||
|
*/
|
||||||
|
function installUv() {
|
||||||
|
console.error('🐍 Installing uv for Python/Chroma support...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
// Windows: Use PowerShell installer
|
||||||
|
console.error(' Installing via PowerShell...');
|
||||||
|
execSync('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Unix/macOS: Use curl installer
|
||||||
|
console.error(' Installing via curl...');
|
||||||
|
execSync('curl -LsSf https://astral.sh/uv/install.sh | sh', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify installation
|
||||||
|
if (isUvInstalled()) {
|
||||||
|
const version = getUvVersion();
|
||||||
|
console.error(`✅ uv ${version} installed successfully`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// uv may be installed but not in PATH yet for this session
|
||||||
|
// Try common installation paths
|
||||||
|
const uvPaths = IS_WINDOWS
|
||||||
|
? [join(homedir(), '.local', 'bin', 'uv.exe'), join(homedir(), '.cargo', 'bin', 'uv.exe')]
|
||||||
|
: [join(homedir(), '.local', 'bin', 'uv'), join(homedir(), '.cargo', 'bin', 'uv'), '/usr/local/bin/uv'];
|
||||||
|
|
||||||
|
for (const uvPath of uvPaths) {
|
||||||
|
if (existsSync(uvPath)) {
|
||||||
|
console.error(`✅ uv installed at ${uvPath}`);
|
||||||
|
console.error('⚠️ Please restart your terminal or add uv to PATH:');
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
console.error(` $env:Path += ";${join(homedir(), '.local', 'bin')}"`);
|
||||||
|
} else {
|
||||||
|
console.error(` export PATH="$HOME/.local/bin:$PATH"`);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('uv installation completed but binary not found');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Failed to install uv automatically');
|
||||||
|
console.error(' Please install manually:');
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
console.error(' - winget install astral-sh.uv');
|
||||||
|
console.error(' - Or: powershell -c "irm https://astral.sh/uv/install.ps1 | iex"');
|
||||||
|
} else {
|
||||||
|
console.error(' - curl -LsSf https://astral.sh/uv/install.sh | sh');
|
||||||
|
console.error(' - Or: brew install uv (macOS)');
|
||||||
|
}
|
||||||
|
console.error(' Then restart your terminal and try again.');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if dependencies need to be installed
|
||||||
|
*/
|
||||||
|
function needsInstall() {
|
||||||
|
if (!existsSync(join(ROOT, 'node_modules'))) return true;
|
||||||
|
try {
|
||||||
|
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
||||||
|
const marker = JSON.parse(readFileSync(MARKER, 'utf-8'));
|
||||||
|
return pkg.version !== marker.version || getBunVersion() !== marker.bun;
|
||||||
|
} catch {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install dependencies using Bun
|
||||||
|
*/
|
||||||
|
function installDeps() {
|
||||||
|
console.error('📦 Installing dependencies with Bun...');
|
||||||
|
try {
|
||||||
|
execSync('bun install', { cwd: ROOT, stdio: 'inherit', shell: IS_WINDOWS });
|
||||||
|
} catch {
|
||||||
|
// Retry with force flag
|
||||||
|
execSync('bun install --force', { cwd: ROOT, stdio: 'inherit', shell: IS_WINDOWS });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write version marker
|
||||||
|
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
||||||
|
writeFileSync(MARKER, JSON.stringify({
|
||||||
|
version: pkg.version,
|
||||||
|
bun: getBunVersion(),
|
||||||
|
uv: getUvVersion(),
|
||||||
|
installedAt: new Date().toISOString()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main execution
|
||||||
|
try {
|
||||||
|
// Step 1: Ensure Bun is installed (REQUIRED)
|
||||||
|
if (!isBunInstalled()) {
|
||||||
|
installBun();
|
||||||
|
|
||||||
|
// Re-check after installation
|
||||||
|
if (!isBunInstalled()) {
|
||||||
|
console.error('❌ Bun is required but not available in PATH');
|
||||||
|
console.error(' Please restart your terminal after installation');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Ensure uv is installed (REQUIRED for vector search)
|
||||||
|
if (!isUvInstalled()) {
|
||||||
|
installUv();
|
||||||
|
|
||||||
|
// Re-check after installation
|
||||||
|
if (!isUvInstalled()) {
|
||||||
|
console.error('❌ uv is required but not available in PATH');
|
||||||
|
console.error(' Please restart your terminal after installation');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Install dependencies if needed
|
||||||
|
if (needsInstall()) {
|
||||||
|
installDeps();
|
||||||
|
console.error('✅ Dependencies installed');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Installation failed:', e.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user