@archpilotlabs/archpilot 0.2.2 → 0.2.4

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 (298) hide show
  1. package/CHANGELOG.md +538 -0
  2. package/README.md +1 -0
  3. package/dist/archpilot-cli.js +850 -159
  4. package/dist/cli/src/archpilot-cli.js +5523 -0
  5. package/dist/cli/src/archpilot-cli.js.map +1 -0
  6. package/dist/core/src/adr/adrLoader.js +97 -0
  7. package/dist/core/src/adr/adrLoader.js.map +1 -0
  8. package/dist/core/src/adr/adrParser.js +77 -0
  9. package/dist/core/src/adr/adrParser.js.map +1 -0
  10. package/dist/core/src/adr/adrTemplate.js +45 -0
  11. package/dist/core/src/adr/adrTemplate.js.map +1 -0
  12. package/dist/core/src/adr/adrTypes.js +3 -0
  13. package/dist/core/src/adr/adrTypes.js.map +1 -0
  14. package/dist/core/src/adr/adrValidation.js +160 -0
  15. package/dist/core/src/adr/adrValidation.js.map +1 -0
  16. package/dist/core/src/adr/index.js +9 -0
  17. package/dist/core/src/adr/index.js.map +1 -0
  18. package/dist/core/src/adrManagement.js +174 -0
  19. package/dist/core/src/adrManagement.js.map +1 -0
  20. package/dist/core/src/adrRequirementStatus.js +62 -0
  21. package/dist/core/src/adrRequirementStatus.js.map +1 -0
  22. package/dist/core/src/adrScaffoldGeneration.js +325 -0
  23. package/dist/core/src/adrScaffoldGeneration.js.map +1 -0
  24. package/dist/core/src/apiDesignAnalysis.js +869 -0
  25. package/dist/core/src/apiDesignAnalysis.js.map +1 -0
  26. package/dist/core/src/applicationLayeringAnalysis.js +920 -0
  27. package/dist/core/src/applicationLayeringAnalysis.js.map +1 -0
  28. package/dist/core/src/applyRulePack.js +117 -0
  29. package/dist/core/src/applyRulePack.js.map +1 -0
  30. package/dist/core/src/architectureBaseline.js +271 -0
  31. package/dist/core/src/architectureBaseline.js.map +1 -0
  32. package/dist/core/src/architectureComponentDiscoveryDefaults.js +139 -0
  33. package/dist/core/src/architectureComponentDiscoveryDefaults.js.map +1 -0
  34. package/dist/core/src/architectureDependencyContext.js +316 -0
  35. package/dist/core/src/architectureDependencyContext.js.map +1 -0
  36. package/dist/core/src/architectureDriftDetection.js +96 -0
  37. package/dist/core/src/architectureDriftDetection.js.map +1 -0
  38. package/dist/core/src/architectureDriftTimeline.js +221 -0
  39. package/dist/core/src/architectureDriftTimeline.js.map +1 -0
  40. package/dist/core/src/architectureGovernanceBaseline.js +469 -0
  41. package/dist/core/src/architectureGovernanceBaseline.js.map +1 -0
  42. package/dist/core/src/architectureHealthHistory.js +208 -0
  43. package/dist/core/src/architectureHealthHistory.js.map +1 -0
  44. package/dist/core/src/architectureHealthScore.js +657 -0
  45. package/dist/core/src/architectureHealthScore.js.map +1 -0
  46. package/dist/core/src/architectureInit.js +826 -0
  47. package/dist/core/src/architectureInit.js.map +1 -0
  48. package/dist/core/src/architectureMap.js +727 -0
  49. package/dist/core/src/architectureMap.js.map +1 -0
  50. package/dist/core/src/architectureMigrationPreview.js +467 -0
  51. package/dist/core/src/architectureMigrationPreview.js.map +1 -0
  52. package/dist/core/src/architectureModelRefresh.js +209 -0
  53. package/dist/core/src/architectureModelRefresh.js.map +1 -0
  54. package/dist/core/src/architectureReportWorkflow.js +139 -0
  55. package/dist/core/src/architectureReportWorkflow.js.map +1 -0
  56. package/dist/core/src/architectureValidation.js +3879 -0
  57. package/dist/core/src/architectureValidation.js.map +1 -0
  58. package/dist/core/src/architectureWorkspaceModel.js +166 -0
  59. package/dist/core/src/architectureWorkspaceModel.js.map +1 -0
  60. package/dist/core/src/authorizationTenantAnalysis.js +652 -0
  61. package/dist/core/src/authorizationTenantAnalysis.js.map +1 -0
  62. package/dist/core/src/bootstrapArchitectureConfig.js +150 -0
  63. package/dist/core/src/bootstrapArchitectureConfig.js.map +1 -0
  64. package/dist/core/src/changeRisk/changeRiskAssessment.js +251 -0
  65. package/dist/core/src/changeRisk/changeRiskAssessment.js.map +1 -0
  66. package/dist/core/src/changeRisk/changeRiskTypes.js +3 -0
  67. package/dist/core/src/changeRisk/changeRiskTypes.js.map +1 -0
  68. package/dist/core/src/changeRisk/index.js +6 -0
  69. package/dist/core/src/changeRisk/index.js.map +1 -0
  70. package/dist/core/src/ci/githubInlineAnnotations.js +245 -0
  71. package/dist/core/src/ci/githubInlineAnnotations.js.map +1 -0
  72. package/dist/core/src/ci/githubPrCommentAdapter.js +232 -0
  73. package/dist/core/src/ci/githubPrCommentAdapter.js.map +1 -0
  74. package/dist/core/src/ciWorkflowTemplates.js +1042 -0
  75. package/dist/core/src/ciWorkflowTemplates.js.map +1 -0
  76. package/dist/core/src/compliance/complianceExportBuilder.js +122 -0
  77. package/dist/core/src/compliance/complianceExportBuilder.js.map +1 -0
  78. package/dist/core/src/compliance/complianceExportTypes.js +3 -0
  79. package/dist/core/src/compliance/complianceExportTypes.js.map +1 -0
  80. package/dist/core/src/compliance/complianceExportWriter.js +48 -0
  81. package/dist/core/src/compliance/complianceExportWriter.js.map +1 -0
  82. package/dist/core/src/compliance/complianceRulePackResolver.js +62 -0
  83. package/dist/core/src/compliance/complianceRulePackResolver.js.map +1 -0
  84. package/dist/core/src/config/index.js +17 -0
  85. package/dist/core/src/config/index.js.map +1 -0
  86. package/dist/core/src/config/projectConfig.js +224 -0
  87. package/dist/core/src/config/projectConfig.js.map +1 -0
  88. package/dist/core/src/config/projectIdentity.js +160 -0
  89. package/dist/core/src/config/projectIdentity.js.map +1 -0
  90. package/dist/core/src/dataQueryRiskDetection.js +1203 -0
  91. package/dist/core/src/dataQueryRiskDetection.js.map +1 -0
  92. package/dist/core/src/dependencyValidation.js +2557 -0
  93. package/dist/core/src/dependencyValidation.js.map +1 -0
  94. package/dist/core/src/discoverAdrs.js +15 -0
  95. package/dist/core/src/discoverAdrs.js.map +1 -0
  96. package/dist/core/src/drift/driftComparator.js +49 -0
  97. package/dist/core/src/drift/driftComparator.js.map +1 -0
  98. package/dist/core/src/drift/driftSnapshotLoader.js +136 -0
  99. package/dist/core/src/drift/driftSnapshotLoader.js.map +1 -0
  100. package/dist/core/src/drift/driftSnapshotTypes.js +3 -0
  101. package/dist/core/src/drift/driftSnapshotTypes.js.map +1 -0
  102. package/dist/core/src/drift/driftSnapshotWriter.js +48 -0
  103. package/dist/core/src/drift/driftSnapshotWriter.js.map +1 -0
  104. package/dist/core/src/drift/index.js +6 -0
  105. package/dist/core/src/drift/index.js.map +1 -0
  106. package/dist/core/src/eventArchitectureAnalysis.js +925 -0
  107. package/dist/core/src/eventArchitectureAnalysis.js.map +1 -0
  108. package/dist/core/src/findingTargetResolution.js +117 -0
  109. package/dist/core/src/findingTargetResolution.js.map +1 -0
  110. package/dist/core/src/generateArchitectureDiagrams.js +57 -0
  111. package/dist/core/src/generateArchitectureDiagrams.js.map +1 -0
  112. package/dist/core/src/generateImpactAnalysis.js +366 -0
  113. package/dist/core/src/generateImpactAnalysis.js.map +1 -0
  114. package/dist/core/src/generateOnboardingDocs.js +262 -0
  115. package/dist/core/src/generateOnboardingDocs.js.map +1 -0
  116. package/dist/core/src/governance/cloudConnection.js +203 -0
  117. package/dist/core/src/governance/cloudConnection.js.map +1 -0
  118. package/dist/core/src/governance/governanceContracts.js +129 -0
  119. package/dist/core/src/governance/governanceContracts.js.map +1 -0
  120. package/dist/core/src/governance/governanceGitMetadata.js +78 -0
  121. package/dist/core/src/governance/governanceGitMetadata.js.map +1 -0
  122. package/dist/core/src/governance/governanceUploadClient.js +119 -0
  123. package/dist/core/src/governance/governanceUploadClient.js.map +1 -0
  124. package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js +155 -0
  125. package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js.map +1 -0
  126. package/dist/core/src/governance/governanceUploadPayload.js +439 -0
  127. package/dist/core/src/governance/governanceUploadPayload.js.map +1 -0
  128. package/dist/core/src/governance/runGovernanceUpload.js +103 -0
  129. package/dist/core/src/governance/runGovernanceUpload.js.map +1 -0
  130. package/dist/core/src/impactAnalysisEngine.js +376 -0
  131. package/dist/core/src/impactAnalysisEngine.js.map +1 -0
  132. package/dist/core/src/initializationState.js +99 -0
  133. package/dist/core/src/initializationState.js.map +1 -0
  134. package/dist/core/src/managedArtifacts.js +151 -0
  135. package/dist/core/src/managedArtifacts.js.map +1 -0
  136. package/dist/core/src/moduleContractValidation.js +266 -0
  137. package/dist/core/src/moduleContractValidation.js.map +1 -0
  138. package/dist/core/src/moduleContractsGenerator.js +337 -0
  139. package/dist/core/src/moduleContractsGenerator.js.map +1 -0
  140. package/dist/core/src/moduleDiscovery.js +416 -0
  141. package/dist/core/src/moduleDiscovery.js.map +1 -0
  142. package/dist/core/src/moduleScope.js +426 -0
  143. package/dist/core/src/moduleScope.js.map +1 -0
  144. package/dist/core/src/onboardingGuidance.js +74 -0
  145. package/dist/core/src/onboardingGuidance.js.map +1 -0
  146. package/dist/core/src/operationalLogging.js +7 -0
  147. package/dist/core/src/operationalLogging.js.map +1 -0
  148. package/dist/core/src/packageVersion.js +52 -0
  149. package/dist/core/src/packageVersion.js.map +1 -0
  150. package/dist/core/src/policy/effectivePolicyResolver.js +91 -0
  151. package/dist/core/src/policy/effectivePolicyResolver.js.map +1 -0
  152. package/dist/core/src/policy/exceptionLoader.js +285 -0
  153. package/dist/core/src/policy/exceptionLoader.js.map +1 -0
  154. package/dist/core/src/policy/remotePolicyLoader.js +227 -0
  155. package/dist/core/src/policy/remotePolicyLoader.js.map +1 -0
  156. package/dist/core/src/policy/remotePolicyTypes.js +3 -0
  157. package/dist/core/src/policy/remotePolicyTypes.js.map +1 -0
  158. package/dist/core/src/policy/riskPolicyConfig.js +206 -0
  159. package/dist/core/src/policy/riskPolicyConfig.js.map +1 -0
  160. package/dist/core/src/policy/riskPolicyEnforcement.js +203 -0
  161. package/dist/core/src/policy/riskPolicyEnforcement.js.map +1 -0
  162. package/dist/core/src/policy/riskPolicyExitCode.js +16 -0
  163. package/dist/core/src/policy/riskPolicyExitCode.js.map +1 -0
  164. package/dist/core/src/policy/riskPolicyInitializer.js +90 -0
  165. package/dist/core/src/policy/riskPolicyInitializer.js.map +1 -0
  166. package/dist/core/src/quickFix/quickFixEngine.js +132 -0
  167. package/dist/core/src/quickFix/quickFixEngine.js.map +1 -0
  168. package/dist/core/src/quickFix/quickFixMessaging.js +15 -0
  169. package/dist/core/src/quickFix/quickFixMessaging.js.map +1 -0
  170. package/dist/core/src/quickFix/quickFixProviders.js +87 -0
  171. package/dist/core/src/quickFix/quickFixProviders.js.map +1 -0
  172. package/dist/core/src/quickFix/quickFixTypes.js +3 -0
  173. package/dist/core/src/quickFix/quickFixTypes.js.map +1 -0
  174. package/dist/core/src/remediation/fileHelpers.js +86 -0
  175. package/dist/core/src/remediation/fileHelpers.js.map +1 -0
  176. package/dist/core/src/remediation/fixRegistry.js +645 -0
  177. package/dist/core/src/remediation/fixRegistry.js.map +1 -0
  178. package/dist/core/src/remediation/index.js +8 -0
  179. package/dist/core/src/remediation/index.js.map +1 -0
  180. package/dist/core/src/remediation/remediationEngine.js +207 -0
  181. package/dist/core/src/remediation/remediationEngine.js.map +1 -0
  182. package/dist/core/src/reporting/adrReporter.js +59 -0
  183. package/dist/core/src/reporting/adrReporter.js.map +1 -0
  184. package/dist/core/src/reporting/architectureBaselineReporter.js +64 -0
  185. package/dist/core/src/reporting/architectureBaselineReporter.js.map +1 -0
  186. package/dist/core/src/reporting/architectureDiagramReporter.js +148 -0
  187. package/dist/core/src/reporting/architectureDiagramReporter.js.map +1 -0
  188. package/dist/core/src/reporting/architectureDriftTimelineReporter.js +44 -0
  189. package/dist/core/src/reporting/architectureDriftTimelineReporter.js.map +1 -0
  190. package/dist/core/src/reporting/architectureHealthHistoryReporter.js +51 -0
  191. package/dist/core/src/reporting/architectureHealthHistoryReporter.js.map +1 -0
  192. package/dist/core/src/reporting/architectureMapReporter.js +228 -0
  193. package/dist/core/src/reporting/architectureMapReporter.js.map +1 -0
  194. package/dist/core/src/reporting/architecturePrCommentReporter.js +324 -0
  195. package/dist/core/src/reporting/architecturePrCommentReporter.js.map +1 -0
  196. package/dist/core/src/reporting/architecturePrReviewReporter.js +389 -0
  197. package/dist/core/src/reporting/architecturePrReviewReporter.js.map +1 -0
  198. package/dist/core/src/reporting/architectureReportArtifacts.js +166 -0
  199. package/dist/core/src/reporting/architectureReportArtifacts.js.map +1 -0
  200. package/dist/core/src/reporting/architectureReviewReportGenerator.js +382 -0
  201. package/dist/core/src/reporting/architectureReviewReportGenerator.js.map +1 -0
  202. package/dist/core/src/reporting/architectureReviewReporter.js +1633 -0
  203. package/dist/core/src/reporting/architectureReviewReporter.js.map +1 -0
  204. package/dist/core/src/reporting/architectureRiskAssessment.js +101 -0
  205. package/dist/core/src/reporting/architectureRiskAssessment.js.map +1 -0
  206. package/dist/core/src/reporting/architectureScoreBadge.js +177 -0
  207. package/dist/core/src/reporting/architectureScoreBadge.js.map +1 -0
  208. package/dist/core/src/reporting/architectureSupplementalReporters.js +124 -0
  209. package/dist/core/src/reporting/architectureSupplementalReporters.js.map +1 -0
  210. package/dist/core/src/reporting/changeRiskAssessment.js +6 -0
  211. package/dist/core/src/reporting/changeRiskAssessment.js.map +1 -0
  212. package/dist/core/src/reporting/changeRiskTypes.js +3 -0
  213. package/dist/core/src/reporting/changeRiskTypes.js.map +1 -0
  214. package/dist/core/src/reporting/impactAnalysisReporter.js +111 -0
  215. package/dist/core/src/reporting/impactAnalysisReporter.js.map +1 -0
  216. package/dist/core/src/reporting/onboardingDocsReporter.js +113 -0
  217. package/dist/core/src/reporting/onboardingDocsReporter.js.map +1 -0
  218. package/dist/core/src/reporting/rulePackReporter.js +61 -0
  219. package/dist/core/src/reporting/rulePackReporter.js.map +1 -0
  220. package/dist/core/src/reporting/safetyControlsDetection.js +343 -0
  221. package/dist/core/src/reporting/safetyControlsDetection.js.map +1 -0
  222. package/dist/core/src/resolveRuleAdrs.js +31 -0
  223. package/dist/core/src/resolveRuleAdrs.js.map +1 -0
  224. package/dist/core/src/reviewGenerationWorkflow.js +220 -0
  225. package/dist/core/src/reviewGenerationWorkflow.js.map +1 -0
  226. package/dist/core/src/rulePacks/index.js +17 -0
  227. package/dist/core/src/rulePacks/index.js.map +1 -0
  228. package/dist/core/src/rulePacks/layeredMonolithRulePack.js +45 -0
  229. package/dist/core/src/rulePacks/layeredMonolithRulePack.js.map +1 -0
  230. package/dist/core/src/rulePacks/modularMonolithRulePack.js +41 -0
  231. package/dist/core/src/rulePacks/modularMonolithRulePack.js.map +1 -0
  232. package/dist/core/src/rulePacks/types.js +3 -0
  233. package/dist/core/src/rulePacks/types.js.map +1 -0
  234. package/dist/core/src/setupNextSteps.js +939 -0
  235. package/dist/core/src/setupNextSteps.js.map +1 -0
  236. package/dist/core/src/setupRefresh.js +152 -0
  237. package/dist/core/src/setupRefresh.js.map +1 -0
  238. package/dist/core/src/smartInit/apiDbHintDetection.js +836 -0
  239. package/dist/core/src/smartInit/apiDbHintDetection.js.map +1 -0
  240. package/dist/core/src/smartInit/architectureProposalBuilder.js +1215 -0
  241. package/dist/core/src/smartInit/architectureProposalBuilder.js.map +1 -0
  242. package/dist/core/src/smartInit/architectureStyleDetection.js +472 -0
  243. package/dist/core/src/smartInit/architectureStyleDetection.js.map +1 -0
  244. package/dist/core/src/smartInit/archpilotIgnore.js +139 -0
  245. package/dist/core/src/smartInit/archpilotIgnore.js.map +1 -0
  246. package/dist/core/src/smartInit/componentDetection.js +1084 -0
  247. package/dist/core/src/smartInit/componentDetection.js.map +1 -0
  248. package/dist/core/src/smartInit/implementationProfileResolution.js +53 -0
  249. package/dist/core/src/smartInit/implementationProfileResolution.js.map +1 -0
  250. package/dist/core/src/smartInit/index.js +31 -0
  251. package/dist/core/src/smartInit/index.js.map +1 -0
  252. package/dist/core/src/smartInit/moduleDetection.js +982 -0
  253. package/dist/core/src/smartInit/moduleDetection.js.map +1 -0
  254. package/dist/core/src/smartInit/projectKindDetection.js +437 -0
  255. package/dist/core/src/smartInit/projectKindDetection.js.map +1 -0
  256. package/dist/core/src/smartInit/repoTopologyDetection.js +470 -0
  257. package/dist/core/src/smartInit/repoTopologyDetection.js.map +1 -0
  258. package/dist/core/src/smartInit/runContext.js +112 -0
  259. package/dist/core/src/smartInit/runContext.js.map +1 -0
  260. package/dist/core/src/smartInit/smartInitEngine.js +94 -0
  261. package/dist/core/src/smartInit/smartInitEngine.js.map +1 -0
  262. package/dist/core/src/smartInit/stackDetection.js +503 -0
  263. package/dist/core/src/smartInit/stackDetection.js.map +1 -0
  264. package/dist/core/src/smartInit/toolingHintDetection.js +345 -0
  265. package/dist/core/src/smartInit/toolingHintDetection.js.map +1 -0
  266. package/dist/core/src/sourceScopeClassification.js +83 -0
  267. package/dist/core/src/sourceScopeClassification.js.map +1 -0
  268. package/dist/core/src/stackAdapters.js +2475 -0
  269. package/dist/core/src/stackAdapters.js.map +1 -0
  270. package/dist/core/src/stackMetadata.js +157 -0
  271. package/dist/core/src/stackMetadata.js.map +1 -0
  272. package/dist/core/src/suppressions/index.js +3 -0
  273. package/dist/core/src/suppressions/index.js.map +1 -0
  274. package/dist/core/src/suppressions/suppressionReporter.js +38 -0
  275. package/dist/core/src/suppressions/suppressionReporter.js.map +1 -0
  276. package/dist/core/src/suppressions/suppressionTypes.js +3 -0
  277. package/dist/core/src/suppressions/suppressionTypes.js.map +1 -0
  278. package/dist/core/src/suppressions/suppressionValidator.js +119 -0
  279. package/dist/core/src/suppressions/suppressionValidator.js.map +1 -0
  280. package/dist/core/src/transactionDomainAnalysis.js +1416 -0
  281. package/dist/core/src/transactionDomainAnalysis.js.map +1 -0
  282. package/dist/core/src/validation/changedFilesResolver.js +165 -0
  283. package/dist/core/src/validation/changedFilesResolver.js.map +1 -0
  284. package/dist/core/src/validationProfiling.js +33 -0
  285. package/dist/core/src/validationProfiling.js.map +1 -0
  286. package/dist/core/src/validationRuleExplanations.js +69 -0
  287. package/dist/core/src/validationRuleExplanations.js.map +1 -0
  288. package/dist/core/src/validationSourceInventory.js +200 -0
  289. package/dist/core/src/validationSourceInventory.js.map +1 -0
  290. package/dist/core/src/validationSuppressions.js +231 -0
  291. package/dist/core/src/validationSuppressions.js.map +1 -0
  292. package/dist/core/src/validationTypeScriptAstCache.js +82 -0
  293. package/dist/core/src/validationTypeScriptAstCache.js.map +1 -0
  294. package/dist/core/src/validationWorkflow.js +222 -0
  295. package/dist/core/src/validationWorkflow.js.map +1 -0
  296. package/dist/core/src/workspaceRoot.js +68 -0
  297. package/dist/core/src/workspaceRoot.js.map +1 -0
  298. package/package.json +3 -2
