@autobe/agent 0.30.0-dev.20260315 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. package/LICENSE +661 -661
  2. package/lib/constants/AutoBeTemplateFileConstant.d.ts +1 -1
  3. package/lib/factory/consentFunctionCall.js +4 -4
  4. package/lib/factory/createAutoBeContext.js +24 -24
  5. package/lib/factory/createAutoBeMessageContent.js +6 -6
  6. package/lib/index.mjs +41 -41
  7. package/lib/orchestrate/analyze/histories/transformAnalyzeScenarioHistory.js +18 -18
  8. package/lib/orchestrate/analyze/histories/transformAnalyzeScenarioReviewHistory.js +13 -13
  9. package/lib/orchestrate/analyze/histories/transformAnalyzeSectionCrossFileReviewHistory.js +47 -47
  10. package/lib/orchestrate/analyze/histories/transformAnalyzeSectionReviewHistory.js +66 -66
  11. package/lib/orchestrate/analyze/histories/transformAnalyzeWriteSectionHistory.js +91 -91
  12. package/lib/orchestrate/analyze/histories/transformAnalyzeWriteSectionPatchHistory.js +46 -46
  13. package/lib/orchestrate/analyze/histories/transformAnalyzeWriteUnitHistory.js +72 -72
  14. package/lib/orchestrate/analyze/orchestrateAnalyzeScenario.js +1 -1
  15. package/lib/orchestrate/analyze/orchestrateAnalyzeSectionCrossFileReview.js +1 -1
  16. package/lib/orchestrate/analyze/orchestrateAnalyzeSectionReview.js +1 -1
  17. package/lib/orchestrate/analyze/orchestrateAnalyzeWriteSection.js +1 -1
  18. package/lib/orchestrate/analyze/orchestrateAnalyzeWriteSectionPatch.js +1 -1
  19. package/lib/orchestrate/analyze/orchestrateAnalyzeWriteUnit.js +1 -1
  20. package/lib/orchestrate/common/histories/transformCommonCorrectCastingHistory.js +5 -5
  21. package/lib/orchestrate/common/histories/transformPreliminaryHistory.js +44 -44
  22. package/lib/orchestrate/common/histories/transformPreviousAndLatestCorrectHistory.js +44 -44
  23. package/lib/orchestrate/common/internal/fixPrelminaryApplication.js +22 -22
  24. package/lib/orchestrate/common/internal/validatePreliminary.js +116 -116
  25. package/lib/orchestrate/facade/createAutoBeFacadeController.js +3 -3
  26. package/lib/orchestrate/facade/structures/transformFacadeStateMessage.js +20 -20
  27. package/lib/orchestrate/interface/histories/transformInterfaceActionEndpointReviewHistory.js +34 -34
  28. package/lib/orchestrate/interface/histories/transformInterfaceActionEndpointWriteHistory.js +37 -37
  29. package/lib/orchestrate/interface/histories/transformInterfaceAuthorizationHistory.js +56 -56
  30. package/lib/orchestrate/interface/histories/transformInterfaceBaseEndpointReviewHistory.js +26 -26
  31. package/lib/orchestrate/interface/histories/transformInterfaceBaseEndpointWriteHistory.js +28 -28
  32. package/lib/orchestrate/interface/histories/transformInterfaceEndpointAuthorizationSection.js +11 -11
  33. package/lib/orchestrate/interface/histories/transformInterfaceGroupHistory.js +38 -38
  34. package/lib/orchestrate/interface/histories/transformInterfaceOperationHistory.js +29 -29
  35. package/lib/orchestrate/interface/histories/transformInterfaceOperationParameterHistory.js +15 -15
  36. package/lib/orchestrate/interface/histories/transformInterfaceOperationReviewHistory.js +6 -6
  37. package/lib/orchestrate/interface/histories/transformInterfacePrerequisiteHistory.js +25 -25
  38. package/lib/orchestrate/interface/histories/transformInterfaceSchemaCastingHistory.js +67 -67
  39. package/lib/orchestrate/interface/histories/transformInterfaceSchemaComplementHistory.js +60 -60
  40. package/lib/orchestrate/interface/histories/transformInterfaceSchemaRefineHistory.js +83 -83
  41. package/lib/orchestrate/interface/histories/transformInterfaceSchemaRenameHistory.js +29 -29
  42. package/lib/orchestrate/interface/histories/transformInterfaceSchemaReviewHistory.js +74 -74
  43. package/lib/orchestrate/interface/histories/transformInterfaceSchemaWriteHistory.js +46 -46
  44. package/lib/orchestrate/interface/orchestrateInterfaceAuthorization.js +1 -1
  45. package/lib/orchestrate/interface/orchestrateInterfaceEndpointReview.js +1 -1
  46. package/lib/orchestrate/interface/orchestrateInterfaceEndpointWrite.js +1 -1
  47. package/lib/orchestrate/interface/orchestrateInterfaceGroup.js +9 -9
  48. package/lib/orchestrate/interface/orchestrateInterfaceOperation.js +1 -1
  49. package/lib/orchestrate/interface/orchestrateInterfaceOperationReview.js +1 -1
  50. package/lib/orchestrate/interface/orchestrateInterfacePrerequisite.js +4 -4
  51. package/lib/orchestrate/interface/orchestrateInterfaceSchemaCasting.js +1 -1
  52. package/lib/orchestrate/interface/orchestrateInterfaceSchemaComplement.js +5 -5
  53. package/lib/orchestrate/interface/orchestrateInterfaceSchemaRefine.js +1 -1
  54. package/lib/orchestrate/interface/orchestrateInterfaceSchemaReview.js +1 -1
  55. package/lib/orchestrate/interface/orchestrateInterfaceSchemaWrite.js +1 -1
  56. package/lib/orchestrate/interface/programmers/AutoBeInterfaceAuthorizationProgrammer.js +90 -90
  57. package/lib/orchestrate/interface/programmers/AutoBeInterfaceEndpointProgrammer.js +6 -6
  58. package/lib/orchestrate/interface/programmers/AutoBeInterfaceEndpointReviewProgrammer.js +25 -25
  59. package/lib/orchestrate/interface/programmers/AutoBeInterfaceOperationProgrammer.js +71 -71
  60. package/lib/orchestrate/interface/programmers/AutoBeInterfacePrerequisiteProgrammer.js +162 -162
  61. package/lib/orchestrate/interface/programmers/AutoBeInterfaceSchemaProgrammer.js +11 -11
  62. package/lib/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.js +73 -73
  63. package/lib/orchestrate/interface/programmers/AutoBeInterfaceSchemaRefineProgrammer.js +35 -35
  64. package/lib/orchestrate/interface/programmers/AutoBeInterfaceSchemaReviewProgrammer.js +11 -11
  65. package/lib/orchestrate/interface/utils/AutoBeJsonSchemaFactory.js +4 -4
  66. package/lib/orchestrate/interface/utils/AutoBeJsonSchemaValidator.js +283 -283
  67. package/lib/orchestrate/interface/utils/fulfillJsonSchemaErrorMessages.js +76 -76
  68. package/lib/orchestrate/prisma/histories/transformPrismaAuthorizationHistory.js +76 -76
  69. package/lib/orchestrate/prisma/histories/transformPrismaAuthorizationReviewHistory.js +51 -51
  70. package/lib/orchestrate/prisma/histories/transformPrismaComponentReviewHistory.js +54 -54
  71. package/lib/orchestrate/prisma/histories/transformPrismaComponentsHistory.js +83 -83
  72. package/lib/orchestrate/prisma/histories/transformPrismaCorrectHistory.js +6 -6
  73. package/lib/orchestrate/prisma/histories/transformPrismaGroupHistory.js +22 -22
  74. package/lib/orchestrate/prisma/histories/transformPrismaGroupReviewHistory.js +41 -41
  75. package/lib/orchestrate/prisma/histories/transformPrismaSchemaHistory.js +39 -39
  76. package/lib/orchestrate/prisma/histories/transformPrismaSchemaReviewHistory.js +41 -41
  77. package/lib/orchestrate/prisma/orchestratePrismaAuthorization.js +1 -1
  78. package/lib/orchestrate/prisma/orchestratePrismaAuthorizationReview.js +1 -1
  79. package/lib/orchestrate/prisma/orchestratePrismaComponent.js +1 -1
  80. package/lib/orchestrate/prisma/orchestratePrismaComponentReview.js +1 -1
  81. package/lib/orchestrate/prisma/orchestratePrismaCorrect.js +1 -1
  82. package/lib/orchestrate/prisma/orchestratePrismaGroup.js +1 -1
  83. package/lib/orchestrate/prisma/orchestratePrismaGroupReview.js +1 -1
  84. package/lib/orchestrate/prisma/orchestratePrismaSchema.js +1 -1
  85. package/lib/orchestrate/prisma/orchestratePrismaSchemaReview.js +1 -1
  86. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseAuthorizationProgrammer.js +23 -23
  87. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseAuthorizationReviewProgrammer.js +7 -7
  88. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseComponentProgrammer.js +5 -5
  89. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseComponentReviewProgrammer.js +20 -20
  90. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseGroupProgrammer.js +13 -13
  91. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseGroupReviewProgrammer.js +51 -51
  92. package/lib/orchestrate/prisma/programmers/AutoBeDatabaseSchemaProgrammer.js +25 -25
  93. package/lib/orchestrate/realize/histories/transformRealizeAuthorizationCorrectHistory.js +28 -28
  94. package/lib/orchestrate/realize/histories/transformRealizeAuthorizationWriteHistory.js +14 -14
  95. package/lib/orchestrate/realize/histories/transformRealizeCollectorCorrectHistory.js +42 -42
  96. package/lib/orchestrate/realize/histories/transformRealizeCollectorPlanHistory.js +27 -27
  97. package/lib/orchestrate/realize/histories/transformRealizeCollectorWriteHistory.js +57 -57
  98. package/lib/orchestrate/realize/histories/transformRealizeCorrectCastingHistory.js +35 -35
  99. package/lib/orchestrate/realize/histories/transformRealizeOperationCorrectHistory.js +14 -14
  100. package/lib/orchestrate/realize/histories/transformRealizeOperationWriteHistory.js +37 -37
  101. package/lib/orchestrate/realize/histories/transformRealizeOperationWriteHistory.js.map +1 -1
  102. package/lib/orchestrate/realize/histories/transformRealizeTransformerCorrectHistory.js +47 -47
  103. package/lib/orchestrate/realize/histories/transformRealizeTransformerPlanHistory.js +27 -27
  104. package/lib/orchestrate/realize/histories/transformRealizeTransformerWriteHistory.js +51 -51
  105. package/lib/orchestrate/realize/orchestrateRealizeAuthorizationCorrect.js +1 -1
  106. package/lib/orchestrate/realize/orchestrateRealizeAuthorizationWrite.js +1 -1
  107. package/lib/orchestrate/realize/orchestrateRealizeCollectorCorrectOverall.js +1 -1
  108. package/lib/orchestrate/realize/orchestrateRealizeCollectorPlan.js +11 -11
  109. package/lib/orchestrate/realize/orchestrateRealizeCollectorWrite.js +1 -1
  110. package/lib/orchestrate/realize/orchestrateRealizeOperationCorrectOverall.js +1 -1
  111. package/lib/orchestrate/realize/orchestrateRealizeOperationWrite.js +1 -1
  112. package/lib/orchestrate/realize/orchestrateRealizeTransformerCorrectOverall.js +1 -1
  113. package/lib/orchestrate/realize/orchestrateRealizeTransformerPlan.js +11 -11
  114. package/lib/orchestrate/realize/orchestrateRealizeTransformerWrite.js +1 -1
  115. package/lib/orchestrate/realize/programmers/AutoBeRealizeCollectorProgrammer.js +41 -41
  116. package/lib/orchestrate/realize/programmers/AutoBeRealizeOperationProgrammer.js +21 -21
  117. package/lib/orchestrate/realize/programmers/AutoBeRealizeTransformerProgrammer.js +57 -57
  118. package/lib/orchestrate/realize/utils/getRealizeWriteInputType.js +3 -3
  119. package/lib/orchestrate/realize/utils/printErrorHints.js +5 -5
  120. package/lib/orchestrate/test/compile/getTestImportStatements.js +9 -9
  121. package/lib/orchestrate/test/histories/transformTestAuthorizeWriteHistory.js +38 -38
  122. package/lib/orchestrate/test/histories/transformTestGenerationWriteHistory.js +79 -79
  123. package/lib/orchestrate/test/histories/transformTestOperationWriteHistory.js +162 -162
  124. package/lib/orchestrate/test/histories/transformTestPrepareWriteHistory.js +54 -54
  125. package/lib/orchestrate/test/histories/transformTestScenarioHistory.js +31 -31
  126. package/lib/orchestrate/test/histories/transformTestScenarioReviewHistory.js +27 -27
  127. package/lib/orchestrate/test/orchestrateTestScenario.js +1 -1
  128. package/lib/orchestrate/test/orchestrateTestScenarioReview.js +1 -1
  129. package/lib/orchestrate/test/programmers/AutoBeTestAuthorizeProgrammer.js +31 -31
  130. package/lib/orchestrate/test/programmers/AutoBeTestGenerateProgrammer.js +23 -23
  131. package/lib/orchestrate/test/programmers/AutoBeTestOperationProgrammer.js +6 -6
  132. package/lib/orchestrate/test/programmers/AutoBeTestPrepareProgrammer.js +34 -34
  133. package/lib/orchestrate/test/programmers/AutoBeTestScenarioProgrammer.js +39 -39
  134. package/lib/utils/predicateStateMessage.js +19 -19
  135. package/lib/utils/validateEmptyCode.js +16 -16
  136. package/package.json +5 -5
  137. package/src/AutoBeAgent.ts +374 -374
  138. package/src/AutoBeAgentBase.ts +126 -126
  139. package/src/AutoBeMockAgent.ts +254 -254
  140. package/src/constants/AutoBeConfigConstant.ts +173 -173
  141. package/src/constants/AutoBeTemplateFileConstant.ts +1 -1
  142. package/src/context/AutoBeContext.ts +107 -107
  143. package/src/context/AutoBeState.ts +66 -66
  144. package/src/context/AutoBeTokenUsage.ts +307 -307
  145. package/src/context/AutoBeTokenUsageComponent.ts +227 -227
  146. package/src/describe/describe.ts +47 -47
  147. package/src/describe/image/histories/transformImageDescribeDraftHistories.ts +16 -16
  148. package/src/describe/image/orchestrateImageDescribeDraft.ts +200 -200
  149. package/src/describe/image/structures/IAutoBeImageDescribeDraftApplication.ts +92 -92
  150. package/src/describe/imageDescribe.ts +64 -64
  151. package/src/factory/consentFunctionCall.ts +141 -141
  152. package/src/factory/createAgenticaHistory.ts +71 -71
  153. package/src/factory/createAutoBeContext.ts +584 -584
  154. package/src/factory/createAutoBeMessageContent.ts +36 -36
  155. package/src/factory/createAutoBeState.ts +20 -20
  156. package/src/factory/getAutoBeGenerated.ts +317 -317
  157. package/src/factory/getAutoBeRealizeGenerated.ts +31 -31
  158. package/src/factory/getCriticalCompiler.ts +52 -52
  159. package/src/factory/index.ts +1 -1
  160. package/src/factory/mergeSystemMessages.ts +60 -60
  161. package/src/factory/supportFunctionCallFallback.ts +214 -214
  162. package/src/factory/supportMistral.ts +138 -138
  163. package/src/index.ts +16 -16
  164. package/src/orchestrate/analyze/fillTocDeterministic.ts +280 -280
  165. package/src/orchestrate/analyze/histories/transformAnalyzeScenarioHistory.ts +55 -55
  166. package/src/orchestrate/analyze/histories/transformAnalyzeScenarioReviewHistory.ts +74 -74
  167. package/src/orchestrate/analyze/histories/transformAnalyzeSectionCrossFileReviewHistory.ts +179 -179
  168. package/src/orchestrate/analyze/histories/transformAnalyzeSectionReviewHistory.ts +163 -163
  169. package/src/orchestrate/analyze/histories/transformAnalyzeWriteSectionHistory.ts +191 -191
  170. package/src/orchestrate/analyze/histories/transformAnalyzeWriteSectionPatchHistory.ts +122 -122
  171. package/src/orchestrate/analyze/histories/transformAnalyzeWriteUnitHistory.ts +161 -161
  172. package/src/orchestrate/analyze/index.ts +7 -7
  173. package/src/orchestrate/analyze/orchestrateAnalyze.ts +1693 -1693
  174. package/src/orchestrate/analyze/orchestrateAnalyzeScenario.ts +267 -267
  175. package/src/orchestrate/analyze/orchestrateAnalyzeScenarioReview.ts +122 -122
  176. package/src/orchestrate/analyze/orchestrateAnalyzeSectionCrossFileReview.ts +146 -146
  177. package/src/orchestrate/analyze/orchestrateAnalyzeSectionReview.ts +154 -154
  178. package/src/orchestrate/analyze/orchestrateAnalyzeWriteSection.ts +388 -388
  179. package/src/orchestrate/analyze/orchestrateAnalyzeWriteSectionPatch.ts +407 -407
  180. package/src/orchestrate/analyze/orchestrateAnalyzeWriteUnit.ts +348 -348
  181. package/src/orchestrate/analyze/programmers/AutoBeAnalyzeProgrammer.ts +149 -149
  182. package/src/orchestrate/analyze/structures/FixedAnalyzeTemplate.ts +961 -961
  183. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeScenarioApplication.ts +141 -141
  184. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeScenarioReviewApplication.ts +96 -96
  185. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeSectionCrossFileReviewApplication.ts +160 -160
  186. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeSectionReviewApplication.ts +192 -192
  187. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeWriteSectionApplication.ts +142 -142
  188. package/src/orchestrate/analyze/structures/IAutoBeAnalyzeWriteUnitApplication.ts +123 -123
  189. package/src/orchestrate/analyze/utils/buildConstraintConsistencyReport.ts +813 -813
  190. package/src/orchestrate/analyze/utils/buildErrorCodeRegistry.ts +324 -324
  191. package/src/orchestrate/analyze/utils/buildHardValidators.ts +88 -88
  192. package/src/orchestrate/analyze/utils/detectInventedEntities.ts +87 -87
  193. package/src/orchestrate/analyze/utils/detectProseConstraintConflicts.ts +319 -319
  194. package/src/orchestrate/analyze/utils/repairSectionReviewUtils.ts +181 -181
  195. package/src/orchestrate/analyze/utils/repairUtils.ts +60 -60
  196. package/src/orchestrate/analyze/utils/validateScenarioBasics.ts +104 -104
  197. package/src/orchestrate/common/AutoBePreliminaryController.ts +400 -400
  198. package/src/orchestrate/common/histories/transformCommonCorrectCastingHistory.ts +32 -32
  199. package/src/orchestrate/common/histories/transformPreliminaryHistory.ts +742 -742
  200. package/src/orchestrate/common/histories/transformPreviousAndLatestCorrectHistory.ts +77 -77
  201. package/src/orchestrate/common/internal/complementPreliminaryCollection.ts +263 -263
  202. package/src/orchestrate/common/internal/convertToSectionEntries.ts +57 -57
  203. package/src/orchestrate/common/internal/createPreliminaryCollection.ts +76 -76
  204. package/src/orchestrate/common/internal/fixPrelminaryApplication.ts +346 -346
  205. package/src/orchestrate/common/internal/validatePreliminary.ts +671 -671
  206. package/src/orchestrate/common/orchestrateCommonCorrectCasting.ts +223 -223
  207. package/src/orchestrate/common/orchestratePreliminary.ts +610 -610
  208. package/src/orchestrate/common/structures/AutoBePreliminaryRequest.ts +42 -42
  209. package/src/orchestrate/common/structures/IAnalysisSectionEntry.ts +35 -35
  210. package/src/orchestrate/common/structures/IAutoBeCommonCorrectCastingApplication.ts +72 -72
  211. package/src/orchestrate/common/structures/IAutoBeOrchestrateResult.ts +28 -28
  212. package/src/orchestrate/common/structures/IAutoBePreliminaryCollection.ts +52 -52
  213. package/src/orchestrate/common/structures/IAutoBePreliminaryGetAnalysisSections.ts +34 -34
  214. package/src/orchestrate/common/structures/IAutoBePreliminaryGetDatabaseSchemas.ts +31 -31
  215. package/src/orchestrate/common/structures/IAutoBePreliminaryGetInterfaceOperations.ts +32 -32
  216. package/src/orchestrate/common/structures/IAutoBePreliminaryGetInterfaceSchemas.ts +31 -31
  217. package/src/orchestrate/common/structures/IAutoBePreliminaryGetPreviousAnalysisSections.ts +28 -28
  218. package/src/orchestrate/common/structures/IAutoBePreliminaryGetPreviousDatabaseSchemas.ts +88 -88
  219. package/src/orchestrate/common/structures/IAutoBePreliminaryGetPreviousInterfaceOperations.ts +102 -102
  220. package/src/orchestrate/common/structures/IAutoBePreliminaryGetPreviousInterfaceSchemas.ts +105 -105
  221. package/src/orchestrate/common/structures/IAutoBePreliminaryGetRealizeCollectors.ts +32 -32
  222. package/src/orchestrate/common/structures/IAutoBePreliminaryGetRealizeTransformers.ts +32 -32
  223. package/src/orchestrate/facade/createAutoBeFacadeController.ts +118 -118
  224. package/src/orchestrate/facade/histories/IAutoBeFacadeApplication.ts +139 -139
  225. package/src/orchestrate/facade/histories/IAutoBeFacadeApplicationProps.ts +8 -8
  226. package/src/orchestrate/facade/histories/IAutoBeFacadeApplicationResult.ts +9 -9
  227. package/src/orchestrate/facade/structures/transformFacadeStateMessage.ts +59 -59
  228. package/src/orchestrate/index.ts +5 -5
  229. package/src/orchestrate/interface/histories/transformInterfaceActionEndpointReviewHistory.ts +83 -83
  230. package/src/orchestrate/interface/histories/transformInterfaceActionEndpointWriteHistory.ts +78 -78
  231. package/src/orchestrate/interface/histories/transformInterfaceAuthorizationHistory.ts +129 -129
  232. package/src/orchestrate/interface/histories/transformInterfaceBaseEndpointReviewHistory.ts +74 -74
  233. package/src/orchestrate/interface/histories/transformInterfaceBaseEndpointWriteHistory.ts +68 -68
  234. package/src/orchestrate/interface/histories/transformInterfaceCommonHistory.ts +64 -64
  235. package/src/orchestrate/interface/histories/transformInterfaceEndpointAuthorizationSection.ts +42 -42
  236. package/src/orchestrate/interface/histories/transformInterfaceGroupHistory.ts +103 -103
  237. package/src/orchestrate/interface/histories/transformInterfaceOperationHistory.ts +81 -81
  238. package/src/orchestrate/interface/histories/transformInterfaceOperationParameterHistory.ts +53 -53
  239. package/src/orchestrate/interface/histories/transformInterfaceOperationReviewHistory.ts +49 -49
  240. package/src/orchestrate/interface/histories/transformInterfacePrerequisiteHistory.ts +94 -94
  241. package/src/orchestrate/interface/histories/transformInterfaceSchemaCastingHistory.ts +122 -122
  242. package/src/orchestrate/interface/histories/transformInterfaceSchemaComplementHistory.ts +192 -192
  243. package/src/orchestrate/interface/histories/transformInterfaceSchemaRefineHistory.ts +189 -189
  244. package/src/orchestrate/interface/histories/transformInterfaceSchemaRenameHistory.ts +63 -63
  245. package/src/orchestrate/interface/histories/transformInterfaceSchemaReviewHistory.ts +173 -173
  246. package/src/orchestrate/interface/histories/transformInterfaceSchemaWriteHistory.ts +88 -88
  247. package/src/orchestrate/interface/index.ts +6 -6
  248. package/src/orchestrate/interface/orchestrateInterface.ts +118 -118
  249. package/src/orchestrate/interface/orchestrateInterfaceActionEndpoint.ts +58 -58
  250. package/src/orchestrate/interface/orchestrateInterfaceAuthorization.ts +208 -208
  251. package/src/orchestrate/interface/orchestrateInterfaceBaseEndpoint.ts +55 -55
  252. package/src/orchestrate/interface/orchestrateInterfaceEndpoint.ts +67 -67
  253. package/src/orchestrate/interface/orchestrateInterfaceEndpointOverall.ts +80 -80
  254. package/src/orchestrate/interface/orchestrateInterfaceEndpointReview.ts +212 -212
  255. package/src/orchestrate/interface/orchestrateInterfaceEndpointWrite.ts +236 -236
  256. package/src/orchestrate/interface/orchestrateInterfaceGroup.ts +166 -166
  257. package/src/orchestrate/interface/orchestrateInterfaceOperation.ts +322 -322
  258. package/src/orchestrate/interface/orchestrateInterfaceOperationReview.ts +245 -245
  259. package/src/orchestrate/interface/orchestrateInterfacePrerequisite.ts +240 -240
  260. package/src/orchestrate/interface/orchestrateInterfaceSchema.ts +191 -191
  261. package/src/orchestrate/interface/orchestrateInterfaceSchemaCasting.ts +274 -274
  262. package/src/orchestrate/interface/orchestrateInterfaceSchemaComplement.ts +329 -329
  263. package/src/orchestrate/interface/orchestrateInterfaceSchemaRefine.ts +292 -292
  264. package/src/orchestrate/interface/orchestrateInterfaceSchemaRename.ts +266 -266
  265. package/src/orchestrate/interface/orchestrateInterfaceSchemaReview.ts +310 -310
  266. package/src/orchestrate/interface/orchestrateInterfaceSchemaWrite.ts +283 -283
  267. package/src/orchestrate/interface/programmers/AutoBeInterfaceAuthorizationProgrammer.ts +260 -260
  268. package/src/orchestrate/interface/programmers/AutoBeInterfaceEndpointProgrammer.ts +155 -155
  269. package/src/orchestrate/interface/programmers/AutoBeInterfaceEndpointReviewProgrammer.ts +139 -139
  270. package/src/orchestrate/interface/programmers/AutoBeInterfaceOperationProgrammer.ts +277 -277
  271. package/src/orchestrate/interface/programmers/AutoBeInterfacePrerequisiteProgrammer.ts +259 -259
  272. package/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaProgrammer.ts +152 -152
  273. package/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaPropertyReviseProgrammer.ts +347 -347
  274. package/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaRefineProgrammer.ts +183 -183
  275. package/src/orchestrate/interface/programmers/AutoBeInterfaceSchemaReviewProgrammer.ts +263 -263
  276. package/src/orchestrate/interface/structures/IAutoBeInterfaceAuthorizationApplication.ts +135 -135
  277. package/src/orchestrate/interface/structures/IAutoBeInterfaceEndpointReviewApplication.ts +128 -128
  278. package/src/orchestrate/interface/structures/IAutoBeInterfaceEndpointWriteApplication.ts +133 -133
  279. package/src/orchestrate/interface/structures/IAutoBeInterfaceGroupApplication.ts +122 -122
  280. package/src/orchestrate/interface/structures/IAutoBeInterfaceOperationApplication.ts +178 -178
  281. package/src/orchestrate/interface/structures/IAutoBeInterfaceOperationReviewApplication.ts +175 -175
  282. package/src/orchestrate/interface/structures/IAutoBeInterfacePrerequisiteApplication.ts +130 -130
  283. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaApplication.ts +121 -121
  284. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaCastingApplication.ts +153 -153
  285. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaComplementApplication.ts +123 -123
  286. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaRefineApplication.ts +181 -181
  287. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaRenameApplication.ts +45 -45
  288. package/src/orchestrate/interface/structures/IAutoBeInterfaceSchemaReviewApplication.ts +108 -108
  289. package/src/orchestrate/interface/utils/AutoBeJsonSchemaCollection.ts +42 -42
  290. package/src/orchestrate/interface/utils/AutoBeJsonSchemaFactory.ts +714 -714
  291. package/src/orchestrate/interface/utils/AutoBeJsonSchemaNamingConvention.ts +86 -86
  292. package/src/orchestrate/interface/utils/AutoBeJsonSchemaValidator.ts +725 -725
  293. package/src/orchestrate/interface/utils/fulfillJsonSchemaErrorMessages.ts +219 -219
  294. package/src/orchestrate/prisma/histories/transformPrismaAuthorizationHistory.ts +144 -144
  295. package/src/orchestrate/prisma/histories/transformPrismaAuthorizationReviewHistory.ts +104 -104
  296. package/src/orchestrate/prisma/histories/transformPrismaComponentReviewHistory.ts +97 -97
  297. package/src/orchestrate/prisma/histories/transformPrismaComponentsHistory.ts +136 -136
  298. package/src/orchestrate/prisma/histories/transformPrismaCorrectHistory.ts +41 -41
  299. package/src/orchestrate/prisma/histories/transformPrismaGroupHistory.ts +63 -63
  300. package/src/orchestrate/prisma/histories/transformPrismaGroupReviewHistory.ts +79 -79
  301. package/src/orchestrate/prisma/histories/transformPrismaSchemaHistory.ts +97 -97
  302. package/src/orchestrate/prisma/histories/transformPrismaSchemaReviewHistory.ts +126 -126
  303. package/src/orchestrate/prisma/index.ts +7 -7
  304. package/src/orchestrate/prisma/orchestratePrisma.ts +296 -296
  305. package/src/orchestrate/prisma/orchestratePrismaAuthorization.ts +173 -173
  306. package/src/orchestrate/prisma/orchestratePrismaAuthorizationReview.ts +183 -183
  307. package/src/orchestrate/prisma/orchestratePrismaComponent.ts +205 -205
  308. package/src/orchestrate/prisma/orchestratePrismaComponentReview.ts +205 -205
  309. package/src/orchestrate/prisma/orchestratePrismaCorrect.ts +265 -265
  310. package/src/orchestrate/prisma/orchestratePrismaGroup.ts +121 -121
  311. package/src/orchestrate/prisma/orchestratePrismaGroupReview.ts +141 -141
  312. package/src/orchestrate/prisma/orchestratePrismaSchema.ts +218 -218
  313. package/src/orchestrate/prisma/orchestratePrismaSchemaReview.ts +220 -220
  314. package/src/orchestrate/prisma/programmers/AutoBeDatabaseAuthorizationProgrammer.ts +86 -86
  315. package/src/orchestrate/prisma/programmers/AutoBeDatabaseAuthorizationReviewProgrammer.ts +103 -103
  316. package/src/orchestrate/prisma/programmers/AutoBeDatabaseComponentProgrammer.ts +80 -80
  317. package/src/orchestrate/prisma/programmers/AutoBeDatabaseComponentReviewProgrammer.ts +168 -168
  318. package/src/orchestrate/prisma/programmers/AutoBeDatabaseGroupProgrammer.ts +63 -63
  319. package/src/orchestrate/prisma/programmers/AutoBeDatabaseGroupReviewProgrammer.ts +210 -210
  320. package/src/orchestrate/prisma/programmers/AutoBeDatabaseModelProgrammer.ts +57 -57
  321. package/src/orchestrate/prisma/programmers/AutoBeDatabaseSchemaProgrammer.ts +92 -92
  322. package/src/orchestrate/prisma/structures/IAutoBeDatabaseAuthorizationApplication.ts +147 -147
  323. package/src/orchestrate/prisma/structures/IAutoBeDatabaseAuthorizationReviewApplication.ts +153 -153
  324. package/src/orchestrate/prisma/structures/IAutoBeDatabaseComponentApplication.ts +142 -142
  325. package/src/orchestrate/prisma/structures/IAutoBeDatabaseComponentReviewApplication.ts +151 -151
  326. package/src/orchestrate/prisma/structures/IAutoBeDatabaseCorrectApplication.ts +157 -157
  327. package/src/orchestrate/prisma/structures/IAutoBeDatabaseGroupApplication.ts +117 -117
  328. package/src/orchestrate/prisma/structures/IAutoBeDatabaseGroupReviewApplication.ts +154 -154
  329. package/src/orchestrate/prisma/structures/IAutoBeDatabaseSchemaApplication.ts +144 -144
  330. package/src/orchestrate/prisma/structures/IAutoBeDatabaseSchemaReviewApplication.ts +138 -138
  331. package/src/orchestrate/realize/histories/transformRealizeAuthorizationCorrectHistory.ts +89 -89
  332. package/src/orchestrate/realize/histories/transformRealizeAuthorizationWriteHistory.ts +45 -45
  333. package/src/orchestrate/realize/histories/transformRealizeCollectorCorrectHistory.ts +137 -137
  334. package/src/orchestrate/realize/histories/transformRealizeCollectorPlanHistory.ts +64 -64
  335. package/src/orchestrate/realize/histories/transformRealizeCollectorWriteHistory.ts +147 -147
  336. package/src/orchestrate/realize/histories/transformRealizeCorrectCastingHistory.ts +69 -69
  337. package/src/orchestrate/realize/histories/transformRealizeOperationCorrectHistory.ts +94 -94
  338. package/src/orchestrate/realize/histories/transformRealizeOperationWriteHistory.ts +127 -127
  339. package/src/orchestrate/realize/histories/transformRealizeTransformerCorrectHistory.ts +147 -147
  340. package/src/orchestrate/realize/histories/transformRealizeTransformerPlanHistory.ts +61 -61
  341. package/src/orchestrate/realize/histories/transformRealizeTransformerWriteHistory.ts +133 -133
  342. package/src/orchestrate/realize/histories/transformRealizeWriteMembershipHistory.ts +30 -30
  343. package/src/orchestrate/realize/index.ts +3 -3
  344. package/src/orchestrate/realize/internal/orchestrateRealizeCorrectCasting.ts +444 -444
  345. package/src/orchestrate/realize/internal/orchestrateRealizeCorrectOverall.ts +449 -449
  346. package/src/orchestrate/realize/orchestrateRealize.ts +143 -143
  347. package/src/orchestrate/realize/orchestrateRealizeAuthorizationCorrect.ts +207 -207
  348. package/src/orchestrate/realize/orchestrateRealizeAuthorizationWrite.ts +209 -209
  349. package/src/orchestrate/realize/orchestrateRealizeCollector.ts +41 -41
  350. package/src/orchestrate/realize/orchestrateRealizeCollectorCorrectCasting.ts +43 -43
  351. package/src/orchestrate/realize/orchestrateRealizeCollectorCorrectOverall.ts +157 -157
  352. package/src/orchestrate/realize/orchestrateRealizeCollectorPlan.ts +264 -264
  353. package/src/orchestrate/realize/orchestrateRealizeCollectorWrite.ts +225 -225
  354. package/src/orchestrate/realize/orchestrateRealizeOperation.ts +48 -48
  355. package/src/orchestrate/realize/orchestrateRealizeOperationCorrectCasting.ts +69 -69
  356. package/src/orchestrate/realize/orchestrateRealizeOperationCorrectOverall.ts +173 -173
  357. package/src/orchestrate/realize/orchestrateRealizeOperationWrite.ts +262 -262
  358. package/src/orchestrate/realize/orchestrateRealizeTransformer.ts +41 -41
  359. package/src/orchestrate/realize/orchestrateRealizeTransformerCorrectCasting.ts +38 -38
  360. package/src/orchestrate/realize/orchestrateRealizeTransformerCorrectOverall.ts +160 -160
  361. package/src/orchestrate/realize/orchestrateRealizeTransformerPlan.ts +254 -254
  362. package/src/orchestrate/realize/orchestrateRealizeTransformerWrite.ts +226 -226
  363. package/src/orchestrate/realize/programmers/AutoBeRealizeCollectorProgrammer.ts +424 -424
  364. package/src/orchestrate/realize/programmers/AutoBeRealizeOperationProgrammer.ts +409 -409
  365. package/src/orchestrate/realize/programmers/AutoBeRealizeTransformerProgrammer.ts +451 -451
  366. package/src/orchestrate/realize/programmers/compileRealizeFiles.ts +65 -65
  367. package/src/orchestrate/realize/structures/IAutoBeRealizeAuthorizationCorrectApplication.ts +119 -119
  368. package/src/orchestrate/realize/structures/IAutoBeRealizeAuthorizationWriteApplication.ts +167 -167
  369. package/src/orchestrate/realize/structures/IAutoBeRealizeCollectorCorrectApplication.ts +191 -191
  370. package/src/orchestrate/realize/structures/IAutoBeRealizeCollectorPlanApplication.ts +177 -177
  371. package/src/orchestrate/realize/structures/IAutoBeRealizeCollectorWriteApplication.ts +207 -207
  372. package/src/orchestrate/realize/structures/IAutoBeRealizeFunctionFailure.ts +11 -11
  373. package/src/orchestrate/realize/structures/IAutoBeRealizeOperationCorrectApplication.ts +134 -134
  374. package/src/orchestrate/realize/structures/IAutoBeRealizeOperationWriteApplication.ts +138 -138
  375. package/src/orchestrate/realize/structures/IAutoBeRealizeScenarioResult.ts +32 -32
  376. package/src/orchestrate/realize/structures/IAutoBeRealizeTransformerCorrectApplication.ts +248 -248
  377. package/src/orchestrate/realize/structures/IAutoBeRealizeTransformerPlanApplication.ts +150 -150
  378. package/src/orchestrate/realize/structures/IAutoBeRealizeTransformerWriteApplication.ts +278 -278
  379. package/src/orchestrate/realize/utils/AuthorizationFileSystem.ts +10 -10
  380. package/src/orchestrate/realize/utils/AutoBeRealizeAuthorizationFileSystem.ts +9 -9
  381. package/src/orchestrate/realize/utils/AutoBeRealizeAuthorizationReplaceImport.ts +62 -62
  382. package/src/orchestrate/realize/utils/InternalFileSystem.ts +12 -12
  383. package/src/orchestrate/realize/utils/ProviderFileSystem.ts +4 -4
  384. package/src/orchestrate/realize/utils/filterDiagnostics.ts +25 -25
  385. package/src/orchestrate/realize/utils/generateTS2339Hints.ts +54 -54
  386. package/src/orchestrate/realize/utils/getRealizeWriteImportStatements.ts +42 -42
  387. package/src/orchestrate/realize/utils/getRealizeWriteInputType.ts +88 -88
  388. package/src/orchestrate/realize/utils/printErrorHints.ts +54 -54
  389. package/src/orchestrate/test/compile/getTestArtifacts.ts +124 -124
  390. package/src/orchestrate/test/compile/getTestExternalDeclarations.ts +39 -39
  391. package/src/orchestrate/test/compile/getTestImportStatements.ts +27 -27
  392. package/src/orchestrate/test/experimental/orchestrateTestCorrect.ast +237 -237
  393. package/src/orchestrate/test/experimental/orchestrateTestWrite.ast +322 -322
  394. package/src/orchestrate/test/experimental/transformTestCorrectHistories.ast +52 -52
  395. package/src/orchestrate/test/histories/transformTestAuthorizeWriteHistory.ts +80 -80
  396. package/src/orchestrate/test/histories/transformTestCorrectOverallHistory.ts +116 -116
  397. package/src/orchestrate/test/histories/transformTestGenerationWriteHistory.ts +118 -118
  398. package/src/orchestrate/test/histories/transformTestOperationWriteHistory.ts +287 -287
  399. package/src/orchestrate/test/histories/transformTestPrepareWriteHistory.ts +95 -95
  400. package/src/orchestrate/test/histories/transformTestScenarioHistory.ts +120 -120
  401. package/src/orchestrate/test/histories/transformTestScenarioReviewHistory.ts +99 -99
  402. package/src/orchestrate/test/histories/transformTestValidateEvent.ts +11 -11
  403. package/src/orchestrate/test/index.ts +5 -5
  404. package/src/orchestrate/test/internal/orchestrateTestCorrectCasting.ts +96 -96
  405. package/src/orchestrate/test/internal/orchestrateTestCorrectOverall.ts +219 -219
  406. package/src/orchestrate/test/internal/orchestrateTestCorrectRequest.ts +206 -206
  407. package/src/orchestrate/test/orchestrateTest.ts +161 -161
  408. package/src/orchestrate/test/orchestrateTestAuthorize.ts +125 -125
  409. package/src/orchestrate/test/orchestrateTestAuthorizeWrite.ts +263 -263
  410. package/src/orchestrate/test/orchestrateTestGenerate.ts +121 -121
  411. package/src/orchestrate/test/orchestrateTestGenerateWrite.ts +211 -211
  412. package/src/orchestrate/test/orchestrateTestOperation.ts +133 -133
  413. package/src/orchestrate/test/orchestrateTestOperationWrite.ts +221 -221
  414. package/src/orchestrate/test/orchestrateTestPrepare.ts +117 -117
  415. package/src/orchestrate/test/orchestrateTestPrepareWrite.ts +264 -264
  416. package/src/orchestrate/test/orchestrateTestScenario.ts +290 -290
  417. package/src/orchestrate/test/orchestrateTestScenarioReview.ts +262 -262
  418. package/src/orchestrate/test/programmers/AutoBeTestAuthorizeProgrammer.ts +149 -149
  419. package/src/orchestrate/test/programmers/AutoBeTestFunctionProgrammer.ts +90 -90
  420. package/src/orchestrate/test/programmers/AutoBeTestGenerateProgrammer.ts +170 -170
  421. package/src/orchestrate/test/programmers/AutoBeTestOperationProgrammer.ts +168 -168
  422. package/src/orchestrate/test/programmers/AutoBeTestPrepareProgrammer.ts +261 -261
  423. package/src/orchestrate/test/programmers/AutoBeTestScenarioProgrammer.ts +316 -316
  424. package/src/orchestrate/test/structures/IAutoBeTestArtifacts.ts +8 -8
  425. package/src/orchestrate/test/structures/IAutoBeTestAuthorizationWriteApplication.ts +113 -113
  426. package/src/orchestrate/test/structures/IAutoBeTestAuthorizeWriteResult.ts +10 -10
  427. package/src/orchestrate/test/structures/IAutoBeTestCorrectOverallApplication.ts +134 -134
  428. package/src/orchestrate/test/structures/IAutoBeTestCorrectRequestApplication.ts +152 -152
  429. package/src/orchestrate/test/structures/IAutoBeTestFunction.ts +10 -10
  430. package/src/orchestrate/test/structures/IAutoBeTestFunctionFailure.ts +10 -10
  431. package/src/orchestrate/test/structures/IAutoBeTestGenerateProcedure.ts +15 -15
  432. package/src/orchestrate/test/structures/IAutoBeTestGenerationWriteApplication.ts +145 -145
  433. package/src/orchestrate/test/structures/IAutoBeTestOperationProcedure.ts +17 -17
  434. package/src/orchestrate/test/structures/IAutoBeTestOperationWriteApplication.ts +162 -162
  435. package/src/orchestrate/test/structures/IAutoBeTestPrepareCorrectOverallApplication.ts +194 -194
  436. package/src/orchestrate/test/structures/IAutoBeTestPrepareProcedure.ts +8 -8
  437. package/src/orchestrate/test/structures/IAutoBeTestPrepareWriteApplication.ts +147 -147
  438. package/src/orchestrate/test/structures/IAutoBeTestProcedure.ts +10 -10
  439. package/src/orchestrate/test/structures/IAutoBeTestScenarioApplication.ts +105 -105
  440. package/src/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.ts +8 -8
  441. package/src/orchestrate/test/structures/IAutoBeTestScenarioAuthorizationActor.ts +7 -7
  442. package/src/orchestrate/test/structures/IAutoBeTestScenarioReviewApplication.ts +133 -133
  443. package/src/orchestrate/test/utils/getPrerequisites.ts +51 -51
  444. package/src/orchestrate/test/utils/getReferenceIds.ts +26 -26
  445. package/src/orchestrate/test/utils/insertScriptToTestResult.ts +14 -14
  446. package/src/structures/IAutoBeConfig.ts +110 -110
  447. package/src/structures/IAutoBeOrchestrateHistory.ts +44 -44
  448. package/src/structures/IAutoBeProps.ts +102 -102
  449. package/src/structures/IAutoBeVendor.ts +113 -113
  450. package/src/utils/AutoBePreliminaryExhaustedError.ts +30 -30
  451. package/src/utils/AutoBeTimeoutError.ts +35 -35
  452. package/src/utils/EmbeddingProvider.ts +4 -4
  453. package/src/utils/LocalEmbeddingProvider.ts +145 -145
  454. package/src/utils/RAGRetrieval.ts +411 -411
  455. package/src/utils/TimedConversation.ts +125 -125
  456. package/src/utils/backoffRetry.ts +169 -169
  457. package/src/utils/divideArray.ts +35 -35
  458. package/src/utils/emplaceMap.ts +31 -31
  459. package/src/utils/executeCachedBatch.ts +67 -67
  460. package/src/utils/forceRetry.ts +15 -15
  461. package/src/utils/getEmbedder.ts +16 -16
  462. package/src/utils/parseTextFunctionCall.ts +437 -437
  463. package/src/utils/predicateStateMessage.ts +131 -131
  464. package/src/utils/validateEmptyCode.ts +73 -73
  465. package/src/utils/validateEnglishOnly.ts +224 -224
  466. package/README.md +0 -261
