@codeyam/codeyam-cli 0.1.0-staging.323686 → 0.1.0-staging.483fdc2

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 (171) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +2 -2
  4. package/analyzer-template/packages/ai/index.ts +6 -1
  5. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +39 -17
  6. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +67 -9
  7. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +308 -50
  8. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +15 -6
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +664 -242
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.ts +16 -3
  11. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.ts +6 -4
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +20 -1
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +35 -13
  14. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +160 -0
  15. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts +40 -30
  16. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +289 -83
  17. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +269 -1
  18. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +9 -5
  19. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +11 -3
  20. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
  21. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +297 -7
  22. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +1 -1
  23. package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
  24. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +10 -7
  25. package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +25 -13
  26. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +4 -3
  27. package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +65 -59
  28. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +113 -26
  29. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.ts +19 -0
  30. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.ts +19 -0
  31. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllExports.ts +11 -0
  32. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.ts +8 -0
  33. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.ts +49 -1
  34. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.ts +2 -1
  35. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +20 -6
  36. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +14 -4
  37. package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
  38. package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +0 -3
  39. package/analyzer-template/packages/analyze/src/lib/files/analyzeRemixRoute.ts +4 -5
  40. package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +14 -12
  41. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +57 -13
  42. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +29 -0
  43. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +35 -4
  44. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +117 -9
  45. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +199 -17
  46. package/analyzer-template/packages/analyze/src/lib/files/scenarios/propagateArrayItemSchemas.ts +474 -0
  47. package/analyzer-template/packages/analyze/src/lib/files/setImportedExports.ts +2 -1
  48. package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
  49. package/analyzer-template/packages/aws/package.json +1 -1
  50. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
  51. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  52. package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
  53. package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
  54. package/analyzer-template/packages/github/package.json +1 -1
  55. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +6 -5
  56. package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
  57. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
  58. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  59. package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
  60. package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
  61. package/analyzer-template/project/constructMockCode.ts +54 -9
  62. package/analyzer-template/project/writeMockDataTsx.ts +73 -2
  63. package/background/src/lib/virtualized/project/constructMockCode.js +45 -3
  64. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  65. package/background/src/lib/virtualized/project/writeMockDataTsx.js +71 -2
  66. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  67. package/codeyam-cli/scripts/apply-setup.js +146 -0
  68. package/codeyam-cli/scripts/apply-setup.js.map +1 -1
  69. package/codeyam-cli/src/commands/debug.js +7 -5
  70. package/codeyam-cli/src/commands/debug.js.map +1 -1
  71. package/codeyam-cli/src/utils/install-skills.js +22 -0
  72. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  73. package/codeyam-cli/src/utils/reviewedRules.js +92 -0
  74. package/codeyam-cli/src/utils/reviewedRules.js.map +1 -0
  75. package/codeyam-cli/src/webserver/build/client/assets/globals-CX9f-5xM.css +1 -0
  76. package/codeyam-cli/src/webserver/build/client/assets/{manifest-7522edd4.js → manifest-bba56ec1.js} +1 -1
  77. package/codeyam-cli/src/webserver/build/client/assets/memory-DuTFSyJ2.js +92 -0
  78. package/codeyam-cli/src/webserver/build/client/assets/{root-eVAaavTS.js → root-DTfSQARG.js} +6 -6
  79. package/codeyam-cli/src/webserver/build/server/assets/{index-DVzYx8PN.js → index-TD1f-DHV.js} +1 -1
  80. package/codeyam-cli/src/webserver/build/server/assets/server-build-BQ-1XyEa.js +258 -0
  81. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  82. package/codeyam-cli/src/webserver/build-info.json +5 -5
  83. package/codeyam-cli/templates/codeyam:memory.md +174 -233
  84. package/codeyam-cli/templates/codeyam:new-rule.md +41 -2
  85. package/codeyam-cli/templates/rule-reflection-hook.py +161 -0
  86. package/codeyam-cli/templates/rules-instructions.md +126 -0
  87. package/package.json +1 -1
  88. package/packages/ai/index.js +2 -1
  89. package/packages/ai/index.js.map +1 -1
  90. package/packages/ai/src/lib/analyzeScope.js +29 -12
  91. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  92. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +54 -8
  93. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  94. package/packages/ai/src/lib/astScopes/processExpression.js +239 -43
  95. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  96. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +503 -165
  97. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  98. package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js +13 -3
  99. package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js.map +1 -1
  100. package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js +6 -4
  101. package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js.map +1 -1
  102. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +22 -1
  103. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  104. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +34 -9
  105. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  106. package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +159 -0
  107. package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -0
  108. package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js +37 -20
  109. package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js.map +1 -1
  110. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +237 -73
  111. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  112. package/packages/ai/src/lib/generateEntityScenarioData.js +195 -1
  113. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  114. package/packages/ai/src/lib/generateEntityScenarios.js +7 -1
  115. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  116. package/packages/ai/src/lib/generateExecutionFlows.js +10 -2
  117. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  118. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +209 -3
  119. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
  120. package/packages/ai/src/lib/mergeStatements.js +70 -51
  121. package/packages/ai/src/lib/mergeStatements.js.map +1 -1
  122. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +10 -4
  123. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  124. package/packages/ai/src/lib/resolvePathToControllable.js +24 -14
  125. package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
  126. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  127. package/packages/analyze/src/lib/FileAnalyzer.js +60 -36
  128. package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
  129. package/packages/analyze/src/lib/ProjectAnalyzer.js +96 -26
  130. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  131. package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js +14 -0
  132. package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js.map +1 -1
  133. package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js +14 -0
  134. package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js.map +1 -1
  135. package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js +6 -0
  136. package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js.map +1 -1
  137. package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js +6 -0
  138. package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js.map +1 -1
  139. package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js +39 -1
  140. package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js.map +1 -1
  141. package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js +2 -1
  142. package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js.map +1 -1
  143. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +13 -5
  144. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  145. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +14 -4
  146. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  147. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +2 -1
  148. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
  149. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +0 -3
  150. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
  151. package/packages/analyze/src/lib/files/analyzeRemixRoute.js +3 -2
  152. package/packages/analyze/src/lib/files/analyzeRemixRoute.js.map +1 -1
  153. package/packages/analyze/src/lib/files/getImportedExports.js +11 -7
  154. package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
  155. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +52 -10
  156. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
  157. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +25 -8
  158. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  159. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +34 -4
  160. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  161. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +56 -8
  162. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
  163. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +168 -9
  164. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  165. package/packages/analyze/src/lib/files/setImportedExports.js +2 -1
  166. package/packages/analyze/src/lib/files/setImportedExports.js.map +1 -1
  167. package/packages/analyze/src/lib/utils/getFileByPath.js +12 -0
  168. package/packages/analyze/src/lib/utils/getFileByPath.js.map +1 -0
  169. package/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +0 -1
  170. package/codeyam-cli/src/webserver/build/client/assets/memory-yxFcrxBX.js +0 -92
  171. package/codeyam-cli/src/webserver/build/server/assets/server-build-4Cr0uToj.js +0 -257
