{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/composition/syncDrift/index.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { parseCompiledContracts } from '@agimon-ai/doompi-core/api-contracts';\nimport { parseDoomMcpBundle } from '@agimon-ai/doompi-core/mcp-facet';\nimport { parseDoomServerBundle } from '@agimon-ai/doompi-core/server-facet';\nimport { readSyncRegistration, type SyncRegistration } from '@agimon-ai/doompi-core/sync-registration';\n\nimport { readStartupBootstrapStatus, readBootstrapStatus } from '../../builders/cli/bootstrapLocator';\nimport { inputsAreFresh, parseInputFingerprint } from '../../compiler/inputs';\nimport {\n  computeInputsHash,\n  computeMcpSourcesHash,\n  computeServerSourcesHash,\n  computeWebSourcesHash,\n  readSyncState,\n  type SyncState,\n} from '../syncState';\n\nexport type SyncDriftReason =\n  | 'never-synced'\n  | 'configuration-changed'\n  | 'code-changed'\n  | 'runtime-stale'\n  | 'cockpit-bundle-missing'\n  | 'package-apis-missing'\n  | 'server-bundle-stale'\n  | 'mcp-bundle-stale';\n\nexport interface SyncDrift {\n  /** True when nothing needs syncing before a session starts. */\n  fresh: boolean;\n  reasons: SyncDriftReason[];\n  /** The recorded inputs hash, for a caller that wants to log what moved. */\n  recordedInputsHash?: string;\n  currentInputsHash?: string;\n}\n\nexport interface ReadSyncDriftOptions {\n  repoRoot: string;\n  /** Launcher-owned Doom entry used to build this repository's generated bootstrap. */\n  expectedBootstrapEntry?: string;\n  homeDirectory?: string;\n  /** Web hosts cannot reuse a CLI-only generation without plugin artifacts. */\n  requireWebBundle?: boolean;\n  /** Ignore producer source drift while retaining generation and artifact checks. */\n  requireFreshSources?: boolean;\n}\n\nfunction artifactReceiptIsIntact(receipt: Record<string, unknown>, inside: (target: string) => boolean): boolean {\n  if (\n    typeof receipt.output !== 'string' ||\n    !Array.isArray(receipt.artifacts) ||\n    !Array.isArray(receipt.artifactInputs)\n  ) {\n    return false;\n  }\n  if (receipt.artifactInputs.length === 0 || receipt.artifacts.some((file) => typeof file !== 'string')) return false;\n  const expected = new Set([receipt.output, ...(receipt.artifacts as string[])].map((file) => fs.realpathSync(file)));\n  const seen = new Set<string>();\n  for (const value of receipt.artifactInputs) {\n    const input = parseInputFingerprint(value);\n    if (!input || !/^[a-f0-9]{64}$/u.test(input.sha256) || !inside(input.path)) return false;\n    const target = fs.realpathSync(input.path);\n    if (!expected.has(target)) return false;\n    const stat = fs.statSync(target);\n    if (!stat.isFile() || stat.size !== input.size) return false;\n    if (crypto.createHash('sha256').update(fs.readFileSync(target)).digest('hex') !== input.sha256) return false;\n    seen.add(target);\n  }\n  return seen.size === expected.size;\n}\n\nfunction serverBundleIsUsable(\n  state: Pick<SyncState, 'serverBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'serverBundle'>,\n  requireFreshSources: boolean,\n): boolean {\n  const bundle = state.serverBundle;\n  if (!bundle || !registration.serverBundle) return false;\n  try {\n    if (requireFreshSources && bundle.sourcesHash !== computeServerSourcesHash(state.resolved)) return false;\n    const descriptorPath = fs.realpathSync(bundle.descriptorPath);\n    if (descriptorPath !== fs.realpathSync(registration.serverBundle.path)) return false;\n    const descriptor = parseDoomServerBundle(JSON.parse(fs.readFileSync(descriptorPath, 'utf8')));\n    if (descriptor.generation !== registration.generation || descriptor.fingerprint !== bundle.fingerprint)\n      return false;\n\n    const root = fs.realpathSync(registration.generationRoot);\n    const inside = (target: string) => {\n      const relative = path.relative(root, fs.realpathSync(target));\n      return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n    };\n    if (!descriptor.contracts) return false;\n    const contractFile = path.resolve(path.dirname(descriptorPath), descriptor.contracts.file);\n    if (!inside(contractFile)) return false;\n    const bytes = fs.readFileSync(contractFile);\n    if (crypto.createHash('sha256').update(bytes).digest('hex') !== descriptor.contracts.sha256) return false;\n    const contracts = parseCompiledContracts(JSON.parse(bytes.toString('utf8')));\n    if (contracts.generation !== descriptor.generation || contracts.fingerprint !== descriptor.fingerprint)\n      return false;\n    const outputs = [\n      ...descriptor.entries.map((entry) => ({ key: entry.packageName, module: entry.module })),\n      ...contracts.packages.flatMap((entry) =>\n        entry.module ? [{ key: `${entry.packageName}#contracts`, module: entry.module }] : [],\n      ),\n    ];\n    if (Object.keys(bundle.compilerManifests).length !== outputs.length) return false;\n    for (const entry of outputs) {\n      const manifestPath = bundle.compilerManifests[entry.key];\n      if (!manifestPath || !inside(manifestPath)) return false;\n      const receipt = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as Record<string, unknown>;\n      if (\n        typeof receipt.output !== 'string' ||\n        !inside(receipt.output) ||\n        fs.realpathSync(receipt.output) !== fs.realpathSync(path.resolve(path.dirname(descriptorPath), entry.module)) ||\n        !Array.isArray(receipt.artifacts) ||\n        !receipt.artifacts.every((file) => typeof file === 'string' && inside(file))\n      )\n        return false;\n      const inputs = Array.isArray(receipt.inputs) ? receipt.inputs.map(parseInputFingerprint) : [];\n      if (inputs.length === 0 || inputs.some((input) => input === undefined)) return false;\n      if (requireFreshSources && !inputsAreFresh(inputs as NonNullable<(typeof inputs)[number]>[])) return false;\n      if (!artifactReceiptIsIntact(receipt, inside)) return false;\n    }\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/** Validate direct-module receipts without importing candidates or loading the compiler. */\nexport function serverBundleIsFresh(\n  state: Pick<SyncState, 'serverBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'serverBundle'>,\n): boolean {\n  return serverBundleIsUsable(state, registration, true);\n}\n\n/** Validate generated server artifacts while allowing the producer source to drift. */\nexport function serverBundleIsRuntimeUsable(\n  state: Pick<SyncState, 'serverBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'serverBundle'>,\n): boolean {\n  return serverBundleIsUsable(state, registration, false);\n}\n\nfunction mcpBundleIsUsable(\n  state: Pick<SyncState, 'mcpBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'mcpBundle'>,\n  requireFreshSources: boolean,\n): boolean {\n  const bundle = state.mcpBundle;\n  if (!bundle || !registration.mcpBundle) return false;\n  try {\n    if (requireFreshSources && bundle.sourcesHash !== computeMcpSourcesHash(state.resolved)) return false;\n    const descriptorPath = fs.realpathSync(bundle.descriptorPath);\n    if (descriptorPath !== fs.realpathSync(registration.mcpBundle.path)) return false;\n    const descriptorBytes = fs.readFileSync(descriptorPath);\n    if (crypto.createHash('sha256').update(descriptorBytes).digest('hex') !== registration.mcpBundle.sha256)\n      return false;\n    const descriptor = parseDoomMcpBundle(JSON.parse(descriptorBytes.toString('utf8')));\n    if (\n      descriptor.generation !== registration.generation ||\n      descriptor.fingerprint !== bundle.fingerprint ||\n      descriptor.fingerprint !== registration.mcpBundle.fingerprint\n    )\n      return false;\n\n    const root = fs.realpathSync(registration.generationRoot);\n    const inside = (target: string) => {\n      const relative = path.relative(root, fs.realpathSync(target));\n      return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n    };\n    if (Object.keys(bundle.compilerManifests).length !== descriptor.entries.length) return false;\n    for (const entry of descriptor.entries) {\n      const manifestPath = bundle.compilerManifests[entry.packageName];\n      if (!manifestPath || !inside(manifestPath)) return false;\n      const receipt = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as Record<string, unknown>;\n      const modulePath = path.resolve(path.dirname(descriptorPath), entry.module);\n      if (\n        typeof receipt.output !== 'string' ||\n        !inside(receipt.output) ||\n        fs.realpathSync(receipt.output) !== fs.realpathSync(modulePath) ||\n        crypto.createHash('sha256').update(fs.readFileSync(modulePath)).digest('hex') !== entry.sha256 ||\n        !Array.isArray(receipt.artifacts) ||\n        !receipt.artifacts.every((file) => typeof file === 'string' && inside(file))\n      )\n        return false;\n      const inputs = Array.isArray(receipt.inputs) ? receipt.inputs.map(parseInputFingerprint) : [];\n      if (inputs.length === 0 || inputs.some((input) => input === undefined)) return false;\n      if (requireFreshSources && !inputsAreFresh(inputs as NonNullable<(typeof inputs)[number]>[])) return false;\n      if (!artifactReceiptIsIntact(receipt, inside)) return false;\n    }\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/** Validate MCP source inputs, descriptor identity, and compiler artifact receipts. */\nexport function mcpBundleIsFresh(\n  state: Pick<SyncState, 'mcpBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'mcpBundle'>,\n): boolean {\n  return mcpBundleIsUsable(state, registration, true);\n}\n\n/** Validate admitted MCP artifacts while allowing producer sources to drift. */\nexport function mcpBundleIsRuntimeUsable(\n  state: Pick<SyncState, 'mcpBundle' | 'resolved'>,\n  registration: Pick<SyncRegistration, 'generation' | 'generationRoot' | 'mcpBundle'>,\n): boolean {\n  return mcpBundleIsUsable(state, registration, false);\n}\n\n/**\n * Whether this repository is synced for the composition it would launch.\n *\n * Sync produces three things a session or the cockpit reads later: the\n * resolved composition, the plugin bundle the browser loads, and the package\n * API routes each host mounts. A session started against any of them stale\n * runs, but quietly wrong: the cockpit shows no plugin surfaces and package\n * APIs answer nothing, with nothing in the log to say why.\n *\n * The hash is the one sync already records. It covers every `.doom` document\n * in both the repository and the home directory, the MCP configuration, the\n * plugin catalogue, and each profile's persona files, so an edit to any of\n * them reads as drift without this having to know what changed.\n */\nexport function readSyncDrift(options: ReadSyncDriftOptions): SyncDrift {\n  const homeDirectory = options.homeDirectory ?? os.homedir();\n  const requireFreshSources = options.requireFreshSources ?? true;\n  const reasons: SyncDriftReason[] = [];\n\n  let state: SyncState | undefined;\n  let registration: ReturnType<typeof readSyncRegistration>;\n  try {\n    registration = readSyncRegistration(options.repoRoot, homeDirectory);\n    state = registration ? readSyncState(options.repoRoot, homeDirectory) : undefined;\n  } catch {\n    // Unreadable or invalid registration is indistinguishable from absent for\n    // this purpose: the next session needs a sync before it can be trusted.\n    state = undefined;\n    registration = undefined;\n  }\n  if (!state || !registration) return { fresh: false, reasons: ['never-synced'] };\n\n  let currentInputsHash: string | undefined;\n  try {\n    currentInputsHash = computeInputsHash(options.repoRoot, state.selection, homeDirectory);\n  } catch {\n    // A malformed document cannot be hashed, and syncing is what reports it.\n    reasons.push('configuration-changed');\n  }\n  if (currentInputsHash !== undefined && currentInputsHash !== state.inputsHash) {\n    reasons.push('configuration-changed');\n  }\n  // Cockpit sources are compiled straight from each package's web/ folder, so a\n  // rebuilt plugin surface is a real change that no configuration hash sees. A\n  // state recorded before this was tracked has nothing to compare and is left\n  // alone rather than being called stale on sight.\n  if (\n    requireFreshSources &&\n    state.webSourcesHash !== undefined &&\n    computeWebSourcesHash(state.resolved) !== state.webSourcesHash\n  ) {\n    reasons.push('code-changed');\n  }\n  // The same question the `--check` path asks, so the cockpit and the CLI\n  // cannot disagree about whether one repository is synced.\n  try {\n    const bootstrapStatus = requireFreshSources\n      ? readBootstrapStatus(options.repoRoot, options.expectedBootstrapEntry, homeDirectory)\n      : readStartupBootstrapStatus(options.repoRoot, options.expectedBootstrapEntry, homeDirectory);\n    if (!bootstrapStatus.fresh) reasons.push('runtime-stale');\n  } catch {\n    // An unreadable bootstrap record is exactly as unusable as a stale one, and\n    // syncing is what reports the underlying cause.\n    reasons.push('runtime-stale');\n  }\n  if (\n    (registration.webDirectory === null && options.requireWebBundle) ||\n    (registration.webDirectory !== null &&\n      (!fs.existsSync(path.join(registration.webDirectory, 'index.html')) ||\n        !fs.existsSync(path.join(path.dirname(registration.webDirectory), 'plugins', 'composition.js')) ||\n        !fs.existsSync(path.join(path.dirname(registration.webDirectory), 'plugins', 'manifest.json'))))\n  ) {\n    reasons.push('cockpit-bundle-missing');\n  }\n  if (!fs.existsSync(registration.apiDirectory)) reasons.push('package-apis-missing');\n  if (\n    !(requireFreshSources ? serverBundleIsFresh(state, registration) : serverBundleIsRuntimeUsable(state, registration))\n  )\n    reasons.push('server-bundle-stale');\n  if (!(requireFreshSources ? mcpBundleIsFresh(state, registration) : mcpBundleIsRuntimeUsable(state, registration)))\n    reasons.push('mcp-bundle-stale');\n\n  return {\n    fresh: reasons.length === 0,\n    reasons,\n    recordedInputsHash: state.inputsHash,\n    ...(currentInputsHash === undefined ? {} : { currentInputsHash }),\n  };\n}\n\n/** A one-line account of what drifted, for a log the person running the hub reads. */\nexport function describeSyncDrift(drift: SyncDrift): string {\n  if (drift.fresh) return 'the repository is synced';\n  const detail: Record<SyncDriftReason, string> = {\n    'never-synced': 'it has never been synced',\n    'configuration-changed': 'its configuration changed since the last sync',\n    'code-changed': 'its cockpit sources changed since the last sync',\n    'runtime-stale': 'its precompiled runtime is out of date',\n    'cockpit-bundle-missing': 'the cockpit bundle is missing',\n    'package-apis-missing': 'the package API routes are missing',\n    'server-bundle-stale': 'its server bundle is missing or out of date',\n    'mcp-bundle-stale': 'its MCP bundle is missing or out of date',\n  };\n  return drift.reasons.map((reason) => detail[reason]).join(', ');\n}\n"],"mappings":"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"}