@archpilotlabs/archpilot 0.0.16 → 0.0.17
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 +217 -38
- package/package.json +1 -1
package/dist/archpilot-cli.js
CHANGED
|
@@ -214124,6 +214124,29 @@ async function countContractFiles(contractsDir) {
|
|
|
214124
214124
|
return 0;
|
|
214125
214125
|
}
|
|
214126
214126
|
}
|
|
214127
|
+
function countGovernedModulesFromConfig(value) {
|
|
214128
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
214129
|
+
return 0;
|
|
214130
|
+
}
|
|
214131
|
+
const typed = value;
|
|
214132
|
+
const modules = typed.modules;
|
|
214133
|
+
if (Array.isArray(modules)) {
|
|
214134
|
+
return modules.filter((entry) => typeof entry === "string" && entry.trim().length > 0).length;
|
|
214135
|
+
}
|
|
214136
|
+
if (modules && typeof modules === "object" && !Array.isArray(modules)) {
|
|
214137
|
+
return Object.keys(modules).filter((key) => key.trim().length > 0).length;
|
|
214138
|
+
}
|
|
214139
|
+
return 0;
|
|
214140
|
+
}
|
|
214141
|
+
async function readGovernedModuleCount(workspaceRoot) {
|
|
214142
|
+
const architecturePath = path5.join(workspaceRoot, ".archpilot", "architecture.json");
|
|
214143
|
+
try {
|
|
214144
|
+
const raw = await import_node_fs5.promises.readFile(architecturePath, { encoding: "utf8" });
|
|
214145
|
+
return countGovernedModulesFromConfig(JSON.parse(raw));
|
|
214146
|
+
} catch {
|
|
214147
|
+
return 0;
|
|
214148
|
+
}
|
|
214149
|
+
}
|
|
214127
214150
|
async function readValidationStatusFromWorkspace(workspaceRoot) {
|
|
214128
214151
|
const validationStatusPath = path5.join(workspaceRoot, ".archpilot", "validation-status.json");
|
|
214129
214152
|
let raw;
|
|
@@ -214145,8 +214168,9 @@ async function readValidationStatusFromWorkspace(workspaceRoot) {
|
|
|
214145
214168
|
async function buildSetupSnapshot(workspaceRoot, validationStatus, options) {
|
|
214146
214169
|
const archpilotDir = path5.join(workspaceRoot, ".archpilot");
|
|
214147
214170
|
const contractsDir = path5.join(archpilotDir, "contracts");
|
|
214148
|
-
const [hasArchitectureConfig, hasDependencyRules, hasLayerRules, hasContractsFolder, hasGithubCiWorkflow, detectedBaselineSnapshot, detectedDriftReport, detectedReviewReport] = await Promise.all([
|
|
214171
|
+
const [hasArchitectureConfig, governedModuleCount, hasDependencyRules, hasLayerRules, hasContractsFolder, hasGithubCiWorkflow, detectedBaselineSnapshot, detectedDriftReport, detectedReviewReport] = await Promise.all([
|
|
214149
214172
|
pathExists3(path5.join(archpilotDir, "architecture.json")),
|
|
214173
|
+
readGovernedModuleCount(workspaceRoot),
|
|
214150
214174
|
pathExists3(path5.join(archpilotDir, "dependency-rules.json")),
|
|
214151
214175
|
pathExists3(path5.join(archpilotDir, "layer-rules.json")),
|
|
214152
214176
|
pathExists3(contractsDir),
|
|
@@ -214167,6 +214191,7 @@ async function buildSetupSnapshot(workspaceRoot, validationStatus, options) {
|
|
|
214167
214191
|
});
|
|
214168
214192
|
return {
|
|
214169
214193
|
hasArchitectureConfig,
|
|
214194
|
+
governedModuleCount,
|
|
214170
214195
|
hasDependencyRules,
|
|
214171
214196
|
hasLayerRules,
|
|
214172
214197
|
hasContractsFolder,
|
|
@@ -214204,9 +214229,11 @@ function buildModelFromSnapshot(snapshot, generatedAtUtc, renderContext) {
|
|
|
214204
214229
|
const hasMissingDependencyRules = !snapshot.hasDependencyRules;
|
|
214205
214230
|
const hasMissingLayerRules = !snapshot.hasLayerRules;
|
|
214206
214231
|
const hasMissingContracts = snapshot.contractFileCount === 0;
|
|
214232
|
+
const hasGovernedModules = snapshot.governedModuleCount > 0;
|
|
214233
|
+
const hasMissingInitialSetupArtifacts = hasMissingDependencyRules || hasMissingLayerRules || hasGovernedModules && hasMissingContracts;
|
|
214207
214234
|
const missingGithubCiWorkflow = firstSuccessfulValidationCompleted && !snapshot.hasGithubCiWorkflow;
|
|
214208
214235
|
const missingAdrScaffolds = firstSuccessfulValidationCompleted && snapshot.hasAdrRelatedFindings && snapshot.requiredAdrScaffoldCount > 0;
|
|
214209
|
-
const setupGapCountFromFiles = (hasMissingDependencyRules ? 1 : 0) + (hasMissingLayerRules ? 1 : 0) + (hasMissingContracts ? 1 : 0);
|
|
214236
|
+
const setupGapCountFromFiles = (hasMissingDependencyRules ? 1 : 0) + (hasMissingLayerRules ? 1 : 0) + (hasGovernedModules && hasMissingContracts ? 1 : 0);
|
|
214210
214237
|
const setupGapCount = typeof setupGapCountFromStatus === "number" ? ensureScore(setupGapCountFromStatus, 0, 1e3) : setupGapCountFromFiles;
|
|
214211
214238
|
const readinessScore = typeof summary?.readinessScore === "number" ? ensureScore(summary.readinessScore) : snapshot.hasArchitectureConfig ? ensureScore(100 - setupGapCountFromFiles * 20) : 0;
|
|
214212
214239
|
const architectureHealthScore = typeof summary?.healthScore === "number" ? ensureScore(summary.healthScore) : void 0;
|
|
@@ -214243,8 +214270,8 @@ function buildModelFromSnapshot(snapshot, generatedAtUtc, renderContext) {
|
|
|
214243
214270
|
{
|
|
214244
214271
|
id: "contracts",
|
|
214245
214272
|
label: "Module contracts generated",
|
|
214246
|
-
completed: snapshot.contractFileCount > 0,
|
|
214247
|
-
description: snapshot.contractFileCount > 0 ? `${snapshot.contractFileCount} contract file(s) found.` : "No .archpilot/contracts/*.contract.json files found."
|
|
214273
|
+
completed: !hasGovernedModules || snapshot.contractFileCount > 0,
|
|
214274
|
+
description: !hasGovernedModules ? "No governed modules configured." : snapshot.contractFileCount > 0 ? `${snapshot.contractFileCount} contract file(s) found.` : "No .archpilot/contracts/*.contract.json files found."
|
|
214248
214275
|
},
|
|
214249
214276
|
{
|
|
214250
214277
|
id: "github-ci-governance",
|
|
@@ -214376,29 +214403,51 @@ function buildModelFromSnapshot(snapshot, generatedAtUtc, renderContext) {
|
|
|
214376
214403
|
});
|
|
214377
214404
|
} else if (!firstSuccessfulValidationCompleted) {
|
|
214378
214405
|
pushStage({
|
|
214379
|
-
id: "validate",
|
|
214380
|
-
title: "Validate",
|
|
214381
|
-
description: "Run the first validation pass to establish findings, readiness, and architecture health.",
|
|
214406
|
+
id: hasGovernedModules && hasMissingInitialSetupArtifacts ? "setup" : "validate",
|
|
214407
|
+
title: hasGovernedModules && hasMissingInitialSetupArtifacts ? "Setup" : "Validate",
|
|
214408
|
+
description: hasGovernedModules && hasMissingInitialSetupArtifacts ? "Generate missing setup artifacts before the first validation pass." : "Run the first validation pass to establish findings, readiness, and architecture health.",
|
|
214382
214409
|
steps: [
|
|
214383
|
-
|
|
214384
|
-
|
|
214385
|
-
|
|
214386
|
-
|
|
214387
|
-
|
|
214388
|
-
|
|
214389
|
-
|
|
214410
|
+
...hasGovernedModules && hasMissingInitialSetupArtifacts ? [
|
|
214411
|
+
{
|
|
214412
|
+
id: "generate-missing-config-contracts",
|
|
214413
|
+
title: "Generate Missing Config & Contracts",
|
|
214414
|
+
description: "Create dependency/layer config and module contracts before first validation.",
|
|
214415
|
+
priority: 1,
|
|
214416
|
+
action: {
|
|
214417
|
+
label: "Generate Missing Config & Contracts",
|
|
214418
|
+
command: "archpilot bootstrap --with-contracts",
|
|
214419
|
+
inspectorActionId: "bootstrap-config-and-contracts",
|
|
214420
|
+
description: "Create missing setup config and module contracts in one deterministic pass."
|
|
214421
|
+
}
|
|
214422
|
+
},
|
|
214423
|
+
{
|
|
214424
|
+
id: "run-validation",
|
|
214425
|
+
title: "Run Architecture Validation",
|
|
214426
|
+
description: "Validate after setup artifacts exist to reduce first-run setup noise.",
|
|
214427
|
+
priority: 2,
|
|
214428
|
+
action: runValidationAction
|
|
214429
|
+
}
|
|
214430
|
+
] : [
|
|
214431
|
+
{
|
|
214432
|
+
id: "run-validation",
|
|
214433
|
+
title: "Run Architecture Validation",
|
|
214434
|
+
description: "Validate the current architecture and generate findings for the Inspector.",
|
|
214435
|
+
priority: 1,
|
|
214436
|
+
action: runValidationAction
|
|
214437
|
+
}
|
|
214438
|
+
],
|
|
214390
214439
|
{
|
|
214391
214440
|
id: "review-findings",
|
|
214392
214441
|
title: "Review Findings",
|
|
214393
214442
|
description: "Use Findings to inspect architecture violations, policy issues, and structural problems.",
|
|
214394
|
-
priority: 2,
|
|
214443
|
+
priority: hasGovernedModules && hasMissingInitialSetupArtifacts ? 3 : 2,
|
|
214395
214444
|
action: reviewFindingsAction
|
|
214396
214445
|
},
|
|
214397
214446
|
{
|
|
214398
214447
|
id: "fix-structural-issues",
|
|
214399
214448
|
title: "Fix structural issues",
|
|
214400
214449
|
description: "Address the most important module boundary and dependency problems first.",
|
|
214401
|
-
priority: 3
|
|
214450
|
+
priority: hasGovernedModules && hasMissingInitialSetupArtifacts ? 4 : 3
|
|
214402
214451
|
}
|
|
214403
214452
|
]
|
|
214404
214453
|
});
|
|
@@ -214568,6 +214617,11 @@ function buildModelFromSnapshot(snapshot, generatedAtUtc, renderContext) {
|
|
|
214568
214617
|
label: "Run Smart Init",
|
|
214569
214618
|
command: "archpilot smart-init-proposal",
|
|
214570
214619
|
description: "Detect and review a deterministic architecture proposal for this repository."
|
|
214620
|
+
} : !firstSuccessfulValidationCompleted && hasGovernedModules && hasMissingInitialSetupArtifacts ? {
|
|
214621
|
+
label: "Generate Missing Config & Contracts",
|
|
214622
|
+
command: "archpilot bootstrap --with-contracts",
|
|
214623
|
+
inspectorActionId: "bootstrap-config-and-contracts",
|
|
214624
|
+
description: "Create missing setup config and module contracts before the first validation run."
|
|
214571
214625
|
} : !firstSuccessfulValidationCompleted ? runValidationAction : setupGapCount > 0 ? hasMissingDependencyRules || hasMissingLayerRules ? {
|
|
214572
214626
|
label: "Bootstrap Missing Config",
|
|
214573
214627
|
command: "archpilot bootstrap --with-contracts",
|
|
@@ -217898,6 +217952,21 @@ var highConfidenceDomainNames = /* @__PURE__ */ new Set([
|
|
|
217898
217952
|
"workflow",
|
|
217899
217953
|
"workflows"
|
|
217900
217954
|
]);
|
|
217955
|
+
var componentRoleNames = /* @__PURE__ */ new Set([
|
|
217956
|
+
"app",
|
|
217957
|
+
"application",
|
|
217958
|
+
"backend",
|
|
217959
|
+
"bff",
|
|
217960
|
+
"client",
|
|
217961
|
+
"engine",
|
|
217962
|
+
"frontend",
|
|
217963
|
+
"gateway",
|
|
217964
|
+
"ledger",
|
|
217965
|
+
"mobile",
|
|
217966
|
+
"service",
|
|
217967
|
+
"web",
|
|
217968
|
+
"worker"
|
|
217969
|
+
]);
|
|
217901
217970
|
var frontendUtilityDirectoryNames = /* @__PURE__ */ new Set([
|
|
217902
217971
|
"components",
|
|
217903
217972
|
"hooks",
|
|
@@ -217993,6 +218062,40 @@ function isLowValueModuleName(moduleName) {
|
|
|
217993
218062
|
function moduleNameSegments(moduleName) {
|
|
217994
218063
|
return moduleName.toLowerCase().split(/[\/._-]+/u).map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
217995
218064
|
}
|
|
218065
|
+
function normalizeIdentity(value) {
|
|
218066
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/gu, "");
|
|
218067
|
+
}
|
|
218068
|
+
function pathLeafIdentity(value) {
|
|
218069
|
+
const normalized = normalizePath5(value).replace(/\/+$/gu, "");
|
|
218070
|
+
const leaf = normalized.split("/").filter((segment) => segment.length > 0).at(-1) ?? normalized;
|
|
218071
|
+
return normalizeIdentity(leaf);
|
|
218072
|
+
}
|
|
218073
|
+
function getComponentAlignedEvidence(input2) {
|
|
218074
|
+
const modulePath = normalizePath5(input2.modulePath).replace(/\/+$/gu, "");
|
|
218075
|
+
const moduleNameIdentity = normalizeIdentity(input2.moduleName);
|
|
218076
|
+
const modulePathLeaf = pathLeafIdentity(modulePath);
|
|
218077
|
+
const matchingPath = input2.context?.componentPaths?.map((entry) => normalizePath5(entry).replace(/\/+$/gu, "")).find(
|
|
218078
|
+
(componentPath) => componentPath.length > 0 && componentPath !== "." && (componentPath === modulePath || componentPath.startsWith(`${modulePath}/`) || modulePath.startsWith(`${componentPath}/`))
|
|
218079
|
+
);
|
|
218080
|
+
if (matchingPath) {
|
|
218081
|
+
return `Matches detected component/service/app path ${matchingPath}`;
|
|
218082
|
+
}
|
|
218083
|
+
const matchingName = input2.context?.componentNames?.map(normalizeIdentity).find((identity) => identity.length > 0 && (identity === moduleNameIdentity || identity === modulePathLeaf));
|
|
218084
|
+
if (matchingName) {
|
|
218085
|
+
return `Matches detected component/service/app identity ${input2.moduleName}`;
|
|
218086
|
+
}
|
|
218087
|
+
const matchingResourcePath = input2.context?.resourcePaths?.map((entry) => normalizePath5(entry).replace(/\/+$/gu, "")).find(
|
|
218088
|
+
(resourcePath) => resourcePath.length > 0 && resourcePath !== "." && (resourcePath === modulePath || resourcePath.startsWith(`${modulePath}/`) || modulePath.startsWith(`${resourcePath}/`))
|
|
218089
|
+
);
|
|
218090
|
+
if (matchingResourcePath) {
|
|
218091
|
+
return `Matches detected resource path ${matchingResourcePath}`;
|
|
218092
|
+
}
|
|
218093
|
+
const matchingResourceName = input2.context?.resourceNames?.map(normalizeIdentity).find((identity) => identity.length > 0 && (identity === moduleNameIdentity || identity === modulePathLeaf));
|
|
218094
|
+
if (matchingResourceName) {
|
|
218095
|
+
return `Matches detected resource identity ${input2.moduleName}`;
|
|
218096
|
+
}
|
|
218097
|
+
return void 0;
|
|
218098
|
+
}
|
|
217996
218099
|
function classifyModuleCandidate(input2) {
|
|
217997
218100
|
const evidence = [];
|
|
217998
218101
|
const segments = moduleNameSegments(input2.moduleName);
|
|
@@ -218001,6 +218104,7 @@ function classifyModuleCandidate(input2) {
|
|
|
218001
218104
|
const hasTechnicalLayerName = segments.some((segment) => technicalLayerNames.has(segment));
|
|
218002
218105
|
const hasSharedInfrastructureName = segments.some((segment) => sharedInfrastructureNames.has(segment));
|
|
218003
218106
|
const hasDomainName = segments.some((segment) => highConfidenceDomainNames.has(segment));
|
|
218107
|
+
const hasComponentRoleName = segments.some((segment) => componentRoleNames.has(segment));
|
|
218004
218108
|
const underExplicitArchitectureRoot = ["modules", "features", "domain", "domains"].includes(rootLeaf);
|
|
218005
218109
|
const underLayerRoot = ["application", "infrastructure"].includes(rootLeaf);
|
|
218006
218110
|
if (hasTechnicalLayerName) {
|
|
@@ -218027,6 +218131,14 @@ function classifyModuleCandidate(input2) {
|
|
|
218027
218131
|
selectedByDefault: false
|
|
218028
218132
|
};
|
|
218029
218133
|
}
|
|
218134
|
+
if (underExplicitArchitectureRoot && segments.length > 1 && hasComponentRoleName) {
|
|
218135
|
+
evidence.push(`Name '${input2.moduleName}' combines a module root with an app/service/component role`);
|
|
218136
|
+
return {
|
|
218137
|
+
classification: "uncertain",
|
|
218138
|
+
evidence,
|
|
218139
|
+
selectedByDefault: false
|
|
218140
|
+
};
|
|
218141
|
+
}
|
|
218030
218142
|
if (underExplicitArchitectureRoot && input2.hasSourceFiles && input2.sourceFileCount >= 1) {
|
|
218031
218143
|
evidence.push(`Located under explicit architecture boundary root ${input2.rootPath}`);
|
|
218032
218144
|
return {
|
|
@@ -218178,15 +218290,24 @@ function makeDetectedModule(workspaceRoot, moduleName, modulePath, rootPath, has
|
|
|
218178
218290
|
sourceFileCount
|
|
218179
218291
|
});
|
|
218180
218292
|
evidence.push(...candidateClassification.evidence);
|
|
218293
|
+
const componentAlignedEvidence = getComponentAlignedEvidence({
|
|
218294
|
+
moduleName,
|
|
218295
|
+
modulePath,
|
|
218296
|
+
context
|
|
218297
|
+
});
|
|
218298
|
+
if (componentAlignedEvidence) {
|
|
218299
|
+
evidence.push(componentAlignedEvidence);
|
|
218300
|
+
}
|
|
218181
218301
|
const scope = resolveModuleScope(workspaceRoot, modulePath, context);
|
|
218302
|
+
const classification = componentAlignedEvidence && candidateClassification.classification === "architecture-module" ? "uncertain" : candidateClassification.classification;
|
|
218182
218303
|
return {
|
|
218183
218304
|
name: moduleName,
|
|
218184
218305
|
path: modulePath,
|
|
218185
218306
|
confidence,
|
|
218186
218307
|
evidence,
|
|
218187
218308
|
...scope ? { scope } : {},
|
|
218188
|
-
classification
|
|
218189
|
-
selectedByDefault:
|
|
218309
|
+
classification,
|
|
218310
|
+
selectedByDefault: classification === "architecture-module" && candidateClassification.selectedByDefault && confidence !== "low"
|
|
218190
218311
|
};
|
|
218191
218312
|
}
|
|
218192
218313
|
function collectModuleCandidatesFromRoot(workspaceRoot, modulesRootRelative, defaultConfidence, context) {
|
|
@@ -218448,7 +218569,11 @@ function detectModules(workspaceRoot, options) {
|
|
|
218448
218569
|
projectKinds: options?.projectKinds,
|
|
218449
218570
|
stacks: options?.stacks,
|
|
218450
218571
|
ignoreMatcher: options?.ignoreMatcher,
|
|
218451
|
-
projectRoots: options?.projectRoots?.map(normalizePath5)
|
|
218572
|
+
projectRoots: options?.projectRoots?.map(normalizePath5),
|
|
218573
|
+
componentPaths: options?.componentPaths?.map(normalizePath5),
|
|
218574
|
+
componentNames: options?.componentNames,
|
|
218575
|
+
resourcePaths: options?.resourcePaths?.map(normalizePath5),
|
|
218576
|
+
resourceNames: options?.resourceNames
|
|
218452
218577
|
};
|
|
218453
218578
|
const explicitRoots = collectExplicitRoots(workspaceRoot, context);
|
|
218454
218579
|
const usesFrontendAppRouter = options?.stacks?.some((stack) => stack === "nextjs" || stack === "react" || stack === "vue" || stack === "angular");
|
|
@@ -218537,7 +218662,11 @@ function detectModuleCandidatesForRoot(workspaceRoot, modulesRootRelative, optio
|
|
|
218537
218662
|
projectKinds: options?.projectKinds,
|
|
218538
218663
|
stacks: options?.stacks,
|
|
218539
218664
|
ignoreMatcher: options?.ignoreMatcher,
|
|
218540
|
-
projectRoots: options?.projectRoots?.map(normalizePath5)
|
|
218665
|
+
projectRoots: options?.projectRoots?.map(normalizePath5),
|
|
218666
|
+
componentPaths: options?.componentPaths?.map(normalizePath5),
|
|
218667
|
+
componentNames: options?.componentNames,
|
|
218668
|
+
resourcePaths: options?.resourcePaths?.map(normalizePath5),
|
|
218669
|
+
resourceNames: options?.resourceNames
|
|
218541
218670
|
}
|
|
218542
218671
|
);
|
|
218543
218672
|
}
|
|
@@ -237005,16 +237134,66 @@ function sortModuleCandidates(candidates) {
|
|
|
237005
237134
|
return left.name.localeCompare(right.name);
|
|
237006
237135
|
});
|
|
237007
237136
|
}
|
|
237008
|
-
function
|
|
237137
|
+
function normalizeIdentity2(value) {
|
|
237138
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/gu, "");
|
|
237139
|
+
}
|
|
237140
|
+
function normalizeComponentPath(value) {
|
|
237141
|
+
return value.replaceAll("\\", "/").replace(/\/+$/gu, "");
|
|
237142
|
+
}
|
|
237143
|
+
function isComponentAlignedModuleCandidate(candidate, components, resources = []) {
|
|
237144
|
+
const candidatePath = normalizeComponentPath(candidate.path);
|
|
237145
|
+
const candidateNameIdentity = normalizeIdentity2(candidate.name);
|
|
237146
|
+
const candidatePathLeafIdentity = normalizeIdentity2(candidatePath.split("/").filter((segment) => segment.length > 0).at(-1) ?? candidate.path);
|
|
237147
|
+
const matchesComponent = components.some((component) => {
|
|
237148
|
+
const componentPath = normalizeComponentPath(component.path);
|
|
237149
|
+
if (componentPath.length > 0 && componentPath !== "." && (componentPath === candidatePath || componentPath.startsWith(`${candidatePath}/`) || candidatePath.startsWith(`${componentPath}/`))) {
|
|
237150
|
+
return true;
|
|
237151
|
+
}
|
|
237152
|
+
const componentIdentities = [
|
|
237153
|
+
component.id,
|
|
237154
|
+
component.name,
|
|
237155
|
+
componentPath.split("/").filter((segment) => segment.length > 0).at(-1) ?? ""
|
|
237156
|
+
].map(normalizeIdentity2);
|
|
237157
|
+
return candidateNameIdentity.length > 0 && componentIdentities.some(
|
|
237158
|
+
(identity) => identity.length > 0 && (identity === candidateNameIdentity || identity === candidatePathLeafIdentity)
|
|
237159
|
+
);
|
|
237160
|
+
});
|
|
237161
|
+
if (matchesComponent) {
|
|
237162
|
+
return true;
|
|
237163
|
+
}
|
|
237164
|
+
return resources.some((resource) => {
|
|
237165
|
+
const resourcePath = typeof resource.path === "string" ? normalizeComponentPath(resource.path) : "";
|
|
237166
|
+
if (resourcePath.length > 0 && resourcePath !== "." && (resourcePath === candidatePath || resourcePath.startsWith(`${candidatePath}/`) || candidatePath.startsWith(`${resourcePath}/`))) {
|
|
237167
|
+
return true;
|
|
237168
|
+
}
|
|
237169
|
+
const resourceIdentities = [
|
|
237170
|
+
resource.id ?? "",
|
|
237171
|
+
resource.name ?? "",
|
|
237172
|
+
resource.provider ?? "",
|
|
237173
|
+
resourcePath.split("/").filter((segment) => segment.length > 0).at(-1) ?? ""
|
|
237174
|
+
].map(normalizeIdentity2);
|
|
237175
|
+
return candidateNameIdentity.length > 0 && resourceIdentities.some(
|
|
237176
|
+
(identity) => identity.length > 0 && (identity === candidateNameIdentity || identity === candidatePathLeafIdentity)
|
|
237177
|
+
);
|
|
237178
|
+
});
|
|
237179
|
+
}
|
|
237180
|
+
function resolveModuleCandidates(detection, resources = []) {
|
|
237009
237181
|
return sortModuleCandidates(
|
|
237010
|
-
(detection.modules?.modules ?? []).map((module2) =>
|
|
237011
|
-
|
|
237012
|
-
|
|
237013
|
-
|
|
237014
|
-
|
|
237015
|
-
|
|
237016
|
-
|
|
237017
|
-
|
|
237182
|
+
(detection.modules?.modules ?? []).map((module2) => {
|
|
237183
|
+
const isComponentOrResourceAligned = isComponentAlignedModuleCandidate(
|
|
237184
|
+
module2,
|
|
237185
|
+
detection.detectedComponents ?? [],
|
|
237186
|
+
resources
|
|
237187
|
+
);
|
|
237188
|
+
return {
|
|
237189
|
+
name: module2.name,
|
|
237190
|
+
path: module2.path,
|
|
237191
|
+
classification: isComponentOrResourceAligned && module2.classification === "architecture-module" ? "uncertain" : module2.classification,
|
|
237192
|
+
confidence: module2.confidence,
|
|
237193
|
+
evidence: isComponentOrResourceAligned ? [...module2.evidence, "Matches detected component/service/app or resource identity; review before governing as a module"] : [...module2.evidence],
|
|
237194
|
+
selectedByDefault: isComponentOrResourceAligned && module2.classification === "architecture-module" ? false : module2.selectedByDefault
|
|
237195
|
+
};
|
|
237196
|
+
})
|
|
237018
237197
|
);
|
|
237019
237198
|
}
|
|
237020
237199
|
function groupModuleCandidates(candidates) {
|
|
@@ -237622,15 +237801,6 @@ function buildArchitectureProposal(detection) {
|
|
|
237622
237801
|
} else if ((moduleRoots?.length ?? 0) > 0) {
|
|
237623
237802
|
addEvidence7(evidence, `Detected module roots: ${moduleRoots.join(", ")}`);
|
|
237624
237803
|
}
|
|
237625
|
-
const moduleCandidates = resolveModuleCandidates(detection);
|
|
237626
|
-
const moduleCandidateGroups = groupModuleCandidates(moduleCandidates);
|
|
237627
|
-
const modules = moduleCandidates.filter((module2) => module2.selectedByDefault).map((module2) => module2.name).filter((name) => name.length > 0);
|
|
237628
|
-
if (moduleCandidates.length > 0) {
|
|
237629
|
-
addEvidence7(evidence, `Detected ${moduleCandidates.length} module candidates`);
|
|
237630
|
-
}
|
|
237631
|
-
if (modules.length > 0) {
|
|
237632
|
-
addEvidence7(evidence, `Preselected ${modules.length} architecture module candidates`);
|
|
237633
|
-
}
|
|
237634
237804
|
const apiStyle = resolveProposalApiStyle(detection);
|
|
237635
237805
|
if (apiStyle) {
|
|
237636
237806
|
addEvidence7(evidence, apiStyle === "none" ? "Detected no public API signals" : `Detected ${apiStyle.toUpperCase()} API`);
|
|
@@ -237645,6 +237815,15 @@ function buildArchitectureProposal(detection) {
|
|
|
237645
237815
|
const authStyle = apiStyle && apiStyle !== "none" ? "jwt" : "none";
|
|
237646
237816
|
const components = resolveProposalComponents(detection);
|
|
237647
237817
|
const resources = resolveProposalResources({ detection, database, apiStyle });
|
|
237818
|
+
const moduleCandidates = resolveModuleCandidates(detection, resources ?? []);
|
|
237819
|
+
const moduleCandidateGroups = groupModuleCandidates(moduleCandidates);
|
|
237820
|
+
const modules = moduleCandidates.filter((module2) => module2.selectedByDefault).map((module2) => module2.name).filter((name) => name.length > 0);
|
|
237821
|
+
if (moduleCandidates.length > 0) {
|
|
237822
|
+
addEvidence7(evidence, `Detected ${moduleCandidates.length} module candidates`);
|
|
237823
|
+
}
|
|
237824
|
+
if (modules.length > 0) {
|
|
237825
|
+
addEvidence7(evidence, `Preselected ${modules.length} architecture module candidates`);
|
|
237826
|
+
}
|
|
237648
237827
|
if (database && database !== "none") {
|
|
237649
237828
|
addEvidence7(evidence, `Detected ${database} database`);
|
|
237650
237829
|
} else if (database === "none") {
|