@@ -0,0 +1,2475 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAllStackAdapters = getAllStackAdapters;
4
+ exports.getSmartInitDetectionAdapters = getSmartInitDetectionAdapters;
5
+ exports.getStackAdapterById = getStackAdapterById;
6
+ exports.resolveBackendAdapter = resolveBackendAdapter;
7
+ exports.resolveFrontendAdapter = resolveFrontendAdapter;
8
+ exports.resolveLibraryAdapter = resolveLibraryAdapter;
9
+ exports.resolvePrimaryAdapter = resolvePrimaryAdapter;
10
+ exports.resolvePrimaryAdapterFromContract = resolvePrimaryAdapterFromContract;
11
+ exports.resolveDefaultModulesRootFromContract = resolveDefaultModulesRootFromContract;
12
+ const stackMetadata_1 = require("./stackMetadata");
13
+ function sortUnique(values) {
14
+ return [...new Set(values)].sort((left, right) => left.localeCompare(right));
15
+ }
16
+ function sortUniqueKinds(values) {
17
+ return [...new Set(values)].sort((left, right) => left.localeCompare(right));
18
+ }
19
+ function normalizeDefaults(defaults) {
20
+ return {
21
+ sourceRoots: sortUnique(defaults.sourceRoots),
22
+ moduleRootCandidates: sortUnique(defaults.moduleRootCandidates),
23
+ apiRoots: sortUnique(defaults.apiRoots),
24
+ databaseRoots: sortUnique(defaults.databaseRoots),
25
+ configFiles: sortUnique(defaults.configFiles),
26
+ fileExtensions: sortUnique(defaults.fileExtensions),
27
+ dependencyFileExtensions: sortUnique(defaults.dependencyFileExtensions),
28
+ ignoreDirectories: sortUnique(defaults.ignoreDirectories),
29
+ entrypointHints: sortUnique(defaults.entrypointHints),
30
+ publicEntrypointDirectories: sortUnique(defaults.publicEntrypointDirectories),
31
+ ...(defaults.moduleIndexFileName ? { moduleIndexFileName: defaults.moduleIndexFileName } : {}),
32
+ };
33
+ }
34
+ function toResult(input) {
35
+ const result = {
36
+ adapterId: input.adapterId,
37
+ confidence: input.confidence,
38
+ score: input.score,
39
+ evidence: sortUnique(input.evidence),
40
+ };
41
+ if ((input.projectKindHints?.length ?? 0) > 0) {
42
+ result.projectKindHints = sortUniqueKinds(input.projectKindHints ?? []);
43
+ }
44
+ if (input.apiStyleHint) {
45
+ result.apiStyleHint = input.apiStyleHint;
46
+ }
47
+ if ((input.databaseHints?.length ?? 0) > 0) {
48
+ result.databaseHints = sortUnique(input.databaseHints ?? []);
49
+ }
50
+ return result;
51
+ }
52
+ function buildAdapter(definition) {
53
+ const defaults = normalizeDefaults(definition.defaults);
54
+ const importMode = definition.getImportExtractionMode?.() ?? 'generic';
55
+ const adapter = {
56
+ id: definition.id,
57
+ displayName: definition.displayName,
58
+ ecosystem: definition.ecosystem,
59
+ category: definition.category,
60
+ priority: definition.priority,
61
+ detect: definition.detect,
62
+ getDefaults: () => ({ ...defaults }),
63
+ ...(definition.resolveProjectKinds ? { resolveProjectKinds: definition.resolveProjectKinds } : {}),
64
+ ...(definition.getImportExtractionMode
65
+ ? { getImportExtractionMode: definition.getImportExtractionMode }
66
+ : { getImportExtractionMode: () => importMode }),
67
+ label: definition.displayName,
68
+ manifestDetectionHints: sortUnique(definition.manifestDetectionHints),
69
+ buildToolHints: sortUnique(definition.buildToolHints),
70
+ defaultSourceRoots: [...defaults.sourceRoots],
71
+ defaultEntrypointHints: [...defaults.entrypointHints],
72
+ relevantFileExtensions: [...defaults.fileExtensions],
73
+ dependencyParsingFileExtensions: [...defaults.dependencyFileExtensions],
74
+ ignoreDirectoryNames: [...defaults.ignoreDirectories],
75
+ publicEntrypointDirectoryNames: [...defaults.publicEntrypointDirectories],
76
+ dependencyExtractionStrategyHint: importMode,
77
+ scaffoldingDefaults: {
78
+ modulesRoot: defaults.moduleRootCandidates[0] ?? defaults.sourceRoots[0] ?? 'src/modules',
79
+ moduleIndexFileName: defaults.moduleIndexFileName,
80
+ },
81
+ };
82
+ return adapter;
83
+ }
84
+ const commonIgnoreDirectories = [
85
+ 'node_modules',
86
+ '.git',
87
+ '.vscode-test',
88
+ '.archpilot',
89
+ '.next',
90
+ 'dist',
91
+ 'build',
92
+ 'out',
93
+ 'coverage',
94
+ 'fixtures',
95
+ '__fixtures__',
96
+ ];
97
+ const commonApiRoots = ['src/api', 'api', 'app/api'];
98
+ const commonDatabaseRoots = ['db', 'database', 'prisma', 'migrations'];
99
+ function hasPythonEntrypointEvidence(context) {
100
+ return context.hasFile('app.py') ||
101
+ context.hasFile('main.py') ||
102
+ context.hasFile('__main__.py') ||
103
+ context.hasAnyPathMatchingPattern(/(^|\/)(app|src)\/(main|app|__main__)\.py$/u);
104
+ }
105
+ function hasPythonPackageEvidence(context) {
106
+ return context.hasAnyPathMatchingPattern(/(^|\/)(src\/)?[a-zA-Z_][\w-]*\/__init__\.py$/u);
107
+ }
108
+ function hasPythonRuntimeDependencyEvidence(context) {
109
+ return [
110
+ 'fastapi',
111
+ 'django',
112
+ 'flask',
113
+ 'uvicorn',
114
+ 'gunicorn',
115
+ 'sqlalchemy',
116
+ 'pydantic',
117
+ ].some((dependency) => context.hasFileMatchingPattern('pyproject.toml', new RegExp(`\\b${dependency}\\b`, 'iu')) || context.hasFileMatchingPattern('requirements.txt', new RegExp(`\\b${dependency}\\b`, 'iu')));
118
+ }
119
+ function hasGoEntrypointEvidence(context) {
120
+ return context.hasFile('main.go') ||
121
+ context.hasAnyPathMatchingPattern(/(^|\/)cmd\/[^/]+\/main\.go$/u) ||
122
+ context.hasAnyFileMatchingPattern(/(^|\/).+\.go$/u, /\bpackage\s+main\b/u);
123
+ }
124
+ function hasGoServerDependencyEvidence(context) {
125
+ return context.hasFileMatchingPattern('go.mod', /\b(github\.com\/go-chi\/chi|github\.com\/gin-gonic\/gin|github\.com\/gorilla\/mux|github\.com\/labstack\/echo|connectrpc\.com\/connect)\b/u);
126
+ }
127
+ const genericDefaultAdapter = buildAdapter({
128
+ id: 'other',
129
+ displayName: stackMetadata_1.canonicalStackLabels.other,
130
+ ecosystem: 'other',
131
+ category: 'fallback',
132
+ priority: 0,
133
+ manifestDetectionHints: [],
134
+ buildToolHints: [],
135
+ defaults: {
136
+ sourceRoots: ['src'],
137
+ moduleRootCandidates: ['src/modules', 'src'],
138
+ apiRoots: [...commonApiRoots],
139
+ databaseRoots: [...commonDatabaseRoots],
140
+ configFiles: [],
141
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.py', '.java', '.php', '.go'],
142
+ dependencyFileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
143
+ ignoreDirectories: [...commonIgnoreDirectories],
144
+ entrypointHints: ['index.*', 'main.*'],
145
+ publicEntrypointDirectories: ['public'],
146
+ moduleIndexFileName: 'index.ts',
147
+ },
148
+ detect: () => null,
149
+ getImportExtractionMode: () => 'generic',
150
+ });
151
+ const nodeTypescriptAdapter = buildAdapter({
152
+ id: 'node_typescript',
153
+ displayName: stackMetadata_1.canonicalStackLabels.node_typescript,
154
+ ecosystem: 'node',
155
+ category: 'generic-language',
156
+ priority: 40,
157
+ manifestDetectionHints: ['package.json', 'tsconfig.json'],
158
+ buildToolHints: ['npm', 'pnpm', 'yarn'],
159
+ defaults: {
160
+ sourceRoots: ['src/modules', 'src'],
161
+ moduleRootCandidates: ['src/modules', 'src'],
162
+ apiRoots: ['src/api', 'api'],
163
+ databaseRoots: ['prisma', 'db', 'database', 'migrations'],
164
+ configFiles: ['package.json', 'tsconfig.json'],
165
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
166
+ dependencyFileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
167
+ ignoreDirectories: [...commonIgnoreDirectories],
168
+ entrypointHints: ['index.ts', 'index.tsx', 'main.ts', 'main.tsx', 'index.js', 'main.js'],
169
+ publicEntrypointDirectories: ['public'],
170
+ moduleIndexFileName: 'index.ts',
171
+ },
172
+ detect: (context) => {
173
+ const hasPackageJson = context.hasFile('package.json');
174
+ const hasTsConfig = context.hasFile('tsconfig.json');
175
+ if (hasPackageJson && hasTsConfig) {
176
+ return toResult({
177
+ adapterId: 'node_typescript',
178
+ confidence: 'high',
179
+ score: 88,
180
+ evidence: ['Found package.json', 'Found tsconfig.json'],
181
+ projectKindHints: ['backend', 'library'],
182
+ });
183
+ }
184
+ if (hasPackageJson) {
185
+ return toResult({
186
+ adapterId: 'node_typescript',
187
+ confidence: 'medium',
188
+ score: 54,
189
+ evidence: ['Found package.json without tsconfig.json'],
190
+ projectKindHints: ['backend', 'library'],
191
+ });
192
+ }
193
+ return null;
194
+ },
195
+ resolveProjectKinds: () => ['backend', 'library'],
196
+ getImportExtractionMode: () => 'typescript-imports',
197
+ });
198
+ const stackAdaptersById = {
199
+ other: genericDefaultAdapter,
200
+ node_typescript: nodeTypescriptAdapter,
201
+ express: buildAdapter({
202
+ id: 'express',
203
+ displayName: stackMetadata_1.canonicalStackLabels.express,
204
+ ecosystem: 'node',
205
+ category: 'framework',
206
+ priority: 70,
207
+ manifestDetectionHints: ['package.json', 'tsconfig.json', 'app.js', 'app.ts', 'server.js', 'server.ts'],
208
+ buildToolHints: ['npm', 'pnpm', 'yarn'],
209
+ defaults: {
210
+ sourceRoots: ['src', '.'],
211
+ moduleRootCandidates: ['src/modules', 'src/features', 'routes', 'src/routes', 'src'],
212
+ apiRoots: ['routes', 'src/routes', 'src/api', 'api'],
213
+ databaseRoots: ['prisma', 'db', 'database', 'migrations'],
214
+ configFiles: ['package.json', 'tsconfig.json'],
215
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
216
+ dependencyFileExtensions: ['.ts', '.js', '.mjs', '.cjs'],
217
+ ignoreDirectories: ['node_modules', 'dist', 'coverage'],
218
+ entrypointHints: ['app.ts', 'server.ts', 'src/app.ts', 'src/server.ts', 'app.js', 'server.js', 'src/app.js', 'src/server.js'],
219
+ publicEntrypointDirectories: ['public'],
220
+ moduleIndexFileName: 'index.ts',
221
+ },
222
+ detect: (context) => {
223
+ const evidence = [];
224
+ let strongSignals = 0;
225
+ let mediumSignals = 0;
226
+ let score = 0;
227
+ const hasExpressDependency = context.hasPackageDependency('express');
228
+ const hasExpressFactory = context.hasAnyFileMatchingPattern(/\.(ts|js|mjs|cjs)$/iu, /\bexpress\s*\(\s*\)/u);
229
+ const hasExpressImport = context.hasAnyFileMatchingPattern(/\.(ts|js|mjs|cjs)$/iu, /\b(import\s+express\s+from\s+['"]express['"]|require\s*\(\s*['"]express['"]\s*\))/u);
230
+ const hasAppUse = context.hasAnyFileMatchingPattern(/\.(ts|js|mjs|cjs)$/iu, /\bapp\.use\s*\(/u);
231
+ const hasRouterUsage = context.hasAnyFileMatchingPattern(/\.(ts|js|mjs|cjs)$/iu, /\b(router|Router)\s*\.\s*(get|post|put|patch|delete|use)\s*\(/u);
232
+ const hasRoutesDirectory = context.hasDirectory('routes') || context.hasDirectory('src/routes');
233
+ const hasRouteFiles = context.hasAnyPathMatchingPattern(/(^|\/)(routes|src\/routes)\/.+\.(ts|js|mjs|cjs)$/iu);
234
+ if (hasExpressDependency) {
235
+ strongSignals += 1;
236
+ score += 46;
237
+ evidence.push('Found package.json with express dependency');
238
+ }
239
+ if (hasExpressFactory) {
240
+ strongSignals += 1;
241
+ score += 28;
242
+ evidence.push('Found express() app construction');
243
+ }
244
+ if (hasExpressImport) {
245
+ mediumSignals += 1;
246
+ score += 12;
247
+ evidence.push('Found Express import or require');
248
+ }
249
+ if (hasAppUse) {
250
+ mediumSignals += 1;
251
+ score += 10;
252
+ evidence.push('Found app.use(...) middleware or router mounting');
253
+ }
254
+ if (hasRouterUsage) {
255
+ mediumSignals += 1;
256
+ score += 10;
257
+ evidence.push('Found router HTTP method usage');
258
+ }
259
+ if (hasRoutesDirectory) {
260
+ mediumSignals += 1;
261
+ score += 6;
262
+ evidence.push('Found routes/ or src/routes/ directory');
263
+ }
264
+ if (hasRouteFiles) {
265
+ mediumSignals += 1;
266
+ score += 5;
267
+ evidence.push('Found route files under routes/');
268
+ }
269
+ const hasSafeExpressEvidence = hasExpressDependency &&
270
+ (hasExpressFactory || hasExpressImport || hasAppUse || hasRouterUsage || hasRoutesDirectory);
271
+ if (!hasSafeExpressEvidence) {
272
+ return null;
273
+ }
274
+ const confidence = strongSignals >= 2 || (strongSignals >= 1 && mediumSignals >= 2)
275
+ ? 'high'
276
+ : strongSignals >= 1
277
+ ? 'medium'
278
+ : 'low';
279
+ return toResult({
280
+ adapterId: 'express',
281
+ confidence,
282
+ score,
283
+ evidence,
284
+ projectKindHints: ['backend'],
285
+ apiStyleHint: 'rest',
286
+ });
287
+ },
288
+ resolveProjectKinds: () => ['backend'],
289
+ getImportExtractionMode: () => 'typescript-imports',
290
+ }),
291
+ nestjs: buildAdapter({
292
+ id: 'nestjs',
293
+ displayName: stackMetadata_1.canonicalStackLabels.nestjs,
294
+ ecosystem: 'node',
295
+ category: 'framework',
296
+ priority: 75,
297
+ manifestDetectionHints: ['package.json', 'nest-cli.json', 'tsconfig.json', 'tsconfig.build.json', 'main.ts', 'app.module.ts'],
298
+ buildToolHints: ['npm', 'pnpm', 'yarn'],
299
+ defaults: {
300
+ sourceRoots: ['src'],
301
+ moduleRootCandidates: ['src/modules', 'src', 'src/app'],
302
+ apiRoots: ['src'],
303
+ databaseRoots: ['prisma', 'src/database', 'src/db', 'src/persistence', 'migrations'],
304
+ configFiles: ['package.json', 'nest-cli.json', 'tsconfig.json', 'tsconfig.build.json'],
305
+ fileExtensions: ['.ts', '.js', '.json', '.prisma', '.sql', '.yaml', '.yml'],
306
+ dependencyFileExtensions: ['.ts', '.js'],
307
+ ignoreDirectories: ['node_modules', 'dist', 'coverage'],
308
+ entrypointHints: ['src/main.ts'],
309
+ publicEntrypointDirectories: [],
310
+ moduleIndexFileName: 'main.ts',
311
+ },
312
+ detect: (context) => {
313
+ const evidence = [];
314
+ let strongSignals = 0;
315
+ let mediumSignals = 0;
316
+ let weakSignals = 0;
317
+ let score = 0;
318
+ const hasNestCore = context.hasPackageDependency('@nestjs/core');
319
+ const hasNestCommon = context.hasPackageDependency('@nestjs/common');
320
+ const hasNestCli = context.hasPackageDependency('@nestjs/cli');
321
+ const hasModuleDecorator = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /@Module\s*\(/u);
322
+ const hasControllerDecorator = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /@Controller\s*\(/u);
323
+ const hasInjectableDecorator = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /@Injectable\s*\(/u);
324
+ const hasNestFactoryCreate = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /\bNestFactory\.create\s*\(/u);
325
+ const hasMainTsBootstrap = context.getPaths('main.ts').some((value) => value === 'src/main.ts') &&
326
+ context.hasFileMatchingPattern('main.ts', /\bNestFactory\.create(?:<[^>]+>)?\s*\(/u);
327
+ const hasSrcMainTsWithNestDeps = context.getPaths('main.ts').some((value) => value === 'src/main.ts') &&
328
+ (hasNestCore || hasNestCommon || hasNestCli);
329
+ const hasRouteDecorator = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /@(Get|Post|Put|Delete)\s*\(/u);
330
+ const hasNestFastifyBootstrap = context.hasAnyFileMatchingPattern(/\.(ts|js)$/iu, /\bNestFactory\.create<\s*NestFastifyApplication\s*>\s*\(/u);
331
+ const hasNestFastifyPlatform = context.hasPackageDependency('@nestjs/platform-fastify');
332
+ const hasNestExpressPlatform = context.hasPackageDependency('@nestjs/platform-express');
333
+ const hasAppModuleTs = context.getPaths('app.module.ts').some((value) => value === 'src/app.module.ts');
334
+ const hasModuleFile = context.hasAnyPathMatchingPattern(/(^|\/)src\/.+\.module\.ts$/iu);
335
+ const hasControllerFile = context.hasAnyPathMatchingPattern(/(^|\/)src\/.+\.controller\.ts$/iu);
336
+ const hasServiceFile = context.hasAnyPathMatchingPattern(/(^|\/)src\/.+\.service\.ts$/iu);
337
+ const hasFastifyDependency = context.hasPackageDependency('fastify');
338
+ const hasNestLayout = context.hasDirectory('src');
339
+ const hasTestDirectory = context.hasDirectory('test');
340
+ const hasNestCliConfig = context.hasFile('nest-cli.json');
341
+ const hasTsConfigBuild = context.hasFile('tsconfig.build.json');
342
+ const hasSafeNestCoreEvidence = hasNestCore ||
343
+ hasNestCommon ||
344
+ hasNestCli ||
345
+ ((hasModuleDecorator || hasControllerDecorator || hasInjectableDecorator || hasNestFactoryCreate) &&
346
+ (hasNestLayout || hasAppModuleTs));
347
+ if (hasNestCore) {
348
+ strongSignals += 1;
349
+ score += 36;
350
+ evidence.push('Found package.json with @nestjs/core dependency');
351
+ }
352
+ if (hasNestCommon) {
353
+ strongSignals += 1;
354
+ score += 34;
355
+ evidence.push('Found package.json with @nestjs/common dependency');
356
+ }
357
+ if (hasNestCli) {
358
+ strongSignals += 1;
359
+ score += 24;
360
+ evidence.push('Found package.json with @nestjs/cli dependency');
361
+ }
362
+ if (hasModuleDecorator) {
363
+ strongSignals += 1;
364
+ score += 28;
365
+ evidence.push('Found @Module decorator in source');
366
+ }
367
+ if (hasControllerDecorator) {
368
+ strongSignals += 1;
369
+ score += 24;
370
+ evidence.push('Found @Controller decorator in source');
371
+ }
372
+ if (hasInjectableDecorator) {
373
+ strongSignals += 1;
374
+ score += 18;
375
+ evidence.push('Found @Injectable decorator in source');
376
+ }
377
+ if (hasNestFactoryCreate) {
378
+ strongSignals += 1;
379
+ score += 26;
380
+ evidence.push('Found NestFactory.create bootstrap');
381
+ }
382
+ if (hasMainTsBootstrap) {
383
+ strongSignals += 1;
384
+ score += 18;
385
+ evidence.push('Found NestFactory bootstrap in src/main.ts');
386
+ }
387
+ if (hasSrcMainTsWithNestDeps) {
388
+ strongSignals += 1;
389
+ score += 16;
390
+ evidence.push('Found src/main.ts with NestJS dependency evidence');
391
+ }
392
+ if (hasRouteDecorator) {
393
+ mediumSignals += 1;
394
+ score += 10;
395
+ evidence.push('Found Nest-style route decorator in source');
396
+ }
397
+ if (hasNestFastifyBootstrap) {
398
+ mediumSignals += 1;
399
+ score += 10;
400
+ evidence.push('Found NestFastifyApplication bootstrap evidence');
401
+ }
402
+ if (hasNestFastifyPlatform) {
403
+ mediumSignals += 1;
404
+ score += 8;
405
+ evidence.push('Found package.json with @nestjs/platform-fastify dependency');
406
+ }
407
+ if (hasNestExpressPlatform) {
408
+ mediumSignals += 1;
409
+ score += 7;
410
+ evidence.push('Found package.json with @nestjs/platform-express dependency');
411
+ }
412
+ if (hasAppModuleTs) {
413
+ mediumSignals += 1;
414
+ score += 8;
415
+ evidence.push('Found src/app.module.ts');
416
+ }
417
+ if (hasModuleFile) {
418
+ mediumSignals += 1;
419
+ score += 7;
420
+ evidence.push('Found module file under src/');
421
+ }
422
+ if (hasControllerFile) {
423
+ mediumSignals += 1;
424
+ score += 7;
425
+ evidence.push('Found controller file under src/');
426
+ }
427
+ if (hasServiceFile) {
428
+ mediumSignals += 1;
429
+ score += 6;
430
+ evidence.push('Found service file under src/');
431
+ }
432
+ if (hasNestLayout) {
433
+ weakSignals += 1;
434
+ score += 2;
435
+ evidence.push('Found typical NestJS src/ layout');
436
+ }
437
+ if (hasTestDirectory) {
438
+ weakSignals += 1;
439
+ score += 2;
440
+ evidence.push('Found test directory');
441
+ }
442
+ if (hasNestCliConfig) {
443
+ weakSignals += 1;
444
+ score += 3;
445
+ evidence.push('Found nest-cli.json');
446
+ }
447
+ if (hasTsConfigBuild) {
448
+ weakSignals += 1;
449
+ score += 2;
450
+ evidence.push('Found tsconfig.build.json');
451
+ }
452
+ if (hasFastifyDependency && hasSafeNestCoreEvidence) {
453
+ weakSignals += 1;
454
+ score += 3;
455
+ evidence.push('Found fastify dependency with NestJS evidence');
456
+ }
457
+ if (!hasSafeNestCoreEvidence || strongSignals === 0) {
458
+ return null;
459
+ }
460
+ const hasRestEvidence = hasControllerDecorator || hasRouteDecorator || hasControllerFile;
461
+ const confidence = strongSignals >= 2
462
+ ? 'high'
463
+ : strongSignals >= 1 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
464
+ ? 'medium'
465
+ : 'low';
466
+ return toResult({
467
+ adapterId: 'nestjs',
468
+ confidence,
469
+ score,
470
+ evidence,
471
+ projectKindHints: ['backend'],
472
+ apiStyleHint: hasRestEvidence ? 'rest' : 'unknown',
473
+ });
474
+ },
475
+ resolveProjectKinds: () => ['backend'],
476
+ getImportExtractionMode: () => 'typescript-imports',
477
+ }),
478
+ java: buildAdapter({
479
+ id: 'java',
480
+ displayName: stackMetadata_1.canonicalStackLabels.java,
481
+ ecosystem: 'jvm',
482
+ category: 'generic-language',
483
+ priority: 40,
484
+ manifestDetectionHints: [
485
+ 'pom.xml',
486
+ 'build.gradle',
487
+ 'build.gradle.kts',
488
+ 'settings.gradle',
489
+ 'settings.gradle.kts',
490
+ ],
491
+ buildToolHints: ['maven', 'gradle'],
492
+ defaults: {
493
+ sourceRoots: ['src/main/java', 'src'],
494
+ moduleRootCandidates: ['src/main/java', 'src'],
495
+ apiRoots: ['src/main/java', 'src/main/kotlin'],
496
+ databaseRoots: ['src/main/resources/db', 'src/main/resources/migrations'],
497
+ configFiles: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
498
+ fileExtensions: ['.java'],
499
+ dependencyFileExtensions: ['.java'],
500
+ ignoreDirectories: [
501
+ 'target',
502
+ 'build',
503
+ '.gradle',
504
+ '.idea',
505
+ 'out',
506
+ ...commonIgnoreDirectories,
507
+ ],
508
+ entrypointHints: ['Application.java', 'Main.java', '*Application.java', '*Module.java'],
509
+ publicEntrypointDirectories: [],
510
+ moduleIndexFileName: 'Application.java',
511
+ },
512
+ detect: (context) => {
513
+ if (context.hasFile('pom.xml')) {
514
+ return toResult({
515
+ adapterId: 'java',
516
+ confidence: 'high',
517
+ score: 92,
518
+ evidence: ['Found pom.xml'],
519
+ projectKindHints: ['backend'],
520
+ apiStyleHint: 'unknown',
521
+ });
522
+ }
523
+ if (context.hasFile('build.gradle') || context.hasFile('build.gradle.kts')) {
524
+ return toResult({
525
+ adapterId: 'java',
526
+ confidence: 'high',
527
+ score: 90,
528
+ evidence: [
529
+ context.hasFile('build.gradle') ? 'Found build.gradle' : 'Found build.gradle.kts',
530
+ ],
531
+ projectKindHints: ['backend'],
532
+ apiStyleHint: 'unknown',
533
+ });
534
+ }
535
+ if (context.hasFileExtension('.java')) {
536
+ return toResult({
537
+ adapterId: 'java',
538
+ confidence: 'medium',
539
+ score: 64,
540
+ evidence: ['Found .java source files'],
541
+ projectKindHints: ['backend'],
542
+ apiStyleHint: 'unknown',
543
+ });
544
+ }
545
+ return null;
546
+ },
547
+ resolveProjectKinds: () => ['backend'],
548
+ getImportExtractionMode: () => 'java-imports',
549
+ }),
550
+ spring: buildAdapter({
551
+ id: 'spring',
552
+ displayName: stackMetadata_1.canonicalStackLabels.spring,
553
+ ecosystem: 'jvm',
554
+ category: 'framework',
555
+ priority: 70,
556
+ manifestDetectionHints: [
557
+ 'pom.xml',
558
+ 'build.gradle',
559
+ 'build.gradle.kts',
560
+ 'application.yml',
561
+ 'application.yaml',
562
+ 'application.properties',
563
+ 'bootstrap.yml',
564
+ 'bootstrap.yaml',
565
+ 'mvnw',
566
+ 'gradlew',
567
+ ],
568
+ buildToolHints: ['maven', 'gradle'],
569
+ defaults: {
570
+ sourceRoots: ['src/main/java', 'src/main/kotlin', 'src'],
571
+ moduleRootCandidates: ['src/main/java', 'src/main/kotlin'],
572
+ apiRoots: ['src/main/java', 'src/main/kotlin'],
573
+ databaseRoots: ['src/main/resources', 'src/main/resources/db'],
574
+ configFiles: [
575
+ 'pom.xml',
576
+ 'build.gradle',
577
+ 'build.gradle.kts',
578
+ 'application.yml',
579
+ 'application.yaml',
580
+ 'application.properties',
581
+ ],
582
+ fileExtensions: ['.java', '.kt', '.yml', '.yaml', '.properties', '.sql'],
583
+ dependencyFileExtensions: ['.java', '.kt'],
584
+ ignoreDirectories: [
585
+ 'target',
586
+ 'build',
587
+ '.gradle',
588
+ '.idea',
589
+ 'out',
590
+ ...commonIgnoreDirectories,
591
+ ],
592
+ entrypointHints: ['src/main/java', 'src/main/kotlin', 'Application.java', 'Application.kt'],
593
+ publicEntrypointDirectories: [],
594
+ moduleIndexFileName: 'Application.java',
595
+ },
596
+ detect: (context) => {
597
+ const evidence = [];
598
+ let strongSignals = 0;
599
+ let mediumSignals = 0;
600
+ let weakSignals = 0;
601
+ let score = 0;
602
+ const hasPomSpringDependency = context.hasFileMatchingPattern('pom.xml', /\b(org\.springframework\.boot|spring-boot-starter|spring-web)\b/iu);
603
+ const hasGradleSpringDependency = context.hasFileMatchingPattern('build.gradle', /\b(org\.springframework\.boot|spring-boot-starter|spring-web|id\s+['"]org\.springframework\.boot['"])\b/iu) ||
604
+ context.hasFileMatchingPattern('build.gradle.kts', /\b(org\.springframework\.boot|spring-boot-starter|spring-web|id\s*\(\s*["']org\.springframework\.boot["']\s*\))\b/iu);
605
+ const hasSpringDependencyEvidence = hasPomSpringDependency || hasGradleSpringDependency;
606
+ const hasSpringBootApplication = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@SpringBootApplication\b/u);
607
+ const hasMainSourceWithDependencies = (context.hasDirectory('src/main/java') || context.hasDirectory('src/main/kotlin')) &&
608
+ hasSpringDependencyEvidence;
609
+ const hasApplicationConfigWithDependencies = (context.hasFile('application.yml') ||
610
+ context.hasFile('application.yaml') ||
611
+ context.hasFile('application.properties')) &&
612
+ hasSpringDependencyEvidence;
613
+ const hasRestController = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@RestController\b/u);
614
+ const hasController = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@Controller\b/u);
615
+ const hasService = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@Service\b/u);
616
+ const hasRepository = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@Repository\b/u);
617
+ const hasMappingAnnotation = context.hasAnyFileMatchingPattern(/\.(java|kt)$/iu, /@(RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping)\b/u);
618
+ const hasResourcesDirectory = context.hasDirectory('src/main/resources');
619
+ const hasWrapperWithSpringEvidence = (context.hasFile('mvnw') || context.hasFile('gradlew')) && hasSpringDependencyEvidence;
620
+ const hasTestJvmSource = context.hasDirectory('src/test/java') || context.hasDirectory('src/test/kotlin');
621
+ const hasBootstrapConfig = context.hasFile('bootstrap.yml') || context.hasFile('bootstrap.yaml');
622
+ const hasJvmPackageShape = context.hasDirectory('src/main/java/com') ||
623
+ context.hasDirectory('src/main/java/org') ||
624
+ context.hasDirectory('src/main/kotlin/com') ||
625
+ context.hasDirectory('src/main/kotlin/org');
626
+ if (hasPomSpringDependency) {
627
+ strongSignals += 1;
628
+ score += 54;
629
+ evidence.push('Found pom.xml with Spring dependency markers');
630
+ }
631
+ if (hasGradleSpringDependency) {
632
+ strongSignals += 1;
633
+ score += 54;
634
+ evidence.push('Found Gradle build with Spring plugin or dependency markers');
635
+ }
636
+ if (hasSpringBootApplication) {
637
+ strongSignals += 1;
638
+ score += 44;
639
+ evidence.push('Found @SpringBootApplication in source');
640
+ }
641
+ if (hasMainSourceWithDependencies) {
642
+ strongSignals += 1;
643
+ score += 20;
644
+ evidence.push('Found JVM main source root with Spring dependency evidence');
645
+ }
646
+ if (hasApplicationConfigWithDependencies) {
647
+ strongSignals += 1;
648
+ score += 20;
649
+ evidence.push('Found application config with Spring dependency evidence');
650
+ }
651
+ if (hasRestController) {
652
+ mediumSignals += 1;
653
+ score += 10;
654
+ evidence.push('Found @RestController annotation');
655
+ }
656
+ if (hasController) {
657
+ mediumSignals += 1;
658
+ score += 7;
659
+ evidence.push('Found @Controller annotation');
660
+ }
661
+ if (hasService) {
662
+ mediumSignals += 1;
663
+ score += 6;
664
+ evidence.push('Found @Service annotation');
665
+ }
666
+ if (hasRepository) {
667
+ mediumSignals += 1;
668
+ score += 6;
669
+ evidence.push('Found @Repository annotation');
670
+ }
671
+ if (hasMappingAnnotation) {
672
+ mediumSignals += 1;
673
+ score += 9;
674
+ evidence.push('Found Spring request-mapping annotation');
675
+ }
676
+ if (hasResourcesDirectory) {
677
+ mediumSignals += 1;
678
+ score += 5;
679
+ evidence.push('Found src/main/resources directory');
680
+ }
681
+ if (hasWrapperWithSpringEvidence) {
682
+ mediumSignals += 1;
683
+ score += 4;
684
+ evidence.push('Found Maven/Gradle wrapper with Spring dependency evidence');
685
+ }
686
+ if (hasTestJvmSource) {
687
+ weakSignals += 1;
688
+ score += 2;
689
+ evidence.push('Found JVM test source directory');
690
+ }
691
+ if (hasBootstrapConfig) {
692
+ weakSignals += 1;
693
+ score += 2;
694
+ evidence.push('Found bootstrap.yml or bootstrap.yaml');
695
+ }
696
+ if (hasJvmPackageShape) {
697
+ weakSignals += 1;
698
+ score += 1;
699
+ evidence.push('Found conventional JVM package directory under main source root');
700
+ }
701
+ const hasSafeSpringCoreEvidence = hasSpringDependencyEvidence ||
702
+ hasSpringBootApplication ||
703
+ ((hasRestController || hasController || hasService || hasRepository || hasMappingAnnotation) &&
704
+ (context.hasDirectory('src/main/java') || context.hasDirectory('src/main/kotlin') || hasResourcesDirectory));
705
+ if (!hasSafeSpringCoreEvidence || strongSignals === 0) {
706
+ return null;
707
+ }
708
+ const hasRestEvidence = hasRestController || hasController || hasMappingAnnotation;
709
+ const confidence = strongSignals >= 2
710
+ ? 'high'
711
+ : strongSignals >= 1 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
712
+ ? 'medium'
713
+ : 'low';
714
+ return toResult({
715
+ adapterId: 'spring',
716
+ confidence,
717
+ score,
718
+ evidence,
719
+ projectKindHints: ['backend'],
720
+ apiStyleHint: hasRestEvidence ? 'rest' : 'unknown',
721
+ });
722
+ },
723
+ resolveProjectKinds: () => ['backend'],
724
+ getImportExtractionMode: () => 'java-imports',
725
+ }),
726
+ fastapi: buildAdapter({
727
+ id: 'fastapi',
728
+ displayName: stackMetadata_1.canonicalStackLabels.fastapi,
729
+ ecosystem: 'python',
730
+ category: 'framework',
731
+ priority: 70,
732
+ manifestDetectionHints: [
733
+ 'requirements.txt',
734
+ 'pyproject.toml',
735
+ 'Pipfile',
736
+ 'Pipfile.lock',
737
+ 'poetry.lock',
738
+ 'alembic.ini',
739
+ 'main.py',
740
+ 'app.py',
741
+ ],
742
+ buildToolHints: ['pip', 'poetry', 'uvicorn'],
743
+ defaults: {
744
+ sourceRoots: ['app', 'src', '.'],
745
+ moduleRootCandidates: ['app', 'src/app', 'src', 'routers', 'api'],
746
+ apiRoots: ['app', 'src', 'routers', 'api'],
747
+ databaseRoots: ['app/db', 'app/database', 'src/db', 'src/database', 'migrations', 'alembic'],
748
+ configFiles: [
749
+ 'requirements.txt',
750
+ 'pyproject.toml',
751
+ 'Pipfile',
752
+ 'Pipfile.lock',
753
+ 'poetry.lock',
754
+ 'alembic.ini',
755
+ ],
756
+ fileExtensions: ['.py', '.toml', '.txt', '.ini', '.sql', '.yaml', '.yml'],
757
+ dependencyFileExtensions: ['.py'],
758
+ ignoreDirectories: [
759
+ '__pycache__',
760
+ '.pytest_cache',
761
+ '.venv',
762
+ 'venv',
763
+ 'dist',
764
+ 'build',
765
+ '.idea',
766
+ ...commonIgnoreDirectories,
767
+ ],
768
+ entrypointHints: ['main.py', 'app.py', 'app/main.py', 'src/main.py'],
769
+ publicEntrypointDirectories: [],
770
+ moduleIndexFileName: '__init__.py',
771
+ },
772
+ detect: (context) => {
773
+ const evidence = [];
774
+ let strongSignals = 0;
775
+ let mediumSignals = 0;
776
+ let weakSignals = 0;
777
+ let score = 0;
778
+ const hasRequirementsFastApi = context.hasFileMatchingPattern('requirements.txt', /(^|\s)fastapi([=<>~!]|$)/imu);
779
+ const hasPyprojectFastApi = context.hasFileMatchingPattern('pyproject.toml', /\bfastapi\b/iu);
780
+ const hasPoetryLockFastApi = context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']fastapi["']/iu);
781
+ const hasPipfileFastApi = context.hasFileMatchingPattern('Pipfile', /\bfastapi\b/iu);
782
+ const hasPipfileLockFastApi = context.hasFileMatchingPattern('Pipfile.lock', /"fastapi"\s*:/iu);
783
+ const hasFastApiDependencyEvidence = hasRequirementsFastApi ||
784
+ hasPyprojectFastApi ||
785
+ hasPoetryLockFastApi ||
786
+ hasPipfileFastApi ||
787
+ hasPipfileLockFastApi;
788
+ const hasFastApiImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\bfrom\s+fastapi\s+import\s+FastAPI\b/u);
789
+ const hasFastApiConstruction = context.hasAnyFileMatchingPattern(/\.py$/iu, /\b\w+\s*=\s*FastAPI\s*\(/u);
790
+ const hasRouteDecorator = context.hasAnyFileMatchingPattern(/\.py$/iu, /@(?:app|router)\.(?:get|post|put|delete)\s*\(/u);
791
+ const hasApiRouter = context.hasAnyFileMatchingPattern(/\.py$/iu, /\bAPIRouter\b/u);
792
+ const hasUvicornDependency = context.hasFileMatchingPattern('requirements.txt', /(^|\s)uvicorn([=<>~!]|$)/imu) ||
793
+ context.hasFileMatchingPattern('pyproject.toml', /\buvicorn\b/iu) ||
794
+ context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']uvicorn["']/iu) ||
795
+ context.hasFileMatchingPattern('Pipfile', /\buvicorn\b/iu) ||
796
+ context.hasFileMatchingPattern('Pipfile.lock', /"uvicorn"\s*:/iu);
797
+ const hasStarletteDependency = context.hasFileMatchingPattern('requirements.txt', /(^|\s)starlette([=<>~!]|$)/imu) ||
798
+ context.hasFileMatchingPattern('pyproject.toml', /\bstarlette\b/iu) ||
799
+ context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']starlette["']/iu) ||
800
+ context.hasFileMatchingPattern('Pipfile', /\bstarlette\b/iu) ||
801
+ context.hasFileMatchingPattern('Pipfile.lock', /"starlette"\s*:/iu);
802
+ const hasPydanticDependency = context.hasFileMatchingPattern('requirements.txt', /(^|\s)pydantic([=<>~!]|$)/imu) ||
803
+ context.hasFileMatchingPattern('pyproject.toml', /\bpydantic\b/iu) ||
804
+ context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']pydantic["']/iu) ||
805
+ context.hasFileMatchingPattern('Pipfile', /\bpydantic\b/iu) ||
806
+ context.hasFileMatchingPattern('Pipfile.lock', /"pydantic"\s*:/iu);
807
+ const hasUvicornWithFastApiEvidence = hasUvicornDependency && (hasFastApiDependencyEvidence || hasFastApiImport || hasFastApiConstruction);
808
+ const hasSrcOrAppWithImportEvidence = (context.hasDirectory('src') || context.hasDirectory('app')) && hasFastApiImport;
809
+ const hasEntryPointConstruction = context.hasAnyFileMatchingPattern(/(^|\/)(main|app)\.py$/iu, /\b\w+\s*=\s*FastAPI\s*\(/u);
810
+ const hasRoutersDirectoryWithImportEvidence = context.hasDirectory('routers') &&
811
+ (hasFastApiImport || hasApiRouter || hasRouteDecorator);
812
+ const hasUvicornOrStarletteWithFastApiEvidence = (hasUvicornDependency || hasStarletteDependency) &&
813
+ (hasFastApiDependencyEvidence || hasFastApiImport || hasFastApiConstruction);
814
+ const hasSupportingBackendLayout = context.hasDirectory('app') ||
815
+ context.hasDirectory('src') ||
816
+ context.hasDirectory('routers') ||
817
+ context.hasDirectory('api');
818
+ if (hasRequirementsFastApi) {
819
+ strongSignals += 1;
820
+ score += 54;
821
+ evidence.push('Found requirements.txt with fastapi dependency');
822
+ }
823
+ if (hasPyprojectFastApi) {
824
+ strongSignals += 1;
825
+ score += 54;
826
+ evidence.push('Found pyproject.toml with fastapi dependency');
827
+ }
828
+ if (hasPoetryLockFastApi || hasPipfileFastApi || hasPipfileLockFastApi) {
829
+ strongSignals += 1;
830
+ score += 52;
831
+ evidence.push('Found Pipfile/lock metadata with fastapi dependency');
832
+ }
833
+ if (hasFastApiImport) {
834
+ strongSignals += 1;
835
+ score += 44;
836
+ evidence.push('Found FastAPI import in source');
837
+ }
838
+ if (hasFastApiConstruction) {
839
+ strongSignals += 1;
840
+ score += 40;
841
+ evidence.push('Found FastAPI application construction in source');
842
+ }
843
+ if (hasRouteDecorator) {
844
+ strongSignals += 1;
845
+ score += 26;
846
+ evidence.push('Found FastAPI route decorator in source');
847
+ }
848
+ if (hasUvicornWithFastApiEvidence) {
849
+ strongSignals += 1;
850
+ score += 20;
851
+ evidence.push('Found uvicorn with FastAPI evidence');
852
+ }
853
+ if (hasApiRouter) {
854
+ mediumSignals += 1;
855
+ score += 10;
856
+ evidence.push('Found APIRouter usage');
857
+ }
858
+ if (hasSrcOrAppWithImportEvidence) {
859
+ mediumSignals += 1;
860
+ score += 8;
861
+ evidence.push('Found app/ or src/ directory with FastAPI import evidence');
862
+ }
863
+ if (hasEntryPointConstruction) {
864
+ mediumSignals += 1;
865
+ score += 8;
866
+ evidence.push('Found main.py or app.py with FastAPI application construction');
867
+ }
868
+ if (hasRoutersDirectoryWithImportEvidence) {
869
+ mediumSignals += 1;
870
+ score += 7;
871
+ evidence.push('Found routers/ directory with FastAPI source evidence');
872
+ }
873
+ if (hasUvicornOrStarletteWithFastApiEvidence) {
874
+ mediumSignals += 1;
875
+ score += 6;
876
+ evidence.push('Found uvicorn or starlette with FastAPI evidence');
877
+ }
878
+ if (hasSupportingBackendLayout) {
879
+ weakSignals += 1;
880
+ score += 2;
881
+ evidence.push('Found typical Python backend layout directory');
882
+ }
883
+ if (hasPydanticDependency) {
884
+ weakSignals += 1;
885
+ score += 1;
886
+ evidence.push('Found pydantic dependency as supporting evidence');
887
+ }
888
+ const hasSafeFastApiCoreEvidence = hasFastApiDependencyEvidence ||
889
+ (hasFastApiImport && hasFastApiConstruction) ||
890
+ (hasFastApiImport && (hasRouteDecorator || hasApiRouter));
891
+ if (!hasSafeFastApiCoreEvidence || strongSignals === 0) {
892
+ return null;
893
+ }
894
+ const hasRestEvidence = hasRouteDecorator || hasApiRouter;
895
+ const confidence = strongSignals >= 2
896
+ ? 'high'
897
+ : strongSignals >= 1 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
898
+ ? 'medium'
899
+ : 'low';
900
+ return toResult({
901
+ adapterId: 'fastapi',
902
+ confidence,
903
+ score,
904
+ evidence,
905
+ projectKindHints: ['backend'],
906
+ apiStyleHint: hasRestEvidence ? 'rest' : 'unknown',
907
+ });
908
+ },
909
+ resolveProjectKinds: () => ['backend'],
910
+ getImportExtractionMode: () => 'python-imports',
911
+ }),
912
+ django: buildAdapter({
913
+ id: 'django',
914
+ displayName: stackMetadata_1.canonicalStackLabels.django,
915
+ ecosystem: 'python',
916
+ category: 'framework',
917
+ priority: 68,
918
+ manifestDetectionHints: [
919
+ 'requirements.txt',
920
+ 'pyproject.toml',
921
+ 'Pipfile',
922
+ 'Pipfile.lock',
923
+ 'poetry.lock',
924
+ 'manage.py',
925
+ 'settings.py',
926
+ 'urls.py',
927
+ 'wsgi.py',
928
+ 'asgi.py',
929
+ ],
930
+ buildToolHints: ['pip', 'poetry', 'django-admin'],
931
+ defaults: {
932
+ sourceRoots: ['.', 'src', 'app'],
933
+ moduleRootCandidates: ['.', 'src', 'app'],
934
+ apiRoots: ['.', 'src', 'app'],
935
+ databaseRoots: ['migrations', 'db', 'database'],
936
+ configFiles: ['requirements.txt', 'pyproject.toml', 'Pipfile', 'Pipfile.lock', 'poetry.lock', 'manage.py'],
937
+ fileExtensions: ['.py', '.toml', '.txt', '.sql', '.yaml', '.yml'],
938
+ dependencyFileExtensions: ['.py'],
939
+ ignoreDirectories: [
940
+ '__pycache__',
941
+ '.pytest_cache',
942
+ '.venv',
943
+ 'venv',
944
+ 'dist',
945
+ 'build',
946
+ '.idea',
947
+ ...commonIgnoreDirectories,
948
+ ],
949
+ entrypointHints: ['manage.py', 'wsgi.py', 'asgi.py', 'settings.py', 'urls.py'],
950
+ publicEntrypointDirectories: [],
951
+ moduleIndexFileName: '__init__.py',
952
+ },
953
+ detect: (context) => {
954
+ const evidence = [];
955
+ let strongSignals = 0;
956
+ let mediumSignals = 0;
957
+ let weakSignals = 0;
958
+ let score = 0;
959
+ const hasRequirementsDjango = context.hasFileMatchingPattern('requirements.txt', /(^|\s)django([=<>~!]|$)/imu);
960
+ const hasPyprojectDjango = context.hasFileMatchingPattern('pyproject.toml', /\bdjango\b/iu);
961
+ const hasPoetryLockDjango = context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']django["']/iu);
962
+ const hasPipfileDjango = context.hasFileMatchingPattern('Pipfile', /\bdjango\b/iu);
963
+ const hasPipfileLockDjango = context.hasFileMatchingPattern('Pipfile.lock', /"django"\s*:/iu);
964
+ const hasDjangoDependencyEvidence = hasRequirementsDjango ||
965
+ hasPyprojectDjango ||
966
+ hasPoetryLockDjango ||
967
+ hasPipfileDjango ||
968
+ hasPipfileLockDjango;
969
+ const hasManagePy = context.hasFile('manage.py');
970
+ const hasDjangoSettingsModule = context.hasFileMatchingPattern('manage.py', /\bDJANGO_SETTINGS_MODULE\b/u);
971
+ const hasSettingsPy = context.hasFile('settings.py');
972
+ const hasUrlsPy = context.hasFile('urls.py');
973
+ const hasWsgiOrAsgi = context.hasFile('wsgi.py') || context.hasFile('asgi.py');
974
+ const hasInstalledApps = context.hasFileMatchingPattern('settings.py', /\bINSTALLED_APPS\s*=/u);
975
+ const hasDjangoAdmin = context.hasAnyFileMatchingPattern(/(^|\/)(manage|settings|urls|wsgi|asgi)\.py$/iu, /\bdjango-admin\b/iu);
976
+ const hasDjangoImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\b(from|import)\s+django\b/u);
977
+ const hasDjangoUrlsImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\bfrom\s+django\.urls\s+import\s+(?:path|include|re_path)\b/u);
978
+ if (hasRequirementsDjango) {
979
+ strongSignals += 1;
980
+ score += 52;
981
+ evidence.push('Found requirements.txt with django dependency');
982
+ }
983
+ if (hasPyprojectDjango) {
984
+ strongSignals += 1;
985
+ score += 52;
986
+ evidence.push('Found pyproject.toml with django dependency');
987
+ }
988
+ if (hasPoetryLockDjango || hasPipfileDjango || hasPipfileLockDjango) {
989
+ strongSignals += 1;
990
+ score += 50;
991
+ evidence.push('Found Pipfile/lock metadata with django dependency');
992
+ }
993
+ if (hasManagePy) {
994
+ strongSignals += 1;
995
+ score += 34;
996
+ evidence.push('Found manage.py');
997
+ }
998
+ if (hasDjangoSettingsModule) {
999
+ strongSignals += 1;
1000
+ score += 24;
1001
+ evidence.push('Found DJANGO_SETTINGS_MODULE in manage.py');
1002
+ }
1003
+ if (hasInstalledApps) {
1004
+ strongSignals += 1;
1005
+ score += 24;
1006
+ evidence.push('Found INSTALLED_APPS in settings.py');
1007
+ }
1008
+ if (hasDjangoImport) {
1009
+ strongSignals += 1;
1010
+ score += 22;
1011
+ evidence.push('Found django import in source');
1012
+ }
1013
+ if (hasSettingsPy) {
1014
+ mediumSignals += 1;
1015
+ score += 12;
1016
+ evidence.push('Found settings.py');
1017
+ }
1018
+ if (hasUrlsPy) {
1019
+ mediumSignals += 1;
1020
+ score += 10;
1021
+ evidence.push('Found urls.py');
1022
+ }
1023
+ if (hasWsgiOrAsgi) {
1024
+ mediumSignals += 1;
1025
+ score += 10;
1026
+ evidence.push('Found wsgi.py or asgi.py');
1027
+ }
1028
+ if (hasDjangoUrlsImport) {
1029
+ mediumSignals += 1;
1030
+ score += 10;
1031
+ evidence.push('Found Django URL routing import');
1032
+ }
1033
+ if (hasDjangoAdmin) {
1034
+ weakSignals += 1;
1035
+ score += 3;
1036
+ evidence.push('Found django-admin reference');
1037
+ }
1038
+ if (context.hasDirectory('migrations')) {
1039
+ weakSignals += 1;
1040
+ score += 2;
1041
+ evidence.push('Found migrations directory');
1042
+ }
1043
+ const hasSafeDjangoCoreEvidence = hasDjangoDependencyEvidence ||
1044
+ (hasManagePy && (hasDjangoSettingsModule || hasSettingsPy || hasUrlsPy || hasWsgiOrAsgi)) ||
1045
+ (hasInstalledApps && (hasSettingsPy || hasDjangoImport)) ||
1046
+ (hasDjangoImport && (hasDjangoUrlsImport || hasUrlsPy));
1047
+ if (!hasSafeDjangoCoreEvidence || strongSignals === 0) {
1048
+ return null;
1049
+ }
1050
+ const hasRestEvidence = hasUrlsPy || hasDjangoUrlsImport;
1051
+ const confidence = strongSignals >= 2
1052
+ ? 'high'
1053
+ : strongSignals >= 1 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
1054
+ ? 'medium'
1055
+ : 'low';
1056
+ return toResult({
1057
+ adapterId: 'django',
1058
+ confidence,
1059
+ score,
1060
+ evidence,
1061
+ projectKindHints: ['backend'],
1062
+ apiStyleHint: hasRestEvidence ? 'rest' : 'unknown',
1063
+ });
1064
+ },
1065
+ resolveProjectKinds: () => ['backend'],
1066
+ getImportExtractionMode: () => 'python-imports',
1067
+ }),
1068
+ flask: buildAdapter({
1069
+ id: 'flask',
1070
+ displayName: stackMetadata_1.canonicalStackLabels.flask,
1071
+ ecosystem: 'python',
1072
+ category: 'framework',
1073
+ priority: 66,
1074
+ manifestDetectionHints: [
1075
+ 'requirements.txt',
1076
+ 'pyproject.toml',
1077
+ 'Pipfile',
1078
+ 'Pipfile.lock',
1079
+ 'poetry.lock',
1080
+ 'app.py',
1081
+ 'wsgi.py',
1082
+ 'main.py',
1083
+ ],
1084
+ buildToolHints: ['pip', 'poetry', 'flask'],
1085
+ defaults: {
1086
+ sourceRoots: ['app', 'src', '.'],
1087
+ moduleRootCandidates: ['app', 'src/app', 'src', 'blueprints', 'api'],
1088
+ apiRoots: ['app', 'src', 'blueprints', 'api'],
1089
+ databaseRoots: ['migrations', 'app/db', 'app/database', 'src/db', 'src/database'],
1090
+ configFiles: ['requirements.txt', 'pyproject.toml', 'Pipfile', 'Pipfile.lock', 'poetry.lock'],
1091
+ fileExtensions: ['.py', '.toml', '.txt', '.sql', '.yaml', '.yml'],
1092
+ dependencyFileExtensions: ['.py'],
1093
+ ignoreDirectories: [
1094
+ '__pycache__',
1095
+ '.pytest_cache',
1096
+ '.venv',
1097
+ 'venv',
1098
+ 'dist',
1099
+ 'build',
1100
+ '.idea',
1101
+ ...commonIgnoreDirectories,
1102
+ ],
1103
+ entrypointHints: ['app.py', 'main.py', 'wsgi.py', 'app/__init__.py'],
1104
+ publicEntrypointDirectories: [],
1105
+ moduleIndexFileName: '__init__.py',
1106
+ },
1107
+ detect: (context) => {
1108
+ const evidence = [];
1109
+ let strongSignals = 0;
1110
+ let mediumSignals = 0;
1111
+ let weakSignals = 0;
1112
+ let score = 0;
1113
+ const hasRequirementsFlask = context.hasFileMatchingPattern('requirements.txt', /(^|\s)flask([=<>~!]|$)/imu);
1114
+ const hasPyprojectFlask = context.hasFileMatchingPattern('pyproject.toml', /\bflask\b/iu);
1115
+ const hasPoetryLockFlask = context.hasFileMatchingPattern('poetry.lock', /\bname\s*=\s*["']flask["']/iu);
1116
+ const hasPipfileFlask = context.hasFileMatchingPattern('Pipfile', /\bflask\b/iu);
1117
+ const hasPipfileLockFlask = context.hasFileMatchingPattern('Pipfile.lock', /"flask"\s*:/iu);
1118
+ const hasFlaskDependencyEvidence = hasRequirementsFlask ||
1119
+ hasPyprojectFlask ||
1120
+ hasPoetryLockFlask ||
1121
+ hasPipfileFlask ||
1122
+ hasPipfileLockFlask;
1123
+ const hasFlaskImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\bfrom\s+flask\s+import\s+.*\bFlask\b/u);
1124
+ const hasFlaskConstruction = context.hasAnyFileMatchingPattern(/\.py$/iu, /\b\w+\s*=\s*Flask\s*\(\s*__name__/u);
1125
+ const hasRouteDecorator = context.hasAnyFileMatchingPattern(/\.py$/iu, /@\w+\.route\s*\(/u);
1126
+ const hasMethodRouteDecorator = context.hasAnyFileMatchingPattern(/\.py$/iu, /@\w+\.(?:get|post|put|delete)\s*\(/u);
1127
+ const hasBlueprintImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\bfrom\s+flask\s+import\s+.*\bBlueprint\b/u);
1128
+ const hasBlueprintConstruction = context.hasAnyFileMatchingPattern(/\.py$/iu, /\b\w+\s*=\s*Blueprint\s*\(/u);
1129
+ const hasFlaskEntrypointConstruction = context.hasAnyFileMatchingPattern(/(^|\/)(app|main|wsgi)\.py$/iu, /\b\w+\s*=\s*Flask\s*\(/u);
1130
+ if (hasRequirementsFlask) {
1131
+ strongSignals += 1;
1132
+ score += 52;
1133
+ evidence.push('Found requirements.txt with flask dependency');
1134
+ }
1135
+ if (hasPyprojectFlask) {
1136
+ strongSignals += 1;
1137
+ score += 52;
1138
+ evidence.push('Found pyproject.toml with flask dependency');
1139
+ }
1140
+ if (hasPoetryLockFlask || hasPipfileFlask || hasPipfileLockFlask) {
1141
+ strongSignals += 1;
1142
+ score += 50;
1143
+ evidence.push('Found Pipfile/lock metadata with flask dependency');
1144
+ }
1145
+ if (hasFlaskImport) {
1146
+ strongSignals += 1;
1147
+ score += 34;
1148
+ evidence.push('Found Flask import in source');
1149
+ }
1150
+ if (hasFlaskConstruction) {
1151
+ strongSignals += 1;
1152
+ score += 34;
1153
+ evidence.push('Found Flask application construction in source');
1154
+ }
1155
+ if (hasRouteDecorator) {
1156
+ strongSignals += 1;
1157
+ score += 22;
1158
+ evidence.push('Found Flask route decorator in source');
1159
+ }
1160
+ if (hasMethodRouteDecorator) {
1161
+ mediumSignals += 1;
1162
+ score += 10;
1163
+ evidence.push('Found Flask method route decorator in source');
1164
+ }
1165
+ if (hasBlueprintImport) {
1166
+ mediumSignals += 1;
1167
+ score += 10;
1168
+ evidence.push('Found Blueprint import in source');
1169
+ }
1170
+ if (hasBlueprintConstruction) {
1171
+ mediumSignals += 1;
1172
+ score += 8;
1173
+ evidence.push('Found Blueprint construction in source');
1174
+ }
1175
+ if (hasFlaskEntrypointConstruction) {
1176
+ mediumSignals += 1;
1177
+ score += 8;
1178
+ evidence.push('Found Flask construction in app.py/main.py/wsgi.py');
1179
+ }
1180
+ if (context.hasDirectory('blueprints')) {
1181
+ weakSignals += 1;
1182
+ score += 2;
1183
+ evidence.push('Found blueprints directory');
1184
+ }
1185
+ if (context.hasDirectory('app') || context.hasDirectory('src')) {
1186
+ weakSignals += 1;
1187
+ score += 2;
1188
+ evidence.push('Found typical Python backend layout directory');
1189
+ }
1190
+ const hasSafeFlaskCoreEvidence = hasFlaskDependencyEvidence ||
1191
+ (hasFlaskImport && hasFlaskConstruction) ||
1192
+ (hasFlaskImport && (hasRouteDecorator || hasMethodRouteDecorator || hasBlueprintImport)) ||
1193
+ (hasBlueprintImport && hasBlueprintConstruction);
1194
+ if (!hasSafeFlaskCoreEvidence || strongSignals === 0) {
1195
+ return null;
1196
+ }
1197
+ const hasRestEvidence = hasRouteDecorator || hasMethodRouteDecorator || hasBlueprintImport;
1198
+ const confidence = strongSignals >= 2
1199
+ ? 'high'
1200
+ : strongSignals >= 1 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
1201
+ ? 'medium'
1202
+ : 'low';
1203
+ return toResult({
1204
+ adapterId: 'flask',
1205
+ confidence,
1206
+ score,
1207
+ evidence,
1208
+ projectKindHints: ['backend'],
1209
+ apiStyleHint: hasRestEvidence ? 'rest' : 'unknown',
1210
+ });
1211
+ },
1212
+ resolveProjectKinds: () => ['backend'],
1213
+ getImportExtractionMode: () => 'python-imports',
1214
+ }),
1215
+ python: buildAdapter({
1216
+ id: 'python',
1217
+ displayName: stackMetadata_1.canonicalStackLabels.python,
1218
+ ecosystem: 'python',
1219
+ category: 'generic-language',
1220
+ priority: 40,
1221
+ manifestDetectionHints: ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile'],
1222
+ buildToolHints: ['pip', 'poetry'],
1223
+ defaults: {
1224
+ sourceRoots: ['src/features', 'src/modules', 'src', '.'],
1225
+ moduleRootCandidates: ['src/features', 'src/modules', 'src', '.'],
1226
+ apiRoots: ['src', '.'],
1227
+ databaseRoots: ['migrations', 'alembic', 'db'],
1228
+ configFiles: ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile'],
1229
+ fileExtensions: ['.py'],
1230
+ dependencyFileExtensions: ['.py'],
1231
+ ignoreDirectories: [
1232
+ '__pycache__',
1233
+ '.venv',
1234
+ 'venv',
1235
+ '.idea',
1236
+ ...commonIgnoreDirectories,
1237
+ ],
1238
+ entrypointHints: ['app.py', 'main.py', '__init__.py'],
1239
+ publicEntrypointDirectories: [],
1240
+ moduleIndexFileName: '__init__.py',
1241
+ },
1242
+ detect: (context) => {
1243
+ const hasPythonSource = context.hasFileExtension('.py');
1244
+ const hasEntrypointEvidence = hasPythonEntrypointEvidence(context);
1245
+ const hasPackageEvidence = hasPythonPackageEvidence(context);
1246
+ const hasRuntimeDependencyEvidence = hasPythonRuntimeDependencyEvidence(context);
1247
+ const hasRuntimeOrSourceEvidence = hasPythonSource ||
1248
+ hasEntrypointEvidence ||
1249
+ hasPackageEvidence ||
1250
+ hasRuntimeDependencyEvidence;
1251
+ if (context.hasFile('pyproject.toml')) {
1252
+ const evidence = ['Found pyproject.toml'];
1253
+ if (hasPythonSource) {
1254
+ evidence.push('Found Python source files');
1255
+ }
1256
+ if (hasEntrypointEvidence) {
1257
+ evidence.push('Found Python application entrypoint');
1258
+ }
1259
+ if (hasPackageEvidence) {
1260
+ evidence.push('Found Python package source');
1261
+ }
1262
+ if (hasRuntimeDependencyEvidence) {
1263
+ evidence.push('Found Python runtime dependency evidence');
1264
+ }
1265
+ if (!hasRuntimeOrSourceEvidence) {
1266
+ evidence.push('Treating pyproject.toml as tooling metadata because no Python runtime/source evidence was found');
1267
+ }
1268
+ return toResult({
1269
+ adapterId: 'python',
1270
+ confidence: hasRuntimeOrSourceEvidence ? 'high' : 'low',
1271
+ score: hasRuntimeOrSourceEvidence ? 90 : 42,
1272
+ evidence,
1273
+ projectKindHints: ['backend', 'library'],
1274
+ });
1275
+ }
1276
+ if (context.hasFile('requirements.txt') || context.hasFile('setup.py')) {
1277
+ const evidence = [
1278
+ context.hasFile('requirements.txt') ? 'Found requirements.txt' : 'Found setup.py',
1279
+ ];
1280
+ if (hasPythonSource) {
1281
+ evidence.push('Found Python source files');
1282
+ }
1283
+ if (hasEntrypointEvidence) {
1284
+ evidence.push('Found Python application entrypoint');
1285
+ }
1286
+ if (hasPackageEvidence) {
1287
+ evidence.push('Found Python package source');
1288
+ }
1289
+ if (hasRuntimeDependencyEvidence) {
1290
+ evidence.push('Found Python runtime dependency evidence');
1291
+ }
1292
+ return toResult({
1293
+ adapterId: 'python',
1294
+ confidence: hasRuntimeOrSourceEvidence ? 'high' : 'medium',
1295
+ score: hasRuntimeOrSourceEvidence ? 86 : 58,
1296
+ evidence,
1297
+ projectKindHints: ['backend', 'library'],
1298
+ });
1299
+ }
1300
+ if (hasPythonSource) {
1301
+ return toResult({
1302
+ adapterId: 'python',
1303
+ confidence: 'medium',
1304
+ score: 62,
1305
+ evidence: ['Found .py source files'],
1306
+ projectKindHints: ['backend', 'library'],
1307
+ });
1308
+ }
1309
+ return null;
1310
+ },
1311
+ resolveProjectKinds: () => ['backend', 'library'],
1312
+ getImportExtractionMode: () => 'python-imports',
1313
+ }),
1314
+ laravel: buildAdapter({
1315
+ id: 'laravel',
1316
+ displayName: stackMetadata_1.canonicalStackLabels.laravel,
1317
+ ecosystem: 'php',
1318
+ category: 'framework',
1319
+ priority: 70,
1320
+ manifestDetectionHints: ['composer.json', 'artisan', 'web.php', 'api.php', 'app.php'],
1321
+ buildToolHints: ['composer', 'artisan'],
1322
+ defaults: {
1323
+ sourceRoots: ['app', 'routes', 'config'],
1324
+ moduleRootCandidates: ['app/Modules', 'app/Services', 'app/Http/Controllers', 'app'],
1325
+ apiRoots: ['routes', 'app/Http/Controllers'],
1326
+ databaseRoots: ['database', 'database/migrations'],
1327
+ configFiles: ['composer.json', 'artisan', 'config/app.php'],
1328
+ fileExtensions: ['.php'],
1329
+ dependencyFileExtensions: ['.php'],
1330
+ ignoreDirectories: [
1331
+ 'vendor',
1332
+ 'storage',
1333
+ 'bootstrap/cache',
1334
+ 'public',
1335
+ ...commonIgnoreDirectories,
1336
+ ],
1337
+ entrypointHints: ['artisan', 'public/index.php', 'bootstrap/app.php'],
1338
+ publicEntrypointDirectories: [],
1339
+ moduleIndexFileName: 'index.php',
1340
+ },
1341
+ detect: (context) => {
1342
+ const evidence = [];
1343
+ let strongSignals = 0;
1344
+ let mediumSignals = 0;
1345
+ let score = 0;
1346
+ const hasLaravelComposer = context.hasFileMatchingPattern('composer.json', /["']laravel\/framework["']/iu);
1347
+ const hasArtisan = context.hasFile('artisan');
1348
+ const hasRoutesWeb = context.hasAnyPathMatchingPattern(/(^|\/)routes\/web\.php$/iu);
1349
+ const hasRoutesApi = context.hasAnyPathMatchingPattern(/(^|\/)routes\/api\.php$/iu);
1350
+ const hasControllers = context.hasDirectory('app/Http/Controllers');
1351
+ const hasConfigApp = context.hasAnyPathMatchingPattern(/(^|\/)config\/app\.php$/iu);
1352
+ const hasConfigDatabase = context.hasAnyPathMatchingPattern(/(^|\/)config\/database\.php$/iu);
1353
+ const hasBootstrapApp = context.hasAnyPathMatchingPattern(/(^|\/)bootstrap\/app\.php$/iu);
1354
+ const hasAppHttp = context.hasDirectory('app/Http');
1355
+ const hasServiceProvider = context.hasAnyPathMatchingPattern(/(^|\/)app\/Providers\/.+ServiceProvider\.php$/iu);
1356
+ const hasLaravelRouteFacade = context.hasAnyFileMatchingPattern(/(^|\/)routes\/.+\.php$/iu, /\bRoute::(get|post|put|patch|delete|middleware|group)\s*\(/u);
1357
+ const hasMeaningfulApiRoute = context.hasAnyFileMatchingPattern(/(^|\/)routes\/api\.php$/iu, /\bRoute::(?:get|post|put|patch|delete|apiResource|resource)\s*\(\s*['"][^'"]*[A-Za-z0-9_{]/u);
1358
+ const hasApiMiddlewareOrPrefix = context.hasAnyFileMatchingPattern(/(^|\/)routes\/api\.php$/iu, /\bRoute::(?:middleware\s*\(\s*['"]api['"]|prefix\s*\(\s*['"]api(?:\/|['"]))/u);
1359
+ if (hasLaravelComposer) {
1360
+ strongSignals += 1;
1361
+ score += 50;
1362
+ evidence.push('Found composer.json with laravel/framework dependency');
1363
+ }
1364
+ if (hasArtisan) {
1365
+ strongSignals += 1;
1366
+ score += 18;
1367
+ evidence.push('Found artisan entrypoint');
1368
+ }
1369
+ if (hasRoutesWeb) {
1370
+ mediumSignals += 1;
1371
+ score += 10;
1372
+ evidence.push('Found routes/web.php');
1373
+ }
1374
+ if (hasRoutesApi) {
1375
+ mediumSignals += 1;
1376
+ score += 10;
1377
+ evidence.push('Found routes/api.php');
1378
+ }
1379
+ if (hasControllers) {
1380
+ mediumSignals += 1;
1381
+ score += 10;
1382
+ evidence.push('Found app/Http/Controllers directory');
1383
+ }
1384
+ if (hasAppHttp) {
1385
+ mediumSignals += 1;
1386
+ score += 8;
1387
+ evidence.push('Found app/Http directory');
1388
+ }
1389
+ if (hasConfigApp) {
1390
+ mediumSignals += 1;
1391
+ score += 6;
1392
+ evidence.push('Found config/app.php');
1393
+ }
1394
+ if (hasConfigDatabase) {
1395
+ mediumSignals += 1;
1396
+ score += 5;
1397
+ evidence.push('Found config/database.php');
1398
+ }
1399
+ if (hasBootstrapApp) {
1400
+ mediumSignals += 1;
1401
+ score += 7;
1402
+ evidence.push('Found bootstrap/app.php');
1403
+ }
1404
+ if (hasServiceProvider) {
1405
+ mediumSignals += 1;
1406
+ score += 6;
1407
+ evidence.push('Found Laravel service provider');
1408
+ }
1409
+ if (hasLaravelRouteFacade) {
1410
+ mediumSignals += 1;
1411
+ score += 8;
1412
+ evidence.push('Found Laravel Route facade usage');
1413
+ }
1414
+ if (!hasLaravelComposer ||
1415
+ !(hasArtisan || hasRoutesWeb || hasRoutesApi || hasControllers || hasAppHttp || hasConfigApp || hasConfigDatabase || hasBootstrapApp)) {
1416
+ return null;
1417
+ }
1418
+ return toResult({
1419
+ adapterId: 'laravel',
1420
+ confidence: strongSignals >= 2 || mediumSignals >= 2 ? 'high' : 'medium',
1421
+ score,
1422
+ evidence,
1423
+ projectKindHints: ['backend'],
1424
+ apiStyleHint: hasMeaningfulApiRoute || hasApiMiddlewareOrPrefix ? 'rest' : 'unknown',
1425
+ });
1426
+ },
1427
+ resolveProjectKinds: () => ['backend'],
1428
+ getImportExtractionMode: () => 'php-imports',
1429
+ }),
1430
+ php: buildAdapter({
1431
+ id: 'php',
1432
+ displayName: stackMetadata_1.canonicalStackLabels.php,
1433
+ ecosystem: 'php',
1434
+ category: 'generic-language',
1435
+ priority: 40,
1436
+ manifestDetectionHints: ['composer.json'],
1437
+ buildToolHints: ['composer'],
1438
+ defaults: {
1439
+ sourceRoots: ['app', 'src', '.'],
1440
+ moduleRootCandidates: ['app', 'src', '.'],
1441
+ apiRoots: ['app', 'public'],
1442
+ databaseRoots: ['database', 'migrations'],
1443
+ configFiles: ['composer.json'],
1444
+ fileExtensions: ['.php'],
1445
+ dependencyFileExtensions: ['.php'],
1446
+ ignoreDirectories: [
1447
+ 'vendor',
1448
+ 'storage',
1449
+ 'bootstrap/cache',
1450
+ 'public',
1451
+ ...commonIgnoreDirectories,
1452
+ ],
1453
+ entrypointHints: ['index.php', 'app.php', 'Application.php'],
1454
+ publicEntrypointDirectories: [],
1455
+ moduleIndexFileName: 'index.php',
1456
+ },
1457
+ detect: (context) => {
1458
+ if (!context.hasFile('composer.json')) {
1459
+ if (!context.hasFileExtension('.php')) {
1460
+ return null;
1461
+ }
1462
+ return toResult({
1463
+ adapterId: 'php',
1464
+ confidence: 'medium',
1465
+ score: 60,
1466
+ evidence: ['Found .php source files'],
1467
+ projectKindHints: ['backend', 'library'],
1468
+ });
1469
+ }
1470
+ return toResult({
1471
+ adapterId: 'php',
1472
+ confidence: 'high',
1473
+ score: 86,
1474
+ evidence: ['Found composer.json'],
1475
+ projectKindHints: ['backend', 'library'],
1476
+ });
1477
+ },
1478
+ resolveProjectKinds: () => ['backend', 'library'],
1479
+ getImportExtractionMode: () => 'php-imports',
1480
+ }),
1481
+ go: buildAdapter({
1482
+ id: 'go',
1483
+ displayName: stackMetadata_1.canonicalStackLabels.go,
1484
+ ecosystem: 'go',
1485
+ category: 'generic-language',
1486
+ priority: 40,
1487
+ manifestDetectionHints: ['go.mod', 'go.sum'],
1488
+ buildToolHints: ['go'],
1489
+ defaults: {
1490
+ sourceRoots: ['cmd', 'internal', 'pkg', '.'],
1491
+ moduleRootCandidates: ['internal', 'cmd', 'pkg', '.'],
1492
+ apiRoots: ['cmd', 'internal'],
1493
+ databaseRoots: ['internal/db', 'migrations'],
1494
+ configFiles: ['go.mod', 'go.sum'],
1495
+ fileExtensions: ['.go'],
1496
+ dependencyFileExtensions: ['.go'],
1497
+ ignoreDirectories: ['vendor', 'bin', ...commonIgnoreDirectories],
1498
+ entrypointHints: ['main.go', 'app.go'],
1499
+ publicEntrypointDirectories: [],
1500
+ moduleIndexFileName: 'main.go',
1501
+ },
1502
+ detect: (context) => {
1503
+ const hasGoSource = context.hasFileExtension('.go');
1504
+ const hasEntrypointEvidence = hasGoEntrypointEvidence(context);
1505
+ const hasServerDependencyEvidence = hasGoServerDependencyEvidence(context);
1506
+ if (!context.hasFile('go.mod')) {
1507
+ if (!hasGoSource) {
1508
+ return null;
1509
+ }
1510
+ return toResult({
1511
+ adapterId: 'go',
1512
+ confidence: 'medium',
1513
+ score: 60,
1514
+ evidence: ['Found .go source files'],
1515
+ projectKindHints: ['backend', 'library'],
1516
+ });
1517
+ }
1518
+ const evidence = ['Found go.mod'];
1519
+ let score = 86;
1520
+ if (hasGoSource) {
1521
+ score += 4;
1522
+ evidence.push('Found Go source files');
1523
+ }
1524
+ if (hasEntrypointEvidence) {
1525
+ score += 5;
1526
+ evidence.push('Found Go application entrypoint');
1527
+ }
1528
+ if (context.hasDirectory('cmd')) {
1529
+ score += 2;
1530
+ evidence.push('Found Go cmd/ entrypoint directory');
1531
+ }
1532
+ if (hasServerDependencyEvidence) {
1533
+ score += 2;
1534
+ evidence.push('Found Go server/router dependency evidence');
1535
+ }
1536
+ return toResult({
1537
+ adapterId: 'go',
1538
+ confidence: 'high',
1539
+ score: Math.min(score, 99),
1540
+ evidence,
1541
+ projectKindHints: ['backend', 'library'],
1542
+ });
1543
+ },
1544
+ resolveProjectKinds: () => ['backend', 'library'],
1545
+ getImportExtractionMode: () => 'go-imports',
1546
+ }),
1547
+ dotnet: buildAdapter({
1548
+ id: 'dotnet',
1549
+ displayName: stackMetadata_1.canonicalStackLabels.dotnet,
1550
+ ecosystem: 'dotnet',
1551
+ category: 'framework',
1552
+ priority: 70,
1553
+ manifestDetectionHints: [
1554
+ 'Program.cs',
1555
+ 'appsettings.json',
1556
+ 'appsettings.Development.json',
1557
+ 'launchSettings.json',
1558
+ ],
1559
+ buildToolHints: ['dotnet'],
1560
+ defaults: {
1561
+ sourceRoots: ['.'],
1562
+ moduleRootCandidates: ['Controllers', 'Features', 'Modules', 'src'],
1563
+ apiRoots: ['Controllers', 'Endpoints', 'src', '.'],
1564
+ databaseRoots: ['Migrations', 'Data', 'Persistence', 'Infrastructure', 'src'],
1565
+ configFiles: [
1566
+ '*.sln',
1567
+ '*.csproj',
1568
+ 'Program.cs',
1569
+ 'appsettings.json',
1570
+ 'appsettings.Development.json',
1571
+ 'Properties/launchSettings.json',
1572
+ ],
1573
+ fileExtensions: ['.cs', '.json', '.sql', '.http'],
1574
+ dependencyFileExtensions: ['.cs'],
1575
+ ignoreDirectories: ['bin', 'obj', '.vs', ...commonIgnoreDirectories],
1576
+ entrypointHints: ['Program.cs'],
1577
+ publicEntrypointDirectories: [],
1578
+ moduleIndexFileName: 'Program.cs',
1579
+ },
1580
+ detect: (context) => {
1581
+ const evidence = [];
1582
+ let strongSignals = 0;
1583
+ let mediumSignals = 0;
1584
+ let weakSignals = 0;
1585
+ let score = 0;
1586
+ const hasCsproj = context.hasAnyPathMatchingPattern(/(^|\/)[^/]+\.csproj$/iu);
1587
+ const hasSln = context.hasAnyPathMatchingPattern(/(^|\/)[^/]+\.sln$/iu);
1588
+ const hasProgramCs = context.hasFile('Program.cs');
1589
+ const hasWebSdkCsproj = context.hasAnyFileMatchingPattern(/(^|\/)[^/]+\.csproj$/iu, /\bMicrosoft\.NET\.Sdk\.Web\b/u);
1590
+ const hasAspNetPackageReference = context.hasAnyFileMatchingPattern(/(^|\/)[^/]+\.csproj$/iu, /\b(Microsoft\.AspNetCore\.[A-Za-z0-9.]+|Swashbuckle\.AspNetCore|Microsoft\.AspNetCore\.OpenApi)\b/u) ||
1591
+ context.hasAnyFileMatchingPattern(/\.cs$/iu, /\busing\s+Microsoft\.AspNetCore\.[A-Za-z0-9.]+;/u);
1592
+ const hasBuilderServices = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\bbuilder\.Services\b/u);
1593
+ const hasCreateBuilder = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\bWebApplication\.CreateBuilder\s*\(/u);
1594
+ const hasMinimalApiMapping = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\bapp\.(MapGet|MapPost)\s*\(/u);
1595
+ const hasMapControllers = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\bapp\.MapControllers\s*\(/u);
1596
+ const hasApiController = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\[ApiController\]/u);
1597
+ const hasRouteAttribute = context.hasAnyFileMatchingPattern(/\.cs$/iu, /\[Route\s*\(/u);
1598
+ const hasAppSettingsWithDotnetEvidence = context.hasFile('appsettings.json') && (hasCsproj || hasProgramCs || hasWebSdkCsproj || hasAspNetPackageReference);
1599
+ const hasControllersDirectory = context.hasDirectory('Controllers');
1600
+ const hasLaunchSettings = context.hasAnyPathMatchingPattern(/(^|\/)Properties\/launchSettings\.json$/iu);
1601
+ const hasAppSettingsDevelopment = context.hasFile('appsettings.Development.json');
1602
+ const hasWwwroot = context.hasDirectory('wwwroot');
1603
+ const hasTypicalDotnetLayout = context.hasDirectory('Properties') ||
1604
+ context.hasDirectory('Features') ||
1605
+ context.hasDirectory('Modules') ||
1606
+ context.hasDirectory('Endpoints') ||
1607
+ context.hasDirectory('Migrations');
1608
+ if (hasCsproj) {
1609
+ strongSignals += 1;
1610
+ score += 54;
1611
+ evidence.push('Found one or more .csproj files');
1612
+ }
1613
+ if (hasSln && hasCsproj) {
1614
+ strongSignals += 1;
1615
+ score += 26;
1616
+ evidence.push('Found .sln with .csproj project files');
1617
+ }
1618
+ if (hasProgramCs) {
1619
+ strongSignals += 1;
1620
+ score += 28;
1621
+ evidence.push('Found Program.cs');
1622
+ }
1623
+ if (hasWebSdkCsproj) {
1624
+ strongSignals += 1;
1625
+ score += 42;
1626
+ evidence.push('Found csproj using Microsoft.NET.Sdk.Web');
1627
+ }
1628
+ if (hasAspNetPackageReference) {
1629
+ strongSignals += 1;
1630
+ score += 34;
1631
+ evidence.push('Found ASP.NET/OpenAPI package evidence');
1632
+ }
1633
+ if (hasBuilderServices) {
1634
+ strongSignals += 1;
1635
+ score += 16;
1636
+ evidence.push('Found builder.Services usage');
1637
+ }
1638
+ if (hasCreateBuilder) {
1639
+ strongSignals += 1;
1640
+ score += 18;
1641
+ evidence.push('Found WebApplication.CreateBuilder usage');
1642
+ }
1643
+ if (hasMinimalApiMapping) {
1644
+ strongSignals += 1;
1645
+ score += 20;
1646
+ evidence.push('Found minimal API route mapping in source');
1647
+ }
1648
+ if (hasMapControllers) {
1649
+ strongSignals += 1;
1650
+ score += 18;
1651
+ evidence.push('Found app.MapControllers usage');
1652
+ }
1653
+ if (hasApiController) {
1654
+ strongSignals += 1;
1655
+ score += 16;
1656
+ evidence.push('Found [ApiController] attribute');
1657
+ }
1658
+ if (hasRouteAttribute) {
1659
+ strongSignals += 1;
1660
+ score += 12;
1661
+ evidence.push('Found [Route(...)] attribute');
1662
+ }
1663
+ if (hasAppSettingsWithDotnetEvidence) {
1664
+ strongSignals += 1;
1665
+ score += 12;
1666
+ evidence.push('Found appsettings.json with .NET backend evidence');
1667
+ }
1668
+ if (hasControllersDirectory) {
1669
+ mediumSignals += 1;
1670
+ score += 8;
1671
+ evidence.push('Found Controllers directory');
1672
+ }
1673
+ if (hasLaunchSettings) {
1674
+ mediumSignals += 1;
1675
+ score += 8;
1676
+ evidence.push('Found Properties/launchSettings.json');
1677
+ }
1678
+ if (hasAppSettingsDevelopment) {
1679
+ mediumSignals += 1;
1680
+ score += 5;
1681
+ evidence.push('Found appsettings.Development.json');
1682
+ }
1683
+ if (hasWwwroot) {
1684
+ mediumSignals += 1;
1685
+ score += 2;
1686
+ evidence.push('Found wwwroot directory as supporting evidence');
1687
+ }
1688
+ if (hasTypicalDotnetLayout) {
1689
+ weakSignals += 1;
1690
+ score += 2;
1691
+ evidence.push('Found typical .NET backend layout directory');
1692
+ }
1693
+ const hasApiEvidence = hasMinimalApiMapping ||
1694
+ hasMapControllers ||
1695
+ hasApiController ||
1696
+ hasRouteAttribute ||
1697
+ hasControllersDirectory;
1698
+ const hasSafeDotnetCoreEvidence = hasCsproj && (hasProgramCs ||
1699
+ hasWebSdkCsproj ||
1700
+ hasAspNetPackageReference ||
1701
+ hasCreateBuilder ||
1702
+ hasBuilderServices ||
1703
+ hasApiEvidence);
1704
+ if (!hasSafeDotnetCoreEvidence) {
1705
+ return null;
1706
+ }
1707
+ const confidence = strongSignals >= 3
1708
+ ? 'high'
1709
+ : strongSignals >= 2 || mediumSignals >= 3 || (mediumSignals >= 2 && weakSignals >= 1)
1710
+ ? 'medium'
1711
+ : 'low';
1712
+ return toResult({
1713
+ adapterId: 'dotnet',
1714
+ confidence,
1715
+ score,
1716
+ evidence,
1717
+ projectKindHints: ['backend'],
1718
+ apiStyleHint: hasApiEvidence ? 'rest' : 'unknown',
1719
+ });
1720
+ },
1721
+ resolveProjectKinds: () => ['backend'],
1722
+ getImportExtractionMode: () => 'csharp-imports',
1723
+ }),
1724
+ ruby_rails: buildAdapter({
1725
+ id: 'ruby_rails',
1726
+ displayName: stackMetadata_1.canonicalStackLabels.ruby_rails,
1727
+ ecosystem: 'other',
1728
+ category: 'framework',
1729
+ priority: 70,
1730
+ manifestDetectionHints: ['Gemfile', 'rails', 'routes.rb', 'application.rb'],
1731
+ buildToolHints: ['bundle'],
1732
+ defaults: {
1733
+ sourceRoots: ['app', 'config'],
1734
+ moduleRootCandidates: ['app/services', 'app/controllers', 'app/models', 'app'],
1735
+ apiRoots: ['app/controllers', 'config/routes.rb'],
1736
+ databaseRoots: ['db'],
1737
+ configFiles: ['Gemfile', 'config/routes.rb', 'config/application.rb'],
1738
+ fileExtensions: ['.rb'],
1739
+ dependencyFileExtensions: ['.rb'],
1740
+ ignoreDirectories: ['vendor', 'tmp', 'log', ...commonIgnoreDirectories],
1741
+ entrypointHints: ['config/application.rb'],
1742
+ publicEntrypointDirectories: [],
1743
+ moduleIndexFileName: 'application.rb',
1744
+ },
1745
+ detect: (context) => {
1746
+ const evidence = [];
1747
+ let strongSignals = 0;
1748
+ let mediumSignals = 0;
1749
+ let score = 0;
1750
+ const hasRailsGem = context.hasFileMatchingPattern('Gemfile', /\bgem\s+['"]rails['"]/u);
1751
+ const hasBinRails = context.hasAnyPathMatchingPattern(/(^|\/)bin\/rails$/u);
1752
+ const hasRoutes = context.hasAnyPathMatchingPattern(/(^|\/)config\/routes\.rb$/u);
1753
+ const hasControllers = context.hasDirectory('app/controllers');
1754
+ const hasModels = context.hasDirectory('app/models');
1755
+ const hasServices = context.hasDirectory('app/services');
1756
+ const hasRailsRoutesDraw = context.hasFileMatchingPattern('routes.rb', /\bRails\.application\.routes\.draw\b/u);
1757
+ const hasApplicationClass = context.hasAnyFileMatchingPattern(/(^|\/)config\/application\.rb$/u, /\bclass\s+Application\s+<\s+Rails::Application\b/u);
1758
+ const hasApplicationController = context.hasAnyFileMatchingPattern(/(^|\/)app\/controllers\/.+\.rb$/u, /\bApplicationController\b/u);
1759
+ if (hasRailsGem) {
1760
+ strongSignals += 1;
1761
+ score += 48;
1762
+ evidence.push('Found Gemfile with rails gem');
1763
+ }
1764
+ if (hasBinRails) {
1765
+ strongSignals += 1;
1766
+ score += 18;
1767
+ evidence.push('Found bin/rails');
1768
+ }
1769
+ if (hasRoutes) {
1770
+ mediumSignals += 1;
1771
+ score += 10;
1772
+ evidence.push('Found config/routes.rb');
1773
+ }
1774
+ if (hasControllers) {
1775
+ mediumSignals += 1;
1776
+ score += 8;
1777
+ evidence.push('Found app/controllers directory');
1778
+ }
1779
+ if (hasModels) {
1780
+ mediumSignals += 1;
1781
+ score += 6;
1782
+ evidence.push('Found app/models directory');
1783
+ }
1784
+ if (hasServices) {
1785
+ mediumSignals += 1;
1786
+ score += 5;
1787
+ evidence.push('Found app/services directory');
1788
+ }
1789
+ if (hasRailsRoutesDraw) {
1790
+ mediumSignals += 1;
1791
+ score += 8;
1792
+ evidence.push('Found Rails routes draw block');
1793
+ }
1794
+ if (hasApplicationClass) {
1795
+ mediumSignals += 1;
1796
+ score += 8;
1797
+ evidence.push('Found Rails application class');
1798
+ }
1799
+ if (hasApplicationController) {
1800
+ mediumSignals += 1;
1801
+ score += 5;
1802
+ evidence.push('Found ApplicationController inheritance');
1803
+ }
1804
+ if (!hasRailsGem || !(hasBinRails || hasRoutes || hasControllers || hasApplicationClass)) {
1805
+ return null;
1806
+ }
1807
+ return toResult({
1808
+ adapterId: 'ruby_rails',
1809
+ confidence: strongSignals >= 2 || mediumSignals >= 3 ? 'high' : 'medium',
1810
+ score,
1811
+ evidence,
1812
+ projectKindHints: ['backend'],
1813
+ apiStyleHint: hasRoutes || hasControllers ? 'rest' : 'unknown',
1814
+ });
1815
+ },
1816
+ resolveProjectKinds: () => ['backend'],
1817
+ getImportExtractionMode: () => 'generic',
1818
+ }),
1819
+ kotlin: buildAdapter({
1820
+ id: 'kotlin',
1821
+ displayName: stackMetadata_1.canonicalStackLabels.kotlin,
1822
+ ecosystem: 'jvm',
1823
+ category: 'generic-language',
1824
+ priority: 40,
1825
+ manifestDetectionHints: ['build.gradle.kts', 'pom.xml', 'settings.gradle.kts'],
1826
+ buildToolHints: ['gradle', 'maven'],
1827
+ defaults: {
1828
+ sourceRoots: ['src/main/kotlin', 'src'],
1829
+ moduleRootCandidates: ['src/main/kotlin', 'src'],
1830
+ apiRoots: ['src/main/kotlin'],
1831
+ databaseRoots: ['src/main/resources/db', 'src/main/resources/migrations'],
1832
+ configFiles: ['build.gradle.kts', 'pom.xml', 'settings.gradle.kts'],
1833
+ fileExtensions: ['.kt', '.kts'],
1834
+ dependencyFileExtensions: ['.kt', '.kts'],
1835
+ ignoreDirectories: [
1836
+ 'target',
1837
+ 'build',
1838
+ '.gradle',
1839
+ '.idea',
1840
+ 'out',
1841
+ ...commonIgnoreDirectories,
1842
+ ],
1843
+ entrypointHints: ['Application.kt', 'Main.kt'],
1844
+ publicEntrypointDirectories: [],
1845
+ moduleIndexFileName: 'Application.kt',
1846
+ },
1847
+ detect: (context) => {
1848
+ const evidence = [];
1849
+ let score = 0;
1850
+ const hasBuildGradleKts = context.hasFile('build.gradle.kts');
1851
+ const hasSettingsGradleKts = context.hasFile('settings.gradle.kts');
1852
+ const hasKotlinPluginInGradle = context.hasFileMatchingPattern('build.gradle.kts', /\bkotlin\s*\(\s*["']jvm["']\s*\)/u) ||
1853
+ context.hasFileMatchingPattern('build.gradle.kts', /\bid\s*\(\s*["']org\.jetbrains\.kotlin\.jvm["']\s*\)/u);
1854
+ const hasPomKotlinPlugin = context.hasFileMatchingPattern('pom.xml', /\bkotlin-maven-plugin\b/u) ||
1855
+ context.hasFileMatchingPattern('pom.xml', /\borg\.jetbrains\.kotlin\b/u);
1856
+ const hasKotlinSourceRoot = context.hasDirectory('src/main/kotlin');
1857
+ const hasKtFiles = context.hasFileExtension('.kt') || context.hasFileExtension('.kts');
1858
+ const hasKotlinPackageShape = context.hasDirectory('src/main/kotlin/com') || context.hasDirectory('src/main/kotlin/org');
1859
+ if (hasBuildGradleKts) {
1860
+ score += 30;
1861
+ evidence.push('Found build.gradle.kts');
1862
+ }
1863
+ if (hasSettingsGradleKts) {
1864
+ score += 8;
1865
+ evidence.push('Found settings.gradle.kts');
1866
+ }
1867
+ if (hasKotlinPluginInGradle) {
1868
+ score += 32;
1869
+ evidence.push('Found Kotlin JVM plugin in build.gradle.kts');
1870
+ }
1871
+ if (hasPomKotlinPlugin) {
1872
+ score += 32;
1873
+ evidence.push('Found Kotlin Maven plugin markers in pom.xml');
1874
+ }
1875
+ if (hasKotlinSourceRoot) {
1876
+ score += 18;
1877
+ evidence.push('Found src/main/kotlin source root');
1878
+ }
1879
+ if (hasKtFiles) {
1880
+ score += 16;
1881
+ evidence.push('Found Kotlin source files');
1882
+ }
1883
+ if (hasKotlinPackageShape) {
1884
+ score += 4;
1885
+ evidence.push('Found conventional Kotlin package directory under src/main/kotlin');
1886
+ }
1887
+ const hasSafeKotlinEvidence = hasKtFiles &&
1888
+ (hasBuildGradleKts || hasKotlinPluginInGradle || hasPomKotlinPlugin || hasKotlinSourceRoot);
1889
+ if (!hasSafeKotlinEvidence) {
1890
+ return null;
1891
+ }
1892
+ return toResult({
1893
+ adapterId: 'kotlin',
1894
+ confidence: (hasKotlinPluginInGradle || hasPomKotlinPlugin) && hasKotlinSourceRoot
1895
+ ? 'high'
1896
+ : hasBuildGradleKts || hasKotlinSourceRoot
1897
+ ? 'medium'
1898
+ : 'low',
1899
+ score,
1900
+ evidence,
1901
+ projectKindHints: ['backend', 'library'],
1902
+ apiStyleHint: 'unknown',
1903
+ });
1904
+ },
1905
+ resolveProjectKinds: () => ['backend', 'library'],
1906
+ getImportExtractionMode: () => 'generic',
1907
+ }),
1908
+ kotlin_spring: buildAdapter({
1909
+ id: 'kotlin_spring',
1910
+ displayName: stackMetadata_1.canonicalStackLabels.kotlin_spring,
1911
+ ecosystem: 'jvm',
1912
+ category: 'framework',
1913
+ priority: 20,
1914
+ manifestDetectionHints: ['build.gradle.kts'],
1915
+ buildToolHints: ['gradle'],
1916
+ defaults: {
1917
+ sourceRoots: ['src/main/kotlin'],
1918
+ moduleRootCandidates: ['src/main/kotlin'],
1919
+ apiRoots: ['src/main/kotlin'],
1920
+ databaseRoots: ['src/main/resources/db'],
1921
+ configFiles: ['build.gradle.kts'],
1922
+ fileExtensions: ['.kt'],
1923
+ dependencyFileExtensions: ['.kt'],
1924
+ ignoreDirectories: [...commonIgnoreDirectories],
1925
+ entrypointHints: ['Application.kt'],
1926
+ publicEntrypointDirectories: [],
1927
+ moduleIndexFileName: 'Application.kt',
1928
+ },
1929
+ detect: () => null,
1930
+ getImportExtractionMode: () => 'generic',
1931
+ }),
1932
+ rust: buildAdapter({
1933
+ id: 'rust',
1934
+ displayName: stackMetadata_1.canonicalStackLabels.rust,
1935
+ ecosystem: 'other',
1936
+ category: 'generic-language',
1937
+ priority: 20,
1938
+ manifestDetectionHints: ['Cargo.toml'],
1939
+ buildToolHints: ['cargo'],
1940
+ defaults: {
1941
+ sourceRoots: ['src'],
1942
+ moduleRootCandidates: ['src'],
1943
+ apiRoots: ['src'],
1944
+ databaseRoots: ['migrations'],
1945
+ configFiles: ['Cargo.toml'],
1946
+ fileExtensions: ['.rs'],
1947
+ dependencyFileExtensions: ['.rs'],
1948
+ ignoreDirectories: [...commonIgnoreDirectories],
1949
+ entrypointHints: ['main.rs', 'lib.rs'],
1950
+ publicEntrypointDirectories: [],
1951
+ moduleIndexFileName: 'main.rs',
1952
+ },
1953
+ detect: () => null,
1954
+ getImportExtractionMode: () => 'generic',
1955
+ }),
1956
+ react: buildAdapter({
1957
+ id: 'react',
1958
+ displayName: stackMetadata_1.canonicalStackLabels.react,
1959
+ ecosystem: 'node',
1960
+ category: 'framework',
1961
+ priority: 80,
1962
+ manifestDetectionHints: [
1963
+ 'package.json',
1964
+ 'vite.config.ts',
1965
+ 'vite.config.js',
1966
+ 'webpack.config.js',
1967
+ 'tsconfig.json',
1968
+ ],
1969
+ buildToolHints: ['npm', 'yarn', 'pnpm', 'vite', 'webpack'],
1970
+ defaults: {
1971
+ sourceRoots: ['src', '.'],
1972
+ moduleRootCandidates: ['src', '.'],
1973
+ apiRoots: ['src/api', 'api'],
1974
+ databaseRoots: ['prisma', 'db'],
1975
+ configFiles: ['package.json', 'vite.config.ts', 'vite.config.js', 'webpack.config.js'],
1976
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx'],
1977
+ dependencyFileExtensions: ['.ts', '.tsx', '.js', '.jsx'],
1978
+ ignoreDirectories: ['.next', ...commonIgnoreDirectories],
1979
+ entrypointHints: ['main.tsx', 'main.jsx', 'index.tsx', 'index.jsx', 'App.tsx', 'App.jsx'],
1980
+ publicEntrypointDirectories: [],
1981
+ moduleIndexFileName: 'index.tsx',
1982
+ },
1983
+ detect: (context) => {
1984
+ if (!context.hasPackageDependency('react')) {
1985
+ return null;
1986
+ }
1987
+ const hasViteConfig = context.hasFile('vite.config.ts') || context.hasFile('vite.config.js');
1988
+ const hasWebpackConfig = context.hasFile('webpack.config.js');
1989
+ const confidence = hasViteConfig || hasWebpackConfig ? 'high' : 'medium';
1990
+ const score = hasViteConfig || hasWebpackConfig ? 92 : 72;
1991
+ const evidence = ['Found package.json with react dependency'];
1992
+ if (hasViteConfig) {
1993
+ evidence.push('Found vite.config.js or vite.config.ts');
1994
+ }
1995
+ if (hasWebpackConfig) {
1996
+ evidence.push('Found webpack.config.js');
1997
+ }
1998
+ return toResult({
1999
+ adapterId: 'react',
2000
+ confidence,
2001
+ score,
2002
+ evidence,
2003
+ projectKindHints: ['frontend'],
2004
+ });
2005
+ },
2006
+ resolveProjectKinds: () => ['frontend'],
2007
+ getImportExtractionMode: () => 'js-imports',
2008
+ }),
2009
+ angular: buildAdapter({
2010
+ id: 'angular',
2011
+ displayName: stackMetadata_1.canonicalStackLabels.angular,
2012
+ ecosystem: 'node',
2013
+ category: 'framework',
2014
+ priority: 75,
2015
+ manifestDetectionHints: [
2016
+ 'angular.json',
2017
+ 'package.json',
2018
+ 'tsconfig.app.json',
2019
+ 'polyfills.ts',
2020
+ 'main.ts',
2021
+ ],
2022
+ buildToolHints: ['npm', 'yarn', 'pnpm'],
2023
+ defaults: {
2024
+ sourceRoots: ['src'],
2025
+ moduleRootCandidates: ['src/app'],
2026
+ apiRoots: [],
2027
+ databaseRoots: [],
2028
+ configFiles: ['angular.json', 'tsconfig.json', 'package.json'],
2029
+ fileExtensions: ['.ts', '.html', '.scss', '.css'],
2030
+ dependencyFileExtensions: ['.ts'],
2031
+ ignoreDirectories: ['node_modules', 'dist', 'coverage'],
2032
+ entrypointHints: ['src/main.ts'],
2033
+ publicEntrypointDirectories: [],
2034
+ moduleIndexFileName: 'main.ts',
2035
+ },
2036
+ detect: (context) => {
2037
+ const evidence = [];
2038
+ let strongSignals = 0;
2039
+ let mediumSignals = 0;
2040
+ let score = 0;
2041
+ if (context.hasFile('angular.json')) {
2042
+ strongSignals += 1;
2043
+ score += 28;
2044
+ evidence.push('Found angular.json');
2045
+ }
2046
+ if (context.hasPackageDependency('@angular/core')) {
2047
+ strongSignals += 1;
2048
+ score += 24;
2049
+ evidence.push('Found package.json with @angular/core dependency');
2050
+ }
2051
+ if (context.hasPackageDependency('@angular/cli')) {
2052
+ strongSignals += 1;
2053
+ score += 22;
2054
+ evidence.push('Found package.json with @angular/cli dependency');
2055
+ }
2056
+ if (context.hasDirectory('src/app')) {
2057
+ strongSignals += 1;
2058
+ score += 16;
2059
+ evidence.push('Found src/app directory');
2060
+ }
2061
+ if (context.hasFileMatchingPattern('main.ts', /\b(bootstrapApplication|platformBrowserDynamic|bootstrapModule)\s*\(/u)) {
2062
+ strongSignals += 1;
2063
+ score += 20;
2064
+ evidence.push('Found Angular bootstrap in main.ts');
2065
+ }
2066
+ if (context.hasFile('tsconfig.app.json')) {
2067
+ mediumSignals += 1;
2068
+ score += 8;
2069
+ evidence.push('Found tsconfig.app.json');
2070
+ }
2071
+ if (context.hasDirectory('projects')) {
2072
+ mediumSignals += 1;
2073
+ score += 7;
2074
+ evidence.push('Found projects/ workspace directory');
2075
+ }
2076
+ if (context.hasFile('polyfills.ts')) {
2077
+ mediumSignals += 1;
2078
+ score += 6;
2079
+ evidence.push('Found polyfills.ts');
2080
+ }
2081
+ if (context.hasDirectory('src/environments')) {
2082
+ mediumSignals += 1;
2083
+ score += 6;
2084
+ evidence.push('Found src/environments directory');
2085
+ }
2086
+ if (strongSignals === 0) {
2087
+ return null;
2088
+ }
2089
+ const confidence = strongSignals >= 2 ? 'high' : strongSignals >= 1 || mediumSignals >= 3 ? 'medium' : 'low';
2090
+ return toResult({
2091
+ adapterId: 'angular',
2092
+ confidence,
2093
+ score,
2094
+ evidence,
2095
+ projectKindHints: ['frontend'],
2096
+ apiStyleHint: 'none',
2097
+ });
2098
+ },
2099
+ resolveProjectKinds: () => ['frontend'],
2100
+ getImportExtractionMode: () => 'js-imports',
2101
+ }),
2102
+ vue: buildAdapter({
2103
+ id: 'vue',
2104
+ displayName: stackMetadata_1.canonicalStackLabels.vue,
2105
+ ecosystem: 'node',
2106
+ category: 'framework',
2107
+ priority: 75,
2108
+ manifestDetectionHints: [
2109
+ 'package.json',
2110
+ 'vite.config.ts',
2111
+ 'vite.config.js',
2112
+ 'App.vue',
2113
+ 'main.ts',
2114
+ 'main.js',
2115
+ 'tsconfig.app.json',
2116
+ ],
2117
+ buildToolHints: ['npm', 'yarn', 'pnpm', 'vite'],
2118
+ defaults: {
2119
+ sourceRoots: ['src'],
2120
+ moduleRootCandidates: ['src/components', 'src/views'],
2121
+ apiRoots: [],
2122
+ databaseRoots: [],
2123
+ configFiles: ['vite.config.ts', 'vite.config.js', 'package.json', 'tsconfig.json'],
2124
+ fileExtensions: ['.ts', '.js', '.vue', '.css', '.scss'],
2125
+ dependencyFileExtensions: ['.ts', '.js', '.vue'],
2126
+ ignoreDirectories: ['node_modules', 'dist', 'coverage'],
2127
+ entrypointHints: ['src/main.ts', 'src/main.js'],
2128
+ publicEntrypointDirectories: [],
2129
+ moduleIndexFileName: 'main.ts',
2130
+ },
2131
+ detect: (context) => {
2132
+ const hasVueDependency = context.hasPackageDependency('vue');
2133
+ const hasAppVue = context.hasFile('App.vue');
2134
+ const hasSrcComponents = context.hasDirectory('src/components');
2135
+ const hasVitePluginInConfig = context.hasFileMatchingPattern('vite.config.ts', /\b(plugin-vue|@vitejs\/plugin-vue)\b/iu) ||
2136
+ context.hasFileMatchingPattern('vite.config.js', /\b(plugin-vue|@vitejs\/plugin-vue)\b/iu);
2137
+ const hasVitePluginDependency = context.hasPackageDependency('@vitejs/plugin-vue');
2138
+ const hasSrcViews = context.hasDirectory('src/views');
2139
+ const hasSrcRouter = context.hasDirectory('src/router');
2140
+ const hasSrcMainTs = context.getPaths('main.ts').some((value) => value === 'src/main.ts');
2141
+ const hasSrcMainJs = context.getPaths('main.js').some((value) => value === 'src/main.js');
2142
+ const hasCreateAppReference = (hasSrcMainTs && context.hasFileMatchingPattern('main.ts', /\bcreateApp\s*\(/u)) ||
2143
+ (hasSrcMainJs && context.hasFileMatchingPattern('main.js', /\bcreateApp\s*\(/u));
2144
+ const hasViteConfig = context.hasFile('vite.config.ts') || context.hasFile('vite.config.js');
2145
+ const hasTsConfigApp = context.hasFile('tsconfig.app.json');
2146
+ const hasSrcAssets = context.hasDirectory('src/assets');
2147
+ const evidence = [];
2148
+ let strongSignals = 0;
2149
+ let mediumSignals = 0;
2150
+ let weakSignals = 0;
2151
+ let score = 0;
2152
+ if (hasVueDependency) {
2153
+ strongSignals += 1;
2154
+ score += 30;
2155
+ evidence.push('Found package.json with vue dependency');
2156
+ }
2157
+ if (hasAppVue) {
2158
+ strongSignals += 1;
2159
+ score += 22;
2160
+ evidence.push('Found App.vue');
2161
+ }
2162
+ if (hasSrcComponents) {
2163
+ strongSignals += 1;
2164
+ score += 14;
2165
+ evidence.push('Found src/components directory');
2166
+ }
2167
+ if (hasVitePluginInConfig) {
2168
+ strongSignals += 1;
2169
+ score += 24;
2170
+ evidence.push('Found Vue plugin usage in vite.config.ts or vite.config.js');
2171
+ }
2172
+ if (hasVitePluginDependency) {
2173
+ strongSignals += 1;
2174
+ score += 22;
2175
+ evidence.push('Found package.json with @vitejs/plugin-vue dependency');
2176
+ }
2177
+ if (hasSrcViews) {
2178
+ mediumSignals += 1;
2179
+ score += 8;
2180
+ evidence.push('Found src/views directory');
2181
+ }
2182
+ if (hasSrcRouter) {
2183
+ mediumSignals += 1;
2184
+ score += 8;
2185
+ evidence.push('Found src/router directory');
2186
+ }
2187
+ if (hasCreateAppReference) {
2188
+ mediumSignals += 1;
2189
+ score += 12;
2190
+ evidence.push('Found createApp usage in src/main.ts or src/main.js');
2191
+ }
2192
+ if (hasViteConfig && hasVueDependency) {
2193
+ mediumSignals += 1;
2194
+ score += 8;
2195
+ evidence.push('Found vite.config.ts or vite.config.js with Vue package evidence');
2196
+ }
2197
+ if (hasTsConfigApp) {
2198
+ weakSignals += 1;
2199
+ score += 4;
2200
+ evidence.push('Found tsconfig.app.json');
2201
+ }
2202
+ if (hasSrcAssets) {
2203
+ weakSignals += 1;
2204
+ score += 3;
2205
+ evidence.push('Found src/assets directory');
2206
+ }
2207
+ const hasSafeCoreEvidence = (hasVueDependency && (hasAppVue || hasCreateAppReference || hasVitePluginDependency || hasVitePluginInConfig)) ||
2208
+ (hasAppVue && (hasCreateAppReference || hasSrcComponents || hasVueDependency)) ||
2209
+ (hasVitePluginDependency && hasVitePluginInConfig && hasCreateAppReference);
2210
+ if (!hasSafeCoreEvidence) {
2211
+ return null;
2212
+ }
2213
+ const confidence = strongSignals >= 2
2214
+ ? 'high'
2215
+ : strongSignals >= 1 || mediumSignals >= 2 || (mediumSignals >= 1 && weakSignals >= 2)
2216
+ ? 'medium'
2217
+ : 'low';
2218
+ return toResult({
2219
+ adapterId: 'vue',
2220
+ confidence,
2221
+ score,
2222
+ evidence,
2223
+ projectKindHints: ['frontend'],
2224
+ apiStyleHint: 'none',
2225
+ });
2226
+ },
2227
+ resolveProjectKinds: () => ['frontend'],
2228
+ getImportExtractionMode: () => 'js-imports',
2229
+ }),
2230
+ nextjs: buildAdapter({
2231
+ id: 'nextjs',
2232
+ displayName: stackMetadata_1.canonicalStackLabels.nextjs,
2233
+ ecosystem: 'node',
2234
+ category: 'framework',
2235
+ priority: 100,
2236
+ manifestDetectionHints: ['package.json', 'next.config.js', 'next.config.mjs', 'next.config.ts', 'tsconfig.json'],
2237
+ buildToolHints: ['npm', 'yarn', 'pnpm', 'next'],
2238
+ defaults: {
2239
+ sourceRoots: ['src/features', 'src/modules', 'src', 'app', 'src/app', 'pages', '.'],
2240
+ moduleRootCandidates: ['src/features', 'src/modules', 'app', 'src/app', 'src', 'pages', '.'],
2241
+ apiRoots: ['app/api', 'pages/api', 'src/app/api'],
2242
+ databaseRoots: ['prisma', 'db'],
2243
+ configFiles: ['package.json', 'next.config.js', 'next.config.ts', 'next.config.mjs'],
2244
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx'],
2245
+ dependencyFileExtensions: ['.ts', '.tsx', '.js', '.jsx'],
2246
+ ignoreDirectories: ['.next', ...commonIgnoreDirectories],
2247
+ entrypointHints: [
2248
+ 'app/page.tsx',
2249
+ 'app/page.jsx',
2250
+ 'pages/index.tsx',
2251
+ 'pages/index.jsx',
2252
+ 'src/app/page.tsx',
2253
+ 'src/app/page.jsx',
2254
+ 'src/pages/index.tsx',
2255
+ 'src/pages/index.jsx',
2256
+ ],
2257
+ publicEntrypointDirectories: [],
2258
+ moduleIndexFileName: 'index.tsx',
2259
+ },
2260
+ detect: (context) => {
2261
+ const nextConfigFile = ['next.config.js', 'next.config.ts', 'next.config.mjs']
2262
+ .find((fileName) => context.hasFile(fileName));
2263
+ const hasNextDependency = context.hasPackageDependency('next');
2264
+ if (!nextConfigFile && !hasNextDependency) {
2265
+ return null;
2266
+ }
2267
+ if (nextConfigFile) {
2268
+ return toResult({
2269
+ adapterId: 'nextjs',
2270
+ confidence: 'high',
2271
+ score: hasNextDependency ? 98 : 94,
2272
+ evidence: [
2273
+ `Found ${nextConfigFile}`,
2274
+ ...(hasNextDependency ? ['Found package.json with next dependency'] : []),
2275
+ ],
2276
+ projectKindHints: ['frontend'],
2277
+ });
2278
+ }
2279
+ return toResult({
2280
+ adapterId: 'nextjs',
2281
+ confidence: 'medium',
2282
+ score: 82,
2283
+ evidence: ['Found package.json with next dependency'],
2284
+ projectKindHints: ['frontend'],
2285
+ });
2286
+ },
2287
+ resolveProjectKinds: () => ['frontend'],
2288
+ getImportExtractionMode: () => 'js-imports',
2289
+ }),
2290
+ terraform: buildAdapter({
2291
+ id: 'terraform',
2292
+ displayName: stackMetadata_1.canonicalStackLabels.terraform,
2293
+ ecosystem: 'other',
2294
+ category: 'runtime',
2295
+ priority: 35,
2296
+ manifestDetectionHints: ['main.tf', 'variables.tf', 'outputs.tf', 'providers.tf'],
2297
+ buildToolHints: ['terraform'],
2298
+ defaults: {
2299
+ sourceRoots: ['modules', 'live', 'environments', 'stacks', '.'],
2300
+ moduleRootCandidates: ['modules', 'live', 'environments', 'stacks', '.'],
2301
+ apiRoots: [],
2302
+ databaseRoots: [],
2303
+ configFiles: ['main.tf', 'variables.tf', 'outputs.tf', 'providers.tf'],
2304
+ fileExtensions: ['.tf', '.tfvars'],
2305
+ dependencyFileExtensions: ['.tf', '.tfvars'],
2306
+ ignoreDirectories: [...commonIgnoreDirectories, '.terraform'],
2307
+ entrypointHints: ['main.tf'],
2308
+ publicEntrypointDirectories: [],
2309
+ moduleIndexFileName: 'main.tf',
2310
+ },
2311
+ detect: (context) => {
2312
+ const hasTerraformFiles = context.hasFileExtension('.tf');
2313
+ const hasTerraformLayout = context.hasDirectory('modules') ||
2314
+ context.hasDirectory('environments') ||
2315
+ context.hasDirectory('live') ||
2316
+ context.hasDirectory('stacks');
2317
+ const hasTerraformEntrypoints = context.hasFile('main.tf') ||
2318
+ context.hasFile('variables.tf') ||
2319
+ context.hasFile('outputs.tf') ||
2320
+ context.hasFile('providers.tf');
2321
+ if (!hasTerraformFiles && !hasTerraformLayout && !hasTerraformEntrypoints) {
2322
+ return null;
2323
+ }
2324
+ const evidence = [];
2325
+ let score = 0;
2326
+ if (hasTerraformFiles) {
2327
+ score += 28;
2328
+ evidence.push('Found Terraform .tf files');
2329
+ }
2330
+ if (hasTerraformLayout) {
2331
+ score += 24;
2332
+ evidence.push('Found Terraform-style modules/environments/live/stacks layout');
2333
+ }
2334
+ if (hasTerraformEntrypoints) {
2335
+ score += 22;
2336
+ evidence.push('Found Terraform entrypoint files (main.tf/variables.tf/outputs.tf/providers.tf)');
2337
+ }
2338
+ return toResult({
2339
+ adapterId: 'terraform',
2340
+ confidence: hasTerraformLayout || hasTerraformEntrypoints ? 'high' : 'medium',
2341
+ score,
2342
+ evidence,
2343
+ projectKindHints: ['library'],
2344
+ });
2345
+ },
2346
+ resolveProjectKinds: () => ['library'],
2347
+ getImportExtractionMode: () => 'generic',
2348
+ }),
2349
+ ansible: buildAdapter({
2350
+ id: 'ansible',
2351
+ displayName: stackMetadata_1.canonicalStackLabels.ansible,
2352
+ ecosystem: 'other',
2353
+ category: 'runtime',
2354
+ priority: 34,
2355
+ manifestDetectionHints: ['ansible.cfg', 'site.yml', 'site.yaml'],
2356
+ buildToolHints: ['ansible'],
2357
+ defaults: {
2358
+ sourceRoots: ['roles', 'playbooks', 'inventories', '.'],
2359
+ moduleRootCandidates: ['roles', 'playbooks', 'inventories', '.'],
2360
+ apiRoots: [],
2361
+ databaseRoots: [],
2362
+ configFiles: ['ansible.cfg', 'site.yml', 'site.yaml'],
2363
+ fileExtensions: ['.yml', '.yaml'],
2364
+ dependencyFileExtensions: ['.yml', '.yaml'],
2365
+ ignoreDirectories: [...commonIgnoreDirectories],
2366
+ entrypointHints: ['site.yml', 'site.yaml'],
2367
+ publicEntrypointDirectories: [],
2368
+ moduleIndexFileName: 'site.yml',
2369
+ },
2370
+ detect: (context) => {
2371
+ const hasAnsibleLayout = context.hasDirectory('roles') ||
2372
+ context.hasDirectory('playbooks') ||
2373
+ context.hasDirectory('inventories') ||
2374
+ context.hasDirectory('group_vars') ||
2375
+ context.hasDirectory('host_vars');
2376
+ const hasAnsibleConfig = context.hasFile('ansible.cfg') ||
2377
+ context.hasFile('site.yml') ||
2378
+ context.hasFile('site.yaml');
2379
+ const hasAnsibleYamlEvidence = context.hasAnyFileMatchingPattern(/\.(yml|yaml)$/iu, /^\s*-\s+hosts\s*:/imu) ||
2380
+ context.hasAnyFileMatchingPattern(/\.(yml|yaml)$/iu, /^\s*hosts\s*:/imu) ||
2381
+ context.hasAnyFileMatchingPattern(/\.(yml|yaml)$/iu, /^\s*roles\s*:/imu);
2382
+ if (!hasAnsibleLayout && !hasAnsibleConfig && !hasAnsibleYamlEvidence) {
2383
+ return null;
2384
+ }
2385
+ const evidence = [];
2386
+ let score = 0;
2387
+ if (hasAnsibleLayout) {
2388
+ score += 28;
2389
+ evidence.push('Found Ansible roles/playbooks/inventories layout');
2390
+ }
2391
+ if (hasAnsibleConfig) {
2392
+ score += 18;
2393
+ evidence.push('Found ansible.cfg or site.yml/site.yaml');
2394
+ }
2395
+ if (hasAnsibleYamlEvidence) {
2396
+ score += 16;
2397
+ evidence.push('Found ansible-style YAML structure');
2398
+ }
2399
+ return toResult({
2400
+ adapterId: 'ansible',
2401
+ confidence: hasAnsibleLayout ? 'high' : 'medium',
2402
+ score,
2403
+ evidence,
2404
+ projectKindHints: ['library'],
2405
+ });
2406
+ },
2407
+ resolveProjectKinds: () => ['library'],
2408
+ getImportExtractionMode: () => 'generic',
2409
+ }),
2410
+ library_generic: buildAdapter({
2411
+ id: 'library_generic',
2412
+ displayName: stackMetadata_1.canonicalStackLabels.library_generic,
2413
+ ecosystem: 'other',
2414
+ category: 'runtime',
2415
+ priority: 10,
2416
+ manifestDetectionHints: ['package.json'],
2417
+ buildToolHints: [],
2418
+ defaults: {
2419
+ sourceRoots: ['src'],
2420
+ moduleRootCandidates: ['src'],
2421
+ apiRoots: ['src'],
2422
+ databaseRoots: [],
2423
+ configFiles: ['package.json'],
2424
+ fileExtensions: ['.ts', '.js', '.py', '.go'],
2425
+ dependencyFileExtensions: ['.ts', '.js'],
2426
+ ignoreDirectories: [...commonIgnoreDirectories],
2427
+ entrypointHints: ['index.ts', 'index.js'],
2428
+ publicEntrypointDirectories: [],
2429
+ moduleIndexFileName: 'index.ts',
2430
+ },
2431
+ detect: () => null,
2432
+ getImportExtractionMode: () => 'generic',
2433
+ }),
2434
+ };
2435
+ function getStackFromSlots(slots, key) {
2436
+ const value = slots[key];
2437
+ return typeof value === 'string' ? value : undefined;
2438
+ }
2439
+ function getAllStackAdapters() {
2440
+ return Object.values(stackAdaptersById)
2441
+ .sort((left, right) => left.id.localeCompare(right.id));
2442
+ }
2443
+ function getSmartInitDetectionAdapters() {
2444
+ return getAllStackAdapters().filter((adapter) => adapter.id !== 'other' && adapter.id !== 'library_generic');
2445
+ }
2446
+ function getStackAdapterById(stackId) {
2447
+ if (!stackId || stackId === 'other') {
2448
+ return genericDefaultAdapter;
2449
+ }
2450
+ return stackAdaptersById[stackId] ?? genericDefaultAdapter;
2451
+ }
2452
+ function resolveBackendAdapter(metadata) {
2453
+ return getStackAdapterById(getStackFromSlots(metadata.stacks, 'backendStack'));
2454
+ }
2455
+ function resolveFrontendAdapter(metadata) {
2456
+ return getStackAdapterById(getStackFromSlots(metadata.stacks, 'frontendStack'));
2457
+ }
2458
+ function resolveLibraryAdapter(metadata) {
2459
+ return getStackAdapterById(getStackFromSlots(metadata.stacks, 'libraryStack'));
2460
+ }
2461
+ function resolvePrimaryAdapter(metadata) {
2462
+ return getStackAdapterById(metadata.stacks.backendStack ??
2463
+ metadata.stacks.frontendStack ??
2464
+ metadata.stacks.libraryStack ??
2465
+ 'other');
2466
+ }
2467
+ function resolvePrimaryAdapterFromContract(contract) {
2468
+ return resolvePrimaryAdapter((0, stackMetadata_1.normalizeStackMetadata)(contract));
2469
+ }
2470
+ function resolveDefaultModulesRootFromContract(contract, fallback = 'src/modules') {
2471
+ const adapter = resolvePrimaryAdapterFromContract(contract);
2472
+ const defaults = adapter.getDefaults();
2473
+ return defaults.moduleRootCandidates[0] ?? defaults.sourceRoots[0] ?? fallback;
2474
+ }
2475
+ //# sourceMappingURL=stackAdapters.js.map