@dailephd/my-dev-kit-lab 0.2.0

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.
Files changed (250) hide show
  1. package/README.md +272 -0
  2. package/benchmarks/contracts/benchmark-project-profiles.json +1199 -0
  3. package/benchmarks/contracts/todo-behavior.md +70 -0
  4. package/benchmarks/contracts/todo-benchmark-case.json +227 -0
  5. package/benchmarks/projects/README.md +34 -0
  6. package/benchmarks/projects/task-analytics-large-mixed/README.md +1 -0
  7. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/__init__.py +3 -0
  8. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/fixtures.py +6 -0
  9. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/metrics.py +29 -0
  10. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/models.py +21 -0
  11. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/parser.py +16 -0
  12. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/pipeline.py +9 -0
  13. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/quality.py +8 -0
  14. package/benchmarks/projects/task-analytics-large-mixed/py/task_analytics/reporting.py +11 -0
  15. package/benchmarks/projects/task-analytics-large-mixed/py/tests/test_metrics.py +19 -0
  16. package/benchmarks/projects/task-analytics-large-mixed/py/tests/test_parser.py +15 -0
  17. package/benchmarks/projects/task-analytics-large-mixed/py/tests/test_quality.py +19 -0
  18. package/benchmarks/projects/task-analytics-large-mixed/py/tests/test_reporting.py +15 -0
  19. package/benchmarks/projects/task-analytics-large-mixed/ts/package.json +12 -0
  20. package/benchmarks/projects/task-analytics-large-mixed/ts/src/index.ts +11 -0
  21. package/benchmarks/projects/task-analytics-large-mixed/ts/src/models/analyticsSnapshot.ts +20 -0
  22. package/benchmarks/projects/task-analytics-large-mixed/ts/src/models/project.ts +5 -0
  23. package/benchmarks/projects/task-analytics-large-mixed/ts/src/models/task.ts +10 -0
  24. package/benchmarks/projects/task-analytics-large-mixed/ts/src/reporting/buildProjectLeaderboard.ts +7 -0
  25. package/benchmarks/projects/task-analytics-large-mixed/ts/src/reporting/formatTaskHealthReport.ts +13 -0
  26. package/benchmarks/projects/task-analytics-large-mixed/ts/src/services/buildAnalyticsSnapshot.ts +39 -0
  27. package/benchmarks/projects/task-analytics-large-mixed/ts/src/services/completeTask.ts +10 -0
  28. package/benchmarks/projects/task-analytics-large-mixed/ts/src/services/createTask.ts +21 -0
  29. package/benchmarks/projects/task-analytics-large-mixed/ts/src/services/listTasksByProject.ts +6 -0
  30. package/benchmarks/projects/task-analytics-large-mixed/ts/src/store/projectStore.ts +20 -0
  31. package/benchmarks/projects/task-analytics-large-mixed/ts/src/store/taskStore.ts +44 -0
  32. package/benchmarks/projects/task-analytics-large-mixed/ts/src/validation/projectValidation.ts +12 -0
  33. package/benchmarks/projects/task-analytics-large-mixed/ts/src/validation/taskValidation.ts +18 -0
  34. package/benchmarks/projects/task-analytics-large-mixed/ts/tests/buildAnalyticsSnapshot.test.ts +48 -0
  35. package/benchmarks/projects/task-analytics-large-mixed/ts/tests/completeTask.test.ts +21 -0
  36. package/benchmarks/projects/task-analytics-large-mixed/ts/tests/createTask.test.ts +31 -0
  37. package/benchmarks/projects/task-analytics-large-mixed/ts/tests/listTasksByProject.test.ts +18 -0
  38. package/benchmarks/projects/task-analytics-large-mixed/ts/tests/reporting.test.ts +19 -0
  39. package/benchmarks/projects/task-analytics-large-mixed/ts/tsconfig.json +12 -0
  40. package/benchmarks/projects/task-analytics-large-mixed/ts/vitest.config.ts +5 -0
  41. package/benchmarks/projects/task-workflow-medium-ts/README.md +1 -0
  42. package/benchmarks/projects/task-workflow-medium-ts/package.json +12 -0
  43. package/benchmarks/projects/task-workflow-medium-ts/src/index.ts +9 -0
  44. package/benchmarks/projects/task-workflow-medium-ts/src/models/project.ts +6 -0
  45. package/benchmarks/projects/task-workflow-medium-ts/src/models/task.ts +39 -0
  46. package/benchmarks/projects/task-workflow-medium-ts/src/services/completeTask.ts +15 -0
  47. package/benchmarks/projects/task-workflow-medium-ts/src/services/createTask.ts +26 -0
  48. package/benchmarks/projects/task-workflow-medium-ts/src/services/filterTasks.ts +17 -0
  49. package/benchmarks/projects/task-workflow-medium-ts/src/services/importTasks.ts +33 -0
  50. package/benchmarks/projects/task-workflow-medium-ts/src/services/summarizeTasks.ts +30 -0
  51. package/benchmarks/projects/task-workflow-medium-ts/src/store/taskStore.ts +76 -0
  52. package/benchmarks/projects/task-workflow-medium-ts/src/utils/deterministicId.ts +3 -0
  53. package/benchmarks/projects/task-workflow-medium-ts/src/validation/taskValidation.ts +45 -0
  54. package/benchmarks/projects/task-workflow-medium-ts/tests/completeTask.test.ts +16 -0
  55. package/benchmarks/projects/task-workflow-medium-ts/tests/createTask.test.ts +21 -0
  56. package/benchmarks/projects/task-workflow-medium-ts/tests/filterTasks.test.ts +18 -0
  57. package/benchmarks/projects/task-workflow-medium-ts/tests/importTasks.test.ts +22 -0
  58. package/benchmarks/projects/task-workflow-medium-ts/tests/summarizeTasks.test.ts +29 -0
  59. package/benchmarks/projects/task-workflow-medium-ts/tsconfig.json +12 -0
  60. package/benchmarks/projects/task-workflow-medium-ts/vitest.config.ts +5 -0
  61. package/benchmarks/projects/todo-js/README.md +3 -0
  62. package/benchmarks/projects/todo-js/package.json +11 -0
  63. package/benchmarks/projects/todo-js/src/index.js +2 -0
  64. package/benchmarks/projects/todo-js/src/taskService.js +37 -0
  65. package/benchmarks/projects/todo-js/src/taskStore.js +28 -0
  66. package/benchmarks/projects/todo-js/tests/taskService.test.js +45 -0
  67. package/benchmarks/projects/todo-js/vitest.config.js +5 -0
  68. package/benchmarks/projects/todo-mixed-ts-py/README.md +3 -0
  69. package/benchmarks/projects/todo-mixed-ts-py/package.json +13 -0
  70. package/benchmarks/projects/todo-mixed-ts-py/python/task_service.py +76 -0
  71. package/benchmarks/projects/todo-mixed-ts-py/src/taskCli.ts +38 -0
  72. package/benchmarks/projects/todo-mixed-ts-py/tests/mixedBoundary.test.ts +18 -0
  73. package/benchmarks/projects/todo-mixed-ts-py/tsconfig.json +12 -0
  74. package/benchmarks/projects/todo-mixed-ts-py/vitest.config.ts +5 -0
  75. package/benchmarks/projects/todo-python/README.md +3 -0
  76. package/benchmarks/projects/todo-python/src/__init__.py +4 -0
  77. package/benchmarks/projects/todo-python/src/task_service.py +32 -0
  78. package/benchmarks/projects/todo-python/src/task_store.py +28 -0
  79. package/benchmarks/projects/todo-python/tests/test_task_service.py +52 -0
  80. package/benchmarks/projects/todo-ts/README.md +3 -0
  81. package/benchmarks/projects/todo-ts/package.json +12 -0
  82. package/benchmarks/projects/todo-ts/src/index.ts +2 -0
  83. package/benchmarks/projects/todo-ts/src/taskService.ts +41 -0
  84. package/benchmarks/projects/todo-ts/src/taskStore.ts +34 -0
  85. package/benchmarks/projects/todo-ts/tests/taskService.test.ts +45 -0
  86. package/benchmarks/projects/todo-ts/tsconfig.json +12 -0
  87. package/benchmarks/projects/todo-ts/vitest.config.ts +5 -0
  88. package/dist/scripts/build-gallery.js +3 -0
  89. package/dist/scripts/capture-demo-report.js +3 -0
  90. package/dist/scripts/evaluate-token-savings.js +2 -0
  91. package/dist/scripts/experiments/describeExperiment.js +143 -0
  92. package/dist/scripts/experiments/listExperiments.js +44 -0
  93. package/dist/scripts/experiments/runExperiment.js +199 -0
  94. package/dist/scripts/generate-experiment-plots.js +3 -0
  95. package/dist/scripts/generate-prompt-variants.js +2 -0
  96. package/dist/scripts/render-experiment-report.js +2 -0
  97. package/dist/scripts/run-agent-prompt.js +2 -0
  98. package/dist/scripts/run-controlled-experiment.js +2 -0
  99. package/dist/scripts/run-final-demo.js +3 -0
  100. package/dist/scripts/run-lab-demo.js +5 -0
  101. package/dist/scripts/run-visualization-demos.js +3 -0
  102. package/dist/scripts/security/runCodeql.js +57 -0
  103. package/dist/scripts/security/runDependencyChecks.js +57 -0
  104. package/dist/scripts/security/runFuzzSmoke.js +29 -0
  105. package/dist/scripts/security/runPackageChecks.js +56 -0
  106. package/dist/scripts/security/runSemgrep.js +63 -0
  107. package/dist/scripts/security/validate.js +117 -0
  108. package/dist/scripts/verify-benchmarks.js +202 -0
  109. package/dist/src/agents/adapters/claudeAdapter.js +37 -0
  110. package/dist/src/agents/adapters/codexAdapter.js +110 -0
  111. package/dist/src/agents/adapters/fakeAgentAdapter.js +101 -0
  112. package/dist/src/agents/agentRegistry.js +21 -0
  113. package/dist/src/agents/index.js +7 -0
  114. package/dist/src/agents/parseAgentTokenUsage.js +137 -0
  115. package/dist/src/agents/runAgentPrompt.js +38 -0
  116. package/dist/src/agents/types.js +1 -0
  117. package/dist/src/commands/buildGalleryCommand.js +56 -0
  118. package/dist/src/commands/captureDemoReport.js +116 -0
  119. package/dist/src/commands/evaluateTokenSavings.js +175 -0
  120. package/dist/src/commands/generateExperimentPlotsCommand.js +38 -0
  121. package/dist/src/commands/generatePromptVariants.js +67 -0
  122. package/dist/src/commands/renderExperimentReportCommand.js +131 -0
  123. package/dist/src/commands/runAgentPromptCommand.js +132 -0
  124. package/dist/src/commands/runControlledExperimentCommand.js +174 -0
  125. package/dist/src/commands/runFinalDemoCommand.js +123 -0
  126. package/dist/src/commands/runLabDemo.js +62 -0
  127. package/dist/src/commands/runVisualizationDemosCommand.js +67 -0
  128. package/dist/src/core/commandLine.js +59 -0
  129. package/dist/src/core/countTokens.js +8 -0
  130. package/dist/src/core/fileGlobs.js +100 -0
  131. package/dist/src/core/localProjectTarget.js +75 -0
  132. package/dist/src/core/pathSafety.js +19 -0
  133. package/dist/src/core/pythonCommand.js +30 -0
  134. package/dist/src/core/resolveCommand.js +110 -0
  135. package/dist/src/core/runMeasuredCommand.js +143 -0
  136. package/dist/src/evaluation/benchmarkMetadata.js +207 -0
  137. package/dist/src/evaluation/buildExperimentMatrix.js +75 -0
  138. package/dist/src/evaluation/classifyAgentRunOutcome.js +40 -0
  139. package/dist/src/evaluation/compareExperimentRuns.js +79 -0
  140. package/dist/src/evaluation/compareTokenSavings.js +47 -0
  141. package/dist/src/evaluation/controlledExperimentTypes.js +1 -0
  142. package/dist/src/evaluation/index.js +18 -0
  143. package/dist/src/evaluation/parseAgentAnswer.js +230 -0
  144. package/dist/src/evaluation/projectComplexity.js +126 -0
  145. package/dist/src/evaluation/projectFileTree.js +83 -0
  146. package/dist/src/evaluation/readEvaluationCases.js +59 -0
  147. package/dist/src/evaluation/renderTokenSavingsReportInput.js +55 -0
  148. package/dist/src/evaluation/runControlledExperiment.js +158 -0
  149. package/dist/src/evaluation/runMyDevKitRetrieval.js +197 -0
  150. package/dist/src/evaluation/runRawFullFileBaseline.js +31 -0
  151. package/dist/src/evaluation/scoreCorrectness.js +127 -0
  152. package/dist/src/evaluation/types.js +1 -0
  153. package/dist/src/evaluation/writeExperimentArtifacts.js +104 -0
  154. package/dist/src/evaluation/writeTokenSavingsArtifacts.js +57 -0
  155. package/dist/src/experiments/config.js +24 -0
  156. package/dist/src/experiments/defaultRegistry.js +7 -0
  157. package/dist/src/experiments/errors.js +18 -0
  158. package/dist/src/experiments/index.js +9 -0
  159. package/dist/src/experiments/outputPaths.js +25 -0
  160. package/dist/src/experiments/plugins/contextStrategyComparison/config.js +37 -0
  161. package/dist/src/experiments/plugins/contextStrategyComparison/index.js +3 -0
  162. package/dist/src/experiments/plugins/contextStrategyComparison/plugin.js +83 -0
  163. package/dist/src/experiments/plugins/contextStrategyComparison/resultMapping.js +260 -0
  164. package/dist/src/experiments/plugins/index.js +1 -0
  165. package/dist/src/experiments/registry.js +43 -0
  166. package/dist/src/experiments/results.js +48 -0
  167. package/dist/src/experiments/runner.js +181 -0
  168. package/dist/src/experiments/target.js +8 -0
  169. package/dist/src/experiments/types.js +1 -0
  170. package/dist/src/gallery/index.js +2 -0
  171. package/dist/src/gallery/types.js +1 -0
  172. package/dist/src/gallery/writeGalleryManifest.js +214 -0
  173. package/dist/src/index.js +12 -0
  174. package/dist/src/plots/buildExperimentPlotData.js +137 -0
  175. package/dist/src/plots/index.js +4 -0
  176. package/dist/src/plots/renderSvgChart.js +82 -0
  177. package/dist/src/plots/types.js +1 -0
  178. package/dist/src/plots/writePlotArtifacts.js +46 -0
  179. package/dist/src/prompts/buildPromptContext.js +68 -0
  180. package/dist/src/prompts/generateMyDevKitPrompt.js +106 -0
  181. package/dist/src/prompts/generatePromptVariants.js +36 -0
  182. package/dist/src/prompts/generateRawFullFilePrompt.js +97 -0
  183. package/dist/src/prompts/index.js +7 -0
  184. package/dist/src/prompts/measurePromptComplexity.js +41 -0
  185. package/dist/src/prompts/types.js +1 -0
  186. package/dist/src/prompts/writePromptArtifacts.js +43 -0
  187. package/dist/src/report/buildExperimentReportInput.js +339 -0
  188. package/dist/src/report/experimentReportTypes.js +1 -0
  189. package/dist/src/report/experiments/buildPluginExperimentReport.js +153 -0
  190. package/dist/src/report/experiments/experimentReportModel.js +1 -0
  191. package/dist/src/report/experiments/index.js +4 -0
  192. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +133 -0
  193. package/dist/src/report/experiments/writePluginExperimentReports.js +30 -0
  194. package/dist/src/report/index.js +8 -0
  195. package/dist/src/report/renderExperimentHtmlReport.js +354 -0
  196. package/dist/src/report/renderHtmlReport.js +103 -0
  197. package/dist/src/report/types.js +10 -0
  198. package/dist/src/report/writeExperimentReportArtifacts.js +38 -0
  199. package/dist/src/report/writeReportArtifacts.js +39 -0
  200. package/dist/src/screenshot/captureReportScreenshot.js +75 -0
  201. package/dist/src/screenshot/index.js +2 -0
  202. package/dist/src/screenshot/types.js +1 -0
  203. package/dist/src/securityValidation/artifacts.js +15 -0
  204. package/dist/src/securityValidation/cliAdversarial/adversarialCliConfig.js +38 -0
  205. package/dist/src/securityValidation/cliAdversarial/dataVolumeChecks.js +194 -0
  206. package/dist/src/securityValidation/cliAdversarial/jsonStdoutChecks.js +359 -0
  207. package/dist/src/securityValidation/cliAdversarial/malformedArtifactChecks.js +284 -0
  208. package/dist/src/securityValidation/cliAdversarial/malformedArtifactFixtures.js +79 -0
  209. package/dist/src/securityValidation/cliAdversarial/pathBoundaryChecks.js +431 -0
  210. package/dist/src/securityValidation/cliAdversarial/pathCases.js +144 -0
  211. package/dist/src/securityValidation/cliAdversarial/readOnlyBoundaryChecks.js +294 -0
  212. package/dist/src/securityValidation/cliAdversarial/runAdversarialCheck.js +149 -0
  213. package/dist/src/securityValidation/cliAdversarial/subprocessSafetyChecks.js +214 -0
  214. package/dist/src/securityValidation/cliAdversarial/tempWorkspace.js +160 -0
  215. package/dist/src/securityValidation/commandRunner.js +136 -0
  216. package/dist/src/securityValidation/config.js +39 -0
  217. package/dist/src/securityValidation/dependencies/parseNpmAudit.js +115 -0
  218. package/dist/src/securityValidation/dependencies/parseNpmLs.js +71 -0
  219. package/dist/src/securityValidation/dependencies/parseNpmOutdated.js +41 -0
  220. package/dist/src/securityValidation/dependencies/runDependencyChecks.js +239 -0
  221. package/dist/src/securityValidation/dependencies/runOsvScanner.js +43 -0
  222. package/dist/src/securityValidation/fuzz/fuzzHarness.js +61 -0
  223. package/dist/src/securityValidation/fuzz/fuzzTargets.js +204 -0
  224. package/dist/src/securityValidation/fuzz/randomInput.js +0 -0
  225. package/dist/src/securityValidation/index.js +34 -0
  226. package/dist/src/securityValidation/packageChecks/forbiddenPackageContents.js +67 -0
  227. package/dist/src/securityValidation/packageChecks/parseNpmPackDryRun.js +56 -0
  228. package/dist/src/securityValidation/packageChecks/runPackageChecks.js +88 -0
  229. package/dist/src/securityValidation/report/renderSecurityReport.js +248 -0
  230. package/dist/src/securityValidation/report/securityReportTypes.js +1 -0
  231. package/dist/src/securityValidation/staticScans/codeql.js +66 -0
  232. package/dist/src/securityValidation/staticScans/semgrep.js +180 -0
  233. package/dist/src/securityValidation/testMatrix.js +535 -0
  234. package/dist/src/securityValidation/types.js +34 -0
  235. package/dist/src/securityValidation/validate/resolveTarget.js +32 -0
  236. package/dist/src/securityValidation/validate/runSecurityValidation.js +169 -0
  237. package/dist/src/securityValidation/validate/verdict.js +73 -0
  238. package/dist/src/visualizationDemos/buildMyDevKitVisualizationCommands.js +59 -0
  239. package/dist/src/visualizationDemos/index.js +4 -0
  240. package/dist/src/visualizationDemos/runVisualizationDemos.js +82 -0
  241. package/dist/src/visualizationDemos/types.js +1 -0
  242. package/dist/src/visualizationDemos/writeVisualizationDemoArtifacts.js +25 -0
  243. package/docs/METRICS.md +286 -0
  244. package/examples/demo-report-input.json +78 -0
  245. package/examples/lab-demo-cases.json +35 -0
  246. package/examples/real-agent-campaign-cases.json +118 -0
  247. package/examples/token-savings-cases.json +122 -0
  248. package/package.json +91 -0
  249. package/tests/fixtures/fake-adversarial-cli.js +152 -0
  250. package/tests/fixtures/fake-my-dev-kit-cli.js +83 -0
