@dailephd/my-dev-kit-lab 0.6.3 → 0.7.1

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 (123) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +7 -4
  3. package/benchmarks/contracts/context-window-scaling-cases.json +220 -0
  4. package/benchmarks/projects/README.md +3 -1
  5. package/benchmarks/projects/context-window-scaling-fixed-ts/README.md +14 -0
  6. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/carrier-depot-catalog-01.ts +302 -0
  7. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/course-module-catalog-06.ts +302 -0
  8. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/library-shelf-catalog-07.ts +302 -0
  9. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/sensor-station-catalog-05.ts +302 -0
  10. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/staff-rota-catalog-03.ts +302 -0
  11. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/supplier-contract-catalog-02.ts +302 -0
  12. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/vehicle-route-catalog-04.ts +302 -0
  13. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/archive-box-catalog-12.ts +302 -0
  14. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/clinic-ward-catalog-08.ts +302 -0
  15. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/greenhouse-bay-catalog-13.ts +302 -0
  16. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/harbor-berth-catalog-10.ts +302 -0
  17. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/kitchen-section-catalog-15.ts +302 -0
  18. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/market-stall-catalog-09.ts +302 -0
  19. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/station-platform-catalog-14.ts +302 -0
  20. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/workshop-bench-catalog-11.ts +302 -0
  21. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/archive-box-catalog-28.ts +302 -0
  22. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/carrier-depot-catalog-17.ts +302 -0
  23. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/clinic-ward-catalog-24.ts +302 -0
  24. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/course-module-catalog-22.ts +302 -0
  25. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/greenhouse-bay-catalog-29.ts +302 -0
  26. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/harbor-berth-catalog-26.ts +302 -0
  27. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/kitchen-section-catalog-31.ts +302 -0
  28. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/library-shelf-catalog-23.ts +302 -0
  29. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/market-stall-catalog-25.ts +302 -0
  30. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/sensor-station-catalog-21.ts +302 -0
  31. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/staff-rota-catalog-19.ts +302 -0
  32. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/station-platform-catalog-30.ts +302 -0
  33. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/supplier-contract-catalog-18.ts +302 -0
  34. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/vehicle-route-catalog-20.ts +302 -0
  35. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/warehouse-zone-catalog-16.ts +302 -0
  36. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/workshop-bench-catalog-27.ts +302 -0
  37. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/archive-box-catalog-44.ts +302 -0
  38. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-33.ts +302 -0
  39. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-49.ts +302 -0
  40. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-40.ts +302 -0
  41. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-56.ts +302 -0
  42. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-38.ts +302 -0
  43. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-54.ts +302 -0
  44. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/greenhouse-bay-catalog-45.ts +302 -0
  45. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-42.ts +302 -0
  46. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-58.ts +302 -0
  47. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/kitchen-section-catalog-47.ts +302 -0
  48. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-39.ts +302 -0
  49. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-55.ts +302 -0
  50. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-41.ts +302 -0
  51. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-57.ts +302 -0
  52. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-37.ts +302 -0
  53. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-53.ts +302 -0
  54. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-35.ts +302 -0
  55. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-51.ts +302 -0
  56. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/station-platform-catalog-46.ts +302 -0
  57. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-34.ts +302 -0
  58. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-50.ts +302 -0
  59. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-36.ts +302 -0
  60. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-52.ts +302 -0
  61. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-32.ts +302 -0
  62. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-48.ts +302 -0
  63. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/workshop-bench-catalog-43.ts +302 -0
  64. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/auditRedaction.ts +25 -0
  65. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/inventoryReservation.ts +26 -0
  66. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/invoiceTotals.ts +25 -0
  67. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/shippingQuote.ts +32 -0
  68. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/auditRedaction.test.ts +17 -0
  69. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/inventoryReservation.test.ts +19 -0
  70. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/invoiceTotals.test.ts +14 -0
  71. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/shippingQuote.test.ts +19 -0
  72. package/dist/src/cli/help.js +19 -3
  73. package/dist/src/commands/runExperimentDescribeCommand.js +6 -0
  74. package/dist/src/commands/runExperimentRunCommand.js +118 -7
  75. package/dist/src/evaluation/syntheticRepository/config.js +304 -0
  76. package/dist/src/evaluation/syntheticRepository/evaluationCase.js +43 -0
  77. package/dist/src/evaluation/syntheticRepository/identity.js +41 -0
  78. package/dist/src/evaluation/syntheticRepository/index.js +16 -0
  79. package/dist/src/evaluation/syntheticRepository/inspection.js +92 -0
  80. package/dist/src/evaluation/syntheticRepository/layout.js +50 -0
  81. package/dist/src/evaluation/syntheticRepository/manifest.js +281 -0
  82. package/dist/src/evaluation/syntheticRepository/manifestVerification.js +112 -0
  83. package/dist/src/evaluation/syntheticRepository/materialize.js +170 -0
  84. package/dist/src/evaluation/syntheticRepository/planning.js +479 -0
  85. package/dist/src/evaluation/syntheticRepository/prng.js +47 -0
  86. package/dist/src/evaluation/syntheticRepository/renderPython.js +68 -0
  87. package/dist/src/evaluation/syntheticRepository/renderRepository.js +39 -0
  88. package/dist/src/evaluation/syntheticRepository/renderShared.js +93 -0
  89. package/dist/src/evaluation/syntheticRepository/renderTypeScript.js +82 -0
  90. package/dist/src/evaluation/syntheticRepository/topology.js +96 -0
  91. package/dist/src/evaluation/syntheticRepository/types.js +26 -0
  92. package/dist/src/experiments/defaultRegistry.js +2 -0
  93. package/dist/src/experiments/plugins/contextWindowScaling/cliBudgets.js +31 -0
  94. package/dist/src/experiments/plugins/contextWindowScaling/config.js +84 -0
  95. package/dist/src/experiments/plugins/contextWindowScaling/contextBudget.js +43 -0
  96. package/dist/src/experiments/plugins/contextWindowScaling/evaluation.js +36 -0
  97. package/dist/src/experiments/plugins/contextWindowScaling/execution.js +187 -0
  98. package/dist/src/experiments/plugins/contextWindowScaling/executionArtifact.js +15 -0
  99. package/dist/src/experiments/plugins/contextWindowScaling/executionArtifactReader.js +186 -0
  100. package/dist/src/experiments/plugins/contextWindowScaling/index.js +15 -0
  101. package/dist/src/experiments/plugins/contextWindowScaling/metadata.js +12 -0
  102. package/dist/src/experiments/plugins/contextWindowScaling/metrics.js +149 -0
  103. package/dist/src/experiments/plugins/contextWindowScaling/plugin.js +185 -0
  104. package/dist/src/experiments/plugins/contextWindowScaling/projectProfile.js +51 -0
  105. package/dist/src/experiments/plugins/contextWindowScaling/relevantFiles.js +76 -0
  106. package/dist/src/experiments/plugins/contextWindowScaling/successEvidence.js +60 -0
  107. package/dist/src/experiments/plugins/contextWindowScaling/syntheticInputs.js +56 -0
  108. package/dist/src/experiments/plugins/contextWindowScaling/types.js +1 -0
  109. package/dist/src/experiments/plugins/index.js +1 -0
  110. package/dist/src/experiments/plugins/warmIndexReuse/agentEvaluation.js +1 -1
  111. package/dist/src/plots/buildContextWindowScalingPlotData.js +96 -0
  112. package/dist/src/plots/index.js +1 -0
  113. package/dist/src/plots/writePlotArtifacts.js +12 -3
  114. package/dist/src/report/experiments/buildContextWindowScalingReport.js +84 -0
  115. package/dist/src/report/experiments/buildPluginExperimentReport.js +22 -2
  116. package/dist/src/report/experiments/contextWindowScalingReportModel.js +3 -0
  117. package/dist/src/report/experiments/index.js +4 -0
  118. package/dist/src/report/experiments/renderContextWindowScalingHtml.js +99 -0
  119. package/dist/src/report/experiments/renderContextWindowScalingText.js +108 -0
  120. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
  121. package/dist/src/report/experiments/renderPluginExperimentReportText.js +8 -0
  122. package/docs/METRICS.md +29 -1
  123. package/package.json +1 -1
