UNPKG

@lenne.tech/cli

Version:

lenne.Tech CLI: lt

147 lines (146 loc) 6.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.printMigrateResult = printMigrateResult; exports.runMigrate = runMigrate; /** * Reusable init/migrate logic — used by `commands/dev/init.ts` (interactive * + verbose, also chained from `commands/dev/install.ts`) and * `commands/fullstack/init.ts` (silent best-effort after project creation). * * Returns a structured result so callers can decide what to print. * Idempotent — safe to run multiple times. */ const fs_1 = require("fs"); const gluegun_1 = require("gluegun"); const path_1 = require("path"); const dev_identity_1 = require("./dev-identity"); const dev_patches_1 = require("./dev-patches"); const dev_project_1 = require("./dev-project"); const dev_state_1 = require("./dev-state"); const package_name_1 = require("./package-name"); /** * Print a `runMigrate` result via the toolbox. Shared by `lt dev init` * and the auto-init step of `lt dev install` so both render identically. * Does NOT print Caddy-install hints — chaining handles that separately. */ function printMigrateResult(toolbox, result) { const { print: { colors, info, success }, } = toolbox; info(''); info(colors.bold(`Initializing "${result.identity.slug}" for lt dev`)); info(colors.dim('─'.repeat(60))); if (result.identity.subdomains.app) info(` App URL: https://${result.identity.subdomains.app.hostname}`); if (result.identity.subdomains.api) info(` API URL: https://${result.identity.subdomains.api.hostname}`); info(` DB: mongodb://127.0.0.1/${result.dbName}`); info(''); if (result.renamedTemplatePackage) { success(`renamed root package.json name → "${result.renamedTemplatePackage}" (was unmodified template default)`); } if (result.codePatches.length > 0) { for (const r of result.codePatches) { if (r.patched) success(`patched ${r.replacements}× in ${r.file}`); else info(colors.dim(`already patched: ${r.file}`)); } } else { info(colors.dim(' patches: not needed (already env-aware)')); } result.claudePatches.filter((r) => r.patched).forEach((r) => success(`updated CLAUDE.md URL block: ${r.file}`)); if (result.registryUpdated) { success(`registered in ${process.env.LT_DEV_REGISTRY_PATH || '~/.lenneTech/projects.json'}`); } if (result.addedGitignoreEntry) success('added `.lt-dev/` to .gitignore'); if (result.alreadyMigrated) { info(colors.dim(' Project was already initialized — nothing changed.')); } } /** * Run all migration steps for a resolved project. * * Idempotent — re-running with no changes returns `alreadyMigrated: true`. */ function runMigrate(input) { const { layout } = input; // 0. If the root package.json still carries an unmodified starter-template // name (e.g. `lt-monorepo` from a raw `git clone`), rewrite it to the // directory basename before deriving identity. Otherwise every cloned // project would slug to `lt-monorepo` and collide on // `https://lt-monorepo.localhost`. `lt fullstack init` already handles // this — the call here is the safety net for projects that bypassed // init (e.g. manual `git clone lenneTech/lt-monorepo my-project`). const renamedTemplatePackage = (0, package_name_1.renameUnmodifiedTemplatePackage)({ filesystem: gluegun_1.filesystem, projectRoot: layout.root, }); const identity = (0, dev_identity_1.buildIdentity)(layout.root); const dbName = (0, dev_project_1.deriveDbName)(layout.apiDir, identity.slug); // 1. Code patches. Run `autoPatch` over EVERY existing config file (not just // the ones a port-detector flags): the patches are idempotent, and some — // e.g. the playwright.config `ignoreHTTPSErrors` + shard-aware // `LT_DEV_TEST_SHARDS` timeout block — apply to configs that are already // env-aware. So `lt dev init` makes any project fully `lt dev test --shard` // ready in one command; an up-to-date config is a no-op (`patched: false`). const filesToPatch = []; if (layout.apiDir) { const apiCfg = (0, path_1.join)(layout.apiDir, 'src', 'config.env.ts'); if ((0, fs_1.existsSync)(apiCfg)) filesToPatch.push(apiCfg); } if (layout.appDir) { for (const rel of ['nuxt.config.ts', 'playwright.config.ts']) { const f = (0, path_1.join)(layout.appDir, rel); if ((0, fs_1.existsSync)(f)) filesToPatch.push(f); } } const codePatches = filesToPatch.map((f) => (0, dev_patches_1.autoPatch)(f)); // 2. CLAUDE.md URL block (root + each subproject — only patches existing files). const claudeCandidates = [ (0, path_1.join)(layout.root, 'CLAUDE.md'), ...(layout.apiDir ? [(0, path_1.join)(layout.apiDir, 'CLAUDE.md')] : []), ...(layout.appDir ? [(0, path_1.join)(layout.appDir, 'CLAUDE.md')] : []), ]; const claudePatches = claudeCandidates .filter((f) => (0, fs_1.existsSync)(f)) .map((f) => (0, dev_patches_1.patchClaudeMd)(f, { dbName, identity })); // 3. Registry — only write when something actually changed. const reg = (0, dev_state_1.loadRegistry)(); const subdomainMap = {}; for (const [k, v] of Object.entries(identity.subdomains)) subdomainMap[k] = v.hostname; const existing = reg.projects[identity.slug]; const next = { dbName, internalPorts: (existing === null || existing === void 0 ? void 0 : existing.internalPorts) || {}, lastUsedAt: existing === null || existing === void 0 ? void 0 : existing.lastUsedAt, path: layout.root, subdomains: subdomainMap, }; const registryChanged = !existing || existing.path !== next.path || existing.dbName !== next.dbName || JSON.stringify(existing.subdomains) !== JSON.stringify(next.subdomains); if (registryChanged) { reg.projects[identity.slug] = next; (0, dev_state_1.saveRegistry)(reg); } // 4. .gitignore const addedGitignoreEntry = (0, dev_patches_1.addToGitignore)(layout.root, '.lt-dev/'); const codePatched = codePatches.filter((r) => r.patched).length > 0; const claudePatched = claudePatches.filter((r) => r.patched).length > 0; const alreadyMigrated = !codePatched && !claudePatched && !registryChanged && !addedGitignoreEntry && !renamedTemplatePackage; return { addedGitignoreEntry, alreadyMigrated, claudePatches, codePatches, dbName, identity, registryUpdated: registryChanged, renamedTemplatePackage, }; }