@@ -0,0 +1,131 @@
1
+ import { access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { captureReportScreenshot, SCREENSHOT_SKIP_WARNING } from "../screenshot/index.js";
4
+ import { buildExperimentReportInput, getExperimentReportArtifactPaths, writeExperimentReportArtifacts } from "../report/index.js";
5
+ export function parseRenderExperimentReportArgs(argv) {
6
+ let experimentDir = "";
7
+ let outDir = "";
8
+ let title;
9
+ let subtitle;
10
+ let screenshot = false;
11
+ let requireScreenshot = false;
12
+ let maxPromptChars;
13
+ let maxFileTreeEntries;
14
+ let plotsDir;
15
+ let visualizationsDir;
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const arg = argv[index];
18
+ if (arg === "--experiment") {
19
+ experimentDir = argv[index + 1] ?? "";
20
+ index += 1;
21
+ }
22
+ else if (arg === "--out") {
23
+ outDir = argv[index + 1] ?? "";
24
+ index += 1;
25
+ }
26
+ else if (arg === "--title") {
27
+ title = argv[index + 1] ?? "";
28
+ index += 1;
29
+ }
30
+ else if (arg === "--subtitle") {
31
+ subtitle = argv[index + 1] ?? "";
32
+ index += 1;
33
+ }
34
+ else if (arg === "--screenshot") {
35
+ screenshot = true;
36
+ }
37
+ else if (arg === "--no-screenshot") {
38
+ screenshot = false;
39
+ }
40
+ else if (arg === "--require-screenshot") {
41
+ requireScreenshot = true;
42
+ screenshot = true;
43
+ }
44
+ else if (arg === "--max-prompt-chars") {
45
+ maxPromptChars = parsePositiveInteger("--max-prompt-chars", argv[index + 1] ?? "");
46
+ index += 1;
47
+ }
48
+ else if (arg === "--max-file-tree-entries") {
49
+ maxFileTreeEntries = parsePositiveInteger("--max-file-tree-entries", argv[index + 1] ?? "");
50
+ index += 1;
51
+ }
52
+ else if (arg === "--plots") {
53
+ plotsDir = argv[index + 1] ?? "";
54
+ index += 1;
55
+ }
56
+ else if (arg === "--visualizations") {
57
+ visualizationsDir = argv[index + 1] ?? "";
58
+ index += 1;
59
+ }
60
+ }
61
+ if (!experimentDir || !outDir) {
62
+ throw new Error([
63
+ "Usage: --experiment <controlled-experiment-dir> --out <directory>",
64
+ "[--title <title>] [--subtitle <subtitle>] [--screenshot|--no-screenshot]",
65
+ "[--require-screenshot] [--max-prompt-chars <n>] [--max-file-tree-entries <n>]",
66
+ "[--plots <dir>] [--visualizations <dir>]"
67
+ ].join(" "));
68
+ }
69
+ return { experimentDir, outDir, title, subtitle, screenshot, requireScreenshot, maxPromptChars, maxFileTreeEntries, plotsDir, visualizationsDir };
70
+ }
71
+ export async function runRenderExperimentReportFromArgs(args, repoRoot = process.cwd(), dependencies = {}) {
72
+ const experimentDir = path.resolve(repoRoot, args.experimentDir);
73
+ await access(experimentDir).catch(() => {
74
+ throw new Error(`Experiment directory not found: ${args.experimentDir}`);
75
+ });
76
+ const outDir = path.resolve(repoRoot, args.outDir);
77
+ const outputPaths = getExperimentReportArtifactPaths(outDir);
78
+ const report = await buildExperimentReportInput({
79
+ experimentDir,
80
+ repoRoot,
81
+ title: args.title,
82
+ subtitle: args.subtitle,
83
+ maxPromptChars: args.maxPromptChars,
84
+ maxFileTreeEntries: args.maxFileTreeEntries,
85
+ plotsDir: args.plotsDir,
86
+ visualizationsDir: args.visualizationsDir
87
+ });
88
+ let screenshot = {
89
+ status: "skipped",
90
+ htmlPath: outputPaths.htmlPath,
91
+ pngPath: outputPaths.pngPath,
92
+ warning: "PNG screenshot skipped because --screenshot was not provided."
93
+ };
94
+ let result = await writeExperimentReportArtifacts({ outDir, report, screenshot });
95
+ if (args.screenshot) {
96
+ const captureScreenshot = dependencies.captureScreenshot ?? captureReportScreenshot;
97
+ screenshot = await captureScreenshot(outputPaths.htmlPath, outputPaths.pngPath);
98
+ if (screenshot.status === "skipped" && !screenshot.warning) {
99
+ screenshot.warning = SCREENSHOT_SKIP_WARNING;
100
+ }
101
+ result = await writeExperimentReportArtifacts({ outDir, report, screenshot });
102
+ }
103
+ if (args.requireScreenshot && result.screenshot.status !== "captured") {
104
+ throw new Error(result.screenshot.error ?? result.screenshot.warning ?? "Required screenshot was not captured.");
105
+ }
106
+ return result;
107
+ }
108
+ export async function runRenderExperimentReportCommand(argv) {
109
+ try {
110
+ const args = parseRenderExperimentReportArgs(argv);
111
+ const result = await runRenderExperimentReportFromArgs(args);
112
+ console.log([
113
+ `Report: ${result.outputPaths.htmlPath}`,
114
+ `JSON: ${result.outputPaths.jsonPath}`,
115
+ `Screenshot: ${result.screenshot.status}`,
116
+ `Output: ${result.outputPaths.outDir}`
117
+ ].join("\n"));
118
+ return 0;
119
+ }
120
+ catch (error) {
121
+ console.error(error instanceof Error ? error.message : String(error));
122
+ return 1;
123
+ }
124
+ }
125
+ function parsePositiveInteger(label, value) {
126
+ const parsed = Number(value);
127
+ if (!Number.isInteger(parsed) || parsed <= 0) {
128
+ throw new Error(`${label} must be a positive integer.`);
129
+ }
130
+ return parsed;
131
+ }
@@ -0,0 +1,132 @@
1
+ import path from "node:path";
2
+ import { parseAgentCommandTemplate, runAgentPrompt } from "../agents/index.js";
3
+ import { parseAgentId } from "../agents/agentRegistry.js";
4
+ import { readBenchmarkProjectProfiles, readEvaluationCases } from "../evaluation/index.js";
5
+ import { generatePromptVariants, parsePromptComplexityLevel, parsePromptStrategy } from "../prompts/index.js";
6
+ export function parseRunAgentPromptArgs(argv) {
7
+ let agentId;
8
+ let casesPath = "";
9
+ let caseId = "";
10
+ let strategy;
11
+ let complexity;
12
+ let outDir = "";
13
+ let projectProfilesPath = "benchmarks/contracts/benchmark-project-profiles.json";
14
+ let commandTemplate;
15
+ let requireAvailable = false;
16
+ let timeoutMs;
17
+ for (let index = 0; index < argv.length; index += 1) {
18
+ const arg = argv[index];
19
+ if (arg === "--agent") {
20
+ agentId = parseAgentId(argv[index + 1] ?? "");
21
+ index += 1;
22
+ }
23
+ else if (arg === "--cases") {
24
+ casesPath = argv[index + 1] ?? "";
25
+ index += 1;
26
+ }
27
+ else if (arg === "--case") {
28
+ caseId = argv[index + 1] ?? "";
29
+ index += 1;
30
+ }
31
+ else if (arg === "--strategy") {
32
+ strategy = parsePromptStrategy(argv[index + 1] ?? "");
33
+ index += 1;
34
+ }
35
+ else if (arg === "--complexity") {
36
+ complexity = parsePromptComplexityLevel(argv[index + 1] ?? "");
37
+ index += 1;
38
+ }
39
+ else if (arg === "--out") {
40
+ outDir = argv[index + 1] ?? "";
41
+ index += 1;
42
+ }
43
+ else if (arg === "--project-profiles") {
44
+ projectProfilesPath = argv[index + 1] ?? "";
45
+ index += 1;
46
+ }
47
+ else if (arg === "--command-template") {
48
+ commandTemplate = parseAgentCommandTemplate(argv[index + 1] ?? "");
49
+ index += 1;
50
+ }
51
+ else if (arg === "--require-agent") {
52
+ requireAvailable = true;
53
+ }
54
+ else if (arg === "--timeout-ms") {
55
+ timeoutMs = Number(argv[index + 1] ?? "");
56
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
57
+ throw new Error("--timeout-ms must be a positive number.");
58
+ }
59
+ index += 1;
60
+ }
61
+ }
62
+ if (!agentId || !casesPath || !caseId || !strategy || !complexity || !outDir || !projectProfilesPath) {
63
+ throw new Error([
64
+ "Usage: --agent <fake-agent|codex|claude> --cases <path> --case <id>",
65
+ "--strategy <raw-full-file|my-dev-kit-guided> --complexity <short|medium|long|multi-step>",
66
+ "--out <directory> [--project-profiles <path>] [--command-template <command>] [--require-agent] [--timeout-ms <ms>]"
67
+ ].join(" "));
68
+ }
69
+ return {
70
+ agentId,
71
+ casesPath,
72
+ caseId,
73
+ strategy,
74
+ complexity,
75
+ outDir,
76
+ projectProfilesPath,
77
+ commandTemplate,
78
+ requireAvailable,
79
+ timeoutMs
80
+ };
81
+ }
82
+ export async function runAgentPromptFromArgs(args, repoRoot = process.cwd()) {
83
+ const projectProfiles = await readBenchmarkProjectProfiles(path.resolve(repoRoot, args.projectProfilesPath), repoRoot);
84
+ const cases = await readEvaluationCases(path.resolve(repoRoot, args.casesPath), repoRoot, {
85
+ projectProfiles,
86
+ requireProjectProfileRef: true
87
+ });
88
+ const evaluationCase = cases.find((candidate) => candidate.id === args.caseId);
89
+ if (!evaluationCase) {
90
+ throw new Error(`Evaluation case not found: ${args.caseId}`);
91
+ }
92
+ const [promptVariant] = generatePromptVariants({
93
+ cases: [evaluationCase],
94
+ projectProfiles,
95
+ strategies: [args.strategy],
96
+ complexityLevels: [args.complexity]
97
+ });
98
+ if (!promptVariant) {
99
+ throw new Error(`Failed to generate prompt variant for case: ${args.caseId}`);
100
+ }
101
+ const outDir = path.resolve(repoRoot, args.outDir);
102
+ const result = await runAgentPrompt({
103
+ runId: `${args.caseId}.${args.agentId}.${args.strategy}.${args.complexity}`,
104
+ agentId: args.agentId,
105
+ promptVariant,
106
+ promptText: promptVariant.promptText,
107
+ cwd: repoRoot,
108
+ outDir,
109
+ commandTemplate: args.commandTemplate,
110
+ timeoutMs: args.timeoutMs,
111
+ requireAvailable: args.requireAvailable,
112
+ env: process.env
113
+ });
114
+ return { projectProfiles, cases, promptVariant, result, outDir };
115
+ }
116
+ export async function runAgentPromptCommand(argv) {
117
+ try {
118
+ const args = parseRunAgentPromptArgs(argv);
119
+ const { result, outDir } = await runAgentPromptFromArgs(args);
120
+ console.log([
121
+ `Agent: ${result.agentId}`,
122
+ `Status: ${result.status}`,
123
+ `Prompt: ${path.join(outDir, "prompt.txt")}`,
124
+ `Result: ${path.join(outDir, "agent-run-result.json")}`
125
+ ].join("\n"));
126
+ return result.status === "failed" ? 1 : 0;
127
+ }
128
+ catch (error) {
129
+ console.error(error instanceof Error ? error.message : String(error));
130
+ return 1;
131
+ }
132
+ }
@@ -0,0 +1,174 @@
1
+ import path from "node:path";
2
+ import { parseAgentCommandTemplate } from "../agents/index.js";
3
+ import { parseAgentId } from "../agents/agentRegistry.js";
4
+ import { readBenchmarkProjectProfiles, readEvaluationCases } from "../evaluation/index.js";
5
+ import { contextStrategyComparisonPlugin, resolveExperimentTarget } from "../experiments/index.js";
6
+ import { parsePromptComplexityLevel, parsePromptStrategy } from "../prompts/index.js";
7
+ export function parseRunControlledExperimentArgs(argv) {
8
+ let casesPath = "";
9
+ let projectProfilesPath = "benchmarks/contracts/benchmark-project-profiles.json";
10
+ let outDir = "";
11
+ const caseIds = [];
12
+ const benchmarkProjects = [];
13
+ let agents;
14
+ let strategies;
15
+ let complexityLevels;
16
+ let timeoutMs;
17
+ let maxRuns;
18
+ let continueOnFailure = true;
19
+ let requireAgents = false;
20
+ let includeRealAgents = false;
21
+ const commandTemplates = {};
22
+ for (let index = 0; index < argv.length; index += 1) {
23
+ const arg = argv[index];
24
+ if (arg === "--cases") {
25
+ casesPath = argv[index + 1] ?? "";
26
+ index += 1;
27
+ }
28
+ else if (arg === "--project-profiles") {
29
+ projectProfilesPath = argv[index + 1] ?? "";
30
+ index += 1;
31
+ }
32
+ else if (arg === "--case") {
33
+ caseIds.push(...splitList(argv[index + 1] ?? ""));
34
+ index += 1;
35
+ }
36
+ else if (arg === "--benchmark-project") {
37
+ benchmarkProjects.push(...splitList(argv[index + 1] ?? ""));
38
+ index += 1;
39
+ }
40
+ else if (arg === "--agents") {
41
+ agents = splitList(argv[index + 1] ?? "").map((value) => parseAgentId(value));
42
+ index += 1;
43
+ }
44
+ else if (arg === "--strategies") {
45
+ strategies = splitList(argv[index + 1] ?? "").map(parsePromptStrategy);
46
+ index += 1;
47
+ }
48
+ else if (arg === "--complexities") {
49
+ complexityLevels = splitList(argv[index + 1] ?? "").map(parsePromptComplexityLevel);
50
+ index += 1;
51
+ }
52
+ else if (arg === "--out") {
53
+ outDir = argv[index + 1] ?? "";
54
+ index += 1;
55
+ }
56
+ else if (arg === "--timeout-ms") {
57
+ timeoutMs = parsePositiveInteger("--timeout-ms", argv[index + 1] ?? "");
58
+ index += 1;
59
+ }
60
+ else if (arg === "--max-runs") {
61
+ maxRuns = parsePositiveInteger("--max-runs", argv[index + 1] ?? "");
62
+ index += 1;
63
+ }
64
+ else if (arg === "--continue-on-failure") {
65
+ continueOnFailure = true;
66
+ }
67
+ else if (arg === "--no-continue-on-failure") {
68
+ continueOnFailure = false;
69
+ }
70
+ else if (arg === "--require-agents") {
71
+ requireAgents = true;
72
+ }
73
+ else if (arg === "--include-real-agents") {
74
+ includeRealAgents = true;
75
+ }
76
+ else if (arg === "--command-template-codex") {
77
+ commandTemplates.codex = parseAgentCommandTemplate(argv[index + 1] ?? "");
78
+ index += 1;
79
+ }
80
+ else if (arg === "--command-template-claude") {
81
+ commandTemplates.claude = parseAgentCommandTemplate(argv[index + 1] ?? "");
82
+ index += 1;
83
+ }
84
+ }
85
+ if (!casesPath || !outDir) {
86
+ throw new Error([
87
+ "Usage: --cases <path> --out <directory>",
88
+ "[--project-profiles <path>] [--case <id>] [--benchmark-project <id>]",
89
+ "[--agents <fake-agent,codex,claude>] [--strategies <raw-full-file,my-dev-kit-guided>]",
90
+ "[--complexities <short,medium,long,multi-step>] [--timeout-ms <ms>] [--max-runs <n>]",
91
+ "[--continue-on-failure] [--require-agents] [--include-real-agents]",
92
+ "[--command-template-codex <command>] [--command-template-claude <command>]"
93
+ ].join(" "));
94
+ }
95
+ return {
96
+ casesPath,
97
+ projectProfilesPath,
98
+ caseIds: caseIds.length > 0 ? caseIds : undefined,
99
+ benchmarkProjects: benchmarkProjects.length > 0 ? benchmarkProjects : undefined,
100
+ agents,
101
+ strategies,
102
+ complexityLevels,
103
+ outDir,
104
+ timeoutMs,
105
+ requireAgents,
106
+ continueOnFailure,
107
+ maxRuns,
108
+ commandTemplates: Object.keys(commandTemplates).length > 0 ? commandTemplates : undefined,
109
+ includeRealAgents
110
+ };
111
+ }
112
+ export async function runControlledExperimentFromArgs(args, repoRoot = process.cwd()) {
113
+ const projectProfilesPath = path.resolve(repoRoot, args.projectProfilesPath ?? "benchmarks/contracts/benchmark-project-profiles.json");
114
+ const casesPath = path.resolve(repoRoot, args.casesPath);
115
+ const projectProfiles = await readBenchmarkProjectProfiles(projectProfilesPath, repoRoot);
116
+ const cases = await readEvaluationCases(casesPath, repoRoot, {
117
+ projectProfiles,
118
+ requireProjectProfileRef: true
119
+ });
120
+ const config = {
121
+ ...args,
122
+ casesPath: args.casesPath,
123
+ projectProfilesPath: args.projectProfilesPath
124
+ };
125
+ const validation = contextStrategyComparisonPlugin.validateConfig(config);
126
+ if (!validation.valid || !validation.config) {
127
+ throw new Error(`Invalid context strategy comparison config: ${validation.errors.join("; ")}`);
128
+ }
129
+ const result = await contextStrategyComparisonPlugin.run({
130
+ runId: `context-strategy-comparison-${Date.now()}`,
131
+ startedAt: new Date(),
132
+ toolRoot: repoRoot,
133
+ target: resolveExperimentTarget(undefined, repoRoot),
134
+ config: validation.config,
135
+ outputRoot: path.resolve(repoRoot, validation.config.outDir),
136
+ inputs: {
137
+ cases,
138
+ projectProfiles,
139
+ env: process.env
140
+ }
141
+ });
142
+ const artifacts = result.legacyArtifacts;
143
+ return { projectProfiles, cases, artifacts };
144
+ }
145
+ export async function runControlledExperimentCommand(argv) {
146
+ try {
147
+ const args = parseRunControlledExperimentArgs(argv);
148
+ const { artifacts } = await runControlledExperimentFromArgs(args);
149
+ console.log([
150
+ `Runs: ${artifacts.summary.totalRuns}`,
151
+ `Completed: ${artifacts.summary.completedRuns}`,
152
+ `Comparisons: ${artifacts.summary.totalComparisons}`,
153
+ `Output: ${path.resolve(args.outDir)}`
154
+ ].join("\n"));
155
+ return artifacts.summary.failedRuns > 0 && args.continueOnFailure === false ? 1 : 0;
156
+ }
157
+ catch (error) {
158
+ console.error(error instanceof Error ? error.message : String(error));
159
+ return 1;
160
+ }
161
+ }
162
+ function splitList(value) {
163
+ return value
164
+ .split(",")
165
+ .map((item) => item.trim())
166
+ .filter(Boolean);
167
+ }
168
+ function parsePositiveInteger(label, value) {
169
+ const parsed = Number(value);
170
+ if (!Number.isInteger(parsed) || parsed <= 0) {
171
+ throw new Error(`${label} must be a positive integer.`);
172
+ }
173
+ return parsed;
174
+ }
@@ -0,0 +1,123 @@
1
+ import path from "node:path";
2
+ import { parsePromptComplexityLevel, parsePromptStrategy } from "../prompts/index.js";
3
+ import { parseAgentId } from "../agents/agentRegistry.js";
4
+ import { runControlledExperimentFromArgs } from "./runControlledExperimentCommand.js";
5
+ import { runRenderExperimentReportFromArgs } from "./renderExperimentReportCommand.js";
6
+ import { runGenerateExperimentPlotsFromArgs } from "./generateExperimentPlotsCommand.js";
7
+ import { runVisualizationDemosFromArgs } from "./runVisualizationDemosCommand.js";
8
+ import { runBuildGalleryFromArgs } from "./buildGalleryCommand.js";
9
+ export function parseRunFinalDemoArgs(argv) {
10
+ let casesPath = "";
11
+ let outDir = "";
12
+ let kitCommand = "";
13
+ let agents = ["fake-agent"];
14
+ let strategies = ["raw-full-file", "my-dev-kit-guided"];
15
+ let complexities = ["short"];
16
+ let caseIds;
17
+ let benchmarkProjects;
18
+ let maxRuns;
19
+ let screenshot = false;
20
+ let includeRealAgents = false;
21
+ let continueOnFailure = true;
22
+ let timeoutMs;
23
+ for (let index = 0; index < argv.length; index += 1) {
24
+ const arg = argv[index];
25
+ if (arg === "--cases") {
26
+ casesPath = argv[++index] ?? "";
27
+ }
28
+ else if (arg === "--out") {
29
+ outDir = argv[++index] ?? "";
30
+ }
31
+ else if (arg === "--kit-command") {
32
+ kitCommand = argv[++index] ?? "";
33
+ }
34
+ else if (arg === "--agents") {
35
+ agents = splitList(argv[++index] ?? "").map((value) => parseAgentId(value));
36
+ }
37
+ else if (arg === "--strategies") {
38
+ strategies = splitList(argv[++index] ?? "").map(parsePromptStrategy);
39
+ }
40
+ else if (arg === "--complexities") {
41
+ complexities = splitList(argv[++index] ?? "").map(parsePromptComplexityLevel);
42
+ }
43
+ else if (arg === "--case") {
44
+ caseIds = splitList(argv[++index] ?? "");
45
+ }
46
+ else if (arg === "--benchmark-project") {
47
+ benchmarkProjects = splitList(argv[++index] ?? "");
48
+ }
49
+ else if (arg === "--max-runs") {
50
+ maxRuns = Number(argv[++index]);
51
+ }
52
+ else if (arg === "--screenshot") {
53
+ screenshot = true;
54
+ }
55
+ else if (arg === "--no-screenshot") {
56
+ screenshot = false;
57
+ }
58
+ else if (arg === "--include-real-agents") {
59
+ includeRealAgents = true;
60
+ }
61
+ else if (arg === "--continue-on-failure") {
62
+ continueOnFailure = true;
63
+ }
64
+ else if (arg === "--no-continue-on-failure") {
65
+ continueOnFailure = false;
66
+ }
67
+ else if (arg === "--timeout-ms") {
68
+ timeoutMs = Number(argv[++index]);
69
+ }
70
+ }
71
+ if (!casesPath || !outDir || !kitCommand)
72
+ throw new Error("Usage: --cases <path> --out <dir> --kit-command <command>");
73
+ return { casesPath, outDir, kitCommand, agents, strategies, complexities, caseIds, benchmarkProjects, maxRuns, screenshot, includeRealAgents, continueOnFailure, timeoutMs };
74
+ }
75
+ export async function runFinalDemoFromArgs(args, repoRoot = process.cwd()) {
76
+ const rootOut = path.resolve(repoRoot, args.outDir);
77
+ const experimentDir = path.join(rootOut, "controlled-experiment");
78
+ const plotsDir = path.join(rootOut, "plots");
79
+ const visualizationsDir = path.join(rootOut, "visualization-demos");
80
+ const reportDir = path.join(rootOut, "experiment-report");
81
+ const galleryDir = path.join(rootOut, "gallery");
82
+ const experiment = await runControlledExperimentFromArgs({
83
+ casesPath: args.casesPath,
84
+ projectProfilesPath: "benchmarks/contracts/benchmark-project-profiles.json",
85
+ outDir: experimentDir,
86
+ agents: args.agents,
87
+ strategies: args.strategies,
88
+ complexityLevels: args.complexities,
89
+ caseIds: args.caseIds,
90
+ benchmarkProjects: args.benchmarkProjects,
91
+ maxRuns: args.maxRuns,
92
+ includeRealAgents: args.includeRealAgents,
93
+ continueOnFailure: args.continueOnFailure,
94
+ timeoutMs: args.timeoutMs
95
+ }, repoRoot);
96
+ const plots = await runGenerateExperimentPlotsFromArgs({ experimentDir, outDir: plotsDir }, repoRoot);
97
+ const firstProject = experiment.projectProfiles[0]?.rootPath ?? "benchmarks/projects/todo-ts";
98
+ const visualization = await runVisualizationDemosFromArgs({ projectPath: firstProject, kitCommand: args.kitCommand, outDir: visualizationsDir, timeoutMs: args.timeoutMs }, repoRoot);
99
+ const report = await runRenderExperimentReportFromArgs({ experimentDir, outDir: reportDir, screenshot: args.screenshot, requireScreenshot: false, plotsDir, visualizationsDir }, repoRoot);
100
+ const gallery = await runBuildGalleryFromArgs({ experimentDir, reportDir, plotsDir, visualizationsDir, outDir: galleryDir }, repoRoot);
101
+ return { experiment, plots, visualization, report, gallery, outDir: rootOut };
102
+ }
103
+ export async function runFinalDemoCommand(argv) {
104
+ try {
105
+ const args = parseRunFinalDemoArgs(argv);
106
+ const result = await runFinalDemoFromArgs(args);
107
+ console.log([
108
+ `Experiment runs: ${result.experiment.artifacts.summary.totalRuns}`,
109
+ `Charts: ${result.plots.summary.chartCount}`,
110
+ `Visualization runs: ${result.visualization.summary.totalRuns}`,
111
+ `Gallery manifest: ${result.gallery.manifestPath}`,
112
+ `Output: ${result.outDir}`
113
+ ].join("\n"));
114
+ return 0;
115
+ }
116
+ catch (error) {
117
+ console.error(error instanceof Error ? error.message : String(error));
118
+ return 1;
119
+ }
120
+ }
121
+ function splitList(value) {
122
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
123
+ }
@@ -0,0 +1,62 @@
1
+ import path from "node:path";
2
+ import { validateBenchmarks } from "../../scripts/verify-benchmarks.js";
3
+ import { runTokenSavingsEvaluation, parseEvaluateTokenSavingsArgs } from "./evaluateTokenSavings.js";
4
+ import { writeGalleryManifest } from "../gallery/index.js";
5
+ export function parseRunLabDemoArgs(argv) {
6
+ const evaluationArgs = parseEvaluateTokenSavingsArgs(argv);
7
+ return {
8
+ ...evaluationArgs,
9
+ skipBenchmarkValidation: argv.includes("--skip-benchmark-validation")
10
+ };
11
+ }
12
+ function summarize(result, outDir) {
13
+ return [
14
+ `Benchmark validation: ${result.benchmarkValidation.skipped ? "skipped" : result.benchmarkValidation.ok ? "passed" : "failed"}`,
15
+ `Cases: ${result.evaluation.artifacts.summary.caseCount}`,
16
+ `Completed: ${result.evaluation.artifacts.summary.completedCaseCount}`,
17
+ `Skipped: ${result.evaluation.artifacts.summary.skippedCaseCount}`,
18
+ `Gallery manifest: ${result.gallery.manifestPath}`,
19
+ `Output: ${outDir}`
20
+ ].join("\n");
21
+ }
22
+ export async function runLabDemo(args, repoRoot = process.cwd()) {
23
+ const warnings = [];
24
+ const benchmarkValidation = args.skipBenchmarkValidation
25
+ ? { skipped: true, ok: true, checks: [], errors: [] }
26
+ : { skipped: false, ...validateBenchmarks(repoRoot) };
27
+ if (!args.skipBenchmarkValidation && !benchmarkValidation.ok) {
28
+ throw new Error(`Benchmark validation failed:\n${benchmarkValidation.errors.map((error) => `- ${error}`).join("\n")}`);
29
+ }
30
+ if (args.skipBenchmarkValidation) {
31
+ warnings.push("Benchmark validation skipped because --skip-benchmark-validation was provided.");
32
+ }
33
+ const evaluation = await runTokenSavingsEvaluation(args, repoRoot);
34
+ const gallery = await writeGalleryManifest({
35
+ outDir: path.resolve(repoRoot, args.outDir),
36
+ summary: evaluation.artifacts.summary,
37
+ artifactPaths: evaluation.artifacts.artifactPaths,
38
+ screenshot: evaluation.artifacts.screenshot,
39
+ warnings: [...warnings, ...evaluation.artifacts.warnings]
40
+ });
41
+ return {
42
+ benchmarkValidation,
43
+ evaluation,
44
+ gallery,
45
+ warnings: gallery.manifest.warnings
46
+ };
47
+ }
48
+ export async function runLabDemoCommand(argv) {
49
+ try {
50
+ const args = parseRunLabDemoArgs(argv);
51
+ const result = await runLabDemo(args);
52
+ console.log(summarize(result, path.resolve(args.outDir)));
53
+ if (args.requireKit && result.evaluation.artifacts.summary.completedCaseCount === 0) {
54
+ return 1;
55
+ }
56
+ return 0;
57
+ }
58
+ catch (error) {
59
+ console.error(error instanceof Error ? error.message : String(error));
60
+ return 1;
61
+ }
62
+ }