@@ -1,813 +1,813 @@
1
- import {
2
- AutoBeAnalyze,
3
- AutoBeAnalyzeWriteSectionEvent,
4
- } from "@autobe/interface";
5
- import YAML from "yaml";
6
-
7
- type ConstraintSource = {
8
- file: AutoBeAnalyze.IFileScenario;
9
- sectionTitle: string;
10
- };
11
-
12
- type ConstraintValue = {
13
- normalized: string;
14
- display: string;
15
- sources: ConstraintSource[];
16
- };
17
-
18
- type ConstraintEntry = {
19
- key: string;
20
- values: Map<string, ConstraintValue>;
21
- };
22
-
23
- const YAML_CODE_BLOCK_REGEX = /```yaml\n([\s\S]*?)```/g;
24
-
25
- export const buildConstraintConsistencyReport = (props: {
26
- files: Array<{
27
- file: AutoBeAnalyze.IFileScenario;
28
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
29
- }>;
30
- }): string => {
31
- const constraints: Map<string, ConstraintEntry> = new Map();
32
- let totalConstraints: number = 0;
33
-
34
- for (const { file, sectionEvents } of props.files) {
35
- for (const sectionsForModule of sectionEvents) {
36
- for (const sectionEvent of sectionsForModule) {
37
- for (const section of sectionEvent.sectionSections) {
38
- const pairs = extractConstraints(section.content);
39
- for (const { key, value } of pairs) {
40
- totalConstraints++;
41
- const normalized = normalizeValue(value);
42
- if (!constraints.has(key)) {
43
- constraints.set(key, {
44
- key,
45
- values: new Map(),
46
- });
47
- }
48
- const entry = constraints.get(key)!;
49
- if (!entry.values.has(normalized)) {
50
- entry.values.set(normalized, {
51
- normalized,
52
- display: value.trim(),
53
- sources: [],
54
- });
55
- }
56
- entry.values.get(normalized)!.sources.push({
57
- file,
58
- sectionTitle: section.title,
59
- });
60
- }
61
- }
62
- }
63
- }
64
- }
65
-
66
- const conflicts: ConstraintEntry[] = [...constraints.values()].filter(
67
- (entry) => entry.values.size > 1,
68
- );
69
-
70
- if (conflicts.length === 0) {
71
- return [
72
- "No numeric constraint conflicts detected.",
73
- `Scanned ${totalConstraints} numeric constraints from YAML spec blocks.`,
74
- ].join("\n");
75
- }
76
-
77
- const lines: string[] = [
78
- `Detected ${conflicts.length} numeric constraint conflict(s).`,
79
- `Scanned ${totalConstraints} numeric constraints from YAML spec blocks.`,
80
- "",
81
- "Conflicts:",
82
- ];
83
-
84
- for (const entry of conflicts) {
85
- lines.push(`- ${entry.key}:`);
86
- for (const value of entry.values.values()) {
87
- const sources = value.sources
88
- .map((s) => `${s.file.filename} → ${s.sectionTitle}`)
89
- .slice(0, 6)
90
- .join("; ");
91
- lines.push(` - ${value.display} (e.g., ${sources})`);
92
- }
93
- }
94
-
95
- return lines.join("\n");
96
- };
97
-
98
- /**
99
- * Extract numeric constraints from YAML spec blocks.
100
- *
101
- * Parses YAML code blocks and extracts Entity.attribute constraints that
102
- * contain numeric values (e.g., length limits, quantity limits).
103
- */
104
- const extractConstraints = (
105
- content: string,
106
- ): Array<{ key: string; value: string }> => {
107
- if (!content) return [];
108
- const results: Array<{ key: string; value: string }> = [];
109
- const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
110
-
111
- for (const match of yamlMatches) {
112
- const yamlContent = match[1] ?? "";
113
- try {
114
- const parsed = YAML.parse(yamlContent);
115
- if (!parsed || typeof parsed !== "object") continue;
116
-
117
- // Handle entity attribute YAML blocks
118
- if (
119
- typeof parsed.entity === "string" &&
120
- Array.isArray(parsed.attributes)
121
- ) {
122
- for (const attr of parsed.attributes) {
123
- if (!attr || typeof attr.name !== "string") continue;
124
- const constraintStr = String(attr.constraints ?? "");
125
- if (!hasNumeric(constraintStr)) continue;
126
- results.push({
127
- key: `${parsed.entity}.${attr.name}`,
128
- value: constraintStr,
129
- });
130
- }
131
- }
132
-
133
- // Handle error code YAML blocks (HTTP status codes)
134
- if (Array.isArray(parsed.errors)) {
135
- for (const err of parsed.errors) {
136
- if (!err || typeof err.code !== "string") continue;
137
- if (typeof err.http === "number") {
138
- results.push({
139
- key: `error.${err.code}.http`,
140
- value: String(err.http),
141
- });
142
- }
143
- }
144
- }
145
- } catch {
146
- // skip parse errors
147
- }
148
- }
149
-
150
- return results;
151
- };
152
-
153
- const normalizeValue = (value: string): string =>
154
- value
155
- .toLowerCase()
156
- .replace(/[–—]/g, "-")
157
- .replace(/`/g, "")
158
- .replace(/\s+/g, " ")
159
- .trim();
160
-
161
- const hasNumeric = (value: string): boolean => /\d/.test(value);
162
-
163
- // ─── Structured Conflict Detection ───
164
-
165
- export interface IConstraintConflict {
166
- key: string;
167
- values: Array<{
168
- display: string;
169
- files: string[];
170
- }>;
171
- }
172
-
173
- /**
174
- * Detect numeric constraint conflicts across files as structured data.
175
- *
176
- * Returns an array of conflicts where the same constraint key has different
177
- * normalized values across files.
178
- */
179
- export const detectConstraintConflicts = (props: {
180
- files: Array<{
181
- file: AutoBeAnalyze.IFileScenario;
182
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
183
- }>;
184
- }): IConstraintConflict[] => {
185
- const constraints: Map<string, ConstraintEntry> = new Map();
186
-
187
- for (const { file, sectionEvents } of props.files) {
188
- for (const sectionsForModule of sectionEvents) {
189
- for (const sectionEvent of sectionsForModule) {
190
- for (const section of sectionEvent.sectionSections) {
191
- const pairs = extractConstraints(section.content);
192
- for (const { key, value } of pairs) {
193
- const normalized = normalizeValue(value);
194
- if (!constraints.has(key)) {
195
- constraints.set(key, { key, values: new Map() });
196
- }
197
- const entry = constraints.get(key)!;
198
- if (!entry.values.has(normalized)) {
199
- entry.values.set(normalized, {
200
- normalized,
201
- display: value.trim(),
202
- sources: [],
203
- });
204
- }
205
- entry.values.get(normalized)!.sources.push({
206
- file,
207
- sectionTitle: section.title,
208
- });
209
- }
210
- }
211
- }
212
- }
213
- }
214
-
215
- return [...constraints.values()]
216
- .filter((entry) => entry.values.size > 1)
217
- .map((entry) => ({
218
- key: entry.key,
219
- values: [...entry.values.values()].map((v) => ({
220
- display: v.display,
221
- files: [...new Set(v.sources.map((s) => s.file.filename))],
222
- })),
223
- }));
224
- };
225
-
226
- /** Build a map from filename → list of conflict feedback strings. */
227
- export const buildFileConflictMap = (
228
- conflicts: IConstraintConflict[],
229
- ): Map<string, string[]> => {
230
- const map: Map<string, string[]> = new Map();
231
-
232
- for (const conflict of conflicts) {
233
- const allFiles = new Set(conflict.values.flatMap((v) => v.files));
234
- const feedback =
235
- `${conflict.key} has conflicting values: ` +
236
- conflict.values
237
- .map((v) => `"${v.display}" in [${v.files.join(", ")}]`)
238
- .join(" vs ");
239
-
240
- for (const filename of allFiles) {
241
- if (!map.has(filename)) map.set(filename, []);
242
- map.get(filename)!.push(feedback);
243
- }
244
- }
245
-
246
- return map;
247
- };
248
-
249
- // ─── Attribute Duplicate Detection ───
250
-
251
- export interface IAttributeDuplicate {
252
- key: string;
253
- files: string[];
254
- hasValueConflict: boolean;
255
- values?: Array<{
256
- specification: string;
257
- files: string[];
258
- }>;
259
- }
260
-
261
- /**
262
- * Detect cross-file attribute duplication from YAML spec blocks.
263
- *
264
- * Returns attributes that are defined in YAML blocks across multiple files.
265
- */
266
- export const detectAttributeDuplicates = (props: {
267
- files: Array<{
268
- file: AutoBeAnalyze.IFileScenario;
269
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
270
- }>;
271
- }): IAttributeDuplicate[] => {
272
- // key → { normalized spec → { display, files } }
273
- const attributes: Map<
274
- string,
275
- Map<string, { display: string; files: Set<string> }>
276
- > = new Map();
277
- const allFilesByKey: Map<string, Set<string>> = new Map();
278
-
279
- for (const { file, sectionEvents } of props.files) {
280
- for (const sectionsForModule of sectionEvents) {
281
- for (const sectionEvent of sectionsForModule) {
282
- for (const section of sectionEvent.sectionSections) {
283
- const specs = extractAttributeSpecs(section.content);
284
- for (const { key, specification } of specs) {
285
- if (!allFilesByKey.has(key)) allFilesByKey.set(key, new Set());
286
- allFilesByKey.get(key)!.add(file.filename);
287
-
288
- if (!attributes.has(key)) attributes.set(key, new Map());
289
- const specMap = attributes.get(key)!;
290
- const normalized = normalizeValue(specification);
291
- if (!specMap.has(normalized)) {
292
- specMap.set(normalized, {
293
- display: specification.trim(),
294
- files: new Set(),
295
- });
296
- }
297
- specMap.get(normalized)!.files.add(file.filename);
298
- }
299
- }
300
- }
301
- }
302
- }
303
-
304
- return [...allFilesByKey.entries()]
305
- .filter(([, files]) => files.size > 1)
306
- .map(([key, files]) => {
307
- const specMap = attributes.get(key)!;
308
- const hasValueConflict = specMap.size > 1;
309
- return {
310
- key,
311
- files: [...files],
312
- hasValueConflict,
313
- ...(hasValueConflict
314
- ? {
315
- values: [...specMap.values()].map((v) => ({
316
- specification: v.display,
317
- files: [...v.files],
318
- })),
319
- }
320
- : {}),
321
- };
322
- });
323
- };
324
-
325
- export const buildFileAttributeDuplicateMap = (
326
- duplicates: IAttributeDuplicate[],
327
- ): Map<string, string[]> => {
328
- const map: Map<string, string[]> = new Map();
329
-
330
- for (const dup of duplicates) {
331
- let feedback: string;
332
- if (dup.hasValueConflict && dup.values) {
333
- feedback =
334
- `${dup.key} has conflicting specifications across files: ` +
335
- dup.values
336
- .map((v) => `"${v.specification}" in [${v.files.join(", ")}]`)
337
- .join(" vs ") +
338
- `. Align to ONE canonical definition.`;
339
- } else {
340
- feedback =
341
- `${dup.key} is fully specified in multiple files: [${dup.files.join(", ")}]. ` +
342
- `Only ONE file should contain the full spec.`;
343
- }
344
-
345
- for (const filename of dup.files) {
346
- if (!map.has(filename)) map.set(filename, []);
347
- map.get(filename)!.push(feedback);
348
- }
349
- }
350
-
351
- return map;
352
- };
353
-
354
- // ─── Enum Conflict Detection ───
355
-
356
- export interface IEnumConflict {
357
- key: string;
358
- values: Array<{
359
- enumSet: string;
360
- display: string;
361
- files: string[];
362
- }>;
363
- }
364
-
365
- /**
366
- * Detect enum value conflicts from YAML spec blocks.
367
- *
368
- * Scans YAML attribute blocks for enum-like constraints and detects when
369
- * different files define different enum value sets for the same attribute.
370
- */
371
- export const detectEnumConflicts = (props: {
372
- files: Array<{
373
- file: AutoBeAnalyze.IFileScenario;
374
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
375
- }>;
376
- }): IEnumConflict[] => {
377
- type EnumValue = {
378
- enumSet: string;
379
- display: string;
380
- files: Set<string>;
381
- };
382
- const enums: Map<string, Map<string, EnumValue>> = new Map();
383
-
384
- for (const { file, sectionEvents } of props.files) {
385
- for (const sectionsForModule of sectionEvents) {
386
- for (const sectionEvent of sectionsForModule) {
387
- for (const section of sectionEvent.sectionSections) {
388
- const specs = extractEnumSpecs(section.content);
389
- for (const { key, enumSet, display } of specs) {
390
- if (!enums.has(key)) enums.set(key, new Map());
391
- const entry = enums.get(key)!;
392
- if (!entry.has(enumSet)) {
393
- entry.set(enumSet, { enumSet, display, files: new Set() });
394
- }
395
- entry.get(enumSet)!.files.add(file.filename);
396
- }
397
- }
398
- }
399
- }
400
- }
401
-
402
- return [...enums.entries()]
403
- .filter(([, values]) => values.size > 1)
404
- .map(([key, values]) => ({
405
- key,
406
- values: [...values.values()].map((v) => ({
407
- enumSet: v.enumSet,
408
- display: v.display,
409
- files: [...v.files],
410
- })),
411
- }));
412
- };
413
-
414
- export const buildFileEnumConflictMap = (
415
- conflicts: IEnumConflict[],
416
- ): Map<string, string[]> => {
417
- const map: Map<string, string[]> = new Map();
418
-
419
- for (const conflict of conflicts) {
420
- const allFiles = new Set(conflict.values.flatMap((v) => v.files));
421
- const feedback =
422
- `${conflict.key} has conflicting enum values: ` +
423
- conflict.values
424
- .map((v) => `enum(${v.enumSet}) in [${v.files.join(", ")}]`)
425
- .join(" vs ");
426
-
427
- for (const filename of allFiles) {
428
- if (!map.has(filename)) map.set(filename, []);
429
- map.get(filename)!.push(feedback);
430
- }
431
- }
432
-
433
- return map;
434
- };
435
-
436
- // ─── Permission Rule Conflict Detection ───
437
-
438
- export interface IPermissionConflict {
439
- actorOperation: string;
440
- rules: Array<{
441
- condition: string;
442
- files: string[];
443
- }>;
444
- }
445
-
446
- /**
447
- * Detect permission rule conflicts from YAML spec blocks.
448
- *
449
- * A conflict occurs when one YAML block allows an action but another doesn't
450
- * include it for the same actor+resource.
451
- */
452
- export const detectPermissionConflicts = (props: {
453
- files: Array<{
454
- file: AutoBeAnalyze.IFileScenario;
455
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
456
- }>;
457
- }): IPermissionConflict[] => {
458
- // actor:resource → action → Set<filename>
459
- const ruleMap: Map<string, Map<string, Set<string>>> = new Map();
460
-
461
- for (const { file, sectionEvents } of props.files) {
462
- for (const sectionsForModule of sectionEvents) {
463
- for (const sectionEvent of sectionsForModule) {
464
- for (const section of sectionEvent.sectionSections) {
465
- const rules = extractPermissionRulesFromYaml(section.content);
466
- for (const { actor, resource, actions } of rules) {
467
- const key = `${actor.toLowerCase()}:${resource}`;
468
- if (!ruleMap.has(key)) ruleMap.set(key, new Map());
469
- const actionMap = ruleMap.get(key)!;
470
- for (const action of actions) {
471
- const normAction = action.toLowerCase();
472
- if (!actionMap.has(normAction))
473
- actionMap.set(normAction, new Set());
474
- actionMap.get(normAction)!.add(file.filename);
475
- }
476
- }
477
- }
478
- }
479
- }
480
- }
481
-
482
- // Permission conflicts are rare in YAML-based approach since
483
- // 01-actors-and-auth is the canonical source. Return empty for now.
484
- return [];
485
- };
486
-
487
- export const buildFilePermissionConflictMap = (
488
- conflicts: IPermissionConflict[],
489
- ): Map<string, string[]> => {
490
- const map: Map<string, string[]> = new Map();
491
-
492
- for (const conflict of conflicts) {
493
- const allFiles = new Set(conflict.rules.flatMap((r) => r.files));
494
- const feedback =
495
- `Permission conflict for "${conflict.actorOperation}": ` +
496
- conflict.rules
497
- .map((r) => `"${r.condition}" in [${r.files.join(", ")}]`)
498
- .join(" vs ");
499
-
500
- for (const filename of allFiles) {
501
- if (!map.has(filename)) map.set(filename, []);
502
- map.get(filename)!.push(feedback);
503
- }
504
- }
505
-
506
- return map;
507
- };
508
-
509
- // ─── State Field Conflict Detection ───
510
-
511
- export interface IStateFieldConflict {
512
- entity: string;
513
- conflictType: string;
514
- fields: Array<{
515
- fieldName: string;
516
- specification: string;
517
- files: string[];
518
- }>;
519
- }
520
-
521
- /**
522
- * Detect state field conflicts from YAML spec blocks.
523
- *
524
- * Known contradiction patterns:
525
- *
526
- * 1. Same entity has both `deletedAt` (datetime) and `isDeleted` (boolean)
527
- * 2. Same entity has `status` (enum) and semantically equivalent `is*` booleans
528
- */
529
- export const detectStateFieldConflicts = (props: {
530
- files: Array<{
531
- file: AutoBeAnalyze.IFileScenario;
532
- sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
533
- }>;
534
- }): IStateFieldConflict[] => {
535
- // entity → { fieldName → { specification, files } }
536
- const entityFields: Map<
537
- string,
538
- Map<string, { specification: string; files: Set<string> }>
539
- > = new Map();
540
-
541
- for (const { file, sectionEvents } of props.files) {
542
- for (const sectionsForModule of sectionEvents) {
543
- for (const sectionEvent of sectionsForModule) {
544
- for (const section of sectionEvent.sectionSections) {
545
- const specs = extractAttributeSpecs(section.content);
546
- for (const { key, specification } of specs) {
547
- const dotIndex = key.indexOf(".");
548
- if (dotIndex < 0) continue;
549
- const entity = key.slice(0, dotIndex);
550
- const field = key.slice(dotIndex + 1).toLowerCase();
551
-
552
- if (!entityFields.has(entity)) entityFields.set(entity, new Map());
553
- const fields = entityFields.get(entity)!;
554
- if (!fields.has(field))
555
- fields.set(field, { specification, files: new Set() });
556
- fields.get(field)!.files.add(file.filename);
557
- }
558
- }
559
- }
560
- }
561
- }
562
-
563
- const conflicts: IStateFieldConflict[] = [];
564
-
565
- for (const [entity, fields] of entityFields) {
566
- const fieldNames = [...fields.keys()];
567
-
568
- // Pattern 1: deletedAt + isDeleted on same entity
569
- const hasDeletedAt = fieldNames.some(
570
- (f) => f === "deletedat" || f === "deleted_at",
571
- );
572
- const hasIsDeleted = fieldNames.some(
573
- (f) => f === "isdeleted" || f === "is_deleted",
574
- );
575
-
576
- if (hasDeletedAt && hasIsDeleted) {
577
- const deletedAtField =
578
- fields.get("deletedat") ?? fields.get("deleted_at");
579
- const isDeletedField =
580
- fields.get("isdeleted") ?? fields.get("is_deleted");
581
-
582
- if (deletedAtField && isDeletedField) {
583
- conflicts.push({
584
- entity,
585
- conflictType: "deletedAt vs isDeleted",
586
- fields: [
587
- {
588
- fieldName: "deletedAt",
589
- specification: deletedAtField.specification,
590
- files: [...deletedAtField.files],
591
- },
592
- {
593
- fieldName: "isDeleted",
594
- specification: isDeletedField.specification,
595
- files: [...isDeletedField.files],
596
- },
597
- ],
598
- });
599
- }
600
- }
601
-
602
- // Pattern 2: status (enum) + is* booleans
603
- const statusField = fields.get("status");
604
- if (statusField && /enum/i.test(statusField.specification)) {
605
- const isBooleans = fieldNames.filter(
606
- (f) =>
607
- f.startsWith("is") && /boolean/i.test(fields.get(f)!.specification),
608
- );
609
-
610
- for (const boolField of isBooleans) {
611
- const concept = boolField.slice(2).toLowerCase();
612
- if (statusField.specification.toLowerCase().includes(concept)) {
613
- const boolEntry = fields.get(boolField)!;
614
- conflicts.push({
615
- entity,
616
- conflictType: `status enum includes "${concept}" but separate is${concept.charAt(0).toUpperCase() + concept.slice(1)} boolean also exists`,
617
- fields: [
618
- {
619
- fieldName: "status",
620
- specification: statusField.specification,
621
- files: [...statusField.files],
622
- },
623
- {
624
- fieldName: boolField,
625
- specification: boolEntry.specification,
626
- files: [...boolEntry.files],
627
- },
628
- ],
629
- });
630
- }
631
- }
632
- }
633
- }
634
-
635
- return conflicts;
636
- };
637
-
638
- export const buildFileStateFieldConflictMap = (
639
- conflicts: IStateFieldConflict[],
640
- ): Map<string, string[]> => {
641
- const map: Map<string, string[]> = new Map();
642
-
643
- for (const conflict of conflicts) {
644
- const allFiles = new Set(conflict.fields.flatMap((f) => f.files));
645
- const feedback =
646
- `State field conflict for "${conflict.entity}": ${conflict.conflictType}. ` +
647
- conflict.fields
648
- .map(
649
- (f) =>
650
- `"${f.fieldName}: ${f.specification}" in [${f.files.join(", ")}]`,
651
- )
652
- .join(" vs ") +
653
- `. Use ONE canonical approach.`;
654
-
655
- for (const filename of allFiles) {
656
- if (!map.has(filename)) map.set(filename, []);
657
- map.get(filename)!.push(feedback);
658
- }
659
- }
660
-
661
- return map;
662
- };
663
-
664
- // ─── YAML-based Attribute Specs Extraction (shared) ───
665
-
666
- const ENUM_PATTERN = /enum\s*[\(\[\{]([^)\]\}]+)[\)\]\}]/i;
667
-
668
- /**
669
- * Extract attribute specs from YAML code blocks.
670
- *
671
- * Parses YAML blocks with `entity` + `attributes` structure and returns
672
- * Entity.attribute → constraints pairs.
673
- */
674
- const extractAttributeSpecs = (
675
- content: string,
676
- ): Array<{ key: string; specification: string }> => {
677
- if (!content) return [];
678
- const results: Array<{ key: string; specification: string }> = [];
679
- const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
680
-
681
- for (const match of yamlMatches) {
682
- const yamlContent = match[1] ?? "";
683
- try {
684
- const parsed = YAML.parse(yamlContent);
685
- if (
686
- !parsed ||
687
- typeof parsed !== "object" ||
688
- typeof parsed.entity !== "string" ||
689
- !Array.isArray(parsed.attributes)
690
- )
691
- continue;
692
-
693
- for (const attr of parsed.attributes) {
694
- if (!attr || typeof attr.name !== "string") continue;
695
- const spec = [
696
- attr.type ? String(attr.type) : "",
697
- attr.constraints ? String(attr.constraints) : "",
698
- ]
699
- .filter(Boolean)
700
- .join(", ");
701
- if (!spec) continue;
702
- results.push({
703
- key: `${parsed.entity}.${attr.name}`,
704
- specification: spec,
705
- });
706
- }
707
- } catch {
708
- // skip parse errors
709
- }
710
- }
711
-
712
- return results;
713
- };
714
-
715
- /** Extract enum specs from YAML attribute blocks. */
716
- const extractEnumSpecs = (
717
- content: string,
718
- ): Array<{ key: string; enumSet: string; display: string }> => {
719
- if (!content) return [];
720
- const results: Array<{ key: string; enumSet: string; display: string }> = [];
721
- const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
722
-
723
- for (const match of yamlMatches) {
724
- const yamlContent = match[1] ?? "";
725
- try {
726
- const parsed = YAML.parse(yamlContent);
727
- if (
728
- !parsed ||
729
- typeof parsed !== "object" ||
730
- typeof parsed.entity !== "string" ||
731
- !Array.isArray(parsed.attributes)
732
- )
733
- continue;
734
-
735
- for (const attr of parsed.attributes) {
736
- if (!attr || typeof attr.name !== "string") continue;
737
- const typeStr = String(attr.type ?? "");
738
- const constraintStr = String(attr.constraints ?? "");
739
- const combined = `${typeStr} ${constraintStr}`;
740
-
741
- const enumMatch = combined.match(ENUM_PATTERN);
742
- if (!enumMatch) continue;
743
-
744
- const rawEnumValues = enumMatch[1]!;
745
- const enumSet = [
746
- ...new Set(
747
- rawEnumValues
748
- .split(/[|,]/)
749
- .map((v) => v.trim().toLowerCase())
750
- .filter((v) => v.length > 0),
751
- ),
752
- ]
753
- .sort()
754
- .join("|");
755
-
756
- results.push({
757
- key: `${parsed.entity}.${attr.name}`,
758
- enumSet,
759
- display: combined.trim(),
760
- });
761
- }
762
- } catch {
763
- // skip parse errors
764
- }
765
- }
766
-
767
- return results;
768
- };
769
-
770
- /** Extract permission rules from YAML spec blocks. */
771
- const extractPermissionRulesFromYaml = (
772
- content: string,
773
- ): Array<{ actor: string; resource: string; actions: string[] }> => {
774
- if (!content) return [];
775
- const results: Array<{
776
- actor: string;
777
- resource: string;
778
- actions: string[];
779
- }> = [];
780
- const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
781
-
782
- for (const match of yamlMatches) {
783
- const yamlContent = match[1] ?? "";
784
- try {
785
- const parsed = YAML.parse(yamlContent);
786
- if (
787
- !parsed ||
788
- typeof parsed !== "object" ||
789
- !Array.isArray(parsed.permissions)
790
- )
791
- continue;
792
-
793
- for (const perm of parsed.permissions) {
794
- if (
795
- !perm ||
796
- typeof perm.actor !== "string" ||
797
- typeof perm.resource !== "string" ||
798
- !Array.isArray(perm.actions)
799
- )
800
- continue;
801
- results.push({
802
- actor: perm.actor,
803
- resource: perm.resource,
804
- actions: perm.actions.map(String),
805
- });
806
- }
807
- } catch {
808
- // skip parse errors
809
- }
810
- }
811
-
812
- return results;
813
- };
1
+ import {
2
+ AutoBeAnalyze,
3
+ AutoBeAnalyzeWriteSectionEvent,
4
+ } from "@autobe/interface";
5
+ import YAML from "yaml";
6
+
7
+ type ConstraintSource = {
8
+ file: AutoBeAnalyze.IFileScenario;
9
+ sectionTitle: string;
10
+ };
11
+
12
+ type ConstraintValue = {
13
+ normalized: string;
14
+ display: string;
15
+ sources: ConstraintSource[];
16
+ };
17
+
18
+ type ConstraintEntry = {
19
+ key: string;
20
+ values: Map<string, ConstraintValue>;
21
+ };
22
+
23
+ const YAML_CODE_BLOCK_REGEX = /```yaml\n([\s\S]*?)```/g;
24
+
25
+ export const buildConstraintConsistencyReport = (props: {
26
+ files: Array<{
27
+ file: AutoBeAnalyze.IFileScenario;
28
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
29
+ }>;
30
+ }): string => {
31
+ const constraints: Map<string, ConstraintEntry> = new Map();
32
+ let totalConstraints: number = 0;
33
+
34
+ for (const { file, sectionEvents } of props.files) {
35
+ for (const sectionsForModule of sectionEvents) {
36
+ for (const sectionEvent of sectionsForModule) {
37
+ for (const section of sectionEvent.sectionSections) {
38
+ const pairs = extractConstraints(section.content);
39
+ for (const { key, value } of pairs) {
40
+ totalConstraints++;
41
+ const normalized = normalizeValue(value);
42
+ if (!constraints.has(key)) {
43
+ constraints.set(key, {
44
+ key,
45
+ values: new Map(),
46
+ });
47
+ }
48
+ const entry = constraints.get(key)!;
49
+ if (!entry.values.has(normalized)) {
50
+ entry.values.set(normalized, {
51
+ normalized,
52
+ display: value.trim(),
53
+ sources: [],
54
+ });
55
+ }
56
+ entry.values.get(normalized)!.sources.push({
57
+ file,
58
+ sectionTitle: section.title,
59
+ });
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ const conflicts: ConstraintEntry[] = [...constraints.values()].filter(
67
+ (entry) => entry.values.size > 1,
68
+ );
69
+
70
+ if (conflicts.length === 0) {
71
+ return [
72
+ "No numeric constraint conflicts detected.",
73
+ `Scanned ${totalConstraints} numeric constraints from YAML spec blocks.`,
74
+ ].join("\n");
75
+ }
76
+
77
+ const lines: string[] = [
78
+ `Detected ${conflicts.length} numeric constraint conflict(s).`,
79
+ `Scanned ${totalConstraints} numeric constraints from YAML spec blocks.`,
80
+ "",
81
+ "Conflicts:",
82
+ ];
83
+
84
+ for (const entry of conflicts) {
85
+ lines.push(`- ${entry.key}:`);
86
+ for (const value of entry.values.values()) {
87
+ const sources = value.sources
88
+ .map((s) => `${s.file.filename} → ${s.sectionTitle}`)
89
+ .slice(0, 6)
90
+ .join("; ");
91
+ lines.push(` - ${value.display} (e.g., ${sources})`);
92
+ }
93
+ }
94
+
95
+ return lines.join("\n");
96
+ };
97
+
98
+ /**
99
+ * Extract numeric constraints from YAML spec blocks.
100
+ *
101
+ * Parses YAML code blocks and extracts Entity.attribute constraints that
102
+ * contain numeric values (e.g., length limits, quantity limits).
103
+ */
104
+ const extractConstraints = (
105
+ content: string,
106
+ ): Array<{ key: string; value: string }> => {
107
+ if (!content) return [];
108
+ const results: Array<{ key: string; value: string }> = [];
109
+ const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
110
+
111
+ for (const match of yamlMatches) {
112
+ const yamlContent = match[1] ?? "";
113
+ try {
114
+ const parsed = YAML.parse(yamlContent);
115
+ if (!parsed || typeof parsed !== "object") continue;
116
+
117
+ // Handle entity attribute YAML blocks
118
+ if (
119
+ typeof parsed.entity === "string" &&
120
+ Array.isArray(parsed.attributes)
121
+ ) {
122
+ for (const attr of parsed.attributes) {
123
+ if (!attr || typeof attr.name !== "string") continue;
124
+ const constraintStr = String(attr.constraints ?? "");
125
+ if (!hasNumeric(constraintStr)) continue;
126
+ results.push({
127
+ key: `${parsed.entity}.${attr.name}`,
128
+ value: constraintStr,
129
+ });
130
+ }
131
+ }
132
+
133
+ // Handle error code YAML blocks (HTTP status codes)
134
+ if (Array.isArray(parsed.errors)) {
135
+ for (const err of parsed.errors) {
136
+ if (!err || typeof err.code !== "string") continue;
137
+ if (typeof err.http === "number") {
138
+ results.push({
139
+ key: `error.${err.code}.http`,
140
+ value: String(err.http),
141
+ });
142
+ }
143
+ }
144
+ }
145
+ } catch {
146
+ // skip parse errors
147
+ }
148
+ }
149
+
150
+ return results;
151
+ };
152
+
153
+ const normalizeValue = (value: string): string =>
154
+ value
155
+ .toLowerCase()
156
+ .replace(/[–—]/g, "-")
157
+ .replace(/`/g, "")
158
+ .replace(/\s+/g, " ")
159
+ .trim();
160
+
161
+ const hasNumeric = (value: string): boolean => /\d/.test(value);
162
+
163
+ // ─── Structured Conflict Detection ───
164
+
165
+ export interface IConstraintConflict {
166
+ key: string;
167
+ values: Array<{
168
+ display: string;
169
+ files: string[];
170
+ }>;
171
+ }
172
+
173
+ /**
174
+ * Detect numeric constraint conflicts across files as structured data.
175
+ *
176
+ * Returns an array of conflicts where the same constraint key has different
177
+ * normalized values across files.
178
+ */
179
+ export const detectConstraintConflicts = (props: {
180
+ files: Array<{
181
+ file: AutoBeAnalyze.IFileScenario;
182
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
183
+ }>;
184
+ }): IConstraintConflict[] => {
185
+ const constraints: Map<string, ConstraintEntry> = new Map();
186
+
187
+ for (const { file, sectionEvents } of props.files) {
188
+ for (const sectionsForModule of sectionEvents) {
189
+ for (const sectionEvent of sectionsForModule) {
190
+ for (const section of sectionEvent.sectionSections) {
191
+ const pairs = extractConstraints(section.content);
192
+ for (const { key, value } of pairs) {
193
+ const normalized = normalizeValue(value);
194
+ if (!constraints.has(key)) {
195
+ constraints.set(key, { key, values: new Map() });
196
+ }
197
+ const entry = constraints.get(key)!;
198
+ if (!entry.values.has(normalized)) {
199
+ entry.values.set(normalized, {
200
+ normalized,
201
+ display: value.trim(),
202
+ sources: [],
203
+ });
204
+ }
205
+ entry.values.get(normalized)!.sources.push({
206
+ file,
207
+ sectionTitle: section.title,
208
+ });
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+
215
+ return [...constraints.values()]
216
+ .filter((entry) => entry.values.size > 1)
217
+ .map((entry) => ({
218
+ key: entry.key,
219
+ values: [...entry.values.values()].map((v) => ({
220
+ display: v.display,
221
+ files: [...new Set(v.sources.map((s) => s.file.filename))],
222
+ })),
223
+ }));
224
+ };
225
+
226
+ /** Build a map from filename → list of conflict feedback strings. */
227
+ export const buildFileConflictMap = (
228
+ conflicts: IConstraintConflict[],
229
+ ): Map<string, string[]> => {
230
+ const map: Map<string, string[]> = new Map();
231
+
232
+ for (const conflict of conflicts) {
233
+ const allFiles = new Set(conflict.values.flatMap((v) => v.files));
234
+ const feedback =
235
+ `${conflict.key} has conflicting values: ` +
236
+ conflict.values
237
+ .map((v) => `"${v.display}" in [${v.files.join(", ")}]`)
238
+ .join(" vs ");
239
+
240
+ for (const filename of allFiles) {
241
+ if (!map.has(filename)) map.set(filename, []);
242
+ map.get(filename)!.push(feedback);
243
+ }
244
+ }
245
+
246
+ return map;
247
+ };
248
+
249
+ // ─── Attribute Duplicate Detection ───
250
+
251
+ export interface IAttributeDuplicate {
252
+ key: string;
253
+ files: string[];
254
+ hasValueConflict: boolean;
255
+ values?: Array<{
256
+ specification: string;
257
+ files: string[];
258
+ }>;
259
+ }
260
+
261
+ /**
262
+ * Detect cross-file attribute duplication from YAML spec blocks.
263
+ *
264
+ * Returns attributes that are defined in YAML blocks across multiple files.
265
+ */
266
+ export const detectAttributeDuplicates = (props: {
267
+ files: Array<{
268
+ file: AutoBeAnalyze.IFileScenario;
269
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
270
+ }>;
271
+ }): IAttributeDuplicate[] => {
272
+ // key → { normalized spec → { display, files } }
273
+ const attributes: Map<
274
+ string,
275
+ Map<string, { display: string; files: Set<string> }>
276
+ > = new Map();
277
+ const allFilesByKey: Map<string, Set<string>> = new Map();
278
+
279
+ for (const { file, sectionEvents } of props.files) {
280
+ for (const sectionsForModule of sectionEvents) {
281
+ for (const sectionEvent of sectionsForModule) {
282
+ for (const section of sectionEvent.sectionSections) {
283
+ const specs = extractAttributeSpecs(section.content);
284
+ for (const { key, specification } of specs) {
285
+ if (!allFilesByKey.has(key)) allFilesByKey.set(key, new Set());
286
+ allFilesByKey.get(key)!.add(file.filename);
287
+
288
+ if (!attributes.has(key)) attributes.set(key, new Map());
289
+ const specMap = attributes.get(key)!;
290
+ const normalized = normalizeValue(specification);
291
+ if (!specMap.has(normalized)) {
292
+ specMap.set(normalized, {
293
+ display: specification.trim(),
294
+ files: new Set(),
295
+ });
296
+ }
297
+ specMap.get(normalized)!.files.add(file.filename);
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ return [...allFilesByKey.entries()]
305
+ .filter(([, files]) => files.size > 1)
306
+ .map(([key, files]) => {
307
+ const specMap = attributes.get(key)!;
308
+ const hasValueConflict = specMap.size > 1;
309
+ return {
310
+ key,
311
+ files: [...files],
312
+ hasValueConflict,
313
+ ...(hasValueConflict
314
+ ? {
315
+ values: [...specMap.values()].map((v) => ({
316
+ specification: v.display,
317
+ files: [...v.files],
318
+ })),
319
+ }
320
+ : {}),
321
+ };
322
+ });
323
+ };
324
+
325
+ export const buildFileAttributeDuplicateMap = (
326
+ duplicates: IAttributeDuplicate[],
327
+ ): Map<string, string[]> => {
328
+ const map: Map<string, string[]> = new Map();
329
+
330
+ for (const dup of duplicates) {
331
+ let feedback: string;
332
+ if (dup.hasValueConflict && dup.values) {
333
+ feedback =
334
+ `${dup.key} has conflicting specifications across files: ` +
335
+ dup.values
336
+ .map((v) => `"${v.specification}" in [${v.files.join(", ")}]`)
337
+ .join(" vs ") +
338
+ `. Align to ONE canonical definition.`;
339
+ } else {
340
+ feedback =
341
+ `${dup.key} is fully specified in multiple files: [${dup.files.join(", ")}]. ` +
342
+ `Only ONE file should contain the full spec.`;
343
+ }
344
+
345
+ for (const filename of dup.files) {
346
+ if (!map.has(filename)) map.set(filename, []);
347
+ map.get(filename)!.push(feedback);
348
+ }
349
+ }
350
+
351
+ return map;
352
+ };
353
+
354
+ // ─── Enum Conflict Detection ───
355
+
356
+ export interface IEnumConflict {
357
+ key: string;
358
+ values: Array<{
359
+ enumSet: string;
360
+ display: string;
361
+ files: string[];
362
+ }>;
363
+ }
364
+
365
+ /**
366
+ * Detect enum value conflicts from YAML spec blocks.
367
+ *
368
+ * Scans YAML attribute blocks for enum-like constraints and detects when
369
+ * different files define different enum value sets for the same attribute.
370
+ */
371
+ export const detectEnumConflicts = (props: {
372
+ files: Array<{
373
+ file: AutoBeAnalyze.IFileScenario;
374
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
375
+ }>;
376
+ }): IEnumConflict[] => {
377
+ type EnumValue = {
378
+ enumSet: string;
379
+ display: string;
380
+ files: Set<string>;
381
+ };
382
+ const enums: Map<string, Map<string, EnumValue>> = new Map();
383
+
384
+ for (const { file, sectionEvents } of props.files) {
385
+ for (const sectionsForModule of sectionEvents) {
386
+ for (const sectionEvent of sectionsForModule) {
387
+ for (const section of sectionEvent.sectionSections) {
388
+ const specs = extractEnumSpecs(section.content);
389
+ for (const { key, enumSet, display } of specs) {
390
+ if (!enums.has(key)) enums.set(key, new Map());
391
+ const entry = enums.get(key)!;
392
+ if (!entry.has(enumSet)) {
393
+ entry.set(enumSet, { enumSet, display, files: new Set() });
394
+ }
395
+ entry.get(enumSet)!.files.add(file.filename);
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
+
402
+ return [...enums.entries()]
403
+ .filter(([, values]) => values.size > 1)
404
+ .map(([key, values]) => ({
405
+ key,
406
+ values: [...values.values()].map((v) => ({
407
+ enumSet: v.enumSet,
408
+ display: v.display,
409
+ files: [...v.files],
410
+ })),
411
+ }));
412
+ };
413
+
414
+ export const buildFileEnumConflictMap = (
415
+ conflicts: IEnumConflict[],
416
+ ): Map<string, string[]> => {
417
+ const map: Map<string, string[]> = new Map();
418
+
419
+ for (const conflict of conflicts) {
420
+ const allFiles = new Set(conflict.values.flatMap((v) => v.files));
421
+ const feedback =
422
+ `${conflict.key} has conflicting enum values: ` +
423
+ conflict.values
424
+ .map((v) => `enum(${v.enumSet}) in [${v.files.join(", ")}]`)
425
+ .join(" vs ");
426
+
427
+ for (const filename of allFiles) {
428
+ if (!map.has(filename)) map.set(filename, []);
429
+ map.get(filename)!.push(feedback);
430
+ }
431
+ }
432
+
433
+ return map;
434
+ };
435
+
436
+ // ─── Permission Rule Conflict Detection ───
437
+
438
+ export interface IPermissionConflict {
439
+ actorOperation: string;
440
+ rules: Array<{
441
+ condition: string;
442
+ files: string[];
443
+ }>;
444
+ }
445
+
446
+ /**
447
+ * Detect permission rule conflicts from YAML spec blocks.
448
+ *
449
+ * A conflict occurs when one YAML block allows an action but another doesn't
450
+ * include it for the same actor+resource.
451
+ */
452
+ export const detectPermissionConflicts = (props: {
453
+ files: Array<{
454
+ file: AutoBeAnalyze.IFileScenario;
455
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
456
+ }>;
457
+ }): IPermissionConflict[] => {
458
+ // actor:resource → action → Set<filename>
459
+ const ruleMap: Map<string, Map<string, Set<string>>> = new Map();
460
+
461
+ for (const { file, sectionEvents } of props.files) {
462
+ for (const sectionsForModule of sectionEvents) {
463
+ for (const sectionEvent of sectionsForModule) {
464
+ for (const section of sectionEvent.sectionSections) {
465
+ const rules = extractPermissionRulesFromYaml(section.content);
466
+ for (const { actor, resource, actions } of rules) {
467
+ const key = `${actor.toLowerCase()}:${resource}`;
468
+ if (!ruleMap.has(key)) ruleMap.set(key, new Map());
469
+ const actionMap = ruleMap.get(key)!;
470
+ for (const action of actions) {
471
+ const normAction = action.toLowerCase();
472
+ if (!actionMap.has(normAction))
473
+ actionMap.set(normAction, new Set());
474
+ actionMap.get(normAction)!.add(file.filename);
475
+ }
476
+ }
477
+ }
478
+ }
479
+ }
480
+ }
481
+
482
+ // Permission conflicts are rare in YAML-based approach since
483
+ // 01-actors-and-auth is the canonical source. Return empty for now.
484
+ return [];
485
+ };
486
+
487
+ export const buildFilePermissionConflictMap = (
488
+ conflicts: IPermissionConflict[],
489
+ ): Map<string, string[]> => {
490
+ const map: Map<string, string[]> = new Map();
491
+
492
+ for (const conflict of conflicts) {
493
+ const allFiles = new Set(conflict.rules.flatMap((r) => r.files));
494
+ const feedback =
495
+ `Permission conflict for "${conflict.actorOperation}": ` +
496
+ conflict.rules
497
+ .map((r) => `"${r.condition}" in [${r.files.join(", ")}]`)
498
+ .join(" vs ");
499
+
500
+ for (const filename of allFiles) {
501
+ if (!map.has(filename)) map.set(filename, []);
502
+ map.get(filename)!.push(feedback);
503
+ }
504
+ }
505
+
506
+ return map;
507
+ };
508
+
509
+ // ─── State Field Conflict Detection ───
510
+
511
+ export interface IStateFieldConflict {
512
+ entity: string;
513
+ conflictType: string;
514
+ fields: Array<{
515
+ fieldName: string;
516
+ specification: string;
517
+ files: string[];
518
+ }>;
519
+ }
520
+
521
+ /**
522
+ * Detect state field conflicts from YAML spec blocks.
523
+ *
524
+ * Known contradiction patterns:
525
+ *
526
+ * 1. Same entity has both `deletedAt` (datetime) and `isDeleted` (boolean)
527
+ * 2. Same entity has `status` (enum) and semantically equivalent `is*` booleans
528
+ */
529
+ export const detectStateFieldConflicts = (props: {
530
+ files: Array<{
531
+ file: AutoBeAnalyze.IFileScenario;
532
+ sectionEvents: AutoBeAnalyzeWriteSectionEvent[][];
533
+ }>;
534
+ }): IStateFieldConflict[] => {
535
+ // entity → { fieldName → { specification, files } }
536
+ const entityFields: Map<
537
+ string,
538
+ Map<string, { specification: string; files: Set<string> }>
539
+ > = new Map();
540
+
541
+ for (const { file, sectionEvents } of props.files) {
542
+ for (const sectionsForModule of sectionEvents) {
543
+ for (const sectionEvent of sectionsForModule) {
544
+ for (const section of sectionEvent.sectionSections) {
545
+ const specs = extractAttributeSpecs(section.content);
546
+ for (const { key, specification } of specs) {
547
+ const dotIndex = key.indexOf(".");
548
+ if (dotIndex < 0) continue;
549
+ const entity = key.slice(0, dotIndex);
550
+ const field = key.slice(dotIndex + 1).toLowerCase();
551
+
552
+ if (!entityFields.has(entity)) entityFields.set(entity, new Map());
553
+ const fields = entityFields.get(entity)!;
554
+ if (!fields.has(field))
555
+ fields.set(field, { specification, files: new Set() });
556
+ fields.get(field)!.files.add(file.filename);
557
+ }
558
+ }
559
+ }
560
+ }
561
+ }
562
+
563
+ const conflicts: IStateFieldConflict[] = [];
564
+
565
+ for (const [entity, fields] of entityFields) {
566
+ const fieldNames = [...fields.keys()];
567
+
568
+ // Pattern 1: deletedAt + isDeleted on same entity
569
+ const hasDeletedAt = fieldNames.some(
570
+ (f) => f === "deletedat" || f === "deleted_at",
571
+ );
572
+ const hasIsDeleted = fieldNames.some(
573
+ (f) => f === "isdeleted" || f === "is_deleted",
574
+ );
575
+
576
+ if (hasDeletedAt && hasIsDeleted) {
577
+ const deletedAtField =
578
+ fields.get("deletedat") ?? fields.get("deleted_at");
579
+ const isDeletedField =
580
+ fields.get("isdeleted") ?? fields.get("is_deleted");
581
+
582
+ if (deletedAtField && isDeletedField) {
583
+ conflicts.push({
584
+ entity,
585
+ conflictType: "deletedAt vs isDeleted",
586
+ fields: [
587
+ {
588
+ fieldName: "deletedAt",
589
+ specification: deletedAtField.specification,
590
+ files: [...deletedAtField.files],
591
+ },
592
+ {
593
+ fieldName: "isDeleted",
594
+ specification: isDeletedField.specification,
595
+ files: [...isDeletedField.files],
596
+ },
597
+ ],
598
+ });
599
+ }
600
+ }
601
+
602
+ // Pattern 2: status (enum) + is* booleans
603
+ const statusField = fields.get("status");
604
+ if (statusField && /enum/i.test(statusField.specification)) {
605
+ const isBooleans = fieldNames.filter(
606
+ (f) =>
607
+ f.startsWith("is") && /boolean/i.test(fields.get(f)!.specification),
608
+ );
609
+
610
+ for (const boolField of isBooleans) {
611
+ const concept = boolField.slice(2).toLowerCase();
612
+ if (statusField.specification.toLowerCase().includes(concept)) {
613
+ const boolEntry = fields.get(boolField)!;
614
+ conflicts.push({
615
+ entity,
616
+ conflictType: `status enum includes "${concept}" but separate is${concept.charAt(0).toUpperCase() + concept.slice(1)} boolean also exists`,
617
+ fields: [
618
+ {
619
+ fieldName: "status",
620
+ specification: statusField.specification,
621
+ files: [...statusField.files],
622
+ },
623
+ {
624
+ fieldName: boolField,
625
+ specification: boolEntry.specification,
626
+ files: [...boolEntry.files],
627
+ },
628
+ ],
629
+ });
630
+ }
631
+ }
632
+ }
633
+ }
634
+
635
+ return conflicts;
636
+ };
637
+
638
+ export const buildFileStateFieldConflictMap = (
639
+ conflicts: IStateFieldConflict[],
640
+ ): Map<string, string[]> => {
641
+ const map: Map<string, string[]> = new Map();
642
+
643
+ for (const conflict of conflicts) {
644
+ const allFiles = new Set(conflict.fields.flatMap((f) => f.files));
645
+ const feedback =
646
+ `State field conflict for "${conflict.entity}": ${conflict.conflictType}. ` +
647
+ conflict.fields
648
+ .map(
649
+ (f) =>
650
+ `"${f.fieldName}: ${f.specification}" in [${f.files.join(", ")}]`,
651
+ )
652
+ .join(" vs ") +
653
+ `. Use ONE canonical approach.`;
654
+
655
+ for (const filename of allFiles) {
656
+ if (!map.has(filename)) map.set(filename, []);
657
+ map.get(filename)!.push(feedback);
658
+ }
659
+ }
660
+
661
+ return map;
662
+ };
663
+
664
+ // ─── YAML-based Attribute Specs Extraction (shared) ───
665
+
666
+ const ENUM_PATTERN = /enum\s*[\(\[\{]([^)\]\}]+)[\)\]\}]/i;
667
+
668
+ /**
669
+ * Extract attribute specs from YAML code blocks.
670
+ *
671
+ * Parses YAML blocks with `entity` + `attributes` structure and returns
672
+ * Entity.attribute → constraints pairs.
673
+ */
674
+ const extractAttributeSpecs = (
675
+ content: string,
676
+ ): Array<{ key: string; specification: string }> => {
677
+ if (!content) return [];
678
+ const results: Array<{ key: string; specification: string }> = [];
679
+ const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
680
+
681
+ for (const match of yamlMatches) {
682
+ const yamlContent = match[1] ?? "";
683
+ try {
684
+ const parsed = YAML.parse(yamlContent);
685
+ if (
686
+ !parsed ||
687
+ typeof parsed !== "object" ||
688
+ typeof parsed.entity !== "string" ||
689
+ !Array.isArray(parsed.attributes)
690
+ )
691
+ continue;
692
+
693
+ for (const attr of parsed.attributes) {
694
+ if (!attr || typeof attr.name !== "string") continue;
695
+ const spec = [
696
+ attr.type ? String(attr.type) : "",
697
+ attr.constraints ? String(attr.constraints) : "",
698
+ ]
699
+ .filter(Boolean)
700
+ .join(", ");
701
+ if (!spec) continue;
702
+ results.push({
703
+ key: `${parsed.entity}.${attr.name}`,
704
+ specification: spec,
705
+ });
706
+ }
707
+ } catch {
708
+ // skip parse errors
709
+ }
710
+ }
711
+
712
+ return results;
713
+ };
714
+
715
+ /** Extract enum specs from YAML attribute blocks. */
716
+ const extractEnumSpecs = (
717
+ content: string,
718
+ ): Array<{ key: string; enumSet: string; display: string }> => {
719
+ if (!content) return [];
720
+ const results: Array<{ key: string; enumSet: string; display: string }> = [];
721
+ const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
722
+
723
+ for (const match of yamlMatches) {
724
+ const yamlContent = match[1] ?? "";
725
+ try {
726
+ const parsed = YAML.parse(yamlContent);
727
+ if (
728
+ !parsed ||
729
+ typeof parsed !== "object" ||
730
+ typeof parsed.entity !== "string" ||
731
+ !Array.isArray(parsed.attributes)
732
+ )
733
+ continue;
734
+
735
+ for (const attr of parsed.attributes) {
736
+ if (!attr || typeof attr.name !== "string") continue;
737
+ const typeStr = String(attr.type ?? "");
738
+ const constraintStr = String(attr.constraints ?? "");
739
+ const combined = `${typeStr} ${constraintStr}`;
740
+
741
+ const enumMatch = combined.match(ENUM_PATTERN);
742
+ if (!enumMatch) continue;
743
+
744
+ const rawEnumValues = enumMatch[1]!;
745
+ const enumSet = [
746
+ ...new Set(
747
+ rawEnumValues
748
+ .split(/[|,]/)
749
+ .map((v) => v.trim().toLowerCase())
750
+ .filter((v) => v.length > 0),
751
+ ),
752
+ ]
753
+ .sort()
754
+ .join("|");
755
+
756
+ results.push({
757
+ key: `${parsed.entity}.${attr.name}`,
758
+ enumSet,
759
+ display: combined.trim(),
760
+ });
761
+ }
762
+ } catch {
763
+ // skip parse errors
764
+ }
765
+ }
766
+
767
+ return results;
768
+ };
769
+
770
+ /** Extract permission rules from YAML spec blocks. */
771
+ const extractPermissionRulesFromYaml = (
772
+ content: string,
773
+ ): Array<{ actor: string; resource: string; actions: string[] }> => {
774
+ if (!content) return [];
775
+ const results: Array<{
776
+ actor: string;
777
+ resource: string;
778
+ actions: string[];
779
+ }> = [];
780
+ const yamlMatches = content.matchAll(YAML_CODE_BLOCK_REGEX);
781
+
782
+ for (const match of yamlMatches) {
783
+ const yamlContent = match[1] ?? "";
784
+ try {
785
+ const parsed = YAML.parse(yamlContent);
786
+ if (
787
+ !parsed ||
788
+ typeof parsed !== "object" ||
789
+ !Array.isArray(parsed.permissions)
790
+ )
791
+ continue;
792
+
793
+ for (const perm of parsed.permissions) {
794
+ if (
795
+ !perm ||
796
+ typeof perm.actor !== "string" ||
797
+ typeof perm.resource !== "string" ||
798
+ !Array.isArray(perm.actions)
799
+ )
800
+ continue;
801
+ results.push({
802
+ actor: perm.actor,
803
+ resource: perm.resource,
804
+ actions: perm.actions.map(String),
805
+ });
806
+ }
807
+ } catch {
808
+ // skip parse errors
809
+ }
810
+ }
811
+
812
+ return results;
813
+ };