mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-20 17:34:10 +01:00
* 📝 docs: Add AGENTS.md for project structure and coding standards
- Introduced AGENTS.md to outline project workspaces, coding standards, and development commands.
- Defined workspace boundaries for backend and frontend development, emphasizing TypeScript usage.
- Established guidelines for code style, iteration performance, type safety, and import order.
- Updated CONTRIBUTING.md to reference AGENTS.md for coding standards and project conventions.
- Modified package.json to streamline build commands, consolidating frontend and backend build processes.
* chore: Update build commands and improve smart reinstall process
- Modified AGENTS.md to clarify the purpose of `npm run smart-reinstall` and other build commands, emphasizing Turborepo's role in dependency management and builds.
- Updated package.json to streamline build commands, replacing the legacy frontend build with a Turborepo-based approach for improved performance.
- Enhanced the smart reinstall script to fully delegate build processes to Turborepo, including cache management and dependency checks, ensuring a more efficient build workflow.
181 lines
5.2 KiB
JavaScript
181 lines
5.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Smart Reinstall for LibreChat
|
|
*
|
|
* Combines cached dependency installation with Turborepo-powered builds.
|
|
*
|
|
* Dependencies (npm ci):
|
|
* Hashes package-lock.json and stores a marker in node_modules.
|
|
* Skips npm ci entirely when the lockfile hasn't changed.
|
|
*
|
|
* Package builds (Turborepo):
|
|
* Turbo hashes each package's source/config inputs (including the
|
|
* lockfile), caches build outputs (dist/), and restores from cache
|
|
* when inputs match. This script delegates entirely to turbo for builds.
|
|
*
|
|
* Usage:
|
|
* npm run smart-reinstall # Smart cached mode
|
|
* npm run smart-reinstall -- --force # Full clean reinstall, bust all caches
|
|
* npm run smart-reinstall -- --skip-client # Skip frontend (Vite) build
|
|
* npm run smart-reinstall -- --clean-cache # Wipe turbo build cache
|
|
* npm run smart-reinstall -- --verbose # Turbo verbose output
|
|
*/
|
|
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execSync } = require('child_process');
|
|
|
|
require('./helpers');
|
|
|
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
const DEPS_HASH_MARKER = path.join(ROOT_DIR, 'node_modules', '.librechat-deps-hash');
|
|
|
|
const flags = {
|
|
force: process.argv.includes('--force'),
|
|
cleanCache: process.argv.includes('--clean-cache'),
|
|
skipClient: process.argv.includes('--skip-client'),
|
|
verbose: process.argv.includes('--verbose'),
|
|
};
|
|
|
|
const NODE_MODULES_DIRS = [
|
|
ROOT_DIR,
|
|
path.join(ROOT_DIR, 'packages', 'data-provider'),
|
|
path.join(ROOT_DIR, 'packages', 'data-schemas'),
|
|
path.join(ROOT_DIR, 'packages', 'client'),
|
|
path.join(ROOT_DIR, 'packages', 'api'),
|
|
path.join(ROOT_DIR, 'client'),
|
|
path.join(ROOT_DIR, 'api'),
|
|
];
|
|
|
|
function hashFile(filePath) {
|
|
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex').slice(0, 16);
|
|
}
|
|
|
|
function exec(cmd, opts = {}) {
|
|
execSync(cmd, { cwd: ROOT_DIR, stdio: 'inherit', ...opts });
|
|
}
|
|
|
|
function checkDeps() {
|
|
const lockfile = path.join(ROOT_DIR, 'package-lock.json');
|
|
if (!fs.existsSync(lockfile)) {
|
|
return { needsInstall: true, hash: 'missing' };
|
|
}
|
|
|
|
const hash = hashFile(lockfile);
|
|
|
|
if (!fs.existsSync(path.join(ROOT_DIR, 'node_modules'))) {
|
|
return { needsInstall: true, hash };
|
|
}
|
|
if (!fs.existsSync(DEPS_HASH_MARKER)) {
|
|
return { needsInstall: true, hash };
|
|
}
|
|
|
|
const stored = fs.readFileSync(DEPS_HASH_MARKER, 'utf-8').trim();
|
|
return { needsInstall: stored !== hash, hash };
|
|
}
|
|
|
|
function installDeps(hash) {
|
|
const { deleteNodeModules } = require('./helpers');
|
|
NODE_MODULES_DIRS.forEach(deleteNodeModules);
|
|
|
|
console.purple('Cleaning npm cache...');
|
|
exec('npm cache clean --force');
|
|
|
|
console.purple('Installing dependencies (npm ci)...');
|
|
exec('npm ci');
|
|
|
|
fs.writeFileSync(DEPS_HASH_MARKER, hash, 'utf-8');
|
|
}
|
|
|
|
function runTurboBuild() {
|
|
const args = ['npx', 'turbo', 'run', 'build'];
|
|
|
|
if (flags.skipClient) {
|
|
args.push('--filter=!@librechat/frontend');
|
|
}
|
|
if (flags.force) {
|
|
args.push('--force');
|
|
}
|
|
if (flags.verbose) {
|
|
args.push('--verbosity=2');
|
|
}
|
|
|
|
const cmd = args.join(' ');
|
|
console.gray(` ${cmd}\n`);
|
|
exec(cmd);
|
|
}
|
|
|
|
function cleanTurboCache() {
|
|
console.purple('Clearing Turborepo cache...');
|
|
try {
|
|
exec('npx turbo daemon stop', { stdio: 'pipe' });
|
|
} catch {
|
|
// daemon may not be running
|
|
}
|
|
|
|
const localTurboCache = path.join(ROOT_DIR, '.turbo');
|
|
if (fs.existsSync(localTurboCache)) {
|
|
fs.rmSync(localTurboCache, { recursive: true });
|
|
}
|
|
|
|
try {
|
|
exec('npx turbo clean', { stdio: 'pipe' });
|
|
console.green('Turbo cache cleared.');
|
|
} catch {
|
|
console.gray('Could not clear global turbo cache (may not exist yet).');
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
const startTime = Date.now();
|
|
|
|
console.green('\n Smart Reinstall — LibreChat');
|
|
console.green('─'.repeat(45));
|
|
|
|
if (flags.cleanCache) {
|
|
cleanTurboCache();
|
|
if (!flags.force) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Step 1: Dependencies
|
|
console.purple('\n[1/2] Checking dependencies...');
|
|
|
|
if (flags.force) {
|
|
console.orange(' Force mode — reinstalling all dependencies');
|
|
const lockfile = path.join(ROOT_DIR, 'package-lock.json');
|
|
const hash = fs.existsSync(lockfile) ? hashFile(lockfile) : 'none';
|
|
installDeps(hash);
|
|
console.green(' Dependencies installed.');
|
|
} else {
|
|
const { needsInstall, hash } = checkDeps();
|
|
if (needsInstall) {
|
|
console.orange(' package-lock.json changed or node_modules missing');
|
|
installDeps(hash);
|
|
console.green(' Dependencies installed.');
|
|
} else {
|
|
console.green(' Dependencies up to date — skipping npm ci');
|
|
}
|
|
}
|
|
|
|
// Step 2: Build via Turborepo
|
|
console.purple('\n[2/2] Building packages...');
|
|
runTurboBuild();
|
|
|
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
console.log('');
|
|
console.green('─'.repeat(45));
|
|
console.green(` Done (${elapsed}s)`);
|
|
console.green(' Start the app with: npm run backend');
|
|
console.green('─'.repeat(45));
|
|
})().catch((err) => {
|
|
console.red(`\nError: ${err.message}`);
|
|
if (flags.verbose) {
|
|
console.red(err.stack);
|
|
}
|
|
console.gray(' Tip: run with --force to clean all caches and reinstall from scratch');
|
|
console.gray(' Tip: run with --verbose for detailed output');
|
|
process.exit(1);
|
|
});
|