@camstack/agent 1.1.49 → 1.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../node-root/src/index.ts","../../node-root/src/dev-uploads.ts","../../node-root/src/root-package-spec.ts","../../node-root/src/root-state.ts","../../node-root/src/boot-plan.ts","../../node-root/src/semver-compare.ts","../../node-root/src/workspace-detect.ts","../../node-root/src/starter-core.ts","../../node-root/src/root-update-service.ts","../src/starter.ts"],"sourcesContent":["/**\n * @camstack/node-root — the shared, zero-runtime-dep node-root boot core.\n *\n * PRIVATE workspace package: it is BUNDLED at build time into the hub's\n * `dist/server-root/index.js` (tsup) and into the agent's tsup output —\n * never published, never resolved from node_modules at runtime. Both node\n * starters and both update services are thin per-node adapters over these\n * modules, so the boot-plan / probation / rollback semantics can never\n * drift between the hub and the agent.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nexport * from './dev-uploads.js'\nexport * from './root-package-spec.js'\nexport * from './root-state.js'\nexport * from './boot-plan.js'\nexport * from './semver-compare.js'\nexport * from './workspace-detect.js'\nexport * from './starter-core.js'\nexport * from './root-update-service.js'\n","/**\n * Dev server-deploy channel — layout + manifest for locally-uploaded root\n * package closures (ZERO-DEP: node:fs/node:path only, same constraint as\n * root-state.ts — the baked starter bundles this module).\n *\n * `camstack deploy-server` packs every workspace package in the server's\n * `@camstack/*` closure at one uniform dev version\n * (`<base>-dev.<epochSeconds>`) and uploads the tarballs to\n * `POST /api/server-upload`. The hub stores them under:\n *\n * <dataDir>/server-root/dev-uploads/<version>/\n * <flattened-pkg-name>.tgz one per uploaded package\n * manifest.json { version, packages: { name → filename } }\n *\n * `RootUpdateService.stageAndActivate` detects the dir and stages from these\n * tarballs (synthetic package.json with `file:` refs + `overrides`) instead\n * of the npm registry. Everything downstream — probation boot, promote,\n * rollback — is version-string driven and unchanged; the `-dev.` suffix is\n * self-describing.\n *\n * Spec: docs/superpowers/specs — dev server-deploy channel (2026-07-13).\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nexport const DEV_UPLOADS_DIRNAME = 'dev-uploads'\nexport const DEV_UPLOAD_MANIFEST_FILE = 'manifest.json'\n\n/** Number of dev-uploads entries retained by the promote-time sweep. */\nexport const DEV_UPLOADS_KEEP_COUNT = 3\n\n/**\n * Dev-channel version shape: `<semver-base>-dev.<epochSeconds>`. The suffix\n * is sortable, self-describing, and can never collide with a published\n * registry version. The upload route and the staging branch BOTH gate on it.\n */\nconst DEV_CHANNEL_VERSION_RE = /-dev\\.\\d+$/\n\nexport function isDevChannelVersion(version: string): boolean {\n return DEV_CHANNEL_VERSION_RE.test(version)\n}\n\n/**\n * The `<epochSeconds>` ordering key of a dev-channel version (or dir name).\n * Returns null for anything that is not dev-channel shaped — the sweep\n * treats those as oldest so malformed residue is collected first.\n */\nexport function devChannelEpoch(version: string): number | null {\n const match = /-dev\\.(\\d+)$/.exec(version)\n if (match === null) return null\n const epoch = Number.parseInt(match[1] ?? '', 10)\n return Number.isNaN(epoch) ? null : epoch\n}\n\n/** `<dataDir>/server-root/dev-uploads` */\nexport function devUploadsDir(rootDir: string): string {\n return path.join(rootDir, DEV_UPLOADS_DIRNAME)\n}\n\n/** `<dataDir>/server-root/dev-uploads/<version>` */\nexport function devUploadVersionDir(rootDir: string, version: string): string {\n return path.join(devUploadsDir(rootDir), version)\n}\n\n// ---------------------------------------------------------------------------\n// Manifest IO\n// ---------------------------------------------------------------------------\n\n/**\n * Written by the hub's `/api/server-upload` route after validating every\n * tarball; read by the staging branch. Maps each uploaded package NAME to\n * its tgz FILENAME inside the version dir — staging never has to re-derive\n * package names from flattened filenames.\n */\nexport interface DevUploadManifest {\n readonly version: string\n readonly packages: Readonly<Record<string, string>>\n}\n\nexport function devUploadManifestPath(versionDirPath: string): string {\n return path.join(versionDirPath, DEV_UPLOAD_MANIFEST_FILE)\n}\n\nfunction isDevUploadManifest(v: unknown): v is DevUploadManifest {\n if (typeof v !== 'object' || v === null) return false\n const m = v as Record<string, unknown>\n if (typeof m['version'] !== 'string') return false\n const packages = m['packages']\n if (typeof packages !== 'object' || packages === null || Array.isArray(packages)) return false\n return Object.values(packages).every((filename) => typeof filename === 'string')\n}\n\n/** Read + validate the manifest. Returns null when missing/corrupt. */\nexport function readDevUploadManifest(versionDirPath: string): DevUploadManifest | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(devUploadManifestPath(versionDirPath), 'utf-8'))\n return isDevUploadManifest(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Write the manifest atomically (tmp sibling + rename). Creates the dir. */\nexport function writeDevUploadManifest(versionDirPath: string, manifest: DevUploadManifest): void {\n fs.mkdirSync(versionDirPath, { recursive: true })\n const target = devUploadManifestPath(versionDirPath)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n","/**\n * Root-package spec — the per-node-type parameters of the shared node-root\n * boot machinery. Everything else (the `server-root/` data-dir layout, the\n * `state.json` schema, the probation/rollback boot plan, the update service)\n * is IDENTICAL between the hub and the agent; only the root package's name\n * and its loadable entry differ.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\n\nexport interface RootPackageSpec {\n /** The npm name of the node's root package. */\n readonly packageName: string\n /**\n * Path segments of the loadable entry INSIDE the root package dir\n * (`node_modules/<packageName>/<...entryRelPath>`).\n */\n readonly entryRelPath: readonly string[]\n}\n\n/** The hub's root package — the starter loads its launcher. */\nexport const HUB_ROOT_SPEC: RootPackageSpec = {\n packageName: '@camstack/server',\n entryRelPath: ['dist', 'launcher.js'],\n}\n\n/** The agent's root package — the starter loads its CLI entry. */\nexport const AGENT_ROOT_SPEC: RootPackageSpec = {\n packageName: '@camstack/agent',\n entryRelPath: ['dist', 'cli.js'],\n}\n","/**\n * Data-dir server-root layout + state file — ZERO-DEP (node:fs/node:path only).\n *\n * Loaded by each node's baked STARTER before any node_modules resolution is\n * trusted, so this module must never import from `@camstack/*` (runtime) or\n * any npm package. The hub's `ServerUpdateService` and the agent's update\n * service consume the same module — one source of truth for the layout and\n * the state shape. The layout is IDENTICAL on both node types (the dir is\n * named `server-root/` everywhere); only the root package name + entry differ\n * and arrive via {@link RootPackageSpec}.\n *\n * Layout (`<dataDir>/server-root/`):\n * versions/<semver>/ npm-installed closure for one version\n * node_modules/<pkg>/<entry> ← the loadable entry (spec-defined)\n * state.json pointer file (ServerRootState, atomic)\n *\n * A POINTER FILE (state.json) is used instead of `current`/`previous`\n * symlinks: atomic via tmp+rename, works on every fs, and carries the\n * probation/rollback bookkeeping in the same durable record.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { RootPackageSpec } from './root-package-spec.js'\n\nexport const SERVER_ROOT_DIRNAME = 'server-root'\nexport const SERVER_ROOT_STATE_FILE = 'state.json'\n/**\n * Restart-intent marker filename. Written by the update service moments before\n * a graceful self-restart (apply/rollback), then read + consumed by an\n * external process supervisor so it can tell an INTENTIONAL restart-for-update\n * apart from a crash — a crash-backoff policy must never penalise an update\n * restart. Lives in the server-root dir next to `state.json`.\n *\n * (Phase 3 — the Electron shell supervisor reads it; the docker restart policy\n * relaunches unconditionally so the marker is a harmless no-op there.)\n */\nexport const RESTART_INTENT_FILE = '.restart-intent'\n\n// ---------------------------------------------------------------------------\n// State shape\n// ---------------------------------------------------------------------------\n\nexport interface ServerRootPendingBoot {\n /** The freshly-staged version awaiting its probation boot. */\n readonly version: string\n /** The version that was current when the update was requested (null = baked). */\n readonly fromVersion: string | null\n readonly requestedAtMs: number\n /** 0 = not yet booted; >=1 = a probation boot started and never confirmed. */\n readonly bootAttempts: number\n}\n\nexport interface ServerRootRollbackInfo {\n readonly fromVersion: string\n /** null = rolled back all the way to the baked seed. */\n readonly toVersion: string | null\n readonly atMs: number\n readonly reason: string\n}\n\nexport interface ServerRootState {\n readonly schemaVersion: 1\n /** The confirmed-healthy active version (null = boot from the baked seed). */\n readonly currentVersion: string | null\n /** N-1 kept for rollback (its versions/ dir is retained). */\n readonly previousVersion: string | null\n readonly pendingBoot: ServerRootPendingBoot | null\n /** Set when the most recent update attempt was rolled back. */\n readonly rolledBack: ServerRootRollbackInfo | null\n}\n\nexport function emptyServerRootState(): ServerRootState {\n return {\n schemaVersion: 1,\n currentVersion: null,\n previousVersion: null,\n pendingBoot: null,\n rolledBack: null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Layout helpers\n// ---------------------------------------------------------------------------\n\nexport function serverRootDir(dataDir: string): string {\n return path.join(dataDir, SERVER_ROOT_DIRNAME)\n}\n\nexport function versionsDir(rootDir: string): string {\n return path.join(rootDir, 'versions')\n}\n\nexport function versionDir(rootDir: string, version: string): string {\n return path.join(versionsDir(rootDir), version)\n}\n\n/** `versions/<v>/node_modules/<packageName>` — the installed root package dir. */\nexport function rootPackageDir(versionDirPath: string, spec: RootPackageSpec): string {\n return path.join(versionDirPath, 'node_modules', ...spec.packageName.split('/'))\n}\n\n/** The loadable entry inside the installed root package dir. */\nexport function rootEntryPath(versionDirPath: string, spec: RootPackageSpec): string {\n return path.join(rootPackageDir(versionDirPath, spec), ...spec.entryRelPath)\n}\n\nexport function stateFilePath(rootDir: string): string {\n return path.join(rootDir, SERVER_ROOT_STATE_FILE)\n}\n\n// ---------------------------------------------------------------------------\n// State IO (atomic, corruption-tolerant)\n// ---------------------------------------------------------------------------\n\nfunction isNullableString(v: unknown): v is string | null {\n return v === null || typeof v === 'string'\n}\n\nfunction isPendingBoot(v: unknown): v is ServerRootPendingBoot {\n if (typeof v !== 'object' || v === null) return false\n const p = v as Record<string, unknown>\n return (\n typeof p['version'] === 'string' &&\n isNullableString(p['fromVersion']) &&\n typeof p['requestedAtMs'] === 'number' &&\n typeof p['bootAttempts'] === 'number'\n )\n}\n\nfunction isRollbackInfo(v: unknown): v is ServerRootRollbackInfo {\n if (typeof v !== 'object' || v === null) return false\n const r = v as Record<string, unknown>\n return (\n typeof r['fromVersion'] === 'string' &&\n isNullableString(r['toVersion']) &&\n typeof r['atMs'] === 'number' &&\n typeof r['reason'] === 'string'\n )\n}\n\nexport function isServerRootState(v: unknown): v is ServerRootState {\n if (typeof v !== 'object' || v === null) return false\n const s = v as Record<string, unknown>\n if (s['schemaVersion'] !== 1) return false\n if (!isNullableString(s['currentVersion'])) return false\n if (!isNullableString(s['previousVersion'])) return false\n if (s['pendingBoot'] !== null && !isPendingBoot(s['pendingBoot'])) return false\n if (s['rolledBack'] !== null && !isRollbackInfo(s['rolledBack'])) return false\n return true\n}\n\n/** Read + validate the state file. Returns null when missing/corrupt/mismatched. */\nexport function readServerRootState(rootDir: string): ServerRootState | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(stateFilePath(rootDir), 'utf-8'))\n return isServerRootState(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Write the state file atomically (tmp sibling + rename). Creates rootDir. */\nexport function writeServerRootState(rootDir: string, state: ServerRootState): void {\n fs.mkdirSync(rootDir, { recursive: true })\n const target = stateFilePath(rootDir)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n\n// ---------------------------------------------------------------------------\n// Restart-intent marker (supervisor: update-restart vs crash discrimination)\n// ---------------------------------------------------------------------------\n\n/**\n * Payload of the restart-intent marker. `requestedAtMs` lets a reader ignore a\n * STALE marker (e.g. one left behind by a hard kill between write and\n * relaunch) via a freshness window instead of mis-classifying a much-later\n * crash as an update restart. `reason` carries the human `requestedBy` string.\n */\nexport interface RestartIntentMarker {\n readonly requestedAtMs: number\n readonly reason: string\n}\n\nexport function restartIntentMarkerPath(rootDir: string): string {\n return path.join(rootDir, RESTART_INTENT_FILE)\n}\n\nfunction isRestartIntentMarker(v: unknown): v is RestartIntentMarker {\n if (typeof v !== 'object' || v === null) return false\n const m = v as Record<string, unknown>\n return typeof m['requestedAtMs'] === 'number' && typeof m['reason'] === 'string'\n}\n\n/** Write the marker atomically (tmp sibling + rename). Creates rootDir. */\nexport function writeRestartIntentMarker(rootDir: string, marker: RestartIntentMarker): void {\n fs.mkdirSync(rootDir, { recursive: true })\n const target = restartIntentMarkerPath(rootDir)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(marker, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n\n/** Read + validate the marker. Returns null when missing/corrupt. */\nexport function readRestartIntentMarker(rootDir: string): RestartIntentMarker | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(restartIntentMarkerPath(rootDir), 'utf-8'))\n return isRestartIntentMarker(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Delete the marker if present (idempotent — a missing file is not an error). */\nexport function clearRestartIntentMarker(rootDir: string): void {\n try {\n fs.rmSync(restartIntentMarkerPath(rootDir), { force: true })\n } catch {\n /* best-effort */\n }\n}\n\n// ---------------------------------------------------------------------------\n// Version-dir validation\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the minimum required Node major from an `engines.node` range like\n * `>=22`, `>= 22.12`, `^24.0.0`, `22.x`. Returns null when unparseable\n * (validation is then permissive — a bogus range must not brick boot).\n */\nexport function minNodeMajorOf(enginesNode: string): number | null {\n const match = /(\\d+)/.exec(enginesNode)\n if (match === null) return null\n const major = Number.parseInt(match[1] ?? '', 10)\n return Number.isNaN(major) ? null : major\n}\n\n/**\n * Validate that `versions/<version>` holds a loadable root-package closure\n * for `spec`. Returns null when valid, else a human-readable reason. Checks:\n * 1. the entry file exists,\n * 2. the package.json parses with the right `name` + `version`,\n * 3. `engines.node` (when parseable) is satisfied by the running runtime —\n * the starter refuses a native-ABI mismatch with a clear error instead\n * of segfaulting (design risk: node bump vs shm-ring prebuilds).\n */\nexport function validateVersionDir(\n rootDir: string,\n version: string,\n nodeMajor: number,\n spec: RootPackageSpec,\n): string | null {\n const vDir = versionDir(rootDir, version)\n const entry = rootEntryPath(vDir, spec)\n if (!fs.existsSync(entry)) {\n return `root entry missing: ${entry}`\n }\n\n const pkgJsonPath = path.join(rootPackageDir(vDir, spec), 'package.json')\n let pkg: Record<string, unknown>\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return `package.json malformed: ${pkgJsonPath}`\n }\n pkg = raw as Record<string, unknown>\n } catch {\n return `package.json unreadable: ${pkgJsonPath}`\n }\n\n if (pkg['name'] !== spec.packageName) {\n return `package name mismatch: expected ${spec.packageName}, got ${String(pkg['name'])}`\n }\n if (pkg['version'] !== version) {\n return `package version mismatch: dir says ${version}, package.json says ${String(pkg['version'])}`\n }\n\n const engines = pkg['engines']\n if (typeof engines === 'object' && engines !== null) {\n const enginesNode = (engines as Record<string, unknown>)['node']\n if (typeof enginesNode === 'string') {\n const minMajor = minNodeMajorOf(enginesNode)\n if (minMajor !== null && nodeMajor < minMajor) {\n return `engines.node \"${enginesNode}\" requires Node >= ${minMajor}, runtime is ${nodeMajor}`\n }\n }\n }\n\n return null\n}\n","/**\n * Pure boot-plan decision for the server-root starter — ZERO-DEP.\n *\n * Given the durable `ServerRootState` and a validity predicate for staged\n * version dirs, decide WHICH closure this boot should load and what the\n * state file must be updated to. All filesystem access is behind the\n * injected `isValidVersion` callback so the decision itself is unit-testable.\n *\n * Probation / rollback protocol (mirrors `launcher-framework-swap.ts`):\n * - `pendingBoot.bootAttempts === 0` → this is the probation boot: bump the\n * counter durably BEFORE loading the new version. The hub clears the\n * pending record (promoting the version to `currentVersion`) only once it\n * reaches ready (`ServerUpdateService.confirmBootHealthy`).\n * - `pendingBoot.bootAttempts >= 1` → the previous probation boot died\n * before confirming: auto-rollback to `currentVersion` (or baked) and\n * record `rolledBack` so the status cap can surface it.\n */\nimport type { ServerRootState } from './root-state.js'\n\nexport type BootPlan =\n | {\n readonly kind: 'baked'\n readonly reason: string\n readonly stateToWrite: ServerRootState | null\n }\n | {\n readonly kind: 'data-root'\n readonly version: string\n /** True when this boot must be confirmed healthy (freshly-staged version). */\n readonly probation: boolean\n readonly stateToWrite: ServerRootState | null\n }\n\ntype IsValidVersion = (version: string) => boolean\ntype NowFn = () => number\n\n/**\n * Decide the boot target. Never throws; never mutates `state`.\n * `stateToWrite` is non-null whenever the durable state must change\n * (probation counter bump, rollback, invalid-version eviction).\n */\nexport function planBoot(\n state: ServerRootState | null,\n isValidVersion: IsValidVersion,\n now: NowFn,\n): BootPlan {\n if (state === null) {\n return { kind: 'baked', reason: 'no server-root state', stateToWrite: null }\n }\n\n let next: ServerRootState = state\n let changed = false\n\n // ── Pending (freshly-staged) version ──────────────────────────────────\n if (next.pendingBoot !== null) {\n const pending = next.pendingBoot\n if (pending.bootAttempts >= 1) {\n // Previous probation boot never confirmed healthy — roll back.\n next = {\n ...next,\n pendingBoot: null,\n rolledBack: {\n fromVersion: pending.version,\n toVersion: next.currentVersion,\n atMs: now(),\n reason: 'probation boot did not reach ready — rolled back',\n },\n }\n changed = true\n } else if (!isValidVersion(pending.version)) {\n next = {\n ...next,\n pendingBoot: null,\n rolledBack: {\n fromVersion: pending.version,\n toVersion: next.currentVersion,\n atMs: now(),\n reason: 'staged version failed validation',\n },\n }\n changed = true\n } else {\n // Probation boot: bump the attempt counter durably, keep currentVersion\n // untouched until the hub confirms the boot healthy.\n return {\n kind: 'data-root',\n version: pending.version,\n probation: true,\n stateToWrite: {\n ...next,\n pendingBoot: { ...pending, bootAttempts: pending.bootAttempts + 1 },\n },\n }\n }\n }\n\n // ── Confirmed current version ──────────────────────────────────────────\n if (next.currentVersion !== null) {\n if (isValidVersion(next.currentVersion)) {\n return {\n kind: 'data-root',\n version: next.currentVersion,\n probation: false,\n stateToWrite: changed ? next : null,\n }\n }\n\n // Current version dir is broken — try N-1, else baked.\n const broken = next.currentVersion\n if (next.previousVersion !== null && isValidVersion(next.previousVersion)) {\n const fallback = next.previousVersion\n return {\n kind: 'data-root',\n version: fallback,\n probation: false,\n stateToWrite: {\n ...next,\n currentVersion: fallback,\n previousVersion: null,\n rolledBack: {\n fromVersion: broken,\n toVersion: fallback,\n atMs: now(),\n reason: 'active version failed validation',\n },\n },\n }\n }\n\n return {\n kind: 'baked',\n reason: `active version ${broken} failed validation and no valid previous version exists`,\n stateToWrite: {\n ...next,\n currentVersion: null,\n rolledBack: {\n fromVersion: broken,\n toVersion: null,\n atMs: now(),\n reason: 'active version failed validation',\n },\n },\n }\n }\n\n return {\n kind: 'baked',\n reason: 'no active data-root version',\n stateToWrite: changed ? next : null,\n }\n}\n","/**\n * Minimal semver comparison — zero-dep (used by the starter, which must never\n * import from node_modules). Handles `MAJOR.MINOR.PATCH[-prerelease]`:\n * numeric segment compare, missing segments = 0, prerelease < its release,\n * prereleases of the same base compare lexically. Malformed segments compare\n * as 0 (best effort — never throws).\n */\n\ntype SemverParts = {\n readonly nums: readonly number[]\n readonly prerelease: string | null\n}\n\nfunction parse(version: string): SemverParts {\n const dashIdx = version.indexOf('-')\n const base = dashIdx === -1 ? version : version.slice(0, dashIdx)\n const prerelease = dashIdx === -1 ? null : version.slice(dashIdx + 1)\n const nums = base.split('.').map((seg) => {\n const n = Number.parseInt(seg, 10)\n return Number.isNaN(n) ? 0 : n\n })\n return { nums, prerelease }\n}\n\n/** Returns -1 when a < b, 0 when equal, 1 when a > b. */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parse(a)\n const pb = parse(b)\n const len = Math.max(pa.nums.length, pb.nums.length)\n for (let i = 0; i < len; i++) {\n const na = pa.nums[i] ?? 0\n const nb = pb.nums[i] ?? 0\n if (na < nb) return -1\n if (na > nb) return 1\n }\n if (pa.prerelease === null && pb.prerelease === null) return 0\n if (pa.prerelease === null) return 1\n if (pb.prerelease === null) return -1\n if (pa.prerelease < pb.prerelease) return -1\n if (pa.prerelease > pb.prerelease) return 1\n return 0\n}\n","/**\n * Workspace-checkout detection for the starter — ZERO-DEP.\n *\n * The starter must defer to plain resolution in a dev checkout (`npm run\n * dev:full` / `npm start` from the monorepo): the data-dir server root is a\n * production mechanism and must never shadow freshly-built workspace code.\n * Detection = any ancestor package.json declaring `workspaces` (the monorepo\n * root has one; the baked image run-dir's `npm init -y` package.json and the\n * data-dir version closures never do).\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\n/**\n * Walk up from `fromDir` looking for a package.json with a `workspaces`\n * field. Returns the directory containing it, or null when none exists.\n */\nexport function detectWorkspaceRoot(fromDir: string): string | null {\n let dir = path.resolve(fromDir)\n for (;;) {\n const pkgPath = path.join(dir, 'package.json')\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (\n typeof raw === 'object' &&\n raw !== null &&\n (raw as Record<string, unknown>)['workspaces'] !== undefined\n ) {\n return dir\n }\n } catch {\n // missing / unreadable package.json — keep walking\n }\n const parent = path.dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n","/**\n * Shared STARTER core — the boot flow both node starters (hub + agent) run.\n * ZERO-DEP: bundled into each starter at build time; must never resolve\n * anything from node_modules at runtime.\n *\n * Boot sequence (identical on both node types; per-node names arrive via\n * {@link NodeStarterOptions}):\n * 1. Workspace checkout? → defer to plain resolution (load the sibling\n * seed entry; the dev loop never runs the built starter at all).\n * 2. Read `<dataDir>/server-root/state.json`, run the pure boot plan\n * (probation counter / auto-rollback / validity fallback) and persist\n * any state change BEFORE loading code.\n * 3. Data-root chosen → register in-process resolver hooks so the node's\n * MAIN process resolves the host-external packages (@camstack/system, …)\n * from the ACTIVE root's node_modules, then load that root's entry.\n * 4. Otherwise → load the baked seed entry next to the starter.\n *\n * Console usage is intentional: the starter runs before any logging exists.\n * Every line is prefixed `[starter]`.\n */\nimport * as path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { planBoot } from './boot-plan.js'\nimport type { RootPackageSpec } from './root-package-spec.js'\nimport {\n readServerRootState,\n rootEntryPath,\n serverRootDir,\n validateVersionDir,\n versionDir,\n writeServerRootState,\n} from './root-state.js'\nimport { detectWorkspaceRoot } from './workspace-detect.js'\n\n/**\n * Mirror of the host-external list in\n * `packages/system/src/kernel/moleculer/framework-resolver-hook.mjs` — kept\n * inline because the starter must stay zero-dep. Only these specifiers are\n * redirected to the active root; everything else resolves normally.\n */\nexport const HOST_EXTERNAL_SPECIFIERS: readonly string[] = [\n '@camstack/system',\n '@camstack/shm-ring',\n '@camstack/types',\n '@camstack/sdk',\n 'zod',\n '@trpc/server',\n '@trpc/client',\n 'sharp',\n 'node-av',\n]\n\nexport function isHostExternal(specifier: string): boolean {\n return HOST_EXTERNAL_SPECIFIERS.some(\n (name) => specifier === name || specifier.startsWith(`${name}/`),\n )\n}\n\ntype ResolveContext = { readonly parentURL?: string }\ntype NextResolve = (specifier: string, context?: ResolveContext) => unknown\ntype RegisterHooksFn = (hooks: {\n resolve: (specifier: string, context: ResolveContext, nextResolve: NextResolve) => unknown\n}) => void\n\n/**\n * Register in-process resolver hooks (Node >= 22.15 `module.registerHooks`,\n * covers BOTH require and import) that anchor host-external resolution inside\n * the active root's node_modules. Failure-tolerant: if the anchored resolve\n * fails (package absent from the closure, e.g. sharp/node-av), fall back to\n * the default walk (NODE_PATH /data/framework still covers those).\n */\nexport function registerActiveRootResolver(activeRootDir: string): void {\n // Documented type boundary: `module.registerHooks` is not yet in the\n // bundled @types/node — feature-detect it off the untyped module surface.\n const moduleApi: Record<string, unknown> = require('node:module')\n const registerHooks = moduleApi['registerHooks']\n if (typeof registerHooks !== 'function') {\n console.warn(\n '[starter] module.registerHooks unavailable (Node < 22.15) — host-external redirect skipped',\n )\n return\n }\n const anchorURL = pathToFileURL(\n path.join(activeRootDir, 'node_modules', '__camstack_starter_anchor__.js'),\n ).href\n const hooks: Parameters<RegisterHooksFn>[0] = {\n resolve: (specifier, context, nextResolve) => {\n if (isHostExternal(specifier)) {\n try {\n return nextResolve(specifier, { ...context, parentURL: anchorURL })\n } catch {\n // Not in the active root's closure — fall through to default.\n }\n }\n return nextResolve(specifier, context)\n },\n }\n ;(registerHooks as RegisterHooksFn)(hooks)\n}\n\n/** Per-node env-var names the starter writes / reads. */\nexport interface StarterEnvNames {\n /** Boot-mode marker read by the node's update service (`workspace`/`baked`/`data-root`). */\n readonly bootMode: string\n /** Absolute path of the active data-root version dir (data-root boots only). */\n readonly activeRoot: string\n /** Active data-root version (data-root boots only). */\n readonly activeVersion: string\n /** Kill switch: `<killSwitch>=off` forces the baked seed closure. */\n readonly killSwitch: string\n}\n\nexport interface NodeStarterOptions {\n readonly spec: RootPackageSpec\n readonly envNames: StarterEnvNames\n /** The node's resolved data dir (owner-specific env/argv resolution). */\n readonly dataDir: string\n /** Absolute path of the baked seed entry sibling to the starter. */\n readonly seedEntry: string\n /** The starter's own dir (`__dirname`) — anchors workspace detection. */\n readonly starterDir: string\n /** Load an entry file (a plain CJS `require` in the real starters). */\n readonly loadEntry: (entryPath: string) => void\n /** Test seams. Defaults: `process.env`, `Date.now`, running node major. */\n readonly env?: NodeJS.ProcessEnv\n readonly now?: () => number\n readonly nodeMajor?: number\n readonly registerResolver?: (activeRootDir: string) => void\n}\n\n/**\n * Run the shared starter flow. Never throws for boot-plan reasons — every\n * failure path degrades to the baked seed. (A `loadEntry` throw propagates:\n * that is the caller's fatal handler's job.)\n */\nexport function runNodeStarter(options: NodeStarterOptions): void {\n const env = options.env ?? process.env\n const now = options.now ?? Date.now\n const registerResolver = options.registerResolver ?? registerActiveRootResolver\n\n // ── 1. Workspace checkout → plain resolution, dev loop untouched ────────\n const disabled = env[options.envNames.killSwitch] === 'off'\n const workspaceRoot = detectWorkspaceRoot(options.starterDir)\n if (workspaceRoot !== null) {\n console.log(\n `[starter] workspace checkout detected at ${workspaceRoot} — using plain resolution`,\n )\n env[options.envNames.bootMode] = 'workspace'\n options.loadEntry(options.seedEntry)\n return\n }\n if (disabled) {\n console.log(`[starter] ${options.envNames.killSwitch}=off — booting the baked seed closure`)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n return\n }\n\n // ── 2. Boot plan from the durable server-root state ─────────────────────\n const rootDir = serverRootDir(options.dataDir)\n const state = readServerRootState(rootDir)\n const nodeMajor =\n options.nodeMajor ?? Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n const isValidVersion = (version: string): boolean => {\n const reason = validateVersionDir(rootDir, version, nodeMajor, options.spec)\n if (reason !== null) console.warn(`[starter] version ${version} invalid: ${reason}`)\n return reason === null\n }\n\n const plan = planBoot(state, isValidVersion, now)\n if (plan.stateToWrite !== null) {\n try {\n writeServerRootState(rootDir, plan.stateToWrite)\n } catch (err) {\n // A state write failure must not brick boot — fall back to the seed\n // (booting a probation version WITHOUT the durable attempt counter\n // would disarm the crash-loop rollback).\n console.error('[starter] FAILED to persist server-root state — booting baked seed:', err)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n return\n }\n if (\n plan.stateToWrite.rolledBack !== null &&\n (state?.rolledBack ?? null) !== plan.stateToWrite.rolledBack\n ) {\n const rb = plan.stateToWrite.rolledBack\n console.warn(\n `[starter] ROLLED BACK ${rb.fromVersion} -> ${rb.toVersion ?? 'baked seed'}: ${rb.reason}`,\n )\n }\n }\n\n // ── 3. Load the chosen closure ───────────────────────────────────────────\n if (plan.kind === 'data-root') {\n const activeRootDir = versionDir(rootDir, plan.version)\n const entry = rootEntryPath(activeRootDir, options.spec)\n console.log(\n `[starter] booting ${options.spec.packageName}@${plan.version} from ${activeRootDir}` +\n (plan.probation ? ' (probation boot — health-check armed)' : ''),\n )\n env[options.envNames.bootMode] = 'data-root'\n env[options.envNames.activeRoot] = activeRootDir\n env[options.envNames.activeVersion] = plan.version\n registerResolver(activeRootDir)\n options.loadEntry(entry)\n return\n }\n\n console.log(`[starter] booting baked seed closure (${plan.reason})`)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n}\n","/**\n * RootUpdateService — the shared install/update/rollback engine for a node's\n * runtime-updatable ROOT package (`@camstack/server` on the hub,\n * `@camstack/agent` on agents). Phase 2 of the runtime-updatable node\n * packages design: the hub's `ServerUpdateService` and the agent's\n * `AgentUpdateService` are thin adapters over this one class, so the\n * security-review fixes (rollback reentrancy guards, fresh-transient prune\n * protection, corrupt-state visibility) exist in exactly one place.\n *\n * Responsibilities:\n * - stage a new `<pkg>@X` closure into\n * `<dataDir>/server-root/versions/<X>/` (npm install into a same-fs\n * staging dir + atomic rename activation),\n * - keep exactly one previous version (N-1) for rollback,\n * - drive the probation-boot protocol via the durable `state.json`\n * (`pendingBoot` armed here, consumed by the STARTER on the next boot,\n * promoted by `confirmBootHealthy()` once the node reaches ready),\n * - back the `server-management` cap methods on every node type.\n *\n * The starter core (starter-core.ts) owns the OTHER half: choosing the\n * closure at boot, bumping the probation counter, auto-rolling-back a\n * version whose probation boot never confirmed.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nimport { execFile } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { promisify } from 'node:util'\nimport type {\n ServerBootMode,\n ServerPackageStatus,\n ServerUpdateActionResult,\n ServerUpdateCheckResult,\n ServerUpdateState,\n} from '@camstack/types'\nimport {\n DEV_UPLOADS_KEEP_COUNT,\n devChannelEpoch,\n devUploadVersionDir,\n devUploadsDir,\n isDevChannelVersion,\n readDevUploadManifest,\n} from './dev-uploads.js'\nimport type { RootPackageSpec } from './root-package-spec.js'\nimport { compareSemver } from './semver-compare.js'\nimport {\n emptyServerRootState,\n readServerRootState,\n rootEntryPath,\n rootPackageDir,\n serverRootDir,\n stateFilePath,\n validateVersionDir,\n versionDir,\n versionsDir,\n writeServerRootState,\n type ServerRootState,\n} from './root-state.js'\nimport { detectWorkspaceRoot } from './workspace-detect.js'\n\nconst execFileAsync = promisify(execFile)\n\n/** npm registry override args — mirrors addon-package.service (module-local there). */\nfunction buildNpmRegistryArgs(registry: string | undefined): readonly string[] {\n if (registry === undefined || registry.length === 0) return []\n return ['--registry', registry, `--@camstack:registry=${registry}`]\n}\n\nexport type NpmExecFn = (\n args: readonly string[],\n opts: { readonly cwd?: string; readonly timeoutMs: number },\n) => Promise<{ stdout: string }>\n\n/**\n * Structural logger surface — satisfied by the hub's `IScopedLogger` AND the\n * agent's console logger, without a runtime dependency on `@camstack/types`.\n */\nexport interface RootUpdateLogger {\n debug(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n info(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n warn(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n error(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n}\n\n/** Per-node env-var names the update service reads (written by the starter). */\nexport interface RootUpdateEnvNames {\n /** `workspace` / `baked` / `data-root` marker set by the starter. */\n readonly bootMode: string\n /** Active data-root version (data-root boots only). */\n readonly activeVersion: string\n /** Directory of the immutable baked seed root package (image-set). */\n readonly seedDir: string\n}\n\nexport interface RootUpdateServiceOptions {\n readonly spec: RootPackageSpec\n readonly envNames: RootUpdateEnvNames\n readonly logger: RootUpdateLogger\n /** Graceful restart seam (hub: AddonPackageService.restartServer; agent: SIGTERM self). */\n readonly restartServer: (requestedBy: string) => void\n /** The node's resolved data dir (adapters own the per-node default). */\n readonly dataDir: string\n /** package.json of the RUNNING root-package copy (adapters own the default). */\n readonly runningPackageJsonPath: string\n /** Anchor for the boot-mode fallback classification (adapter `__dirname`). */\n readonly workspaceProbeDir: string\n /** Overrides for tests. */\n readonly execNpm?: NpmExecFn\n readonly env?: NodeJS.ProcessEnv\n readonly now?: () => number\n}\n\ninterface CheckCache {\n readonly latestVersion: string | null\n readonly checkedAtMs: number\n readonly error: string | null\n}\n\nconst NPM_VIEW_TIMEOUT_MS = 20_000\nconst NPM_INSTALL_TIMEOUT_MS = 15 * 60_000\nconst RESTART_REASON_PREFIX = 'server-update'\n\nfunction readPackageVersion(pkgJsonPath: string): string | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n if (typeof raw === 'object' && raw !== null) {\n const version = (raw as Record<string, unknown>)['version']\n if (typeof version === 'string') return version\n }\n } catch {\n // missing / malformed — treated as unknown\n }\n return null\n}\n\nexport class RootUpdateService {\n private readonly spec: RootPackageSpec\n private readonly envNames: RootUpdateEnvNames\n private readonly logger: RootUpdateLogger\n private readonly restartServerFn: (requestedBy: string) => void\n private readonly dataDir: string\n private readonly execNpm: NpmExecFn\n private readonly env: NodeJS.ProcessEnv\n private readonly now: () => number\n private readonly runningPackageJsonPath: string\n private readonly workspaceProbeDir: string\n\n private checkCache: CheckCache | null = null\n private inFlight: 'idle' | 'checking' | 'staging' = 'idle'\n\n constructor(options: RootUpdateServiceOptions) {\n this.spec = options.spec\n this.envNames = options.envNames\n this.logger = options.logger\n this.restartServerFn = options.restartServer\n this.dataDir = path.resolve(options.dataDir)\n this.execNpm =\n options.execNpm ??\n (async (args, opts) => {\n const { stdout } = await execFileAsync('npm', [...args], {\n cwd: opts.cwd,\n timeout: opts.timeoutMs,\n })\n return { stdout }\n })\n this.env = options.env ?? process.env\n this.now = options.now ?? Date.now\n this.runningPackageJsonPath = options.runningPackageJsonPath\n this.workspaceProbeDir = options.workspaceProbeDir\n }\n\n // ── Status ────────────────────────────────────────────────────────────\n\n resolveBootMode(): ServerBootMode {\n const raw = this.env[this.envNames.bootMode]\n if (raw === 'workspace' || raw === 'baked' || raw === 'data-root') return raw\n // The starter didn't run (dev tsx entry, `npm start`, or a pre-starter\n // image) — classify by checkout shape.\n return detectWorkspaceRoot(this.workspaceProbeDir) !== null ? 'workspace' : 'baked'\n }\n\n private runningVersion(): string | null {\n return readPackageVersion(this.runningPackageJsonPath)\n }\n\n /** The running root package's identity — feeds registerNode / topology rows. */\n getRunningRootPackage(): { readonly name: string; readonly version: string | null } {\n return { name: this.spec.packageName, version: this.runningVersion() }\n }\n\n private seedVersion(): string | null {\n const seedDir = this.env[this.envNames.seedDir]\n if (seedDir === undefined || seedDir.length === 0) return null\n return readPackageVersion(path.join(seedDir, 'package.json'))\n }\n\n private rootDir(): string {\n return serverRootDir(this.dataDir)\n }\n\n private readState(): ServerRootState {\n return readServerRootState(this.rootDir()) ?? emptyServerRootState()\n }\n\n /**\n * Like `readState`, but distinguishes \"state.json missing\" (normal on a\n * fresh node) from \"state.json present but corrupt\" — in the corrupt case\n * the starter booted the baked seed while installed data-dir versions are\n * silently ignored, which the status surface must make visible.\n */\n private readStateInfo(): { state: ServerRootState; corrupt: boolean } {\n const rootDir = this.rootDir()\n const raw = readServerRootState(rootDir)\n if (raw !== null) return { state: raw, corrupt: false }\n return { state: emptyServerRootState(), corrupt: fs.existsSync(stateFilePath(rootDir)) }\n }\n\n private updateState(state: ServerRootState): ServerUpdateState {\n if (this.inFlight === 'checking') return 'checking'\n if (this.inFlight === 'staging') return 'staging'\n if (state.pendingBoot !== null) {\n // Distinguish \"staged, not yet restarted\" (still on the OLD version)\n // from \"restarted onto the staged version, awaiting its boot-health\n // confirmation\" — the latter is the probation boot: apply/rollback are\n // refused and the node must not be manually restarted (security review\n // #2). We ARE the probation boot when the active version the starter\n // booted equals the pending version.\n const activeVersion = this.env[this.envNames.activeVersion] ?? null\n if (activeVersion !== null && activeVersion === state.pendingBoot.version) {\n return 'awaiting-confirmation'\n }\n return 'pending-restart'\n }\n return 'idle'\n }\n\n async getServerPackageStatus(): Promise<ServerPackageStatus> {\n const { state, corrupt } = this.readStateInfo()\n const runningVersion = this.runningVersion()\n const latestVersion = this.checkCache?.latestVersion ?? null\n const updateAvailable =\n latestVersion !== null &&\n runningVersion !== null &&\n compareSemver(latestVersion, runningVersion) > 0\n return {\n packageName: this.spec.packageName,\n runningVersion,\n nodeRuntimeVersion: process.versions.node,\n activeVersion: this.env[this.envNames.activeVersion] ?? state.currentVersion,\n previousVersion: state.previousVersion,\n seedVersion: this.seedVersion(),\n latestVersion,\n updateAvailable,\n bootMode: this.resolveBootMode(),\n updateState: this.updateState(state),\n pendingVersion: state.pendingBoot?.version ?? null,\n rolledBack: state.rolledBack,\n stateFileCorrupt: corrupt,\n lastCheckedAtMs: this.checkCache?.checkedAtMs ?? null,\n }\n }\n\n // ── Check ─────────────────────────────────────────────────────────────\n\n async checkServerUpdate(): Promise<ServerUpdateCheckResult> {\n const runningVersion = this.runningVersion()\n if (this.inFlight !== 'idle') {\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion: this.checkCache?.latestVersion ?? null,\n updateAvailable: false,\n checkedAtMs: this.checkCache?.checkedAtMs ?? this.now(),\n error: `busy: ${this.inFlight}`,\n }\n }\n this.inFlight = 'checking'\n try {\n const registry = this.env['CAMSTACK_NPM_REGISTRY']\n const args = [\n 'view',\n `${this.spec.packageName}@latest`,\n 'version',\n ...buildNpmRegistryArgs(registry),\n ]\n const { stdout } = await this.execNpm(args, { timeoutMs: NPM_VIEW_TIMEOUT_MS })\n const latestVersion = stdout.trim().length > 0 ? stdout.trim() : null\n this.checkCache = { latestVersion, checkedAtMs: this.now(), error: null }\n const updateAvailable =\n latestVersion !== null &&\n runningVersion !== null &&\n compareSemver(latestVersion, runningVersion) > 0\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion,\n updateAvailable,\n checkedAtMs: this.checkCache.checkedAtMs,\n error: null,\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.checkCache = {\n latestVersion: this.checkCache?.latestVersion ?? null,\n checkedAtMs: this.now(),\n error: message,\n }\n this.logger.warn('root package update check failed', { meta: { error: message } })\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion: this.checkCache.latestVersion,\n updateAvailable: false,\n checkedAtMs: this.checkCache.checkedAtMs,\n error: message,\n }\n } finally {\n this.inFlight = 'idle'\n }\n }\n\n // ── Apply ─────────────────────────────────────────────────────────────\n\n async applyServerUpdate(input: { version?: string }): Promise<ServerUpdateActionResult> {\n const bootMode = this.resolveBootMode()\n if (bootMode === 'workspace') {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message:\n 'Refused: running from a workspace checkout — the dev loop resolves code from the ' +\n 'workspace, a data-root update would never be loaded.',\n }\n }\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const stateBefore = this.readState()\n if (stateBefore.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message: `Refused: version ${stateBefore.pendingBoot.version} is already staged and awaiting restart.`,\n }\n }\n\n // Resolve the target version (explicit or latest from the registry).\n let target = input.version ?? null\n if (target === null) {\n const check = await this.checkServerUpdate()\n if (check.error !== null || check.latestVersion === null) {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: could not resolve the latest version (${check.error ?? 'no version returned'}).`,\n }\n }\n target = check.latestVersion\n }\n\n const runningVersion = this.runningVersion()\n if (target === runningVersion) {\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message: `Refused: ${this.spec.packageName}@${target} is already running.`,\n }\n }\n\n // Dev server-deploy channel boundary (phase 1: hub only). A `-dev.<epoch>`\n // version stages EXCLUSIVELY from tarballs previously uploaded to THIS\n // node's `server-root/dev-uploads/<version>/` — it never exists on the\n // npm registry, so a node without the uploads must fail loudly here\n // instead of timing out inside `npm install`.\n if (isDevChannelVersion(target)) {\n const uploadsDir = devUploadVersionDir(this.rootDir(), target)\n if (!fs.existsSync(uploadsDir)) {\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message:\n `Refused: dev-channel version ${target} has no uploaded tarballs on this node ` +\n `(${uploadsDir} is missing). Dev server deploys are hub-only in this phase — ` +\n `upload via \\`camstack deploy-server\\` against this node first.`,\n }\n }\n }\n\n this.inFlight = 'staging'\n try {\n await this.stageAndActivate(target)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.logger.error('root package update staging failed', {\n meta: { targetVersion: target, error: message },\n })\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message: `Staging failed: ${message}`,\n }\n } finally {\n this.inFlight = 'idle'\n }\n\n // Arm the probation boot + schedule the graceful restart.\n const state = this.readState()\n writeServerRootState(this.rootDir(), {\n ...state,\n pendingBoot: {\n version: target,\n fromVersion: state.currentVersion,\n requestedAtMs: this.now(),\n bootAttempts: 0,\n },\n rolledBack: null,\n })\n this.logger.info('root package update staged — restarting to apply', {\n meta: { targetVersion: target, fromVersion: state.currentVersion },\n })\n this.restartServerFn(`${RESTART_REASON_PREFIX}: ${this.spec.packageName}@${target}`)\n return {\n accepted: true,\n targetVersion: target,\n restarting: true,\n message: `Staged ${this.spec.packageName}@${target} — restarting to apply (probation boot with auto-rollback).`,\n }\n }\n\n /**\n * npm-install the target closure into a SAME-FS staging dir inside\n * `versions/`, validate it, then atomically rename it into place.\n */\n private async stageAndActivate(target: string): Promise<void> {\n const rootDir = this.rootDir()\n const vDir = versionsDir(rootDir)\n fs.mkdirSync(vDir, { recursive: true })\n const stagingDir = path.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`)\n fs.mkdirSync(stagingDir, { recursive: true })\n\n try {\n // Dev server-deploy channel: when tarballs for `target` were uploaded to\n // `server-root/dev-uploads/<target>/`, stage from THEM instead of the\n // registry — a synthetic package.json depends on the root tgz via\n // `file:` and pins every other uploaded package through `overrides`, so\n // ANY transitive occurrence resolves to the uploaded copy. External deps\n // still come from npmjs / CAMSTACK_NPM_REGISTRY. Everything downstream\n // (entry check, version check, activation, probation) is unchanged.\n const devDir = devUploadVersionDir(rootDir, target)\n const registry = this.env['CAMSTACK_NPM_REGISTRY']\n const installArgs = ['install', '--omit=dev', '--no-audit', '--no-fund', '--loglevel=error']\n if (fs.existsSync(devDir)) {\n fs.writeFileSync(\n path.join(stagingDir, 'package.json'),\n JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2),\n 'utf-8',\n )\n await this.execNpm([...installArgs, ...buildNpmRegistryArgs(registry)], {\n cwd: stagingDir,\n timeoutMs: NPM_INSTALL_TIMEOUT_MS,\n })\n } else {\n fs.writeFileSync(\n path.join(stagingDir, 'package.json'),\n JSON.stringify({ name: 'camstack-node-root', private: true }, null, 2),\n 'utf-8',\n )\n await this.execNpm(\n [...installArgs, `${this.spec.packageName}@${target}`, ...buildNpmRegistryArgs(registry)],\n { cwd: stagingDir, timeoutMs: NPM_INSTALL_TIMEOUT_MS },\n )\n }\n\n const entry = rootEntryPath(stagingDir, this.spec)\n if (!fs.existsSync(entry)) {\n throw new Error(`staged closure is missing the root entry (${entry})`)\n }\n const stagedVersion = readPackageVersion(\n path.join(rootPackageDir(stagingDir, this.spec), 'package.json'),\n )\n if (stagedVersion !== target) {\n throw new Error(\n `staged closure version mismatch: expected ${target}, got ${stagedVersion ?? 'unknown'}`,\n )\n }\n\n // Activate: evict any existing dir for this version, then atomic rename.\n const dest = versionDir(rootDir, target)\n if (fs.existsSync(dest)) {\n const aside = `${dest}.evicted-${this.now()}`\n await fs.promises.rename(dest, aside)\n await fs.promises.rm(aside, { recursive: true, force: true }).catch(() => undefined)\n }\n await fs.promises.rename(stagingDir, dest)\n } catch (err) {\n await fs.promises.rm(stagingDir, { recursive: true, force: true }).catch(() => undefined)\n throw err\n }\n }\n\n /**\n * Synthetic staging package.json for the dev server-deploy channel:\n * `dependencies` carries the root package as a `file:` ref to its uploaded\n * tgz; `overrides` maps EVERY OTHER uploaded `@camstack/<name>` to its tgz\n * so any transitive occurrence resolves to the uploaded copy, never npm.\n * Fail-closed: a missing/invalid manifest, a manifest for a different\n * version, a missing root package, or a listed-but-absent tgz all throw\n * (surfaced by `applyServerUpdate` as a staging failure).\n */\n private buildDevUploadsPackageJson(\n devDir: string,\n target: string,\n ): {\n readonly name: string\n readonly private: true\n readonly dependencies: Readonly<Record<string, string>>\n readonly overrides?: Readonly<Record<string, string>>\n } {\n const manifest = readDevUploadManifest(devDir)\n if (manifest === null) {\n throw new Error(`dev-uploads manifest missing or invalid in ${devDir}`)\n }\n if (manifest.version !== target) {\n throw new Error(\n `dev-uploads manifest version mismatch: dir is for ${target}, manifest says ${manifest.version}`,\n )\n }\n const rootTgz = manifest.packages[this.spec.packageName]\n if (rootTgz === undefined) {\n throw new Error(\n `dev-uploads for ${target} do not include the root package ${this.spec.packageName}`,\n )\n }\n const fileRef = (filename: string): string => {\n const abs = path.join(devDir, filename)\n if (!fs.existsSync(abs)) {\n throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`)\n }\n return `file:${abs}`\n }\n const overrides: Record<string, string> = {}\n for (const [pkgName, filename] of Object.entries(manifest.packages)) {\n if (pkgName === this.spec.packageName) continue\n overrides[pkgName] = fileRef(filename)\n }\n return {\n name: 'camstack-node-root',\n private: true,\n dependencies: { [this.spec.packageName]: fileRef(rootTgz) },\n ...(Object.keys(overrides).length > 0 ? { overrides } : {}),\n }\n }\n\n // ── Rollback ──────────────────────────────────────────────────────────\n\n async rollbackServerUpdate(): Promise<ServerUpdateActionResult> {\n // Same reentrancy/precondition guards as applyServerUpdate: without them a\n // rollback racing an armed update (10s restart grace) silently overwrites\n // pendingBoot — last write wins with no error to the loser.\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const state = this.readState()\n if (state.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: version ${state.pendingBoot.version} is already staged and awaiting restart.`,\n }\n }\n if (state.currentVersion === null || state.previousVersion === null) {\n return {\n accepted: false,\n targetVersion: state.previousVersion,\n restarting: false,\n message: 'Refused: no previous version available to roll back to.',\n }\n }\n const nodeMajor = Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n const invalidReason = validateVersionDir(\n this.rootDir(),\n state.previousVersion,\n nodeMajor,\n this.spec,\n )\n if (invalidReason !== null) {\n return {\n accepted: false,\n targetVersion: state.previousVersion,\n restarting: false,\n message: `Refused: previous version ${state.previousVersion} is not loadable (${invalidReason}).`,\n }\n }\n\n writeServerRootState(this.rootDir(), {\n ...state,\n pendingBoot: {\n version: state.previousVersion,\n fromVersion: state.currentVersion,\n requestedAtMs: this.now(),\n bootAttempts: 0,\n },\n })\n this.logger.info('root package rollback requested — restarting', {\n meta: { fromVersion: state.currentVersion, toVersion: state.previousVersion },\n })\n this.restartServerFn(\n `${RESTART_REASON_PREFIX}: rollback to ${this.spec.packageName}@${state.previousVersion}`,\n )\n return {\n accepted: true,\n targetVersion: state.previousVersion,\n restarting: true,\n message: `Rolling back to ${this.spec.packageName}@${state.previousVersion} — restarting.`,\n }\n }\n\n // ── Plain restart ─────────────────────────────────────────────────────\n\n /**\n * Plain process restart — no version change. Backs the `restartServer` cap\n * method. Guards mirror apply/rollback: refuse while a stage is in flight\n * (a concurrent npm install must not be interrupted) or while a version is\n * already staged awaiting restart (a naive bounce would boot the OLD version\n * and orphan the pending one — the operator should apply/rollback instead).\n */\n restartNode(): ServerUpdateActionResult {\n const runningVersion = this.runningVersion()\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: runningVersion,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const state = this.readState()\n if (state.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: runningVersion,\n restarting: false,\n message: `Refused: version ${state.pendingBoot.version} is staged and awaiting restart — apply or roll it back instead of a plain restart.`,\n }\n }\n this.logger.info('plain node restart requested', { meta: { runningVersion } })\n this.restartServerFn(`${RESTART_REASON_PREFIX}: manual restart`)\n return {\n accepted: true,\n targetVersion: runningVersion,\n restarting: true,\n message: 'Restarting the node — the supervisor relaunches it on the same version.',\n }\n }\n\n // ── Boot health confirmation ──────────────────────────────────────────\n\n /**\n * Called by the post-boot path once the node is READY (hub: post-boot\n * pipeline; agent: first acked `$hub.registerNode`). When THIS process is\n * the probation boot of a pending version, promote it: `currentVersion` ←\n * pending, `previousVersion` ← the version it replaced (N-1 retained for\n * rollback), clear `pendingBoot` + `rolledBack`, and prune every version\n * dir beyond {current, previous}. No-op otherwise.\n */\n confirmBootHealthy(): { promoted: string | null } {\n const state = readServerRootState(this.rootDir())\n if (state === null || state.pendingBoot === null) return { promoted: null }\n\n const activeVersion = this.env[this.envNames.activeVersion] ?? null\n if (activeVersion !== state.pendingBoot.version) {\n // We are NOT the probation boot of this pending version (e.g. the\n // starter never ran, or it booted a different closure). Leave the\n // marker for the starter's own rollback logic.\n return { promoted: null }\n }\n\n const promoted: ServerRootState = {\n ...state,\n currentVersion: state.pendingBoot.version,\n previousVersion: state.pendingBoot.fromVersion,\n pendingBoot: null,\n rolledBack: null,\n }\n writeServerRootState(this.rootDir(), promoted)\n this.pruneVersions(\n [promoted.currentVersion, promoted.previousVersion].filter(\n (v): v is string => typeof v === 'string',\n ),\n )\n this.sweepDevUploads(DEV_UPLOADS_KEEP_COUNT)\n this.logger.info('root package update confirmed healthy', {\n meta: {\n version: promoted.currentVersion,\n previousVersion: promoted.previousVersion,\n },\n })\n return { promoted: promoted.currentVersion }\n }\n\n /**\n * Remove version dirs under `versions/` not in `keep`.\n *\n * Transient dot-entries (`.staging-*` / `.evicted-*`) are NOT pruned unless\n * older than {@link RootUpdateService.STALE_TRANSIENT_MS}: the API starts\n * serving BEFORE the post-boot `confirmBootHealthy()` runs, so a concurrent\n * `applyServerUpdate` can be mid-npm-install into a fresh `.staging-*` dir\n * when this prune fires — deleting it would corrupt that install. Fresh\n * transient dirs are owned by their in-flight operation (which cleans up on\n * failure); the staleness sweep only collects dirs orphaned by a crash.\n */\n private pruneVersions(keep: readonly string[]): void {\n const vDir = versionsDir(this.rootDir())\n let entries: string[]\n try {\n entries = fs.readdirSync(vDir)\n } catch {\n return\n }\n for (const entry of entries) {\n if (keep.includes(entry)) continue\n const full = path.join(vDir, entry)\n if (entry.startsWith('.')) {\n try {\n const ageMs = this.now() - fs.statSync(full).mtimeMs\n if (ageMs < RootUpdateService.STALE_TRANSIENT_MS) continue\n } catch {\n // stat failed (already gone / unreadable) — skip it\n continue\n }\n }\n try {\n fs.rmSync(full, { recursive: true, force: true })\n this.logger.debug('pruned server-root version dir', { meta: { entry } })\n } catch (err) {\n this.logger.warn('failed to prune server-root version dir', {\n meta: { entry, error: err instanceof Error ? err.message : String(err) },\n })\n }\n }\n }\n\n /**\n * Promote-time sweep of `server-root/dev-uploads/`: keep only the\n * `keepCount` most recent entries (ordered by the self-describing\n * `-dev.<epochSeconds>` suffix; non-dev-shaped residue counts as oldest).\n * Uses the same rename-aside graveyard pattern as the addon installer —\n * a rename is a metadata op that succeeds even when a tarball is held\n * open, and residue in the graveyard is re-swept on the next promote.\n */\n private sweepDevUploads(keepCount: number): void {\n const dir = devUploadsDir(this.rootDir())\n let entries: string[]\n try {\n entries = fs.readdirSync(dir)\n } catch {\n return // no dev-uploads dir — nothing to sweep\n }\n const graveyard = path.join(dir, '.sweeping')\n // Best-effort collect residue left behind by an earlier sweep first.\n try {\n for (const residue of fs.readdirSync(graveyard)) {\n try {\n fs.rmSync(path.join(graveyard, residue), { recursive: true, force: true })\n } catch {\n /* still held open — retried on the next promote */\n }\n }\n } catch {\n /* graveyard absent — nothing to collect */\n }\n\n const versions = entries.filter((name) => !name.startsWith('.'))\n const byNewestFirst = [...versions].sort(\n (a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1),\n )\n const doomed = byNewestFirst.slice(keepCount)\n if (doomed.length === 0) return\n fs.mkdirSync(graveyard, { recursive: true })\n for (const entry of doomed) {\n const aside = path.join(graveyard, `${entry}-${this.now()}`)\n try {\n fs.renameSync(path.join(dir, entry), aside)\n } catch (err) {\n this.logger.warn('failed to move dev-uploads entry aside for sweep', {\n meta: { entry, error: err instanceof Error ? err.message : String(err) },\n })\n continue\n }\n try {\n fs.rmSync(aside, { recursive: true, force: true })\n this.logger.debug('swept dev-uploads entry', { meta: { entry } })\n } catch {\n /* held open — the aside copy is collected on the next promote */\n }\n }\n }\n\n /** Transient (.staging- / .evicted-) dirs younger than this are never pruned. */\n private static readonly STALE_TRANSIENT_MS = 24 * 60 * 60 * 1000\n}\n","/**\n * AGENT STARTER — the tiny, immutable, dependency-free entry baked into the\n * agent image (and, in phase 3, spawned by the Electron shell). Everything\n * above it (the agent CLI, framework, addons) is runtime-updatable; the\n * starter itself can NEVER self-update — a new image is the only way to\n * change it, which is why it must stay deliberately dumb.\n *\n * The boot flow is the SHARED node-root core (`runNodeStarter`, bundled into\n * this file by tsup — see tsup.config.ts): workspace defer → durable boot\n * plan (probation counter / auto-rollback / validity fallback) → the\n * host-external resolver hooks anchored in the active root → load the chosen\n * closure. This file only binds the agent's names: `@camstack/agent`,\n * `dist/cli.js`, the `CAMSTACK_AGENT_*` env markers and the\n * `CAMSTACK_DATA_DIR` / `--data` data dir.\n *\n * Layout mirror of the hub:\n * <agentDataDir>/server-root/versions/<semver>/node_modules/@camstack/agent/dist/cli.js\n * <agentDataDir>/server-root/state.json\n *\n * Console usage is intentional: the starter runs before any logging exists.\n */\nimport { existsSync } from 'node:fs'\nimport * as path from 'node:path'\nimport { AGENT_ROOT_SPEC, runNodeStarter } from '@camstack/node-root'\n\n/**\n * Resolve the agent data dir the way the CLI will (`CAMSTACK_DATA_DIR` env\n * wins, then `--data`/`-d` argv, then `./camstack-data`). The starter runs\n * BEFORE the CLI parses argv, so it mirrors the flag inline — otherwise an\n * operator running `camstack-agent --data /x` would get the server-root in a\n * different data dir than the agent itself.\n */\nfunction resolveAgentDataDir(argv: readonly string[], env: NodeJS.ProcessEnv): string {\n const fromEnv = env['CAMSTACK_DATA_DIR']\n if (fromEnv !== undefined && fromEnv.length > 0) return path.resolve(fromEnv)\n for (let i = 2; i < argv.length - 1; i++) {\n if (argv[i] === '--data' || argv[i] === '-d') {\n const next = argv[i + 1]\n if (next !== undefined && !next.startsWith('-')) return path.resolve(next)\n }\n }\n return path.resolve('camstack-data')\n}\n\n/**\n * Restart-policy dependency warning (security review #3). `server-management`\n * apply/rollback = graceful exit + supervisor relaunch. Without an\n * always-relaunching restart policy (docker: `unless-stopped`/`always`) a node\n * that exits to apply an update simply STAYS DOWN. No code can enforce the\n * policy — make the dependency visible at boot. Diagnostic only.\n */\nfunction warnRestartPolicyDependency(): void {\n if (!existsSync('/.dockerenv')) return\n console.warn(\n '[starter] container detected — server-management apply/rollback exit this ' +\n 'process for the supervisor to relaunch. Ensure the container restart policy is ' +\n \"'unless-stopped' or 'always', otherwise an update/rollback leaves the node down.\",\n )\n}\n\nfunction start(): void {\n warnRestartPolicyDependency()\n\n const seedPackageDir = path.resolve(__dirname, '..')\n if (process.env['CAMSTACK_SEED_AGENT_DIR'] === undefined) {\n process.env['CAMSTACK_SEED_AGENT_DIR'] = seedPackageDir\n }\n\n runNodeStarter({\n spec: AGENT_ROOT_SPEC,\n envNames: {\n bootMode: 'CAMSTACK_AGENT_BOOT_MODE',\n activeRoot: 'CAMSTACK_AGENT_ACTIVE_ROOT',\n activeVersion: 'CAMSTACK_AGENT_ACTIVE_VERSION',\n killSwitch: 'CAMSTACK_AGENT_ROOT',\n },\n dataDir: resolveAgentDataDir(process.argv, process.env),\n seedEntry: path.join(__dirname, 'cli.js'),\n starterDir: __dirname,\n // The CLI is CJS (tsup build) — a plain require keeps the starter\n // synchronous; the CLI reads the SAME process.argv it always did.\n loadEntry: (entryPath) => require(entryPath),\n })\n}\n\ntry {\n start()\n} catch (err) {\n console.error('[starter] FATAL:', err)\n process.exit(1)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,QAAA,cAAA,CAAA;AAAA,aAAA,aAAA;MAAA,iBAAA,MAAAA;MAAA,qBAAA,MAAA;MAAA,wBAAA,MAAA;MAAA,0BAAA,MAAA;MAAA,0BAAA,MAAA;MAAA,eAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,mBAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,wBAAA,MAAA;MAAA,0BAAA,MAAA;MAAA,eAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,iBAAA,MAAA;MAAA,uBAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,eAAA,MAAA;MAAA,sBAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,gBAAA,MAAA;MAAA,mBAAA,MAAA;MAAA,gBAAA,MAAA;MAAA,UAAA,MAAA;MAAA,uBAAA,MAAA;MAAA,yBAAA,MAAA;MAAA,qBAAA,MAAA;MAAA,4BAAA,MAAA;MAAA,yBAAA,MAAA;MAAA,eAAA,MAAA;MAAA,gBAAA,MAAA;MAAA,gBAAA,MAAAC;MAAA,eAAA,MAAA;MAAA,eAAA,MAAA;MAAA,oBAAA,MAAA;MAAA,YAAA,MAAA;MAAA,aAAA,MAAA;MAAA,wBAAA,MAAA;MAAA,0BAAA,MAAA;MAAA,sBAAA,MAAA;IAAA,CAAA;AAAA,IAAAC,QAAA,UAAA,aAAA,WAAA;ACsBA,QAAA,KAAoBC,SAAA,QAAA,IAAA,CAAA;AACpB,QAAAC,QAAsBD,SAAA,QAAA,MAAA,CAAA;AAEf,QAAM,sBAAsB;AAC5B,QAAM,2BAA2B;AAGjC,QAAM,yBAAyB;AAOtC,QAAM,yBAAyB;AAExB,aAAS,oBAAoB,SAA0B;AAC5D,aAAO,uBAAuB,KAAK,OAAO;IAC5C;AAOO,aAAS,gBAAgB,SAAgC;AAC9D,YAAM,QAAQ,eAAe,KAAK,OAAO;AACzC,UAAI,UAAU,KAAM,QAAO;AAC3B,YAAM,QAAQ,OAAO,SAAS,MAAM,CAAC,KAAK,IAAI,EAAE;AAChD,aAAO,OAAO,MAAM,KAAK,IAAI,OAAO;IACtC;AAGO,aAAS,cAAc,SAAyB;AACrD,aAAYC,MAAA,KAAK,SAAS,mBAAmB;IAC/C;AAGO,aAAS,oBAAoB,SAAiB,SAAyB;AAC5E,aAAYA,MAAA,KAAK,cAAc,OAAO,GAAG,OAAO;IAClD;AAiBO,aAAS,sBAAsB,gBAAgC;AACpE,aAAYA,MAAA,KAAK,gBAAgB,wBAAwB;IAC3D;AAEA,aAAS,oBAAoB,GAAoC;AAC/D,UAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,YAAM,IAAI;AACV,UAAI,OAAO,EAAE,SAAS,MAAM,SAAU,QAAO;AAC7C,YAAM,WAAW,EAAE,UAAU;AAC7B,UAAI,OAAO,aAAa,YAAY,aAAa,QAAQ,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACzF,aAAO,OAAO,OAAO,QAAQ,EAAE,MAAM,CAAC,aAAa,OAAO,aAAa,QAAQ;IACjF;AAGO,aAAS,sBAAsB,gBAAkD;AACtF,UAAI;AACF,cAAM,MAAe,KAAK,MAAS,GAAA,aAAa,sBAAsB,cAAc,GAAG,OAAO,CAAC;AAC/F,eAAO,oBAAoB,GAAG,IAAI,MAAM;MAC1C,QAAQ;AACN,eAAO;MACT;IACF;AAGO,aAAS,uBAAuB,gBAAwB,UAAmC;AAC7F,SAAA,UAAU,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAChD,YAAM,SAAS,sBAAsB,cAAc;AACnD,YAAM,MAAM,GAAG,MAAM;AAClB,SAAA,cAAc,KAAK,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAC7D,SAAA,WAAW,KAAK,MAAM;IAC3B;ACxFO,QAAM,gBAAiC;MAC5C,aAAa;MACb,cAAc,CAAC,QAAQ,aAAa;IACtC;AAGO,QAAMJ,mBAAmC;MAC9C,aAAa;MACb,cAAc,CAAC,QAAQ,QAAQ;IACjC;ACRA,QAAAK,MAAoBF,SAAA,QAAA,IAAA,CAAA;AACpB,QAAAC,SAAsBD,SAAA,QAAA,MAAA,CAAA;AAGf,QAAM,sBAAsB;AAC5B,QAAM,yBAAyB;AAW/B,QAAM,sBAAsB;AAmC5B,aAAS,uBAAwC;AACtD,aAAO;QACL,eAAe;QACf,gBAAgB;QAChB,iBAAiB;QACjB,aAAa;QACb,YAAY;MACd;IACF;AAMO,aAAS,cAAc,SAAyB;AACrD,aAAYG,OAAA,KAAK,SAAS,mBAAmB;IAC/C;AAEO,aAAS,YAAY,SAAyB;AACnD,aAAYA,OAAA,KAAK,SAAS,UAAU;IACtC;AAEO,aAAS,WAAW,SAAiB,SAAyB;AACnE,aAAYA,OAAA,KAAK,YAAY,OAAO,GAAG,OAAO;IAChD;AAGO,aAAS,eAAe,gBAAwB,MAA+B;AACpF,aAAYA,OAAA,KAAK,gBAAgB,gBAAgB,GAAG,KAAK,YAAY,MAAM,GAAG,CAAC;IACjF;AAGO,aAAS,cAAc,gBAAwB,MAA+B;AACnF,aAAYA,OAAA,KAAK,eAAe,gBAAgB,IAAI,GAAG,GAAG,KAAK,YAAY;IAC7E;AAEO,aAAS,cAAc,SAAyB;AACrD,aAAYA,OAAA,KAAK,SAAS,sBAAsB;IAClD;AAMA,aAAS,iBAAiB,GAAgC;AACxD,aAAO,MAAM,QAAQ,OAAO,MAAM;IACpC;AAEA,aAAS,cAAc,GAAwC;AAC7D,UAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,YAAM,IAAI;AACV,aACE,OAAO,EAAE,SAAS,MAAM,YACxB,iBAAiB,EAAE,aAAa,CAAC,KACjC,OAAO,EAAE,eAAe,MAAM,YAC9B,OAAO,EAAE,cAAc,MAAM;IAEjC;AAEA,aAAS,eAAe,GAAyC;AAC/D,UAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,YAAM,IAAI;AACV,aACE,OAAO,EAAE,aAAa,MAAM,YAC5B,iBAAiB,EAAE,WAAW,CAAC,KAC/B,OAAO,EAAE,MAAM,MAAM,YACrB,OAAO,EAAE,QAAQ,MAAM;IAE3B;AAEO,aAAS,kBAAkB,GAAkC;AAClE,UAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,YAAM,IAAI;AACV,UAAI,EAAE,eAAe,MAAM,EAAG,QAAO;AACrC,UAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,EAAG,QAAO;AACnD,UAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,EAAG,QAAO;AACpD,UAAI,EAAE,aAAa,MAAM,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC,EAAG,QAAO;AAC1E,UAAI,EAAE,YAAY,MAAM,QAAQ,CAAC,eAAe,EAAE,YAAY,CAAC,EAAG,QAAO;AACzE,aAAO;IACT;AAGO,aAAS,oBAAoB,SAAyC;AAC3E,UAAI;AACF,cAAM,MAAe,KAAK,MAAS,IAAA,aAAa,cAAc,OAAO,GAAG,OAAO,CAAC;AAChF,eAAO,kBAAkB,GAAG,IAAI,MAAM;MACxC,QAAQ;AACN,eAAO;MACT;IACF;AAGO,aAAS,qBAAqB,SAAiB,OAA8B;AAC/E,UAAA,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACzC,YAAM,SAAS,cAAc,OAAO;AACpC,YAAM,MAAM,GAAG,MAAM;AAClB,UAAA,cAAc,KAAK,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAC1D,UAAA,WAAW,KAAK,MAAM;IAC3B;AAiBO,aAAS,wBAAwB,SAAyB;AAC/D,aAAYA,OAAA,KAAK,SAAS,mBAAmB;IAC/C;AAEA,aAAS,sBAAsB,GAAsC;AACnE,UAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,YAAM,IAAI;AACV,aAAO,OAAO,EAAE,eAAe,MAAM,YAAY,OAAO,EAAE,QAAQ,MAAM;IAC1E;AAGO,aAAS,yBAAyB,SAAiB,QAAmC;AACxF,UAAA,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACzC,YAAM,SAAS,wBAAwB,OAAO;AAC9C,YAAM,MAAM,GAAG,MAAM;AAClB,UAAA,cAAc,KAAK,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAC3D,UAAA,WAAW,KAAK,MAAM;IAC3B;AAGO,aAAS,wBAAwB,SAA6C;AACnF,UAAI;AACF,cAAM,MAAe,KAAK,MAAS,IAAA,aAAa,wBAAwB,OAAO,GAAG,OAAO,CAAC;AAC1F,eAAO,sBAAsB,GAAG,IAAI,MAAM;MAC5C,QAAQ;AACN,eAAO;MACT;IACF;AAGO,aAAS,yBAAyB,SAAuB;AAC9D,UAAI;AACC,YAAA,OAAO,wBAAwB,OAAO,GAAG,EAAE,OAAO,KAAK,CAAC;MAC7D,QAAQ;MAER;IACF;AAWO,aAAS,eAAe,aAAoC;AACjE,YAAM,QAAQ,QAAQ,KAAK,WAAW;AACtC,UAAI,UAAU,KAAM,QAAO;AAC3B,YAAM,QAAQ,OAAO,SAAS,MAAM,CAAC,KAAK,IAAI,EAAE;AAChD,aAAO,OAAO,MAAM,KAAK,IAAI,OAAO;IACtC;AAWO,aAAS,mBACd,SACA,SACA,WACA,MACe;AACf,YAAM,OAAO,WAAW,SAAS,OAAO;AACxC,YAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,UAAI,CAAI,IAAA,WAAW,KAAK,GAAG;AACzB,eAAO,uBAAuB,KAAK;MACrC;AAEA,YAAM,cAAmBA,OAAA,KAAK,eAAe,MAAM,IAAI,GAAG,cAAc;AACxE,UAAI;AACJ,UAAI;AACF,cAAM,MAAe,KAAK,MAAS,IAAA,aAAa,aAAa,OAAO,CAAC;AACrE,YAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,GAAG,GAAG;AACjE,iBAAO,2BAA2B,WAAW;QAC/C;AACA,cAAM;MACR,QAAQ;AACN,eAAO,4BAA4B,WAAW;MAChD;AAEA,UAAI,IAAI,MAAM,MAAM,KAAK,aAAa;AACpC,eAAO,mCAAmC,KAAK,WAAW,SAAS,OAAO,IAAI,MAAM,CAAC,CAAC;MACxF;AACA,UAAI,IAAI,SAAS,MAAM,SAAS;AAC9B,eAAO,sCAAsC,OAAO,uBAAuB,OAAO,IAAI,SAAS,CAAC,CAAC;MACnG;AAEA,YAAM,UAAU,IAAI,SAAS;AAC7B,UAAI,OAAO,YAAY,YAAY,YAAY,MAAM;AACnD,cAAM,cAAe,QAAoC,MAAM;AAC/D,YAAI,OAAO,gBAAgB,UAAU;AACnC,gBAAM,WAAW,eAAe,WAAW;AAC3C,cAAI,aAAa,QAAQ,YAAY,UAAU;AAC7C,mBAAO,iBAAiB,WAAW,sBAAsB,QAAQ,gBAAgB,SAAS;UAC5F;QACF;MACF;AAEA,aAAO;IACT;AC7PO,aAAS,SACd,OACA,gBACA,KACU;AACV,UAAI,UAAU,MAAM;AAClB,eAAO,EAAE,MAAM,SAAS,QAAQ,wBAAwB,cAAc,KAAK;MAC7E;AAEA,UAAI,OAAwB;AAC5B,UAAI,UAAU;AAGd,UAAI,KAAK,gBAAgB,MAAM;AAC7B,cAAM,UAAU,KAAK;AACrB,YAAI,QAAQ,gBAAgB,GAAG;AAE7B,iBAAO;YACL,GAAG;YACH,aAAa;YACb,YAAY;cACV,aAAa,QAAQ;cACrB,WAAW,KAAK;cAChB,MAAM,IAAI;cACV,QAAQ;YACV;UACF;AACA,oBAAU;QACZ,WAAW,CAAC,eAAe,QAAQ,OAAO,GAAG;AAC3C,iBAAO;YACL,GAAG;YACH,aAAa;YACb,YAAY;cACV,aAAa,QAAQ;cACrB,WAAW,KAAK;cAChB,MAAM,IAAI;cACV,QAAQ;YACV;UACF;AACA,oBAAU;QACZ,OAAO;AAGL,iBAAO;YACL,MAAM;YACN,SAAS,QAAQ;YACjB,WAAW;YACX,cAAc;cACZ,GAAG;cACH,aAAa,EAAE,GAAG,SAAS,cAAc,QAAQ,eAAe,EAAE;YACpE;UACF;QACF;MACF;AAGA,UAAI,KAAK,mBAAmB,MAAM;AAChC,YAAI,eAAe,KAAK,cAAc,GAAG;AACvC,iBAAO;YACL,MAAM;YACN,SAAS,KAAK;YACd,WAAW;YACX,cAAc,UAAU,OAAO;UACjC;QACF;AAGA,cAAM,SAAS,KAAK;AACpB,YAAI,KAAK,oBAAoB,QAAQ,eAAe,KAAK,eAAe,GAAG;AACzE,gBAAM,WAAW,KAAK;AACtB,iBAAO;YACL,MAAM;YACN,SAAS;YACT,WAAW;YACX,cAAc;cACZ,GAAG;cACH,gBAAgB;cAChB,iBAAiB;cACjB,YAAY;gBACV,aAAa;gBACb,WAAW;gBACX,MAAM,IAAI;gBACV,QAAQ;cACV;YACF;UACF;QACF;AAEA,eAAO;UACL,MAAM;UACN,QAAQ,kBAAkB,MAAM;UAChC,cAAc;YACZ,GAAG;YACH,gBAAgB;YAChB,YAAY;cACV,aAAa;cACb,WAAW;cACX,MAAM,IAAI;cACV,QAAQ;YACV;UACF;QACF;MACF;AAEA,aAAO;QACL,MAAM;QACN,QAAQ;QACR,cAAc,UAAU,OAAO;MACjC;IACF;ACzIA,aAAS,MAAM,SAA8B;AAC3C,YAAM,UAAU,QAAQ,QAAQ,GAAG;AACnC,YAAM,OAAO,YAAY,KAAK,UAAU,QAAQ,MAAM,GAAG,OAAO;AAChE,YAAM,aAAa,YAAY,KAAK,OAAO,QAAQ,MAAM,UAAU,CAAC;AACpE,YAAM,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,QAAQ;AACxC,cAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,eAAO,OAAO,MAAM,CAAC,IAAI,IAAI;MAC/B,CAAC;AACD,aAAO,EAAE,MAAM,WAAW;IAC5B;AAGO,aAAS,cAAc,GAAW,GAAuB;AAC9D,YAAM,KAAK,MAAM,CAAC;AAClB,YAAM,KAAK,MAAM,CAAC;AAClB,YAAM,MAAM,KAAK,IAAI,GAAG,KAAK,QAAQ,GAAG,KAAK,MAAM;AACnD,eAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,cAAM,KAAK,GAAG,KAAK,CAAC,KAAK;AACzB,cAAM,KAAK,GAAG,KAAK,CAAC,KAAK;AACzB,YAAI,KAAK,GAAI,QAAO;AACpB,YAAI,KAAK,GAAI,QAAO;MACtB;AACA,UAAI,GAAG,eAAe,QAAQ,GAAG,eAAe,KAAM,QAAO;AAC7D,UAAI,GAAG,eAAe,KAAM,QAAO;AACnC,UAAI,GAAG,eAAe,KAAM,QAAO;AACnC,UAAI,GAAG,aAAa,GAAG,WAAY,QAAO;AAC1C,UAAI,GAAG,aAAa,GAAG,WAAY,QAAO;AAC1C,aAAO;IACT;AC/BA,QAAAD,MAAoBF,SAAA,QAAA,IAAA,CAAA;AACpB,QAAAC,QAAsBD,SAAA,QAAA,MAAA,CAAA;AAMf,aAAS,oBAAoB,SAAgC;AAClE,UAAI,MAAW,MAAA,QAAQ,OAAO;AAC9B,iBAAS;AACP,cAAM,UAAe,MAAA,KAAK,KAAK,cAAc;AAC7C,YAAI;AACF,gBAAM,MAAe,KAAK,MAAS,IAAA,aAAa,SAAS,OAAO,CAAC;AACjE,cACE,OAAO,QAAQ,YACf,QAAQ,QACP,IAAgC,YAAY,MAAM,QACnD;AACA,mBAAO;UACT;QACF,QAAQ;QAER;AACA,cAAM,SAAc,MAAA,QAAQ,GAAG;AAC/B,YAAI,WAAW,IAAK,QAAO;AAC3B,cAAM;MACR;IACF;ACjBA,QAAAC,QAAsBD,SAAA,QAAA,MAAA,CAAA;AACtB,QAAA,kBAA8B,QAAA,KAAA;AAmBvB,QAAM,2BAA8C;MACzD;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;IACF;AAEO,aAAS,eAAe,WAA4B;AACzD,aAAO,yBAAyB;QAC9B,CAAC,SAAS,cAAc,QAAQ,UAAU,WAAW,GAAG,IAAI,GAAG;MACjE;IACF;AAeO,aAAS,2BAA2B,eAA6B;AAGtE,YAAM,YAAqC,QAAQ,QAAa;AAChE,YAAM,gBAAgB,UAAU,eAAe;AAC/C,UAAI,OAAO,kBAAkB,YAAY;AACvC,gBAAQ;UACN;QACF;AACA;MACF;AACA,YAAM,aAAA,GAAY,gBAAA;QACX,MAAA,KAAK,eAAe,gBAAgB,gCAAgC;MAC3E,EAAE;AACF,YAAM,QAAwC;QAC5C,SAAS,CAAC,WAAW,SAAS,gBAAgB;AAC5C,cAAI,eAAe,SAAS,GAAG;AAC7B,gBAAI;AACF,qBAAO,YAAY,WAAW,EAAE,GAAG,SAAS,WAAW,UAAU,CAAC;YACpE,QAAQ;YAER;UACF;AACA,iBAAO,YAAY,WAAW,OAAO;QACvC;MACF;AACE,oBAAkC,KAAK;IAC3C;AAqCO,aAASF,gBAAe,SAAmC;AAChE,YAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,YAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,YAAM,mBAAmB,QAAQ,oBAAoB;AAGrD,YAAM,WAAW,IAAI,QAAQ,SAAS,UAAU,MAAM;AACtD,YAAM,gBAAgB,oBAAoB,QAAQ,UAAU;AAC5D,UAAI,kBAAkB,MAAM;AAC1B,gBAAQ;UACN,4CAA4C,aAAa;QAC3D;AACA,YAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,gBAAQ,UAAU,QAAQ,SAAS;AACnC;MACF;AACA,UAAI,UAAU;AACZ,gBAAQ,IAAI,aAAa,QAAQ,SAAS,UAAU,4CAAuC;AAC3F,YAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,gBAAQ,UAAU,QAAQ,SAAS;AACnC;MACF;AAGA,YAAM,UAAU,cAAc,QAAQ,OAAO;AAC7C,YAAM,QAAQ,oBAAoB,OAAO;AACzC,YAAM,YACJ,QAAQ,aAAa,OAAO,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACrF,YAAM,iBAAiB,CAAC,YAA6B;AACnD,cAAM,SAAS,mBAAmB,SAAS,SAAS,WAAW,QAAQ,IAAI;AAC3E,YAAI,WAAW,KAAM,SAAQ,KAAK,qBAAqB,OAAO,aAAa,MAAM,EAAE;AACnF,eAAO,WAAW;MACpB;AAEA,YAAM,OAAO,SAAS,OAAO,gBAAgB,GAAG;AAChD,UAAI,KAAK,iBAAiB,MAAM;AAC9B,YAAI;AACF,+BAAqB,SAAS,KAAK,YAAY;QACjD,SAAS,KAAK;AAIZ,kBAAQ,MAAM,4EAAuE,GAAG;AACxF,cAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,kBAAQ,UAAU,QAAQ,SAAS;AACnC;QACF;AACA,YACE,KAAK,aAAa,eAAe,SAChC,OAAO,cAAc,UAAU,KAAK,aAAa,YAClD;AACA,gBAAM,KAAK,KAAK,aAAa;AAC7B,kBAAQ;YACN,yBAAyB,GAAG,WAAW,OAAO,GAAG,aAAa,YAAY,KAAK,GAAG,MAAM;UAC1F;QACF;MACF;AAGA,UAAI,KAAK,SAAS,aAAa;AAC7B,cAAM,gBAAgB,WAAW,SAAS,KAAK,OAAO;AACtD,cAAM,QAAQ,cAAc,eAAe,QAAQ,IAAI;AACvD,gBAAQ;UACN,qBAAqB,QAAQ,KAAK,WAAW,IAAI,KAAK,OAAO,SAAS,aAAa,MAChF,KAAK,YAAY,gDAA2C;QACjE;AACA,YAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,YAAI,QAAQ,SAAS,UAAU,IAAI;AACnC,YAAI,QAAQ,SAAS,aAAa,IAAI,KAAK;AAC3C,yBAAiB,aAAa;AAC9B,gBAAQ,UAAU,KAAK;AACvB;MACF;AAEA,cAAQ,IAAI,yCAAyC,KAAK,MAAM,GAAG;AACnE,UAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,cAAQ,UAAU,QAAQ,SAAS;IACrC;AC3LA,QAAA,4BAAyB,QAAA,eAAA;AACzB,QAAAI,MAAoBF,SAAA,QAAA,IAAA,CAAA;AACpB,QAAAC,QAAsBD,SAAA,QAAA,MAAA,CAAA;AACtB,QAAA,mBAA0B,QAAA,MAAA;AAiC1B,QAAM,iBAAA,GAAgB,iBAAA,WAAU,0BAAA,QAAQ;AAGxC,aAAS,qBAAqB,UAAiD;AAC7E,UAAI,aAAa,UAAa,SAAS,WAAW,EAAG,QAAO,CAAC;AAC7D,aAAO,CAAC,cAAc,UAAU,wBAAwB,QAAQ,EAAE;IACpE;AAoDA,QAAM,sBAAsB;AAC5B,QAAM,yBAAyB,KAAK;AACpC,QAAM,wBAAwB;AAE9B,aAAS,mBAAmB,aAAoC;AAC9D,UAAI;AACF,cAAM,MAAe,KAAK,MAAS,IAAA,aAAa,aAAa,OAAO,CAAC;AACrE,YAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,gBAAM,UAAW,IAAgC,SAAS;AAC1D,cAAI,OAAO,YAAY,SAAU,QAAO;QAC1C;MACF,QAAQ;MAER;AACA,aAAO;IACT;AAEO,QAAM,oBAAN,MAAM,mBAAkB;MACZ;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MAET,aAAgC;MAChC,WAA4C;MAEpD,YAAY,SAAmC;AAC7C,aAAK,OAAO,QAAQ;AACpB,aAAK,WAAW,QAAQ;AACxB,aAAK,SAAS,QAAQ;AACtB,aAAK,kBAAkB,QAAQ;AAC/B,aAAK,UAAe,MAAA,QAAQ,QAAQ,OAAO;AAC3C,aAAK,UACH,QAAQ,YACP,OAAO,MAAM,SAAS;AACrB,gBAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,CAAC,GAAG,IAAI,GAAG;YACvD,KAAK,KAAK;YACV,SAAS,KAAK;UAChB,CAAC;AACD,iBAAO,EAAE,OAAO;QAClB;AACF,aAAK,MAAM,QAAQ,OAAO,QAAQ;AAClC,aAAK,MAAM,QAAQ,OAAO,KAAK;AAC/B,aAAK,yBAAyB,QAAQ;AACtC,aAAK,oBAAoB,QAAQ;MACnC;;MAIA,kBAAkC;AAChC,cAAM,MAAM,KAAK,IAAI,KAAK,SAAS,QAAQ;AAC3C,YAAI,QAAQ,eAAe,QAAQ,WAAW,QAAQ,YAAa,QAAO;AAG1E,eAAO,oBAAoB,KAAK,iBAAiB,MAAM,OAAO,cAAc;MAC9E;MAEQ,iBAAgC;AACtC,eAAO,mBAAmB,KAAK,sBAAsB;MACvD;;MAGA,wBAAoF;AAClF,eAAO,EAAE,MAAM,KAAK,KAAK,aAAa,SAAS,KAAK,eAAe,EAAE;MACvE;MAEQ,cAA6B;AACnC,cAAM,UAAU,KAAK,IAAI,KAAK,SAAS,OAAO;AAC9C,YAAI,YAAY,UAAa,QAAQ,WAAW,EAAG,QAAO;AAC1D,eAAO,mBAAwB,MAAA,KAAK,SAAS,cAAc,CAAC;MAC9D;MAEQ,UAAkB;AACxB,eAAO,cAAc,KAAK,OAAO;MACnC;MAEQ,YAA6B;AACnC,eAAO,oBAAoB,KAAK,QAAQ,CAAC,KAAK,qBAAqB;MACrE;;;;;;;MAQQ,gBAA8D;AACpE,cAAM,UAAU,KAAK,QAAQ;AAC7B,cAAM,MAAM,oBAAoB,OAAO;AACvC,YAAI,QAAQ,KAAM,QAAO,EAAE,OAAO,KAAK,SAAS,MAAM;AACtD,eAAO,EAAE,OAAO,qBAAqB,GAAG,SAAY,IAAA,WAAW,cAAc,OAAO,CAAC,EAAE;MACzF;MAEQ,YAAY,OAA2C;AAC7D,YAAI,KAAK,aAAa,WAAY,QAAO;AACzC,YAAI,KAAK,aAAa,UAAW,QAAO;AACxC,YAAI,MAAM,gBAAgB,MAAM;AAO9B,gBAAM,gBAAgB,KAAK,IAAI,KAAK,SAAS,aAAa,KAAK;AAC/D,cAAI,kBAAkB,QAAQ,kBAAkB,MAAM,YAAY,SAAS;AACzE,mBAAO;UACT;AACA,iBAAO;QACT;AACA,eAAO;MACT;MAEA,MAAM,yBAAuD;AAC3D,cAAM,EAAE,OAAO,QAAQ,IAAI,KAAK,cAAc;AAC9C,cAAM,iBAAiB,KAAK,eAAe;AAC3C,cAAM,gBAAgB,KAAK,YAAY,iBAAiB;AACxD,cAAM,kBACJ,kBAAkB,QAClB,mBAAmB,QACnB,cAAc,eAAe,cAAc,IAAI;AACjD,eAAO;UACL,aAAa,KAAK,KAAK;UACvB;UACA,oBAAoB,QAAQ,SAAS;UACrC,eAAe,KAAK,IAAI,KAAK,SAAS,aAAa,KAAK,MAAM;UAC9D,iBAAiB,MAAM;UACvB,aAAa,KAAK,YAAY;UAC9B;UACA;UACA,UAAU,KAAK,gBAAgB;UAC/B,aAAa,KAAK,YAAY,KAAK;UACnC,gBAAgB,MAAM,aAAa,WAAW;UAC9C,YAAY,MAAM;UAClB,kBAAkB;UAClB,iBAAiB,KAAK,YAAY,eAAe;QACnD;MACF;;MAIA,MAAM,oBAAsD;AAC1D,cAAM,iBAAiB,KAAK,eAAe;AAC3C,YAAI,KAAK,aAAa,QAAQ;AAC5B,iBAAO;YACL,aAAa,KAAK,KAAK;YACvB;YACA,eAAe,KAAK,YAAY,iBAAiB;YACjD,iBAAiB;YACjB,aAAa,KAAK,YAAY,eAAe,KAAK,IAAI;YACtD,OAAO,SAAS,KAAK,QAAQ;UAC/B;QACF;AACA,aAAK,WAAW;AAChB,YAAI;AACF,gBAAM,WAAW,KAAK,IAAI,uBAAuB;AACjD,gBAAM,OAAO;YACX;YACA,GAAG,KAAK,KAAK,WAAW;YACxB;YACA,GAAG,qBAAqB,QAAQ;UAClC;AACA,gBAAM,EAAE,OAAO,IAAI,MAAM,KAAK,QAAQ,MAAM,EAAE,WAAW,oBAAoB,CAAC;AAC9E,gBAAM,gBAAgB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,KAAK,IAAI;AACjE,eAAK,aAAa,EAAE,eAAe,aAAa,KAAK,IAAI,GAAG,OAAO,KAAK;AACxE,gBAAM,kBACJ,kBAAkB,QAClB,mBAAmB,QACnB,cAAc,eAAe,cAAc,IAAI;AACjD,iBAAO;YACL,aAAa,KAAK,KAAK;YACvB;YACA;YACA;YACA,aAAa,KAAK,WAAW;YAC7B,OAAO;UACT;QACF,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAK,aAAa;YAChB,eAAe,KAAK,YAAY,iBAAiB;YACjD,aAAa,KAAK,IAAI;YACtB,OAAO;UACT;AACA,eAAK,OAAO,KAAK,oCAAoC,EAAE,MAAM,EAAE,OAAO,QAAQ,EAAE,CAAC;AACjF,iBAAO;YACL,aAAa,KAAK,KAAK;YACvB;YACA,eAAe,KAAK,WAAW;YAC/B,iBAAiB;YACjB,aAAa,KAAK,WAAW;YAC7B,OAAO;UACT;QACF,UAAA;AACE,eAAK,WAAW;QAClB;MACF;;MAIA,MAAM,kBAAkB,OAAgE;AACtF,cAAM,WAAW,KAAK,gBAAgB;AACtC,YAAI,aAAa,aAAa;AAC5B,iBAAO;YACL,UAAU;YACV,eAAe,MAAM,WAAW;YAChC,YAAY;YACZ,SACE;UAEJ;QACF;AACA,YAAI,KAAK,aAAa,QAAQ;AAC5B,iBAAO;YACL,UAAU;YACV,eAAe,MAAM,WAAW;YAChC,YAAY;YACZ,SAAS,4CAA4C,KAAK,QAAQ;UACpE;QACF;AACA,cAAM,cAAc,KAAK,UAAU;AACnC,YAAI,YAAY,gBAAgB,MAAM;AACpC,iBAAO;YACL,UAAU;YACV,eAAe,MAAM,WAAW;YAChC,YAAY;YACZ,SAAS,oBAAoB,YAAY,YAAY,OAAO;UAC9D;QACF;AAGA,YAAI,SAAS,MAAM,WAAW;AAC9B,YAAI,WAAW,MAAM;AACnB,gBAAM,QAAQ,MAAM,KAAK,kBAAkB;AAC3C,cAAI,MAAM,UAAU,QAAQ,MAAM,kBAAkB,MAAM;AACxD,mBAAO;cACL,UAAU;cACV,eAAe;cACf,YAAY;cACZ,SAAS,kDAAkD,MAAM,SAAS,qBAAqB;YACjG;UACF;AACA,mBAAS,MAAM;QACjB;AAEA,cAAM,iBAAiB,KAAK,eAAe;AAC3C,YAAI,WAAW,gBAAgB;AAC7B,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,YAAY,KAAK,KAAK,WAAW,IAAI,MAAM;UACtD;QACF;AAOA,YAAI,oBAAoB,MAAM,GAAG;AAC/B,gBAAM,aAAa,oBAAoB,KAAK,QAAQ,GAAG,MAAM;AAC7D,cAAI,CAAI,IAAA,WAAW,UAAU,GAAG;AAC9B,mBAAO;cACL,UAAU;cACV,eAAe;cACf,YAAY;cACZ,SACE,gCAAgC,MAAM,2CAClC,UAAU;YAElB;UACF;QACF;AAEA,aAAK,WAAW;AAChB,YAAI;AACF,gBAAM,KAAK,iBAAiB,MAAM;QACpC,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAK,OAAO,MAAM,sCAAsC;YACtD,MAAM,EAAE,eAAe,QAAQ,OAAO,QAAQ;UAChD,CAAC;AACD,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,mBAAmB,OAAO;UACrC;QACF,UAAA;AACE,eAAK,WAAW;QAClB;AAGA,cAAM,QAAQ,KAAK,UAAU;AAC7B,6BAAqB,KAAK,QAAQ,GAAG;UACnC,GAAG;UACH,aAAa;YACX,SAAS;YACT,aAAa,MAAM;YACnB,eAAe,KAAK,IAAI;YACxB,cAAc;UAChB;UACA,YAAY;QACd,CAAC;AACD,aAAK,OAAO,KAAK,yDAAoD;UACnE,MAAM,EAAE,eAAe,QAAQ,aAAa,MAAM,eAAe;QACnE,CAAC;AACD,aAAK,gBAAgB,GAAG,qBAAqB,KAAK,KAAK,KAAK,WAAW,IAAI,MAAM,EAAE;AACnF,eAAO;UACL,UAAU;UACV,eAAe;UACf,YAAY;UACZ,SAAS,UAAU,KAAK,KAAK,WAAW,IAAI,MAAM;QACpD;MACF;;;;;MAMA,MAAc,iBAAiB,QAA+B;AAC5D,cAAM,UAAU,KAAK,QAAQ;AAC7B,cAAM,OAAO,YAAY,OAAO;AAC7B,YAAA,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,cAAM,aAAkB,MAAA,KAAK,MAAM,YAAY,MAAM,IAAI,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE;AACjF,YAAA,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAE5C,YAAI;AAQF,gBAAM,SAAS,oBAAoB,SAAS,MAAM;AAClD,gBAAM,WAAW,KAAK,IAAI,uBAAuB;AACjD,gBAAM,cAAc,CAAC,WAAW,cAAc,cAAc,aAAa,kBAAkB;AAC3F,cAAO,IAAA,WAAW,MAAM,GAAG;AACtB,gBAAA;cACI,MAAA,KAAK,YAAY,cAAc;cACpC,KAAK,UAAU,KAAK,2BAA2B,QAAQ,MAAM,GAAG,MAAM,CAAC;cACvE;YACF;AACA,kBAAM,KAAK,QAAQ,CAAC,GAAG,aAAa,GAAG,qBAAqB,QAAQ,CAAC,GAAG;cACtE,KAAK;cACL,WAAW;YACb,CAAC;UACH,OAAO;AACF,gBAAA;cACI,MAAA,KAAK,YAAY,cAAc;cACpC,KAAK,UAAU,EAAE,MAAM,sBAAsB,SAAS,KAAK,GAAG,MAAM,CAAC;cACrE;YACF;AACA,kBAAM,KAAK;cACT,CAAC,GAAG,aAAa,GAAG,KAAK,KAAK,WAAW,IAAI,MAAM,IAAI,GAAG,qBAAqB,QAAQ,CAAC;cACxF,EAAE,KAAK,YAAY,WAAW,uBAAuB;YACvD;UACF;AAEA,gBAAM,QAAQ,cAAc,YAAY,KAAK,IAAI;AACjD,cAAI,CAAI,IAAA,WAAW,KAAK,GAAG;AACzB,kBAAM,IAAI,MAAM,6CAA6C,KAAK,GAAG;UACvE;AACA,gBAAM,gBAAgB;YACf,MAAA,KAAK,eAAe,YAAY,KAAK,IAAI,GAAG,cAAc;UACjE;AACA,cAAI,kBAAkB,QAAQ;AAC5B,kBAAM,IAAI;cACR,6CAA6C,MAAM,SAAS,iBAAiB,SAAS;YACxF;UACF;AAGA,gBAAM,OAAO,WAAW,SAAS,MAAM;AACvC,cAAO,IAAA,WAAW,IAAI,GAAG;AACvB,kBAAM,QAAQ,GAAG,IAAI,YAAY,KAAK,IAAI,CAAC;AAC3C,kBAAS,IAAA,SAAS,OAAO,MAAM,KAAK;AACpC,kBAAS,IAAA,SAAS,GAAG,OAAO,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;UACrF;AACA,gBAAS,IAAA,SAAS,OAAO,YAAY,IAAI;QAC3C,SAAS,KAAK;AACZ,gBAAS,IAAA,SAAS,GAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACxF,gBAAM;QACR;MACF;;;;;;;;;;MAWQ,2BACN,QACA,QAMA;AACA,cAAM,WAAW,sBAAsB,MAAM;AAC7C,YAAI,aAAa,MAAM;AACrB,gBAAM,IAAI,MAAM,8CAA8C,MAAM,EAAE;QACxE;AACA,YAAI,SAAS,YAAY,QAAQ;AAC/B,gBAAM,IAAI;YACR,qDAAqD,MAAM,mBAAmB,SAAS,OAAO;UAChG;QACF;AACA,cAAM,UAAU,SAAS,SAAS,KAAK,KAAK,WAAW;AACvD,YAAI,YAAY,QAAW;AACzB,gBAAM,IAAI;YACR,mBAAmB,MAAM,oCAAoC,KAAK,KAAK,WAAW;UACpF;QACF;AACA,cAAM,UAAU,CAAC,aAA6B;AAC5C,gBAAM,MAAW,MAAA,KAAK,QAAQ,QAAQ;AACtC,cAAI,CAAI,IAAA,WAAW,GAAG,GAAG;AACvB,kBAAM,IAAI,MAAM,0DAA0D,GAAG,EAAE;UACjF;AACA,iBAAO,QAAQ,GAAG;QACpB;AACA,cAAM,YAAoC,CAAC;AAC3C,mBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,SAAS,QAAQ,GAAG;AACnE,cAAI,YAAY,KAAK,KAAK,YAAa;AACvC,oBAAU,OAAO,IAAI,QAAQ,QAAQ;QACvC;AACA,eAAO;UACL,MAAM;UACN,SAAS;UACT,cAAc,EAAE,CAAC,KAAK,KAAK,WAAW,GAAG,QAAQ,OAAO,EAAE;UAC1D,GAAI,OAAO,KAAK,SAAS,EAAE,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;QAC3D;MACF;;MAIA,MAAM,uBAA0D;AAI9D,YAAI,KAAK,aAAa,QAAQ;AAC5B,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,4CAA4C,KAAK,QAAQ;UACpE;QACF;AACA,cAAM,QAAQ,KAAK,UAAU;AAC7B,YAAI,MAAM,gBAAgB,MAAM;AAC9B,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,oBAAoB,MAAM,YAAY,OAAO;UACxD;QACF;AACA,YAAI,MAAM,mBAAmB,QAAQ,MAAM,oBAAoB,MAAM;AACnE,iBAAO;YACL,UAAU;YACV,eAAe,MAAM;YACrB,YAAY;YACZ,SAAS;UACX;QACF;AACA,cAAM,YAAY,OAAO,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AAChF,cAAM,gBAAgB;UACpB,KAAK,QAAQ;UACb,MAAM;UACN;UACA,KAAK;QACP;AACA,YAAI,kBAAkB,MAAM;AAC1B,iBAAO;YACL,UAAU;YACV,eAAe,MAAM;YACrB,YAAY;YACZ,SAAS,6BAA6B,MAAM,eAAe,qBAAqB,aAAa;UAC/F;QACF;AAEA,6BAAqB,KAAK,QAAQ,GAAG;UACnC,GAAG;UACH,aAAa;YACX,SAAS,MAAM;YACf,aAAa,MAAM;YACnB,eAAe,KAAK,IAAI;YACxB,cAAc;UAChB;QACF,CAAC;AACD,aAAK,OAAO,KAAK,qDAAgD;UAC/D,MAAM,EAAE,aAAa,MAAM,gBAAgB,WAAW,MAAM,gBAAgB;QAC9E,CAAC;AACD,aAAK;UACH,GAAG,qBAAqB,iBAAiB,KAAK,KAAK,WAAW,IAAI,MAAM,eAAe;QACzF;AACA,eAAO;UACL,UAAU;UACV,eAAe,MAAM;UACrB,YAAY;UACZ,SAAS,mBAAmB,KAAK,KAAK,WAAW,IAAI,MAAM,eAAe;QAC5E;MACF;;;;;;;;;MAWA,cAAwC;AACtC,cAAM,iBAAiB,KAAK,eAAe;AAC3C,YAAI,KAAK,aAAa,QAAQ;AAC5B,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,4CAA4C,KAAK,QAAQ;UACpE;QACF;AACA,cAAM,QAAQ,KAAK,UAAU;AAC7B,YAAI,MAAM,gBAAgB,MAAM;AAC9B,iBAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,SAAS,oBAAoB,MAAM,YAAY,OAAO;UACxD;QACF;AACA,aAAK,OAAO,KAAK,gCAAgC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AAC7E,aAAK,gBAAgB,GAAG,qBAAqB,kBAAkB;AAC/D,eAAO;UACL,UAAU;UACV,eAAe;UACf,YAAY;UACZ,SAAS;QACX;MACF;;;;;;;;;;MAYA,qBAAkD;AAChD,cAAM,QAAQ,oBAAoB,KAAK,QAAQ,CAAC;AAChD,YAAI,UAAU,QAAQ,MAAM,gBAAgB,KAAM,QAAO,EAAE,UAAU,KAAK;AAE1E,cAAM,gBAAgB,KAAK,IAAI,KAAK,SAAS,aAAa,KAAK;AAC/D,YAAI,kBAAkB,MAAM,YAAY,SAAS;AAI/C,iBAAO,EAAE,UAAU,KAAK;QAC1B;AAEA,cAAM,WAA4B;UAChC,GAAG;UACH,gBAAgB,MAAM,YAAY;UAClC,iBAAiB,MAAM,YAAY;UACnC,aAAa;UACb,YAAY;QACd;AACA,6BAAqB,KAAK,QAAQ,GAAG,QAAQ;AAC7C,aAAK;UACH,CAAC,SAAS,gBAAgB,SAAS,eAAe,EAAE;YAClD,CAAC,MAAmB,OAAO,MAAM;UACnC;QACF;AACA,aAAK,gBAAgB,sBAAsB;AAC3C,aAAK,OAAO,KAAK,yCAAyC;UACxD,MAAM;YACJ,SAAS,SAAS;YAClB,iBAAiB,SAAS;UAC5B;QACF,CAAC;AACD,eAAO,EAAE,UAAU,SAAS,eAAe;MAC7C;;;;;;;;;;;;MAaQ,cAAc,MAA+B;AACnD,cAAM,OAAO,YAAY,KAAK,QAAQ,CAAC;AACvC,YAAI;AACJ,YAAI;AACF,oBAAa,IAAA,YAAY,IAAI;QAC/B,QAAQ;AACN;QACF;AACA,mBAAW,SAAS,SAAS;AAC3B,cAAI,KAAK,SAAS,KAAK,EAAG;AAC1B,gBAAM,OAAY,MAAA,KAAK,MAAM,KAAK;AAClC,cAAI,MAAM,WAAW,GAAG,GAAG;AACzB,gBAAI;AACF,oBAAM,QAAQ,KAAK,IAAI,IAAO,IAAA,SAAS,IAAI,EAAE;AAC7C,kBAAI,QAAQ,mBAAkB,mBAAoB;YACpD,QAAQ;AAEN;YACF;UACF;AACA,cAAI;AACC,gBAAA,OAAO,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAChD,iBAAK,OAAO,MAAM,kCAAkC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;UACzE,SAAS,KAAK;AACZ,iBAAK,OAAO,KAAK,2CAA2C;cAC1D,MAAM,EAAE,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;YACzE,CAAC;UACH;QACF;MACF;;;;;;;;;MAUQ,gBAAgB,WAAyB;AAC/C,cAAM,MAAM,cAAc,KAAK,QAAQ,CAAC;AACxC,YAAI;AACJ,YAAI;AACF,oBAAa,IAAA,YAAY,GAAG;QAC9B,QAAQ;AACN;QACF;AACA,cAAM,YAAiB,MAAA,KAAK,KAAK,WAAW;AAE5C,YAAI;AACF,qBAAW,WAAc,IAAA,YAAY,SAAS,GAAG;AAC/C,gBAAI;AACC,kBAAA,OAAY,MAAA,KAAK,WAAW,OAAO,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;YAC3E,QAAQ;YAER;UACF;QACF,QAAQ;QAER;AAEA,cAAM,WAAW,QAAQ,OAAO,CAAC,SAAS,CAAC,KAAK,WAAW,GAAG,CAAC;AAC/D,cAAM,gBAAgB,CAAC,GAAG,QAAQ,EAAE;UAClC,CAAC,GAAG,OAAO,gBAAgB,CAAC,KAAK,OAAO,gBAAgB,CAAC,KAAK;QAChE;AACA,cAAM,SAAS,cAAc,MAAM,SAAS;AAC5C,YAAI,OAAO,WAAW,EAAG;AACtB,YAAA,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC3C,mBAAW,SAAS,QAAQ;AAC1B,gBAAM,QAAa,MAAA,KAAK,WAAW,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,EAAE;AAC3D,cAAI;AACC,gBAAA,WAAgB,MAAA,KAAK,KAAK,KAAK,GAAG,KAAK;UAC5C,SAAS,KAAK;AACZ,iBAAK,OAAO,KAAK,oDAAoD;cACnE,MAAM,EAAE,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;YACzE,CAAC;AACD;UACF;AACA,cAAI;AACC,gBAAA,OAAO,OAAO,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACjD,iBAAK,OAAO,MAAM,2BAA2B,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;UAClE,QAAQ;UAER;QACF;MACF;;MAGA,OAAwB,qBAAqB,KAAK,KAAK,KAAK;IAC9D;;;;;AC7xBA,qBAA2B;AAC3B,WAAsB;AACtB,uBAAgD;AAShD,SAAS,oBAAoB,MAAyB,KAAgC;AACpF,QAAM,UAAU,IAAI,mBAAmB;AACvC,MAAI,YAAY,UAAa,QAAQ,SAAS,EAAG,QAAY,aAAQ,OAAO;AAC5E,WAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACxC,QAAI,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,MAAM;AAC5C,YAAM,OAAO,KAAK,IAAI,CAAC;AACvB,UAAI,SAAS,UAAa,CAAC,KAAK,WAAW,GAAG,EAAG,QAAY,aAAQ,IAAI;AAAA,IAC3E;AAAA,EACF;AACA,SAAY,aAAQ,eAAe;AACrC;AASA,SAAS,8BAAoC;AAC3C,MAAI,KAAC,2BAAW,aAAa,EAAG;AAChC,UAAQ;AAAA,IACN;AAAA,EAGF;AACF;AAEA,SAAS,QAAc;AACrB,8BAA4B;AAE5B,QAAM,iBAAsB,aAAQ,WAAW,IAAI;AACnD,MAAI,QAAQ,IAAI,yBAAyB,MAAM,QAAW;AACxD,YAAQ,IAAI,yBAAyB,IAAI;AAAA,EAC3C;AAEA,uCAAe;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,YAAY;AAAA,IACd;AAAA,IACA,SAAS,oBAAoB,QAAQ,MAAM,QAAQ,GAAG;AAAA,IACtD,WAAgB,UAAK,WAAW,QAAQ;AAAA,IACxC,YAAY;AAAA;AAAA;AAAA,IAGZ,WAAW,CAAC,cAAc,QAAQ,SAAS;AAAA,EAC7C,CAAC;AACH;AAEA,IAAI;AACF,QAAM;AACR,SAAS,KAAK;AACZ,UAAQ,MAAM,oBAAoB,GAAG;AACrC,UAAQ,KAAK,CAAC;AAChB;","names":["AGENT_ROOT_SPEC","runNodeStarter","module","__toESM","path","fs","path2"]}
1
+ {"version":3,"sources":["../../node-root/src/index.ts","../../node-root/src/dev-uploads.ts","../../node-root/src/root-package-spec.ts","../../node-root/src/root-state.ts","../../node-root/src/semver-compare.ts","../../node-root/src/boot-plan.ts","../../node-root/src/workspace-detect.ts","../../node-root/src/starter-core.ts","../../node-root/src/root-update-service.ts","../src/starter.ts"],"sourcesContent":["/**\n * @camstack/node-root — the shared, zero-runtime-dep node-root boot core.\n *\n * PRIVATE workspace package: it is BUNDLED at build time into the hub's\n * `dist/server-root/index.js` (tsup) and into the agent's tsup output —\n * never published, never resolved from node_modules at runtime. Both node\n * starters and both update services are thin per-node adapters over these\n * modules, so the boot-plan / probation / rollback semantics can never\n * drift between the hub and the agent.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nexport * from './dev-uploads.js'\nexport * from './root-package-spec.js'\nexport * from './root-state.js'\nexport * from './boot-plan.js'\nexport * from './semver-compare.js'\nexport * from './workspace-detect.js'\nexport * from './starter-core.js'\nexport * from './root-update-service.js'\n","/**\n * Dev server-deploy channel — layout + manifest for locally-uploaded root\n * package closures (ZERO-DEP: node:fs/node:path only, same constraint as\n * root-state.ts — the baked starter bundles this module).\n *\n * `camstack deploy-server` packs every workspace package in the server's\n * `@camstack/*` closure at one uniform dev version\n * (`<base>-dev.<epochSeconds>`) and uploads the tarballs to\n * `POST /api/server-upload`. The hub stores them under:\n *\n * <dataDir>/server-root/dev-uploads/<version>/\n * <flattened-pkg-name>.tgz one per uploaded package\n * manifest.json { version, packages: { name → filename } }\n *\n * `RootUpdateService.stageAndActivate` detects the dir and stages from these\n * tarballs (synthetic package.json with `file:` refs + `overrides`) instead\n * of the npm registry. Everything downstream — probation boot, promote,\n * rollback — is version-string driven and unchanged; the `-dev.` suffix is\n * self-describing.\n *\n * Spec: docs/superpowers/specs — dev server-deploy channel (2026-07-13).\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nexport const DEV_UPLOADS_DIRNAME = 'dev-uploads'\nexport const DEV_UPLOAD_MANIFEST_FILE = 'manifest.json'\n\n/** Number of dev-uploads entries retained by the promote-time sweep. */\nexport const DEV_UPLOADS_KEEP_COUNT = 3\n\n/**\n * Dev-channel version shape: `<semver-base>-dev.<epochSeconds>`. The suffix\n * is sortable, self-describing, and can never collide with a published\n * registry version. The upload route and the staging branch BOTH gate on it.\n */\nconst DEV_CHANNEL_VERSION_RE = /-dev\\.\\d+$/\n\nexport function isDevChannelVersion(version: string): boolean {\n return DEV_CHANNEL_VERSION_RE.test(version)\n}\n\n/**\n * The `<epochSeconds>` ordering key of a dev-channel version (or dir name).\n * Returns null for anything that is not dev-channel shaped — the sweep\n * treats those as oldest so malformed residue is collected first.\n */\nexport function devChannelEpoch(version: string): number | null {\n const match = /-dev\\.(\\d+)$/.exec(version)\n if (match === null) return null\n const epoch = Number.parseInt(match[1] ?? '', 10)\n return Number.isNaN(epoch) ? null : epoch\n}\n\n/** `<dataDir>/server-root/dev-uploads` */\nexport function devUploadsDir(rootDir: string): string {\n return path.join(rootDir, DEV_UPLOADS_DIRNAME)\n}\n\n/** `<dataDir>/server-root/dev-uploads/<version>` */\nexport function devUploadVersionDir(rootDir: string, version: string): string {\n return path.join(devUploadsDir(rootDir), version)\n}\n\n// ---------------------------------------------------------------------------\n// Manifest IO\n// ---------------------------------------------------------------------------\n\n/**\n * Written by the hub's `/api/server-upload` route after validating every\n * tarball; read by the staging branch. Maps each uploaded package NAME to\n * its tgz FILENAME inside the version dir — staging never has to re-derive\n * package names from flattened filenames.\n */\nexport interface DevUploadManifest {\n readonly version: string\n readonly packages: Readonly<Record<string, string>>\n}\n\nexport function devUploadManifestPath(versionDirPath: string): string {\n return path.join(versionDirPath, DEV_UPLOAD_MANIFEST_FILE)\n}\n\nfunction isDevUploadManifest(v: unknown): v is DevUploadManifest {\n if (typeof v !== 'object' || v === null) return false\n const m = v as Record<string, unknown>\n if (typeof m['version'] !== 'string') return false\n const packages = m['packages']\n if (typeof packages !== 'object' || packages === null || Array.isArray(packages)) return false\n return Object.values(packages).every((filename) => typeof filename === 'string')\n}\n\n/** Read + validate the manifest. Returns null when missing/corrupt. */\nexport function readDevUploadManifest(versionDirPath: string): DevUploadManifest | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(devUploadManifestPath(versionDirPath), 'utf-8'))\n return isDevUploadManifest(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Write the manifest atomically (tmp sibling + rename). Creates the dir. */\nexport function writeDevUploadManifest(versionDirPath: string, manifest: DevUploadManifest): void {\n fs.mkdirSync(versionDirPath, { recursive: true })\n const target = devUploadManifestPath(versionDirPath)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n","/**\n * Root-package spec — the per-node-type parameters of the shared node-root\n * boot machinery. Everything else (the `server-root/` data-dir layout, the\n * `state.json` schema, the probation/rollback boot plan, the update service)\n * is IDENTICAL between the hub and the agent; only the root package's name\n * and its loadable entry differ.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\n\nexport interface RootPackageSpec {\n /** The npm name of the node's root package. */\n readonly packageName: string\n /**\n * Path segments of the loadable entry INSIDE the root package dir\n * (`node_modules/<packageName>/<...entryRelPath>`).\n */\n readonly entryRelPath: readonly string[]\n}\n\n/** The hub's root package — the starter loads its launcher. */\nexport const HUB_ROOT_SPEC: RootPackageSpec = {\n packageName: '@camstack/server',\n entryRelPath: ['dist', 'launcher.js'],\n}\n\n/** The agent's root package — the starter loads its CLI entry. */\nexport const AGENT_ROOT_SPEC: RootPackageSpec = {\n packageName: '@camstack/agent',\n entryRelPath: ['dist', 'cli.js'],\n}\n","/**\n * Data-dir server-root layout + state file — ZERO-DEP (node:fs/node:path only).\n *\n * Loaded by each node's baked STARTER before any node_modules resolution is\n * trusted, so this module must never import from `@camstack/*` (runtime) or\n * any npm package. The hub's `ServerUpdateService` and the agent's update\n * service consume the same module — one source of truth for the layout and\n * the state shape. The layout is IDENTICAL on both node types (the dir is\n * named `server-root/` everywhere); only the root package name + entry differ\n * and arrive via {@link RootPackageSpec}.\n *\n * Layout (`<dataDir>/server-root/`):\n * versions/<semver>/ npm-installed closure for one version\n * node_modules/<pkg>/<entry> ← the loadable entry (spec-defined)\n * state.json pointer file (ServerRootState, atomic)\n *\n * A POINTER FILE (state.json) is used instead of `current`/`previous`\n * symlinks: atomic via tmp+rename, works on every fs, and carries the\n * probation/rollback bookkeeping in the same durable record.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { RootPackageSpec } from './root-package-spec.js'\n\nexport const SERVER_ROOT_DIRNAME = 'server-root'\nexport const SERVER_ROOT_STATE_FILE = 'state.json'\n/**\n * Restart-intent marker filename. Written by the update service moments before\n * a graceful self-restart (apply/rollback), then read + consumed by an\n * external process supervisor so it can tell an INTENTIONAL restart-for-update\n * apart from a crash — a crash-backoff policy must never penalise an update\n * restart. Lives in the server-root dir next to `state.json`.\n *\n * (Phase 3 — the Electron shell supervisor reads it; the docker restart policy\n * relaunches unconditionally so the marker is a harmless no-op there.)\n */\nexport const RESTART_INTENT_FILE = '.restart-intent'\n\n// ---------------------------------------------------------------------------\n// State shape\n// ---------------------------------------------------------------------------\n\nexport interface ServerRootPendingBoot {\n /** The freshly-staged version awaiting its probation boot. */\n readonly version: string\n /** The version that was current when the update was requested (null = baked). */\n readonly fromVersion: string | null\n readonly requestedAtMs: number\n /** 0 = not yet booted; >=1 = a probation boot started and never confirmed. */\n readonly bootAttempts: number\n}\n\nexport interface ServerRootRollbackInfo {\n readonly fromVersion: string\n /** null = rolled back all the way to the baked seed. */\n readonly toVersion: string | null\n readonly atMs: number\n readonly reason: string\n}\n\nexport interface ServerRootState {\n readonly schemaVersion: 1\n /** The confirmed-healthy active version (null = boot from the baked seed). */\n readonly currentVersion: string | null\n /** N-1 kept for rollback (its versions/ dir is retained). */\n readonly previousVersion: string | null\n readonly pendingBoot: ServerRootPendingBoot | null\n /** Set when the most recent update attempt was rolled back. */\n readonly rolledBack: ServerRootRollbackInfo | null\n}\n\nexport function emptyServerRootState(): ServerRootState {\n return {\n schemaVersion: 1,\n currentVersion: null,\n previousVersion: null,\n pendingBoot: null,\n rolledBack: null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Layout helpers\n// ---------------------------------------------------------------------------\n\nexport function serverRootDir(dataDir: string): string {\n return path.join(dataDir, SERVER_ROOT_DIRNAME)\n}\n\nexport function versionsDir(rootDir: string): string {\n return path.join(rootDir, 'versions')\n}\n\nexport function versionDir(rootDir: string, version: string): string {\n return path.join(versionsDir(rootDir), version)\n}\n\n/** `versions/<v>/node_modules/<packageName>` — the installed root package dir. */\nexport function rootPackageDir(versionDirPath: string, spec: RootPackageSpec): string {\n return path.join(versionDirPath, 'node_modules', ...spec.packageName.split('/'))\n}\n\n/** The loadable entry inside the installed root package dir. */\nexport function rootEntryPath(versionDirPath: string, spec: RootPackageSpec): string {\n return path.join(rootPackageDir(versionDirPath, spec), ...spec.entryRelPath)\n}\n\nexport function stateFilePath(rootDir: string): string {\n return path.join(rootDir, SERVER_ROOT_STATE_FILE)\n}\n\n// ---------------------------------------------------------------------------\n// State IO (atomic, corruption-tolerant)\n// ---------------------------------------------------------------------------\n\nfunction isNullableString(v: unknown): v is string | null {\n return v === null || typeof v === 'string'\n}\n\nfunction isPendingBoot(v: unknown): v is ServerRootPendingBoot {\n if (typeof v !== 'object' || v === null) return false\n const p = v as Record<string, unknown>\n return (\n typeof p['version'] === 'string' &&\n isNullableString(p['fromVersion']) &&\n typeof p['requestedAtMs'] === 'number' &&\n typeof p['bootAttempts'] === 'number'\n )\n}\n\nfunction isRollbackInfo(v: unknown): v is ServerRootRollbackInfo {\n if (typeof v !== 'object' || v === null) return false\n const r = v as Record<string, unknown>\n return (\n typeof r['fromVersion'] === 'string' &&\n isNullableString(r['toVersion']) &&\n typeof r['atMs'] === 'number' &&\n typeof r['reason'] === 'string'\n )\n}\n\nexport function isServerRootState(v: unknown): v is ServerRootState {\n if (typeof v !== 'object' || v === null) return false\n const s = v as Record<string, unknown>\n if (s['schemaVersion'] !== 1) return false\n if (!isNullableString(s['currentVersion'])) return false\n if (!isNullableString(s['previousVersion'])) return false\n if (s['pendingBoot'] !== null && !isPendingBoot(s['pendingBoot'])) return false\n if (s['rolledBack'] !== null && !isRollbackInfo(s['rolledBack'])) return false\n return true\n}\n\n/** Read + validate the state file. Returns null when missing/corrupt/mismatched. */\nexport function readServerRootState(rootDir: string): ServerRootState | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(stateFilePath(rootDir), 'utf-8'))\n return isServerRootState(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Write the state file atomically (tmp sibling + rename). Creates rootDir. */\nexport function writeServerRootState(rootDir: string, state: ServerRootState): void {\n fs.mkdirSync(rootDir, { recursive: true })\n const target = stateFilePath(rootDir)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n\n// ---------------------------------------------------------------------------\n// Restart-intent marker (supervisor: update-restart vs crash discrimination)\n// ---------------------------------------------------------------------------\n\n/**\n * Payload of the restart-intent marker. `requestedAtMs` lets a reader ignore a\n * STALE marker (e.g. one left behind by a hard kill between write and\n * relaunch) via a freshness window instead of mis-classifying a much-later\n * crash as an update restart. `reason` carries the human `requestedBy` string.\n */\nexport interface RestartIntentMarker {\n readonly requestedAtMs: number\n readonly reason: string\n}\n\nexport function restartIntentMarkerPath(rootDir: string): string {\n return path.join(rootDir, RESTART_INTENT_FILE)\n}\n\nfunction isRestartIntentMarker(v: unknown): v is RestartIntentMarker {\n if (typeof v !== 'object' || v === null) return false\n const m = v as Record<string, unknown>\n return typeof m['requestedAtMs'] === 'number' && typeof m['reason'] === 'string'\n}\n\n/** Write the marker atomically (tmp sibling + rename). Creates rootDir. */\nexport function writeRestartIntentMarker(rootDir: string, marker: RestartIntentMarker): void {\n fs.mkdirSync(rootDir, { recursive: true })\n const target = restartIntentMarkerPath(rootDir)\n const tmp = `${target}.tmp`\n fs.writeFileSync(tmp, JSON.stringify(marker, null, 2), 'utf-8')\n fs.renameSync(tmp, target)\n}\n\n/** Read + validate the marker. Returns null when missing/corrupt. */\nexport function readRestartIntentMarker(rootDir: string): RestartIntentMarker | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(restartIntentMarkerPath(rootDir), 'utf-8'))\n return isRestartIntentMarker(raw) ? raw : null\n } catch {\n return null\n }\n}\n\n/** Delete the marker if present (idempotent — a missing file is not an error). */\nexport function clearRestartIntentMarker(rootDir: string): void {\n try {\n fs.rmSync(restartIntentMarkerPath(rootDir), { force: true })\n } catch {\n /* best-effort */\n }\n}\n\n// ---------------------------------------------------------------------------\n// Version-dir validation\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the minimum required Node major from an `engines.node` range like\n * `>=22`, `>= 22.12`, `^24.0.0`, `22.x`. Returns null when unparseable\n * (validation is then permissive — a bogus range must not brick boot).\n */\nexport function minNodeMajorOf(enginesNode: string): number | null {\n const match = /(\\d+)/.exec(enginesNode)\n if (match === null) return null\n const major = Number.parseInt(match[1] ?? '', 10)\n return Number.isNaN(major) ? null : major\n}\n\n/**\n * Validate that `versions/<version>` holds a loadable root-package closure\n * for `spec`. Returns null when valid, else a human-readable reason. Checks:\n * 1. the entry file exists,\n * 2. the package.json parses with the right `name` + `version`,\n * 3. `engines.node` (when parseable) is satisfied by the running runtime —\n * the starter refuses a native-ABI mismatch with a clear error instead\n * of segfaulting (design risk: node bump vs shm-ring prebuilds).\n */\nexport function validateVersionDir(\n rootDir: string,\n version: string,\n nodeMajor: number,\n spec: RootPackageSpec,\n): string | null {\n const vDir = versionDir(rootDir, version)\n const entry = rootEntryPath(vDir, spec)\n if (!fs.existsSync(entry)) {\n return `root entry missing: ${entry}`\n }\n\n const pkgJsonPath = path.join(rootPackageDir(vDir, spec), 'package.json')\n let pkg: Record<string, unknown>\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n return `package.json malformed: ${pkgJsonPath}`\n }\n pkg = raw as Record<string, unknown>\n } catch {\n return `package.json unreadable: ${pkgJsonPath}`\n }\n\n if (pkg['name'] !== spec.packageName) {\n return `package name mismatch: expected ${spec.packageName}, got ${String(pkg['name'])}`\n }\n if (pkg['version'] !== version) {\n return `package version mismatch: dir says ${version}, package.json says ${String(pkg['version'])}`\n }\n\n const engines = pkg['engines']\n if (typeof engines === 'object' && engines !== null) {\n const enginesNode = (engines as Record<string, unknown>)['node']\n if (typeof enginesNode === 'string') {\n const minMajor = minNodeMajorOf(enginesNode)\n if (minMajor !== null && nodeMajor < minMajor) {\n return `engines.node \"${enginesNode}\" requires Node >= ${minMajor}, runtime is ${nodeMajor}`\n }\n }\n }\n\n return null\n}\n","/**\n * Minimal semver comparison — zero-dep (used by the starter, which must never\n * import from node_modules). Handles `MAJOR.MINOR.PATCH[-prerelease]`:\n * numeric segment compare, missing segments = 0, prerelease < its release,\n * prereleases of the same base compare lexically. Malformed segments compare\n * as 0 (best effort — never throws).\n */\n\ntype SemverParts = {\n readonly nums: readonly number[]\n readonly prerelease: string | null\n}\n\nfunction parse(version: string): SemverParts {\n const dashIdx = version.indexOf('-')\n const base = dashIdx === -1 ? version : version.slice(0, dashIdx)\n const prerelease = dashIdx === -1 ? null : version.slice(dashIdx + 1)\n const nums = base.split('.').map((seg) => {\n const n = Number.parseInt(seg, 10)\n return Number.isNaN(n) ? 0 : n\n })\n return { nums, prerelease }\n}\n\n/** Returns -1 when a < b, 0 when equal, 1 when a > b. */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parse(a)\n const pb = parse(b)\n const len = Math.max(pa.nums.length, pb.nums.length)\n for (let i = 0; i < len; i++) {\n const na = pa.nums[i] ?? 0\n const nb = pb.nums[i] ?? 0\n if (na < nb) return -1\n if (na > nb) return 1\n }\n if (pa.prerelease === null && pb.prerelease === null) return 0\n if (pa.prerelease === null) return 1\n if (pb.prerelease === null) return -1\n if (pa.prerelease < pb.prerelease) return -1\n if (pa.prerelease > pb.prerelease) return 1\n return 0\n}\n","/**\n * Pure boot-plan decision for the server-root starter — ZERO-DEP.\n *\n * Given the durable `ServerRootState` and a validity predicate for staged\n * version dirs, decide WHICH closure this boot should load and what the\n * state file must be updated to. All filesystem access is behind the\n * injected `isValidVersion` callback so the decision itself is unit-testable.\n *\n * Probation / rollback protocol (mirrors `launcher-framework-swap.ts`):\n * - `pendingBoot.bootAttempts === 0` → this is the probation boot: bump the\n * counter durably BEFORE loading the new version. The hub clears the\n * pending record (promoting the version to `currentVersion`) only once it\n * reaches ready (`ServerUpdateService.confirmBootHealthy`).\n * - `pendingBoot.bootAttempts >= 1` → the previous probation boot died\n * before confirming: auto-rollback to `currentVersion` (or baked) and\n * record `rolledBack` so the status cap can surface it.\n */\nimport type { ServerRootState } from './root-state.js'\nimport { compareSemver } from './semver-compare.js'\n\nexport type BootPlan =\n | {\n readonly kind: 'baked'\n readonly reason: string\n readonly stateToWrite: ServerRootState | null\n }\n | {\n readonly kind: 'data-root'\n readonly version: string\n /** True when this boot must be confirmed healthy (freshly-staged version). */\n readonly probation: boolean\n readonly stateToWrite: ServerRootState | null\n }\n\ntype IsValidVersion = (version: string) => boolean\ntype NowFn = () => number\n\n/**\n * Decide the boot target. Never throws; never mutates `state`.\n * `stateToWrite` is non-null whenever the durable state must change\n * (probation counter bump, rollback, invalid-version eviction).\n *\n * `seedVersion` is the version baked into THIS image's seed closure (null when\n * unknown — adoption is then disabled, preserving the historical behaviour).\n * When a release image ships a strictly-newer seed than the confirmed active\n * data-root version, we ADOPT the baked seed: booting baked runs the new\n * image's code, so a stale `applyServerUpdate` data-root can no longer shadow\n * a newer image (the \"new caps 404 after a release swap\" bug). Adoption is\n * gated on `!changed` so it never fires in the same boot as a rollback /\n * eviction, and the pending/probation branch returns earlier — probation and\n * rollback semantics are untouched.\n */\nexport function planBoot(\n state: ServerRootState | null,\n isValidVersion: IsValidVersion,\n now: NowFn,\n seedVersion: string | null = null,\n): BootPlan {\n if (state === null) {\n return { kind: 'baked', reason: 'no server-root state', stateToWrite: null }\n }\n\n let next: ServerRootState = state\n let changed = false\n\n // ── Pending (freshly-staged) version ──────────────────────────────────\n if (next.pendingBoot !== null) {\n const pending = next.pendingBoot\n if (pending.bootAttempts >= 1) {\n // Previous probation boot never confirmed healthy — roll back.\n next = {\n ...next,\n pendingBoot: null,\n rolledBack: {\n fromVersion: pending.version,\n toVersion: next.currentVersion,\n atMs: now(),\n reason: 'probation boot did not reach ready — rolled back',\n },\n }\n changed = true\n } else if (!isValidVersion(pending.version)) {\n next = {\n ...next,\n pendingBoot: null,\n rolledBack: {\n fromVersion: pending.version,\n toVersion: next.currentVersion,\n atMs: now(),\n reason: 'staged version failed validation',\n },\n }\n changed = true\n } else {\n // Probation boot: bump the attempt counter durably, keep currentVersion\n // untouched until the hub confirms the boot healthy.\n return {\n kind: 'data-root',\n version: pending.version,\n probation: true,\n stateToWrite: {\n ...next,\n pendingBoot: { ...pending, bootAttempts: pending.bootAttempts + 1 },\n },\n }\n }\n }\n\n // ── Confirmed current version ──────────────────────────────────────────\n if (next.currentVersion !== null) {\n if (isValidVersion(next.currentVersion)) {\n // Baked-seed adoption: a release image whose seed is strictly newer than\n // the confirmed active version wins — otherwise a stale applyServerUpdate\n // data-root shadows the newer image's code (new caps 404 after a swap).\n // Gated on `!changed` so it never pre-empts an in-flight rollback.\n if (!changed && seedVersion !== null && compareSemver(seedVersion, next.currentVersion) > 0) {\n return {\n kind: 'baked',\n reason: `baked seed ${seedVersion} is newer than active data-root ${next.currentVersion} — adopting the image seed`,\n stateToWrite: {\n ...next,\n currentVersion: null,\n previousVersion: null,\n pendingBoot: null,\n rolledBack: null,\n },\n }\n }\n return {\n kind: 'data-root',\n version: next.currentVersion,\n probation: false,\n stateToWrite: changed ? next : null,\n }\n }\n\n // Current version dir is broken — try N-1, else baked.\n const broken = next.currentVersion\n if (next.previousVersion !== null && isValidVersion(next.previousVersion)) {\n const fallback = next.previousVersion\n return {\n kind: 'data-root',\n version: fallback,\n probation: false,\n stateToWrite: {\n ...next,\n currentVersion: fallback,\n previousVersion: null,\n rolledBack: {\n fromVersion: broken,\n toVersion: fallback,\n atMs: now(),\n reason: 'active version failed validation',\n },\n },\n }\n }\n\n return {\n kind: 'baked',\n reason: `active version ${broken} failed validation and no valid previous version exists`,\n stateToWrite: {\n ...next,\n currentVersion: null,\n rolledBack: {\n fromVersion: broken,\n toVersion: null,\n atMs: now(),\n reason: 'active version failed validation',\n },\n },\n }\n }\n\n return {\n kind: 'baked',\n reason: 'no active data-root version',\n stateToWrite: changed ? next : null,\n }\n}\n","/**\n * Workspace-checkout detection for the starter — ZERO-DEP.\n *\n * The starter must defer to plain resolution in a dev checkout (`npm run\n * dev:full` / `npm start` from the monorepo): the data-dir server root is a\n * production mechanism and must never shadow freshly-built workspace code.\n * Detection = any ancestor package.json declaring `workspaces` (the monorepo\n * root has one; the baked image run-dir's `npm init -y` package.json and the\n * data-dir version closures never do).\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\n/**\n * Walk up from `fromDir` looking for a package.json with a `workspaces`\n * field. Returns the directory containing it, or null when none exists.\n */\nexport function detectWorkspaceRoot(fromDir: string): string | null {\n let dir = path.resolve(fromDir)\n for (;;) {\n const pkgPath = path.join(dir, 'package.json')\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (\n typeof raw === 'object' &&\n raw !== null &&\n (raw as Record<string, unknown>)['workspaces'] !== undefined\n ) {\n return dir\n }\n } catch {\n // missing / unreadable package.json — keep walking\n }\n const parent = path.dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n","/**\n * Shared STARTER core — the boot flow both node starters (hub + agent) run.\n * ZERO-DEP: bundled into each starter at build time; must never resolve\n * anything from node_modules at runtime.\n *\n * Boot sequence (identical on both node types; per-node names arrive via\n * {@link NodeStarterOptions}):\n * 1. Workspace checkout? → defer to plain resolution (load the sibling\n * seed entry; the dev loop never runs the built starter at all).\n * 2. Read `<dataDir>/server-root/state.json`, run the pure boot plan\n * (probation counter / auto-rollback / validity fallback) and persist\n * any state change BEFORE loading code.\n * 3. Data-root chosen → register in-process resolver hooks so the node's\n * MAIN process resolves the host-external packages (@camstack/system, …)\n * from the ACTIVE root's node_modules, then load that root's entry.\n * 4. Otherwise → load the baked seed entry next to the starter.\n *\n * Console usage is intentional: the starter runs before any logging exists.\n * Every line is prefixed `[starter]`.\n */\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { planBoot } from './boot-plan.js'\nimport type { RootPackageSpec } from './root-package-spec.js'\nimport {\n readServerRootState,\n rootEntryPath,\n serverRootDir,\n validateVersionDir,\n versionDir,\n writeServerRootState,\n} from './root-state.js'\nimport { detectWorkspaceRoot } from './workspace-detect.js'\n\n/**\n * Mirror of the host-external list in\n * `packages/system/src/kernel/moleculer/framework-resolver-hook.mjs` — kept\n * inline because the starter must stay zero-dep. Only these specifiers are\n * redirected to the active root; everything else resolves normally.\n */\nexport const HOST_EXTERNAL_SPECIFIERS: readonly string[] = [\n '@camstack/system',\n '@camstack/shm-ring',\n '@camstack/types',\n '@camstack/sdk',\n 'zod',\n '@trpc/server',\n '@trpc/client',\n 'sharp',\n 'node-av',\n]\n\nexport function isHostExternal(specifier: string): boolean {\n return HOST_EXTERNAL_SPECIFIERS.some(\n (name) => specifier === name || specifier.startsWith(`${name}/`),\n )\n}\n\ntype ResolveContext = { readonly parentURL?: string }\ntype NextResolve = (specifier: string, context?: ResolveContext) => unknown\ntype RegisterHooksFn = (hooks: {\n resolve: (specifier: string, context: ResolveContext, nextResolve: NextResolve) => unknown\n}) => void\n\n/**\n * Register in-process resolver hooks (Node >= 22.15 `module.registerHooks`,\n * covers BOTH require and import) that anchor host-external resolution inside\n * the active root's node_modules. Failure-tolerant: if the anchored resolve\n * fails (package absent from the closure, e.g. sharp/node-av), fall back to\n * the default walk (NODE_PATH /data/framework still covers those).\n */\nexport function registerActiveRootResolver(activeRootDir: string): void {\n // Documented type boundary: `module.registerHooks` is not yet in the\n // bundled @types/node — feature-detect it off the untyped module surface.\n const moduleApi: Record<string, unknown> = require('node:module')\n const registerHooks = moduleApi['registerHooks']\n if (typeof registerHooks !== 'function') {\n console.warn(\n '[starter] module.registerHooks unavailable (Node < 22.15) — host-external redirect skipped',\n )\n return\n }\n const anchorURL = pathToFileURL(\n path.join(activeRootDir, 'node_modules', '__camstack_starter_anchor__.js'),\n ).href\n const hooks: Parameters<RegisterHooksFn>[0] = {\n resolve: (specifier, context, nextResolve) => {\n if (isHostExternal(specifier)) {\n try {\n return nextResolve(specifier, { ...context, parentURL: anchorURL })\n } catch {\n // Not in the active root's closure — fall through to default.\n }\n }\n return nextResolve(specifier, context)\n },\n }\n ;(registerHooks as RegisterHooksFn)(hooks)\n}\n\n/** Per-node env-var names the starter writes / reads. */\nexport interface StarterEnvNames {\n /** Boot-mode marker read by the node's update service (`workspace`/`baked`/`data-root`). */\n readonly bootMode: string\n /** Absolute path of the active data-root version dir (data-root boots only). */\n readonly activeRoot: string\n /** Active data-root version (data-root boots only). */\n readonly activeVersion: string\n /** Kill switch: `<killSwitch>=off` forces the baked seed closure. */\n readonly killSwitch: string\n}\n\nexport interface NodeStarterOptions {\n readonly spec: RootPackageSpec\n readonly envNames: StarterEnvNames\n /** The node's resolved data dir (owner-specific env/argv resolution). */\n readonly dataDir: string\n /** Absolute path of the baked seed entry sibling to the starter. */\n readonly seedEntry: string\n /** The starter's own dir (`__dirname`) — anchors workspace detection. */\n readonly starterDir: string\n /** Load an entry file (a plain CJS `require` in the real starters). */\n readonly loadEntry: (entryPath: string) => void\n /** Test seams. Defaults: `process.env`, `Date.now`, running node major. */\n readonly env?: NodeJS.ProcessEnv\n readonly now?: () => number\n readonly nodeMajor?: number\n readonly registerResolver?: (activeRootDir: string) => void\n}\n\n/**\n * Read the version baked into the seed closure from its `package.json` (sibling\n * to the seed package dir: `<seedEntry>/../../package.json`). Zero-dep, never\n * throws — any failure returns null, which disables baked-seed adoption in\n * {@link planBoot} and preserves the historical \"boot the data-root version\n * unconditionally\" behaviour.\n */\nexport function readSeedVersion(seedEntry: string): string | null {\n try {\n const pkgJsonPath = path.join(path.dirname(seedEntry), '..', 'package.json')\n const raw: unknown = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n if (typeof raw === 'object' && raw !== null) {\n const version = (raw as Record<string, unknown>)['version']\n if (typeof version === 'string') return version\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Run the shared starter flow. Never throws for boot-plan reasons — every\n * failure path degrades to the baked seed. (A `loadEntry` throw propagates:\n * that is the caller's fatal handler's job.)\n */\nexport function runNodeStarter(options: NodeStarterOptions): void {\n const env = options.env ?? process.env\n const now = options.now ?? Date.now\n const registerResolver = options.registerResolver ?? registerActiveRootResolver\n\n // ── 1. Workspace checkout → plain resolution, dev loop untouched ────────\n const disabled = env[options.envNames.killSwitch] === 'off'\n const workspaceRoot = detectWorkspaceRoot(options.starterDir)\n if (workspaceRoot !== null) {\n console.log(\n `[starter] workspace checkout detected at ${workspaceRoot} — using plain resolution`,\n )\n env[options.envNames.bootMode] = 'workspace'\n options.loadEntry(options.seedEntry)\n return\n }\n if (disabled) {\n console.log(`[starter] ${options.envNames.killSwitch}=off — booting the baked seed closure`)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n return\n }\n\n // ── 2. Boot plan from the durable server-root state ─────────────────────\n const rootDir = serverRootDir(options.dataDir)\n const state = readServerRootState(rootDir)\n const nodeMajor =\n options.nodeMajor ?? Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n const isValidVersion = (version: string): boolean => {\n const reason = validateVersionDir(rootDir, version, nodeMajor, options.spec)\n if (reason !== null) console.warn(`[starter] version ${version} invalid: ${reason}`)\n return reason === null\n }\n\n const seedVersion = readSeedVersion(options.seedEntry)\n const plan = planBoot(state, isValidVersion, now, seedVersion)\n if (plan.stateToWrite !== null) {\n try {\n writeServerRootState(rootDir, plan.stateToWrite)\n } catch (err) {\n // A state write failure must not brick boot — fall back to the seed\n // (booting a probation version WITHOUT the durable attempt counter\n // would disarm the crash-loop rollback).\n console.error('[starter] FAILED to persist server-root state — booting baked seed:', err)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n return\n }\n if (\n plan.stateToWrite.rolledBack !== null &&\n (state?.rolledBack ?? null) !== plan.stateToWrite.rolledBack\n ) {\n const rb = plan.stateToWrite.rolledBack\n console.warn(\n `[starter] ROLLED BACK ${rb.fromVersion} -> ${rb.toVersion ?? 'baked seed'}: ${rb.reason}`,\n )\n }\n }\n\n // ── 3. Load the chosen closure ───────────────────────────────────────────\n if (plan.kind === 'data-root') {\n const activeRootDir = versionDir(rootDir, plan.version)\n const entry = rootEntryPath(activeRootDir, options.spec)\n console.log(\n `[starter] booting ${options.spec.packageName}@${plan.version} from ${activeRootDir}` +\n (plan.probation ? ' (probation boot — health-check armed)' : ''),\n )\n env[options.envNames.bootMode] = 'data-root'\n env[options.envNames.activeRoot] = activeRootDir\n env[options.envNames.activeVersion] = plan.version\n registerResolver(activeRootDir)\n options.loadEntry(entry)\n return\n }\n\n console.log(`[starter] booting baked seed closure (${plan.reason})`)\n env[options.envNames.bootMode] = 'baked'\n options.loadEntry(options.seedEntry)\n}\n","/**\n * RootUpdateService — the shared install/update/rollback engine for a node's\n * runtime-updatable ROOT package (`@camstack/server` on the hub,\n * `@camstack/agent` on agents). Phase 2 of the runtime-updatable node\n * packages design: the hub's `ServerUpdateService` and the agent's\n * `AgentUpdateService` are thin adapters over this one class, so the\n * security-review fixes (rollback reentrancy guards, fresh-transient prune\n * protection, corrupt-state visibility) exist in exactly one place.\n *\n * Responsibilities:\n * - stage a new `<pkg>@X` closure into\n * `<dataDir>/server-root/versions/<X>/` (npm install into a same-fs\n * staging dir + atomic rename activation),\n * - keep exactly one previous version (N-1) for rollback,\n * - drive the probation-boot protocol via the durable `state.json`\n * (`pendingBoot` armed here, consumed by the STARTER on the next boot,\n * promoted by `confirmBootHealthy()` once the node reaches ready),\n * - back the `server-management` cap methods on every node type.\n *\n * The starter core (starter-core.ts) owns the OTHER half: choosing the\n * closure at boot, bumping the probation counter, auto-rolling-back a\n * version whose probation boot never confirmed.\n *\n * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md\n */\nimport { execFile } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { promisify } from 'node:util'\nimport type {\n ServerBootMode,\n ServerPackageStatus,\n ServerUpdateActionResult,\n ServerUpdateCheckResult,\n ServerUpdateState,\n} from '@camstack/types'\nimport {\n DEV_UPLOADS_KEEP_COUNT,\n devChannelEpoch,\n devUploadVersionDir,\n devUploadsDir,\n isDevChannelVersion,\n readDevUploadManifest,\n} from './dev-uploads.js'\nimport type { RootPackageSpec } from './root-package-spec.js'\nimport { compareSemver } from './semver-compare.js'\nimport {\n emptyServerRootState,\n readServerRootState,\n rootEntryPath,\n rootPackageDir,\n serverRootDir,\n stateFilePath,\n validateVersionDir,\n versionDir,\n versionsDir,\n writeServerRootState,\n type ServerRootState,\n} from './root-state.js'\nimport { detectWorkspaceRoot } from './workspace-detect.js'\n\nconst execFileAsync = promisify(execFile)\n\n/** npm registry override args — mirrors addon-package.service (module-local there). */\nfunction buildNpmRegistryArgs(registry: string | undefined): readonly string[] {\n if (registry === undefined || registry.length === 0) return []\n return ['--registry', registry, `--@camstack:registry=${registry}`]\n}\n\nexport type NpmExecFn = (\n args: readonly string[],\n opts: { readonly cwd?: string; readonly timeoutMs: number },\n) => Promise<{ stdout: string }>\n\n/**\n * Structural logger surface — satisfied by the hub's `IScopedLogger` AND the\n * agent's console logger, without a runtime dependency on `@camstack/types`.\n */\nexport interface RootUpdateLogger {\n debug(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n info(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n warn(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n error(message: string, context?: { readonly meta?: Record<string, unknown> }): void\n}\n\n/** Per-node env-var names the update service reads (written by the starter). */\nexport interface RootUpdateEnvNames {\n /** `workspace` / `baked` / `data-root` marker set by the starter. */\n readonly bootMode: string\n /** Active data-root version (data-root boots only). */\n readonly activeVersion: string\n /** Directory of the immutable baked seed root package (image-set). */\n readonly seedDir: string\n}\n\nexport interface RootUpdateServiceOptions {\n readonly spec: RootPackageSpec\n readonly envNames: RootUpdateEnvNames\n readonly logger: RootUpdateLogger\n /** Graceful restart seam (hub: AddonPackageService.restartServer; agent: SIGTERM self). */\n readonly restartServer: (requestedBy: string) => void\n /** The node's resolved data dir (adapters own the per-node default). */\n readonly dataDir: string\n /** package.json of the RUNNING root-package copy (adapters own the default). */\n readonly runningPackageJsonPath: string\n /** Anchor for the boot-mode fallback classification (adapter `__dirname`). */\n readonly workspaceProbeDir: string\n /** Overrides for tests. */\n readonly execNpm?: NpmExecFn\n readonly env?: NodeJS.ProcessEnv\n readonly now?: () => number\n}\n\ninterface CheckCache {\n readonly latestVersion: string | null\n readonly checkedAtMs: number\n readonly error: string | null\n}\n\nconst NPM_VIEW_TIMEOUT_MS = 20_000\nconst NPM_INSTALL_TIMEOUT_MS = 15 * 60_000\nconst RESTART_REASON_PREFIX = 'server-update'\n\nfunction readPackageVersion(pkgJsonPath: string): string | null {\n try {\n const raw: unknown = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n if (typeof raw === 'object' && raw !== null) {\n const version = (raw as Record<string, unknown>)['version']\n if (typeof version === 'string') return version\n }\n } catch {\n // missing / malformed — treated as unknown\n }\n return null\n}\n\nexport class RootUpdateService {\n private readonly spec: RootPackageSpec\n private readonly envNames: RootUpdateEnvNames\n private readonly logger: RootUpdateLogger\n private readonly restartServerFn: (requestedBy: string) => void\n private readonly dataDir: string\n private readonly execNpm: NpmExecFn\n private readonly env: NodeJS.ProcessEnv\n private readonly now: () => number\n private readonly runningPackageJsonPath: string\n private readonly workspaceProbeDir: string\n\n private checkCache: CheckCache | null = null\n private inFlight: 'idle' | 'checking' | 'staging' = 'idle'\n\n constructor(options: RootUpdateServiceOptions) {\n this.spec = options.spec\n this.envNames = options.envNames\n this.logger = options.logger\n this.restartServerFn = options.restartServer\n this.dataDir = path.resolve(options.dataDir)\n this.execNpm =\n options.execNpm ??\n (async (args, opts) => {\n const { stdout } = await execFileAsync('npm', [...args], {\n cwd: opts.cwd,\n timeout: opts.timeoutMs,\n })\n return { stdout }\n })\n this.env = options.env ?? process.env\n this.now = options.now ?? Date.now\n this.runningPackageJsonPath = options.runningPackageJsonPath\n this.workspaceProbeDir = options.workspaceProbeDir\n }\n\n // ── Status ────────────────────────────────────────────────────────────\n\n resolveBootMode(): ServerBootMode {\n const raw = this.env[this.envNames.bootMode]\n if (raw === 'workspace' || raw === 'baked' || raw === 'data-root') return raw\n // The starter didn't run (dev tsx entry, `npm start`, or a pre-starter\n // image) — classify by checkout shape.\n return detectWorkspaceRoot(this.workspaceProbeDir) !== null ? 'workspace' : 'baked'\n }\n\n private runningVersion(): string | null {\n return readPackageVersion(this.runningPackageJsonPath)\n }\n\n /** The running root package's identity — feeds registerNode / topology rows. */\n getRunningRootPackage(): { readonly name: string; readonly version: string | null } {\n return { name: this.spec.packageName, version: this.runningVersion() }\n }\n\n private seedVersion(): string | null {\n const seedDir = this.env[this.envNames.seedDir]\n if (seedDir === undefined || seedDir.length === 0) return null\n return readPackageVersion(path.join(seedDir, 'package.json'))\n }\n\n private rootDir(): string {\n return serverRootDir(this.dataDir)\n }\n\n private readState(): ServerRootState {\n return readServerRootState(this.rootDir()) ?? emptyServerRootState()\n }\n\n /**\n * Like `readState`, but distinguishes \"state.json missing\" (normal on a\n * fresh node) from \"state.json present but corrupt\" — in the corrupt case\n * the starter booted the baked seed while installed data-dir versions are\n * silently ignored, which the status surface must make visible.\n */\n private readStateInfo(): { state: ServerRootState; corrupt: boolean } {\n const rootDir = this.rootDir()\n const raw = readServerRootState(rootDir)\n if (raw !== null) return { state: raw, corrupt: false }\n return { state: emptyServerRootState(), corrupt: fs.existsSync(stateFilePath(rootDir)) }\n }\n\n private updateState(state: ServerRootState): ServerUpdateState {\n if (this.inFlight === 'checking') return 'checking'\n if (this.inFlight === 'staging') return 'staging'\n if (state.pendingBoot !== null) {\n // Distinguish \"staged, not yet restarted\" (still on the OLD version)\n // from \"restarted onto the staged version, awaiting its boot-health\n // confirmation\" — the latter is the probation boot: apply/rollback are\n // refused and the node must not be manually restarted (security review\n // #2). We ARE the probation boot when the active version the starter\n // booted equals the pending version.\n const activeVersion = this.env[this.envNames.activeVersion] ?? null\n if (activeVersion !== null && activeVersion === state.pendingBoot.version) {\n return 'awaiting-confirmation'\n }\n return 'pending-restart'\n }\n return 'idle'\n }\n\n async getServerPackageStatus(): Promise<ServerPackageStatus> {\n const { state, corrupt } = this.readStateInfo()\n const runningVersion = this.runningVersion()\n const latestVersion = this.checkCache?.latestVersion ?? null\n const updateAvailable =\n latestVersion !== null &&\n runningVersion !== null &&\n compareSemver(latestVersion, runningVersion) > 0\n return {\n packageName: this.spec.packageName,\n runningVersion,\n nodeRuntimeVersion: process.versions.node,\n activeVersion: this.env[this.envNames.activeVersion] ?? state.currentVersion,\n previousVersion: state.previousVersion,\n seedVersion: this.seedVersion(),\n latestVersion,\n updateAvailable,\n bootMode: this.resolveBootMode(),\n updateState: this.updateState(state),\n pendingVersion: state.pendingBoot?.version ?? null,\n rolledBack: state.rolledBack,\n stateFileCorrupt: corrupt,\n lastCheckedAtMs: this.checkCache?.checkedAtMs ?? null,\n }\n }\n\n // ── Check ─────────────────────────────────────────────────────────────\n\n async checkServerUpdate(): Promise<ServerUpdateCheckResult> {\n const runningVersion = this.runningVersion()\n if (this.inFlight !== 'idle') {\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion: this.checkCache?.latestVersion ?? null,\n updateAvailable: false,\n checkedAtMs: this.checkCache?.checkedAtMs ?? this.now(),\n error: `busy: ${this.inFlight}`,\n }\n }\n this.inFlight = 'checking'\n try {\n const registry = this.env['CAMSTACK_NPM_REGISTRY']\n const args = [\n 'view',\n `${this.spec.packageName}@latest`,\n 'version',\n ...buildNpmRegistryArgs(registry),\n ]\n const { stdout } = await this.execNpm(args, { timeoutMs: NPM_VIEW_TIMEOUT_MS })\n const latestVersion = stdout.trim().length > 0 ? stdout.trim() : null\n this.checkCache = { latestVersion, checkedAtMs: this.now(), error: null }\n const updateAvailable =\n latestVersion !== null &&\n runningVersion !== null &&\n compareSemver(latestVersion, runningVersion) > 0\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion,\n updateAvailable,\n checkedAtMs: this.checkCache.checkedAtMs,\n error: null,\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.checkCache = {\n latestVersion: this.checkCache?.latestVersion ?? null,\n checkedAtMs: this.now(),\n error: message,\n }\n this.logger.warn('root package update check failed', { meta: { error: message } })\n return {\n packageName: this.spec.packageName,\n runningVersion,\n latestVersion: this.checkCache.latestVersion,\n updateAvailable: false,\n checkedAtMs: this.checkCache.checkedAtMs,\n error: message,\n }\n } finally {\n this.inFlight = 'idle'\n }\n }\n\n // ── Apply ─────────────────────────────────────────────────────────────\n\n async applyServerUpdate(input: { version?: string }): Promise<ServerUpdateActionResult> {\n const bootMode = this.resolveBootMode()\n if (bootMode === 'workspace') {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message:\n 'Refused: running from a workspace checkout — the dev loop resolves code from the ' +\n 'workspace, a data-root update would never be loaded.',\n }\n }\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const stateBefore = this.readState()\n if (stateBefore.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: input.version ?? null,\n restarting: false,\n message: `Refused: version ${stateBefore.pendingBoot.version} is already staged and awaiting restart.`,\n }\n }\n\n // Resolve the target version (explicit or latest from the registry).\n let target = input.version ?? null\n if (target === null) {\n const check = await this.checkServerUpdate()\n if (check.error !== null || check.latestVersion === null) {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: could not resolve the latest version (${check.error ?? 'no version returned'}).`,\n }\n }\n target = check.latestVersion\n }\n\n const runningVersion = this.runningVersion()\n if (target === runningVersion) {\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message: `Refused: ${this.spec.packageName}@${target} is already running.`,\n }\n }\n\n // Dev server-deploy channel boundary (phase 1: hub only). A `-dev.<epoch>`\n // version stages EXCLUSIVELY from tarballs previously uploaded to THIS\n // node's `server-root/dev-uploads/<version>/` — it never exists on the\n // npm registry, so a node without the uploads must fail loudly here\n // instead of timing out inside `npm install`.\n if (isDevChannelVersion(target)) {\n const uploadsDir = devUploadVersionDir(this.rootDir(), target)\n if (!fs.existsSync(uploadsDir)) {\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message:\n `Refused: dev-channel version ${target} has no uploaded tarballs on this node ` +\n `(${uploadsDir} is missing). Dev server deploys are hub-only in this phase — ` +\n `upload via \\`camstack deploy-server\\` against this node first.`,\n }\n }\n }\n\n this.inFlight = 'staging'\n try {\n await this.stageAndActivate(target)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n this.logger.error('root package update staging failed', {\n meta: { targetVersion: target, error: message },\n })\n return {\n accepted: false,\n targetVersion: target,\n restarting: false,\n message: `Staging failed: ${message}`,\n }\n } finally {\n this.inFlight = 'idle'\n }\n\n // Arm the probation boot + schedule the graceful restart.\n const state = this.readState()\n writeServerRootState(this.rootDir(), {\n ...state,\n pendingBoot: {\n version: target,\n fromVersion: state.currentVersion,\n requestedAtMs: this.now(),\n bootAttempts: 0,\n },\n rolledBack: null,\n })\n this.logger.info('root package update staged — restarting to apply', {\n meta: { targetVersion: target, fromVersion: state.currentVersion },\n })\n this.restartServerFn(`${RESTART_REASON_PREFIX}: ${this.spec.packageName}@${target}`)\n return {\n accepted: true,\n targetVersion: target,\n restarting: true,\n message: `Staged ${this.spec.packageName}@${target} — restarting to apply (probation boot with auto-rollback).`,\n }\n }\n\n /**\n * npm-install the target closure into a SAME-FS staging dir inside\n * `versions/`, validate it, then atomically rename it into place.\n */\n private async stageAndActivate(target: string): Promise<void> {\n const rootDir = this.rootDir()\n const vDir = versionsDir(rootDir)\n fs.mkdirSync(vDir, { recursive: true })\n const stagingDir = path.join(vDir, `.staging-${target}-${process.pid}-${this.now()}`)\n fs.mkdirSync(stagingDir, { recursive: true })\n\n try {\n // Dev server-deploy channel: when tarballs for `target` were uploaded to\n // `server-root/dev-uploads/<target>/`, stage from THEM instead of the\n // registry — a synthetic package.json depends on the root tgz via\n // `file:` and pins every other uploaded package through `overrides`, so\n // ANY transitive occurrence resolves to the uploaded copy. External deps\n // still come from npmjs / CAMSTACK_NPM_REGISTRY. Everything downstream\n // (entry check, version check, activation, probation) is unchanged.\n const devDir = devUploadVersionDir(rootDir, target)\n const registry = this.env['CAMSTACK_NPM_REGISTRY']\n const installArgs = ['install', '--omit=dev', '--no-audit', '--no-fund', '--loglevel=error']\n if (fs.existsSync(devDir)) {\n fs.writeFileSync(\n path.join(stagingDir, 'package.json'),\n JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2),\n 'utf-8',\n )\n await this.execNpm([...installArgs, ...buildNpmRegistryArgs(registry)], {\n cwd: stagingDir,\n timeoutMs: NPM_INSTALL_TIMEOUT_MS,\n })\n } else {\n fs.writeFileSync(\n path.join(stagingDir, 'package.json'),\n JSON.stringify({ name: 'camstack-node-root', private: true }, null, 2),\n 'utf-8',\n )\n await this.execNpm(\n [...installArgs, `${this.spec.packageName}@${target}`, ...buildNpmRegistryArgs(registry)],\n { cwd: stagingDir, timeoutMs: NPM_INSTALL_TIMEOUT_MS },\n )\n }\n\n const entry = rootEntryPath(stagingDir, this.spec)\n if (!fs.existsSync(entry)) {\n throw new Error(`staged closure is missing the root entry (${entry})`)\n }\n const stagedVersion = readPackageVersion(\n path.join(rootPackageDir(stagingDir, this.spec), 'package.json'),\n )\n if (stagedVersion !== target) {\n throw new Error(\n `staged closure version mismatch: expected ${target}, got ${stagedVersion ?? 'unknown'}`,\n )\n }\n\n // Activate: evict any existing dir for this version, then atomic rename.\n const dest = versionDir(rootDir, target)\n if (fs.existsSync(dest)) {\n const aside = `${dest}.evicted-${this.now()}`\n await fs.promises.rename(dest, aside)\n await fs.promises.rm(aside, { recursive: true, force: true }).catch(() => undefined)\n }\n await fs.promises.rename(stagingDir, dest)\n } catch (err) {\n await fs.promises.rm(stagingDir, { recursive: true, force: true }).catch(() => undefined)\n throw err\n }\n }\n\n /**\n * Synthetic staging package.json for the dev server-deploy channel:\n * `dependencies` carries the root package as a `file:` ref to its uploaded\n * tgz; `overrides` maps EVERY OTHER uploaded `@camstack/<name>` to its tgz\n * so any transitive occurrence resolves to the uploaded copy, never npm.\n * Fail-closed: a missing/invalid manifest, a manifest for a different\n * version, a missing root package, or a listed-but-absent tgz all throw\n * (surfaced by `applyServerUpdate` as a staging failure).\n */\n private buildDevUploadsPackageJson(\n devDir: string,\n target: string,\n ): {\n readonly name: string\n readonly private: true\n readonly dependencies: Readonly<Record<string, string>>\n readonly overrides?: Readonly<Record<string, string>>\n } {\n const manifest = readDevUploadManifest(devDir)\n if (manifest === null) {\n throw new Error(`dev-uploads manifest missing or invalid in ${devDir}`)\n }\n if (manifest.version !== target) {\n throw new Error(\n `dev-uploads manifest version mismatch: dir is for ${target}, manifest says ${manifest.version}`,\n )\n }\n const rootTgz = manifest.packages[this.spec.packageName]\n if (rootTgz === undefined) {\n throw new Error(\n `dev-uploads for ${target} do not include the root package ${this.spec.packageName}`,\n )\n }\n const fileRef = (filename: string): string => {\n const abs = path.join(devDir, filename)\n if (!fs.existsSync(abs)) {\n throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`)\n }\n return `file:${abs}`\n }\n const overrides: Record<string, string> = {}\n for (const [pkgName, filename] of Object.entries(manifest.packages)) {\n if (pkgName === this.spec.packageName) continue\n overrides[pkgName] = fileRef(filename)\n }\n return {\n name: 'camstack-node-root',\n private: true,\n dependencies: { [this.spec.packageName]: fileRef(rootTgz) },\n ...(Object.keys(overrides).length > 0 ? { overrides } : {}),\n }\n }\n\n // ── Rollback ──────────────────────────────────────────────────────────\n\n async rollbackServerUpdate(): Promise<ServerUpdateActionResult> {\n // Same reentrancy/precondition guards as applyServerUpdate: without them a\n // rollback racing an armed update (10s restart grace) silently overwrites\n // pendingBoot — last write wins with no error to the loser.\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const state = this.readState()\n if (state.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: null,\n restarting: false,\n message: `Refused: version ${state.pendingBoot.version} is already staged and awaiting restart.`,\n }\n }\n if (state.currentVersion === null || state.previousVersion === null) {\n return {\n accepted: false,\n targetVersion: state.previousVersion,\n restarting: false,\n message: 'Refused: no previous version available to roll back to.',\n }\n }\n const nodeMajor = Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n const invalidReason = validateVersionDir(\n this.rootDir(),\n state.previousVersion,\n nodeMajor,\n this.spec,\n )\n if (invalidReason !== null) {\n return {\n accepted: false,\n targetVersion: state.previousVersion,\n restarting: false,\n message: `Refused: previous version ${state.previousVersion} is not loadable (${invalidReason}).`,\n }\n }\n\n writeServerRootState(this.rootDir(), {\n ...state,\n pendingBoot: {\n version: state.previousVersion,\n fromVersion: state.currentVersion,\n requestedAtMs: this.now(),\n bootAttempts: 0,\n },\n })\n this.logger.info('root package rollback requested — restarting', {\n meta: { fromVersion: state.currentVersion, toVersion: state.previousVersion },\n })\n this.restartServerFn(\n `${RESTART_REASON_PREFIX}: rollback to ${this.spec.packageName}@${state.previousVersion}`,\n )\n return {\n accepted: true,\n targetVersion: state.previousVersion,\n restarting: true,\n message: `Rolling back to ${this.spec.packageName}@${state.previousVersion} — restarting.`,\n }\n }\n\n // ── Plain restart ─────────────────────────────────────────────────────\n\n /**\n * Plain process restart — no version change. Backs the `restartServer` cap\n * method. Guards mirror apply/rollback: refuse while a stage is in flight\n * (a concurrent npm install must not be interrupted) or while a version is\n * already staged awaiting restart (a naive bounce would boot the OLD version\n * and orphan the pending one — the operator should apply/rollback instead).\n */\n restartNode(): ServerUpdateActionResult {\n const runningVersion = this.runningVersion()\n if (this.inFlight !== 'idle') {\n return {\n accepted: false,\n targetVersion: runningVersion,\n restarting: false,\n message: `Refused: another operation is in flight (${this.inFlight}).`,\n }\n }\n const state = this.readState()\n if (state.pendingBoot !== null) {\n return {\n accepted: false,\n targetVersion: runningVersion,\n restarting: false,\n message: `Refused: version ${state.pendingBoot.version} is staged and awaiting restart — apply or roll it back instead of a plain restart.`,\n }\n }\n this.logger.info('plain node restart requested', { meta: { runningVersion } })\n this.restartServerFn(`${RESTART_REASON_PREFIX}: manual restart`)\n return {\n accepted: true,\n targetVersion: runningVersion,\n restarting: true,\n message: 'Restarting the node — the supervisor relaunches it on the same version.',\n }\n }\n\n // ── Boot health confirmation ──────────────────────────────────────────\n\n /**\n * Called by the post-boot path once the node is READY (hub: post-boot\n * pipeline; agent: first acked `$hub.registerNode`). When THIS process is\n * the probation boot of a pending version, promote it: `currentVersion` ←\n * pending, `previousVersion` ← the version it replaced (N-1 retained for\n * rollback), clear `pendingBoot` + `rolledBack`, and prune every version\n * dir beyond {current, previous}. No-op otherwise.\n */\n confirmBootHealthy(): { promoted: string | null } {\n const state = readServerRootState(this.rootDir())\n if (state === null || state.pendingBoot === null) return { promoted: null }\n\n const activeVersion = this.env[this.envNames.activeVersion] ?? null\n if (activeVersion !== state.pendingBoot.version) {\n // We are NOT the probation boot of this pending version (e.g. the\n // starter never ran, or it booted a different closure). Leave the\n // marker for the starter's own rollback logic.\n return { promoted: null }\n }\n\n const promoted: ServerRootState = {\n ...state,\n currentVersion: state.pendingBoot.version,\n previousVersion: state.pendingBoot.fromVersion,\n pendingBoot: null,\n rolledBack: null,\n }\n writeServerRootState(this.rootDir(), promoted)\n this.pruneVersions(\n [promoted.currentVersion, promoted.previousVersion].filter(\n (v): v is string => typeof v === 'string',\n ),\n )\n this.sweepDevUploads(DEV_UPLOADS_KEEP_COUNT)\n this.logger.info('root package update confirmed healthy', {\n meta: {\n version: promoted.currentVersion,\n previousVersion: promoted.previousVersion,\n },\n })\n return { promoted: promoted.currentVersion }\n }\n\n /**\n * Remove version dirs under `versions/` not in `keep`.\n *\n * Transient dot-entries (`.staging-*` / `.evicted-*`) are NOT pruned unless\n * older than {@link RootUpdateService.STALE_TRANSIENT_MS}: the API starts\n * serving BEFORE the post-boot `confirmBootHealthy()` runs, so a concurrent\n * `applyServerUpdate` can be mid-npm-install into a fresh `.staging-*` dir\n * when this prune fires — deleting it would corrupt that install. Fresh\n * transient dirs are owned by their in-flight operation (which cleans up on\n * failure); the staleness sweep only collects dirs orphaned by a crash.\n */\n private pruneVersions(keep: readonly string[]): void {\n const vDir = versionsDir(this.rootDir())\n let entries: string[]\n try {\n entries = fs.readdirSync(vDir)\n } catch {\n return\n }\n for (const entry of entries) {\n if (keep.includes(entry)) continue\n const full = path.join(vDir, entry)\n if (entry.startsWith('.')) {\n try {\n const ageMs = this.now() - fs.statSync(full).mtimeMs\n if (ageMs < RootUpdateService.STALE_TRANSIENT_MS) continue\n } catch {\n // stat failed (already gone / unreadable) — skip it\n continue\n }\n }\n try {\n fs.rmSync(full, { recursive: true, force: true })\n this.logger.debug('pruned server-root version dir', { meta: { entry } })\n } catch (err) {\n this.logger.warn('failed to prune server-root version dir', {\n meta: { entry, error: err instanceof Error ? err.message : String(err) },\n })\n }\n }\n }\n\n /**\n * Promote-time sweep of `server-root/dev-uploads/`: keep only the\n * `keepCount` most recent entries (ordered by the self-describing\n * `-dev.<epochSeconds>` suffix; non-dev-shaped residue counts as oldest).\n * Uses the same rename-aside graveyard pattern as the addon installer —\n * a rename is a metadata op that succeeds even when a tarball is held\n * open, and residue in the graveyard is re-swept on the next promote.\n */\n private sweepDevUploads(keepCount: number): void {\n const dir = devUploadsDir(this.rootDir())\n let entries: string[]\n try {\n entries = fs.readdirSync(dir)\n } catch {\n return // no dev-uploads dir — nothing to sweep\n }\n const graveyard = path.join(dir, '.sweeping')\n // Best-effort collect residue left behind by an earlier sweep first.\n try {\n for (const residue of fs.readdirSync(graveyard)) {\n try {\n fs.rmSync(path.join(graveyard, residue), { recursive: true, force: true })\n } catch {\n /* still held open — retried on the next promote */\n }\n }\n } catch {\n /* graveyard absent — nothing to collect */\n }\n\n const versions = entries.filter((name) => !name.startsWith('.'))\n const byNewestFirst = [...versions].sort(\n (a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1),\n )\n const doomed = byNewestFirst.slice(keepCount)\n if (doomed.length === 0) return\n fs.mkdirSync(graveyard, { recursive: true })\n for (const entry of doomed) {\n const aside = path.join(graveyard, `${entry}-${this.now()}`)\n try {\n fs.renameSync(path.join(dir, entry), aside)\n } catch (err) {\n this.logger.warn('failed to move dev-uploads entry aside for sweep', {\n meta: { entry, error: err instanceof Error ? err.message : String(err) },\n })\n continue\n }\n try {\n fs.rmSync(aside, { recursive: true, force: true })\n this.logger.debug('swept dev-uploads entry', { meta: { entry } })\n } catch {\n /* held open — the aside copy is collected on the next promote */\n }\n }\n }\n\n /** Transient (.staging- / .evicted-) dirs younger than this are never pruned. */\n private static readonly STALE_TRANSIENT_MS = 24 * 60 * 60 * 1000\n}\n","/**\n * AGENT STARTER — the tiny, immutable, dependency-free entry baked into the\n * agent image (and, in phase 3, spawned by the Electron shell). Everything\n * above it (the agent CLI, framework, addons) is runtime-updatable; the\n * starter itself can NEVER self-update — a new image is the only way to\n * change it, which is why it must stay deliberately dumb.\n *\n * The boot flow is the SHARED node-root core (`runNodeStarter`, bundled into\n * this file by tsup — see tsup.config.ts): workspace defer → durable boot\n * plan (probation counter / auto-rollback / validity fallback) → the\n * host-external resolver hooks anchored in the active root → load the chosen\n * closure. This file only binds the agent's names: `@camstack/agent`,\n * `dist/cli.js`, the `CAMSTACK_AGENT_*` env markers and the\n * `CAMSTACK_DATA_DIR` / `--data` data dir.\n *\n * Layout mirror of the hub:\n * <agentDataDir>/server-root/versions/<semver>/node_modules/@camstack/agent/dist/cli.js\n * <agentDataDir>/server-root/state.json\n *\n * Console usage is intentional: the starter runs before any logging exists.\n */\nimport { existsSync } from 'node:fs'\nimport * as path from 'node:path'\nimport { AGENT_ROOT_SPEC, runNodeStarter } from '@camstack/node-root'\n\n/**\n * Resolve the agent data dir the way the CLI will (`CAMSTACK_DATA_DIR` env\n * wins, then `--data`/`-d` argv, then `./camstack-data`). The starter runs\n * BEFORE the CLI parses argv, so it mirrors the flag inline — otherwise an\n * operator running `camstack-agent --data /x` would get the server-root in a\n * different data dir than the agent itself.\n */\nfunction resolveAgentDataDir(argv: readonly string[], env: NodeJS.ProcessEnv): string {\n const fromEnv = env['CAMSTACK_DATA_DIR']\n if (fromEnv !== undefined && fromEnv.length > 0) return path.resolve(fromEnv)\n for (let i = 2; i < argv.length - 1; i++) {\n if (argv[i] === '--data' || argv[i] === '-d') {\n const next = argv[i + 1]\n if (next !== undefined && !next.startsWith('-')) return path.resolve(next)\n }\n }\n return path.resolve('camstack-data')\n}\n\n/**\n * Restart-policy dependency warning (security review #3). `server-management`\n * apply/rollback = graceful exit + supervisor relaunch. Without an\n * always-relaunching restart policy (docker: `unless-stopped`/`always`) a node\n * that exits to apply an update simply STAYS DOWN. No code can enforce the\n * policy — make the dependency visible at boot. Diagnostic only.\n */\nfunction warnRestartPolicyDependency(): void {\n if (!existsSync('/.dockerenv')) return\n console.warn(\n '[starter] container detected — server-management apply/rollback exit this ' +\n 'process for the supervisor to relaunch. Ensure the container restart policy is ' +\n \"'unless-stopped' or 'always', otherwise an update/rollback leaves the node down.\",\n )\n}\n\nfunction start(): void {\n warnRestartPolicyDependency()\n\n const seedPackageDir = path.resolve(__dirname, '..')\n if (process.env['CAMSTACK_SEED_AGENT_DIR'] === undefined) {\n process.env['CAMSTACK_SEED_AGENT_DIR'] = seedPackageDir\n }\n\n runNodeStarter({\n spec: AGENT_ROOT_SPEC,\n envNames: {\n bootMode: 'CAMSTACK_AGENT_BOOT_MODE',\n activeRoot: 'CAMSTACK_AGENT_ACTIVE_ROOT',\n activeVersion: 'CAMSTACK_AGENT_ACTIVE_VERSION',\n killSwitch: 'CAMSTACK_AGENT_ROOT',\n },\n dataDir: resolveAgentDataDir(process.argv, process.env),\n seedEntry: path.join(__dirname, 'cli.js'),\n starterDir: __dirname,\n // The CLI is CJS (tsup build) — a plain require keeps the starter\n // synchronous; the CLI reads the SAME process.argv it always did.\n loadEntry: (entryPath) => require(entryPath),\n })\n}\n\ntry {\n start()\n} catch (err) {\n console.error('[starter] FATAL:', err)\n process.exit(1)\n}\n"],"mappings":"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","names":["AGENT_ROOT_SPEC","runNodeStarter","module","__toESM","path","fs","path2"]}
package/dist/starter.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  __require,
4
4
  __toESM,
