@archpilotlabs/archpilot 0.2.2 → 0.2.3
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.
- package/dist/archpilot-cli.js +516 -105
- package/dist/cli/src/archpilot-cli.js +5523 -0
- package/dist/cli/src/archpilot-cli.js.map +1 -0
- package/dist/core/src/adr/adrLoader.js +97 -0
- package/dist/core/src/adr/adrLoader.js.map +1 -0
- package/dist/core/src/adr/adrParser.js +77 -0
- package/dist/core/src/adr/adrParser.js.map +1 -0
- package/dist/core/src/adr/adrTemplate.js +45 -0
- package/dist/core/src/adr/adrTemplate.js.map +1 -0
- package/dist/core/src/adr/adrTypes.js +3 -0
- package/dist/core/src/adr/adrTypes.js.map +1 -0
- package/dist/core/src/adr/adrValidation.js +160 -0
- package/dist/core/src/adr/adrValidation.js.map +1 -0
- package/dist/core/src/adr/index.js +9 -0
- package/dist/core/src/adr/index.js.map +1 -0
- package/dist/core/src/adrManagement.js +174 -0
- package/dist/core/src/adrManagement.js.map +1 -0
- package/dist/core/src/adrRequirementStatus.js +62 -0
- package/dist/core/src/adrRequirementStatus.js.map +1 -0
- package/dist/core/src/adrScaffoldGeneration.js +325 -0
- package/dist/core/src/adrScaffoldGeneration.js.map +1 -0
- package/dist/core/src/apiDesignAnalysis.js +869 -0
- package/dist/core/src/apiDesignAnalysis.js.map +1 -0
- package/dist/core/src/applicationLayeringAnalysis.js +920 -0
- package/dist/core/src/applicationLayeringAnalysis.js.map +1 -0
- package/dist/core/src/applyRulePack.js +117 -0
- package/dist/core/src/applyRulePack.js.map +1 -0
- package/dist/core/src/architectureBaseline.js +271 -0
- package/dist/core/src/architectureBaseline.js.map +1 -0
- package/dist/core/src/architectureComponentDiscoveryDefaults.js +139 -0
- package/dist/core/src/architectureComponentDiscoveryDefaults.js.map +1 -0
- package/dist/core/src/architectureDependencyContext.js +316 -0
- package/dist/core/src/architectureDependencyContext.js.map +1 -0
- package/dist/core/src/architectureDriftDetection.js +96 -0
- package/dist/core/src/architectureDriftDetection.js.map +1 -0
- package/dist/core/src/architectureDriftTimeline.js +221 -0
- package/dist/core/src/architectureDriftTimeline.js.map +1 -0
- package/dist/core/src/architectureGovernanceBaseline.js +469 -0
- package/dist/core/src/architectureGovernanceBaseline.js.map +1 -0
- package/dist/core/src/architectureHealthHistory.js +208 -0
- package/dist/core/src/architectureHealthHistory.js.map +1 -0
- package/dist/core/src/architectureHealthScore.js +657 -0
- package/dist/core/src/architectureHealthScore.js.map +1 -0
- package/dist/core/src/architectureInit.js +826 -0
- package/dist/core/src/architectureInit.js.map +1 -0
- package/dist/core/src/architectureMap.js +727 -0
- package/dist/core/src/architectureMap.js.map +1 -0
- package/dist/core/src/architectureMigrationPreview.js +467 -0
- package/dist/core/src/architectureMigrationPreview.js.map +1 -0
- package/dist/core/src/architectureModelRefresh.js +209 -0
- package/dist/core/src/architectureModelRefresh.js.map +1 -0
- package/dist/core/src/architectureReportWorkflow.js +139 -0
- package/dist/core/src/architectureReportWorkflow.js.map +1 -0
- package/dist/core/src/architectureValidation.js +3879 -0
- package/dist/core/src/architectureValidation.js.map +1 -0
- package/dist/core/src/architectureWorkspaceModel.js +166 -0
- package/dist/core/src/architectureWorkspaceModel.js.map +1 -0
- package/dist/core/src/authorizationTenantAnalysis.js +652 -0
- package/dist/core/src/authorizationTenantAnalysis.js.map +1 -0
- package/dist/core/src/bootstrapArchitectureConfig.js +150 -0
- package/dist/core/src/bootstrapArchitectureConfig.js.map +1 -0
- package/dist/core/src/changeRisk/changeRiskAssessment.js +251 -0
- package/dist/core/src/changeRisk/changeRiskAssessment.js.map +1 -0
- package/dist/core/src/changeRisk/changeRiskTypes.js +3 -0
- package/dist/core/src/changeRisk/changeRiskTypes.js.map +1 -0
- package/dist/core/src/changeRisk/index.js +6 -0
- package/dist/core/src/changeRisk/index.js.map +1 -0
- package/dist/core/src/ci/githubInlineAnnotations.js +245 -0
- package/dist/core/src/ci/githubInlineAnnotations.js.map +1 -0
- package/dist/core/src/ci/githubPrCommentAdapter.js +232 -0
- package/dist/core/src/ci/githubPrCommentAdapter.js.map +1 -0
- package/dist/core/src/ciWorkflowTemplates.js +1042 -0
- package/dist/core/src/ciWorkflowTemplates.js.map +1 -0
- package/dist/core/src/compliance/complianceExportBuilder.js +122 -0
- package/dist/core/src/compliance/complianceExportBuilder.js.map +1 -0
- package/dist/core/src/compliance/complianceExportTypes.js +3 -0
- package/dist/core/src/compliance/complianceExportTypes.js.map +1 -0
- package/dist/core/src/compliance/complianceExportWriter.js +48 -0
- package/dist/core/src/compliance/complianceExportWriter.js.map +1 -0
- package/dist/core/src/compliance/complianceRulePackResolver.js +62 -0
- package/dist/core/src/compliance/complianceRulePackResolver.js.map +1 -0
- package/dist/core/src/config/index.js +17 -0
- package/dist/core/src/config/index.js.map +1 -0
- package/dist/core/src/config/projectConfig.js +224 -0
- package/dist/core/src/config/projectConfig.js.map +1 -0
- package/dist/core/src/config/projectIdentity.js +160 -0
- package/dist/core/src/config/projectIdentity.js.map +1 -0
- package/dist/core/src/dataQueryRiskDetection.js +1203 -0
- package/dist/core/src/dataQueryRiskDetection.js.map +1 -0
- package/dist/core/src/dependencyValidation.js +2557 -0
- package/dist/core/src/dependencyValidation.js.map +1 -0
- package/dist/core/src/discoverAdrs.js +15 -0
- package/dist/core/src/discoverAdrs.js.map +1 -0
- package/dist/core/src/drift/driftComparator.js +49 -0
- package/dist/core/src/drift/driftComparator.js.map +1 -0
- package/dist/core/src/drift/driftSnapshotLoader.js +136 -0
- package/dist/core/src/drift/driftSnapshotLoader.js.map +1 -0
- package/dist/core/src/drift/driftSnapshotTypes.js +3 -0
- package/dist/core/src/drift/driftSnapshotTypes.js.map +1 -0
- package/dist/core/src/drift/driftSnapshotWriter.js +48 -0
- package/dist/core/src/drift/driftSnapshotWriter.js.map +1 -0
- package/dist/core/src/drift/index.js +6 -0
- package/dist/core/src/drift/index.js.map +1 -0
- package/dist/core/src/eventArchitectureAnalysis.js +925 -0
- package/dist/core/src/eventArchitectureAnalysis.js.map +1 -0
- package/dist/core/src/findingTargetResolution.js +117 -0
- package/dist/core/src/findingTargetResolution.js.map +1 -0
- package/dist/core/src/generateArchitectureDiagrams.js +57 -0
- package/dist/core/src/generateArchitectureDiagrams.js.map +1 -0
- package/dist/core/src/generateImpactAnalysis.js +366 -0
- package/dist/core/src/generateImpactAnalysis.js.map +1 -0
- package/dist/core/src/generateOnboardingDocs.js +262 -0
- package/dist/core/src/generateOnboardingDocs.js.map +1 -0
- package/dist/core/src/governance/cloudConnection.js +203 -0
- package/dist/core/src/governance/cloudConnection.js.map +1 -0
- package/dist/core/src/governance/governanceContracts.js +129 -0
- package/dist/core/src/governance/governanceContracts.js.map +1 -0
- package/dist/core/src/governance/governanceGitMetadata.js +78 -0
- package/dist/core/src/governance/governanceGitMetadata.js.map +1 -0
- package/dist/core/src/governance/governanceUploadClient.js +119 -0
- package/dist/core/src/governance/governanceUploadClient.js.map +1 -0
- package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js +155 -0
- package/dist/core/src/governance/governanceUploadLimitErrorFormatting.js.map +1 -0
- package/dist/core/src/governance/governanceUploadPayload.js +439 -0
- package/dist/core/src/governance/governanceUploadPayload.js.map +1 -0
- package/dist/core/src/governance/runGovernanceUpload.js +103 -0
- package/dist/core/src/governance/runGovernanceUpload.js.map +1 -0
- package/dist/core/src/impactAnalysisEngine.js +376 -0
- package/dist/core/src/impactAnalysisEngine.js.map +1 -0
- package/dist/core/src/initializationState.js +99 -0
- package/dist/core/src/initializationState.js.map +1 -0
- package/dist/core/src/managedArtifacts.js +151 -0
- package/dist/core/src/managedArtifacts.js.map +1 -0
- package/dist/core/src/moduleContractValidation.js +266 -0
- package/dist/core/src/moduleContractValidation.js.map +1 -0
- package/dist/core/src/moduleContractsGenerator.js +337 -0
- package/dist/core/src/moduleContractsGenerator.js.map +1 -0
- package/dist/core/src/moduleDiscovery.js +416 -0
- package/dist/core/src/moduleDiscovery.js.map +1 -0
- package/dist/core/src/moduleScope.js +426 -0
- package/dist/core/src/moduleScope.js.map +1 -0
- package/dist/core/src/onboardingGuidance.js +74 -0
- package/dist/core/src/onboardingGuidance.js.map +1 -0
- package/dist/core/src/operationalLogging.js +7 -0
- package/dist/core/src/operationalLogging.js.map +1 -0
- package/dist/core/src/packageVersion.js +52 -0
- package/dist/core/src/packageVersion.js.map +1 -0
- package/dist/core/src/policy/effectivePolicyResolver.js +91 -0
- package/dist/core/src/policy/effectivePolicyResolver.js.map +1 -0
- package/dist/core/src/policy/exceptionLoader.js +285 -0
- package/dist/core/src/policy/exceptionLoader.js.map +1 -0
- package/dist/core/src/policy/remotePolicyLoader.js +227 -0
- package/dist/core/src/policy/remotePolicyLoader.js.map +1 -0
- package/dist/core/src/policy/remotePolicyTypes.js +3 -0
- package/dist/core/src/policy/remotePolicyTypes.js.map +1 -0
- package/dist/core/src/policy/riskPolicyConfig.js +206 -0
- package/dist/core/src/policy/riskPolicyConfig.js.map +1 -0
- package/dist/core/src/policy/riskPolicyEnforcement.js +203 -0
- package/dist/core/src/policy/riskPolicyEnforcement.js.map +1 -0
- package/dist/core/src/policy/riskPolicyExitCode.js +16 -0
- package/dist/core/src/policy/riskPolicyExitCode.js.map +1 -0
- package/dist/core/src/policy/riskPolicyInitializer.js +90 -0
- package/dist/core/src/policy/riskPolicyInitializer.js.map +1 -0
- package/dist/core/src/quickFix/quickFixEngine.js +132 -0
- package/dist/core/src/quickFix/quickFixEngine.js.map +1 -0
- package/dist/core/src/quickFix/quickFixMessaging.js +15 -0
- package/dist/core/src/quickFix/quickFixMessaging.js.map +1 -0
- package/dist/core/src/quickFix/quickFixProviders.js +87 -0
- package/dist/core/src/quickFix/quickFixProviders.js.map +1 -0
- package/dist/core/src/quickFix/quickFixTypes.js +3 -0
- package/dist/core/src/quickFix/quickFixTypes.js.map +1 -0
- package/dist/core/src/remediation/fileHelpers.js +86 -0
- package/dist/core/src/remediation/fileHelpers.js.map +1 -0
- package/dist/core/src/remediation/fixRegistry.js +645 -0
- package/dist/core/src/remediation/fixRegistry.js.map +1 -0
- package/dist/core/src/remediation/index.js +8 -0
- package/dist/core/src/remediation/index.js.map +1 -0
- package/dist/core/src/remediation/remediationEngine.js +207 -0
- package/dist/core/src/remediation/remediationEngine.js.map +1 -0
- package/dist/core/src/reporting/adrReporter.js +59 -0
- package/dist/core/src/reporting/adrReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureBaselineReporter.js +64 -0
- package/dist/core/src/reporting/architectureBaselineReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureDiagramReporter.js +148 -0
- package/dist/core/src/reporting/architectureDiagramReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureDriftTimelineReporter.js +44 -0
- package/dist/core/src/reporting/architectureDriftTimelineReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureHealthHistoryReporter.js +51 -0
- package/dist/core/src/reporting/architectureHealthHistoryReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureMapReporter.js +228 -0
- package/dist/core/src/reporting/architectureMapReporter.js.map +1 -0
- package/dist/core/src/reporting/architecturePrCommentReporter.js +324 -0
- package/dist/core/src/reporting/architecturePrCommentReporter.js.map +1 -0
- package/dist/core/src/reporting/architecturePrReviewReporter.js +389 -0
- package/dist/core/src/reporting/architecturePrReviewReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureReportArtifacts.js +166 -0
- package/dist/core/src/reporting/architectureReportArtifacts.js.map +1 -0
- package/dist/core/src/reporting/architectureReviewReportGenerator.js +382 -0
- package/dist/core/src/reporting/architectureReviewReportGenerator.js.map +1 -0
- package/dist/core/src/reporting/architectureReviewReporter.js +1633 -0
- package/dist/core/src/reporting/architectureReviewReporter.js.map +1 -0
- package/dist/core/src/reporting/architectureRiskAssessment.js +101 -0
- package/dist/core/src/reporting/architectureRiskAssessment.js.map +1 -0
- package/dist/core/src/reporting/architectureScoreBadge.js +177 -0
- package/dist/core/src/reporting/architectureScoreBadge.js.map +1 -0
- package/dist/core/src/reporting/architectureSupplementalReporters.js +124 -0
- package/dist/core/src/reporting/architectureSupplementalReporters.js.map +1 -0
- package/dist/core/src/reporting/changeRiskAssessment.js +6 -0
- package/dist/core/src/reporting/changeRiskAssessment.js.map +1 -0
- package/dist/core/src/reporting/changeRiskTypes.js +3 -0
- package/dist/core/src/reporting/changeRiskTypes.js.map +1 -0
- package/dist/core/src/reporting/impactAnalysisReporter.js +111 -0
- package/dist/core/src/reporting/impactAnalysisReporter.js.map +1 -0
- package/dist/core/src/reporting/onboardingDocsReporter.js +113 -0
- package/dist/core/src/reporting/onboardingDocsReporter.js.map +1 -0
- package/dist/core/src/reporting/rulePackReporter.js +61 -0
- package/dist/core/src/reporting/rulePackReporter.js.map +1 -0
- package/dist/core/src/reporting/safetyControlsDetection.js +343 -0
- package/dist/core/src/reporting/safetyControlsDetection.js.map +1 -0
- package/dist/core/src/resolveRuleAdrs.js +31 -0
- package/dist/core/src/resolveRuleAdrs.js.map +1 -0
- package/dist/core/src/reviewGenerationWorkflow.js +220 -0
- package/dist/core/src/reviewGenerationWorkflow.js.map +1 -0
- package/dist/core/src/rulePacks/index.js +17 -0
- package/dist/core/src/rulePacks/index.js.map +1 -0
- package/dist/core/src/rulePacks/layeredMonolithRulePack.js +45 -0
- package/dist/core/src/rulePacks/layeredMonolithRulePack.js.map +1 -0
- package/dist/core/src/rulePacks/modularMonolithRulePack.js +41 -0
- package/dist/core/src/rulePacks/modularMonolithRulePack.js.map +1 -0
- package/dist/core/src/rulePacks/types.js +3 -0
- package/dist/core/src/rulePacks/types.js.map +1 -0
- package/dist/core/src/setupNextSteps.js +939 -0
- package/dist/core/src/setupNextSteps.js.map +1 -0
- package/dist/core/src/setupRefresh.js +152 -0
- package/dist/core/src/setupRefresh.js.map +1 -0
- package/dist/core/src/smartInit/apiDbHintDetection.js +836 -0
- package/dist/core/src/smartInit/apiDbHintDetection.js.map +1 -0
- package/dist/core/src/smartInit/architectureProposalBuilder.js +1215 -0
- package/dist/core/src/smartInit/architectureProposalBuilder.js.map +1 -0
- package/dist/core/src/smartInit/architectureStyleDetection.js +472 -0
- package/dist/core/src/smartInit/architectureStyleDetection.js.map +1 -0
- package/dist/core/src/smartInit/archpilotIgnore.js +139 -0
- package/dist/core/src/smartInit/archpilotIgnore.js.map +1 -0
- package/dist/core/src/smartInit/componentDetection.js +1084 -0
- package/dist/core/src/smartInit/componentDetection.js.map +1 -0
- package/dist/core/src/smartInit/implementationProfileResolution.js +53 -0
- package/dist/core/src/smartInit/implementationProfileResolution.js.map +1 -0
- package/dist/core/src/smartInit/index.js +31 -0
- package/dist/core/src/smartInit/index.js.map +1 -0
- package/dist/core/src/smartInit/moduleDetection.js +982 -0
- package/dist/core/src/smartInit/moduleDetection.js.map +1 -0
- package/dist/core/src/smartInit/projectKindDetection.js +437 -0
- package/dist/core/src/smartInit/projectKindDetection.js.map +1 -0
- package/dist/core/src/smartInit/repoTopologyDetection.js +470 -0
- package/dist/core/src/smartInit/repoTopologyDetection.js.map +1 -0
- package/dist/core/src/smartInit/runContext.js +112 -0
- package/dist/core/src/smartInit/runContext.js.map +1 -0
- package/dist/core/src/smartInit/smartInitEngine.js +94 -0
- package/dist/core/src/smartInit/smartInitEngine.js.map +1 -0
- package/dist/core/src/smartInit/stackDetection.js +503 -0
- package/dist/core/src/smartInit/stackDetection.js.map +1 -0
- package/dist/core/src/smartInit/toolingHintDetection.js +345 -0
- package/dist/core/src/smartInit/toolingHintDetection.js.map +1 -0
- package/dist/core/src/sourceScopeClassification.js +83 -0
- package/dist/core/src/sourceScopeClassification.js.map +1 -0
- package/dist/core/src/stackAdapters.js +2475 -0
- package/dist/core/src/stackAdapters.js.map +1 -0
- package/dist/core/src/stackMetadata.js +157 -0
- package/dist/core/src/stackMetadata.js.map +1 -0
- package/dist/core/src/suppressions/index.js +3 -0
- package/dist/core/src/suppressions/index.js.map +1 -0
- package/dist/core/src/suppressions/suppressionReporter.js +38 -0
- package/dist/core/src/suppressions/suppressionReporter.js.map +1 -0
- package/dist/core/src/suppressions/suppressionTypes.js +3 -0
- package/dist/core/src/suppressions/suppressionTypes.js.map +1 -0
- package/dist/core/src/suppressions/suppressionValidator.js +119 -0
- package/dist/core/src/suppressions/suppressionValidator.js.map +1 -0
- package/dist/core/src/transactionDomainAnalysis.js +1416 -0
- package/dist/core/src/transactionDomainAnalysis.js.map +1 -0
- package/dist/core/src/validation/changedFilesResolver.js +165 -0
- package/dist/core/src/validation/changedFilesResolver.js.map +1 -0
- package/dist/core/src/validationProfiling.js +33 -0
- package/dist/core/src/validationProfiling.js.map +1 -0
- package/dist/core/src/validationRuleExplanations.js +69 -0
- package/dist/core/src/validationRuleExplanations.js.map +1 -0
- package/dist/core/src/validationSourceInventory.js +200 -0
- package/dist/core/src/validationSourceInventory.js.map +1 -0
- package/dist/core/src/validationSuppressions.js +231 -0
- package/dist/core/src/validationSuppressions.js.map +1 -0
- package/dist/core/src/validationTypeScriptAstCache.js +82 -0
- package/dist/core/src/validationTypeScriptAstCache.js.map +1 -0
- package/dist/core/src/validationWorkflow.js +222 -0
- package/dist/core/src/validationWorkflow.js.map +1 -0
- package/dist/core/src/workspaceRoot.js +68 -0
- package/dist/core/src/workspaceRoot.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1042 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.githubCiWorkflowRelativePath = void 0;
|
|
37
|
+
exports.detectGithubCiRepositoryCapabilities = detectGithubCiRepositoryCapabilities;
|
|
38
|
+
exports.detectGithubCiWorkflowStrategy = detectGithubCiWorkflowStrategy;
|
|
39
|
+
exports.generateGithubCiGovernanceWorkflow = generateGithubCiGovernanceWorkflow;
|
|
40
|
+
exports.generateCiValidationWorkflow = generateCiValidationWorkflow;
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const node_fs_1 = require("node:fs");
|
|
43
|
+
const defaultPnpmVersion = '10.0.0';
|
|
44
|
+
const defaultYarnVersion = '1.22.22';
|
|
45
|
+
exports.githubCiWorkflowRelativePath = '.github/workflows/archpilot-ci.yml';
|
|
46
|
+
async function pathExists(targetPath) {
|
|
47
|
+
try {
|
|
48
|
+
await node_fs_1.promises.access(targetPath);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function directoryExists(targetPath) {
|
|
56
|
+
try {
|
|
57
|
+
const stats = await node_fs_1.promises.stat(targetPath);
|
|
58
|
+
return stats.isDirectory();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function readJsonFile(filePath) {
|
|
65
|
+
if (!(await pathExists(filePath))) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const raw = await node_fs_1.promises.readFile(filePath, 'utf8');
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function readRootPackageJson(workspaceRoot) {
|
|
77
|
+
return readJsonFile(path.join(workspaceRoot, 'package.json'));
|
|
78
|
+
}
|
|
79
|
+
function hasWorkspaceConfig(packageJson) {
|
|
80
|
+
if (!packageJson) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const { workspaces } = packageJson;
|
|
84
|
+
if (Array.isArray(workspaces)) {
|
|
85
|
+
return workspaces.length > 0;
|
|
86
|
+
}
|
|
87
|
+
if (!workspaces || typeof workspaces !== 'object') {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const packages = workspaces.packages;
|
|
91
|
+
return Array.isArray(packages) && packages.length > 0;
|
|
92
|
+
}
|
|
93
|
+
function extractPackageManagerFromManifest(packageJson) {
|
|
94
|
+
const packageManager = typeof packageJson?.packageManager === 'string'
|
|
95
|
+
? packageJson.packageManager.trim()
|
|
96
|
+
: undefined;
|
|
97
|
+
if (!packageManager) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (packageManager.startsWith('pnpm@')) {
|
|
101
|
+
return 'pnpm';
|
|
102
|
+
}
|
|
103
|
+
if (packageManager.startsWith('yarn@')) {
|
|
104
|
+
return 'yarn';
|
|
105
|
+
}
|
|
106
|
+
if (packageManager.startsWith('npm@')) {
|
|
107
|
+
return 'npm';
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
function hasPnpmPackageManagerDeclaration(packageJson) {
|
|
112
|
+
return typeof packageJson?.packageManager === 'string' && packageJson.packageManager.trim().startsWith('pnpm@');
|
|
113
|
+
}
|
|
114
|
+
function extractPackageManagerVersion(packageJson, packageManager) {
|
|
115
|
+
const declaration = typeof packageJson?.packageManager === 'string'
|
|
116
|
+
? packageJson.packageManager.trim()
|
|
117
|
+
: undefined;
|
|
118
|
+
if (!declaration) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const match = new RegExp(`^${packageManager}@([^+\\s]+)`, 'u').exec(declaration);
|
|
122
|
+
return match?.[1];
|
|
123
|
+
}
|
|
124
|
+
function resolvePackageManager(options) {
|
|
125
|
+
const packageManagerFromManifest = extractPackageManagerFromManifest(options.rootPackageJson);
|
|
126
|
+
if (packageManagerFromManifest) {
|
|
127
|
+
return packageManagerFromManifest;
|
|
128
|
+
}
|
|
129
|
+
if (options.hasPnpmLockfile) {
|
|
130
|
+
return 'pnpm';
|
|
131
|
+
}
|
|
132
|
+
if (options.hasYarnLockfile) {
|
|
133
|
+
return 'yarn';
|
|
134
|
+
}
|
|
135
|
+
if (options.hasNpmLockfile) {
|
|
136
|
+
return 'npm';
|
|
137
|
+
}
|
|
138
|
+
return 'npm';
|
|
139
|
+
}
|
|
140
|
+
function normalizeScripts(value) {
|
|
141
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
142
|
+
return {};
|
|
143
|
+
}
|
|
144
|
+
return Object.fromEntries(Object.entries(value)
|
|
145
|
+
.filter((entry) => typeof entry[1] === 'string')
|
|
146
|
+
.map(([key, script]) => [key, script.trim()]));
|
|
147
|
+
}
|
|
148
|
+
function normalizeDependencies(packageJson) {
|
|
149
|
+
const dependencies = new Set();
|
|
150
|
+
for (const record of [packageJson?.dependencies, packageJson?.devDependencies]) {
|
|
151
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
for (const key of Object.keys(record)) {
|
|
155
|
+
dependencies.add(key);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return dependencies;
|
|
159
|
+
}
|
|
160
|
+
function usesLocalArchpilotCli(packageJson) {
|
|
161
|
+
const bin = packageJson?.bin;
|
|
162
|
+
if (!bin) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (typeof bin === 'string') {
|
|
166
|
+
return bin.includes('archpilot-cli');
|
|
167
|
+
}
|
|
168
|
+
const archpilotBin = bin.archpilot;
|
|
169
|
+
return typeof archpilotBin === 'string' && archpilotBin.includes('archpilot-cli');
|
|
170
|
+
}
|
|
171
|
+
function hasScript(packageJson, scriptName) {
|
|
172
|
+
return typeof packageJson?.scripts?.[scriptName] === 'string';
|
|
173
|
+
}
|
|
174
|
+
function findManifestByPackageName(manifests, packageName) {
|
|
175
|
+
return manifests.find((manifest) => manifest.name === packageName);
|
|
176
|
+
}
|
|
177
|
+
function detectArchpilotGovernanceWorkspaceLayout(manifests) {
|
|
178
|
+
const coreManifest = findManifestByPackageName(manifests, '@archpilot/core');
|
|
179
|
+
const cliManifest = findManifestByPackageName(manifests, '@archpilotlabs/archpilot');
|
|
180
|
+
const vscodeManifest = findManifestByPackageName(manifests, '@archpilot/vscode-extension') ??
|
|
181
|
+
findManifestByPackageName(manifests, 'archpilot-vscode');
|
|
182
|
+
if (!coreManifest || !cliManifest) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const toLayer = (manifest) => ({
|
|
186
|
+
relativeDir: manifest.relativeDir,
|
|
187
|
+
packageName: manifest.name ?? manifest.relativeDir,
|
|
188
|
+
scripts: manifest.scripts,
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
core: toLayer(coreManifest),
|
|
192
|
+
cli: toLayer(cliManifest),
|
|
193
|
+
...(vscodeManifest ? { vscode: toLayer(vscodeManifest) } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
async function collectPackageManifests(workspaceRoot, rootPackageJson) {
|
|
197
|
+
const manifests = [];
|
|
198
|
+
if (rootPackageJson) {
|
|
199
|
+
manifests.push({
|
|
200
|
+
relativeDir: '.',
|
|
201
|
+
name: typeof rootPackageJson.name === 'string' ? rootPackageJson.name : undefined,
|
|
202
|
+
scripts: normalizeScripts(rootPackageJson.scripts),
|
|
203
|
+
dependencies: normalizeDependencies(rootPackageJson),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async function walk(relativeDir) {
|
|
207
|
+
const absoluteDir = path.join(workspaceRoot, relativeDir);
|
|
208
|
+
let entries;
|
|
209
|
+
try {
|
|
210
|
+
entries = await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true });
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
for (const entry of entries) {
|
|
216
|
+
if (!entry.isDirectory()) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist' || entry.name === '.next') {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const childRelativeDir = relativeDir === '.' ? entry.name : path.posix.join(relativeDir.replace(/\\/g, '/'), entry.name);
|
|
223
|
+
const packageJson = await readJsonFile(path.join(workspaceRoot, childRelativeDir, 'package.json'));
|
|
224
|
+
if (packageJson) {
|
|
225
|
+
manifests.push({
|
|
226
|
+
relativeDir: childRelativeDir.replace(/\\/g, '/'),
|
|
227
|
+
name: typeof packageJson.name === 'string' ? packageJson.name : undefined,
|
|
228
|
+
scripts: normalizeScripts(packageJson.scripts),
|
|
229
|
+
dependencies: normalizeDependencies(packageJson),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
await walk(childRelativeDir);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const topLevelDir of ['apps', 'packages', 'services']) {
|
|
236
|
+
if (await directoryExists(path.join(workspaceRoot, topLevelDir))) {
|
|
237
|
+
await walk(topLevelDir);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return manifests;
|
|
241
|
+
}
|
|
242
|
+
function hasArchpilotDependency(manifests) {
|
|
243
|
+
return manifests.some((manifest) => manifest.dependencies.has('archpilot') || manifest.dependencies.has('archpilot'));
|
|
244
|
+
}
|
|
245
|
+
const ignoredCapabilityPathSegments = new Set([
|
|
246
|
+
'node_modules',
|
|
247
|
+
'.git',
|
|
248
|
+
'dist',
|
|
249
|
+
'.next',
|
|
250
|
+
'.turbo',
|
|
251
|
+
'coverage',
|
|
252
|
+
'out',
|
|
253
|
+
'build',
|
|
254
|
+
'target',
|
|
255
|
+
'vendor',
|
|
256
|
+
'.venv',
|
|
257
|
+
'venv',
|
|
258
|
+
'__pycache__',
|
|
259
|
+
'test',
|
|
260
|
+
'tests',
|
|
261
|
+
'fixture',
|
|
262
|
+
'fixtures',
|
|
263
|
+
'example',
|
|
264
|
+
'examples',
|
|
265
|
+
'sample',
|
|
266
|
+
'samples',
|
|
267
|
+
'snapshot',
|
|
268
|
+
'snapshots',
|
|
269
|
+
'docs',
|
|
270
|
+
'doc',
|
|
271
|
+
]);
|
|
272
|
+
function shouldIgnoreCapabilityPath(relativeDir) {
|
|
273
|
+
if (relativeDir === '.') {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
return relativeDir
|
|
277
|
+
.replace(/\\/g, '/')
|
|
278
|
+
.split('/')
|
|
279
|
+
.some((segment) => ignoredCapabilityPathSegments.has(segment.toLowerCase()));
|
|
280
|
+
}
|
|
281
|
+
async function readTextFileSafe(filePath) {
|
|
282
|
+
try {
|
|
283
|
+
return await node_fs_1.promises.readFile(filePath, 'utf8');
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function collectRepositoryProjectRoots(workspaceRoot) {
|
|
290
|
+
const projectRoots = new Set();
|
|
291
|
+
async function walk(relativeDir, depth) {
|
|
292
|
+
if (depth > 4 || shouldIgnoreCapabilityPath(relativeDir)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const absoluteDir = path.join(workspaceRoot, relativeDir);
|
|
296
|
+
let entries;
|
|
297
|
+
try {
|
|
298
|
+
entries = await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true });
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const fileNames = new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name.toLowerCase()));
|
|
304
|
+
const hasTerraformFiles = entries.some((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.tf'));
|
|
305
|
+
const hasProjectMarker = fileNames.has('package.json') ||
|
|
306
|
+
fileNames.has('pom.xml') ||
|
|
307
|
+
fileNames.has('build.gradle') ||
|
|
308
|
+
fileNames.has('build.gradle.kts') ||
|
|
309
|
+
fileNames.has('requirements.txt') ||
|
|
310
|
+
fileNames.has('pyproject.toml') ||
|
|
311
|
+
fileNames.has('composer.json') ||
|
|
312
|
+
fileNames.has('go.mod') ||
|
|
313
|
+
fileNames.has('ansible.cfg') ||
|
|
314
|
+
hasTerraformFiles;
|
|
315
|
+
if (hasProjectMarker) {
|
|
316
|
+
projectRoots.add(relativeDir);
|
|
317
|
+
}
|
|
318
|
+
for (const entry of entries) {
|
|
319
|
+
if (!entry.isDirectory()) {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (['node_modules', '.git', 'dist', '.next', '.turbo', 'coverage', 'out', 'build', 'target', 'vendor'].includes(entry.name)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const childRelativeDir = relativeDir === '.'
|
|
326
|
+
? entry.name
|
|
327
|
+
: path.posix.join(relativeDir.replace(/\\/g, '/'), entry.name);
|
|
328
|
+
await walk(childRelativeDir, depth + 1);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
await walk('.', 0);
|
|
332
|
+
return [...projectRoots].sort((left, right) => left.localeCompare(right));
|
|
333
|
+
}
|
|
334
|
+
function buildPrismaGenerateCommand(packageManager, target) {
|
|
335
|
+
const preferredScript = Object.entries(target.scripts).find(([, script]) => /\bprisma\s+generate\b/iu.test(script))?.[0] ??
|
|
336
|
+
(['prisma:generate', 'db:generate', 'prisma:client'].find((name) => Boolean(target.scripts[name])));
|
|
337
|
+
if (preferredScript) {
|
|
338
|
+
if (target.relativeDir === '.') {
|
|
339
|
+
return `${packageManager} run ${preferredScript}`;
|
|
340
|
+
}
|
|
341
|
+
if (packageManager === 'pnpm' && target.packageName) {
|
|
342
|
+
return `pnpm --filter ${target.packageName} run ${preferredScript}`;
|
|
343
|
+
}
|
|
344
|
+
return `${packageManager} --prefix ${target.relativeDir} run ${preferredScript}`;
|
|
345
|
+
}
|
|
346
|
+
if (target.relativeDir === '.') {
|
|
347
|
+
return `${packageManager} exec prisma generate`;
|
|
348
|
+
}
|
|
349
|
+
if (packageManager === 'pnpm' && target.packageName) {
|
|
350
|
+
return `pnpm --filter ${target.packageName} exec prisma generate`;
|
|
351
|
+
}
|
|
352
|
+
return `${packageManager} --prefix ${target.relativeDir} exec prisma generate`;
|
|
353
|
+
}
|
|
354
|
+
function hasPrismaScript(scripts) {
|
|
355
|
+
return Object.values(scripts).some((script) => /\bprisma\s+(generate|migrate)\b/iu.test(script));
|
|
356
|
+
}
|
|
357
|
+
async function detectPrismaTargets(workspaceRoot, packageManager, manifests) {
|
|
358
|
+
const targets = new Map();
|
|
359
|
+
for (const manifest of manifests) {
|
|
360
|
+
const manifestDir = manifest.relativeDir === '.'
|
|
361
|
+
? workspaceRoot
|
|
362
|
+
: path.join(workspaceRoot, ...manifest.relativeDir.split('/'));
|
|
363
|
+
const schemaPath = path.join(manifestDir, 'prisma', 'schema.prisma');
|
|
364
|
+
const hasSchema = await pathExists(schemaPath);
|
|
365
|
+
const hasPrismaDependency = manifest.dependencies.has('prisma') || manifest.dependencies.has('@prisma/client');
|
|
366
|
+
const hasPrismaEvidence = hasSchema || hasPrismaDependency || hasPrismaScript(manifest.scripts);
|
|
367
|
+
if (!hasPrismaEvidence) {
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const normalizedSchemaPath = hasSchema
|
|
371
|
+
? path.posix.join(manifest.relativeDir === '.' ? '' : manifest.relativeDir, 'prisma', 'schema.prisma').replace(/^\/+/u, '')
|
|
372
|
+
: path.posix.join(manifest.relativeDir === '.' ? '' : manifest.relativeDir, 'prisma', 'schema.prisma').replace(/^\/+/u, '');
|
|
373
|
+
const relativeDir = manifest.relativeDir;
|
|
374
|
+
const scripts = manifest.scripts;
|
|
375
|
+
const packageName = manifest.name;
|
|
376
|
+
const target = {
|
|
377
|
+
relativeDir: relativeDir.length === 0 ? '.' : relativeDir,
|
|
378
|
+
packageName,
|
|
379
|
+
schemaPath: normalizedSchemaPath,
|
|
380
|
+
generateCommand: buildPrismaGenerateCommand(packageManager, {
|
|
381
|
+
relativeDir: relativeDir.length === 0 ? '.' : relativeDir,
|
|
382
|
+
packageName,
|
|
383
|
+
scripts,
|
|
384
|
+
}),
|
|
385
|
+
};
|
|
386
|
+
const key = `${target.relativeDir}::${target.packageName ?? ''}::${target.generateCommand}`;
|
|
387
|
+
if (!targets.has(key)) {
|
|
388
|
+
targets.set(key, target);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return [...targets.values()];
|
|
392
|
+
}
|
|
393
|
+
async function detectRootPackageManagerFiles(workspaceRoot) {
|
|
394
|
+
const [hasPnpmLockfile, hasYarnLockfile, hasPackageLockfile, hasNpmShrinkwrap] = await Promise.all([
|
|
395
|
+
pathExists(path.join(workspaceRoot, 'pnpm-lock.yaml')),
|
|
396
|
+
pathExists(path.join(workspaceRoot, 'yarn.lock')),
|
|
397
|
+
pathExists(path.join(workspaceRoot, 'package-lock.json')),
|
|
398
|
+
pathExists(path.join(workspaceRoot, 'npm-shrinkwrap.json')),
|
|
399
|
+
]);
|
|
400
|
+
return {
|
|
401
|
+
hasPnpmLockfile,
|
|
402
|
+
hasYarnLockfile,
|
|
403
|
+
hasNpmLockfile: hasPackageLockfile || hasNpmShrinkwrap,
|
|
404
|
+
...(hasPackageLockfile
|
|
405
|
+
? { npmLockfilePath: 'package-lock.json' }
|
|
406
|
+
: hasNpmShrinkwrap
|
|
407
|
+
? { npmLockfilePath: 'npm-shrinkwrap.json' }
|
|
408
|
+
: {}),
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
async function detectGithubCiRepositoryCapabilities(workspaceRoot) {
|
|
412
|
+
const rootPackageJson = await readRootPackageJson(workspaceRoot);
|
|
413
|
+
const [{ hasPnpmLockfile, hasNpmLockfile, hasYarnLockfile }, hasPnpmWorkspace, hasAppsDir, hasPackagesDir] = await Promise.all([
|
|
414
|
+
detectRootPackageManagerFiles(workspaceRoot),
|
|
415
|
+
pathExists(path.join(workspaceRoot, 'pnpm-workspace.yaml')),
|
|
416
|
+
directoryExists(path.join(workspaceRoot, 'apps')),
|
|
417
|
+
directoryExists(path.join(workspaceRoot, 'packages')),
|
|
418
|
+
]);
|
|
419
|
+
const packageManager = resolvePackageManager({
|
|
420
|
+
rootPackageJson,
|
|
421
|
+
hasPnpmLockfile,
|
|
422
|
+
hasNpmLockfile,
|
|
423
|
+
hasYarnLockfile,
|
|
424
|
+
});
|
|
425
|
+
const manifests = await collectPackageManifests(workspaceRoot, rootPackageJson);
|
|
426
|
+
const hasNodeProject = manifests.length > 0;
|
|
427
|
+
const archpilotGovernanceWorkspaceLayout = detectArchpilotGovernanceWorkspaceLayout(manifests);
|
|
428
|
+
const prismaTargets = hasNodeProject
|
|
429
|
+
? await detectPrismaTargets(workspaceRoot, packageManager, manifests)
|
|
430
|
+
: [];
|
|
431
|
+
const projectRoots = await collectRepositoryProjectRoots(workspaceRoot);
|
|
432
|
+
let hasJavaProject = false;
|
|
433
|
+
let hasPythonProject = false;
|
|
434
|
+
let hasPhpProject = false;
|
|
435
|
+
let hasGoProject = false;
|
|
436
|
+
let hasTerraformProject = false;
|
|
437
|
+
let hasAnsibleProject = false;
|
|
438
|
+
let hasLiquibase = manifests.some((manifest) => Object.values(manifest.scripts).some((script) => /\bliquibase\b/iu.test(script)));
|
|
439
|
+
let hasFlyway = manifests.some((manifest) => Object.values(manifest.scripts).some((script) => /\bflyway\b/iu.test(script)));
|
|
440
|
+
let javaBuildTool;
|
|
441
|
+
let javaBuildCommand;
|
|
442
|
+
let pythonInstallCommand;
|
|
443
|
+
let phpInstallCommand;
|
|
444
|
+
let goBuildCommand;
|
|
445
|
+
for (const relativeDir of projectRoots) {
|
|
446
|
+
const absoluteDir = relativeDir === '.' ? workspaceRoot : path.join(workspaceRoot, ...relativeDir.split('/'));
|
|
447
|
+
const [pomXml, buildGradle, buildGradleKts, mavenWrapper, gradleWrapper, requirementsTxt, pyprojectToml, composerJson, goMod, liquibaseProperties, ansibleCfg,] = await Promise.all([
|
|
448
|
+
pathExists(path.join(absoluteDir, 'pom.xml')),
|
|
449
|
+
pathExists(path.join(absoluteDir, 'build.gradle')),
|
|
450
|
+
pathExists(path.join(absoluteDir, 'build.gradle.kts')),
|
|
451
|
+
pathExists(path.join(absoluteDir, 'mvnw')),
|
|
452
|
+
pathExists(path.join(absoluteDir, 'gradlew')),
|
|
453
|
+
pathExists(path.join(absoluteDir, 'requirements.txt')),
|
|
454
|
+
pathExists(path.join(absoluteDir, 'pyproject.toml')),
|
|
455
|
+
pathExists(path.join(absoluteDir, 'composer.json')),
|
|
456
|
+
pathExists(path.join(absoluteDir, 'go.mod')),
|
|
457
|
+
pathExists(path.join(absoluteDir, 'liquibase.properties')),
|
|
458
|
+
pathExists(path.join(absoluteDir, 'ansible.cfg')),
|
|
459
|
+
]);
|
|
460
|
+
const [pomText, gradleText, gradleKtsText] = await Promise.all([
|
|
461
|
+
pomXml ? readTextFileSafe(path.join(absoluteDir, 'pom.xml')) : Promise.resolve(undefined),
|
|
462
|
+
buildGradle ? readTextFileSafe(path.join(absoluteDir, 'build.gradle')) : Promise.resolve(undefined),
|
|
463
|
+
buildGradleKts ? readTextFileSafe(path.join(absoluteDir, 'build.gradle.kts')) : Promise.resolve(undefined),
|
|
464
|
+
]);
|
|
465
|
+
const hasLiquibaseChangelog = await directoryExists(path.join(absoluteDir, 'db', 'changelog'));
|
|
466
|
+
const hasFlywayMigrationDir = await directoryExists(path.join(absoluteDir, 'db', 'migration'));
|
|
467
|
+
const hasFlywayConfig = (await pathExists(path.join(absoluteDir, 'flyway.conf'))) ||
|
|
468
|
+
(await pathExists(path.join(absoluteDir, 'flyway.toml'))) ||
|
|
469
|
+
(await pathExists(path.join(absoluteDir, 'flyway.properties')));
|
|
470
|
+
const hasTerraformFiles = (await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true }).catch(() => []))
|
|
471
|
+
.some((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.tf'));
|
|
472
|
+
const hasPlaybookDir = await directoryExists(path.join(absoluteDir, 'playbooks'));
|
|
473
|
+
const hasRolesDir = await directoryExists(path.join(absoluteDir, 'roles'));
|
|
474
|
+
const hasAnsiblePlaybookFiles = (await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true }).catch(() => []))
|
|
475
|
+
.some((entry) => entry.isFile() &&
|
|
476
|
+
/site|playbook|deploy|provision/u.test(entry.name.toLowerCase()) &&
|
|
477
|
+
(entry.name.toLowerCase().endsWith('.yml') || entry.name.toLowerCase().endsWith('.yaml')));
|
|
478
|
+
if (pomXml || buildGradle || buildGradleKts) {
|
|
479
|
+
hasJavaProject = true;
|
|
480
|
+
if (!javaBuildTool) {
|
|
481
|
+
javaBuildTool = pomXml ? 'maven' : 'gradle';
|
|
482
|
+
javaBuildCommand = pomXml
|
|
483
|
+
? (mavenWrapper ? `${relativeDir === '.' ? '.' : relativeDir}/mvnw -B verify` : 'mvn -B verify')
|
|
484
|
+
: (gradleWrapper ? `${relativeDir === '.' ? '.' : relativeDir}/gradlew build` : 'gradle build');
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (requirementsTxt || pyprojectToml) {
|
|
488
|
+
hasPythonProject = true;
|
|
489
|
+
if (!pythonInstallCommand && requirementsTxt) {
|
|
490
|
+
pythonInstallCommand = relativeDir === '.'
|
|
491
|
+
? 'python -m pip install -r requirements.txt'
|
|
492
|
+
: `python -m pip install -r ${relativeDir}/requirements.txt`;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (composerJson) {
|
|
496
|
+
hasPhpProject = true;
|
|
497
|
+
if (!phpInstallCommand) {
|
|
498
|
+
phpInstallCommand = relativeDir === '.'
|
|
499
|
+
? 'composer install --no-interaction --no-progress --prefer-dist'
|
|
500
|
+
: `composer --working-dir=${relativeDir} install --no-interaction --no-progress --prefer-dist`;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (goMod) {
|
|
504
|
+
hasGoProject = true;
|
|
505
|
+
if (!goBuildCommand) {
|
|
506
|
+
goBuildCommand = relativeDir === '.'
|
|
507
|
+
? 'go test ./...'
|
|
508
|
+
: `(cd ${relativeDir} && go test ./...)`;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (hasTerraformFiles) {
|
|
512
|
+
hasTerraformProject = true;
|
|
513
|
+
}
|
|
514
|
+
if (ansibleCfg || hasPlaybookDir || hasRolesDir || hasAnsiblePlaybookFiles) {
|
|
515
|
+
hasAnsibleProject = true;
|
|
516
|
+
}
|
|
517
|
+
hasLiquibase =
|
|
518
|
+
hasLiquibase ||
|
|
519
|
+
liquibaseProperties ||
|
|
520
|
+
hasLiquibaseChangelog ||
|
|
521
|
+
/\bliquibase\b/iu.test(pomText ?? '') ||
|
|
522
|
+
/\bliquibase\b/iu.test(gradleText ?? '') ||
|
|
523
|
+
/\bliquibase\b/iu.test(gradleKtsText ?? '');
|
|
524
|
+
hasFlyway =
|
|
525
|
+
hasFlyway ||
|
|
526
|
+
hasFlywayConfig ||
|
|
527
|
+
hasFlywayMigrationDir ||
|
|
528
|
+
/\bflyway\b/iu.test(pomText ?? '') ||
|
|
529
|
+
/\bflyway\b/iu.test(gradleText ?? '') ||
|
|
530
|
+
/\bflyway\b/iu.test(gradleKtsText ?? '');
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
hasNodeProject,
|
|
534
|
+
hasJavaProject,
|
|
535
|
+
hasPythonProject,
|
|
536
|
+
hasPhpProject,
|
|
537
|
+
hasGoProject,
|
|
538
|
+
hasTerraformProject,
|
|
539
|
+
hasAnsibleProject,
|
|
540
|
+
hasMonorepoWorkspaces: hasPnpmWorkspace || hasWorkspaceConfig(rootPackageJson) || (hasAppsDir && hasPackagesDir),
|
|
541
|
+
hasVsCodeExtensionPackaging: Boolean(rootPackageJson?.contributes) ||
|
|
542
|
+
typeof rootPackageJson?.engines === 'object' &&
|
|
543
|
+
typeof (rootPackageJson.engines?.vscode) === 'string',
|
|
544
|
+
hasTurboRepo: await pathExists(path.join(workspaceRoot, 'turbo.json')),
|
|
545
|
+
hasNxWorkspace: await pathExists(path.join(workspaceRoot, 'nx.json')),
|
|
546
|
+
hasLiquibase,
|
|
547
|
+
hasFlyway,
|
|
548
|
+
packageManager: hasNodeProject ? packageManager : undefined,
|
|
549
|
+
...(javaBuildTool ? { javaBuildTool } : {}),
|
|
550
|
+
...(pythonInstallCommand ? { pythonInstallCommand } : {}),
|
|
551
|
+
...(phpInstallCommand ? { phpInstallCommand } : {}),
|
|
552
|
+
...(goBuildCommand ? { goBuildCommand } : {}),
|
|
553
|
+
...(javaBuildCommand ? { javaBuildCommand } : {}),
|
|
554
|
+
prismaTargets,
|
|
555
|
+
projectRoots,
|
|
556
|
+
...(archpilotGovernanceWorkspaceLayout
|
|
557
|
+
? {
|
|
558
|
+
archpilotGovernanceWorkspaceLayout: {
|
|
559
|
+
corePackageName: archpilotGovernanceWorkspaceLayout.core.packageName,
|
|
560
|
+
cliPackageName: archpilotGovernanceWorkspaceLayout.cli.packageName,
|
|
561
|
+
...(archpilotGovernanceWorkspaceLayout.vscode
|
|
562
|
+
? { vscodePackageName: archpilotGovernanceWorkspaceLayout.vscode.packageName }
|
|
563
|
+
: {}),
|
|
564
|
+
},
|
|
565
|
+
}
|
|
566
|
+
: {}),
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function buildValidationCommand(packageManager, options) {
|
|
570
|
+
void options.usesLocalCli;
|
|
571
|
+
void options.hasArchpilotBinary;
|
|
572
|
+
const workspaceCliPrefix = buildArchpilotCliCommandPrefix(packageManager);
|
|
573
|
+
if (options.usesLocalCli) {
|
|
574
|
+
return {
|
|
575
|
+
buildCommand: `${packageManager} run compile`,
|
|
576
|
+
validationCommand: `${workspaceCliPrefix} validate --ci`,
|
|
577
|
+
uploadCommand: `${workspaceCliPrefix} governance upload`,
|
|
578
|
+
validationUsesLocalResolution: false,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
if (options.hasArchpilotBinary) {
|
|
582
|
+
return {
|
|
583
|
+
validationCommand: `${workspaceCliPrefix} validate --ci`,
|
|
584
|
+
uploadCommand: `${workspaceCliPrefix} governance upload`,
|
|
585
|
+
validationUsesLocalResolution: false,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
validationCommand: `${workspaceCliPrefix} validate --ci`,
|
|
590
|
+
uploadCommand: `${workspaceCliPrefix} governance upload`,
|
|
591
|
+
validationUsesLocalResolution: false,
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
function buildBuildCommand(packageManager, rootPackageJson, isWorkspaceRepo, manifests) {
|
|
595
|
+
if (hasScript(rootPackageJson, 'build')) {
|
|
596
|
+
return `${packageManager} run build`;
|
|
597
|
+
}
|
|
598
|
+
if (isWorkspaceRepo && packageManager === 'pnpm') {
|
|
599
|
+
const workspaceManifests = manifests.filter((manifest) => manifest.relativeDir !== '.');
|
|
600
|
+
const buildableManifests = workspaceManifests.filter((manifest) => Boolean(manifest.scripts.build));
|
|
601
|
+
if (buildableManifests.length === 0) {
|
|
602
|
+
return undefined;
|
|
603
|
+
}
|
|
604
|
+
if (buildableManifests.length === workspaceManifests.length) {
|
|
605
|
+
return 'pnpm -r build';
|
|
606
|
+
}
|
|
607
|
+
return 'pnpm -r --if-present build';
|
|
608
|
+
}
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
function buildScopedWorkspaceOption(flagName, values) {
|
|
612
|
+
return values.map((value) => `${flagName} ${value}`).join(' ');
|
|
613
|
+
}
|
|
614
|
+
function buildArchpilotGovernanceInstallCommand(packageManager, hasRootLockfile, layout, packageManagerVersion) {
|
|
615
|
+
const governancePackages = [layout.core.packageName, layout.cli.packageName];
|
|
616
|
+
switch (packageManager) {
|
|
617
|
+
case 'pnpm': {
|
|
618
|
+
const installBase = hasRootLockfile ? 'pnpm install --frozen-lockfile' : 'pnpm install --no-frozen-lockfile';
|
|
619
|
+
return installBase;
|
|
620
|
+
}
|
|
621
|
+
case 'yarn':
|
|
622
|
+
return hasRootLockfile
|
|
623
|
+
? ((packageManagerVersion && !packageManagerVersion.startsWith('1.')) ? 'yarn install --immutable' : 'yarn install --frozen-lockfile')
|
|
624
|
+
: 'yarn install';
|
|
625
|
+
case 'npm':
|
|
626
|
+
default: {
|
|
627
|
+
const installBase = hasRootLockfile ? 'npm ci' : 'npm install';
|
|
628
|
+
return `${installBase} ${buildScopedWorkspaceOption('--workspace', governancePackages)}`.trim();
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
function buildArchpilotGovernanceBuildCommand(packageManager, layout) {
|
|
633
|
+
const buildablePackages = [layout.core, layout.cli].filter((pkg) => Boolean(pkg.scripts.build));
|
|
634
|
+
if (buildablePackages.length === 0) {
|
|
635
|
+
return undefined;
|
|
636
|
+
}
|
|
637
|
+
const commands = buildablePackages.map((pkg) => {
|
|
638
|
+
switch (packageManager) {
|
|
639
|
+
case 'pnpm':
|
|
640
|
+
return `pnpm --filter ${pkg.packageName} run build`;
|
|
641
|
+
case 'yarn':
|
|
642
|
+
return `yarn workspace ${pkg.packageName} run build`;
|
|
643
|
+
case 'npm':
|
|
644
|
+
default:
|
|
645
|
+
return `npm run build --workspace ${pkg.packageName}`;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
return commands.join('\n');
|
|
649
|
+
}
|
|
650
|
+
function filterPrismaTargetsForWorkspaceLayout(prismaTargets, layout) {
|
|
651
|
+
if (!layout) {
|
|
652
|
+
return prismaTargets;
|
|
653
|
+
}
|
|
654
|
+
const governancePackageNames = new Set([layout.core.packageName, layout.cli.packageName]);
|
|
655
|
+
const governanceRelativeDirs = new Set([layout.core.relativeDir, layout.cli.relativeDir]);
|
|
656
|
+
return prismaTargets.filter((target) => (target.packageName ? governancePackageNames.has(target.packageName) : false) ||
|
|
657
|
+
governanceRelativeDirs.has(target.relativeDir));
|
|
658
|
+
}
|
|
659
|
+
function appendRunCommand(lines, command, indent = ' ') {
|
|
660
|
+
if (command.includes('\n')) {
|
|
661
|
+
lines.push(`${indent}run: |`);
|
|
662
|
+
for (const line of command.split('\n')) {
|
|
663
|
+
lines.push(`${indent} ${line}`);
|
|
664
|
+
}
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
lines.push(`${indent}run: ${command}`);
|
|
668
|
+
}
|
|
669
|
+
function buildArchpilotCliCommandPrefix(packageManager) {
|
|
670
|
+
switch (packageManager) {
|
|
671
|
+
case 'pnpm':
|
|
672
|
+
return 'pnpm dlx @archpilotlabs/archpilot';
|
|
673
|
+
case 'yarn':
|
|
674
|
+
return 'yarn dlx @archpilotlabs/archpilot';
|
|
675
|
+
case 'npm':
|
|
676
|
+
default:
|
|
677
|
+
return 'npx @archpilotlabs/archpilot';
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function renderSetupSteps(strategy) {
|
|
681
|
+
const steps = [
|
|
682
|
+
' - name: Checkout repository',
|
|
683
|
+
' uses: actions/checkout@v4',
|
|
684
|
+
' with:',
|
|
685
|
+
' fetch-depth: 0',
|
|
686
|
+
'',
|
|
687
|
+
];
|
|
688
|
+
const usesCorepack = strategy.hasNodeProject && (strategy.packageManager === 'pnpm' ||
|
|
689
|
+
strategy.packageManager === 'yarn');
|
|
690
|
+
if (usesCorepack) {
|
|
691
|
+
steps.push(' - name: Enable Corepack');
|
|
692
|
+
steps.push(' run: corepack enable');
|
|
693
|
+
steps.push('');
|
|
694
|
+
}
|
|
695
|
+
if (strategy.hasNodeProject) {
|
|
696
|
+
steps.push(' - name: Setup Node.js');
|
|
697
|
+
steps.push(' uses: actions/setup-node@v4');
|
|
698
|
+
steps.push(' with:');
|
|
699
|
+
steps.push(` node-version: ${strategy.packageManager === 'pnpm' ? '20' : '22'}`);
|
|
700
|
+
if ((strategy.packageManager === 'npm' && strategy.hasRootLockfile) ||
|
|
701
|
+
strategy.packageManager === 'pnpm' ||
|
|
702
|
+
strategy.packageManager === 'yarn') {
|
|
703
|
+
steps.push(` cache: ${strategy.packageManager}`);
|
|
704
|
+
if (strategy.cacheDependencyPath) {
|
|
705
|
+
steps.push(` cache-dependency-path: ${strategy.cacheDependencyPath}`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
steps.push('');
|
|
709
|
+
}
|
|
710
|
+
if (strategy.hasNodeProject && strategy.packageManager === 'pnpm') {
|
|
711
|
+
steps.push(' - name: Prepare pnpm');
|
|
712
|
+
steps.push(` run: corepack prepare pnpm@${strategy.packageManagerVersion ?? defaultPnpmVersion} --activate`);
|
|
713
|
+
steps.push('');
|
|
714
|
+
}
|
|
715
|
+
if (strategy.hasNodeProject && strategy.packageManager === 'yarn') {
|
|
716
|
+
steps.push(' - name: Prepare Yarn');
|
|
717
|
+
steps.push(` run: corepack prepare yarn@${strategy.packageManagerVersion ?? defaultYarnVersion} --activate`);
|
|
718
|
+
steps.push('');
|
|
719
|
+
}
|
|
720
|
+
if (strategy.capabilities.hasJavaProject) {
|
|
721
|
+
steps.push(' - name: Setup Java');
|
|
722
|
+
steps.push(' uses: actions/setup-java@v4');
|
|
723
|
+
steps.push(' with:');
|
|
724
|
+
steps.push(' distribution: temurin');
|
|
725
|
+
steps.push(' java-version: 17');
|
|
726
|
+
steps.push('');
|
|
727
|
+
}
|
|
728
|
+
if (strategy.capabilities.hasPythonProject) {
|
|
729
|
+
steps.push(' - name: Setup Python');
|
|
730
|
+
steps.push(' uses: actions/setup-python@v5');
|
|
731
|
+
steps.push(' with:');
|
|
732
|
+
steps.push(' python-version: "3.12"');
|
|
733
|
+
steps.push('');
|
|
734
|
+
}
|
|
735
|
+
if (strategy.capabilities.hasPhpProject) {
|
|
736
|
+
steps.push(' - name: Setup PHP');
|
|
737
|
+
steps.push(' uses: shivammathur/setup-php@v2');
|
|
738
|
+
steps.push(' with:');
|
|
739
|
+
steps.push(' php-version: "8.2"');
|
|
740
|
+
steps.push('');
|
|
741
|
+
}
|
|
742
|
+
if (strategy.capabilities.hasGoProject) {
|
|
743
|
+
steps.push(' - name: Setup Go');
|
|
744
|
+
steps.push(' uses: actions/setup-go@v5');
|
|
745
|
+
steps.push(' with:');
|
|
746
|
+
steps.push(' go-version: "1.22"');
|
|
747
|
+
steps.push('');
|
|
748
|
+
}
|
|
749
|
+
return steps;
|
|
750
|
+
}
|
|
751
|
+
function renderInstallSteps(strategy) {
|
|
752
|
+
const steps = [];
|
|
753
|
+
if (strategy.hasNodeProject) {
|
|
754
|
+
steps.push(` - name: ${strategy.installStepName ?? 'Install dependencies'}`);
|
|
755
|
+
appendRunCommand(steps, strategy.installCommand);
|
|
756
|
+
}
|
|
757
|
+
if (strategy.capabilities.pythonInstallCommand) {
|
|
758
|
+
steps.push('');
|
|
759
|
+
steps.push(' - name: Install Python dependencies');
|
|
760
|
+
steps.push(` run: ${strategy.capabilities.pythonInstallCommand}`);
|
|
761
|
+
}
|
|
762
|
+
if (strategy.capabilities.phpInstallCommand) {
|
|
763
|
+
steps.push('');
|
|
764
|
+
steps.push(' - name: Install PHP dependencies');
|
|
765
|
+
steps.push(` run: ${strategy.capabilities.phpInstallCommand}`);
|
|
766
|
+
}
|
|
767
|
+
return steps;
|
|
768
|
+
}
|
|
769
|
+
function renderBuildAndToolingSteps(strategy) {
|
|
770
|
+
const steps = [];
|
|
771
|
+
for (const prismaTarget of strategy.prismaTargets) {
|
|
772
|
+
steps.push('');
|
|
773
|
+
steps.push(` - name: Generate Prisma client (${prismaTarget.relativeDir})`);
|
|
774
|
+
appendRunCommand(steps, prismaTarget.generateCommand);
|
|
775
|
+
}
|
|
776
|
+
if (strategy.buildCommand) {
|
|
777
|
+
steps.push('');
|
|
778
|
+
steps.push(` - name: ${strategy.buildStepName ?? 'Build repository'}`);
|
|
779
|
+
appendRunCommand(steps, strategy.buildCommand);
|
|
780
|
+
}
|
|
781
|
+
if (strategy.capabilities.javaBuildCommand) {
|
|
782
|
+
steps.push('');
|
|
783
|
+
steps.push(' - name: Build Java project');
|
|
784
|
+
steps.push(` run: ${strategy.capabilities.javaBuildCommand}`);
|
|
785
|
+
}
|
|
786
|
+
if (strategy.capabilities.goBuildCommand) {
|
|
787
|
+
steps.push('');
|
|
788
|
+
steps.push(' - name: Test Go project');
|
|
789
|
+
steps.push(` run: ${strategy.capabilities.goBuildCommand}`);
|
|
790
|
+
}
|
|
791
|
+
return steps;
|
|
792
|
+
}
|
|
793
|
+
async function detectGithubCiWorkflowStrategy(workspaceRoot) {
|
|
794
|
+
const rootPackageJson = await readRootPackageJson(workspaceRoot);
|
|
795
|
+
const [{ hasPnpmLockfile, hasNpmLockfile, hasYarnLockfile, npmLockfilePath }, capabilities] = await Promise.all([
|
|
796
|
+
detectRootPackageManagerFiles(workspaceRoot),
|
|
797
|
+
detectGithubCiRepositoryCapabilities(workspaceRoot),
|
|
798
|
+
]);
|
|
799
|
+
const packageManager = resolvePackageManager({
|
|
800
|
+
rootPackageJson,
|
|
801
|
+
hasPnpmLockfile,
|
|
802
|
+
hasNpmLockfile,
|
|
803
|
+
hasYarnLockfile,
|
|
804
|
+
});
|
|
805
|
+
const hasRootLockfile = packageManager === 'pnpm'
|
|
806
|
+
? hasPnpmLockfile
|
|
807
|
+
: packageManager === 'yarn'
|
|
808
|
+
? hasYarnLockfile
|
|
809
|
+
: hasNpmLockfile;
|
|
810
|
+
const isWorkspaceRepo = capabilities.hasMonorepoWorkspaces;
|
|
811
|
+
const manifests = await collectPackageManifests(workspaceRoot, rootPackageJson);
|
|
812
|
+
const hasNodeProject = capabilities.hasNodeProject;
|
|
813
|
+
const packageManagerVersion = extractPackageManagerVersion(rootPackageJson, packageManager);
|
|
814
|
+
const archpilotGovernanceWorkspaceLayout = detectArchpilotGovernanceWorkspaceLayout(manifests);
|
|
815
|
+
const prismaTargets = filterPrismaTargetsForWorkspaceLayout(capabilities.prismaTargets, archpilotGovernanceWorkspaceLayout);
|
|
816
|
+
let installCommand = 'npm install';
|
|
817
|
+
let cacheDependencyPath;
|
|
818
|
+
switch (packageManager) {
|
|
819
|
+
case 'pnpm':
|
|
820
|
+
installCommand = hasRootLockfile ? 'pnpm install --frozen-lockfile' : 'pnpm install --no-frozen-lockfile';
|
|
821
|
+
cacheDependencyPath = 'pnpm-lock.yaml';
|
|
822
|
+
break;
|
|
823
|
+
case 'yarn':
|
|
824
|
+
installCommand = hasRootLockfile
|
|
825
|
+
? ((packageManagerVersion && !packageManagerVersion.startsWith('1.')) ? 'yarn install --immutable' : 'yarn install --frozen-lockfile')
|
|
826
|
+
: 'yarn install';
|
|
827
|
+
cacheDependencyPath = hasRootLockfile ? 'yarn.lock' : undefined;
|
|
828
|
+
break;
|
|
829
|
+
case 'npm':
|
|
830
|
+
default:
|
|
831
|
+
installCommand = hasRootLockfile ? 'npm ci' : 'npm install';
|
|
832
|
+
cacheDependencyPath = hasRootLockfile ? npmLockfilePath : undefined;
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
if (archpilotGovernanceWorkspaceLayout) {
|
|
836
|
+
installCommand = buildArchpilotGovernanceInstallCommand(packageManager, hasRootLockfile, archpilotGovernanceWorkspaceLayout, packageManagerVersion);
|
|
837
|
+
}
|
|
838
|
+
const localCliEnabled = usesLocalArchpilotCli(rootPackageJson);
|
|
839
|
+
const hasArchpilotBinary = localCliEnabled || hasArchpilotDependency(manifests);
|
|
840
|
+
const validationStrategy = buildValidationCommand(packageManager, {
|
|
841
|
+
usesLocalCli: localCliEnabled && hasScript(rootPackageJson, 'compile'),
|
|
842
|
+
hasArchpilotBinary,
|
|
843
|
+
});
|
|
844
|
+
const buildCommand = validationStrategy.buildCommand ??
|
|
845
|
+
(archpilotGovernanceWorkspaceLayout
|
|
846
|
+
? buildArchpilotGovernanceBuildCommand(packageManager, archpilotGovernanceWorkspaceLayout)
|
|
847
|
+
: undefined) ??
|
|
848
|
+
buildBuildCommand(packageManager, rootPackageJson, isWorkspaceRepo, manifests);
|
|
849
|
+
return {
|
|
850
|
+
packageManager,
|
|
851
|
+
...(packageManagerVersion ? { packageManagerVersion } : {}),
|
|
852
|
+
hasPnpmPackageManagerDeclaration: hasPnpmPackageManagerDeclaration(rootPackageJson),
|
|
853
|
+
hasNodeProject,
|
|
854
|
+
hasRootPackageJson: Boolean(rootPackageJson),
|
|
855
|
+
hasRootLockfile,
|
|
856
|
+
isWorkspaceRepo,
|
|
857
|
+
installCommand,
|
|
858
|
+
buildCommand,
|
|
859
|
+
...(validationStrategy.validationCommand
|
|
860
|
+
? { validationCommand: validationStrategy.validationCommand }
|
|
861
|
+
: {}),
|
|
862
|
+
...(validationStrategy.uploadCommand ? { uploadCommand: validationStrategy.uploadCommand } : {}),
|
|
863
|
+
validationUsesLocalResolution: validationStrategy.validationUsesLocalResolution,
|
|
864
|
+
...(validationStrategy.validationOmittedReason
|
|
865
|
+
? { validationOmittedReason: validationStrategy.validationOmittedReason }
|
|
866
|
+
: {}),
|
|
867
|
+
usesLocalArchpilotCli: localCliEnabled,
|
|
868
|
+
hasArchpilotBinary,
|
|
869
|
+
...(cacheDependencyPath ? { cacheDependencyPath } : {}),
|
|
870
|
+
prismaTargets,
|
|
871
|
+
...(archpilotGovernanceWorkspaceLayout
|
|
872
|
+
? {
|
|
873
|
+
installStepName: 'Install ArchPilot governance dependencies',
|
|
874
|
+
}
|
|
875
|
+
: {}),
|
|
876
|
+
capabilities,
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
async function generateGithubCiGovernanceWorkflow(workspaceRoot) {
|
|
880
|
+
const strategy = await detectGithubCiWorkflowStrategy(workspaceRoot);
|
|
881
|
+
const setupSteps = renderSetupSteps(strategy);
|
|
882
|
+
const archpilotCliPrefix = buildArchpilotCliCommandPrefix(strategy.packageManager);
|
|
883
|
+
const workflowLines = [
|
|
884
|
+
'name: ArchPilot CI Governance',
|
|
885
|
+
'',
|
|
886
|
+
'on:',
|
|
887
|
+
' pull_request:',
|
|
888
|
+
' workflow_dispatch:',
|
|
889
|
+
' inputs:',
|
|
890
|
+
' drift_policy:',
|
|
891
|
+
" description: 'How baseline drift should affect the workflow result'",
|
|
892
|
+
' required: false',
|
|
893
|
+
" default: 'warn'",
|
|
894
|
+
' type: choice',
|
|
895
|
+
' options:',
|
|
896
|
+
" - 'warn'",
|
|
897
|
+
" - 'fail'",
|
|
898
|
+
' push:',
|
|
899
|
+
' branches:',
|
|
900
|
+
' - main',
|
|
901
|
+
'',
|
|
902
|
+
'jobs:',
|
|
903
|
+
' validate-architecture:',
|
|
904
|
+
' runs-on: ubuntu-latest',
|
|
905
|
+
' permissions:',
|
|
906
|
+
' contents: read',
|
|
907
|
+
' pull-requests: write',
|
|
908
|
+
' steps:',
|
|
909
|
+
...setupSteps,
|
|
910
|
+
];
|
|
911
|
+
const installSteps = renderInstallSteps(strategy);
|
|
912
|
+
if (installSteps.length > 0) {
|
|
913
|
+
workflowLines.push('');
|
|
914
|
+
workflowLines.push(...installSteps);
|
|
915
|
+
}
|
|
916
|
+
const buildAndToolingSteps = renderBuildAndToolingSteps(strategy);
|
|
917
|
+
if (buildAndToolingSteps.length > 0) {
|
|
918
|
+
workflowLines.push(...buildAndToolingSteps);
|
|
919
|
+
}
|
|
920
|
+
workflowLines.push('');
|
|
921
|
+
workflowLines.push(' - name: Print GitHub event context');
|
|
922
|
+
workflowLines.push(' run: |');
|
|
923
|
+
workflowLines.push(' echo "github.event_name=${{ github.event_name }}"');
|
|
924
|
+
workflowLines.push(' echo "github.ref=${{ github.ref }}"');
|
|
925
|
+
workflowLines.push(' echo "github.base_ref=${{ github.base_ref }}"');
|
|
926
|
+
workflowLines.push(' echo "github.head_ref=${{ github.head_ref }}"');
|
|
927
|
+
workflowLines.push('');
|
|
928
|
+
workflowLines.push(' - name: Run ArchPilot CI validation');
|
|
929
|
+
workflowLines.push(' id: archpilot_validate');
|
|
930
|
+
workflowLines.push(' continue-on-error: true');
|
|
931
|
+
workflowLines.push(` run: ${strategy.validationCommand ?? `${archpilotCliPrefix} validate --ci`}`);
|
|
932
|
+
workflowLines.push('');
|
|
933
|
+
workflowLines.push(' - name: Run ArchPilot baseline drift check');
|
|
934
|
+
workflowLines.push(" if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
|
|
935
|
+
workflowLines.push(' id: archpilot_baseline');
|
|
936
|
+
workflowLines.push(' continue-on-error: true');
|
|
937
|
+
workflowLines.push(' shell: bash');
|
|
938
|
+
workflowLines.push(' run: |');
|
|
939
|
+
workflowLines.push(' set +e');
|
|
940
|
+
workflowLines.push(` ${archpilotCliPrefix} baseline check`);
|
|
941
|
+
workflowLines.push(' drift_exit=$?');
|
|
942
|
+
workflowLines.push(' echo "exit_code=$drift_exit" >> "$GITHUB_OUTPUT"');
|
|
943
|
+
workflowLines.push(' exit "$drift_exit"');
|
|
944
|
+
workflowLines.push('');
|
|
945
|
+
workflowLines.push(' - name: Generate ArchPilot PR review');
|
|
946
|
+
workflowLines.push(" if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
|
|
947
|
+
workflowLines.push(' id: archpilot_pr_review');
|
|
948
|
+
workflowLines.push(' continue-on-error: true');
|
|
949
|
+
workflowLines.push(` run: ${archpilotCliPrefix} review pr`);
|
|
950
|
+
workflowLines.push('');
|
|
951
|
+
workflowLines.push(' - name: Publish ArchPilot PR comment');
|
|
952
|
+
workflowLines.push(" if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
|
|
953
|
+
workflowLines.push(' id: archpilot_pr_comment');
|
|
954
|
+
workflowLines.push(' continue-on-error: true');
|
|
955
|
+
workflowLines.push(' env:');
|
|
956
|
+
workflowLines.push(' GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}');
|
|
957
|
+
workflowLines.push(` run: ${archpilotCliPrefix} ci github`);
|
|
958
|
+
workflowLines.push('');
|
|
959
|
+
workflowLines.push(' - name: Upload ArchPilot governance snapshot');
|
|
960
|
+
workflowLines.push(" if: steps.archpilot_validate.outcome == 'success' && github.event_name == 'push' && github.ref == 'refs/heads/main'");
|
|
961
|
+
workflowLines.push(' env:');
|
|
962
|
+
workflowLines.push(' ARCHPILOT_API_TOKEN: ${{ secrets.ARCHPILOT_API_TOKEN }}');
|
|
963
|
+
workflowLines.push(' ARCHPILOT_UPLOAD_MODE: ci');
|
|
964
|
+
workflowLines.push(' CI: "true"');
|
|
965
|
+
workflowLines.push(' shell: bash');
|
|
966
|
+
workflowLines.push(' run: |');
|
|
967
|
+
workflowLines.push(' if [ -z "$ARCHPILOT_API_TOKEN" ]; then');
|
|
968
|
+
workflowLines.push(' echo "ArchPilot governance upload skipped because ARCHPILOT_API_TOKEN secret is not configured."');
|
|
969
|
+
workflowLines.push(' exit 0');
|
|
970
|
+
workflowLines.push(' fi');
|
|
971
|
+
workflowLines.push('');
|
|
972
|
+
workflowLines.push(` ${(strategy.uploadCommand ?? `${archpilotCliPrefix} governance upload`)} --token "\${ARCHPILOT_API_TOKEN}"`);
|
|
973
|
+
workflowLines.push('');
|
|
974
|
+
workflowLines.push(' # Required repository secrets for main-branch upload:');
|
|
975
|
+
workflowLines.push(' # - ARCHPILOT_API_TOKEN');
|
|
976
|
+
workflowLines.push('');
|
|
977
|
+
workflowLines.push(' - name: Finalize workflow result');
|
|
978
|
+
workflowLines.push(' if: always()');
|
|
979
|
+
workflowLines.push(' env:');
|
|
980
|
+
workflowLines.push(' VALIDATION_OUTCOME: ${{ steps.archpilot_validate.outcome }}');
|
|
981
|
+
workflowLines.push(' BASELINE_OUTCOME: ${{ steps.archpilot_baseline.outcome }}');
|
|
982
|
+
workflowLines.push(' BASELINE_EXIT_CODE: ${{ steps.archpilot_baseline.outputs.exit_code }}');
|
|
983
|
+
workflowLines.push(' PR_REVIEW_OUTCOME: ${{ steps.archpilot_pr_review.outcome }}');
|
|
984
|
+
workflowLines.push(' PR_COMMENT_OUTCOME: ${{ steps.archpilot_pr_comment.outcome }}');
|
|
985
|
+
workflowLines.push(" DRIFT_POLICY: ${{ github.event_name == 'workflow_dispatch' && inputs.drift_policy || 'warn' }}");
|
|
986
|
+
workflowLines.push(' shell: bash');
|
|
987
|
+
workflowLines.push(' run: |');
|
|
988
|
+
workflowLines.push(' if [ "$VALIDATION_OUTCOME" = "failure" ]; then');
|
|
989
|
+
workflowLines.push(' echo "ArchPilot validation failed."');
|
|
990
|
+
workflowLines.push(' exit 1');
|
|
991
|
+
workflowLines.push(' fi');
|
|
992
|
+
workflowLines.push('');
|
|
993
|
+
workflowLines.push(' if [ "$BASELINE_OUTCOME" = "failure" ]; then');
|
|
994
|
+
workflowLines.push(' if [ "$BASELINE_EXIT_CODE" = "2" ]; then');
|
|
995
|
+
workflowLines.push(' echo "ArchPilot baseline check could not complete because the baseline is missing or invalid."');
|
|
996
|
+
workflowLines.push(' echo "Run `archpilot baseline create` to enable drift tracking. Continuing without failing CI."');
|
|
997
|
+
workflowLines.push(' exit 0');
|
|
998
|
+
workflowLines.push(' fi');
|
|
999
|
+
workflowLines.push('');
|
|
1000
|
+
workflowLines.push(' if [ "$BASELINE_EXIT_CODE" = "1" ]; then');
|
|
1001
|
+
workflowLines.push(' if [ "$DRIFT_POLICY" = "fail" ]; then');
|
|
1002
|
+
workflowLines.push(' echo "ArchPilot baseline drift detected and drift policy is fail."');
|
|
1003
|
+
workflowLines.push(' exit 1');
|
|
1004
|
+
workflowLines.push(' fi');
|
|
1005
|
+
workflowLines.push('');
|
|
1006
|
+
workflowLines.push(' echo "ArchPilot baseline drift detected, but drift policy is warn. Continuing."');
|
|
1007
|
+
workflowLines.push(' exit 0');
|
|
1008
|
+
workflowLines.push(' fi');
|
|
1009
|
+
workflowLines.push('');
|
|
1010
|
+
workflowLines.push(' if [ -n "$BASELINE_EXIT_CODE" ]; then');
|
|
1011
|
+
workflowLines.push(' echo "ArchPilot baseline check failed unexpectedly with exit code $BASELINE_EXIT_CODE."');
|
|
1012
|
+
workflowLines.push(' else');
|
|
1013
|
+
workflowLines.push(' echo "ArchPilot baseline check failed unexpectedly without an exit code."');
|
|
1014
|
+
workflowLines.push(' fi');
|
|
1015
|
+
workflowLines.push(' exit 1');
|
|
1016
|
+
workflowLines.push(' fi');
|
|
1017
|
+
workflowLines.push('');
|
|
1018
|
+
workflowLines.push(' if [ "$PR_REVIEW_OUTCOME" = "failure" ]; then');
|
|
1019
|
+
workflowLines.push(' echo "ArchPilot PR review generation failed, but validation passed. Continuing because reporting is non-blocking."');
|
|
1020
|
+
workflowLines.push(' fi');
|
|
1021
|
+
workflowLines.push('');
|
|
1022
|
+
workflowLines.push(' if [ "$PR_COMMENT_OUTCOME" = "failure" ]; then');
|
|
1023
|
+
workflowLines.push(' echo "ArchPilot PR comment publishing failed, but validation passed. Continuing because reporting is non-blocking."');
|
|
1024
|
+
workflowLines.push(' fi');
|
|
1025
|
+
workflowLines.push('');
|
|
1026
|
+
workflowLines.push(' echo "ArchPilot workflow completed successfully."');
|
|
1027
|
+
workflowLines.push('');
|
|
1028
|
+
return workflowLines.join('\n');
|
|
1029
|
+
}
|
|
1030
|
+
async function generateCiValidationWorkflow(provider, workspaceRoot) {
|
|
1031
|
+
switch (provider) {
|
|
1032
|
+
case 'github':
|
|
1033
|
+
return generateGithubCiGovernanceWorkflow(workspaceRoot);
|
|
1034
|
+
case 'gitlab':
|
|
1035
|
+
case 'azure':
|
|
1036
|
+
case 'bitbucket':
|
|
1037
|
+
case 'jenkins':
|
|
1038
|
+
default:
|
|
1039
|
+
throw new Error(`CI provider '${provider}' is not supported yet.`);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
//# sourceMappingURL=ciWorkflowTemplates.js.map
|