style(design): apply Minimal Dark Mode design system\n\n- Switched to complete Dark Mode (OLED-friendly)\n- Established standard color palette matching modern technical aesthetics\n- Changed font to Plus Jakarta Sans for increased legibility\n- Enforced dark mode as default in App.tsx\n- Fixed several React cascading render (setState in useEffect) warnings
This commit is contained in:
1 parent
b80531f8a8
commit
bac7b5591e
738 files changed
+138513
-138123
No files matched your search
@@ -0,0 +1,619 @@
|
||||
/**
|
||||
* Cross-platform development environment setup for Gemini Nexus.
|
||||
*
|
||||
* Detects and installs native build toolchains required by better-sqlite3,
|
||||
* keytar, and other native Node.js modules used in this Electron project.
|
||||
*
|
||||
* Platforms:
|
||||
* - Windows → Visual Studio 2022 Build Tools (C++ workload)
|
||||
* - macOS → Xcode Command Line Tools
|
||||
* - Ubuntu → build-essential, python3, libsecret-1-dev
|
||||
* - Manjaro/Arch → base-devel, python, libsecret
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/setup-dev.js # auto-detect and install/guide
|
||||
* node scripts/setup-dev.js --check-only # only verify, don't install
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { execSync, spawnSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
// ─── Terminal Color Helpers ─────────────────────────────────────────────────
|
||||
|
||||
const RESET = '\x1b[0m';
|
||||
const BOLD = '\x1b[1m';
|
||||
const DIM = '\x1b[2m';
|
||||
const RED = '\x1b[31m';
|
||||
const GREEN = '\x1b[32m';
|
||||
const YELLOW = '\x1b[33m';
|
||||
const CYAN = '\x1b[36m';
|
||||
const MAGENTA = '\x1b[35m';
|
||||
|
||||
// Disable colors if NO_COLOR is set or output is piped
|
||||
const useColor = process.env.NO_COLOR === undefined && process.stdout.isTTY;
|
||||
|
||||
function color(code, text) {
|
||||
return useColor ? `${code}${text}${RESET}` : text;
|
||||
}
|
||||
|
||||
function header(text) {
|
||||
console.log(`\n${color(BOLD + MAGENTA, '══')} ${color(BOLD, text)} ${color(BOLD + MAGENTA, '══')}`);
|
||||
}
|
||||
|
||||
function success(text) {
|
||||
console.log(` ${color(GREEN, '✓')} ${text}`);
|
||||
}
|
||||
|
||||
function warn(text) {
|
||||
console.log(` ${color(YELLOW, '⚠')} ${text}`);
|
||||
}
|
||||
|
||||
function error(text) {
|
||||
console.log(` ${color(RED, '✗')} ${text}`);
|
||||
}
|
||||
|
||||
function info(text) {
|
||||
console.log(` ${color(CYAN, '→')} ${text}`);
|
||||
}
|
||||
|
||||
function dim(text) {
|
||||
console.log(` ${color(DIM, text)}`);
|
||||
}
|
||||
|
||||
function section(title) {
|
||||
console.log(`\n ${color(BOLD, title)}:`);
|
||||
}
|
||||
|
||||
// ─── Platform Detection ─────────────────────────────────────────────────────
|
||||
|
||||
const platform = os.platform(); // 'win32' | 'darwin' | 'linux'
|
||||
const arch = os.arch();
|
||||
|
||||
/** Detect Linux distribution from os-release */
|
||||
function detectLinuxDistro() {
|
||||
try {
|
||||
const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
|
||||
const idMatch = osRelease.match(/^ID="?([^"\n]+)"?/m);
|
||||
const idLikeMatch = osRelease.match(/^ID_LIKE="?([^"\n]+)"?/m);
|
||||
|
||||
const id = idMatch ? idMatch[1].toLowerCase() : '';
|
||||
const idLike = idLikeMatch ? idLikeMatch[1].toLowerCase() : '';
|
||||
|
||||
if (id === 'ubuntu' || id === 'debian' || idLike.includes('debian')) {
|
||||
return 'debian';
|
||||
}
|
||||
if (id === 'arch' || id === 'manjaro' || idLike.includes('arch')) {
|
||||
return 'arch';
|
||||
}
|
||||
if (id === 'fedora' || idLike.includes('fedora') || idLike.includes('rhel')) {
|
||||
return 'fedora';
|
||||
}
|
||||
return id || 'unknown';
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Tool Checkers ──────────────────────────────────────────────────────────
|
||||
|
||||
/** Check if a command exists on PATH */
|
||||
function commandExists(cmd) {
|
||||
try {
|
||||
const whereCmd = platform === 'win32' ? 'where' : 'which';
|
||||
execSync(`${whereCmd} "${cmd}"`, { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if running with administrator/sudo privileges */
|
||||
function hasAdminPrivileges() {
|
||||
if (platform === 'win32') {
|
||||
try {
|
||||
// On Windows, check via net session (requires admin)
|
||||
execSync('net session', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// On Unix, check if UID is 0
|
||||
return process.getuid ? process.getuid() === 0 : false;
|
||||
}
|
||||
|
||||
/** Check Windows: Visual Studio Build Tools */
|
||||
function checkWindows() {
|
||||
const results = { ok: true, missing: [] };
|
||||
|
||||
// Check for cl.exe (C++ compiler from VS Build Tools)
|
||||
if (commandExists('cl.exe')) {
|
||||
success('MSVC Compiler (cl.exe) found');
|
||||
} else {
|
||||
// Try to find VS installation via vswhere or registry
|
||||
let vsFound = false;
|
||||
|
||||
// vswhere.exe (shipped with VS 2017+)
|
||||
const vswherePaths = [
|
||||
'C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe',
|
||||
'C:\\Program Files\\Microsoft Visual Studio\\Installer\\vswhere.exe',
|
||||
];
|
||||
|
||||
for (const vswhere of vswherePaths) {
|
||||
try {
|
||||
const output = execSync(`"${vswhere}" -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`, {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
encoding: 'utf8',
|
||||
}).trim();
|
||||
|
||||
if (output) {
|
||||
vsFound = true;
|
||||
success(`Visual Studio found at: ${output}`);
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// vswhere not found, continue
|
||||
}
|
||||
}
|
||||
|
||||
// Check registry fallback
|
||||
if (!vsFound) {
|
||||
try {
|
||||
execSync(
|
||||
'reg query "HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7" /v 17.0',
|
||||
{ stdio: 'ignore' },
|
||||
);
|
||||
vsFound = true;
|
||||
success('Visual Studio 2022 found (registry)');
|
||||
} catch {
|
||||
// Not found in registry either
|
||||
}
|
||||
}
|
||||
|
||||
if (!vsFound) {
|
||||
error('MSVC Build Tools not found');
|
||||
results.ok = false;
|
||||
results.missing.push('msvc');
|
||||
}
|
||||
}
|
||||
|
||||
// Check Python (needed by node-gyp)
|
||||
if (commandExists('python') || commandExists('python3')) {
|
||||
success('Python found');
|
||||
} else {
|
||||
error('Python not found (required by node-gyp)');
|
||||
results.ok = false;
|
||||
results.missing.push('python');
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Check macOS: Xcode Command Line Tools */
|
||||
function checkMacOS() {
|
||||
const results = { ok: true, missing: [] };
|
||||
|
||||
try {
|
||||
const xcodePath = execSync('xcode-select -p', { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }).trim();
|
||||
if (xcodePath) {
|
||||
success(`Xcode CLT found at: ${xcodePath}`);
|
||||
}
|
||||
} catch {
|
||||
error('Xcode Command Line Tools not found');
|
||||
results.ok = false;
|
||||
results.missing.push('xcode-clt');
|
||||
}
|
||||
|
||||
if (commandExists('make') || commandExists('gmake')) {
|
||||
success('make found');
|
||||
} else {
|
||||
error('make not found');
|
||||
results.ok = false;
|
||||
results.missing.push('make');
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Check Linux: build-essential, python3, libsecret */
|
||||
function checkLinux() {
|
||||
const results = { ok: true, missing: [] };
|
||||
const distro = detectLinuxDistro();
|
||||
|
||||
section(`Linux Distribution Detected: ${distro || 'unknown'}`);
|
||||
|
||||
// gcc / g++
|
||||
if (commandExists('gcc') || commandExists('cc')) {
|
||||
success('C compiler found');
|
||||
} else {
|
||||
error('C compiler not found');
|
||||
results.ok = false;
|
||||
results.missing.push('compiler');
|
||||
}
|
||||
|
||||
if (commandExists('g++') || commandExists('c++')) {
|
||||
success('C++ compiler found');
|
||||
} else {
|
||||
error('C++ compiler not found');
|
||||
results.ok = false;
|
||||
results.missing.push('compiler');
|
||||
}
|
||||
|
||||
// make
|
||||
if (commandExists('make')) {
|
||||
success('make found');
|
||||
} else {
|
||||
error('make not found');
|
||||
results.ok = false;
|
||||
results.missing.push('make');
|
||||
}
|
||||
|
||||
// Python 3
|
||||
if (commandExists('python3')) {
|
||||
success('Python 3 found');
|
||||
} else if (commandExists('python')) {
|
||||
// Check if python is python3
|
||||
try {
|
||||
const ver = execSync('python --version', { encoding: 'utf8' });
|
||||
if (ver.includes('3.')) {
|
||||
success('Python 3 found (as python)');
|
||||
} else {
|
||||
error('Python 3 not found (python is v2)');
|
||||
results.ok = false;
|
||||
results.missing.push('python3');
|
||||
}
|
||||
} catch {
|
||||
error('Python not found');
|
||||
results.ok = false;
|
||||
results.missing.push('python3');
|
||||
}
|
||||
} else {
|
||||
error('Python 3 not found');
|
||||
results.ok = false;
|
||||
results.missing.push('python3');
|
||||
}
|
||||
|
||||
// libsecret (needed by keytar)
|
||||
try {
|
||||
if (distro === 'debian') {
|
||||
execSync('dpkg -s libsecret-1-dev', { stdio: 'ignore' });
|
||||
success('libsecret-1-dev found');
|
||||
} else if (distro === 'arch') {
|
||||
execSync('pacman -Qi libsecret', { stdio: 'ignore' });
|
||||
success('libsecret found');
|
||||
} else {
|
||||
// Check for pkg-config
|
||||
try {
|
||||
execSync('pkg-config --exists libsecret-1', { stdio: 'ignore' });
|
||||
success('libsecret (pkg-config) found');
|
||||
} catch {
|
||||
warn('libsecret not detected (may not be needed if using prebuilt keytar)');
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
warn('libsecret not detected (may not be needed if using prebuilt keytar)');
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// ─── Installation Helpers ───────────────────────────────────────────────────
|
||||
|
||||
/** Run a command and stream output, return exit code */
|
||||
function runCommand(cmd, args, opts = {}) {
|
||||
return new Promise((resolve) => {
|
||||
console.log(`\n ${color(CYAN, 'Running:')} ${color(DIM, `${cmd} ${args.join(' ')}`)}`);
|
||||
|
||||
const child = spawnSync(cmd, args, {
|
||||
stdio: 'inherit',
|
||||
shell: platform === 'win32',
|
||||
...opts,
|
||||
});
|
||||
|
||||
resolve(child.status);
|
||||
});
|
||||
}
|
||||
|
||||
/** Install Windows: Visual Studio 2022 Build Tools via winget */
|
||||
async function installWindows() {
|
||||
// Check if winget is available
|
||||
if (!commandExists('winget')) {
|
||||
console.log('');
|
||||
console.log(color(RED, ' winget not found. Please install Visual Studio Build Tools manually:'));
|
||||
console.log(color(CYAN, ' https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022'));
|
||||
console.log('');
|
||||
console.log(' During installation, select:');
|
||||
console.log(color(BOLD, ' "Desktop development with C++" workload'));
|
||||
console.log('');
|
||||
console.log(' Or install via PowerShell (as Administrator):');
|
||||
console.log(color(DIM, ' winget install Microsoft.VisualStudio.2022.BuildTools --override "--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"'));
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
info('Attempting automatic installation of Visual Studio 2022 Build Tools...');
|
||||
dim('This may take several minutes and requires administrator privileges.');
|
||||
console.log('');
|
||||
|
||||
if (!hasAdminPrivileges()) {
|
||||
warn('Not running as Administrator. winget may prompt for elevation.');
|
||||
}
|
||||
|
||||
const status = await runCommand('winget', [
|
||||
'install',
|
||||
'Microsoft.VisualStudio.2022.BuildTools',
|
||||
'--override',
|
||||
'"--quiet --wait --norestart --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.22621 --includeRecommended"',
|
||||
]);
|
||||
|
||||
if (status === 0) {
|
||||
success('Visual Studio 2022 Build Tools installed successfully.');
|
||||
console.log('');
|
||||
warn('You may need to restart your terminal for PATH changes to take effect.');
|
||||
return true;
|
||||
}
|
||||
|
||||
error('Automatic installation failed. Please install manually.');
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Install macOS: Xcode Command Line Tools */
|
||||
async function installMacOS() {
|
||||
console.log('');
|
||||
info('Installing Xcode Command Line Tools...');
|
||||
dim('A GUI dialog will appear. Click "Install" to proceed.');
|
||||
|
||||
const status = await runCommand('xcode-select', ['--install']);
|
||||
|
||||
// xcode-select --install returns 1 if already installed or cancelled
|
||||
if (status === 0) {
|
||||
success('Xcode Command Line Tools installation initiated.');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if already installed (common false-negative)
|
||||
try {
|
||||
execSync('xcode-select -p', { stdio: 'ignore' });
|
||||
success('Xcode Command Line Tools are already installed.');
|
||||
return true;
|
||||
} catch {
|
||||
warn('Xcode CLT installation was cancelled or failed.');
|
||||
warn('You can install manually via: xcode-select --install');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Install Linux: distribution-specific packages */
|
||||
async function installLinux() {
|
||||
const distro = detectLinuxDistro();
|
||||
|
||||
if (distro === 'debian') {
|
||||
// Ubuntu / Debian
|
||||
if (!hasAdminPrivileges()) {
|
||||
warn('Root privileges required. You may be prompted for your password.');
|
||||
}
|
||||
|
||||
const status = await runCommand('sudo', [
|
||||
'apt-get', 'install', '-y',
|
||||
'build-essential',
|
||||
'python3',
|
||||
'libsecret-1-dev',
|
||||
'pkg-config',
|
||||
]);
|
||||
|
||||
if (status === 0) {
|
||||
success('Build dependencies installed successfully.');
|
||||
return true;
|
||||
}
|
||||
|
||||
error('Failed to install build dependencies.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distro === 'arch') {
|
||||
// Manjaro / Arch
|
||||
if (!hasAdminPrivileges()) {
|
||||
warn('Root privileges required. You may be prompted for your password.');
|
||||
}
|
||||
|
||||
const status = await runCommand('sudo', [
|
||||
'pacman', '-S', '--needed', '--noconfirm',
|
||||
'base-devel',
|
||||
'python',
|
||||
'libsecret',
|
||||
'pkg-config',
|
||||
]);
|
||||
|
||||
if (status === 0) {
|
||||
success('Build dependencies installed successfully.');
|
||||
return true;
|
||||
}
|
||||
|
||||
error('Failed to install build dependencies.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distro === 'fedora') {
|
||||
if (!hasAdminPrivileges()) {
|
||||
warn('Root privileges required. You may be prompted for your password.');
|
||||
}
|
||||
|
||||
const status = await runCommand('sudo', [
|
||||
'dnf', 'install', '-y',
|
||||
'gcc-c++',
|
||||
'make',
|
||||
'python3',
|
||||
'libsecret-devel',
|
||||
'pkg-config',
|
||||
]);
|
||||
|
||||
if (status === 0) {
|
||||
success('Build dependencies installed successfully.');
|
||||
return true;
|
||||
}
|
||||
|
||||
error('Failed to install build dependencies.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unknown distro - provide generic instructions
|
||||
console.log('');
|
||||
warn(`Unknown Linux distribution: ${distro}`);
|
||||
console.log('');
|
||||
console.log(' You need the following packages to compile native Node.js modules:');
|
||||
console.log(' - C/C++ compiler (gcc, g++)');
|
||||
console.log(' - GNU Make');
|
||||
console.log(' - Python 3');
|
||||
console.log(' - libsecret development headers (for keytar)');
|
||||
console.log(' - pkg-config');
|
||||
console.log('');
|
||||
console.log(' Install them using your distribution package manager, then run npm install again.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// ─── Main ───────────────────────────────────────────────────────────────────
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const checkOnly = args.includes('--check-only') || args.includes('--check');
|
||||
|
||||
console.log('');
|
||||
console.log(color(BOLD + CYAN, '┌──────────────────────────────────────────┐'));
|
||||
console.log(color(BOLD + CYAN, '│ Gemini Nexus - Dev Environment Setup │'));
|
||||
console.log(color(BOLD + CYAN, '└──────────────────────────────────────────┘'));
|
||||
console.log('');
|
||||
dim(`Platform: ${platform} (${arch})`);
|
||||
dim(`Node.js: ${process.version}`);
|
||||
|
||||
// Step 1: Check current state
|
||||
header('Checking Build Toolchain');
|
||||
|
||||
let results;
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
results = checkWindows();
|
||||
break;
|
||||
case 'darwin':
|
||||
results = checkMacOS();
|
||||
break;
|
||||
case 'linux':
|
||||
results = checkLinux();
|
||||
break;
|
||||
default:
|
||||
console.log('');
|
||||
error(`Unsupported platform: ${platform}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Print summary
|
||||
console.log('');
|
||||
if (results.ok) {
|
||||
success('All build tools are present and ready.');
|
||||
console.log('');
|
||||
dim('You can now run: npm install && npm start');
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Missing tools ──
|
||||
console.log('');
|
||||
error('Some build tools are missing. Native modules like better-sqlite3 and keytar require compilation.');
|
||||
|
||||
if (checkOnly) {
|
||||
console.log('');
|
||||
warn('Build tools are missing. Native modules (better-sqlite3, keytar) require compilation.');
|
||||
warn('Run "npm run setup" to install them automatically, or install manually:');
|
||||
printManualInstructions(platform, results.missing);
|
||||
console.log('');
|
||||
dim('npm install succeeded, but npm start / electron-rebuild will fail until build tools are installed.');
|
||||
// Don't exit with error - allow npm install to succeed (prebuilt binaries may work)
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Attempt installation
|
||||
header('Installing Build Dependencies');
|
||||
|
||||
let installed = false;
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
installed = await installWindows();
|
||||
break;
|
||||
case 'darwin':
|
||||
installed = await installMacOS();
|
||||
break;
|
||||
case 'linux':
|
||||
installed = await installLinux();
|
||||
break;
|
||||
}
|
||||
|
||||
// Step 3: Final status
|
||||
console.log('');
|
||||
if (installed) {
|
||||
success('Setup complete. You can now run: npm install && npm start');
|
||||
console.log('');
|
||||
dim('If you encounter issues, restart your terminal and try again.');
|
||||
} else {
|
||||
console.log('');
|
||||
warn('Automatic installation was not successful.');
|
||||
warn('Please install the required tools manually, then run npm install again.');
|
||||
printManualInstructions(platform, results.missing);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function printManualInstructions(platform, missing) {
|
||||
console.log('');
|
||||
console.log(color(BOLD, ' ── Manual Installation Instructions ──'));
|
||||
console.log('');
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
console.log(' 1. Download Visual Studio 2022 Build Tools:');
|
||||
console.log(color(CYAN, ' https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022'));
|
||||
console.log('');
|
||||
console.log(' 2. Run the installer and select:');
|
||||
console.log(color(BOLD, ' "Desktop development with C++"'));
|
||||
console.log('');
|
||||
console.log(' 3. Or install via PowerShell (as Administrator):');
|
||||
console.log(color(DIM, ' winget install Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"'));
|
||||
console.log('');
|
||||
console.log(' 4. Restart your terminal after installation.');
|
||||
break;
|
||||
|
||||
case 'darwin':
|
||||
console.log(' Run this command in your terminal:');
|
||||
console.log(color(DIM, ' xcode-select --install'));
|
||||
console.log('');
|
||||
console.log(' Then click "Install" in the dialog that appears.');
|
||||
break;
|
||||
|
||||
case 'linux': {
|
||||
const distro = detectLinuxDistro();
|
||||
if (distro === 'debian') {
|
||||
console.log(' Run:');
|
||||
console.log(color(DIM, ' sudo apt-get install -y build-essential python3 libsecret-1-dev pkg-config'));
|
||||
} else if (distro === 'arch') {
|
||||
console.log(' Run:');
|
||||
console.log(color(DIM, ' sudo pacman -S --needed base-devel python libsecret pkg-config'));
|
||||
} else if (distro === 'fedora') {
|
||||
console.log(' Run:');
|
||||
console.log(color(DIM, ' sudo dnf install -y gcc-c++ make python3 libsecret-devel pkg-config'));
|
||||
} else {
|
||||
console.log(' Install: C/C++ compiler, make, python3, libsecret-dev, pkg-config');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// ─── Run ────────────────────────────────────────────────────────────────────
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(color(RED, `\nUnexpected error: ${err.message}`));
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in new issue
Block a user