@codeyam/codeyam-cli 0.1.21 → 0.1.23

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 (122) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +135 -0
  4. package/analyzer-template/packages/ai/src/lib/astScopes/nodeToSource.ts +19 -0
  5. package/analyzer-template/packages/ai/src/lib/astScopes/paths.ts +11 -4
  6. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +31 -8
  7. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.ts +10 -3
  8. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +16 -6
  9. package/analyzer-template/packages/analyze/index.ts +4 -1
  10. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +28 -2
  11. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -36
  12. package/analyzer-template/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.ts +21 -0
  13. package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +82 -10
  14. package/analyzer-template/packages/analyze/src/lib/files/analyzeNextRoute.ts +8 -3
  15. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +239 -58
  16. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +1684 -1462
  17. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js +47 -0
  18. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js.map +1 -0
  19. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js +71 -0
  20. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js.map +1 -0
  21. package/codeyam-cli/src/commands/editor.js +545 -94
  22. package/codeyam-cli/src/commands/editor.js.map +1 -1
  23. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js +23 -0
  24. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js.map +1 -0
  25. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +456 -1
  26. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
  27. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +11 -3
  28. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
  29. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +140 -1
  30. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
  31. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +50 -1
  32. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -1
  33. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +33 -1
  34. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -1
  35. package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js +302 -0
  36. package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js.map +1 -0
  37. package/codeyam-cli/src/utils/__tests__/testRunner.test.js +217 -0
  38. package/codeyam-cli/src/utils/__tests__/testRunner.test.js.map +1 -0
  39. package/codeyam-cli/src/utils/analysisRunner.js +28 -1
  40. package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
  41. package/codeyam-cli/src/utils/analyzer.js +4 -2
  42. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  43. package/codeyam-cli/src/utils/editorAudit.js +136 -5
  44. package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
  45. package/codeyam-cli/src/utils/editorPreview.js +5 -3
  46. package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
  47. package/codeyam-cli/src/utils/editorScenarios.js +60 -0
  48. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
  49. package/codeyam-cli/src/utils/editorSeedAdapter.js +42 -2
  50. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -1
  51. package/codeyam-cli/src/utils/entityChangeStatus.server.js +16 -0
  52. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -1
  53. package/codeyam-cli/src/utils/manualEntityAnalysis.js +196 -0
  54. package/codeyam-cli/src/utils/manualEntityAnalysis.js.map +1 -0
  55. package/codeyam-cli/src/utils/queue/job.js +20 -2
  56. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  57. package/codeyam-cli/src/utils/testRunner.js +199 -1
  58. package/codeyam-cli/src/utils/testRunner.js.map +1 -1
  59. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +30 -11
  60. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -1
  61. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +35 -0
  62. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -1
  63. package/codeyam-cli/src/webserver/build/client/assets/MiniClaudeChat-CQENLSrF.js +36 -0
  64. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-Coe5NhbS.js +1 -0
  65. package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-CJzc4vOH.svg → cy-logo-cli-DoA97ML3.svg} +2 -2
  66. package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DMv5ESGo.js +96 -0
  67. package/codeyam-cli/src/webserver/build/client/assets/{editorPreview-NTuLi4Xg.js → editorPreview-CluPkvXJ.js} +6 -6
  68. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-Blfy9UlN.js → entity._sha._-ByHz6rAQ.js} +13 -12
  69. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-BA5L8bU-.js → entity._sha.scenarios._scenarioId.dev-CmLO432x.js} +1 -1
  70. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-D4dmRgvO.js → entity._sha.scenarios._scenarioId.fullscreen-Bz9sCUF_.js} +1 -1
  71. package/codeyam-cli/src/webserver/build/client/assets/globals-oyPmV37k.css +1 -0
  72. package/codeyam-cli/src/webserver/build/client/assets/{manifest-5025e428.js → manifest-1a45e154.js} +1 -1
  73. package/codeyam-cli/src/webserver/build/client/assets/{root-BCx1S8Z3.js → root-D2_tktnk.js} +6 -6
  74. package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-By5slFjw.js +16 -0
  75. package/codeyam-cli/src/webserver/build/server/assets/{index-C91yWWCI.js → index-DXaOwBnm.js} +1 -1
  76. package/codeyam-cli/src/webserver/build/server/assets/{init-Dkas-RUS.js → init-CLG1LjQM.js} +1 -1
  77. package/codeyam-cli/src/webserver/build/server/assets/server-build-NZmUqQv6.js +688 -0
  78. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  79. package/codeyam-cli/src/webserver/build-info.json +5 -5
  80. package/codeyam-cli/src/webserver/editorProxy.js +55 -3
  81. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  82. package/codeyam-cli/src/webserver/idleDetector.js +15 -0
  83. package/codeyam-cli/src/webserver/idleDetector.js.map +1 -1
  84. package/codeyam-cli/src/webserver/terminalServer.js +8 -2
  85. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  86. package/codeyam-cli/templates/codeyam-editor-reference.md +8 -6
  87. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +42 -34
  88. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +2 -2
  89. package/package.json +1 -1
  90. package/packages/ai/src/lib/astScopes/methodSemantics.js +99 -0
  91. package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
  92. package/packages/ai/src/lib/astScopes/nodeToSource.js +16 -0
  93. package/packages/ai/src/lib/astScopes/nodeToSource.js.map +1 -1
  94. package/packages/ai/src/lib/astScopes/paths.js +12 -3
  95. package/packages/ai/src/lib/astScopes/paths.js.map +1 -1
  96. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +23 -9
  97. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  98. package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js +9 -2
  99. package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js.map +1 -1
  100. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +14 -4
  101. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  102. package/packages/analyze/index.js +1 -1
  103. package/packages/analyze/index.js.map +1 -1
  104. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +16 -2
  105. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  106. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +6 -26
  107. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  108. package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js +14 -0
  109. package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js.map +1 -1
  110. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +44 -11
  111. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
  112. package/packages/analyze/src/lib/files/analyzeNextRoute.js +5 -1
  113. package/packages/analyze/src/lib/files/analyzeNextRoute.js.map +1 -1
  114. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +120 -28
  115. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  116. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +1368 -1193
  117. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  118. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DODLxLcw.js +0 -1
  119. package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-Dx-h1rJK.js +0 -130
  120. package/codeyam-cli/src/webserver/build/client/assets/globals-BrPXT1iR.css +0 -1
  121. package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-C1kjC9UJ.js +0 -13
  122. package/codeyam-cli/src/webserver/build/server/assets/server-build-pulXLTrG.js +0 -640
