{"version":3,"sources":["../src/deploy/index.js","../src/deploy/service.js","../src/deploy/paths.js","../src/deploy/run.js","../src/deploy/log.js","../src/deploy/git.js","../src/deploy/release.js","../src/deploy/activate.js","../src/deploy/deps.js","../src/deploy/test.js","../src/deploy/prune.js","../src/deploy/pm2.js","../src/deploy/nginx.js","../src/deploy/sync-env.js","../src/deploy/build-info.js","../src/deploy/init-structure.js","../src/deploy/bootstrap-host.js","../src/deploy/deploy-service.js","../src/deploy/provision-service.js","../src/deploy/rollback-service.js","../src/deploy/ssh-remote.js","../src/deploy/manifests.js"],"sourcesContent":["/**\n * Deploy ecosystem — manifest-driven EC2 release deploys (git checkout → versioned\n * releases under /apps/<svc>/ → pm2 + nginx upstream switch, with rollback).\n *\n * Projects describe each app as a \"service\" manifest (see ./service.js) and drive\n * everything from one CLI (scripts/deploy/cli.js, exposed as the `cli-deploy` bin).\n * The engine itself is project-agnostic: all specifics come from the manifest.\n */\nexport { defineService, deriveRepoDirName } from \"./service.js\";\nexport { servicePaths, releaseStamp, releaseDir } from \"./paths.js\";\nexport { run, runShell, runCapture, npmEnv, npmInstallEnv } from \"./run.js\";\nexport { appendDeployLog, deployNotice } from \"./log.js\";\nexport { cloneRepo, pullRepo } from \"./git.js\";\nexport { createRelease, readCurrentRelease, listReleases } from \"./release.js\";\nexport { activateRelease } from \"./activate.js\";\nexport { installDeps } from \"./deps.js\";\nexport { runReleaseTests } from \"./test.js\";\nexport { pruneReleases } from \"./prune.js\";\nexport {\n    reloadPm2,\n    stopPm2,\n    startPm2,\n    getPm2Process,\n    parsePm2Jlist,\n    waitPm2,\n    isPidAlive,\n    isFreshOnline,\n} from \"./pm2.js\";\nexport { enableNginxUpstream } from \"./nginx.js\";\nexport { syncEnv, scrubEnvContent } from \"./sync-env.js\";\nexport {\n    bumpPatchVersion,\n    resolveNextVersion,\n    readReleaseBuildInfo,\n    writeReleaseBuildInfo,\n} from \"./build-info.js\";\nexport { initServiceStructure } from \"./init-structure.js\";\nexport { bootstrapHost, installOperatorShell } from \"./bootstrap-host.js\";\nexport { deployService } from \"./deploy-service.js\";\nexport { provisionService } from \"./provision-service.js\";\nexport { rollbackService } from \"./rollback-service.js\";\nexport {\n    REMOTE_CLI_REL,\n    parseGitHost,\n    sshRun,\n    shellQuote,\n    ensureDeployKeyOnRemote,\n    prepareGitHost,\n    ensureRepoDependencies,\n    ensureEnvOnRemote,\n    ensureRemoteRepo,\n    runRemoteCli,\n    runRemoteStatus,\n} from \"./ssh-remote.js\";\nexport { loadServices, resolveServiceFrom } from \"./manifests.js\";\n","/**\n * A \"service\" is a plain manifest object describing how to deploy one app onto a\n * host. Projects define these; the engine is otherwise project-agnostic.\n *\n * Required:\n *   name        unique id, also the default pm2 app + nginx site name\n *   appsRoot    base dir on the host, e.g. /apps/<name>\n *   repoUrl     git url to clone (ssh git@… or https://…)\n *   pm2.script  entry script (relative to the release/cwd)\n *\n * Optional (sensible defaults applied by defineService):\n *   repoDirName     default: repo name derived from repoUrl\n *   repoSubdir      default: \"\" (release = repo root). Set \"v2\" for a monorepo subdir.\n *   keepReleases    default: 3\n *   testCommand     default: null  (shell run in the release before activating; null = skip)\n *   envScrubPatterns default: []   (regex source strings; matching .env lines are dropped)\n *   legacyRepoEnv   default: null  (fallback .env path on a pre-migration host)\n *   buildInfoPath   default: \"build-info.json\"  (written into each release, relative to release root)\n *   deployKey       default: null  (path to a git deploy key; only needed for ssh repoUrl)\n *   requireEnv      default: false (true = fail if no .env found; false = continue with empty)\n *   pm2: {\n *     appName=name, script, args=\"\", port,\n *     stopAllowance=60,   // seconds → injected as --stopAllowance=N on the process\n *     killTimeout=65000,  // ms; pm2 kill_timeout (default: stopAllowance*1000+5000)\n *     killRetryTime=10000, // ms; pm2 kill_retry_time (default 10s; pm2's own default is 100ms)\n *   }\n *   nginx: { siteName=name, fqdn }   (omit nginx entirely to skip the nginx step)\n */\nexport function deriveRepoDirName(repoUrl) {\n    const tail = String(repoUrl ?? \"\").split(\"/\").pop() ?? \"repo\";\n    return tail.replace(/\\.git$/, \"\") || \"repo\";\n}\n\nexport function defineService(service) {\n    if (!service?.name) throw new Error(\"service manifest needs a `name`\");\n    if (!service.appsRoot) throw new Error(`service \"${service.name}\" needs an appsRoot`);\n    if (!service.repoUrl) throw new Error(`service \"${service.name}\" needs a repoUrl`);\n    if (!service.pm2?.script) throw new Error(`service \"${service.name}\" needs pm2.script`);\n\n    const pm2 = {\n        appName: service.name,\n        args: \"\",\n        stopAllowance: 60,\n        ...service.pm2,\n    };\n    if (pm2.killTimeout == null) {\n        const stopSec = Number(pm2.stopAllowance);\n        pm2.killTimeout = Number.isFinite(stopSec) && stopSec > 0\n            ? Math.floor(stopSec * 1000) + 5000\n            : 65_000;\n    }\n    const nginx = service.nginx\n        ? { siteName: service.name, ...service.nginx }\n        : null;\n\n    return {\n        repoDirName: deriveRepoDirName(service.repoUrl),\n        repoSubdir: \"\",\n        keepReleases: 3,\n        testCommand: null,\n        envScrubPatterns: [],\n        legacyRepoEnv: null,\n        buildInfoPath: \"build-info.json\",\n        deployKey: null,\n        requireEnv: false,\n        ...service,\n        pm2,\n        nginx,\n    };\n}\n","import { join } from \"node:path\";\n\n/**\n * Resolve on-disk paths for a service under <appsRoot>/.\n *\n *   <appsRoot>/\n *     <repoDirName>/[<repoSubdir>/]   git checkout (build source only)\n *     releases/<stamp>/               one release = contents of the run dir\n *     shared/.env, ecosystem.config.cjs\n *     logs/deploy.log\n *     current -> releases/<stamp>\n */\nexport function servicePaths(service) {\n    const root = service.appsRoot;\n    const repoDirName = service.repoDirName ?? \"repo\";\n    const repoSubdir = service.repoSubdir ?? \"\";\n\n    const repo = join(root, repoDirName);\n    const repoRun = repoSubdir ? join(repo, repoSubdir) : repo;\n\n    return {\n        root,\n        repo,\n        repoRun,\n        repoEnv: join(repoRun, \".env\"),\n        releases: join(root, \"releases\"),\n        shared: join(root, \"shared\"),\n        logs: join(root, \"logs\"),\n        current: join(root, \"current\"),\n        sharedEnv: join(root, \"shared\", \".env\"),\n        ecosystem: join(root, \"shared\", \"ecosystem.config.cjs\"),\n        /** Preloaded by pm2 `node_args --require` so ENV survives flaky restarts. */\n        ensureEnv: join(root, \"shared\", \"ensure-env.cjs\"),\n        deployLog: join(root, \"logs\", \"deploy.log\"),\n        lockHashFile: join(root, \"shared\", \".package-lock.sha256\"),\n    };\n}\n\n/** ISO-8601 release stamp with `:` (safe on Linux ext4). */\nexport function releaseStamp(date = new Date()) {\n    return date.toISOString().replace(/\\.\\d{3}Z$/, \"Z\");\n}\n\nexport function releaseDir(releasesRoot, stamp) {\n    return join(releasesRoot, stamp);\n}\n","import { spawn } from \"node:child_process\";\n\n/** npm omits devDependencies when NODE_ENV=production — unset it for ci + tests. */\nexport function npmEnv(baseEnv = process.env) {\n    const env = { ...baseEnv };\n    delete env.NODE_ENV;\n    return env;\n}\n\n/** Env for npm ci/install so devDependencies are always installed. */\nexport function npmInstallEnv(baseEnv = process.env) {\n    return {\n        ...npmEnv(baseEnv),\n        NPM_CONFIG_PRODUCTION: \"false\",\n        npm_config_production: \"false\",\n    };\n}\n\n/** Run a command with inherited stdio. Rejects on non-zero exit. */\nexport function run(cmd, args, options = {}) {\n    const { cwd, env, logger } = options;\n\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`$ ${cmd} ${args.join(\" \")}${cwd ? `  (cwd=${cwd})` : \"\"}`);\n        const child = spawn(cmd, args, {\n            cwd,\n            env: env ?? process.env,\n            stdio: \"inherit\",\n        });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => {\n            if (code === 0) resolve();\n            else reject(new Error(`${cmd} exited with code ${code}`));\n        });\n    });\n}\n\n/** Run a shell one-liner via bash -lc. */\nexport function runShell(command, options = {}) {\n    return run(\"bash\", [\"-lc\", command], options);\n}\n\n/**\n * Run a command capturing stdout/stderr (for `pm2 jlist`, etc.).\n * Rejects on non-zero exit unless `allowFail` is set.\n *\n * @returns {Promise<{ stdout: string, stderr: string, code: number|null }>}\n */\nexport function runCapture(cmd, args, options = {}) {\n    const { cwd, env, logger, allowFail = false } = options;\n\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`$ ${cmd} ${args.join(\" \")}${cwd ? `  (cwd=${cwd})` : \"\"}`);\n        const child = spawn(cmd, args, {\n            cwd,\n            env: env ?? process.env,\n            stdio: [\"ignore\", \"pipe\", \"pipe\"],\n        });\n        let stdout = \"\";\n        let stderr = \"\";\n        child.stdout?.on(\"data\", (chunk) => {\n            stdout += chunk.toString();\n        });\n        child.stderr?.on(\"data\", (chunk) => {\n            stderr += chunk.toString();\n        });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => {\n            if (code === 0 || allowFail) resolve({ stdout, stderr, code });\n            else reject(new Error(`${cmd} exited with code ${code}${stderr ? `: ${stderr.trim()}` : \"\"}`));\n        });\n    });\n}\n","import { appendFile, mkdir } from \"node:fs/promises\";\n\n/** Section header: what is about to happen. Falls back to info (e.g. `console`). */\nexport function deployNotice(logger, message) {\n    if (typeof logger?.notice === \"function\") logger.notice(message);\n    else logger?.info?.(message);\n}\n\nexport async function appendDeployLog(deployLogPath, message) {\n    await mkdir(deployLogPath.replace(/\\/[^/]+$/, \"\"), { recursive: true });\n    const line = `[${new Date().toISOString()}] ${message}\\n`;\n    await appendFile(deployLogPath, line);\n}\n","import { access } from \"node:fs/promises\";\n\nimport { servicePaths } from \"./paths.js\";\nimport { run } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nexport async function cloneRepo(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n\n    if (await pathExists(paths.repo)) {\n        throw new Error(`Repo already exists at ${paths.repo} — use git pull instead`);\n    }\n    if (dryRun) {\n        logger.info(`[dryRun] would git clone ${service.repoUrl} ${paths.repo}`);\n        return;\n    }\n\n    await run(\"git\", [\"clone\", service.repoUrl, paths.repo], { logger });\n    logger.info(`cloned ${service.repoUrl} → ${paths.repo}`);\n}\n\nexport async function pullRepo(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n\n    if (!(await pathExists(paths.repo))) {\n        throw new Error(`Repo missing at ${paths.repo} — run provision first`);\n    }\n    if (dryRun) {\n        logger.info(`[dryRun] would git -C ${paths.repo} pull --ff-only`);\n        return;\n    }\n\n    await run(\"git\", [\"-C\", paths.repo, \"pull\", \"--ff-only\"], { logger });\n    logger.info(`pulled ${paths.repo}`);\n}\n","import { cp, mkdir, readlink, readdir, stat } from \"node:fs/promises\";\nimport { join, dirname as pathDirname, sep } from \"node:path\";\n\nimport { releaseDir, releaseStamp, servicePaths } from \"./paths.js\";\n\nconst SKIP_TOP = new Set([\"node_modules\", \".git\"]);\n\nfunction shouldCopyEntry(srcPath) {\n    const parts = srcPath.split(sep);\n    if (parts.some((p) => p === \"node_modules\" || p === \".git\")) return false;\n    const top = parts.at(-1);\n    if (parts.length === 1 && SKIP_TOP.has(top)) return false;\n    return true;\n}\n\n/** Copy the run dir into releases/<stamp>/ (excluding node_modules and .git). */\nexport async function createRelease(service, options = {}) {\n    const { stamp = releaseStamp(), dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const dest = releaseDir(paths.releases, stamp);\n\n    if (dryRun) {\n        logger.info(`[dryRun] would copy ${paths.repoRun} → ${dest}`);\n        return { stamp, path: dest };\n    }\n\n    await mkdir(paths.releases, { recursive: true });\n    await cp(paths.repoRun, dest, {\n        recursive: true,\n        filter: (src) => shouldCopyEntry(src),\n    });\n\n    logger.info(`release ${stamp} created at ${dest}`);\n    return { stamp, path: dest };\n}\n\n/** Resolve current release path if symlink exists. */\nexport async function readCurrentRelease(paths) {\n    try {\n        const target = await readlink(paths.current);\n        return target.startsWith(\"/\") ? target : join(pathDirname(paths.current), target);\n    } catch {\n        return null;\n    }\n}\n\nexport async function listReleases(paths) {\n    let names;\n    try {\n        names = await readdir(paths.releases);\n    } catch {\n        return [];\n    }\n\n    const entries = [];\n    for (const name of names) {\n        const full = releaseDir(paths.releases, name);\n        const s = await stat(full);\n        if (s.isDirectory()) entries.push({ name, path: full, mtime: s.mtime });\n    }\n\n    entries.sort((a, b) => b.name.localeCompare(a.name));\n    return entries;\n}\n","import { symlink, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/** Point current → release and link shared/.env inside the release. */\nexport async function activateRelease(releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would activate ${releasePath} → ${paths.current}`);\n        return;\n    }\n\n    try {\n        await unlink(paths.current);\n    } catch {\n        // first deploy\n    }\n    await symlink(releasePath, paths.current);\n\n    const envLink = join(releasePath, \".env\");\n    try {\n        await unlink(envLink);\n    } catch {\n        // ok\n    }\n    await symlink(paths.sharedEnv, envLink);\n\n    logger.info(`active release: ${releasePath}`);\n}\n","import { createHash } from \"node:crypto\";\nimport { access, cp, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { readCurrentRelease } from \"./release.js\";\nimport { npmInstallEnv, run } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nasync function lockfileHash(releasePath) {\n    const lockPath = join(releasePath, \"package-lock.json\");\n    try {\n        const buf = await readFile(lockPath);\n        return createHash(\"sha256\").update(buf).digest(\"hex\");\n    } catch {\n        return null; // no lockfile → can't fingerprint; always (re)install\n    }\n}\n\nasync function readHashFile(path) {\n    try {\n        return (await readFile(path, \"utf8\")).trim();\n    } catch {\n        return null;\n    }\n}\n\nasync function npmInstall(releasePath, hasLock, logger) {\n    await rm(join(releasePath, \"node_modules\"), { recursive: true, force: true });\n    const cmd = hasLock ? [\"ci\", \"--include=dev\"] : [\"install\", \"--include=dev\", \"--no-audit\", \"--no-fund\"];\n    logger.info(`running npm ${cmd.join(\" \")} in ${releasePath}`);\n    await run(\"npm\", cmd, { cwd: releasePath, logger, env: npmInstallEnv() });\n}\n\n/**\n * Install deps in the release. If the lockfile is unchanged from the active\n * release and its node_modules exists, copy it (fast path); otherwise npm ci.\n */\nexport async function installDeps(service, releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would install deps in ${releasePath}`);\n        return { hash: null, copied: false };\n    }\n\n    const hash = await lockfileHash(releasePath);\n    const hasLock = hash !== null;\n    const hashMarker = join(releasePath, \".deploy-package-lock.sha256\");\n\n    const currentPath = await readCurrentRelease(paths);\n    let copied = false;\n\n    if (hasLock && currentPath && (await pathExists(join(currentPath, \"node_modules\")))) {\n        const currentHash = await readHashFile(join(currentPath, \".deploy-package-lock.sha256\"));\n        if (currentHash === hash) {\n            logger.info(\"lockfile unchanged — copying node_modules from current release\");\n            await cp(join(currentPath, \"node_modules\"), join(releasePath, \"node_modules\"), {\n                recursive: true,\n                force: true,\n            });\n            copied = true;\n        }\n    }\n\n    if (!copied) {\n        await npmInstall(releasePath, hasLock, logger);\n    }\n\n    if (hasLock) {\n        await writeFile(hashMarker, `${hash}\\n`, \"utf8\");\n        await mkdir(paths.shared, { recursive: true });\n        await writeFile(paths.lockHashFile, `${hash}\\n`, \"utf8\");\n    }\n\n    return { hash, copied };\n}\n","import { symlink, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { npmInstallEnv, runShell } from \"./run.js\";\n\n/**\n * Symlink shared/.env into the release and run the service's testCommand (a shell\n * one-liner, e.g. \"npm run test:ci\"). No-op when the service defines no command.\n */\nexport async function runReleaseTests(service, releasePath, paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (!service.testCommand) {\n        logger.info(\"no testCommand configured — skipping tests\");\n        return;\n    }\n\n    if (dryRun) {\n        logger.info(`[dryRun] would run \"${service.testCommand}\" in ${releasePath}`);\n        return;\n    }\n\n    const envLink = join(releasePath, \".env\");\n    try {\n        await unlink(envLink);\n    } catch {\n        // no existing link\n    }\n    await symlink(paths.sharedEnv, envLink);\n\n    logger.info(`running \"${service.testCommand}\" in ${releasePath}`);\n    await runShell(service.testCommand, { cwd: releasePath, logger, env: npmInstallEnv() });\n}\n","import { rm, readlink } from \"node:fs/promises\";\n\nimport { listReleases } from \"./release.js\";\n\n/**\n * Remove old releases, keeping the newest N (always keeps the active one).\n *\n * @param {object} service\n * @param {object} paths\n * @param {{ dryRun?: boolean, logger?: object, protect?: string[] }} [options]\n *   `protect` — release stamp names that must not be deleted (e.g. still-running\n *   previous release during a rolling deploy).\n */\nexport async function pruneReleases(service, paths, options = {}) {\n    const { dryRun = false, logger = console, protect = [] } = options;\n    const keep = service.keepReleases ?? 3;\n    const releases = await listReleases(paths);\n\n    let activeName = null;\n    try {\n        const target = await readlink(paths.current);\n        activeName = target.split(\"/\").pop();\n    } catch {\n        // no current\n    }\n\n    const keepSet = new Set();\n    for (const rel of releases) {\n        if (keepSet.size < keep) keepSet.add(rel.name);\n    }\n    if (activeName) keepSet.add(activeName);\n    for (const name of protect) {\n        if (name) keepSet.add(name);\n    }\n\n    const toRemove = releases.filter((rel) => !keepSet.has(rel.name));\n    for (const rel of toRemove) {\n        if (dryRun) {\n            logger.info(`[dryRun] would rm -rf ${rel.path}`);\n        } else {\n            await rm(rel.path, { recursive: true, force: true });\n            logger.info(`pruned ${rel.path}`);\n        }\n    }\n\n    return { removed: toRemove.map((r) => r.name) };\n}\n","import { runShell, runCapture } from \"./run.js\";\n\nfunction sleep(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** True if `pid` still exists (same host). */\nexport function isPidAlive(pid) {\n    const n = Number(pid);\n    if (!Number.isFinite(n) || n <= 0) return false;\n    try {\n        process.kill(n, 0);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/**\n * Parse `pm2 jlist` stdout. When the daemon was not running, pm2 prints\n * \"[PM2] Spawning PM2 daemon…\" on stdout before the JSON array.\n *\n * @param {string} stdout\n * @returns {unknown[]}\n */\nexport function parsePm2Jlist(stdout) {\n    const raw = String(stdout ?? \"\");\n    // Drop \"[PM2] Spawning…\" banners (stdout when the daemon was not running).\n    const text = raw\n        .split(\"\\n\")\n        .filter((line) => !line.startsWith(\"[PM2]\"))\n        .join(\"\\n\")\n        .trim();\n    if (!text) return [];\n    try {\n        const parsed = JSON.parse(text);\n        return Array.isArray(parsed) ? parsed : [];\n    } catch (err) {\n        throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);\n    }\n}\n\n/**\n * Parse `pm2 jlist` and return the process entry for `appName`, or null.\n *\n * @param {string} appName\n * @param {{ logger?: { info?: Function, warn?: Function } }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function getPm2Process(appName, options = {}) {\n    const { logger } = options;\n    // Warm the daemon so spawn banners do not race the next jlist (best-effort).\n    await runCapture(\"bash\", [\"-lc\", \"pm2 ping >/dev/null 2>&1 || true\"], { logger }).catch(() => {});\n    const { stdout } = await runCapture(\"bash\", [\"-lc\", \"pm2 jlist\"], { logger });\n    let list;\n    try {\n        list = parsePm2Jlist(stdout);\n    } catch (err) {\n        throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);\n    }\n    return list.find((p) => p?.name === appName) ?? null;\n}\n\n/**\n * Poll pm2 until `predicate(proc)` is true (proc may be null if missing), or timeout.\n *\n * @param {string} appName\n * @param {(proc: object|null) => boolean} predicate\n * @param {{ timeoutMs?: number, pollMs?: number, dryRun?: boolean, logger?: object, label?: string }} [options]\n */\nexport async function waitPm2(appName, predicate, options = {}) {\n    const {\n        timeoutMs = 65_000,\n        pollMs = 500,\n        dryRun = false,\n        logger = console,\n        label = \"condition\",\n    } = options;\n\n    if (dryRun) {\n        logger.info?.(`[dryRun] would wait pm2 ${appName} for ${label}`);\n        return null;\n    }\n\n    const deadline = Date.now() + timeoutMs;\n    let lastStatus = \"(unknown)\";\n    while (Date.now() < deadline) {\n        const proc = await getPm2Process(appName, { logger });\n        lastStatus = proc?.pm2_env?.status ?? \"(missing)\";\n        if (predicate(proc)) return proc;\n        await sleep(pollMs);\n    }\n    throw new Error(\n        `pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`\n    );\n}\n\n/**\n * True when pm2 reports the app online on a *new* pid (old process fully gone).\n * Avoids treating a not-yet-dead pre-reload process as a successful restart.\n */\nexport function isFreshOnline(proc, oldPid) {\n    if (proc?.pm2_env?.status !== \"online\") return false;\n    const pid = Number(proc.pid);\n    if (!Number.isFinite(pid) || pid <= 0) return false;\n    if (oldPid != null) {\n        if (pid === oldPid) return false;\n        if (isPidAlive(oldPid)) return false;\n    }\n    return true;\n}\n\n/**\n * Remove app from pm2 (SIGINT + kill_timeout drain) and wait until gone.\n * No-op if the app is not present.\n */\nasync function deletePm2App(appName, options = {}) {\n    const { dryRun = false, logger = console, waitTimeoutMs = 65_000, oldPid = null } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 delete ${appName}`);\n        return;\n    }\n\n    const before = await getPm2Process(appName, { logger });\n    if (!before) {\n        logger.info(`pm2 ${appName}: not present (skip delete)`);\n        return;\n    }\n\n    await runShell(`pm2 delete \"${appName}\"`, { logger });\n    await waitPm2(\n        appName,\n        (proc) => {\n            if (proc) return false;\n            if (oldPid != null && isPidAlive(oldPid)) return false;\n            return true;\n        },\n        { timeoutMs: waitTimeoutMs, logger, label: \"deleted (process gone)\" }\n    );\n    logger.info(`pm2 ${appName} deleted`);\n}\n\n/** Fresh `pm2 start <ecosystem> --update-env` with production ENV on the CLI. */\nasync function startFromEcosystem(paths, options = {}) {\n    const { dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 start ${paths.ecosystem} --update-env`);\n        return;\n    }\n\n    // Prefix ENV on the pm2 CLI: --update-env copies the invoking shell env.\n    await runShell(\n        `ENV=production NODE_ENV=production pm2 start \"${paths.ecosystem}\" --update-env`,\n        { logger }\n    );\n    logger.info(\"pm2 started from ecosystem\");\n}\n\n/**\n * Rolling restart: `pm2 delete` then `pm2 start <ecosystem> --update-env`.\n *\n * Prefer delete+start over `startOrReload --update-env`: reload can leave a first\n * spawn with a stale/wrong ENV (e.g. S3 profile=local) and does not refresh\n * immutable fields like `script` / `node_args`. Delete honors kill_timeout so the\n * old process can drain, then start applies the full ecosystem.\n */\nexport async function reloadPm2(paths, options = {}) {\n    const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(\n            `[dryRun] would pm2 delete${appName ? ` ${appName}` : \"\"} + start ${paths.ecosystem} --update-env`\n        );\n        return;\n    }\n\n    let oldPid = null;\n    if (appName) {\n        const before = await getPm2Process(appName, { logger });\n        const n = Number(before?.pid);\n        if (Number.isFinite(n) && n > 0 && before?.pm2_env?.status === \"online\") {\n            oldPid = n;\n            logger.info(`pm2 ${appName}: recreate (old pid=${oldPid})`);\n        }\n        await deletePm2App(appName, { dryRun, logger, waitTimeoutMs, oldPid });\n    } else {\n        logger.warn?.(\n            \"reloadPm2: appName missing; starting ecosystem without delete \" +\n                \"(pass appName so script/env always recreate cleanly)\"\n        );\n    }\n\n    await startFromEcosystem(paths, { dryRun, logger });\n\n    if (appName) {\n        const proc = await waitPm2(\n            appName,\n            (p) => isFreshOnline(p, oldPid),\n            {\n                timeoutMs: waitTimeoutMs,\n                logger,\n                label: oldPid\n                    ? `online on new pid (old ${oldPid} gone)`\n                    : \"online after recreate\",\n            }\n        );\n        logger.info(`pm2 ${appName} online pid=${proc?.pid ?? \"?\"}`);\n    }\n}\n\n/** `pm2 stop <app>` and wait until status is stopped (or process missing). */\nexport async function stopPm2(appName, options = {}) {\n    const { dryRun = false, logger = console, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would pm2 stop ${appName}`);\n        return;\n    }\n\n    const before = await getPm2Process(appName, { logger });\n    if (!before) {\n        logger.info(`pm2 ${appName}: not present (already stopped)`);\n        return;\n    }\n    if (before.pm2_env?.status === \"stopped\") {\n        logger.info(`pm2 ${appName}: already stopped`);\n        return;\n    }\n\n    const oldPid = Number(before.pid);\n    await runShell(`pm2 stop \"${appName}\"`, { logger });\n    await waitPm2(\n        appName,\n        (proc) => {\n            if (proc && proc.pm2_env?.status !== \"stopped\") return false;\n            if (Number.isFinite(oldPid) && oldPid > 0 && isPidAlive(oldPid)) return false;\n            return true;\n        },\n        { timeoutMs: waitTimeoutMs, logger, label: \"stopped\" }\n    );\n    logger.info(`pm2 ${appName} stopped`);\n}\n\n/**\n * `pm2 start <ecosystem> --update-env` after deleting any existing registration\n * so immutable fields (script, node_args) and env always come from the ecosystem.\n */\nexport async function startPm2(paths, options = {}) {\n    const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65_000 } = options;\n\n    if (dryRun) {\n        logger.info(\n            `[dryRun] would pm2 delete${appName ? ` ${appName}` : \"\"} + start ${paths.ecosystem} --update-env`\n        );\n        return;\n    }\n\n    if (appName) {\n        // stopFirst leaves a stopped registration; delete so start is a full recreate.\n        await deletePm2App(appName, { dryRun, logger, waitTimeoutMs });\n    }\n\n    await startFromEcosystem(paths, { dryRun, logger });\n\n    if (appName) {\n        const proc = await waitPm2(\n            appName,\n            (p) => isFreshOnline(p, null),\n            { timeoutMs: waitTimeoutMs, logger, label: \"online after start\" }\n        );\n        logger.info(`pm2 ${appName} online pid=${proc?.pid ?? \"?\"}`);\n    }\n}\n","import { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { runShell } from \"./run.js\";\n\nasync function hasTlsCert(certPath) {\n    try {\n        await runShell(`sudo test -f '${certPath}'`, {});\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction proxyBlock(port) {\n    return `  location / {\n    proxy_pass http://127.0.0.1:${port};\n    proxy_http_version 1.1;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto $scheme;\n    proxy_read_timeout 120s;\n  }`;\n}\n\nfunction buildNginxConfig(service) {\n    const { nginx, pm2 } = service;\n    const certDir = `/etc/letsencrypt/live/${nginx.fqdn}`;\n\n    return `# ${nginx.siteName} — managed by cli-toolkit deploy (proxy mode)\n# ${nginx.fqdn} → 127.0.0.1:${pm2.port}\n\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name ${nginx.fqdn};\n  location / { return 301 https://$host$request_uri; }\n}\n\nserver {\n  listen 443 ssl;\n  listen [::]:443 ssl;\n  server_name ${nginx.fqdn};\n\n  ssl_certificate ${certDir}/fullchain.pem;\n  ssl_certificate_key ${certDir}/privkey.pem;\n  include /etc/letsencrypt/options-ssl-nginx.conf;\n  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;\n\n  client_max_body_size 25m;\n\n${proxyBlock(pm2.port)}\n}\n`;\n}\n\nfunction buildNginxConfigHttpOnly(service) {\n    const { nginx, pm2 } = service;\n    return `# ${nginx.siteName} — managed by cli-toolkit deploy (HTTP proxy, no TLS cert yet)\n\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name ${nginx.fqdn};\n\n  client_max_body_size 25m;\n\n${proxyBlock(pm2.port)}\n}\n`;\n}\n\n/** Replace the stub nginx site with a reverse-proxy to the app. */\nexport async function enableNginxUpstream(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const { nginx } = service;\n    if (!nginx) {\n        logger.info(\"no nginx config on service — skipping nginx step\");\n        return { skipped: true };\n    }\n\n    const siteAvailable = `/etc/nginx/sites-available/${nginx.siteName}`;\n    const siteEnabled = `/etc/nginx/sites-enabled/${nginx.siteName}`;\n    const cert = `/etc/letsencrypt/live/${nginx.fqdn}/fullchain.pem`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${siteAvailable} (proxy → 127.0.0.1:${service.pm2.port}) and reload nginx`);\n        return { hasCert: null };\n    }\n\n    const hasCert = await hasTlsCert(cert);\n    const config = hasCert ? buildNginxConfig(service) : buildNginxConfigHttpOnly(service);\n\n    const tmp = join(tmpdir(), `${service.name}-nginx.conf`);\n    await writeFile(tmp, config);\n    await runShell(\n        `sudo cp '${tmp}' '${siteAvailable}' && sudo ln -sf '${siteAvailable}' '${siteEnabled}' && sudo nginx -t && sudo systemctl reload nginx`,\n        { logger },\n    );\n\n    logger.info(`nginx upstream enabled for ${nginx.fqdn} → 127.0.0.1:${service.pm2.port} (tls=${hasCert})`);\n    return { hasCert };\n}\n","import { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport { servicePaths } from \"./paths.js\";\n\n/**\n * Drop .env lines matching any of the service's envScrubPatterns (regex source\n * strings). Useful to strip empty keys that would crash strict param validation.\n */\nexport function scrubEnvContent(content, patterns = []) {\n    const regexes = patterns.map((p) => (p instanceof RegExp ? p : new RegExp(p)));\n    if (regexes.length === 0) return content;\n    return content\n        .split(\"\\n\")\n        .filter((line) => !regexes.some((re) => re.test(line.trim())))\n        .join(\"\\n\");\n}\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** Copy <repoRun>/.env → shared/.env (with optional legacy fallback + scrubbing). */\nexport async function syncEnv(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const patterns = service.envScrubPatterns ?? [];\n\n    if (dryRun) {\n        logger.info(`[dryRun] would sync ${paths.repoEnv} → ${paths.sharedEnv}`);\n        return { source: paths.repoEnv, dest: paths.sharedEnv };\n    }\n\n    let source = paths.repoEnv;\n    if (!(await pathExists(source)) && service.legacyRepoEnv && (await pathExists(service.legacyRepoEnv))) {\n        logger.info(`using legacy env: ${service.legacyRepoEnv}`);\n        source = service.legacyRepoEnv;\n    }\n\n    await mkdir(paths.shared, { recursive: true });\n\n    if (!(await pathExists(source))) {\n        if (service.requireEnv) {\n            throw new Error(\n                `No .env found at ${paths.repoEnv}` +\n                    (service.legacyRepoEnv ? ` or ${service.legacyRepoEnv}` : \"\") +\n                    \" — place .env on the host or run the remote deploy from a laptop with a local .env (auto-scp)\",\n            );\n        }\n        // Optional env: ensure shared/.env exists so the per-release symlink is valid.\n        if (!(await pathExists(paths.sharedEnv))) {\n            await writeFile(paths.sharedEnv, \"\", { mode: 0o600 });\n        }\n        logger.warn(`no .env found (source ${source}) — using empty ${paths.sharedEnv}`);\n        return { source: null, dest: paths.sharedEnv };\n    }\n\n    const raw = await readFile(source, \"utf8\");\n    await writeFile(paths.sharedEnv, scrubEnvContent(raw, patterns), { mode: 0o600 });\n    logger.info(`synced ${source} → ${paths.sharedEnv}`);\n    return { source, dest: paths.sharedEnv };\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport { readCurrentRelease } from \"./release.js\";\nimport { servicePaths } from \"./paths.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Bump semver patch (0.1.0 → 0.1.1). */\nexport function bumpPatchVersion(version) {\n    const parts = String(version).trim().split(\".\");\n    const major = Number.parseInt(parts[0], 10) || 0;\n    const minor = Number.parseInt(parts[1], 10) || 0;\n    const patch = Number.parseInt(parts[2], 10) || 0;\n    return `${major}.${minor}.${patch + 1}`;\n}\n\nasync function readJson(path) {\n    try {\n        return JSON.parse(await readFile(path, \"utf8\"));\n    } catch {\n        return null;\n    }\n}\n\nasync function gitShortCommit(repoPath) {\n    try {\n        const { stdout } = await execFileAsync(\"git\", [\"-C\", repoPath, \"rev-parse\", \"--short\", \"HEAD\"], {\n            encoding: \"utf8\",\n        });\n        return stdout.trim() || null;\n    } catch {\n        return null;\n    }\n}\n\n/**\n * Next semver: bump patch from the **currently active** release's build-info,\n * else seed from package.json. Each release carries its own build-info.json so a\n * rollback restores that release's label.\n */\nexport async function resolveNextVersion(service, paths, pkgPath) {\n    const pkg = (await readJson(pkgPath)) ?? {};\n    const baseVersion = pkg.version || \"0.1.0\";\n\n    const currentPath = await readCurrentRelease(paths);\n    if (currentPath) {\n        const active = await readJson(join(currentPath, service.buildInfoPath));\n        if (active?.version) return bumpPatchVersion(active.version);\n    }\n    return baseVersion;\n}\n\n/** Read build-info from a release directory (for rollback logs / status). */\nexport async function readReleaseBuildInfo(service, releasePath) {\n    return readJson(join(releasePath, service.buildInfoPath));\n}\n\n/** Write build-info.json into the new release directory. */\nexport async function writeReleaseBuildInfo(service, releasePath, { stamp, dryRun = false, logger = console }) {\n    const paths = servicePaths(service);\n    const pkgPath = join(paths.repoRun, \"package.json\");\n\n    const version = await resolveNextVersion(service, paths, pkgPath);\n    const gitCommit = await gitShortCommit(paths.repo);\n\n    const buildInfo = {\n        version,\n        release: stamp,\n        deployedAt: new Date().toISOString(),\n        gitCommit,\n        service: service.name,\n    };\n\n    const dest = join(releasePath, service.buildInfoPath);\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${dest} (${JSON.stringify(buildInfo)})`);\n        return buildInfo;\n    }\n\n    await mkdir(dirname(dest), { recursive: true });\n    await writeFile(dest, `${JSON.stringify(buildInfo, null, 2)}\\n`, { mode: 0o644 });\n\n    const gitSuffix = gitCommit ? ` git=${gitCommit}` : \"\";\n    logger.info(`build info: v${version} release=${stamp}${gitSuffix}`);\n    return buildInfo;\n}\n","import { access, appendFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { servicePaths } from \"./paths.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** Fail fast with a useful message when not on a provisioned host. */\nasync function requireDeployRoot(parentDir, serviceRoot) {\n    if (await pathExists(parentDir)) return;\n    throw new Error(\n        `Cannot create ${serviceRoot}: parent directory ${parentDir} does not exist.\\n` +\n            `This is meant to run on the target host (where ${parentDir} exists). ` +\n            `For a local dry run use --appsRoot=/tmp/<service>.`,\n    );\n}\n\nfunction resolveKillTimeoutMs(pm2) {\n    const explicit = Number(pm2?.killTimeout);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    const stopSec = Number(pm2?.stopAllowance);\n    if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1000) + 5000;\n    return 65_000;\n}\n\n/** How often pm2 re-sends SIGINT / logs \"failed to kill - retrying in …\" (ms). */\nconst DEFAULT_KILL_RETRY_TIME_MS = 10_000;\n\nfunction resolveKillRetryTimeMs(pm2) {\n    const explicit = Number(pm2?.killRetryTime);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    return DEFAULT_KILL_RETRY_TIME_MS;\n}\n\n/** Append `--stopAllowance=<sec>` to pm2 args when manifest sets pm2.stopAllowance. */\nfunction resolvePm2Args(pm2) {\n    const base = String(pm2?.args ?? \"\").trim();\n    const stopSec = Number(pm2?.stopAllowance);\n    if (!Number.isFinite(stopSec) || stopSec <= 0) return base;\n    if (/(?:^|\\s)--stopAllowance=/.test(base)) return base;\n    return `${base}${base ? \" \" : \"\"}--stopAllowance=${Math.floor(stopSec)}`.trim();\n}\n\n/** CJS snippet required before the app — always force production on deployed hosts. */\nfunction buildEnsureEnvScript() {\n    return `/**\n * Written by cli-toolkit deploy (init-structure). Do not hand-edit.\n * Preloaded via pm2 node_args --require. Always set (do not only fill when unset):\n * \\`pm2 start … --update-env\\` can inject a non-production ENV from the\n * deploy shell / prior dump, and a conditional assign would leave it in place.\n */\nprocess.env.ENV = \"production\";\nprocess.env.NODE_ENV = \"production\";\n`;\n}\n\nfunction buildEcosystemConfig(service, paths) {\n    const { pm2 } = service;\n    const outLog = join(paths.logs, `${pm2.appName}.out.log`);\n    const errLog = join(paths.logs, `${pm2.appName}.err.log`);\n    const killTimeoutMs = resolveKillTimeoutMs(pm2);\n    const killRetryTimeMs = resolveKillRetryTimeMs(pm2);\n    const args = resolvePm2Args(pm2);\n    const ensureEnv = paths.ensureEnv;\n\n    return `/**\n * pm2 ecosystem for ${service.name} — written by cli-toolkit deploy from the\n * service manifest (init/deploy). Do not hand-edit; change pm2.* in the\n * manifest and redeploy. cwd → \\`current\\` symlink.\n */\nmodule.exports = {\n    apps: [\n        {\n            name: \"${pm2.appName}\",\n            script: \"${pm2.script}\",\n            cwd: \"${paths.current}\",\n            args: ${JSON.stringify(args)},\n            // Absolute --require so ENV is set before Args constructs (see shared/ensure-env.cjs).\n            node_args: ${JSON.stringify(`--require ${ensureEnv}`)},\n            instances: 1,\n            exec_mode: \"fork\",\n            autorestart: true,\n            min_uptime: \"10s\",\n            max_restarts: 10,\n            restart_delay: 2000,\n            max_memory_restart: \"1500M\",\n            // Grace window after SIGINT/SIGTERM before SIGKILL (ms). Align with --stopAllowance.\n            kill_timeout: ${killTimeoutMs},\n            // How often pm2 re-checks / logs \"failed to kill - retrying in …\"\n            // while waiting for graceful exit (pm2 default 100ms → noisy logs).\n            kill_retry_time: ${killRetryTimeMs},\n            out_file: \"${outLog}\",\n            error_file: \"${errLog}\",\n            merge_logs: true,\n            time: true,\n            env: {\n                // cli-toolkit Args: ENV selects env-suffixed defaults (DB_NAME_PRODUCTION, BUCKET_PRODUCTION, …)\n                ENV: \"production\",\n                NODE_ENV: \"production\",\n            },\n        },\n    ],\n};\n`;\n}\n\n/** Create <appsRoot>/{releases,shared,logs} and sync shared/ecosystem.config.cjs from the manifest. */\nexport async function initServiceStructure(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const dirs = [paths.releases, paths.shared, paths.logs];\n    const created = [];\n    const skipped = [];\n\n    if (!dryRun) {\n        await requireDeployRoot(dirname(paths.root), paths.root);\n    }\n\n    for (const dir of dirs) {\n        if (await pathExists(dir)) {\n            skipped.push(dir);\n            continue;\n        }\n        if (!dryRun) await mkdir(dir, { recursive: true });\n        created.push(dir);\n    }\n\n    const ecosystemExisted = await pathExists(paths.ecosystem);\n    const ensureEnvExisted = await pathExists(paths.ensureEnv);\n    if (!dryRun) {\n        await writeFile(paths.ensureEnv, buildEnsureEnvScript(), { mode: 0o644 });\n        await writeFile(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 0o644 });\n    }\n    if (ensureEnvExisted) {\n        logger.info(`synced ${paths.ensureEnv}`);\n    } else {\n        created.push(paths.ensureEnv);\n        logger.info(`seeded ${paths.ensureEnv}`);\n    }\n    if (ecosystemExisted) {\n        logger.info(`synced ${paths.ecosystem} from manifest`);\n    } else {\n        created.push(paths.ecosystem);\n        logger.info(`seeded ${paths.ecosystem}`);\n    }\n\n    const line = `[${new Date().toISOString()}] init-structure service=${service.name} dryRun=${dryRun} created=${created.length} skipped=${skipped.length} ecosystem=synced\\n`;\n    if (!dryRun) {\n        await mkdir(paths.logs, { recursive: true });\n        await appendFile(paths.deployLog, line);\n    }\n\n    logger.info(`service=${service.name} appsRoot=${paths.root}`);\n    logger.info(`created: ${created.length ? created.join(\", \") : \"(none)\"}`);\n    logger.info(`already present: ${skipped.length ? skipped.join(\", \") : \"(none)\"}`);\n\n    return { paths, created, skipped, ecosystemCreated: !ecosystemExisted, ecosystemSynced: true };\n}\n","import { execSync } from \"node:child_process\";\nimport { access, chmod, copyFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\n\nimport { runShell } from \"./run.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction expandHome(path) {\n    return path.startsWith(\"~/\") ? join(homedir(), path.slice(2)) : path;\n}\n\nasync function ensurePm2Startup(options = {}) {\n    const { user = \"ubuntu\", dryRun = false, logger = console } = options;\n\n    if (dryRun) {\n        logger.info(\"[dryRun] would configure pm2 startup systemd\");\n        return;\n    }\n\n    try {\n        execSync(\"pm2 ping\", { stdio: \"ignore\" });\n    } catch {\n        // pm2 daemon may not be up yet\n    }\n\n    try {\n        const out = execSync(`pm2 startup systemd -u ${user} --hp /home/${user}`, { encoding: \"utf8\" });\n        const sudoLine = out.split(\"\\n\").find((l) => l.trim().startsWith(\"sudo\"));\n        if (sudoLine) {\n            execSync(sudoLine.trim(), { stdio: \"inherit\" });\n            logger.info(\"pm2 startup systemd configured\");\n        }\n    } catch (err) {\n        logger.warn(`pm2 startup skipped or already configured: ${err.message}`);\n    }\n}\n\nasync function installDeployKey(deployKeyPath, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const keyPath = expandHome(deployKeyPath);\n\n    if (!(await pathExists(keyPath))) {\n        logger.warn(`deploy key not found at ${keyPath} — skipping git ssh setup`);\n        return;\n    }\n\n    const keyBase = basename(keyPath);\n    const sshDir = join(homedir(), \".ssh\");\n    const destKey = join(sshDir, keyBase);\n    const configPath = join(sshDir, \"config\");\n    const block = `\nHost github.com\n  HostName github.com\n  User git\n  IdentityFile ${destKey}\n  IdentitiesOnly yes\n`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would install deploy key ${keyPath} → ${destKey}`);\n        return;\n    }\n\n    await mkdir(sshDir, { recursive: true, mode: 0o700 });\n    await copyFile(keyPath, destKey);\n    await chmod(destKey, 0o600);\n\n    let config = \"\";\n    if (await pathExists(configPath)) config = await readFile(configPath, \"utf8\");\n    if (!config.includes(\"Host github.com\")) {\n        await writeFile(configPath, `${config.trimEnd()}\\n${block}\\n`, { mode: 0o600 });\n        logger.info(\"updated ~/.ssh/config for github.com\");\n    }\n    logger.info(`deploy key installed at ${destKey}`);\n}\n\nasync function installLogrotate(service, options = {}) {\n    const { dryRun = false, logger = console } = options;\n    const conf = `/etc/logrotate.d/${service.name}`;\n    const body = `${service.appsRoot}/logs/*.log {\n  daily\n  rotate 14\n  compress\n  delaycompress\n  missingok\n  notifempty\n  copytruncate\n}\n`;\n\n    if (dryRun) {\n        logger.info(`[dryRun] would write ${conf}`);\n        return;\n    }\n\n    const tmp = join(\"/tmp\", `${service.name}-logrotate.conf`);\n    await writeFile(tmp, body);\n    await runShell(`sudo cp '${tmp}' '${conf}'`, { logger });\n    logger.info(`logrotate config written: ${conf}`);\n}\n\nconst OPERATOR_SHELL_BEGIN = \"# >>> mlsfarm-operator >>>\";\nconst OPERATOR_SHELL_END = \"# <<< mlsfarm-operator <<<\";\n\n/**\n * Idempotent ~/.bashrc block: ENV=production + cd into /apps/<service>/current\n * on interactive login. Safe to re-run; replaces any prior managed block.\n */\nexport async function installOperatorShell(service, options = {}) {\n    const { user = \"ubuntu\", dryRun = false, logger = console } = options;\n    const appsRoot = service.appsRoot;\n    if (!appsRoot) {\n        logger.warn(\"installOperatorShell: service.appsRoot missing — skipped\");\n        return;\n    }\n\n    const home = user === \"ubuntu\" || user === process.env.USER\n        ? join(homedir(), \".bashrc\")\n        : `/home/${user}/.bashrc`;\n    const currentDir = join(appsRoot, \"current\");\n    const block = [\n        OPERATOR_SHELL_BEGIN,\n        \"# Managed by cli-toolkit deploy bootstrap — do not edit by hand.\",\n        'export ENV=production',\n        `if [ -d \"${currentDir}\" ]; then`,\n        `  cd \"${currentDir}\" || true`,\n        \"fi\",\n        OPERATOR_SHELL_END,\n        \"\",\n    ].join(\"\\n\");\n\n    if (dryRun) {\n        logger.info(`[dryRun] would update ${home} (ENV=production, cd ${currentDir})`);\n        return;\n    }\n\n    let existing = \"\";\n    if (await pathExists(home)) {\n        existing = await readFile(home, \"utf8\");\n    }\n\n    const begin = existing.indexOf(OPERATOR_SHELL_BEGIN);\n    const end = existing.indexOf(OPERATOR_SHELL_END);\n    let next;\n    if (begin !== -1 && end !== -1 && end > begin) {\n        const afterEnd = end + OPERATOR_SHELL_END.length;\n        const rest = existing.slice(afterEnd).replace(/^\\n/, \"\");\n        next = `${existing.slice(0, begin).replace(/\\s*$/, \"\\n\")}${block}${rest}`;\n    } else {\n        next = `${existing.replace(/\\s*$/, \"\\n\")}\\n${block}`;\n    }\n\n    await writeFile(home, next, { mode: 0o644 });\n    logger.info(`operator shell: ${home} → ENV=production, cd ${currentDir}`);\n}\n\n/** One-time host prep: pm2 systemd, optional git deploy key, logrotate, operator shell. */\nexport async function bootstrapHost(service, options = {}) {\n    const { deployKey = service.deployKey, user = \"ubuntu\", dryRun = false, logger = console } = options;\n\n    await ensurePm2Startup({ user, dryRun, logger });\n    if (deployKey) await installDeployKey(deployKey, { dryRun, logger });\n    await installLogrotate(service, { dryRun, logger });\n    await installOperatorShell(service, { user, dryRun, logger });\n    logger.info(\"bootstrap-host complete\");\n}\n","import { readlink } from \"node:fs/promises\";\n\nimport { initServiceStructure } from \"./init-structure.js\";\nimport { appendDeployLog, deployNotice } from \"./log.js\";\nimport { pullRepo } from \"./git.js\";\nimport { createRelease } from \"./release.js\";\nimport { installDeps } from \"./deps.js\";\nimport { runReleaseTests } from \"./test.js\";\nimport { activateRelease } from \"./activate.js\";\nimport { pruneReleases } from \"./prune.js\";\nimport { reloadPm2, stopPm2, startPm2 } from \"./pm2.js\";\nimport { enableNginxUpstream } from \"./nginx.js\";\nimport { syncEnv } from \"./sync-env.js\";\nimport { writeReleaseBuildInfo } from \"./build-info.js\";\nimport { servicePaths } from \"./paths.js\";\n\n/**\n * Resolve pm2 kill_timeout (ms). Prefer manifest `pm2.killTimeout`, else\n * stopAllowance seconds × 1000 + 5s buffer, else 65s.\n */\nfunction resolveKillTimeoutMs(service) {\n    const explicit = Number(service.pm2?.killTimeout);\n    if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);\n    const stopSec = Number(service.pm2?.stopAllowance);\n    if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1000) + 5000;\n    return 65_000;\n}\n\n/**\n * Full deploy: pull → env → release → deps → test → activate → pm2 → prune → nginx.\n *\n * Default (**rolling**): keep the process running while the new release is built and\n * `current` is flipped; then `pm2 delete` + `pm2 start` (SIGINT + kill_timeout drain,\n * then full ecosystem recreate) so script/node_args/env always apply. Previous\n * release is not pruned until after that restart.\n *\n * **`--stopFirst`**: `pm2 stop` + wait → activate/prune → delete + `pm2 start`.\n * Use when a runner is wedged and will not honor graceful stop.\n */\nexport async function deployService(service, options = {}) {\n    const {\n        dryRun = false,\n        skipPull = false,\n        skipTests = false,\n        skipNginx = false,\n        stopFirst = false,\n        logger = console,\n    } = options;\n\n    const paths = servicePaths(service);\n    const appName = service.pm2.appName;\n    const killTimeoutMs = resolveKillTimeoutMs(service);\n    const waitTimeoutMs = killTimeoutMs + 10_000;\n\n    deployNotice(logger, `Prepare ${service.name} directories`);\n    await initServiceStructure(service, { dryRun, logger });\n\n    if (!skipPull) {\n        deployNotice(logger, \"Pull latest repository\");\n        await pullRepo(service, { dryRun, logger });\n    }\n\n    deployNotice(logger, \"Sync environment\");\n    await syncEnv(service, { dryRun, logger });\n\n    deployNotice(logger, \"Create release\");\n    const { stamp, path: releasePath } = await createRelease(service, { dryRun, logger });\n    await writeReleaseBuildInfo(service, releasePath, { stamp, dryRun, logger });\n\n    deployNotice(logger, \"Install dependencies\");\n    await installDeps(service, releasePath, paths, { dryRun, logger });\n\n    if (!skipTests) {\n        deployNotice(logger, \"Run release tests\");\n        await runReleaseTests(service, releasePath, paths, { dryRun, logger });\n    }\n\n    let previousReleaseName = null;\n    try {\n        const prev = await readlink(paths.current);\n        previousReleaseName = prev.split(\"/\").pop() || null;\n    } catch {\n        // first deploy\n    }\n\n    if (stopFirst) {\n        logger.info(`deploy mode=stopFirst app=${appName} killTimeoutMs=${killTimeoutMs}`);\n        deployNotice(logger, `Stop ${appName}`);\n        await stopPm2(appName, { dryRun, logger, waitTimeoutMs });\n        deployNotice(logger, \"Activate release\");\n        await activateRelease(releasePath, paths, { dryRun, logger });\n        deployNotice(logger, \"Prune old releases\");\n        await pruneReleases(service, paths, { dryRun, logger });\n        deployNotice(logger, \"Start pm2\");\n        await startPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n    } else {\n        logger.info(\n            `deploy mode=rolling app=${appName} killTimeoutMs=${killTimeoutMs}` +\n                (previousReleaseName ? ` previous=${previousReleaseName}` : \"\")\n        );\n        deployNotice(logger, \"Activate release\");\n        await activateRelease(releasePath, paths, { dryRun, logger });\n        // Restart into new `current` before pruning the previous tree (still in use by the old process).\n        deployNotice(logger, \"Reload pm2\");\n        await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n        deployNotice(logger, \"Prune old releases\");\n        await pruneReleases(service, paths, { dryRun, logger });\n    }\n\n    if (!skipNginx) {\n        deployNotice(logger, \"Update nginx upstream\");\n        await enableNginxUpstream(service, { dryRun, logger });\n    }\n\n    const summary = `deploy complete stamp=${stamp} mode=${stopFirst ? \"stopFirst\" : \"rolling\"} dryRun=${dryRun}`;\n    deployNotice(logger, `Deploy complete (${stamp})`);\n    logger.info(summary);\n    if (!dryRun) await appendDeployLog(paths.deployLog, summary);\n\n    return { stamp, releasePath, mode: stopFirst ? \"stopFirst\" : \"rolling\" };\n}\n","import { access } from \"node:fs/promises\";\n\nimport { bootstrapHost } from \"./bootstrap-host.js\";\nimport { initServiceStructure } from \"./init-structure.js\";\nimport { cloneRepo, pullRepo } from \"./git.js\";\nimport { deployService } from \"./deploy-service.js\";\nimport { deployNotice } from \"./log.js\";\nimport { syncEnv } from \"./sync-env.js\";\nimport { servicePaths } from \"./paths.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\n/** First-time setup: optional bootstrap, init dirs, clone/pull, sync .env, first deploy. */\nexport async function provisionService(service, options = {}) {\n    const {\n        dryRun = false,\n        deploy = true,\n        skipBootstrap = true,\n        deployKey,\n        logger = console,\n    } = options;\n\n    if (!skipBootstrap) {\n        deployNotice(logger, \"Bootstrap host (pm2, deploy key, operator shell)\");\n        await bootstrapHost(service, { deployKey, dryRun, logger });\n    }\n\n    deployNotice(logger, `Prepare ${service.name} directories`);\n    await initServiceStructure(service, { dryRun, logger });\n    const paths = servicePaths(service);\n\n    if (await pathExists(paths.repo)) {\n        deployNotice(logger, \"Pull existing repository\");\n        logger.info(`repo exists at ${paths.repo} — pulling`);\n        await pullRepo(service, { dryRun, logger });\n    } else {\n        deployNotice(logger, \"Clone repository\");\n        await cloneRepo(service, { dryRun, logger });\n    }\n\n    deployNotice(logger, \"Sync environment\");\n    await syncEnv(service, { dryRun, logger });\n\n    if (deploy) {\n        deployNotice(logger, \"Run first deploy\");\n        await deployService(service, { dryRun, logger, skipPull: true });\n    } else {\n        deployNotice(logger, \"Provision complete (deploy skipped)\");\n        logger.info(\"provision complete (deploy skipped)\");\n    }\n}\n","import { readlink } from \"node:fs/promises\";\n\nimport { activateRelease } from \"./activate.js\";\nimport { readReleaseBuildInfo } from \"./build-info.js\";\nimport { appendDeployLog, deployNotice } from \"./log.js\";\nimport { listReleases } from \"./release.js\";\nimport { reloadPm2 } from \"./pm2.js\";\nimport { servicePaths } from \"./paths.js\";\n\n/** Flip current to a named release or the previous one. */\nexport async function rollbackService(service, options = {}) {\n    const { release: targetName, dryRun = false, logger = console } = options;\n    const paths = servicePaths(service);\n    const releases = await listReleases(paths);\n\n    if (releases.length === 0) throw new Error(\"No releases to roll back to\");\n\n    let activeName = null;\n    try {\n        const target = await readlink(paths.current);\n        activeName = target.split(\"/\").pop();\n    } catch {\n        throw new Error(\"No active release (current symlink missing)\");\n    }\n\n    let rollbackTarget;\n    if (targetName) {\n        rollbackTarget = releases.find((r) => r.name === targetName);\n        if (!rollbackTarget) throw new Error(`Release not found: ${targetName}`);\n    } else {\n        rollbackTarget = releases.find((r) => r.name !== activeName);\n        if (!rollbackTarget) throw new Error(\"No previous release to roll back to\");\n    }\n\n    if (rollbackTarget.name === activeName) throw new Error(`Already on release ${activeName}`);\n\n    deployNotice(logger, `Rollback ${activeName} → ${rollbackTarget.name}`);\n    logger.info(`rollback ${activeName} → ${rollbackTarget.name}`);\n    const buildInfo = await readReleaseBuildInfo(service, rollbackTarget.path);\n    if (buildInfo?.version) {\n        logger.info(`rollback target: v${buildInfo.version} release=${buildInfo.release ?? rollbackTarget.name}`);\n    }\n    deployNotice(logger, \"Activate previous release\");\n    await activateRelease(rollbackTarget.path, paths, { dryRun, logger });\n    const appName = service.pm2?.appName ?? null;\n    const waitTimeoutMs = 65_000;\n    deployNotice(logger, \"Reload pm2\");\n    await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });\n\n    const summary = `rollback ${activeName} → ${rollbackTarget.name} dryRun=${dryRun}`;\n    deployNotice(logger, `Rollback complete (${rollbackTarget.name})`);\n    if (!dryRun) await appendDeployLog(paths.deployLog, summary);\n\n    return { from: activeName, to: rollbackTarget.name, path: rollbackTarget.path };\n}\n","import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { spawn } from \"node:child_process\";\n\nimport { scrubEnvContent } from \"./sync-env.js\";\nimport { servicePaths } from \"./paths.js\";\nimport { deployNotice } from \"./log.js\";\n\n/** Path (relative to the run dir on the server) of the toolkit deploy CLI. */\nexport const REMOTE_CLI_REL = \"node_modules/@nmakarov/cli-toolkit/scripts/deploy/cli.js\";\n\nasync function pathExists(path) {\n    try {\n        await access(path);\n        return true;\n    } catch {\n        return false;\n    }\n}\n\nfunction expandHome(path) {\n    return path.startsWith(\"~/\") ? join(homedir(), path.slice(2)) : path;\n}\n\nfunction resolveLocalEnvPath(envFile) {\n    if (envFile) {\n        const expanded = expandHome(envFile);\n        return expanded.startsWith(\"/\") ? expanded : join(process.cwd(), expanded);\n    }\n    return join(process.cwd(), \".env\");\n}\n\n/** Parse the ssh host out of a git url (git@host:..., ssh://git@host/...). null for https. */\nexport function parseGitHost(repoUrl) {\n    const u = String(repoUrl ?? \"\");\n    let m = u.match(/^[^@]+@([^:]+):/); // git@github.com:org/repo.git\n    if (m) return m[1];\n    m = u.match(/^ssh:\\/\\/[^@]+@([^/:]+)/); // ssh://git@github.com/org/repo.git\n    if (m) return m[1];\n    return null;\n}\n\nexport function shellQuote(value) {\n    return `'${String(value).replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport function sshRun(host, remoteCommand, options = {}) {\n    const { logger } = options;\n    return new Promise((resolve, reject) => {\n        logger?.info?.(`ssh ${host} ${remoteCommand.slice(0, 120)}${remoteCommand.length > 120 ? \"…\" : \"\"}`);\n        const child = spawn(\"ssh\", [host, remoteCommand], { stdio: \"inherit\" });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => (code === 0 ? resolve() : reject(new Error(`ssh ${host} exited with code ${code}`))));\n    });\n}\n\nfunction scp(localPath, remoteSpec) {\n    return new Promise((resolve, reject) => {\n        const child = spawn(\"scp\", [localPath, remoteSpec], { stdio: \"inherit\" });\n        child.on(\"error\", reject);\n        child.on(\"close\", (code) => (code === 0 ? resolve() : reject(new Error(`scp exited with code ${code}`))));\n    });\n}\n\n/** Copy a git deploy key from the laptop to the server (no-op if not present locally). */\nexport async function ensureDeployKeyOnRemote(host, deployKeyPath, options = {}) {\n    const { logger = console } = options;\n    if (!deployKeyPath) return false;\n    const localPath = expandHome(deployKeyPath);\n    if (!(await pathExists(localPath))) return false;\n\n    const keyBase = basename(localPath);\n    deployNotice(logger, `Copy deploy key to ${host}`);\n    logger.info(`copying deploy key ${localPath} → ${host}:~/.ssh/${keyBase}`);\n    await sshRun(host, \"mkdir -p ~/.ssh && chmod 700 ~/.ssh\", { logger });\n    await scp(localPath, `${host}:.ssh/${keyBase}`, { logger });\n    await sshRun(host, `chmod 600 ~/.ssh/${keyBase}`, { logger });\n    return true;\n}\n\n/** known_hosts for the git host + (optional) ~/.ssh/config IdentityFile for the deploy key. */\nexport async function prepareGitHost(host, options = {}) {\n    const { logger = console, gitHost, keyBasename } = options;\n    if (!gitHost) return;\n\n    const configBlock = keyBasename\n        ? `if ! grep -q 'Host ${gitHost}' ~/.ssh/config 2>/dev/null; then\n  printf '%s\\\\n' '' 'Host ${gitHost}' '  HostName ${gitHost}' '  User git' '  IdentityFile ~/.ssh/${keyBasename}' '  IdentitiesOnly yes' >> ~/.ssh/config\n  chmod 600 ~/.ssh/config\n  echo \"configured ~/.ssh/config for ${gitHost}\"\nfi`\n        : `:`;\n\n    const script = `\nset -euo pipefail\nmkdir -p ~/.ssh\nchmod 700 ~/.ssh\nif ! grep -q '^${gitHost}' ~/.ssh/known_hosts 2>/dev/null; then\n  ssh-keyscan -t ed25519,rsa ${gitHost} >> ~/.ssh/known_hosts 2>/dev/null\n  echo \"added ${gitHost} to known_hosts\"\nfi\n${configBlock}\n`.trim();\n\n    await sshRun(host, script, { logger });\n}\n\n/** Install the run-dir workspace deps so the toolkit CLI is available on the server. */\nexport async function ensureRepoDependencies(host, service, options = {}) {\n    const { logger = console } = options;\n    const paths = servicePaths(service);\n    const run = shellQuote(paths.repoRun);\n    await sshRun(\n        host,\n        `cd ${run} && if [ ! -d node_modules/@nmakarov/cli-toolkit ] || [ package-lock.json -nt node_modules/.package-lock.json ]; then npm ci; fi`,\n        { logger },\n    );\n}\n\n/** Copy laptop .env → server run-dir .env (scrubbed). sync-env then copies it to shared/. */\nexport async function ensureEnvOnRemote(host, service, options = {}) {\n    const { logger = console, envFile } = options;\n    const paths = servicePaths(service);\n    const localPath = resolveLocalEnvPath(envFile);\n    if (!(await pathExists(localPath))) return false;\n\n    deployNotice(logger, `Copy environment to ${host}`);\n    logger.info(`copying .env ${localPath} → ${host}:${paths.repoEnv}`);\n    await sshRun(host, `mkdir -p ${shellQuote(dirname(paths.repoEnv))}`, { logger });\n\n    const scrubbed = scrubEnvContent(await readFile(localPath, \"utf8\"), service.envScrubPatterns ?? []);\n    const tmp = join(tmpdir(), `deploy-env-${Date.now()}`);\n    await writeFile(tmp, scrubbed, { mode: 0o600 });\n    await scp(tmp, `${host}:${paths.repoEnv}`, { logger });\n    await sshRun(host, `chmod 600 ${shellQuote(paths.repoEnv)}`, { logger });\n    return true;\n}\n\n/** Ensure a checkout exists on the server, then pull latest + deps + env. */\nexport async function ensureRemoteRepo(host, service, options = {}) {\n    const { logger = console, deployKey = service.deployKey, envFile } = options;\n    const paths = servicePaths(service);\n    const repo = shellQuote(paths.repo);\n    const repoUrl = shellQuote(service.repoUrl);\n    const root = shellQuote(paths.root);\n\n    const localKeyBase = deployKey ? basename(expandHome(deployKey)) : null;\n    await ensureDeployKeyOnRemote(host, deployKey, { logger });\n    await prepareGitHost(host, { logger, gitHost: parseGitHost(service.repoUrl), keyBasename: localKeyBase });\n\n    await sshRun(\n        host,\n        `mkdir -p ${root} && if [ -d ${repo}/.git ]; then git -C ${repo} pull --ff-only; else git clone ${repoUrl} ${repo}; fi`,\n        { logger },\n    );\n\n    await ensureRepoDependencies(host, service, { logger });\n    await ensureEnvOnRemote(host, service, { logger, envFile });\n}\n\n/**\n * Invoke the toolkit deploy CLI on the server in local mode (no --host), passing\n * the same --service/--manifests + extra flags. Run after ensureRemoteRepo.\n */\nexport async function runRemoteCli(host, service, command, args = [], options = {}) {\n    const { logger = console, manifests, skipPull = false, deployKey = service.deployKey, envFile } = options;\n    const paths = servicePaths(service);\n    const run = shellQuote(paths.repoRun);\n    const cli = shellQuote(REMOTE_CLI_REL);\n\n    if (!skipPull) {\n        deployNotice(logger, `Prepare checkout and dependencies on ${host}`);\n        await ensureRemoteRepo(host, service, { logger, deployKey, envFile });\n    } else {\n        deployNotice(logger, `Install host CLI dependencies on ${host}`);\n        await ensureRepoDependencies(host, service, { logger });\n        await ensureEnvOnRemote(host, service, { logger, envFile });\n    }\n\n    deployNotice(logger, `Run ${command} on ${host}`);\n\n    const passthrough = [\n        `--service=${service.name}`,\n        ...(manifests ? [`--manifests=${manifests}`] : []),\n        ...args,\n    ].map(shellQuote).join(\" \");\n\n    await sshRun(host, `cd ${run} && node ${cli} ${shellQuote(command)} ${passthrough}`.trim(), { logger });\n}\n\nexport async function runRemoteStatus(host, service, options = {}) {\n    const { logger = console } = options;\n    const paths = servicePaths(service);\n    const port = service.pm2.port;\n    const app = service.pm2.appName;\n\n    const script = `\necho \"=== apps root ===\"\nls -la ${shellQuote(paths.root)} 2>/dev/null || echo \"(missing)\"\necho \"\"\necho \"=== current ===\"\nreadlink ${shellQuote(paths.current)} 2>/dev/null || echo \"(not set)\"\necho \"\"\necho \"=== releases ===\"\nls -1 ${shellQuote(paths.releases)} 2>/dev/null || echo \"(none)\"\necho \"\"\necho \"=== pm2 ===\"\npm2 describe ${app} 2>/dev/null | head -20 || pm2 status ${app} 2>/dev/null || echo \"(not running)\"\n${port ? `echo \"\"\necho \"=== app health (localhost) ===\"\ncurl -sf http://127.0.0.1:${port}/healthz 2>/dev/null || echo \"(no /healthz on :${port})\"` : \"\"}\n`.trim();\n\n    await sshRun(host, script, { logger });\n}\n","import { isAbsolute, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport { defineService } from \"./service.js\";\n\n/**\n * Load a project's service manifests module. The module may export:\n *   export const services = { \"my-svc\": { … }, … }   // map\n *   export default { \"my-svc\": { … } }                // map as default\n *   export const services = [ { name: \"my-svc\", … } ] // array\n * Every entry is normalized through defineService().\n *\n * @param {{ manifests?: string, cwd?: string }} opts  manifests = path to the module\n * @returns {Promise<Record<string, object>>} name → normalized service\n */\nexport async function loadServices({ manifests = \"deploy/services.js\", cwd = process.cwd() } = {}) {\n    const abs = isAbsolute(manifests) ? manifests : resolve(cwd, manifests);\n    let mod;\n    try {\n        mod = await import(pathToFileURL(abs).href);\n    } catch (err) {\n        throw new Error(`Could not load deploy manifests from ${abs}: ${err.message}`);\n    }\n\n    const raw = mod.services ?? mod.default;\n    if (!raw) {\n        throw new Error(`Manifests module ${abs} must export \\`services\\` (or default): a map or array of service manifests`);\n    }\n\n    const list = Array.isArray(raw) ? raw : Object.values(raw);\n    const out = {};\n    for (const entry of list) {\n        const svc = defineService(entry);\n        out[svc.name] = svc;\n    }\n    return out;\n}\n\n/** Resolve one normalized service by name (optionally overriding appsRoot). */\nexport function resolveServiceFrom(serviceMap, name, { appsRoot } = {}) {\n    const svc = serviceMap[name];\n    if (!svc) {\n        throw new Error(`Unknown service \"${name}\". Known: ${Object.keys(serviceMap).join(\", \") || \"(none)\"}`);\n    }\n    return appsRoot ? { ...svc, appsRoot } : svc;\n}\n"],"mappings":"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","names":["resolve","import_promises","import_promises","import_node_path","pathDirname","import_promises","import_node_path","import_promises","import_node_path","pathExists","import_promises","import_node_path","import_promises","resolve","import_promises","import_node_path","import_promises","pathExists","import_promises","import_node_path","import_node_child_process","import_promises","import_node_path","pathExists","import_node_child_process","import_promises","import_node_os","import_node_path","pathExists","import_promises","resolveKillTimeoutMs","import_promises","pathExists","import_promises","import_promises","import_node_os","import_node_path","import_node_child_process","pathExists","expandHome","resolve","run","import_node_path"]}