@@ -1,8 +1,10 @@
1
+ import { readFile } from "node:fs/promises";
1
2
  import path from "node:path";
2
3
  import { parseAgentCommandTemplate } from "../agents/index.js";
3
4
  import { parseAgentId } from "../agents/agentRegistry.js";
4
5
  import { readBenchmarkProjectProfiles, readEvaluationCases } from "../evaluation/index.js";
5
- import { contextStrategyComparisonPlugin, createDefaultExperimentPluginRegistry, getWarmIndexCampaignPreset, incrementalChangeStalenessPlugin, parseWarmIndexCampaignPresetId, resolveExperimentTarget, runExperiment, warmIndexReusePlugin } from "../experiments/index.js";
6
+ import { contextStrategyComparisonPlugin, contextWindowScalingPlugin, createDefaultExperimentPluginRegistry, getWarmIndexCampaignPreset, incrementalChangeStalenessPlugin, parseContextBudgetsCliValue, parseWarmIndexCampaignPresetId, resolveExperimentTarget, runExperiment, warmIndexReusePlugin } from "../experiments/index.js";
7
+ import { prepareSyntheticContextWindowScalingInputs } from "../experiments/plugins/contextWindowScaling/index.js";
6
8
  import { buildDefaultExperimentOutputRoot } from "../experiments/outputPaths.js";
7
9
  import { parsePromptComplexityLevel, parsePromptStrategy } from "../prompts/index.js";
8
10
  import { writePluginExperimentReports } from "../report/index.js";
@@ -32,27 +34,42 @@ import { runWarmIndexCampaignPresentation } from "./runWarmIndexCampaignPresenta
32
34
  // ---------------------------------------------------------------------------
33
35
  const DEFAULT_CASES_RESOURCE = "examples/token-savings-cases.json";
34
36
  const DEFAULT_PROJECT_PROFILES_RESOURCE = "benchmarks/contracts/benchmark-project-profiles.json";
