mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 22:03:58 +00:00
171 lines
5.4 KiB
JavaScript
171 lines
5.4 KiB
JavaScript
#!/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);
|
||
}); |