5
5
  require_dist
6
- } from "./chunk-Y6BUFOWG.mjs";
6
+ } from "./chunk-KPUXW5YX.mjs";
7
7
 
8
8
  // src/starter.ts
9
9
  var import_node_root = __toESM(require_dist());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/agent",
3
- "version": "1.1.49",
3
+ "version": "1.1.51",
4
4
  "description": "CamStack remote agent — standalone Moleculer node for distributed addon execution",
5
5
  "keywords": [
6
6
  "camstack",
@@ -33,13 +33,13 @@
33
33
  "start": "node dist/cli.js"
34
34
  },
35
35
  "dependencies": {
36
- "@camstack/system": "1.1.47",
37
- "@camstack/types": "1.1.42",
38
- "@camstack/sdk": "1.1.23",
39
- "@camstack/shm-ring": "1.0.22",
40
- "@camstack/addon-pipeline": "1.1.54",
41
- "@camstack/addon-decoder-nodeav": "1.1.10",
42
- "@camstack/addon-agent-ui": "1.1.22",
36
+ "@camstack/system": "1.1.50",
37
+ "@camstack/types": "1.1.45",
38
+ "@camstack/sdk": "1.1.24",
39
+ "@camstack/shm-ring": "1.0.23",
40
+ "@camstack/addon-pipeline": "1.1.57",
41
+ "@camstack/addon-decoder-nodeav": "1.1.12",
42
+ "@camstack/addon-agent-ui": "1.1.23",
43
43
  "fastify": "^5",
44
44
  "@fastify/static": "^9.1.3",
45
45
  "@fastify/cors": "^11.2.0",