37
+ // context-window-scaling owns one frozen bundled case catalog; its fixed project is referenced by the
38
+ // catalog's package-relative targetRoot, so both resolve from the package root, never the cwd.
39
+ const CONTEXT_WINDOW_SCALING_CASES_RESOURCE = "benchmarks/contracts/context-window-scaling-cases.json";
40
+ // Options the context-window-scaling plugin accepts; every other flag is rejected, not ignored.
41
+ const CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS = ["--experiment", "--out", "--case", "--synthetic-config", "--context-budgets", "--kit-command"];
35
42
  export async function runExperimentRunCommandFromArgs(argv, options = {}) {
36
43
  try {
37
44
  const args = parseRunExperimentArgs(argv);
38
45
  const context = options.context ?? createLabExecutionContext();
39
46
  const toolRoot = context.packageRoot;
40
47
  const registry = createDefaultExperimentPluginRegistry();
41
- const inputs = await loadPluginInputs(args, toolRoot, context);
42
48
  const runId = generateExperimentRunId(args.experimentId);
43
- const outputRoot = resolveOutputRoot(args, {
49
+ let outputRoot = resolveOutputRoot(args, {
44
50
  toolRoot,
45
51
  invocationCwd: context.invocationCwd,
46
52
  installedDefaultOutputRoot: options.installedDefaultOutputRoot,
47
53
  experimentId: args.experimentId,
48
54
  runId
49
55
  });
56
+ if (args.syntheticConfigPath !== undefined && outputRoot === undefined) {
57
+ // Synthetic generation needs the concrete root before the runner runs; use the exact default the
58
+ // runner itself would compute for this self-targeted invocation.
59
+ outputRoot = buildDefaultExperimentOutputRoot({
60
+ toolRoot,
61
+ pluginId: args.experimentId,
62
+ target: resolveExperimentTarget(args.targetPath, toolRoot),
63
+ runId
64
+ });
65
+ }
66
+ const inputs = await loadPluginInputs(args, toolRoot, context, outputRoot);
50
67
  const result = await runExperiment({
51
68
  pluginId: args.experimentId,
52
69
  registry,
53
70
  targetPath: args.targetPath,
54
71
  outputRoot,
55
- config: args.config,
72
+ config: pluginConfigFor(args),
56
73
  inputs,
57
74
  toolRoot,
58
75
  runId
@@ -142,9 +159,14 @@ export function parseRunExperimentArgs(argv) {
142
159
  let includeRealAgents;
143
160
  let kitCommand;
144
161
  let campaignPreset;
162
+ let contextBudgets;
163
+ let syntheticConfigPath;
164
+ const seenFlags = [];
145
165
  const commandTemplates = {};
146
166
  for (let index = 0; index < argv.length; index += 1) {
147
167
  const arg = argv[index];
168
+ if (arg !== undefined && arg.startsWith("--"))
169
+ seenFlags.push(arg);
148
170
  if (arg === "--experiment") {
149
171
  experimentId = readRequiredValue(argv, ++index, "--experiment");
150
172
  }
@@ -160,6 +182,12 @@ export function parseRunExperimentArgs(argv) {
160
182
  else if (arg === "--project-profiles") {
161
183
  projectProfilesPath = readRequiredValue(argv, ++index, "--project-profiles");
162
184
  }
185
+ else if (arg === "--synthetic-config") {
186
+ if (syntheticConfigPath !== undefined) {
187
+ throw new Error("--synthetic-config may be supplied only once.");
188
+ }
189
+ syntheticConfigPath = readRequiredValue(argv, ++index, "--synthetic-config");
190
+ }
163
191
  else if (arg === "--case") {
164
192
  caseIds.push(...splitList(readRequiredValue(argv, ++index, "--case")));
165
193
  }
@@ -202,6 +230,9 @@ export function parseRunExperimentArgs(argv) {
202
230
  else if (arg === "--kit-command") {
203
231
  kitCommand = readRequiredValue(argv, ++index, "--kit-command");
204
232
  }
233
+ else if (arg === "--context-budgets") {
234
+ contextBudgets = parseContextBudgetsCliValue(readRequiredValue(argv, ++index, "--context-budgets"));
235
+ }
205
236
  else if (arg === "--campaign") {
206
237
  campaignPreset = parseWarmIndexCampaignPresetId(readRequiredValue(argv, ++index, "--campaign"));
207
238
  }
@@ -216,7 +247,29 @@ export function parseRunExperimentArgs(argv) {
216
247
  if (!experimentId) {
217
248
  throw new Error("Usage: --experiment <id> [--target <path>] [--out <directory>]");
218
249
  }
219
- const KIT_COMMAND_PLUGIN_IDS = [warmIndexReusePlugin.metadata.id, incrementalChangeStalenessPlugin.metadata.id];
250
+ const KIT_COMMAND_PLUGIN_IDS = [
251
+ warmIndexReusePlugin.metadata.id,
252
+ incrementalChangeStalenessPlugin.metadata.id,
253
+ contextWindowScalingPlugin.metadata.id
254
+ ];
255
+ if (contextBudgets !== undefined && experimentId !== contextWindowScalingPlugin.metadata.id) {
256
+ throw new Error(`--context-budgets is only supported for --experiment ${contextWindowScalingPlugin.metadata.id}.`);
257
+ }
258
+ if (syntheticConfigPath !== undefined && experimentId !== contextWindowScalingPlugin.metadata.id) {
259
+ throw new Error(`--synthetic-config is only supported for --experiment ${contextWindowScalingPlugin.metadata.id}.`);
260
+ }
261
+ if (experimentId === contextWindowScalingPlugin.metadata.id) {
262
+ const unsupported = [...new Set(seenFlags.filter((flag) => !CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS.includes(flag)))];
263
+ if (unsupported.length > 0) {
264
+ throw new Error(`${unsupported.join(", ")} ${unsupported.length === 1 ? "is" : "are"} not supported for --experiment ${experimentId}; supported options: ${CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS.join(", ")}.`);
265
+ }
266
+ if (seenFlags.includes("--case") && caseIds.length === 0) {
267
+ throw new Error("--case must list at least one case id.");
268
+ }
269
+ if (syntheticConfigPath !== undefined && seenFlags.includes("--case")) {
270
+ throw new Error("--case and --synthetic-config are mutually exclusive; the synthetic config owns the generated case set.");
271
+ }
272
+ }
220
273
  if (kitCommand !== undefined && !KIT_COMMAND_PLUGIN_IDS.includes(experimentId)) {
221
274
  throw new Error(`--kit-command is only supported for --experiment ${KIT_COMMAND_PLUGIN_IDS.join(" or ")}.`);
222
275
  }
@@ -238,6 +291,7 @@ export function parseRunExperimentArgs(argv) {
238
291
  experimentId,
239
292
  targetPath,
240
293
  outDir,
294
+ syntheticConfigPath,
241
295
  config: withoutUndefined({
242
296
  casesPath,
243
297
  projectProfilesPath,
@@ -253,7 +307,8 @@ export function parseRunExperimentArgs(argv) {
253
307
  includeRealAgents,
254
308
  commandTemplates: Object.keys(commandTemplates).length > 0 ? commandTemplates : undefined,
255
309
  kitCommand,
256
- campaignPreset
310
+ campaignPreset,
311
+ contextBudgets
257
312
  })
258
313
  };
259
314
  }
@@ -279,7 +334,7 @@ function generateExperimentRunId(pluginId) {
279
334
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
280
335
  return `${pluginId}-${timestamp}`;
281
336
  }
282
- async function loadPluginInputs(args, toolRoot, context) {
337
+ async function loadPluginInputs(args, toolRoot, context, outputRoot) {
283
338
  if (args.experimentId === contextStrategyComparisonPlugin.metadata.id) {
284
339
  const validation = contextStrategyComparisonPlugin.validateConfig(args.config);
285
340
  if (!validation.valid || !validation.config) {
@@ -297,8 +352,64 @@ async function loadPluginInputs(args, toolRoot, context) {
297
352
  }
298
353
  return loadCasesAndProjectProfiles(args, toolRoot, context);
299
354
  }
355
+ if (args.experimentId === contextWindowScalingPlugin.metadata.id) {
356
+ return loadContextWindowScalingInputs(args, toolRoot, context, outputRoot);
357
+ }
300
358
  return undefined;
301
359
  }
360
+ // --case is a selection over the frozen bundled catalog (catalog order, not argument order);
361
+ // the rest of the CLI config is the plugin's own ContextWindowScalingConfig.
362
+ function pluginConfigFor(args) {
363
+ if (args.experimentId !== contextWindowScalingPlugin.metadata.id)
364
+ return args.config;
365
+ const { caseIds: _caseIds, ...config } = args.config;
366
+ return config;
367
+ }
368
+ async function loadContextWindowScalingInputs(args, toolRoot, context, outputRoot) {
369
+ const validation = contextWindowScalingPlugin.validateConfig(pluginConfigFor(args));
370
+ if (!validation.valid || !validation.config) {
371
+ throw new Error(`Invalid context window scaling config: ${validation.errors.join("; ")}`);
372
+ }
373
+ if (args.syntheticConfigPath !== undefined) {
374
+ if (outputRoot === undefined) {
375
+ throw new Error("Internal error: synthetic generation requires a resolved experiment output root.");
376
+ }
377
+ const configPath = path.resolve(context.invocationCwd, args.syntheticConfigPath);
378
+ const syntheticRepositoryConfig = await readSyntheticConfigJson(configPath, args.syntheticConfigPath);
379
+ const prepared = prepareSyntheticContextWindowScalingInputs({ syntheticRepositoryConfig, outputRoot });
380
+ return { cases: prepared.cases, projectProfiles: prepared.projectProfiles, env: process.env };
381
+ }
382
+ const catalog = await readEvaluationCases(resolvePackageResource(context, CONTEXT_WINDOW_SCALING_CASES_RESOURCE), toolRoot);
383
+ const requested = args.config.caseIds;
384
+ if (requested === undefined)
385
+ return { cases: catalog, env: process.env };
386
+ const duplicates = [...new Set(requested.filter((id, position) => requested.indexOf(id) !== position))];
387
+ if (duplicates.length > 0) {
388
+ throw new Error(`--case contains duplicate case id(s): ${duplicates.join(", ")}.`);
389
+ }
390
+ const known = new Set(catalog.map((evaluationCase) => evaluationCase.id));
391
+ const unknown = requested.filter((id) => !known.has(id));
392
+ if (unknown.length > 0) {
393
+ throw new Error(`--case contains unknown case id(s): ${unknown.join(", ")}. Expected one of ${catalog.map((evaluationCase) => evaluationCase.id).join(", ")}.`);
394
+ }
395
+ return { cases: catalog.filter((evaluationCase) => requested.includes(evaluationCase.id)), env: process.env };
396
+ }
397
+ // The command only reads and parses the caller-supplied file; schema validation belongs to the synthetic planner.
398
+ async function readSyntheticConfigJson(resolvedPath, displayPath) {
399
+ let text;
400
+ try {
401
+ text = await readFile(resolvedPath, "utf8");
402
+ }
403
+ catch (error) {
404
+ throw new Error(`Cannot read --synthetic-config ${displayPath}: ${error instanceof Error ? error.message : String(error)}`);
405
+ }
406
+ try {
407
+ return JSON.parse(text);
408
+ }
409
+ catch (error) {
410
+ throw new Error(`--synthetic-config ${displayPath} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
411
+ }
412
+ }
302
413
  // Shared by both registered plugins: explicit paths resolve against toolRoot, defaults come from
303
414
  // bundled package resources so they do not depend on the invocation cwd.
304
415
  async function loadCasesAndProjectProfiles(args, toolRoot, context) {
@@ -0,0 +1,304 @@
1
+ import { TASK_LOCALITIES } from "../types.js";
2
+ import { SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION, SYNTHETIC_REPOSITORY_LANGUAGES, SyntheticRepositoryConfigError, } from "./types.js";
3
+ export const SYNTHETIC_REPOSITORY_LIMITS = {
4
+ maxCases: 64,
5
+ caseIdMaxLength: 64,
6
+ seedMaxLength: 256,
7
+ sourceFileCount: { min: 1, max: 10000 },
8
+ moduleDepth: { min: 1, max: 64 },
9
+ internalImportCount: { min: 0, max: 100000 },
10
+ symbolCount: { min: 1, max: 100000 },
11
+ testFileCount: { min: 0, max: 10000 },
12
+ repeatedPatternCount: { min: 0, max: 100000 },
13
+ broadChangeMinSourceFiles: 4,
14
+ crossModuleMinSourceFiles: 2,
15
+ };
16
+ /** Fixed field order of one case; also the canonical serialization order. */
17
+ export const SYNTHETIC_REPOSITORY_CASE_FIELDS = [
18
+ "id",
19
+ "language",
20
+ "seed",
21
+ "sourceFileCount",
22
+ "moduleDepth",
23
+ "internalImportCount",
24
+ "symbolCount",
25
+ "testFileCount",
26
+ "taskLocality",
27
+ "repeatedPatternCount",
28
+ ];
29
+ const COUNT_FIELDS = [
30
+ "sourceFileCount",
31
+ "moduleDepth",
32
+ "internalImportCount",
33
+ "symbolCount",
34
+ "testFileCount",
35
+ "repeatedPatternCount",
36
+ ];
37
+ const CASE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
38
+ const WINDOWS_DEVICE_NAME_PATTERN = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
39
+ /** Locale-independent ordering by UTF-16 code unit. */
40
+ export function compareCodeUnits(left, right) {
41
+ if (left < right)
42
+ return -1;
43
+ if (left > right)
44
+ return 1;
45
+ return 0;
46
+ }
47
+ /**
48
+ * Maximum number of unique directed acyclic import edges among `sourceFileCount` modules whose longest
49
+ * dependency chain has exactly `moduleDepth` modules: the edge count of the balanced complete
50
+ * multipartite arrangement, (N^2 - sum of squared layer sizes) / 2.
51
+ */
52
+ export function maxImportEdges(sourceFileCount, moduleDepth) {
53
+ const base = Math.floor(sourceFileCount / moduleDepth);
54
+ const larger = sourceFileCount % moduleDepth;
55
+ const sumOfSquares = larger * (base + 1) * (base + 1) + (moduleDepth - larger) * base * base;
56
+ return (sourceFileCount * sourceFileCount - sumOfSquares) / 2;
57
+ }
58
+ /** Returns the case in canonical field order. Assumes the spec is valid. */
59
+ export function orderCaseSpec(spec) {
60
+ return {
61
+ id: spec.id,
62
+ language: spec.language,
63
+ seed: spec.seed,
64
+ sourceFileCount: spec.sourceFileCount,
65
+ moduleDepth: spec.moduleDepth,
66
+ internalImportCount: spec.internalImportCount,
67
+ symbolCount: spec.symbolCount,
68
+ testFileCount: spec.testFileCount,
69
+ taskLocality: spec.taskLocality,
70
+ repeatedPatternCount: spec.repeatedPatternCount,
71
+ };
72
+ }
73
+ function isPlainObject(value) {
74
+ if (typeof value !== "object" || value === null || Array.isArray(value))
75
+ return false;
76
+ const prototype = Object.getPrototypeOf(value);
77
+ return prototype === Object.prototype || prototype === null;
78
+ }
79
+ function hasOwn(value, key) {
80
+ return Object.prototype.hasOwnProperty.call(value, key);
81
+ }
82
+ function describeValue(value) {
83
+ if (typeof value === "string") {
84
+ return JSON.stringify(value.length > 40 ? `${value.slice(0, 40)}...` : value);
85
+ }
86
+ if (typeof value === "number" || typeof value === "boolean")
87
+ return String(value);
88
+ if (value === null)
89
+ return "null";
90
+ if (Array.isArray(value))
91
+ return "array";
92
+ return typeof value;
93
+ }
94
+ function hasLoneSurrogate(value) {
95
+ for (let index = 0; index < value.length; index += 1) {
96
+ const unit = value.charCodeAt(index);
97
+ if (unit >= 0xd800 && unit <= 0xdbff) {
98
+ const next = value.charCodeAt(index + 1);
99
+ if (next >= 0xdc00 && next <= 0xdfff) {
100
+ index += 1;
101
+ continue;
102
+ }
103
+ return true;
104
+ }
105
+ if (unit >= 0xdc00 && unit <= 0xdfff)
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ function validateCaseId(value, label, errors) {
111
+ if (typeof value !== "string") {
112
+ errors.push(`${label}.id: must be a string (received ${describeValue(value)}).`);
113
+ return false;
114
+ }
115
+ const before = errors.length;
116
+ if (value.length < 1 || value.length > SYNTHETIC_REPOSITORY_LIMITS.caseIdMaxLength) {
117
+ errors.push(`${label}.id: length must be between 1 and ${SYNTHETIC_REPOSITORY_LIMITS.caseIdMaxLength}.`);
118
+ }
119
+ else if (!CASE_ID_PATTERN.test(value)) {
120
+ errors.push(`${label}.id: must begin with an ASCII letter or digit and contain only ASCII letters, digits, ".", "_" and "-" (received ${describeValue(value)}).`);
121
+ }
122
+ else {
123
+ if (value.endsWith(".")) {
124
+ errors.push(`${label}.id: must not end with ".".`);
125
+ }
126
+ if (WINDOWS_DEVICE_NAME_PATTERN.test(value.split(".")[0])) {
127
+ errors.push(`${label}.id: must not use a reserved device name (received ${describeValue(value)}).`);
128
+ }
129
+ }
130
+ return errors.length === before;
131
+ }
132
+ function validateSeed(value, label, errors) {
133
+ if (typeof value !== "string") {
134
+ errors.push(`${label}.seed: must be a string (received ${describeValue(value)}).`);
135
+ return false;
136
+ }
137
+ const before = errors.length;
138
+ if (!/\S/.test(value)) {
139
+ errors.push(`${label}.seed: must contain at least one non-whitespace character.`);
140
+ }
141
+ if (value.length > SYNTHETIC_REPOSITORY_LIMITS.seedMaxLength) {
142
+ errors.push(`${label}.seed: must be at most ${SYNTHETIC_REPOSITORY_LIMITS.seedMaxLength} UTF-16 code units.`);
143
+ }
144
+ if (hasLoneSurrogate(value)) {
145
+ errors.push(`${label}.seed: must be well-formed Unicode (lone surrogate found).`);
146
+ }
147
+ return errors.length === before;
148
+ }
149
+ function validateCount(value, field, label, errors) {
150
+ const { min, max } = SYNTHETIC_REPOSITORY_LIMITS[field];
151
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) {
152
+ errors.push(`${label}.${field}: must be an integer between ${min} and ${max} (received ${describeValue(value)}).`);
153
+ return false;
154
+ }
155
+ return true;
156
+ }
157
+ function validateCase(value, label, errors) {
158
+ if (!isPlainObject(value)) {
159
+ errors.push(`${label}: must be an object (received ${describeValue(value)}).`);
160
+ return undefined;
161
+ }
162
+ const before = errors.length;
163
+ const allowed = new Set(SYNTHETIC_REPOSITORY_CASE_FIELDS);
164
+ for (const key of Object.keys(value).sort(compareCodeUnits)) {
165
+ if (!allowed.has(key))
166
+ errors.push(`${label}: unknown field ${JSON.stringify(key)}.`);
167
+ }
168
+ for (const field of SYNTHETIC_REPOSITORY_CASE_FIELDS) {
169
+ if (!hasOwn(value, field))
170
+ errors.push(`${label}: missing required field ${field}.`);
171
+ }
172
+ const idOk = hasOwn(value, "id") && validateCaseId(value.id, label, errors);
173
+ const languageOk = hasOwn(value, "language") &&
174
+ SYNTHETIC_REPOSITORY_LANGUAGES.includes(value.language);
175
+ if (hasOwn(value, "language") && !languageOk) {
176
+ errors.push(`${label}.language: must be one of ${SYNTHETIC_REPOSITORY_LANGUAGES.join(", ")} (received ${describeValue(value.language)}).`);
177
+ }
178
+ const seedOk = hasOwn(value, "seed") && validateSeed(value.seed, label, errors);
179
+ const countOk = new Map();
180
+ for (const field of COUNT_FIELDS) {
181
+ countOk.set(field, hasOwn(value, field) && validateCount(value[field], field, label, errors));
182
+ }
183
+ const localityOk = hasOwn(value, "taskLocality") && TASK_LOCALITIES.includes(value.taskLocality);
184
+ if (hasOwn(value, "taskLocality") && !localityOk) {
185
+ errors.push(`${label}.taskLocality: must be one of ${TASK_LOCALITIES.join(", ")} (received ${describeValue(value.taskLocality)}).`);
186
+ }
187
+ const sourceFileCount = value.sourceFileCount;
188
+ const moduleDepth = value.moduleDepth;
189
+ const internalImportCount = value.internalImportCount;
190
+ const symbolCount = value.symbolCount;
191
+ const taskLocality = value.taskLocality;
192
+ const sourceOk = countOk.get("sourceFileCount") === true;
193
+ const depthOk = countOk.get("moduleDepth") === true;
194
+ const importsOk = countOk.get("internalImportCount") === true;
195
+ const symbolsOk = countOk.get("symbolCount") === true;
196
+ if (sourceOk && depthOk) {
197
+ if (moduleDepth > sourceFileCount) {
198
+ errors.push(`${label}.moduleDepth: must not exceed sourceFileCount (${moduleDepth} > ${sourceFileCount}).`);
199
+ }
200
+ else if (importsOk) {
201
+ if (moduleDepth > 1 && internalImportCount < moduleDepth - 1) {
202
+ errors.push(`${label}.internalImportCount: must be at least moduleDepth - 1 (${moduleDepth - 1}) to realize moduleDepth ${moduleDepth}.`);
203
+ }
204
+ const capacity = maxImportEdges(sourceFileCount, moduleDepth);
205
+ if (internalImportCount > capacity) {
206
+ errors.push(`${label}.internalImportCount: exceeds the ${capacity} unique acyclic edges possible for sourceFileCount ${sourceFileCount} with exact moduleDepth ${moduleDepth}.`);
207
+ }
208
+ }
209
+ }
210
+ if (sourceOk && symbolsOk && symbolCount < sourceFileCount) {
211
+ errors.push(`${label}.symbolCount: must be at least sourceFileCount (${symbolCount} < ${sourceFileCount}).`);
212
+ }
213
+ if (sourceOk && localityOk) {
214
+ if (taskLocality === "cross-module") {
215
+ if (sourceFileCount < SYNTHETIC_REPOSITORY_LIMITS.crossModuleMinSourceFiles) {
216
+ errors.push(`${label}.taskLocality: cross-module requires sourceFileCount >= 2.`);
217
+ }
218
+ if (importsOk && internalImportCount < 1) {
219
+ errors.push(`${label}.taskLocality: cross-module requires internalImportCount >= 1.`);
220
+ }
221
+ }
222
+ else if (taskLocality === "broad-change" && sourceFileCount < SYNTHETIC_REPOSITORY_LIMITS.broadChangeMinSourceFiles) {
223
+ errors.push(`${label}.taskLocality: broad-change requires sourceFileCount >= 4.`);
224
+ }
225
+ }
226
+ if (errors.length !== before || !idOk || !languageOk || !seedOk || !localityOk)
227
+ return undefined;
228
+ return orderCaseSpec(value);
229
+ }
230
+ /** Validates one case spec and returns it in canonical field order. Never throws, never repairs. */
231
+ export function validateSyntheticRepositoryCaseSpec(input) {
232
+ const errors = [];
233
+ const spec = validateCase(input, "case", errors);
234
+ if (errors.length > 0 || spec === undefined)
235
+ return { ok: false, errors };
236
+ return { ok: true, errors: [], spec };
237
+ }
238
+ /**
239
+ * Strictly validates an unknown value as SyntheticRepositoryConfigV1. On success the returned config is
240
+ * canonical: cases sorted ascending by id (code-unit order), fixed field order, values untouched.
241
+ */
242
+ export function validateSyntheticRepositoryConfig(input) {
243
+ const errors = [];
244
+ if (!isPlainObject(input)) {
245
+ return { ok: false, errors: [`config: must be an object (received ${describeValue(input)}).`] };
246
+ }
247
+ for (const key of Object.keys(input).sort(compareCodeUnits)) {
248
+ if (key !== "schemaVersion" && key !== "cases")
249
+ errors.push(`config: unknown field ${JSON.stringify(key)}.`);
250
+ }
251
+ if (!hasOwn(input, "schemaVersion")) {
252
+ errors.push("config: missing required field schemaVersion.");
253
+ }
254
+ else if (input.schemaVersion !== SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION) {
255
+ errors.push(`config.schemaVersion: must be ${JSON.stringify(SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION)} (received ${describeValue(input.schemaVersion)}).`);
256
+ }
257
+ if (!hasOwn(input, "cases")) {
258
+ errors.push("config: missing required field cases.");
259
+ return { ok: false, errors };
260
+ }
261
+ const cases = input.cases;
262
+ if (!Array.isArray(cases)) {
263
+ errors.push(`config.cases: must be an array (received ${describeValue(cases)}).`);
264
+ return { ok: false, errors };
265
+ }
266
+ if (cases.length < 1 || cases.length > SYNTHETIC_REPOSITORY_LIMITS.maxCases) {
267
+ errors.push(`config.cases: must contain between 1 and ${SYNTHETIC_REPOSITORY_LIMITS.maxCases} cases (received ${cases.length}).`);
268
+ return { ok: false, errors };
269
+ }
270
+ const valid = [];
271
+ const firstIndexById = new Map();
272
+ cases.forEach((candidate, index) => {
273
+ const label = `cases[${index}]`;
274
+ const spec = validateCase(candidate, label, errors);
275
+ if (spec)
276
+ valid.push(spec);
277
+ const id = isPlainObject(candidate) ? candidate.id : undefined;
278
+ if (typeof id === "string") {
279
+ const key = id.toLowerCase();
280
+ const first = firstIndexById.get(key);
281
+ if (first === undefined) {
282
+ firstIndexById.set(key, index);
283
+ }
284
+ else {
285
+ errors.push(`${label}.id: duplicates cases[${first}].id (ids are compared without regard to letter case).`);
286
+ }
287
+ }
288
+ });
289
+ if (errors.length > 0)
290
+ return { ok: false, errors };
291
+ const sorted = [...valid].sort((left, right) => compareCodeUnits(left.id, right.id));
292
+ return {
293
+ ok: true,
294
+ errors: [],
295
+ config: { schemaVersion: SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION, cases: sorted },
296
+ };
297
+ }
298
+ /** Validates then returns the canonical configuration; throws SyntheticRepositoryConfigError when invalid. */
299
+ export function normalizeSyntheticRepositoryConfig(input) {
300
+ const result = validateSyntheticRepositoryConfig(input);
301
+ if (!result.ok)
302
+ throw new SyntheticRepositoryConfigError(result.errors);
303
+ return result.config;
304
+ }
@@ -0,0 +1,43 @@
1
+ import { describeSyntheticTask } from "./layout.js";
2
+ /** The plan's answer key expressed in the existing benchmark answer-key vocabulary (no second correctness contract). */
3
+ export function buildSyntheticAnswerKey(plan) {
4
+ const { factTextById } = describeSyntheticTask(plan);
5
+ return {
6
+ expectedFiles: [...plan.answerKey.expectedFiles],
7
+ expectedSymbols: [...plan.answerKey.expectedSymbols],
8
+ expectedFacts: plan.answerKey.facts.map((fact) => ({
9
+ id: fact.factId,
10
+ text: factTextById.get(fact.factId),
11
+ weight: fact.weight,
12
+ required: fact.required,
13
+ })),
14
+ expectedContextTargets: plan.answerKey.expectedContextTargets.map((target) => ({
15
+ file: target.file,
16
+ symbols: [...target.symbols],
17
+ required: target.required,
18
+ })),
19
+ minimumCorrectFacts: plan.answerKey.minimumCorrectFacts,
20
+ };
21
+ }
22
+ /**
23
+ * Builds the existing EvaluationCase directly in memory (never through readEvaluationCases, which owns
24
+ * repository-contained JSON cases). `targetRoot` is the stable logical root from the manifest; only
25
+ * `absoluteTargetRoot` carries the physical generated repository directory.
26
+ */
27
+ export function buildSyntheticEvaluationCase(plan, manifest, repositoryRoot) {
28
+ const text = describeSyntheticTask(plan);
29
+ return {
30
+ id: plan.task.taskId,
31
+ title: text.title,
32
+ benchmarkProject: plan.logicalProjectId,
33
+ targetRoot: manifest.logicalTargetRoot,
34
+ sourceRoots: [...manifest.sourceRoots],
35
+ query: text.query,
36
+ expectedFiles: [...plan.answerKey.expectedFiles],
37
+ expectedSymbols: [...plan.answerKey.expectedSymbols],
38
+ rawIncludeGlobs: [...manifest.rawIncludeGlobs],
39
+ answerKey: buildSyntheticAnswerKey(plan),
40
+ taskLocality: plan.task.locality,
41
+ absoluteTargetRoot: repositoryRoot,
42
+ };
43
+ }
@@ -0,0 +1,41 @@
1
+ import { createHash } from "node:crypto";
2
+ import { normalizeSyntheticRepositoryConfig, orderCaseSpec, validateSyntheticRepositoryCaseSpec } from "./config.js";
3
+ import { SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_ID, SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION, SYNTHETIC_REPOSITORY_IDENTITY_ALGORITHM_VERSION, SyntheticRepositoryConfigError, } from "./types.js";
4
+ /** Canonical JSON text of one valid case: fixed key order, exact values. */
5
+ export function canonicalSyntheticRepositoryCaseText(spec) {
6
+ return JSON.stringify(orderCaseSpec(spec));
7
+ }
8
+ /** Canonical JSON text of a normalized configuration (cases already sorted by id). */
9
+ export function canonicalSyntheticRepositoryConfigText(config) {
10
+ return JSON.stringify({
11
+ schemaVersion: config.schemaVersion,
12
+ cases: config.cases.map(orderCaseSpec),
13
+ });
14
+ }
15
+ /**
16
+ * SHA-256 over the UTF-8 bytes of five newline-joined lines: schema id, schema version, identity
17
+ * algorithm version, a domain tag ("case" or "config") and the canonical JSON payload. JSON escapes every
18
+ * newline, so the payload cannot forge an earlier line.
19
+ */
20
+ function hashDomain(domain, payload) {
21
+ const text = [
22
+ SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_ID,
23
+ SYNTHETIC_REPOSITORY_CONFIG_SCHEMA_VERSION,
24
+ SYNTHETIC_REPOSITORY_IDENTITY_ALGORITHM_VERSION,
25
+ domain,
26
+ payload,
27
+ ].join("\n");
28
+ return createHash("sha256").update(Buffer.from(text, "utf8")).digest("hex");
29
+ }
30
+ /** Per-case generation identity (lowercase 64-character SHA-256 hex). Throws on an invalid case. */
31
+ export function computeSyntheticRepositoryCaseIdentity(input) {
32
+ const result = validateSyntheticRepositoryCaseSpec(input);
33
+ if (!result.ok)
34
+ throw new SyntheticRepositoryConfigError(result.errors);
35
+ return hashDomain("case", canonicalSyntheticRepositoryCaseText(result.spec));
36
+ }
37
+ /** Whole-configuration identity over the normalized form; input case order never matters. */
38
+ export function computeSyntheticRepositoryConfigIdentity(input) {
39
+ const config = normalizeSyntheticRepositoryConfig(input);
40
+ return hashDomain("config", canonicalSyntheticRepositoryConfigText(config));
41
+ }
@@ -0,0 +1,16 @@
1
+ export * from "./types.js";
2
+ export { SYNTHETIC_REPOSITORY_CASE_FIELDS, SYNTHETIC_REPOSITORY_LIMITS, compareCodeUnits, maxImportEdges, normalizeSyntheticRepositoryConfig, validateSyntheticRepositoryCaseSpec, validateSyntheticRepositoryConfig, } from "./config.js";
3
+ export { canonicalSyntheticRepositoryCaseText, canonicalSyntheticRepositoryConfigText, computeSyntheticRepositoryCaseIdentity, computeSyntheticRepositoryConfigIdentity, } from "./identity.js";
4
+ export { createSyntheticRepositoryPrng, syntheticRepositoryPrngInitialState } from "./prng.js";
5
+ export { planTopology } from "./topology.js";
6
+ export { planSyntheticRepositories, planSyntheticRepositoryCase, verifySyntheticRepositoryPlan } from "./planning.js";
7
+ export { SyntheticRepositoryRenderError } from "./renderShared.js";
8
+ export { renderTypeScriptRepository } from "./renderTypeScript.js";
9
+ export { pythonModuleName, renderPythonRepository } from "./renderPython.js";
10
+ export { renderSyntheticRepository } from "./renderRepository.js";
11
+ export { inspectRepositoryFiles } from "./inspection.js";
12
+ export { deriveSyntheticRepositoryLayout, describeSyntheticTask } from "./layout.js";
13
+ export { SYNTHETIC_REPOSITORY_MANIFEST_FILE_NAME, SYNTHETIC_REPOSITORY_MANIFEST_SCHEMA_ID, SYNTHETIC_REPOSITORY_MANIFEST_SCHEMA_VERSION, SYNTHETIC_REPOSITORY_REPOSITORY_DIRECTORY, buildSyntheticRepositoryManifest, computeRepositoryContentIdentity, serializeSyntheticRepositoryManifest, validateSyntheticRepositoryManifest, } from "./manifest.js";
14
+ export { verifySyntheticRepositoryMaterialization } from "./manifestVerification.js";
15
+ export { buildSyntheticAnswerKey, buildSyntheticEvaluationCase } from "./evaluationCase.js";
16
+ export { SyntheticRepositoryMaterializationError, materializeSyntheticRepository } from "./materialize.js";