@@ -6,6 +6,20 @@ import type {
6
6
  ReadonlyEntity,
7
7
  } from '~codeyam/types';
8
8
  import { ImmutableAnalysisContext } from '../../analysisContext';
9
+ import { awsLogDebugLevel } from '~codeyam/utils';
10
+
11
+ /**
12
+ * Tracks statistics across the recursive dependency validation.
13
+ * Shared by all recursive calls to provide a complete picture.
14
+ */
15
+ interface ValidationStats {
16
+ totalVisited: number;
17
+ skippedDuplicate: number;
18
+ skippedMissing: number;
19
+ skippedTrivial: number;
20
+ maxDepth: number;
21
+ startTime: number;
22
+ }
9
23
 
10
24
  export default function validateDependencyAnalyses({
11
25
  analysis,
@@ -13,12 +27,18 @@ export default function validateDependencyAnalyses({
13
27
  entity,
14
28
  context,
15
29
  dependentAnalyses,
30
+ _depth = 0,
31
+ _stats,
16
32
  }: {
17
33
  analysis?: Analysis;
18
34
  readonlyAnalysis?: ReadonlyAnalysis;
19
35
  entity: ReadonlyEntity;
20
36
  context: ImmutableAnalysisContext;
21
37
  dependentAnalyses?: ReadonlyAnalysisMap;
38
+ /** Recursion depth (internal, do not set) */
39
+ _depth?: number;
40
+ /** Shared stats tracker (internal, do not set) */
41
+ _stats?: ValidationStats;
22
42
  }): { dependentAnalyses: ReadonlyAnalysisMap } {
23
43
  if (!readonlyAnalysis) readonlyAnalysis = analysis;
24
44
  if (!readonlyAnalysis) {
@@ -32,6 +52,28 @@ export default function validateDependencyAnalyses({
32
52
  );
33
53
  }
34
54
 
55
+ // Initialize stats on the root call
56
+ const isRootCall = _depth === 0;
57
+ if (!_stats) {
58
+ _stats = {
59
+ totalVisited: 0,
60
+ skippedDuplicate: 0,
61
+ skippedMissing: 0,
62
+ skippedTrivial: 0,
63
+ maxDepth: 0,
64
+ startTime: Date.now(),
65
+ };
66
+ }
67
+ if (_depth > _stats.maxDepth) _stats.maxDepth = _depth;
68
+
69
+ const importCount = entity.metadata?.importedExports?.length ?? 0;
70
+ if (isRootCall && importCount > 0) {
71
+ awsLogDebugLevel(
72
+ 2,
73
+ `validateDeps: ${entity.name} has ${importCount} imports to validate`,
74
+ );
75
+ }
76
+
35
77
  if (
36
78
  dependentAnalyses &&
37
79
  dependentAnalyses[readonlyAnalysis.filePath]?.[
@@ -45,6 +87,12 @@ export default function validateDependencyAnalyses({
45
87
  })
46
88
  ) {
47
89
  // already processed this analysis
90
+ if (isRootCall) {
91
+ awsLogDebugLevel(
92
+ 2,
93
+ `validateDeps: ${entity.name} already fully processed (cache hit)`,
94
+ );
95
+ }
48
96
  return { dependentAnalyses };
49
97
  }
50
98
 
@@ -69,9 +117,20 @@ export default function validateDependencyAnalyses({
69
117
 
70
118
  // if the entity has duplicate dependencies, handle gracefully
71
119
  if (dependentAnalyses[dependencyFilePath]?.[dependencyName]) {
120
+ _stats.skippedDuplicate++;
72
121
  continue;
73
122
  }
74
123
 
124
+ _stats.totalVisited++;
125
+
126
+ // Emit periodic progress so the spinner stays alive for large trees
127
+ if (_stats.totalVisited % 50 === 0) {
128
+ awsLogDebugLevel(
129
+ 1,
130
+ `Validating dependencies... (${_stats.totalVisited} resolved, depth ${_depth})`,
131
+ );
132
+ }
133
+
75
134
  // Check if dependency analysis exists in context
76
135
  const dependentAnalysis = context.getAnalysis(
77
136
  dependencyFilePath,
@@ -86,21 +145,20 @@ export default function validateDependencyAnalyses({
86
145
  );
87
146
 
88
147
  if (!dependentEntity) {
89
- // console.warn(
90
- // `CodeYam: validateDependencyAnalyses: Missing dependent entity ${dependencyFilePath}:${dependencyName} for ${entity.filePath}:${entity.name}. This is likely a bug.`,
91
- // );
148
+ _stats.skippedMissing++;
92
149
  continue;
93
150
  }
94
151
 
95
152
  // ignore trivial missing dependencies
96
- if (!['library', 'visual'].includes(dependentEntity.entityType)) continue;
153
+ if (!['library', 'visual'].includes(dependentEntity.entityType)) {
154
+ _stats.skippedTrivial++;
155
+ continue;
156
+ }
97
157
 
98
158
  if (!dependentEntity?.metadata?.hasCircularDependency) {
99
159
  // TODO: This no longer seems to happen thanks to fixes elsewhere, but leave the warning
100
- // console.warn(
101
- // `CodeYam: validateDependencyAnalyses: Missing analysis for dependency ${entity.filePath}:${entity.name} -> ${dependencyFilePath}:${dependencyName}, should be marked as having circular dependencies.`,
102
- // );
103
160
  }
161
+ _stats.skippedMissing++;
104
162
  continue;
105
163
  }
106
164
 
@@ -136,9 +194,6 @@ export default function validateDependencyAnalyses({
136
194
  if (analysis) {
137
195
  // Track dependency relationship in analysis metadata
138
196
  if (!analysis.metadata.dependentAnalyses.includes(dependentAnalysis.id)) {
139
- // console.log(
140
- // `CodeYam: validateDependencyAnalyses: Establishing dependency ${analysis.filePath}:${analysis.entityName} -> ${dependentAnalysis.filePath}:${dependentAnalysis.entityName}.`,
141
- // );
142
197
  analysis.metadata.dependentAnalyses.push(dependentAnalysis.id);
143
198
  }
144
199
  }
@@ -152,9 +207,26 @@ export default function validateDependencyAnalyses({
152
207
  entity: dependentEntity,
153
208
  context: context,
154
209
  dependentAnalyses,
210
+ _depth: _depth + 1,
211
+ _stats,
155
212
  });
156
213
  }
157
214
  }
158
215
 
216
+ // Log summary on root call completion
217
+ if (isRootCall) {
218
+ const elapsed = Date.now() - _stats.startTime;
219
+ const totalDeps = Object.values(dependentAnalyses).reduce(
220
+ (sum, fileMap) => sum + Object.keys(fileMap).length,
221
+ 0,
222
+ );
223
+ awsLogDebugLevel(
224
+ 1,
225
+ `Dependency validation complete for ${entity.name}: ${totalDeps} dependencies resolved, ` +
226
+ `${_stats.skippedDuplicate} duplicates skipped, ${_stats.skippedMissing} missing, ` +
227
+ `${_stats.skippedTrivial} trivial, max depth ${_stats.maxDepth}, ${elapsed}ms`,
228
+ );
229
+ }
230
+
159
231
  return { dependentAnalyses };
160
232
  }
@@ -3,6 +3,8 @@ import { ProjectAnalyzer } from '../ProjectAnalyzer';
3
3
  import { generateSha } from '~codeyam/database';
4
4
  import { isNextRoute } from '~codeyam/utils';
5
5
 
6
+ const warnedLayoutPaths = new Set<string>();
7
+
6
8
  export default function analyzeNextRoute(
7
9
  file: File,
8
10
  projectAnalyzer: ProjectAnalyzer,
@@ -56,9 +58,12 @@ export default function analyzeNextRoute(
56
58
 
57
59
  // Ensure entities array exists before trying to use it
58
60
  if (!layout.entities) {
59
- console.log(
60
- `CodeYam Warning: layout.entities not populated for ${layout.path}, skipping implicit dependency`,
61
- );
61
+ if (!warnedLayoutPaths.has(layout.path)) {
62
+ warnedLayoutPaths.add(layout.path);
63
+ console.log(
64
+ `CodeYam Warning: layout.entities not populated for ${layout.path}, skipping implicit dependency`,
65
+ );
66
+ }
62
67
  return;
63
68
  }
64
69
 
@@ -11,8 +11,10 @@ import {
11
11
  clearAttributesFromMapping,
12
12
  mergeJsonTypeDefinitions,
13
13
  } from '~codeyam/ai';
14
- import mergeInDependentDataStructure from './mergeInDependentDataStructure';
15
- import { awsLog } from '~codeyam/utils';
14
+ import mergeInDependentDataStructure, {
15
+ DataStructureTimeoutError,
16
+ } from './mergeInDependentDataStructure';
17
+ import { awsLog, awsLogDebugLevel } from '~codeyam/utils';
16
18
  import gatherDataForMocks from './gatherDataForMocks';
17
19
  import enrichArrayTypesFromChildSignatures from './enrichArrayTypesFromChildSignatures';
18
20
  import enrichUnknownTypesFromSourceEquivalencies from './enrichUnknownTypesFromSourceEquivalencies';
@@ -328,12 +330,23 @@ export default function generateDataStructure({
328
330
 
329
331
  // Recursive function to traverse the dependency tree
330
332
  const processedAnalyses = new Set<string>();
333
+ const traverseStart = Date.now();
334
+ const TRAVERSE_TIMEOUT_MS = 2_000;
335
+ let traverseCount = 0;
331
336
  const traverseDependencyTree = (analyses: ReadonlyAnalysisMap) => {
332
337
  for (const filePath in analyses) {
333
338
  for (const name in analyses[filePath]) {
334
339
  const analysisKey = `${filePath}:${name}`;
335
340
  if (processedAnalyses.has(analysisKey)) continue;
336
341
  processedAnalyses.add(analysisKey);
342
+ traverseCount++;
343
+
344
+ if (Date.now() - traverseStart > TRAVERSE_TIMEOUT_MS) {
345
+ throw new DataStructureTimeoutError(
346
+ entity.name,
347
+ Date.now() - traverseStart,
348
+ );
349
+ }
337
350
 
338
351
  const childAnalysis = analyses[filePath][name];
339
352
  const childEntity = childAnalysis?.entity;
@@ -443,6 +456,25 @@ export default function generateDataStructure({
443
456
  // Start traversal from direct non-mocked children
444
457
  traverseDependencyTree(nonMockedDependentAnalyses);
445
458
 
459
+ const traverseElapsed = Date.now() - traverseStart;
460
+ const childSchemaKeyCount = Object.values(childDependencySchemas).reduce(
461
+ (sum, fileMap) =>
462
+ sum +
463
+ Object.values(fileMap).reduce(
464
+ (s, schema) =>
465
+ s +
466
+ Object.keys(schema.signatureSchema || {}).length +
467
+ Object.keys(schema.returnValueSchema || {}).length,
468
+ 0,
469
+ ),
470
+ 0,
471
+ );
472
+ awsLogDebugLevel(
473
+ 1,
474
+ `Dependency tree traversal for ${entity.name}: ${traverseCount} analyses, ` +
475
+ `${childSchemaKeyCount} child schema keys, ${allImportedExports.length} imports, ${traverseElapsed}ms`,
476
+ );
477
+
446
478
  // console.info(
447
479
  // 'CODEYAM DEBUG: start merge',
448
480
  // JSON.stringify(
@@ -484,6 +516,14 @@ export default function generateDataStructure({
484
516
  dependencySchemas: isolatedDataStructure.dependencySchemas,
485
517
  });
486
518
 
519
+ const mergeStart = Date.now();
520
+ // Shared deadline for all phases from merge onward
521
+ const genDeadline = mergeStart + 5_000; // 5s total budget for all phases
522
+ awsLogDebugLevel(
523
+ 1,
524
+ `Starting mergeInDependentDataStructure for ${entity.name}...`,
525
+ );
526
+
487
527
  const mergedDataStructure = mergeInDependentDataStructure({
488
528
  importedExports: allImportedExports,
489
529
  dependentAnalyses: nonMockedDependentAnalyses,
@@ -498,6 +538,14 @@ export default function generateDataStructure({
498
538
  dependencySchemas: isolatedDataStructure?.dependencySchemas || {},
499
539
  });
500
540
 
541
+ const mergeTimedOut = !!(mergedDataStructure as any).timedOut;
542
+ awsLogDebugLevel(
543
+ 1,
544
+ `mergeInDependentDataStructure ${mergeTimedOut ? 'PARTIAL' : 'complete'} for ${entity.name}: ` +
545
+ `${Object.keys(mergedDataStructure.signatureSchema).length} sig, ` +
546
+ `${Object.keys(mergedDataStructure.returnValueSchema).length} ret, ${Date.now() - mergeStart}ms`,
547
+ );
548
+
501
549
  mergedDataStructure.environmentVariables =
502
550
  isolatedDataStructure.environmentVariables || [];
503
551
 
@@ -511,6 +559,7 @@ export default function generateDataStructure({
511
559
  // Merge collected child dependency schemas into mergedDataStructure.
512
560
  // This ensures that when gatherDataForMocks looks up schemas for child imports,
513
561
  // the child's schemas are available.
562
+ const childMergeStart = Date.now();
514
563
  for (const schemaFilePath in childDependencySchemas) {
515
564
  for (const schemaName in childDependencySchemas[schemaFilePath]) {
516
565
  mergedDataStructure.dependencySchemas[schemaFilePath] ||= {};
@@ -561,7 +610,13 @@ export default function generateDataStructure({
561
610
  }
562
611
  }
563
612
 
613
+ awsLogDebugLevel(
614
+ 1,
615
+ `Child schema merge for ${entity.name}: ${Date.now() - childMergeStart}ms`,
616
+ );
617
+
564
618
  // Transformation tracing: capture after child schemas merged
619
+ const snapshotStart = Date.now();
565
620
  transformationTracer.snapshot(entity.name, 'childSchemasMerged', {
566
621
  signatureSchema: mergedDataStructure.signatureSchema,
567
622
  returnValueSchema: mergedDataStructure.returnValueSchema,
@@ -588,71 +643,134 @@ export default function generateDataStructure({
588
643
  // ),
589
644
  // );
590
645
 
646
+ awsLogDebugLevel(
647
+ 1,
648
+ `Transformation snapshot for ${entity.name}: ${Date.now() - snapshotStart}ms`,
649
+ );
650
+
591
651
  // Deduplicate function schemas in the merged data structure
592
652
  // The merge process might introduce duplicates even if individual schemas were clean
593
- // Trace deduplication of signatureSchema
594
- const sigBefore = { ...mergedDataStructure.signatureSchema };
595
- mergedDataStructure.signatureSchema = deduplicateFunctionSchemas(
596
- mergedDataStructure.signatureSchema,
597
- );
598
- transformationTracer.traceSchemaTransformResult(
599
- entity.name,
600
- 'deduplicateFunctionSchemas',
601
- sigBefore,
602
- mergedDataStructure.signatureSchema,
603
- { schemaType: 'signature' },
604
- );
653
+ const dedupStart = Date.now();
605
654
 
606
- // Trace deduplication of returnValueSchema
607
- const rvBefore = { ...mergedDataStructure.returnValueSchema };
608
- mergedDataStructure.returnValueSchema = deduplicateFunctionSchemas(
655
+ const sigKeyCount = Object.keys(mergedDataStructure.signatureSchema).length;
656
+ const retKeyCount = Object.keys(
609
657
  mergedDataStructure.returnValueSchema,
610
- );
611
- transformationTracer.traceSchemaTransformResult(
612
- entity.name,
613
- 'deduplicateFunctionSchemas',
614
- rvBefore,
615
- mergedDataStructure.returnValueSchema,
616
- { schemaType: 'returnValue' },
658
+ ).length;
659
+
660
+ // Skip dedup on very large schemas — the O(keys × variants × keyLength) cost
661
+ // is not worth it for schemas with 10K+ keys where function dedup rarely matters.
662
+ const DEDUP_KEY_THRESHOLD = 10_000;
663
+
664
+ if (sigKeyCount < DEDUP_KEY_THRESHOLD) {
665
+ const sigBefore = { ...mergedDataStructure.signatureSchema };
666
+ mergedDataStructure.signatureSchema = deduplicateFunctionSchemas(
667
+ mergedDataStructure.signatureSchema,
668
+ );
669
+ transformationTracer.traceSchemaTransformResult(
670
+ entity.name,
671
+ 'deduplicateFunctionSchemas',
672
+ sigBefore,
673
+ mergedDataStructure.signatureSchema,
674
+ { schemaType: 'signature' },
675
+ );
676
+ } else {
677
+ awsLogDebugLevel(
678
+ 2,
679
+ `${entity.name}: skipping sig dedup (${sigKeyCount} keys > ${DEDUP_KEY_THRESHOLD})`,
680
+ );
681
+ }
682
+
683
+ if (retKeyCount < DEDUP_KEY_THRESHOLD) {
684
+ const rvBefore = { ...mergedDataStructure.returnValueSchema };
685
+ mergedDataStructure.returnValueSchema = deduplicateFunctionSchemas(
686
+ mergedDataStructure.returnValueSchema,
687
+ );
688
+ transformationTracer.traceSchemaTransformResult(
689
+ entity.name,
690
+ 'deduplicateFunctionSchemas',
691
+ rvBefore,
692
+ mergedDataStructure.returnValueSchema,
693
+ { schemaType: 'returnValue' },
694
+ );
695
+ } else {
696
+ awsLogDebugLevel(
697
+ 2,
698
+ `${entity.name}: skipping ret dedup (${retKeyCount} keys > ${DEDUP_KEY_THRESHOLD})`,
699
+ );
700
+ }
701
+
702
+ awsLogDebugLevel(
703
+ 1,
704
+ `${entity.name}: root schema dedup ${Date.now() - dedupStart}ms (sig=${sigKeyCount}, ret=${retKeyCount})`,
617
705
  );
618
706
 
619
707
  // Also deduplicate dependency schemas and clear known attributes
708
+ let depProcessed = 0;
709
+ const depStart = Date.now();
620
710
  for (const filePath in mergedDataStructure.dependencySchemas) {
621
711
  for (const depEntityName in mergedDataStructure.dependencySchemas[
622
712
  filePath
623
713
  ]) {
714
+ if (Date.now() > genDeadline) {
715
+ throw new DataStructureTimeoutError(
716
+ entity.name,
717
+ Date.now() - mergeStart,
718
+ );
719
+ }
720
+
624
721
  const depSchema =
625
722
  mergedDataStructure.dependencySchemas[filePath][depEntityName];
723
+ const depSigKeys = Object.keys(depSchema.signatureSchema || {}).length;
724
+ const depRetKeys = Object.keys(
725
+ depSchema.returnValueSchema || {},
726
+ ).length;
626
727
 
627
- // Trace deduplication of dependency signatureSchema
628
- const depSigBefore = { ...depSchema.signatureSchema };
629
- depSchema.signatureSchema = deduplicateFunctionSchemas(
630
- depSchema.signatureSchema,
631
- );
632
- transformationTracer.traceSchemaTransformResult(
633
- entity.name,
634
- 'deduplicateFunctionSchemas',
635
- depSigBefore,
636
- depSchema.signatureSchema,
637
- { filePath, dependencyName: depEntityName, schemaType: 'signature' },
638
- );
728
+ const depOpStart = Date.now();
639
729
 
640
- // Trace deduplication of dependency returnValueSchema
641
- const depRvBefore = { ...depSchema.returnValueSchema };
642
- depSchema.returnValueSchema = deduplicateFunctionSchemas(
643
- depSchema.returnValueSchema,
644
- );
645
- transformationTracer.traceSchemaTransformResult(
646
- entity.name,
647
- 'deduplicateFunctionSchemas',
648
- depRvBefore,
649
- depSchema.returnValueSchema,
650
- {
651
- filePath,
652
- dependencyName: depEntityName,
653
- schemaType: 'returnValue',
654
- },
655
- );
730
+ if (depSigKeys < DEDUP_KEY_THRESHOLD) {
731
+ const depSigBefore = { ...depSchema.signatureSchema };
732
+ depSchema.signatureSchema = deduplicateFunctionSchemas(
733
+ depSchema.signatureSchema,
734
+ );
735
+ transformationTracer.traceSchemaTransformResult(
736
+ entity.name,
737
+ 'deduplicateFunctionSchemas',
738
+ depSigBefore,
739
+ depSchema.signatureSchema,
740
+ {
741
+ filePath,
742
+ dependencyName: depEntityName,
743
+ schemaType: 'signature',
744
+ },
745
+ );
746
+ }
747
+
748
+ if (depRetKeys < DEDUP_KEY_THRESHOLD) {
749
+ const depRvBefore = { ...depSchema.returnValueSchema };
750
+ depSchema.returnValueSchema = deduplicateFunctionSchemas(
751
+ depSchema.returnValueSchema,
752
+ );
753
+ transformationTracer.traceSchemaTransformResult(
754
+ entity.name,
755
+ 'deduplicateFunctionSchemas',
756
+ depRvBefore,
757
+ depSchema.returnValueSchema,
758
+ {
759
+ filePath,
760
+ dependencyName: depEntityName,
761
+ schemaType: 'returnValue',
762
+ },
763
+ );
764
+ }
765
+
766
+ const depOpElapsed = Date.now() - depOpStart;
767
+ if (depOpElapsed > 1000) {
768
+ awsLogDebugLevel(
769
+ 2,
770
+ `${entity.name}: slow dep dedup ${depEntityName} sig=${depSigKeys} ret=${depRetKeys} ${depOpElapsed}ms`,
771
+ );
772
+ }
773
+ depProcessed++;
656
774
 
657
775
  // Infer function types from child component usage BEFORE fillInSchemaGapsAndUnknowns.
658
776
  // When a hook returns a property with type 'unknown' that is passed to a child
@@ -729,13 +847,33 @@ export default function generateDataStructure({
729
847
  // Fill in type gaps BEFORE clearing attributes, so evidence like .includes()
730
848
  // is used for type inference before being deleted
731
849
 
732
- depSchema.signatureSchema = fillInDirectSchemaGapsAndUnknowns({
733
- schema: depSchema.signatureSchema,
734
- });
850
+ const FILL_IN_KEY_THRESHOLD = 5_000;
851
+ const fillStart = Date.now();
852
+
853
+ if (depSigKeys < FILL_IN_KEY_THRESHOLD) {
854
+ depSchema.signatureSchema = fillInDirectSchemaGapsAndUnknowns({
855
+ schema: depSchema.signatureSchema,
856
+ });
857
+ }
858
+
859
+ if (depRetKeys < FILL_IN_KEY_THRESHOLD) {
860
+ depSchema.returnValueSchema = fillInDirectSchemaGapsAndUnknowns({
861
+ schema: depSchema.returnValueSchema,
862
+ });
863
+ } else {
864
+ awsLogDebugLevel(
865
+ 2,
866
+ `${entity.name}: skipping fillInGaps for ${depEntityName} ret (${depRetKeys} keys > ${FILL_IN_KEY_THRESHOLD})`,
867
+ );
868
+ }
735
869
 
736
- depSchema.returnValueSchema = fillInDirectSchemaGapsAndUnknowns({
737
- schema: depSchema.returnValueSchema,
738
- });
870
+ const fillElapsed = Date.now() - fillStart;
871
+ if (fillElapsed > 1000) {
872
+ awsLogDebugLevel(
873
+ 2,
874
+ `${entity.name}: slow fillInGaps ${depEntityName} sig=${depSigKeys} ret=${depRetKeys} ${fillElapsed}ms`,
875
+ );
876
+ }
739
877
 
740
878
  // Trace clearAttributesFromMapping on dependency schemas
741
879
  transformationTracer.traceSchemaTransform(
@@ -760,15 +898,46 @@ export default function generateDataStructure({
760
898
  }
761
899
  }
762
900
 
901
+ awsLogDebugLevel(
902
+ 1,
903
+ `${entity.name}: dep schema processing: ${depProcessed} deps in ${Date.now() - depStart}ms`,
904
+ );
905
+ awsLogDebugLevel(
906
+ 1,
907
+ `Dedup + dep schema processing for ${entity.name}: ${Date.now() - dedupStart}ms`,
908
+ );
909
+
763
910
  // Transformation tracing: capture after deduplication
911
+ const dedupSnapshotStart = Date.now();
764
912
  transformationTracer.snapshot(entity.name, 'deduplicated', {
765
913
  signatureSchema: mergedDataStructure.signatureSchema,
766
914
  returnValueSchema: mergedDataStructure.returnValueSchema,
767
915
  dependencySchemas: mergedDataStructure.dependencySchemas,
768
916
  });
769
917
 
918
+ awsLogDebugLevel(
919
+ 1,
920
+ `Dedup snapshot for ${entity.name}: ${Date.now() - dedupSnapshotStart}ms`,
921
+ );
922
+
770
923
  analysis.metadata ||= {};
771
924
  analysis.metadata.mergedDataStructure = mergedDataStructure;
925
+ if (mergeTimedOut) {
926
+ (analysis.metadata as any).mergeTimedOut = true;
927
+ }
928
+
929
+ const checkGenDeadline = (phase: string) => {
930
+ if (Date.now() > genDeadline) {
931
+ throw new DataStructureTimeoutError(
932
+ entity.name,
933
+ Date.now() - mergeStart,
934
+ );
935
+ }
936
+ awsLogDebugLevel(
937
+ 1,
938
+ `${entity.name}: ${phase} complete (${Date.now() - mergeStart}ms total)`,
939
+ );
940
+ };
772
941
 
773
942
  // Enrich mocked dependency array types with fields from child component signatures
774
943
  // This ensures that when getSurveysAction returns { data: array }, and SurveyCard
@@ -787,6 +956,8 @@ export default function generateDataStructure({
787
956
  ),
788
957
  );
789
958
 
959
+ checkGenDeadline('enrichArrayTypes');
960
+
790
961
  // Transformation tracing: capture after array types enriched
791
962
  transformationTracer.snapshot(entity.name, 'arrayTypesEnriched', {
792
963
  signatureSchema: mergedDataStructure.signatureSchema,
@@ -811,6 +982,8 @@ export default function generateDataStructure({
811
982
  ),
812
983
  );
813
984
 
985
+ checkGenDeadline('enrichUnknownTypes');
986
+
814
987
  // Transformation tracing: capture after unknown types enriched
815
988
  transformationTracer.snapshot(entity.name, 'unknownTypesEnriched', {
816
989
  signatureSchema: mergedDataStructure.signatureSchema,
@@ -831,6 +1004,8 @@ export default function generateDataStructure({
831
1004
  { entityName: entity.name },
832
1005
  );
833
1006
 
1007
+ checkGenDeadline('gatherDataForMocks');
1008
+
834
1009
  // Transformation tracing: capture after dataForMocks gathered
835
1010
  transformationTracer.snapshot(entity.name, 'dataForMocksGathered', {
836
1011
  signatureSchema: mergedDataStructure.signatureSchema,
@@ -860,6 +1035,8 @@ export default function generateDataStructure({
860
1035
  }
861
1036
  }
862
1037
 
1038
+ checkGenDeadline('mergeChildDataForMocks');
1039
+
863
1040
  const finalizedArgumentsSchema = { ...mergedDataStructure.signatureSchema };
864
1041
 
865
1042
  // Trace fillInDirectSchemaGapsAndUnknowns
@@ -880,9 +1057,13 @@ export default function generateDataStructure({
880
1057
  { stage: 'finalization' },
881
1058
  );
882
1059
 
1060
+ checkGenDeadline('fillInGaps+clearAttributes');
1061
+
883
1062
  const argumentsSchema = convertDotNotation(finalizedArgumentsSchema)
884
1063
  .signature as JsonTypeDefinition[];
885
1064
 
1065
+ checkGenDeadline('convertDotNotation');
1066
+
886
1067
  analysis.metadata.scenariosDataStructure = {
887
1068
  arguments: argumentsSchema,
888
1069
  dataForMocks,