@codeyam/codeyam-cli 0.1.0-staging.323686 → 0.1.0-staging.4813bf3

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 (444) 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 +5 -5
  4. package/analyzer-template/packages/ai/index.ts +7 -1
  5. package/analyzer-template/packages/ai/package.json +2 -2
  6. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +62 -18
  7. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +67 -9
  8. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.ts +10 -17
  9. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +409 -50
  10. package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
  11. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +21 -6
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +992 -249
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +5 -1
  14. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.ts +16 -3
  15. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.ts +6 -4
  16. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +31 -3
  17. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +37 -15
  18. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.ts +70 -0
  19. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +126 -11
  20. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +179 -0
  21. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts +40 -30
  22. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +367 -96
  23. package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +33 -15
  24. package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +58 -3
  25. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +315 -6
  26. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +9 -5
  27. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +49 -5
  28. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
  29. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +649 -142
  30. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +1 -1
  31. package/analyzer-template/packages/ai/src/lib/isolateScopes.ts +51 -3
  32. package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
  33. package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
  34. package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
  35. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +10 -7
  36. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +24 -4
  37. package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +25 -13
  38. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +4 -3
  39. package/analyzer-template/packages/analyze/index.ts +2 -0
  40. package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +65 -59
  41. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +113 -26
  42. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.ts +19 -0
  43. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.ts +19 -0
  44. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllExports.ts +11 -0
  45. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.ts +8 -0
  46. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.ts +49 -1
  47. package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.ts +2 -1
  48. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +89 -9
  49. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +19 -4
  50. package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
  51. package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +0 -3
  52. package/analyzer-template/packages/analyze/src/lib/files/analyzeRemixRoute.ts +4 -5
  53. package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +14 -12
  54. package/analyzer-template/packages/analyze/src/lib/files/scenarios/TransformationTracer.ts +1315 -0
  55. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +61 -13
  56. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +37 -0
  57. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +229 -19
  58. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +117 -9
  59. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +459 -39
  60. package/analyzer-template/packages/analyze/src/lib/files/scenarios/propagateArrayItemSchemas.ts +474 -0
  61. package/analyzer-template/packages/analyze/src/lib/files/setImportedExports.ts +2 -1
  62. package/analyzer-template/packages/analyze/src/lib/index.ts +1 -0
  63. package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
  64. package/analyzer-template/packages/aws/package.json +1 -1
  65. package/analyzer-template/packages/database/package.json +1 -1
  66. package/analyzer-template/packages/database/src/lib/analysisBranchToDb.ts +1 -1
  67. package/analyzer-template/packages/database/src/lib/analysisToDb.ts +1 -1
  68. package/analyzer-template/packages/database/src/lib/branchToDb.ts +1 -1
  69. package/analyzer-template/packages/database/src/lib/commitBranchToDb.ts +1 -1
  70. package/analyzer-template/packages/database/src/lib/commitToDb.ts +1 -1
  71. package/analyzer-template/packages/database/src/lib/fileToDb.ts +1 -1
  72. package/analyzer-template/packages/database/src/lib/kysely/db.ts +6 -0
  73. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
  74. package/analyzer-template/packages/database/src/lib/kysely/tables/labsRequestsTable.ts +52 -0
  75. package/analyzer-template/packages/database/src/lib/projectToDb.ts +1 -1
  76. package/analyzer-template/packages/database/src/lib/saveFiles.ts +1 -1
  77. package/analyzer-template/packages/database/src/lib/scenarioToDb.ts +1 -1
  78. package/analyzer-template/packages/database/src/lib/userScenarioToDb.ts +1 -1
  79. package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js +1 -1
  80. package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js.map +1 -1
  81. package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js +1 -1
  82. package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js.map +1 -1
  83. package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js +1 -1
  84. package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js.map +1 -1
  85. package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js +1 -1
  86. package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js.map +1 -1
  87. package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js +1 -1
  88. package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js.map +1 -1
  89. package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js +1 -1
  90. package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js.map +1 -1
  91. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -0
  92. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
  93. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +3 -0
  94. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
  95. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +1 -1
  96. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts +23 -0
  97. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts.map +1 -0
  98. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
  99. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
  100. package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js +1 -1
  101. package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js.map +1 -1
  102. package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js +1 -1
  103. package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js.map +1 -1
  104. package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js +1 -1
  105. package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js.map +1 -1
  106. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +7 -0
  107. package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  108. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
  109. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  110. package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
  111. package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
  112. package/analyzer-template/packages/github/package.json +1 -1
  113. package/analyzer-template/packages/types/src/types/ProjectMetadata.ts +7 -0
  114. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +6 -5
  115. package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
  116. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +7 -0
  117. package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
  118. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
  119. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  120. package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
  121. package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
  122. package/analyzer-template/project/constructMockCode.ts +90 -10
  123. package/analyzer-template/project/writeMockDataTsx.ts +181 -8
  124. package/analyzer-template/project/writeScenarioComponents.ts +60 -12
  125. package/analyzer-template/project/writeSimpleRoot.ts +21 -11
  126. package/background/src/lib/local/createLocalAnalyzer.js +1 -1
  127. package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
  128. package/background/src/lib/virtualized/project/constructMockCode.js +75 -4
  129. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  130. package/background/src/lib/virtualized/project/writeMockDataTsx.js +162 -4
  131. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  132. package/background/src/lib/virtualized/project/writeScenarioComponents.js +60 -15
  133. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  134. package/background/src/lib/virtualized/project/writeSimpleRoot.js +21 -11
  135. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  136. package/codeyam-cli/scripts/apply-setup.js +180 -0
  137. package/codeyam-cli/scripts/apply-setup.js.map +1 -1
  138. package/codeyam-cli/src/cli.js +2 -0
  139. package/codeyam-cli/src/cli.js.map +1 -1
  140. package/codeyam-cli/src/codeyam-cli.js +18 -2
  141. package/codeyam-cli/src/codeyam-cli.js.map +1 -1
  142. package/codeyam-cli/src/commands/analyze.js +4 -2
  143. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  144. package/codeyam-cli/src/commands/baseline.js +2 -0
  145. package/codeyam-cli/src/commands/baseline.js.map +1 -1
  146. package/codeyam-cli/src/commands/debug.js +9 -5
  147. package/codeyam-cli/src/commands/debug.js.map +1 -1
  148. package/codeyam-cli/src/commands/default.js +31 -20
  149. package/codeyam-cli/src/commands/default.js.map +1 -1
  150. package/codeyam-cli/src/commands/detect-universal-mocks.js +2 -0
  151. package/codeyam-cli/src/commands/detect-universal-mocks.js.map +1 -1
  152. package/codeyam-cli/src/commands/init.js +49 -257
  153. package/codeyam-cli/src/commands/init.js.map +1 -1
  154. package/codeyam-cli/src/commands/memory.js +17 -26
  155. package/codeyam-cli/src/commands/memory.js.map +1 -1
  156. package/codeyam-cli/src/commands/recapture.js +2 -0
  157. package/codeyam-cli/src/commands/recapture.js.map +1 -1
  158. package/codeyam-cli/src/commands/setup-sandbox.js +2 -0
  159. package/codeyam-cli/src/commands/setup-sandbox.js.map +1 -1
  160. package/codeyam-cli/src/commands/setup-simulations.js +284 -0
  161. package/codeyam-cli/src/commands/setup-simulations.js.map +1 -0
  162. package/codeyam-cli/src/commands/test-startup.js +2 -0
  163. package/codeyam-cli/src/commands/test-startup.js.map +1 -1
  164. package/codeyam-cli/src/commands/verify.js +14 -2
  165. package/codeyam-cli/src/commands/verify.js.map +1 -1
  166. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +128 -86
  167. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  168. package/codeyam-cli/src/utils/analyzer.js +7 -0
  169. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  170. package/codeyam-cli/src/utils/backgroundServer.js +5 -0
  171. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  172. package/codeyam-cli/src/utils/generateReport.js +2 -2
  173. package/codeyam-cli/src/utils/install-skills.js +70 -45
  174. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  175. package/codeyam-cli/src/utils/labsAutoCheck.js +19 -0
  176. package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -0
  177. package/codeyam-cli/src/utils/progress.js +7 -0
  178. package/codeyam-cli/src/utils/progress.js.map +1 -1
  179. package/codeyam-cli/src/utils/queue/job.js +4 -0
  180. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  181. package/codeyam-cli/src/utils/requireSimulations.js +10 -0
  182. package/codeyam-cli/src/utils/requireSimulations.js.map +1 -0
  183. package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js +82 -0
  184. package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js.map +1 -0
  185. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +230 -0
  186. package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -0
  187. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js +67 -0
  188. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js.map +1 -0
  189. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js +105 -0
  190. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js.map +1 -0
  191. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js +34 -0
  192. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js.map +1 -0
  193. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js +162 -0
  194. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js.map +1 -0
  195. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js +75 -0
  196. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js.map +1 -0
  197. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +378 -0
  198. package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -0
  199. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +115 -0
  200. package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -0
  201. package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js +127 -0
  202. package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js.map +1 -0
  203. package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js +50 -0
  204. package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js.map +1 -0
  205. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +116 -0
  206. package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -0
  207. package/codeyam-cli/src/utils/ruleReflection/index.js +5 -0
  208. package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -0
  209. package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +44 -0
  210. package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -0
  211. package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js +85 -0
  212. package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js.map +1 -0
  213. package/codeyam-cli/src/utils/ruleReflection/types.js +5 -0
  214. package/codeyam-cli/src/utils/ruleReflection/types.js.map +1 -0
  215. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +293 -0
  216. package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -0
  217. package/codeyam-cli/src/utils/rules/index.js +1 -0
  218. package/codeyam-cli/src/utils/rules/index.js.map +1 -1
  219. package/codeyam-cli/src/utils/rules/parser.js +2 -25
  220. package/codeyam-cli/src/utils/rules/parser.js.map +1 -1
  221. package/codeyam-cli/src/utils/rules/ruleState.js +150 -0
  222. package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -0
  223. package/codeyam-cli/src/utils/rules/staleness.js +16 -11
  224. package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
  225. package/codeyam-cli/src/utils/serverState.js +37 -10
  226. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  227. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +21 -44
  228. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  229. package/codeyam-cli/src/webserver/app/lib/database.js +15 -3
  230. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  231. package/codeyam-cli/src/webserver/backgroundServer.js +24 -0
  232. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  233. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CA3JxPb7.js +1 -0
  234. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-DsN1wKrm.js → EntityItem-B86KKU7e.js} +1 -1
  235. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-DLqD3qNt.js → EntityTypeBadge-B5ctlSYt.js} +1 -1
  236. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-Ba2JVPzP.js → EntityTypeIcon-BqY8gDAW.js} +1 -1
  237. package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-C8lyxW9k.js → InlineSpinner-ClaLpuOo.js} +1 -1
  238. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-aht4aafF.js → InteractivePreview-BDhPilK7.js} +2 -2
  239. package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-CVtiBnY5.js → LibraryFunctionPreview-VeqEBv9v.js} +1 -1
  240. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-B0GLXMsr.js → LoadingDots-Bs7Nn1Jr.js} +1 -1
  241. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-xgeCVgSM.js → LogViewer-Bm3PmcCz.js} +1 -1
  242. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-OApQuNyq.js → ReportIssueModal-CgMEzchJ.js} +3 -8
  243. package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-DuDvi0jm.js → SafeScreenshot-Gq3Ocjo6.js} +1 -1
  244. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-DzccYyI8.js → ScenarioViewer-CBui0id_.js} +2 -2
  245. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-DyFZkK0l.js → TruncatedFilePath-CiwXDxLh.js} +1 -1
  246. package/codeyam-cli/src/webserver/build/client/assets/{_index-BwqWJOgH.js → _index-B3TDXxnk.js} +1 -1
  247. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BwavGCpm.js → activity.(_tab)-BtBFH820.js} +6 -11
  248. package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-CN61MOMa.js +11 -0
  249. package/codeyam-cli/src/webserver/build/client/assets/api.agent-transcripts-l0sNRNKZ.js +1 -0
  250. package/codeyam-cli/src/webserver/build/client/assets/api.labs-unlock-l0sNRNKZ.js +1 -0
  251. package/codeyam-cli/src/webserver/build/client/assets/api.save-fixture-l0sNRNKZ.js +1 -0
  252. package/codeyam-cli/src/webserver/build/client/assets/book-open-PttOB2SF.js +6 -0
  253. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-Cx24_aWc.js → chevron-down-TJp6ofnp.js} +1 -1
  254. package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-CXRTFQ3F.js → chunk-JZWAC4HX-JE9ZIoBl.js} +12 -12
  255. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-BOARzkeR.js → circle-check-CXhHQYrI.js} +1 -1
  256. package/codeyam-cli/src/webserver/build/client/assets/copy-6y9ALfGT.js +11 -0
  257. package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-BdhJEx6B.js → createLucideIcon-Ca9fAY46.js} +1 -1
  258. package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-BBnGWYga.js → dev.empty-C0epRiVn.js} +1 -1
  259. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-BJUiQqZF.js → entity._sha._-BVnB8a9L.js} +10 -10
  260. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js → entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js} +1 -1
  261. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-D1T4TGjf.js → entity._sha_.create-scenario-DGgZjdFg.js} +1 -1
  262. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CTBG2mmz.js → entity._sha_.edit._scenarioId-38yPijoD.js} +1 -1
  263. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-CS2cb_eZ.js → entry.client-BSHEfydn.js} +1 -1
  264. package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DMJ7zii9.js → fileTableUtils-DCPhhSMo.js} +1 -1
  265. package/codeyam-cli/src/webserver/build/client/assets/{files-CJ6lTdTA.js → files-0N0YJQv7.js} +1 -1
  266. package/codeyam-cli/src/webserver/build/client/assets/{git-CPTZZ-JZ.js → git-DXnyr8uP.js} +1 -1
  267. package/codeyam-cli/src/webserver/build/client/assets/globals-CKT08Djd.css +1 -0
  268. package/codeyam-cli/src/webserver/build/client/assets/{index-lzqtyFU8.js → index-CcsFv748.js} +1 -1
  269. package/codeyam-cli/src/webserver/build/client/assets/{index-B1h680n5.js → index-ChN9-fAY.js} +1 -1
  270. package/codeyam-cli/src/webserver/build/client/assets/labs-BLJ7HxOC.js +1 -0
  271. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-B7B9V-bu.js → loader-circle-CTqLEAGU.js} +1 -1
  272. package/codeyam-cli/src/webserver/build/client/assets/manifest-b171b9d3.js +1 -0
  273. package/codeyam-cli/src/webserver/build/client/assets/memory-CCQd4aZA.js +78 -0
  274. package/codeyam-cli/src/webserver/build/client/assets/pause-D6vreykR.js +11 -0
  275. package/codeyam-cli/src/webserver/build/client/assets/root-CHhiHoo_.js +62 -0
  276. package/codeyam-cli/src/webserver/build/client/assets/{search-CxXUmBSd.js → search-B8VUL8nl.js} +1 -1
  277. package/codeyam-cli/src/webserver/build/client/assets/settings-BejnUJ6R.js +1 -0
  278. package/codeyam-cli/src/webserver/build/client/assets/{simulations-DwFIBT09.js → simulations-CPoAg7Zo.js} +1 -1
  279. package/codeyam-cli/src/webserver/build/client/assets/terminal-BrCP7uQo.js +11 -0
  280. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-B6LgvRJg.js → triangle-alert-BZz2NjYa.js} +1 -1
  281. package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-C1v1PQzo.js → useCustomSizes-DNwUduNu.js} +1 -1
  282. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-aSv48UbS.js → useLastLogLine-COky1GVF.js} +1 -1
  283. package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-DYxHZQuP.js → useReportContext-CpZgwliL.js} +1 -1
  284. package/codeyam-cli/src/webserver/build/client/assets/{useToast-mBRpZPiu.js → useToast-Bv9JFvUO.js} +1 -1
  285. package/codeyam-cli/src/webserver/build/server/assets/{index-DVzYx8PN.js → index-8Fv-lH1-.js} +1 -1
  286. package/codeyam-cli/src/webserver/build/server/assets/server-build-Akn3iYFP.js +257 -0
  287. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  288. package/codeyam-cli/src/webserver/build-info.json +5 -5
  289. package/codeyam-cli/templates/{codeyam:debug.md → codeyam-debug.md} +1 -1
  290. package/codeyam-cli/templates/codeyam-diagnose.md +481 -0
  291. package/codeyam-cli/templates/codeyam-memory-hook.sh +19 -20
  292. package/codeyam-cli/templates/codeyam-memory.md +392 -0
  293. package/codeyam-cli/templates/codeyam-new-rule.md +13 -0
  294. package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +13 -1
  295. package/codeyam-cli/templates/{codeyam:sim.md → codeyam-sim.md} +1 -1
  296. package/codeyam-cli/templates/{codeyam:test.md → codeyam-test.md} +1 -1
  297. package/codeyam-cli/templates/{codeyam:verify.md → codeyam-verify.md} +1 -1
  298. package/codeyam-cli/templates/rule-notification-hook.py +56 -0
  299. package/codeyam-cli/templates/rule-reflection-hook.py +627 -0
  300. package/codeyam-cli/templates/rules-instructions.md +132 -0
  301. package/package.json +2 -2
  302. package/packages/ai/index.js +3 -2
  303. package/packages/ai/index.js.map +1 -1
  304. package/packages/ai/src/lib/analyzeScope.js +50 -13
  305. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  306. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +54 -8
  307. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  308. package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js +10 -14
  309. package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js.map +1 -1
  310. package/packages/ai/src/lib/astScopes/processExpression.js +317 -44
  311. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  312. package/packages/ai/src/lib/astScopes/sharedPatterns.js +25 -0
  313. package/packages/ai/src/lib/astScopes/sharedPatterns.js.map +1 -1
  314. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +763 -171
  315. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  316. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +5 -1
  317. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  318. package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js +13 -3
  319. package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js.map +1 -1
  320. package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js +6 -4
  321. package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js.map +1 -1
  322. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +33 -3
  323. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  324. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +36 -11
  325. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  326. package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js +63 -0
  327. package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js.map +1 -0
  328. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +113 -11
  329. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  330. package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +173 -0
  331. package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -0
  332. package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js +37 -20
  333. package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js.map +1 -1
  334. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +309 -84
  335. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  336. package/packages/ai/src/lib/dataStructureChunking.js +26 -11
  337. package/packages/ai/src/lib/dataStructureChunking.js.map +1 -1
  338. package/packages/ai/src/lib/generateEntityDataStructure.js +46 -2
  339. package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
  340. package/packages/ai/src/lib/generateEntityScenarioData.js +227 -4
  341. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  342. package/packages/ai/src/lib/generateEntityScenarios.js +7 -1
  343. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  344. package/packages/ai/src/lib/generateExecutionFlows.js +26 -4
  345. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  346. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +447 -80
  347. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
  348. package/packages/ai/src/lib/isolateScopes.js +39 -3
  349. package/packages/ai/src/lib/isolateScopes.js.map +1 -1
  350. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js +5 -0
  351. package/packages/ai/src/lib/mergeJsonTypeDefinitions.js.map +1 -1
  352. package/packages/ai/src/lib/mergeStatements.js +70 -51
  353. package/packages/ai/src/lib/mergeStatements.js.map +1 -1
  354. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js +97 -0
  355. package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
  356. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +10 -4
  357. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  358. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +17 -2
  359. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
  360. package/packages/ai/src/lib/resolvePathToControllable.js +24 -14
  361. package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
  362. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  363. package/packages/analyze/index.js +1 -0
  364. package/packages/analyze/index.js.map +1 -1
  365. package/packages/analyze/src/lib/FileAnalyzer.js +60 -36
  366. package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
  367. package/packages/analyze/src/lib/ProjectAnalyzer.js +96 -26
  368. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  369. package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js +14 -0
  370. package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js.map +1 -1
  371. package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js +14 -0
  372. package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js.map +1 -1
  373. package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js +6 -0
  374. package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js.map +1 -1
  375. package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js +6 -0
  376. package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js.map +1 -1
  377. package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js +39 -1
  378. package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js.map +1 -1
  379. package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js +2 -1
  380. package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js.map +1 -1
  381. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +65 -7
  382. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  383. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +17 -4
  384. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  385. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +2 -1
  386. package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
  387. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +0 -3
  388. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
  389. package/packages/analyze/src/lib/files/analyzeRemixRoute.js +3 -2
  390. package/packages/analyze/src/lib/files/analyzeRemixRoute.js.map +1 -1
  391. package/packages/analyze/src/lib/files/getImportedExports.js +11 -7
  392. package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
  393. package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js +880 -0
  394. package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js.map +1 -0
  395. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +56 -10
  396. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
  397. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +33 -8
  398. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  399. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +150 -17
  400. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  401. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +56 -8
  402. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
  403. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +399 -31
  404. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  405. package/packages/analyze/src/lib/files/setImportedExports.js +2 -1
  406. package/packages/analyze/src/lib/files/setImportedExports.js.map +1 -1
  407. package/packages/analyze/src/lib/index.js +1 -0
  408. package/packages/analyze/src/lib/index.js.map +1 -1
  409. package/packages/analyze/src/lib/utils/getFileByPath.js +12 -0
  410. package/packages/analyze/src/lib/utils/getFileByPath.js.map +1 -0
  411. package/packages/database/src/lib/analysisBranchToDb.js +1 -1
  412. package/packages/database/src/lib/analysisBranchToDb.js.map +1 -1
  413. package/packages/database/src/lib/analysisToDb.js +1 -1
  414. package/packages/database/src/lib/analysisToDb.js.map +1 -1
  415. package/packages/database/src/lib/branchToDb.js +1 -1
  416. package/packages/database/src/lib/branchToDb.js.map +1 -1
  417. package/packages/database/src/lib/commitBranchToDb.js +1 -1
  418. package/packages/database/src/lib/commitBranchToDb.js.map +1 -1
  419. package/packages/database/src/lib/commitToDb.js +1 -1
  420. package/packages/database/src/lib/commitToDb.js.map +1 -1
  421. package/packages/database/src/lib/fileToDb.js +1 -1
  422. package/packages/database/src/lib/fileToDb.js.map +1 -1
  423. package/packages/database/src/lib/kysely/db.js +3 -0
  424. package/packages/database/src/lib/kysely/db.js.map +1 -1
  425. package/packages/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
  426. package/packages/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
  427. package/packages/database/src/lib/projectToDb.js +1 -1
  428. package/packages/database/src/lib/projectToDb.js.map +1 -1
  429. package/packages/database/src/lib/saveFiles.js +1 -1
  430. package/packages/database/src/lib/saveFiles.js.map +1 -1
  431. package/packages/database/src/lib/scenarioToDb.js +1 -1
  432. package/packages/database/src/lib/scenarioToDb.js.map +1 -1
  433. package/scripts/finalize-analyzer.cjs +8 -76
  434. package/codeyam-cli/src/webserver/build/client/assets/copy-Bb-80kDT.js +0 -6
  435. package/codeyam-cli/src/webserver/build/client/assets/file-code-Dhef1kWN.js +0 -6
  436. package/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +0 -1
  437. package/codeyam-cli/src/webserver/build/client/assets/manifest-7522edd4.js +0 -1
  438. package/codeyam-cli/src/webserver/build/client/assets/memory-yxFcrxBX.js +0 -92
  439. package/codeyam-cli/src/webserver/build/client/assets/root-eVAaavTS.js +0 -62
  440. package/codeyam-cli/src/webserver/build/client/assets/settings-CS5f3WzT.js +0 -1
  441. package/codeyam-cli/src/webserver/build/server/assets/server-build-4Cr0uToj.js +0 -257
  442. package/codeyam-cli/templates/codeyam:diagnose.md +0 -803
  443. package/codeyam-cli/templates/codeyam:memory.md +0 -462
  444. package/codeyam-cli/templates/codeyam:new-rule.md +0 -13