@@ -16,6 +16,7 @@ import validateJson from './validateJson';
16
16
  import { awsLog, awsLogDebugLevel } from '~codeyam/utils';
17
17
  import { AI, parseJsonSafe } from '~codeyam/ai';
18
18
  import convertNullToUndefinedBySchema from './dataStructure/helpers/convertNullToUndefinedBySchema';
19
+ import convertTypeAnnotationsToValues from './dataStructure/helpers/convertTypeAnnotationsToValues';
19
20
  import fixNullIdsBySchema from './dataStructure/helpers/fixNullIdsBySchema';
20
21
  import { JsonTypeDefinition } from '~codeyam/types';
21
22
  import { deepMerge } from '~codeyam/generate';
@@ -459,6 +460,193 @@ function fillMissingMockDataKeysWithDefaults(
459
460
  }
460
461
  }
461
462
 
463
+ /**
464
+ * Enforce execution flow requiredValues by setting falsy paths to null.
465
+ *
466
+ * The LLM doesn't reliably generate null for `comparison: 'falsy'` requirements.
467
+ * For example, a flow like "diffView: falsy" should hide a modal, but the LLM
468
+ * might generate a truthy object, causing the modal to show in all screenshots.
469
+ *
470
+ * This function:
471
+ * 1. Gets requiredValues from covered flows
472
+ * 2. For 'falsy' comparisons: sets the value to null
473
+ * 3. For 'truthy' comparisons with falsy values: generates a default truthy value
474
+ */
475
+ function enforceRequiredValues(
476
+ mockData: Record<string, unknown>,
477
+ coveredFlowIds: string[],
478
+ executionFlows: ExecutionFlow[],
479
+ ): void {
480
+ if (!coveredFlowIds.length || !executionFlows.length) {
481
+ return;
482
+ }
483
+
484
+ // Get all requiredValues from covered flows
485
+ const coveredFlows = executionFlows.filter((flow) =>
486
+ coveredFlowIds.includes(flow.id),
487
+ );
488
+
489
+ for (const flow of coveredFlows) {
490
+ if (!flow.requiredValues) continue;
491
+
492
+ for (const rv of flow.requiredValues) {
493
+ if (!rv.attributePath) continue;
494
+
495
+ // Find the value in mockData - the path could be nested
496
+ // e.g., attributePath: "diffView" could be at mockData['useDiffModal()'].diffView
497
+ const result = findAndSetValueInMockData(
498
+ mockData,
499
+ rv.attributePath,
500
+ rv.comparison,
501
+ rv.valueType,
502
+ );
503
+
504
+ if (result.found) {
505
+ awsLog(
506
+ `CodeYam: Enforced ${rv.comparison} for ${rv.attributePath} (set to ${result.newValue === null ? 'null' : typeof result.newValue})`,
507
+ );
508
+ }
509
+ }
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Find a value in mockData by attributePath and enforce the comparison.
515
+ * The attributePath could be a simple key or a nested path.
516
+ *
517
+ * Returns { found: boolean, newValue: unknown }
518
+ */
519
+ function findAndSetValueInMockData(
520
+ mockData: Record<string, unknown>,
521
+ attributePath: string,
522
+ comparison: string,
523
+ valueType?: string,
524
+ ): { found: boolean; newValue?: unknown } {
525
+ // Try to find the path at various nesting levels
526
+ // The attributePath might be "diffView" but the actual location is
527
+ // mockData['useDiffModal()'].diffView
528
+
529
+ // Strategy 1: Direct path (e.g., mockData[attributePath])
530
+ if (attributePath in mockData) {
531
+ const currentValue = mockData[attributePath];
532
+ const { shouldChange, newValue } = getEnforcedValue(
533
+ currentValue,
534
+ comparison,
535
+ valueType,
536
+ );
537
+ if (shouldChange) {
538
+ mockData[attributePath] = newValue;
539
+ return { found: true, newValue };
540
+ }
541
+ return { found: true, newValue: currentValue };
542
+ }
543
+
544
+ // Strategy 2: Search in nested objects
545
+ for (const [key, value] of Object.entries(mockData)) {
546
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
547
+ const nestedObj = value as Record<string, unknown>;
548
+
549
+ // Check if attributePath exists in this nested object
550
+ if (attributePath in nestedObj) {
551
+ const currentValue = nestedObj[attributePath];
552
+ const { shouldChange, newValue } = getEnforcedValue(
553
+ currentValue,
554
+ comparison,
555
+ valueType,
556
+ );
557
+ if (shouldChange) {
558
+ nestedObj[attributePath] = newValue;
559
+ return { found: true, newValue };
560
+ }
561
+ return { found: true, newValue: currentValue };
562
+ }
563
+
564
+ // Also check dot-notation paths (e.g., "diffView.type")
565
+ if (attributePath.includes('.')) {
566
+ const parts = attributePath.split('.');
567
+ const firstPart = parts[0];
568
+ if (firstPart in nestedObj) {
569
+ // Recurse with the rest of the path
570
+ const result = findAndSetValueInMockData(
571
+ nestedObj,
572
+ attributePath,
573
+ comparison,
574
+ valueType,
575
+ );
576
+ if (result.found) return result;
577
+ }
578
+ }
579
+
580
+ // Recursively search deeper
581
+ const result = findAndSetValueInMockData(
582
+ nestedObj,
583
+ attributePath,
584
+ comparison,
585
+ valueType,
586
+ );
587
+ if (result.found) return result;
588
+ }
589
+ }
590
+
591
+ return { found: false };
592
+ }
593
+
594
+ /**
595
+ * Determine if a value should be changed to match a comparison requirement.
596
+ *
597
+ * For 'falsy' comparison: truthy values should become null
598
+ * For 'truthy' comparison: falsy values should become a default truthy value
599
+ */
600
+ function getEnforcedValue(
601
+ currentValue: unknown,
602
+ comparison: string,
603
+ valueType?: string,
604
+ ): { shouldChange: boolean; newValue: unknown } {
605
+ const isTruthy = Boolean(currentValue);
606
+
607
+ if (comparison === 'falsy') {
608
+ // Value should be falsy
609
+ if (isTruthy) {
610
+ return { shouldChange: true, newValue: null };
611
+ }
612
+ return { shouldChange: false, newValue: currentValue };
613
+ }
614
+
615
+ if (comparison === 'truthy') {
616
+ // Value should be truthy
617
+ if (!isTruthy) {
618
+ // Generate a default truthy value based on valueType
619
+ const defaultValue = generateDefaultTruthyValue(valueType);
620
+ return { shouldChange: true, newValue: defaultValue };
621
+ }
622
+ return { shouldChange: false, newValue: currentValue };
623
+ }
624
+
625
+ // For other comparisons (equals, exists, etc.), don't auto-enforce
626
+ return { shouldChange: false, newValue: currentValue };
627
+ }
628
+
629
+ /**
630
+ * Generate a default truthy value for a given type.
631
+ */
632
+ function generateDefaultTruthyValue(valueType?: string): unknown {
633
+ if (!valueType) return { _placeholder: true };
634
+
635
+ switch (valueType.toLowerCase()) {
636
+ case 'string':
637
+ return 'default-value';
638
+ case 'number':
639
+ return 1;
640
+ case 'boolean':
641
+ return true;
642
+ case 'array':
643
+ return [{ _placeholder: true }];
644
+ case 'object':
645
+ default:
646
+ return { _placeholder: true };
647
+ }
648
+ }
649
+
462
650
  type ScenarioDataWithoutDescription = Omit<ScenarioData, 'scenarioDescription'>;
463
651
 
464
652
  interface GenerateEntityScenarioDataArgs {
@@ -878,6 +1066,16 @@ export async function generateDataForScenario({
878
1066
  convertCommaSeparatedStringsToArrays(fullScenarioData.data.mockData);
879
1067
  }
880
1068
 
1069
+ // Convert type annotation strings that appear as values to actual values.
1070
+ // The LLM sometimes echoes the schema type annotation as the value.
1071
+ // For example, if the schema says { filePath: "string | undefined" },
1072
+ // the LLM might return { filePath: "string | undefined" } instead of
1073
+ // generating an actual value. This converts those type strings to
1074
+ // appropriate default values (e.g., "string | undefined" → undefined).
1075
+ if (fullScenarioData.data.mockData) {
1076
+ convertTypeAnnotationsToValues(fullScenarioData.data.mockData);
1077
+ }
1078
+
881
1079
  // Fix null values for ID fields when the schema indicates they should be non-null.
882
1080
  // The LLM sometimes generates `null` for ID fields (e.g., `"id": null`) when
883
1081
  // the schema type is `"number"`. This causes runtime issues when code checks
@@ -886,6 +1084,18 @@ export async function generateDataForScenario({
886
1084
  fixNullIdsBySchema(fullScenarioData.data.mockData, structure.dataForMocks);
887
1085
  }
888
1086
 
1087
+ // Enforce execution flow requiredValues by setting falsy paths to null.
1088
+ // The LLM doesn't reliably generate null for falsy requirements (e.g., diffView: falsy
1089
+ // to hide a modal). This post-processing ensures that scenarios match their
1090
+ // covered flows' requiredValues.
1091
+ if (fullScenarioData.data.mockData && executionFlows) {
1092
+ enforceRequiredValues(
1093
+ fullScenarioData.data.mockData,
1094
+ scenario.metadata?.coveredFlows || [],
1095
+ executionFlows,
1096
+ );
1097
+ }
1098
+
889
1099
  if (structure.arguments && fullScenarioData.data.argumentsData) {
890
1100
  for (let i = 0; i < fullScenarioData.data.argumentsData.length; i++) {
891
1101
  if (structure.arguments[i]) {
@@ -1075,6 +1285,60 @@ export default async function generateEntityScenarioData({
1075
1285
  defaultScenarioData.data.argumentsData.map((arg) => ({ ...arg }));
1076
1286
  }
1077
1287
 
1288
+ // Enforce requiredValues AFTER merge for non-default scenarios
1289
+ // This ensures that if a non-default scenario doesn't cover a certain flow,
1290
+ // it inherits the enforcement from the default scenario
1291
+ if (scenarioData.data?.mockData && executionFlows) {
1292
+ // Get the flows covered by this scenario
1293
+ const scenarioCoveredFlows =
1294
+ nonDefaultScenarios.find(
1295
+ (s) => s.name === result.scenarioData.scenarioDescription,
1296
+ )?.metadata?.coveredFlows || [];
1297
+
1298
+ // Get the paths that the scenario's flows affect
1299
+ const scenarioAffectedPaths = new Set<string>();
1300
+ for (const flowId of scenarioCoveredFlows) {
1301
+ const flow = executionFlows.find((f) => f.id === flowId);
1302
+ if (flow?.requiredValues) {
1303
+ for (const rv of flow.requiredValues) {
1304
+ if (rv.attributePath) {
1305
+ // Extract base path (e.g., "diffView" from "diffView.type")
1306
+ const basePath = rv.attributePath.split('.')[0];
1307
+ scenarioAffectedPaths.add(basePath);
1308
+ }
1309
+ }
1310
+ }
1311
+ }
1312
+
1313
+ // Get the default scenario's flows
1314
+ const defaultCoveredFlows =
1315
+ defaultScenario.metadata?.coveredFlows || [];
1316
+
1317
+ // For paths NOT affected by the scenario, apply default's enforcement
1318
+ const defaultFlowsForUnaffectedPaths = defaultCoveredFlows.filter(
1319
+ (flowId) => {
1320
+ const flow = executionFlows.find((f) => f.id === flowId);
1321
+ if (!flow?.requiredValues) return false;
1322
+
1323
+ // Check if this flow affects a path that the scenario doesn't cover
1324
+ return flow.requiredValues.some((rv) => {
1325
+ if (!rv.attributePath) return false;
1326
+ const basePath = rv.attributePath.split('.')[0];
1327
+ return !scenarioAffectedPaths.has(basePath);
1328
+ });
1329
+ },
1330
+ );
1331
+
1332
+ // Apply enforcement from default scenario for unaffected paths
1333
+ if (defaultFlowsForUnaffectedPaths.length > 0) {
1334
+ enforceRequiredValues(
1335
+ scenarioData.data.mockData,
1336
+ defaultFlowsForUnaffectedPaths,
1337
+ executionFlows,
1338
+ );
1339
+ }
1340
+ }
1341
+
1078
1342
  return scenarioData;
1079
1343
  });
1080
1344
 
@@ -1104,7 +1368,8 @@ Generate COMPLETE, robust data for the entire data structure.
1104
1368
  : `## Non-Default Scenario
1105
1369
  Generate ONLY the differences from the default scenario.
1106
1370
  - Include only fields that need to change
1107
- - Set to \`null\` to remove data
1371
+ - For object/scalar fields: set to \`null\` to remove/unset the data
1372
+ - For array fields: use \`[]\` for empty arrays (not \`null\`) unless the schema type explicitly includes \`| null\`
1108
1373
  - Omit unchanged fields—they merge from default`;
1109
1374
 
1110
1375
  // Only include the "NO ERROR DATA" instruction when the scenario doesn't require error data
@@ -1188,6 +1453,7 @@ Use simple elements only (\`<div>\`, \`<span>\`). No custom components.
1188
1453
  - Arrays should have many items (at least 4) unless specified otherwise
1189
1454
  - Each item must follow the exact structure provided
1190
1455
  - In general we want robust data, not minimal data unless specified otherwise
1456
+ - For empty arrays, use \`[]\` (not \`null\`) unless the schema type explicitly includes \`| null\` and the scenario requires the attribute be removed
1191
1457
 
1192
1458
  ## CRITICAL: Preserve Exact Structure
1193
1459
  Your response MUST mirror the EXACT nested structure provided in mockData Structure.
@@ -1267,6 +1533,7 @@ Use simple elements only (\`<div>\`, \`<span>\`). No custom components.
1267
1533
  ### Arrays
1268
1534
  - Arrays should have many items (at least 4) unless specified otherwise
1269
1535
  - Each item must follow the exact structure provided
1536
+ - For empty arrays, use \`[]\` (not \`null\`) unless the schema type explicitly includes \`| null\` and the scenario requires the attribute be removed
1270
1537
 
1271
1538
  ## CRITICAL: Preserve Exact Structure
1272
1539
  Your response MUST mirror the EXACT nested structure provided for the missing keys.
@@ -1395,4 +1662,5 @@ NEVER include "error" fields in responses. Skip them entirely.
1395
1662
  - No \`undefined\`—use \`null\` or omit
1396
1663
  - Generate data for ALL keys in the chunk (don't skip any)
1397
1664
  - Arrays should have many items (at least 4) unless specified otherwise
1665
+ - For empty arrays, use \`[]\` (not \`null\`) unless the schema type explicitly includes \`| null\` and the scenario requires the attribute be removed
1398
1666
  `;
@@ -176,11 +176,15 @@ export default async function generateEntityScenarios({
176
176
  return { scenarios: [], llmCall };
177
177
  }
178
178
 
179
- const scenarios = (
180
- result[
181
- `${error ? 'errorD' : 'd'}ataScenarios`
182
- ] as unknown as ScenarioResult[]
183
- ).map(
179
+ const dataScenarios = result[`${error ? 'errorD' : 'd'}ataScenarios`];
180
+
181
+ // Gracefully handle missing dataScenarios (e.g., when LLM returns unexpected format
182
+ // or when test fixtures don't include the expected key)
183
+ if (!Array.isArray(dataScenarios)) {
184
+ return { scenarios: [], llmCall };
185
+ }
186
+
187
+ const scenarios = (dataScenarios as unknown as ScenarioResult[]).map(
184
188
  (scenarioInfo) =>
185
189
  ({
186
190
  projectId: entity.projectId,
@@ -143,6 +143,7 @@ export default function generateExecutionFlows({
143
143
  childIsolated.equivalentSignatureVariables ?? {},
144
144
  compoundConditionals: childIsolated.compoundConditionals ?? [],
145
145
  gatingConditions,
146
+ jsxRenderingUsages: childIsolated.jsxRenderingUsages ?? [],
146
147
  };
147
148
  }
148
149
  }
@@ -159,6 +160,7 @@ export default function generateExecutionFlows({
159
160
  ? childComponentData
160
161
  : undefined,
161
162
  derivedVariables,
163
+ sourceEquivalencies: mergedDataStructure.sourceEquivalencies,
162
164
  });
163
165
 
164
166
  console.log(
@@ -253,7 +255,7 @@ export default function generateExecutionFlows({
253
255
  */
254
256
  function buildGatingPathToChildrenMap(
255
257
  childBoundaryGatingConditions: Record<string, ConditionalUsage[]>,
256
- equivalentSignatureVariables: Record<string, string>,
258
+ equivalentSignatureVariables: Record<string, string | string[]>,
257
259
  attributesMap: Record<string, string>,
258
260
  fullToShortPathMap: Record<string, string>,
259
261
  ): Map<string, string[]> {
@@ -279,10 +281,13 @@ function buildGatingPathToChildrenMap(
279
281
  fullToShortPathMap,
280
282
  );
281
283
 
284
+ // Get the equivalent, handling array case (use first element if array)
285
+ const equiv = equivalentSignatureVariables[gatingPath];
286
+ const equivPath = Array.isArray(equiv) ? equiv[0] : equiv;
282
287
  const finalPath =
283
288
  resolution.isControllable && resolution.resolvedPath
284
289
  ? resolution.resolvedPath
285
- : (equivalentSignatureVariables[gatingPath] ?? gatingPath);
290
+ : (equivPath ?? gatingPath);
286
291
 
287
292
  // Add this child to the list of children gated by this path
288
293
  const existing = gatingPathToChildren.get(finalPath) ?? [];
@@ -303,10 +308,13 @@ function buildGatingPathToChildrenMap(
303
308
  equivalentSignatureVariables,
304
309
  fullToShortPathMap,
305
310
  );
311
+ // Get the equivalent, handling array case (use first element if array)
312
+ const varEquiv = equivalentSignatureVariables[varName];
313
+ const varEquivPath = Array.isArray(varEquiv) ? varEquiv[0] : varEquiv;
306
314
  const resolvedVarPath =
307
315
  varResolution.isControllable && varResolution.resolvedPath
308
316
  ? varResolution.resolvedPath
309
- : (equivalentSignatureVariables[varName] ?? varName);
317
+ : (varEquivPath ?? varName);
310
318
 
311
319
  const varExisting = gatingPathToChildren.get(resolvedVarPath) ?? [];
312
320
  if (!varExisting.includes(childName)) {
@@ -18,7 +18,7 @@ export interface GenerateExecutionFlowsOptions {
18
18
  /** Map of controllable paths to their types (for path resolution) */
19
19
  attributesMap?: Record<string, string>;
20
20
  /** Map from local variable names to data sources */
21
- equivalentSignatureVariables?: Record<string, string>;
21
+ equivalentSignatureVariables?: Record<string, string | string[]>;
22
22
  /** Map from full paths to short paths */
23
23
  fullToShortPathMap?: Record<string, string>;
24
24
  /**