{"version":3,"file":"index.cjs","names":["wantsHelp","doctorHelp","os","path","resolveDoomConfigurationRoot","loadDoomConfig","loadMajorModesConfig","missingLayerPackageSpecifiers","createLayerResolvers","readLocatedSyncState","parseHarnessArgs","selectionEnvironment","loadDomains","collectDrift","toSelection","selectionCompositionFingerprint"],"sources":["../../../../src/cli/commands/doctor/index.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\n\nimport { loadDomains } from '@agimon-ai/doompi-config/domains';\nimport { loadMajorModesConfig } from '@agimon-ai/doompi-config/majorModes';\n\nimport { createLayerResolvers } from '../../../builders/cli/extensionAssembler';\nimport { missingLayerPackageSpecifiers } from '../../../composition/layerPackageInstaller';\nimport { loadDoomConfig } from '../../../composition/projectTrust';\nimport { resolveDoomConfigurationRoot } from '../../../composition/repository';\nimport { readLocatedSyncState } from '../../../composition/syncState';\nimport { parseHarnessArgs } from '../../options';\nimport { wantsHelp } from '../../router';\nimport { collectDrift, selectionCompositionFingerprint, selectionEnvironment, toSelection } from '../sync';\nimport { doctorHelp } from './help';\n\nconst DOCTOR_COMMAND = 'doctor';\nconst HARNESS_ROOT_ENV = 'DOOMPI_ROOT';\nconst LABEL_WIDTH = 14;\n\nexport interface DoctorOutput {\n  write(chunk: string): void;\n}\n\n/** One checked area and what it found. Empty problems means the section passed. */\ninterface Section {\n  label: string;\n  problems: string[];\n}\n\nfunction formatSection(section: Section): string {\n  const label = section.label.padEnd(LABEL_WIDTH);\n  if (section.problems.length === 0) return `${label}ok\\n`;\n  return `${label}${section.problems.length === 1 ? 'FAILED' : `${String(section.problems.length)} problem(s)`}\\n${section.problems\n    .map((problem) => `  ${problem}\\n`)\n    .join('')}`;\n}\n\nfunction messageOf(error: unknown): string {\n  return error instanceof Error ? error.message : String(error);\n}\n\n/** Runs one check, turning the throw a strict parser uses into a reported problem. */\nfunction check(run: () => void): string[] {\n  try {\n    run();\n    return [];\n  } catch (error) {\n    return [messageOf(error)];\n  }\n}\n\n/**\n * Reports what is wrong with a DoomPi installation without changing anything.\n *\n * The strict counterpart to `doompi sync`, which tolerates unknown config keys\n * so a build cannot break over one. Everything `sync --check` reports is\n * reported here too, so this is the one command to run when something is off.\n */\nexport function runDoctor(\n  args: string[],\n  environment: NodeJS.ProcessEnv = process.env,\n  currentDirectory = process.cwd(),\n  output: DoctorOutput = process.stdout,\n): number {\n  if (wantsHelp(args.slice(1))) {\n    output.write(doctorHelp());\n    return 0;\n  }\n  const homeDirectory = environment.HOME ?? os.homedir();\n  const inheritedRoot = environment[HARNESS_ROOT_ENV];\n  const repoRoot = inheritedRoot\n    ? path.resolve(inheritedRoot)\n    : resolveDoomConfigurationRoot(currentDirectory, homeDirectory);\n\n  const sections: Section[] = [\n    { label: 'config.yaml', problems: check(() => loadDoomConfig(repoRoot)) },\n    { label: 'modes.yaml', problems: check(() => loadMajorModesConfig(repoRoot, homeDirectory)) },\n  ];\n  // Everything below reads the resolved composition, which cannot be trusted\n  // while either file is still unreadable.\n  const configurationIsSound = sections.every((section) => section.problems.length === 0);\n  if (configurationIsSound)\n    sections.push(...installationSectionsDoctor(repoRoot, homeDirectory, environment, currentDirectory));\n\n  for (const section of sections) output.write(formatSection(section));\n  const problems = sections.reduce((total, section) => total + section.problems.length, 0);\n  if (problems === 0) {\n    output.write('\\nno problems found\\n');\n    return 0;\n  }\n  output.write(`\\n${String(problems)} problem(s) found\\n`);\n  return 1;\n}\n\nfunction installationSectionsDoctor(\n  repoRoot: string,\n  homeDirectory: string,\n  environment: NodeJS.ProcessEnv,\n  currentDirectory: string,\n): Section[] {\n  const majorModesConfig = loadMajorModesConfig(repoRoot, homeDirectory);\n  const packages = missingLayerPackageSpecifiers(\n    majorModesConfig,\n    Object.keys(majorModesConfig.layers),\n    createLayerResolvers(repoRoot),\n  ).map((specifier) => `configured package is not installed: ${specifier}`);\n\n  let state: Awaited<ReturnType<typeof readLocatedSyncState>>;\n  try {\n    state = readLocatedSyncState(repoRoot, homeDirectory);\n  } catch (error) {\n    return [\n      { label: 'packages', problems: packages },\n      { label: 'sync state', problems: [messageOf(error)] },\n    ];\n  }\n\n  const parsed = parseHarnessArgs(\n    [],\n    selectionEnvironment(repoRoot, environment),\n    currentDirectory,\n    majorModesConfig.defaultMajorMode,\n    loadDomains(repoRoot, homeDirectory).defaultDomains,\n  );\n  const drift = collectDrift(\n    repoRoot,\n    toSelection(parsed.options),\n    state?.state,\n    environment,\n    'persisted',\n    selectionCompositionFingerprint(repoRoot, parsed.options, homeDirectory),\n  );\n  return [\n    { label: 'packages', problems: packages },\n    { label: 'sync state', problems: [] },\n    { label: 'drift', problems: drift },\n  ];\n}\n\n/** Compatibility API. Executables call the command function directly. */\nexport class DoctorCommand {\n  readonly name = DOCTOR_COMMAND;\n\n  matches(args: string[]): boolean {\n    return args[0] === this.name;\n  }\n\n  execute(\n    args: string[],\n    environment: NodeJS.ProcessEnv = process.env,\n    currentDirectory = process.cwd(),\n    output: DoctorOutput = process.stdout,\n  ): number {\n    return runDoctor(args, environment, currentDirectory, output);\n  }\n}\n"],"mappings":"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"}