tf_code/packages/tfcode/scripts/postinstall.cjs
2026-03-24 13:51:14 +11:00

171 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
const { spawn, execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const RESET = '\x1b[0m';
const BOLD = '\x1b[1m';
const GREEN = '\x1b[32m';
const YELLOW = '\x1b[33m';
const RED = '\x1b[31m';
const CYAN = '\x1b[36m';
const DIM = '\x1b[90m';
function log(msg) {
console.log(msg);
}
function logSuccess(msg) {
console.log(`${GREEN}${RESET} ${msg}`);
}
function logError(msg) {
console.error(`${RED}${RESET} ${msg}`);
}
function logInfo(msg) {
console.log(`${CYAN}${RESET} ${msg}`);
}
function logWarning(msg) {
console.log(`${YELLOW}!${RESET} ${msg}`);
}
function checkPython() {
const commands = ['python3', 'python'];
for (const cmd of commands) {
try {
const result = execSync(`${cmd} --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
const match = result.match(/Python (\d+)\.(\d+)/);
if (match) {
const major = parseInt(match[1]);
const minor = parseInt(match[2]);
if (major >= 3 && minor >= 10) {
return { cmd, version: result.trim() };
}
}
} catch {}
}
return null;
}
function installPythonDeps(pythonCmd) {
return new Promise((resolve, reject) => {
const packages = ['toothfairyai', 'pydantic', 'httpx', 'rich'];
log(`${DIM}Installing Python packages: ${packages.join(', ')}...${RESET}`);
// Try with --user first, then --break-system-packages if needed
const args = ['-m', 'pip', 'install', '--user', ...packages];
const proc = spawn(pythonCmd, args, {
stdio: 'inherit',
shell: process.platform === 'win32'
});
proc.on('close', (code) => {
if (code === 0) {
resolve();
} else {
// Try with --break-system-packages flag
log(`${DIM}Retrying with --break-system-packages...${RESET}`);
const retryArgs = ['-m', 'pip', 'install', '--user', '--break-system-packages', ...packages];
const retry = spawn(pythonCmd, retryArgs, {
stdio: 'inherit',
shell: process.platform === 'win32'
});
retry.on('close', (retryCode) => {
if (retryCode === 0) {
resolve();
} else {
reject(new Error(`pip install exited with code ${retryCode}`));
}
});
retry.on('error', (err) => {
reject(err);
});
}
});
proc.on('error', (err) => {
reject(err);
});
});
}
async function main() {
log('');
log(`${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
log(`${BOLD} tfcode - ToothFairyAI's official coding agent${RESET}`);
log(`${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
log('');
// Check for Python
logInfo('Checking Python installation...');
const python = checkPython();
if (!python) {
log('');
logError('Python 3.10+ is required but not found.');
log('');
log(`${BOLD}Please install Python 3.10 or later:${RESET}`);
log('');
log(` ${CYAN}macOS:${RESET} brew install python@3.12`);
log(` ${CYAN}Ubuntu:${RESET} sudo apt-get install python3.12`);
log(` ${CYAN}Windows:${RESET} Download from https://python.org/downloads`);
log('');
log(`${DIM}After installing Python, run: npm rebuild tfcode${RESET}`);
log('');
process.exit(1);
}
logSuccess(`Found ${python.version} (${python.cmd})`);
log('');
// Install Python dependencies
logInfo('Installing ToothFairyAI Python SDK...');
try {
await installPythonDeps(python.cmd);
logSuccess('Python dependencies installed');
} catch (err) {
logWarning(`Failed to install Python dependencies: ${err.message}`);
log('');
log(`${DIM}You can install them manually with:${RESET}`);
log(` ${CYAN}${python.cmd} -m pip install toothfairyai pydantic httpx rich${RESET}`);
log('');
// Don't exit - user might install manually later
}
log('');
log(`${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
log(`${GREEN}✓ tfcode installed successfully!${RESET}`);
log(`${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
log('');
log(`${BOLD}Quick Start:${RESET}`);
log('');
log(` ${CYAN}1.${RESET} Set your ToothFairyAI credentials:`);
log(` ${DIM}export TF_WORKSPACE_ID="your-workspace-id"${RESET}`);
log(` ${DIM}export TF_API_KEY="your-api-key"${RESET}`);
log('');
log(` ${CYAN}2.${RESET} Validate your credentials:`);
log(` ${DIM}tfcode validate${RESET}`);
log('');
log(` ${CYAN}3.${RESET} Sync tools from your workspace:`);
log(` ${DIM}tfcode sync${RESET}`);
log('');
log(` ${CYAN}4.${RESET} Start coding:`);
log(` ${DIM}tfcode${RESET}`);
log('');
log(`${DIM}Documentation: https://toothfairyai.com/developers/tfcode${RESET}`);
log('');
}
main().catch((err) => {
logError(`Installation failed: ${err.message}`);
process.exit(1);
});