{"version":3,"file":"runSingleHarness.cjs","names":["findDefaultStdioHarnessFiles","fs","path","child_process","readTestCases","judgesWithoutTestCases","readProblemMarkdownFrontMatter","stdioJudgePreset","stdioDebugPreset"],"sources":["../../src/cli/runSingleHarness.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { stdioDebugPreset, stdioJudgePreset } from '../presets/stdio.js';\n\nexport const MISSING_TEST_CASES_ERROR =\n  'a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired';\n\n/**\n * Run the judge or debug harness of the problem in the current working directory: a custom\n * `judge.ts` / `debug.ts` when present, or the default stdio preset otherwise (mirroring the\n * Exercode server, which applies the stdio presets to problems without these files).\n */\nexport async function runSingleHarness(kind: 'judge' | 'debug'): Promise<number> {\n  const problemDir = process.cwd();\n\n  const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n  if (defaultHarnessFileNames.length > 0) {\n    console.error(formatDefaultHarnessError(defaultHarnessFileNames));\n    return 1;\n  }\n\n  const harnessFileName = kind === 'judge' ? 'judge.ts' : 'debug.ts';\n  if (fs.existsSync(path.join(problemDir, harnessFileName))) {\n    // process.execPath keeps the harness on the same bun executable regardless of PATH.\n    const spawnResult = child_process.spawnSync(process.execPath, ['run', harnessFileName, ...process.argv.slice(2)], {\n      cwd: problemDir,\n      stdio: 'inherit',\n    });\n    if (spawnResult.error) {\n      console.error(`failed to run ${harnessFileName}: ${spawnResult.error.message}`);\n      return 1;\n    }\n    return spawnResult.status ?? 1;\n  }\n\n  // A custom judge.ts marks the problem as non-standard, so the stdio debug preset would judge the\n  // answer against a contract the problem does not have (mirroring the server, which reports debug\n  // as unsupported in this case).\n  if (kind === 'debug' && fs.existsSync(path.join(problemDir, 'judge.ts'))) {\n    console.error('This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.');\n    return 1;\n  }\n\n  // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n  // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n  // unless static-analysis rules or manual scoring make the problem judgeable without them.\n  if (kind === 'judge') {\n    const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n    if (testCases.length === 0 && !judgesWithoutTestCases(await readProblemMarkdownFrontMatter(problemDir))) {\n      console.error(MISSING_TEST_CASES_ERROR);\n      return 1;\n    }\n  }\n\n  // The presets read the answer directory and params from `process.argv`, which holds them at the\n  // same positions as when a harness script is invoked directly.\n  await (kind === 'judge' ? stdioJudgePreset(problemDir) : stdioDebugPreset(problemDir));\n  return 0;\n}\n\nexport function formatDefaultHarnessError(defaultHarnessFileNames: readonly string[]): string {\n  const fileNames = defaultHarnessFileNames.join(' and ');\n  return `${fileNames} must not be committed because the content is identical to the default stdio harness.\nA problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,\nso delete ${fileNames} and run the problem with \\`bun x exercode-problem judge <answerDir>\\` or \\`bun x exercode-problem debug <answerDir>\\`.\nIf the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`;\n}\n"],"mappings":"ucASA,MAAa,EACX,6KAOF,eAAsB,EAAiB,EAA0C,CAC/E,IAAM,EAAa,QAAQ,IAAI,EAEzB,EAA0B,MAAMA,EAAAA,6BAA6B,CAAU,EAC7E,GAAI,EAAwB,OAAS,EAEnC,OADA,QAAQ,MAAM,EAA0B,CAAuB,CAAC,EACzD,EAGT,IAAM,EAAkB,IAAS,QAAU,WAAa,WACxD,GAAIC,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,CAAe,CAAC,EAAG,CAEzD,IAAM,EAAcC,EAAAA,QAAc,UAAU,QAAQ,SAAU,CAAC,MAAO,EAAiB,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAG,CAChH,IAAK,EACL,MAAO,SACT,CAAC,EAKD,OAJI,EAAY,OACd,QAAQ,MAAM,iBAAiB,EAAgB,IAAI,EAAY,MAAM,SAAS,EACvE,GAEF,EAAY,QAAU,CAC/B,CAwBA,OAnBI,IAAS,SAAWF,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,UAAU,CAAC,GACrE,QAAQ,MAAM,0FAA0F,EACjG,GAML,IAAS,UAEP,MADoBE,EAAAA,cAAcF,EAAAA,QAAK,KAAK,EAAY,YAAY,CAAC,EAAA,CAC3D,SAAW,GAAK,CAACG,EAAAA,uBAAuB,MAAMC,EAAAA,+BAA+B,CAAU,CAAC,GACpG,QAAQ,MAAM,CAAwB,EAC/B,IAMX,MAAO,IAAS,QAAUC,EAAAA,iBAAiB,CAAU,EAAIC,EAAAA,iBAAiB,CAAU,GAC7E,EACT,CAEA,SAAgB,EAA0B,EAAoD,CAC5F,IAAM,EAAY,EAAwB,KAAK,OAAO,EACtD,MAAO,GAAG,EAAU;;YAEV,EAAU;6GAEtB"}