@@ -0,0 +1,1315 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ /**
5
+ * TransformationTracer
6
+ *
7
+ * A tracer that captures data structure transformations during analysis.
8
+ * Captures everything at both coarse-grained (stage snapshots) and fine-grained
9
+ * (individual operations) levels for post-hoc analysis without rerunning.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```typescript
14
+ * // Enable via environment variable
15
+ * CODEYAM_TRACE_TRANSFORMS=1 codeyam analyze
16
+ *
17
+ * // In code
18
+ * transformationTracer.startEntity(entity);
19
+ * transformationTracer.snapshot(entity.name, 'isolated', { signatureSchema, ... });
20
+ * transformationTracer.operation(entity.name, { operation: 'mergePostfix', path: 'sig[0].user', ... });
21
+ * transformationTracer.snapshot(entity.name, 'merged', { signatureSchema, ... });
22
+ * ```
23
+ *
24
+ * ## Analyzing Traces
25
+ *
26
+ * ```typescript
27
+ * const tracer = TransformationTracer.loadTrace('/tmp/codeyam/transform-trace.json');
28
+ * console.log(tracer.getSummary());
29
+ * console.log(tracer.getEntitySummary('DashboardPage'));
30
+ * console.log(tracer.tracePath('DashboardPage', 'signature[0].user'));
31
+ * ```
32
+ */
33
+
34
+ // ============================================================================
35
+ // Types
36
+ // ============================================================================
37
+
38
+ export interface SchemaDiff {
39
+ added: Record<string, string>;
40
+ removed: Record<string, string>;
41
+ changed: Record<string, { from: string; to: string }>;
42
+ }
43
+
44
+ export interface StageSnapshot {
45
+ stage: string;
46
+ timestamp: number;
47
+ data: {
48
+ signatureSchema?: Record<string, string>;
49
+ returnValueSchema?: Record<string, string>;
50
+ dependencySchemas?: Record<string, Record<string, any>>;
51
+ dataForMocks?: Record<string, any>;
52
+ };
53
+ diffFromPrevious?: {
54
+ signatureSchema?: SchemaDiff;
55
+ returnValueSchema?: SchemaDiff;
56
+ dependencySchemas?: Record<string, SchemaDiff>;
57
+ };
58
+ }
59
+
60
+ export interface Operation {
61
+ operation: string;
62
+ stage?: string;
63
+ path?: string;
64
+ before?: any;
65
+ after?: any;
66
+ context?: Record<string, any>;
67
+ timestamp?: number;
68
+ }
69
+
70
+ export interface EntityTrace {
71
+ entityName: string;
72
+ entityType: string;
73
+ filePath: string;
74
+ stages: StageSnapshot[];
75
+ operations: Operation[];
76
+ }
77
+
78
+ export interface TraceFile {
79
+ meta: {
80
+ timestamp: string;
81
+ projectSlug?: string;
82
+ entityCount: number;
83
+ };
84
+ summary: {
85
+ stageChangeCounts: Record<
86
+ string,
87
+ { added: number; removed: number; changed: number }
88
+ >;
89
+ entitiesWithMostChanges: string[];
90
+ };
91
+ entities: Record<string, EntityTrace>;
92
+ }
93
+
94
+ export interface CoarseSummary {
95
+ entityCount: number;
96
+ stageChangeCounts: Record<
97
+ string,
98
+ { added: number; removed: number; changed: number }
99
+ >;
100
+ entitiesWithMostChanges: Array<{ name: string; totalChanges: number }>;
101
+ }
102
+
103
+ export interface EntityStageSummary {
104
+ entityName: string;
105
+ stages: Array<{
106
+ stage: string;
107
+ diffFromPrevious?: {
108
+ signatureSchema?: SchemaDiff;
109
+ returnValueSchema?: SchemaDiff;
110
+ };
111
+ }>;
112
+ }
113
+
114
+ export interface PathHistory {
115
+ entityName: string;
116
+ path: string;
117
+ history: Array<{
118
+ stage?: string;
119
+ operation?: string;
120
+ value: any;
121
+ context?: Record<string, any>;
122
+ }>;
123
+ }
124
+
125
+ export interface TransformationTracerOptions {
126
+ enabled: boolean;
127
+ outputPath?: string;
128
+ }
129
+
130
+ // ============================================================================
131
+ // Utility Functions
132
+ // ============================================================================
133
+
134
+ /**
135
+ * Compute the diff between two schema objects.
136
+ */
137
+ export function computeSchemaDiff(
138
+ before: Record<string, string> | undefined,
139
+ after: Record<string, string> | undefined,
140
+ ): SchemaDiff {
141
+ const diff: SchemaDiff = {
142
+ added: {},
143
+ removed: {},
144
+ changed: {},
145
+ };
146
+
147
+ const beforeKeys = new Set(Object.keys(before ?? {}));
148
+ const afterKeys = new Set(Object.keys(after ?? {}));
149
+
150
+ // Find added keys
151
+ for (const key of afterKeys) {
152
+ if (!beforeKeys.has(key)) {
153
+ diff.added[key] = after![key];
154
+ }
155
+ }
156
+
157
+ // Find removed keys
158
+ for (const key of beforeKeys) {
159
+ if (!afterKeys.has(key)) {
160
+ diff.removed[key] = before![key];
161
+ }
162
+ }
163
+
164
+ // Find changed keys
165
+ for (const key of beforeKeys) {
166
+ if (afterKeys.has(key) && before![key] !== after![key]) {
167
+ diff.changed[key] = { from: before![key], to: after![key] };
168
+ }
169
+ }
170
+
171
+ return diff;
172
+ }
173
+
174
+ /**
175
+ * Check if a diff has any changes.
176
+ */
177
+ export function hasDiffChanges(diff: SchemaDiff): boolean {
178
+ return (
179
+ Object.keys(diff.added).length > 0 ||
180
+ Object.keys(diff.removed).length > 0 ||
181
+ Object.keys(diff.changed).length > 0
182
+ );
183
+ }
184
+
185
+ /**
186
+ * Count total changes in a diff.
187
+ */
188
+ export function countDiffChanges(diff: SchemaDiff): number {
189
+ return (
190
+ Object.keys(diff.added).length +
191
+ Object.keys(diff.removed).length +
192
+ Object.keys(diff.changed).length
193
+ );
194
+ }
195
+
196
+ // ============================================================================
197
+ // TransformationTracer Class
198
+ // ============================================================================
199
+
200
+ // Global counter to identify tracer instances
201
+ let tracerInstanceCounter = 0;
202
+
203
+ export class TransformationTracer {
204
+ private enabled: boolean;
205
+ private outputPath: string;
206
+ private traces: Map<string, EntityTrace> = new Map();
207
+ private currentEntity: string | null = null;
208
+ private currentStage: string | null = null;
209
+ private projectSlug: string | undefined;
210
+ private tracerId: number;
211
+
212
+ constructor(options?: TransformationTracerOptions) {
213
+ this.tracerId = ++tracerInstanceCounter;
214
+ this.enabled = options?.enabled ?? false;
215
+ this.outputPath =
216
+ options?.outputPath ?? '/tmp/codeyam/transform-trace.json';
217
+
218
+ if (this.enabled) {
219
+ console.log(
220
+ `[Tracer] Initialized (id=${this.tracerId}, output=${this.outputPath})`,
221
+ );
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Log a message (only when tracing is enabled).
227
+ */
228
+ private log(message: string): void {
229
+ if (this.isEnabled()) {
230
+ console.log(`[Tracer] ${message}`);
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Check if tracing is enabled.
236
+ * Dynamically checks environment variable so it works even if set after module load.
237
+ */
238
+ isEnabled(): boolean {
239
+ // Check environment variable dynamically - allows setting after module load
240
+ const envValue = process.env.CODEYAM_TRACE_TRANSFORMS;
241
+ if (envValue === '1' || envValue === 'true') {
242
+ return true;
243
+ }
244
+ return this.enabled;
245
+ }
246
+
247
+ /**
248
+ * Enable tracing.
249
+ */
250
+ enable(): void {
251
+ this.enabled = true;
252
+ }
253
+
254
+ /**
255
+ * Disable tracing.
256
+ */
257
+ disable(): void {
258
+ this.enabled = false;
259
+ }
260
+
261
+ /**
262
+ * Set the output path for the trace file.
263
+ */
264
+ setOutputPath(outputPath: string): void {
265
+ this.outputPath = outputPath;
266
+ }
267
+
268
+ /**
269
+ * Set the project slug for metadata.
270
+ */
271
+ setProjectSlug(slug: string): void {
272
+ this.projectSlug = slug;
273
+ }
274
+
275
+ /**
276
+ * Start tracing a new entity.
277
+ * If the entity already exists, preserves its existing stages and operations.
278
+ */
279
+ startEntity(entity: {
280
+ name: string;
281
+ entityType: string;
282
+ filePath: string;
283
+ }): void {
284
+ if (!this.isEnabled()) return;
285
+
286
+ this.currentEntity = entity.name;
287
+
288
+ // Preserve existing trace data if entity was already started
289
+ // (e.g., early stages from generateEntityDataStructure.ts)
290
+ const existing = this.traces.get(entity.name);
291
+ if (existing) {
292
+ this.log(
293
+ `startEntity: ${entity.name} already exists, preserving ${existing.stages.length} stages`,
294
+ );
295
+ return; // Keep existing trace data
296
+ }
297
+
298
+ this.log(`startEntity: ${entity.name}`);
299
+ this.traces.set(entity.name, {
300
+ entityName: entity.name,
301
+ entityType: entity.entityType,
302
+ filePath: entity.filePath,
303
+ stages: [],
304
+ operations: [],
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Take a coarse-grained snapshot at a transformation stage.
310
+ */
311
+ snapshot(
312
+ entityName: string,
313
+ stage: string,
314
+ data: StageSnapshot['data'],
315
+ ): void {
316
+ if (!this.isEnabled()) return;
317
+
318
+ const trace = this.traces.get(entityName);
319
+ if (!trace) {
320
+ this.log(`snapshot: no trace for ${entityName}, creating one`);
321
+ this.startEntity({
322
+ name: entityName,
323
+ entityType: 'unknown',
324
+ filePath: 'unknown',
325
+ });
326
+ return this.snapshot(entityName, stage, data);
327
+ }
328
+
329
+ this.log(`snapshot: ${entityName} → ${stage}`);
330
+ this.currentStage = stage;
331
+
332
+ // Deep clone the data to avoid capturing references that change later
333
+ const clonedData = JSON.parse(JSON.stringify(data));
334
+
335
+ const snapshot: StageSnapshot = {
336
+ stage,
337
+ timestamp: Date.now(),
338
+ data: clonedData,
339
+ };
340
+
341
+ // Compute diff from previous stage if there is one
342
+ const previousSnapshot = trace.stages[trace.stages.length - 1];
343
+ if (previousSnapshot) {
344
+ snapshot.diffFromPrevious = {
345
+ signatureSchema: computeSchemaDiff(
346
+ previousSnapshot.data.signatureSchema,
347
+ clonedData.signatureSchema,
348
+ ),
349
+ returnValueSchema: computeSchemaDiff(
350
+ previousSnapshot.data.returnValueSchema,
351
+ clonedData.returnValueSchema,
352
+ ),
353
+ };
354
+
355
+ // Compute diffs for dependency schemas
356
+ if (
357
+ clonedData.dependencySchemas ||
358
+ previousSnapshot.data.dependencySchemas
359
+ ) {
360
+ snapshot.diffFromPrevious.dependencySchemas = {};
361
+ const allDepKeys = new Set([
362
+ ...Object.keys(clonedData.dependencySchemas ?? {}),
363
+ ...Object.keys(previousSnapshot.data.dependencySchemas ?? {}),
364
+ ]);
365
+
366
+ for (const depKey of allDepKeys) {
367
+ const prevDep = previousSnapshot.data.dependencySchemas?.[depKey];
368
+ const currDep = clonedData.dependencySchemas?.[depKey];
369
+
370
+ // Compare returnValueSchema for each dependency
371
+ for (const entityKey of new Set([
372
+ ...Object.keys(prevDep ?? {}),
373
+ ...Object.keys(currDep ?? {}),
374
+ ])) {
375
+ const fullKey = `${depKey}::${entityKey}`;
376
+ const prevSchema = prevDep?.[entityKey]?.returnValueSchema;
377
+ const currSchema = currDep?.[entityKey]?.returnValueSchema;
378
+ const depDiff = computeSchemaDiff(prevSchema, currSchema);
379
+ if (hasDiffChanges(depDiff)) {
380
+ snapshot.diffFromPrevious.dependencySchemas![fullKey] = depDiff;
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ trace.stages.push(snapshot);
388
+ }
389
+
390
+ /**
391
+ * Log a fine-grained operation within the current stage.
392
+ */
393
+ operation(entityName: string, op: Omit<Operation, 'timestamp'>): void {
394
+ if (!this.isEnabled()) return;
395
+
396
+ const trace = this.traces.get(entityName);
397
+ if (!trace) return;
398
+
399
+ trace.operations.push({
400
+ ...op,
401
+ stage: op.stage ?? this.currentStage ?? undefined,
402
+ timestamp: Date.now(),
403
+ });
404
+ }
405
+
406
+ /**
407
+ * Write the trace to the output file.
408
+ */
409
+ flush(): void {
410
+ if (!this.isEnabled()) return;
411
+ if (this.traces.size === 0) {
412
+ this.log('flush: no traces to write');
413
+ return;
414
+ }
415
+
416
+ const entities = Array.from(this.traces.keys());
417
+ const stageCounts = entities
418
+ .map((e) => `${e}(${this.traces.get(e)!.stages.length})`)
419
+ .join(', ');
420
+ this.log(`flush: writing ${entities.length} entities: ${stageCounts}`);
421
+
422
+ // Compute summary
423
+ const stageChangeCounts: Record<
424
+ string,
425
+ { added: number; removed: number; changed: number }
426
+ > = {};
427
+ const entityChangeCounts: Map<string, number> = new Map();
428
+
429
+ for (const [entityName, trace] of this.traces) {
430
+ let entityTotal = 0;
431
+
432
+ for (const snapshot of trace.stages) {
433
+ if (!snapshot.diffFromPrevious) continue;
434
+
435
+ const previousStage =
436
+ trace.stages[trace.stages.indexOf(snapshot) - 1]?.stage ?? 'start';
437
+ const transitionKey = `${previousStage}→${snapshot.stage}`;
438
+
439
+ if (!stageChangeCounts[transitionKey]) {
440
+ stageChangeCounts[transitionKey] = {
441
+ added: 0,
442
+ removed: 0,
443
+ changed: 0,
444
+ };
445
+ }
446
+
447
+ // Count signature schema changes
448
+ if (snapshot.diffFromPrevious.signatureSchema) {
449
+ const diff = snapshot.diffFromPrevious.signatureSchema;
450
+ stageChangeCounts[transitionKey].added += Object.keys(
451
+ diff.added,
452
+ ).length;
453
+ stageChangeCounts[transitionKey].removed += Object.keys(
454
+ diff.removed,
455
+ ).length;
456
+ stageChangeCounts[transitionKey].changed += Object.keys(
457
+ diff.changed,
458
+ ).length;
459
+ entityTotal += countDiffChanges(diff);
460
+ }
461
+
462
+ // Count return value schema changes
463
+ if (snapshot.diffFromPrevious.returnValueSchema) {
464
+ const diff = snapshot.diffFromPrevious.returnValueSchema;
465
+ stageChangeCounts[transitionKey].added += Object.keys(
466
+ diff.added,
467
+ ).length;
468
+ stageChangeCounts[transitionKey].removed += Object.keys(
469
+ diff.removed,
470
+ ).length;
471
+ stageChangeCounts[transitionKey].changed += Object.keys(
472
+ diff.changed,
473
+ ).length;
474
+ entityTotal += countDiffChanges(diff);
475
+ }
476
+ }
477
+
478
+ entityChangeCounts.set(entityName, entityTotal);
479
+ }
480
+
481
+ // Get top 10 entities with most changes
482
+ const entitiesWithMostChanges = [...entityChangeCounts.entries()]
483
+ .sort((a, b) => b[1] - a[1])
484
+ .slice(0, 10)
485
+ .map(([name]) => name);
486
+
487
+ const traceFile: TraceFile = {
488
+ meta: {
489
+ timestamp: new Date().toISOString(),
490
+ projectSlug: this.projectSlug,
491
+ entityCount: this.traces.size,
492
+ },
493
+ summary: {
494
+ stageChangeCounts,
495
+ entitiesWithMostChanges,
496
+ },
497
+ entities: Object.fromEntries(this.traces),
498
+ };
499
+
500
+ // Ensure directory exists
501
+ const dir = path.dirname(this.outputPath);
502
+ if (!fs.existsSync(dir)) {
503
+ fs.mkdirSync(dir, { recursive: true });
504
+ }
505
+
506
+ fs.writeFileSync(this.outputPath, JSON.stringify(traceFile, null, 2));
507
+ this.log(`flush: wrote trace to ${this.outputPath}`);
508
+ }
509
+
510
+ /**
511
+ * Clear all traces (useful for testing).
512
+ */
513
+ clear(): void {
514
+ this.traces.clear();
515
+ this.currentEntity = null;
516
+ this.currentStage = null;
517
+ }
518
+
519
+ // ============================================================================
520
+ // Analysis Utilities
521
+ // ============================================================================
522
+
523
+ /**
524
+ * Load a trace from a file.
525
+ */
526
+ static loadTrace(tracePath: string): TransformationTracer {
527
+ const content = fs.readFileSync(tracePath, 'utf-8');
528
+ const traceFile: TraceFile = JSON.parse(content);
529
+
530
+ const tracer = new TransformationTracer({ enabled: false });
531
+ tracer.projectSlug = traceFile.meta.projectSlug;
532
+
533
+ for (const [entityName, entityTrace] of Object.entries(
534
+ traceFile.entities,
535
+ )) {
536
+ tracer.traces.set(entityName, entityTrace);
537
+ }
538
+
539
+ return tracer;
540
+ }
541
+
542
+ /**
543
+ * Get a high-level summary of the trace.
544
+ */
545
+ getSummary(): CoarseSummary {
546
+ const stageChangeCounts: Record<
547
+ string,
548
+ { added: number; removed: number; changed: number }
549
+ > = {};
550
+ const entityChangeCounts: Map<string, number> = new Map();
551
+
552
+ for (const [entityName, trace] of this.traces) {
553
+ let entityTotal = 0;
554
+
555
+ for (let i = 1; i < trace.stages.length; i++) {
556
+ const snapshot = trace.stages[i];
557
+ const previousStage = trace.stages[i - 1]?.stage ?? 'start';
558
+ const transitionKey = `${previousStage}→${snapshot.stage}`;
559
+
560
+ if (!stageChangeCounts[transitionKey]) {
561
+ stageChangeCounts[transitionKey] = {
562
+ added: 0,
563
+ removed: 0,
564
+ changed: 0,
565
+ };
566
+ }
567
+
568
+ if (snapshot.diffFromPrevious?.signatureSchema) {
569
+ const diff = snapshot.diffFromPrevious.signatureSchema;
570
+ stageChangeCounts[transitionKey].added += Object.keys(
571
+ diff.added,
572
+ ).length;
573
+ stageChangeCounts[transitionKey].removed += Object.keys(
574
+ diff.removed,
575
+ ).length;
576
+ stageChangeCounts[transitionKey].changed += Object.keys(
577
+ diff.changed,
578
+ ).length;
579
+ entityTotal += countDiffChanges(diff);
580
+ }
581
+
582
+ if (snapshot.diffFromPrevious?.returnValueSchema) {
583
+ const diff = snapshot.diffFromPrevious.returnValueSchema;
584
+ stageChangeCounts[transitionKey].added += Object.keys(
585
+ diff.added,
586
+ ).length;
587
+ stageChangeCounts[transitionKey].removed += Object.keys(
588
+ diff.removed,
589
+ ).length;
590
+ stageChangeCounts[transitionKey].changed += Object.keys(
591
+ diff.changed,
592
+ ).length;
593
+ entityTotal += countDiffChanges(diff);
594
+ }
595
+ }
596
+
597
+ entityChangeCounts.set(entityName, entityTotal);
598
+ }
599
+
600
+ const entitiesWithMostChanges = [...entityChangeCounts.entries()]
601
+ .sort((a, b) => b[1] - a[1])
602
+ .slice(0, 10)
603
+ .map(([name, totalChanges]) => ({ name, totalChanges }));
604
+
605
+ return {
606
+ entityCount: this.traces.size,
607
+ stageChangeCounts,
608
+ entitiesWithMostChanges,
609
+ };
610
+ }
611
+
612
+ /**
613
+ * Get a summary of stages for a specific entity.
614
+ */
615
+ getEntitySummary(entityName: string): EntityStageSummary | null {
616
+ const trace = this.traces.get(entityName);
617
+ if (!trace) return null;
618
+
619
+ return {
620
+ entityName,
621
+ stages: trace.stages.map((s) => ({
622
+ stage: s.stage,
623
+ diffFromPrevious: s.diffFromPrevious
624
+ ? {
625
+ signatureSchema: s.diffFromPrevious.signatureSchema,
626
+ returnValueSchema: s.diffFromPrevious.returnValueSchema,
627
+ }
628
+ : undefined,
629
+ })),
630
+ };
631
+ }
632
+
633
+ /**
634
+ * Get operations for an entity, optionally filtered by path pattern.
635
+ */
636
+ getOperations(entityName: string, pathPattern?: RegExp): Operation[] {
637
+ const trace = this.traces.get(entityName);
638
+ if (!trace) return [];
639
+
640
+ if (!pathPattern) return trace.operations;
641
+
642
+ return trace.operations.filter(
643
+ (op) => op.path && pathPattern.test(op.path),
644
+ );
645
+ }
646
+
647
+ /**
648
+ * Trace the full history of a specific path through all transformations.
649
+ */
650
+ tracePath(entityName: string, targetPath: string): PathHistory {
651
+ const trace = this.traces.get(entityName);
652
+ const history: PathHistory['history'] = [];
653
+
654
+ if (!trace) {
655
+ return { entityName, path: targetPath, history };
656
+ }
657
+
658
+ // Track value through stages
659
+ for (const snapshot of trace.stages) {
660
+ const sigValue = snapshot.data.signatureSchema?.[targetPath];
661
+ const retValue = snapshot.data.returnValueSchema?.[targetPath];
662
+ const value = sigValue ?? retValue;
663
+
664
+ if (value !== undefined) {
665
+ history.push({
666
+ stage: snapshot.stage,
667
+ value,
668
+ });
669
+ }
670
+ }
671
+
672
+ // Track value through operations
673
+ for (const op of trace.operations) {
674
+ if (op.path === targetPath) {
675
+ history.push({
676
+ operation: op.operation,
677
+ stage: op.stage,
678
+ value: op.after ?? op.before,
679
+ context: op.context,
680
+ });
681
+ }
682
+ }
683
+
684
+ return { entityName, path: targetPath, history };
685
+ }
686
+
687
+ /**
688
+ * Get the raw entity trace for direct inspection.
689
+ */
690
+ getEntityTrace(entityName: string): EntityTrace | undefined {
691
+ return this.traces.get(entityName);
692
+ }
693
+
694
+ /**
695
+ * Get all entity names in the trace.
696
+ */
697
+ getEntityNames(): string[] {
698
+ return [...this.traces.keys()];
699
+ }
700
+
701
+ // ============================================================================
702
+ // Debugging Utilities
703
+ // ============================================================================
704
+
705
+ /**
706
+ * Find all paths containing a property name across all stages.
707
+ * Useful for debugging: "where does 'analyses' appear in the schema?"
708
+ */
709
+ findProperty(
710
+ entityName: string,
711
+ propertyName: string,
712
+ ): Array<{
713
+ stage: string;
714
+ path: string;
715
+ type: string;
716
+ schemaType: 'signature' | 'returnValue' | 'dependency';
717
+ }> {
718
+ const trace = this.traces.get(entityName);
719
+ if (!trace) return [];
720
+
721
+ const results: Array<{
722
+ stage: string;
723
+ path: string;
724
+ type: string;
725
+ schemaType: 'signature' | 'returnValue' | 'dependency';
726
+ }> = [];
727
+ const pattern = new RegExp(`(^|\\.)${propertyName}(\\.|\\[|$)`);
728
+
729
+ for (const snapshot of trace.stages) {
730
+ // Search signature schema
731
+ for (const [path, type] of Object.entries(
732
+ snapshot.data.signatureSchema ?? {},
733
+ )) {
734
+ if (pattern.test(path)) {
735
+ results.push({
736
+ stage: snapshot.stage,
737
+ path,
738
+ type,
739
+ schemaType: 'signature',
740
+ });
741
+ }
742
+ }
743
+
744
+ // Search return value schema
745
+ for (const [path, type] of Object.entries(
746
+ snapshot.data.returnValueSchema ?? {},
747
+ )) {
748
+ if (pattern.test(path)) {
749
+ results.push({
750
+ stage: snapshot.stage,
751
+ path,
752
+ type,
753
+ schemaType: 'returnValue',
754
+ });
755
+ }
756
+ }
757
+
758
+ // Search dependency schemas
759
+ for (const [depPath, depEntities] of Object.entries(
760
+ snapshot.data.dependencySchemas ?? {},
761
+ )) {
762
+ for (const [depName, depData] of Object.entries(
763
+ depEntities as Record<
764
+ string,
765
+ { returnValueSchema?: Record<string, string> }
766
+ >,
767
+ )) {
768
+ for (const [path, type] of Object.entries(
769
+ depData.returnValueSchema ?? {},
770
+ )) {
771
+ if (pattern.test(path)) {
772
+ results.push({
773
+ stage: snapshot.stage,
774
+ path: `${depPath}/${depName}::${path}`,
775
+ type,
776
+ schemaType: 'dependency',
777
+ });
778
+ }
779
+ }
780
+ }
781
+ }
782
+ }
783
+
784
+ return results;
785
+ }
786
+
787
+ /**
788
+ * Find properties that have inconsistent types across different paths.
789
+ * Useful for debugging: "why does 'analyses' have different types?"
790
+ *
791
+ * Only compares paths that end with the same pattern (e.g., both end in `.analyses`
792
+ * or both end in `.analyses[]`). Ignores built-in properties like `.length`.
793
+ */
794
+ findTypeInconsistencies(entityName: string): Array<{
795
+ propertyName: string;
796
+ paths: Array<{ path: string; type: string; stage: string }>;
797
+ }> {
798
+ const trace = this.traces.get(entityName);
799
+ if (!trace) return [];
800
+
801
+ // Find the best stage for comparison (last one with dependency schemas)
802
+ let targetStage = trace.stages[trace.stages.length - 1];
803
+ for (let i = trace.stages.length - 1; i >= 0; i--) {
804
+ if (
805
+ Object.keys(trace.stages[i].data.dependencySchemas ?? {}).length > 0
806
+ ) {
807
+ targetStage = trace.stages[i];
808
+ break;
809
+ }
810
+ }
811
+ if (!targetStage) return [];
812
+
813
+ // Built-in properties to ignore
814
+ const builtIns = new Set(['length', 'toString', 'valueOf', 'constructor']);
815
+
816
+ // Group paths by their terminal pattern (e.g., ".analyses" or ".analyses[]")
817
+ const propertyGroups = new Map<
818
+ string,
819
+ Array<{ path: string; type: string }>
820
+ >();
821
+
822
+ const addToGroup = (path: string, type: string) => {
823
+ // Extract terminal property pattern (e.g., "foo.bar.analyses[]" -> "analyses[]")
824
+ const match = path.match(/\.([a-zA-Z_][a-zA-Z0-9_]*)(\[\])?$/);
825
+ if (!match) return;
826
+
827
+ const propName = match[1];
828
+ const isArray = match[2] === '[]';
829
+
830
+ // Skip built-in properties
831
+ if (builtIns.has(propName)) return;
832
+
833
+ // Use pattern as key (includes [] suffix)
834
+ const pattern = propName + (isArray ? '[]' : '');
835
+
836
+ if (!propertyGroups.has(pattern)) {
837
+ propertyGroups.set(pattern, []);
838
+ }
839
+ propertyGroups.get(pattern)!.push({ path, type });
840
+ };
841
+
842
+ // Collect from dependency schemas (where inconsistencies usually appear)
843
+ for (const [, depEntities] of Object.entries(
844
+ targetStage.data.dependencySchemas ?? {},
845
+ )) {
846
+ for (const [, depData] of Object.entries(
847
+ depEntities as Record<
848
+ string,
849
+ { returnValueSchema?: Record<string, string> }
850
+ >,
851
+ )) {
852
+ for (const [path, type] of Object.entries(
853
+ depData.returnValueSchema ?? {},
854
+ )) {
855
+ addToGroup(path, type);
856
+ }
857
+ }
858
+ }
859
+
860
+ // Find inconsistencies (same terminal pattern, different types)
861
+ const inconsistencies: Array<{
862
+ propertyName: string;
863
+ paths: Array<{ path: string; type: string; stage: string }>;
864
+ }> = [];
865
+
866
+ for (const [pattern, paths] of propertyGroups) {
867
+ // Normalize types for comparison (treat "unknown | undefined" and "unknown" as similar)
868
+ const normalizedTypes = new Set(
869
+ paths.map((p) =>
870
+ p.type.replace(/ \| undefined/g, '').replace(/ \| null/g, ''),
871
+ ),
872
+ );
873
+
874
+ if (normalizedTypes.size > 1) {
875
+ inconsistencies.push({
876
+ propertyName: pattern,
877
+ paths: paths.map((p) => ({ ...p, stage: targetStage.stage })),
878
+ });
879
+ }
880
+ }
881
+
882
+ // Sort by number of different types (most inconsistent first)
883
+ inconsistencies.sort((a, b) => {
884
+ const aTypes = new Set(a.paths.map((p) => p.type)).size;
885
+ const bTypes = new Set(b.paths.map((p) => p.type)).size;
886
+ return bTypes - aTypes;
887
+ });
888
+
889
+ return inconsistencies;
890
+ }
891
+
892
+ /**
893
+ * Get a human-readable summary of changes between two stages.
894
+ */
895
+ getStageDiffSummary(
896
+ entityName: string,
897
+ fromStage: string,
898
+ toStage: string,
899
+ ): {
900
+ added: string[];
901
+ removed: string[];
902
+ typeChanged: Array<{ path: string; from: string; to: string }>;
903
+ } | null {
904
+ const trace = this.traces.get(entityName);
905
+ if (!trace) return null;
906
+
907
+ const from = trace.stages.find((s) => s.stage === fromStage);
908
+ const to = trace.stages.find((s) => s.stage === toStage);
909
+ if (!from || !to) return null;
910
+
911
+ const result = {
912
+ added: [] as string[],
913
+ removed: [] as string[],
914
+ typeChanged: [] as Array<{ path: string; from: string; to: string }>,
915
+ };
916
+
917
+ // Compare return value schemas (most common)
918
+ const fromSchema = from.data.returnValueSchema ?? {};
919
+ const toSchema = to.data.returnValueSchema ?? {};
920
+
921
+ const fromKeys = new Set(Object.keys(fromSchema));
922
+ const toKeys = new Set(Object.keys(toSchema));
923
+
924
+ for (const key of toKeys) {
925
+ if (!fromKeys.has(key)) {
926
+ result.added.push(`${key}: ${toSchema[key]}`);
927
+ } else if (fromSchema[key] !== toSchema[key]) {
928
+ result.typeChanged.push({
929
+ path: key,
930
+ from: fromSchema[key],
931
+ to: toSchema[key],
932
+ });
933
+ }
934
+ }
935
+
936
+ for (const key of fromKeys) {
937
+ if (!toKeys.has(key)) {
938
+ result.removed.push(`${key}: ${fromSchema[key]}`);
939
+ }
940
+ }
941
+
942
+ return result;
943
+ }
944
+
945
+ /**
946
+ * Trace a schema transformation by capturing before/after and logging operations for all changes.
947
+ *
948
+ * This is a helper to wrap transformative functions like:
949
+ * - cleanKnownObjectFunctionsFromMapping
950
+ * - clearAttributesFromMapping
951
+ * - fillInDirectSchemaGapsAndUnknowns
952
+ * - deduplicateFunctionSchemas
953
+ *
954
+ * @param entityName - The entity being traced
955
+ * @param operationName - Name of the transformation (e.g., 'cleanKnownObjectFunctions')
956
+ * @param schema - The schema to transform (will be mutated)
957
+ * @param transformFn - The transformation function to run
958
+ * @param context - Optional context to include in operation logs
959
+ * @returns The schema (same reference, mutated)
960
+ */
961
+ traceSchemaTransform<T extends Record<string, string>>(
962
+ entityName: string,
963
+ operationName: string,
964
+ schema: T,
965
+ transformFn: (schema: T) => void,
966
+ context?: Record<string, any>,
967
+ ): T {
968
+ if (!this.enabled) {
969
+ transformFn(schema);
970
+ return schema;
971
+ }
972
+
973
+ // Capture before state
974
+ const before = { ...schema };
975
+
976
+ // Run the transformation
977
+ transformFn(schema);
978
+
979
+ // Compute diff and log operations
980
+ const diff = computeSchemaDiff(before, schema);
981
+
982
+ // Log added paths
983
+ for (const [path, value] of Object.entries(diff.added)) {
984
+ this.operation(entityName, {
985
+ operation: operationName,
986
+ path,
987
+ before: undefined,
988
+ after: value,
989
+ context: { ...context, changeType: 'added' },
990
+ });
991
+ }
992
+
993
+ // Log removed paths
994
+ for (const [path, value] of Object.entries(diff.removed)) {
995
+ this.operation(entityName, {
996
+ operation: operationName,
997
+ path,
998
+ before: value,
999
+ after: undefined,
1000
+ context: { ...context, changeType: 'removed' },
1001
+ });
1002
+ }
1003
+
1004
+ // Log changed paths
1005
+ for (const [path, { from, to }] of Object.entries(diff.changed)) {
1006
+ this.operation(entityName, {
1007
+ operation: operationName,
1008
+ path,
1009
+ before: from,
1010
+ after: to,
1011
+ context: { ...context, changeType: 'changed' },
1012
+ });
1013
+ }
1014
+
1015
+ return schema;
1016
+ }
1017
+
1018
+ /**
1019
+ * Trace a schema transformation where the function returns a new schema (non-mutating).
1020
+ *
1021
+ * Use this for functions like deduplicateFunctionSchemas that return a new object
1022
+ * rather than mutating the input.
1023
+ *
1024
+ * @param entityName - The entity being traced
1025
+ * @param operationName - Name of the transformation
1026
+ * @param before - The schema before transformation
1027
+ * @param after - The schema after transformation
1028
+ * @param context - Optional context to include in operation logs
1029
+ */
1030
+ traceSchemaTransformResult(
1031
+ entityName: string,
1032
+ operationName: string,
1033
+ before: Record<string, string>,
1034
+ after: Record<string, string>,
1035
+ context?: Record<string, any>,
1036
+ ): void {
1037
+ if (!this.enabled) return;
1038
+
1039
+ // Compute diff and log operations
1040
+ const diff = computeSchemaDiff(before, after);
1041
+
1042
+ // Log added paths
1043
+ for (const [path, value] of Object.entries(diff.added)) {
1044
+ this.operation(entityName, {
1045
+ operation: operationName,
1046
+ path,
1047
+ before: undefined,
1048
+ after: value,
1049
+ context: { ...context, changeType: 'added' },
1050
+ });
1051
+ }
1052
+
1053
+ // Log removed paths
1054
+ for (const [path, value] of Object.entries(diff.removed)) {
1055
+ this.operation(entityName, {
1056
+ operation: operationName,
1057
+ path,
1058
+ before: value,
1059
+ after: undefined,
1060
+ context: { ...context, changeType: 'removed' },
1061
+ });
1062
+ }
1063
+
1064
+ // Log changed paths
1065
+ for (const [path, { from, to }] of Object.entries(diff.changed)) {
1066
+ this.operation(entityName, {
1067
+ operation: operationName,
1068
+ path,
1069
+ before: from,
1070
+ after: to,
1071
+ context: { ...context, changeType: 'changed' },
1072
+ });
1073
+ }
1074
+ }
1075
+
1076
+ /**
1077
+ * Trace multiple schemas in a dependency schemas structure.
1078
+ * Useful for tracing transformations that apply to all dependency schemas.
1079
+ *
1080
+ * @param entityName - The entity being traced
1081
+ * @param operationName - Name of the transformation
1082
+ * @param dependencySchemas - The dependency schemas structure
1083
+ * @param transformFn - Function to apply to each schema (signature or returnValue)
1084
+ * @param schemaType - Which schema to transform: 'signature', 'returnValue', or 'both'
1085
+ */
1086
+ traceDependencySchemaTransform(
1087
+ entityName: string,
1088
+ operationName: string,
1089
+ dependencySchemas: Record<
1090
+ string,
1091
+ Record<
1092
+ string,
1093
+ {
1094
+ signatureSchema?: Record<string, string>;
1095
+ returnValueSchema?: Record<string, string>;
1096
+ }
1097
+ >
1098
+ >,
1099
+ transformFn: (schema: Record<string, string>) => void,
1100
+ schemaType: 'signature' | 'returnValue' | 'both' = 'both',
1101
+ ): void {
1102
+ if (!this.enabled) {
1103
+ // Still run the transform even if not tracing
1104
+ for (const filePath in dependencySchemas) {
1105
+ for (const depName in dependencySchemas[filePath]) {
1106
+ const depSchema = dependencySchemas[filePath][depName];
1107
+ if (
1108
+ (schemaType === 'signature' || schemaType === 'both') &&
1109
+ depSchema.signatureSchema
1110
+ ) {
1111
+ transformFn(depSchema.signatureSchema);
1112
+ }
1113
+ if (
1114
+ (schemaType === 'returnValue' || schemaType === 'both') &&
1115
+ depSchema.returnValueSchema
1116
+ ) {
1117
+ transformFn(depSchema.returnValueSchema);
1118
+ }
1119
+ }
1120
+ }
1121
+ return;
1122
+ }
1123
+
1124
+ for (const filePath in dependencySchemas) {
1125
+ for (const depName in dependencySchemas[filePath]) {
1126
+ const depSchema = dependencySchemas[filePath][depName];
1127
+ const depContext = { filePath, dependencyName: depName };
1128
+
1129
+ if (
1130
+ (schemaType === 'signature' || schemaType === 'both') &&
1131
+ depSchema.signatureSchema
1132
+ ) {
1133
+ this.traceSchemaTransform(
1134
+ entityName,
1135
+ operationName,
1136
+ depSchema.signatureSchema,
1137
+ transformFn,
1138
+ { ...depContext, schemaType: 'signature' },
1139
+ );
1140
+ }
1141
+
1142
+ if (
1143
+ (schemaType === 'returnValue' || schemaType === 'both') &&
1144
+ depSchema.returnValueSchema
1145
+ ) {
1146
+ this.traceSchemaTransform(
1147
+ entityName,
1148
+ operationName,
1149
+ depSchema.returnValueSchema,
1150
+ transformFn,
1151
+ { ...depContext, schemaType: 'returnValue' },
1152
+ );
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ /**
1159
+ * Trace changes to dependency schemas before/after a function call.
1160
+ *
1161
+ * Use this for functions like enrichArrayTypesFromChildSignatures or
1162
+ * enrichUnknownTypesFromSourceEquivalencies that modify dependency schemas in place.
1163
+ *
1164
+ * @param entityName - The entity being traced
1165
+ * @param operationName - Name of the transformation
1166
+ * @param dependencySchemas - The dependency schemas to track
1167
+ * @param transformFn - The function to run (should mutate dependencySchemas)
1168
+ */
1169
+ traceDependencySchemaChanges(
1170
+ entityName: string,
1171
+ operationName: string,
1172
+ dependencySchemas: Record<
1173
+ string,
1174
+ Record<
1175
+ string,
1176
+ {
1177
+ signatureSchema?: Record<string, string>;
1178
+ returnValueSchema?: Record<string, string>;
1179
+ }
1180
+ >
1181
+ >,
1182
+ transformFn: () => void,
1183
+ ): void {
1184
+ if (!this.enabled) {
1185
+ transformFn();
1186
+ return;
1187
+ }
1188
+
1189
+ // Capture before state (deep copy of all schemas)
1190
+ const beforeState: Record<
1191
+ string,
1192
+ Record<
1193
+ string,
1194
+ { sig: Record<string, string>; rv: Record<string, string> }
1195
+ >
1196
+ > = {};
1197
+ for (const filePath in dependencySchemas) {
1198
+ beforeState[filePath] = {};
1199
+ for (const depName in dependencySchemas[filePath]) {
1200
+ const depSchema = dependencySchemas[filePath][depName];
1201
+ beforeState[filePath][depName] = {
1202
+ sig: { ...(depSchema.signatureSchema || {}) },
1203
+ rv: { ...(depSchema.returnValueSchema || {}) },
1204
+ };
1205
+ }
1206
+ }
1207
+
1208
+ // Run the transformation
1209
+ transformFn();
1210
+
1211
+ // Compare and log changes
1212
+ for (const filePath in dependencySchemas) {
1213
+ for (const depName in dependencySchemas[filePath]) {
1214
+ const depSchema = dependencySchemas[filePath][depName];
1215
+ const before = beforeState[filePath]?.[depName];
1216
+ const context = { filePath, dependencyName: depName };
1217
+
1218
+ // Check signature schema changes
1219
+ if (depSchema.signatureSchema) {
1220
+ const sigBefore = before?.sig || {};
1221
+ const diff = computeSchemaDiff(sigBefore, depSchema.signatureSchema);
1222
+ for (const [path, value] of Object.entries(diff.added)) {
1223
+ this.operation(entityName, {
1224
+ operation: operationName,
1225
+ path,
1226
+ before: undefined,
1227
+ after: value,
1228
+ context: {
1229
+ ...context,
1230
+ schemaType: 'signature',
1231
+ changeType: 'added',
1232
+ },
1233
+ });
1234
+ }
1235
+ for (const [path, { from, to }] of Object.entries(diff.changed)) {
1236
+ this.operation(entityName, {
1237
+ operation: operationName,
1238
+ path,
1239
+ before: from,
1240
+ after: to,
1241
+ context: {
1242
+ ...context,
1243
+ schemaType: 'signature',
1244
+ changeType: 'changed',
1245
+ },
1246
+ });
1247
+ }
1248
+ }
1249
+
1250
+ // Check return value schema changes
1251
+ if (depSchema.returnValueSchema) {
1252
+ const rvBefore = before?.rv || {};
1253
+ const diff = computeSchemaDiff(rvBefore, depSchema.returnValueSchema);
1254
+ for (const [path, value] of Object.entries(diff.added)) {
1255
+ this.operation(entityName, {
1256
+ operation: operationName,
1257
+ path,
1258
+ before: undefined,
1259
+ after: value,
1260
+ context: {
1261
+ ...context,
1262
+ schemaType: 'returnValue',
1263
+ changeType: 'added',
1264
+ },
1265
+ });
1266
+ }
1267
+ for (const [path, { from, to }] of Object.entries(diff.changed)) {
1268
+ this.operation(entityName, {
1269
+ operation: operationName,
1270
+ path,
1271
+ before: from,
1272
+ after: to,
1273
+ context: {
1274
+ ...context,
1275
+ schemaType: 'returnValue',
1276
+ changeType: 'changed',
1277
+ },
1278
+ });
1279
+ }
1280
+ }
1281
+ }
1282
+ }
1283
+ }
1284
+ }
1285
+
1286
+ // ============================================================================
1287
+ // Global Instance
1288
+ // ============================================================================
1289
+
1290
+ /**
1291
+ * Check if tracing is enabled via environment variable.
1292
+ */
1293
+ function isTracingEnabled(): boolean {
1294
+ const envValue = process.env.CODEYAM_TRACE_TRANSFORMS;
1295
+ return envValue === '1' || envValue === 'true';
1296
+ }
1297
+
1298
+ /**
1299
+ * Global tracer instance.
1300
+ * Enabled via CODEYAM_TRACE_TRANSFORMS=1 environment variable.
1301
+ * Output is always written to /tmp/codeyam/transform-trace.json
1302
+ */
1303
+ export const transformationTracer = new TransformationTracer({
1304
+ enabled: isTracingEnabled(),
1305
+ outputPath: '/tmp/codeyam/transform-trace.json',
1306
+ });
1307
+
1308
+ // Auto-flush on process exit if tracing is enabled and there's data
1309
+ process.on('beforeExit', () => {
1310
+ if (transformationTracer.isEnabled()) {
1311
+ transformationTracer.flush();
1312
+ }
1313
+ });
1314
+
1315
+ export default transformationTracer;