{"version":3,"file":"workflow.mjs","names":[],"sources":["../../../../src/cli/commands/sync/workflow.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\n\nimport { loadMajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\nimport type { HarnessTelemetry } from '@agimon-ai/doompi-core/runtime-log-sink-telemetry';\nimport { acquireSyncLocationLock, resolveSyncLocation } from '@agimon-ai/doompi-core/sync-location';\n\nimport { ensureLayerPackages, type LayerPackageResult } from '../../../composition/layerPackageInstaller';\nimport { readSyncDrift } from '../../../composition/syncDrift';\nimport { wantsHelp } from '../../router';\nimport { syncHelp } from './help';\nimport { resolveSyncRoots, synchronize, syncRegistrationNeedsApiMigration, type SyncSettingsMode } from './index';\nimport { prepareSync } from './prepare';\nimport { SyncProgress, type SyncProgressOutput } from './presenter';\n\nconst CHECK_OPTION = '--check';\n/** Rebuilds and republishes even when nothing drifted. */\nconst FORCE_OPTION = '--force';\nconst PACKAGES_LABEL = 'packages';\nconst BUILD_LABEL = 'build';\n\nexport interface SyncPipelineOptions {\n  settingsMode?: SyncSettingsMode;\n  telemetry?: HarnessTelemetry;\n}\n\nfunction pluralize(count: number, noun: string): string {\n  return `${String(count)} ${noun}${count === 1 ? '' : 's'}`;\n}\n\nfunction packageSummary(result: LayerPackageResult): string {\n  const parts: string[] = [];\n  if (result.updated.length > 0) parts.push(`updated ${pluralize(result.updated.length, 'package')}`);\n  if (result.installed.length > 0) parts.push(`installed ${pluralize(result.installed.length, 'missing package')}`);\n  if (parts.length === 0) parts.push('already up to date');\n  if (result.unchecked.length > 0) parts.push(`${pluralize(result.unchecked.length, 'package')} left unchecked`);\n  return parts.join(', ');\n}\n\n/** Refreshes packages, runs the private cache build, then commits the synchronized state. */\nexport async function runSync(\n  args: string[],\n  environment: NodeJS.ProcessEnv = process.env,\n  currentDirectory = process.cwd(),\n  output: SyncProgressOutput = process.stdout,\n  options: SyncPipelineOptions = {},\n): Promise<number> {\n  // Before the --check split, so both `sync --help` and `sync --check --help`\n  // print instead of running a sync nobody asked for.\n  if (wantsHelp(args)) {\n    output.write(syncHelp());\n    return 0;\n  }\n  if (args.includes(CHECK_OPTION)) {\n    return synchronize(args, environment, currentDirectory, output, {\n      settingsMode: options.settingsMode ?? 'persisted',\n    });\n  }\n\n  const homeDirectory = environment.HOME ?? os.homedir();\n  const roots = resolveSyncRoots(args, environment, currentDirectory, homeDirectory);\n  const { globalOnly, globalRoot, sourceRoot, targetRoot } = roots;\n  const promotingWorkspacePackages = globalOnly && path.resolve(sourceRoot) !== path.resolve(globalRoot);\n\n  // Nothing drifted means the packages are current, the mode extension is\n  // compiled from these exact bytes, and the published generation already\n  // describes them. Refreshing and rebuilding anyway costs seconds per call\n  // and, worse, ends in a republished generation that reloads every attached\n  // cockpit for no change at all. The cockpit calls this before every session\n  // launch, so the cheap answer has to be the common one. A workspace-to-global\n  // promotion is the exception: global runtime inputs do not include the\n  // workspace package selection.\n  const driftOptions = {\n    repoRoot: targetRoot,\n    homeDirectory,\n    requireWebBundle: Boolean(environment.DOOMPI_WEB_PACKAGE_ROOT),\n  };\n  if (\n    !promotingWorkspacePackages &&\n    !args.includes(FORCE_OPTION) &&\n    !syncRegistrationNeedsApiMigration(targetRoot, homeDirectory) &&\n    readSyncDrift(driftOptions).fresh\n  ) {\n    output.write('doompi sync is already up to date\\n');\n    return 0;\n  }\n\n  const releaseLock = await acquireSyncLocationLock(resolveSyncLocation(targetRoot, homeDirectory));\n  try {\n    const progress = new SyncProgress(output);\n    if (promotingWorkspacePackages) {\n      await refreshPackages(sourceRoot, targetRoot, homeDirectory, environment, progress);\n      // --global from a workspace only promotes packages. The workspace owns\n      // configuration; publishing a global runtime would change personal state.\n      return 0;\n    }\n\n    // A concurrent publisher may have resolved the drift while this command\n    // waited for the lock. Do not rebuild and republish the same generation.\n    if (\n      !args.includes(FORCE_OPTION) &&\n      !syncRegistrationNeedsApiMigration(targetRoot, homeDirectory) &&\n      readSyncDrift(driftOptions).fresh\n    ) {\n      output.write('doompi sync is already up to date\\n');\n      return 0;\n    }\n    await refreshPackages(sourceRoot, targetRoot, homeDirectory, environment, progress);\n\n    const captured: string[] = [];\n    const done = progress.start(BUILD_LABEL, 'compiling the mode extension');\n    const buildCode = await prepareSync(\n      args,\n      environment,\n      currentDirectory,\n      {\n        write: (chunk: unknown) => {\n          captured.push(String(chunk));\n          return true;\n        },\n      },\n      options.telemetry,\n    );\n    if (buildCode !== 0) {\n      done('failed');\n      output.write(captured.join(''));\n      return buildCode;\n    }\n    done('mode extension compiled');\n\n    return await synchronize(args, environment, currentDirectory, output, {\n      settingsMode: options.settingsMode ?? 'persisted',\n      homeDirectory,\n      lockHeld: true,\n    });\n  } finally {\n    await releaseLock();\n  }\n}\n/** Moves every package sync owns to its newest published version. */\nasync function refreshPackages(\n  sourceRoot: string,\n  targetRoot: string,\n  homeDirectory: string,\n  environment: NodeJS.ProcessEnv,\n  progress: SyncProgress,\n): Promise<void> {\n  const config = loadMajorModesConfig(sourceRoot, homeDirectory);\n  const done = progress.start(PACKAGES_LABEL, 'checking configured packages for updates');\n  const result = await ensureLayerPackages({\n    // Configuration may come from a workspace while the managed store belongs\n    // to the global destination during an explicit promotion.\n    repoRoot: targetRoot,\n    config,\n    // Every declared layer, not only the selected one: sync writes the state a\n    // later /mode switch reads without reinstalling.\n    layers: Object.keys(config.layers),\n    environment,\n    refresh: true,\n    onProgress: (message) => progress.line(PACKAGES_LABEL, message),\n  });\n  done(packageSummary(result));\n}\n"],"mappings":"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"}