@archpilotlabs/archpilot 0.2.5 → 0.2.7
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/CHANGELOG.md +58 -0
- package/README.md +17 -2
- package/dist/archpilot-cli.js +1120 -133
- package/package.json +1 -1
package/dist/archpilot-cli.js
CHANGED
|
@@ -12907,7 +12907,7 @@ ${lanes.join("\n")}
|
|
|
12907
12907
|
return process.memoryUsage().heapUsed;
|
|
12908
12908
|
},
|
|
12909
12909
|
getFileSize(path74) {
|
|
12910
|
-
const stat =
|
|
12910
|
+
const stat = statSync2(path74);
|
|
12911
12911
|
if (stat == null ? void 0 : stat.isFile()) {
|
|
12912
12912
|
return stat.size;
|
|
12913
12913
|
}
|
|
@@ -12951,7 +12951,7 @@ ${lanes.join("\n")}
|
|
|
12951
12951
|
}
|
|
12952
12952
|
};
|
|
12953
12953
|
return nodeSystem;
|
|
12954
|
-
function
|
|
12954
|
+
function statSync2(path74) {
|
|
12955
12955
|
try {
|
|
12956
12956
|
return _fs.statSync(path74, statSyncOptions);
|
|
12957
12957
|
} catch {
|
|
@@ -13010,7 +13010,7 @@ ${lanes.join("\n")}
|
|
|
13010
13010
|
activeSession.post("Profiler.stop", (err, { profile }) => {
|
|
13011
13011
|
var _a;
|
|
13012
13012
|
if (!err) {
|
|
13013
|
-
if ((_a =
|
|
13013
|
+
if ((_a = statSync2(profilePath)) == null ? void 0 : _a.isDirectory()) {
|
|
13014
13014
|
profilePath = _path.join(profilePath, `${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`);
|
|
13015
13015
|
}
|
|
13016
13016
|
try {
|
|
@@ -13130,7 +13130,7 @@ ${lanes.join("\n")}
|
|
|
13130
13130
|
let stat;
|
|
13131
13131
|
if (typeof dirent === "string" || dirent.isSymbolicLink()) {
|
|
13132
13132
|
const name = combinePaths(path74, entry);
|
|
13133
|
-
stat =
|
|
13133
|
+
stat = statSync2(name);
|
|
13134
13134
|
if (!stat) {
|
|
13135
13135
|
continue;
|
|
13136
13136
|
}
|
|
@@ -13154,7 +13154,7 @@ ${lanes.join("\n")}
|
|
|
13154
13154
|
return matchFiles(path74, extensions, excludes, includes, useCaseSensitiveFileNames2, process.cwd(), depth, getAccessibleFileSystemEntries, realpath);
|
|
13155
13155
|
}
|
|
13156
13156
|
function fileSystemEntryExists(path74, entryKind) {
|
|
13157
|
-
const stat =
|
|
13157
|
+
const stat = statSync2(path74);
|
|
13158
13158
|
if (!stat) {
|
|
13159
13159
|
return false;
|
|
13160
13160
|
}
|
|
@@ -13196,7 +13196,7 @@ ${lanes.join("\n")}
|
|
|
13196
13196
|
}
|
|
13197
13197
|
function getModifiedTime3(path74) {
|
|
13198
13198
|
var _a;
|
|
13199
|
-
return (_a =
|
|
13199
|
+
return (_a = statSync2(path74)) == null ? void 0 : _a.mtime;
|
|
13200
13200
|
}
|
|
13201
13201
|
function setModifiedTime(path74, time) {
|
|
13202
13202
|
try {
|
|
@@ -225435,6 +225435,7 @@ init_sourceScopeClassification();
|
|
|
225435
225435
|
var maxFileSizeBytes = 256 * 1024;
|
|
225436
225436
|
var supplementalRiskScanExtensions = [".json", ".yaml", ".yml", ".sql"];
|
|
225437
225437
|
var backendCodeExtensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".java", ".cs", ".py", ".php", ".go"];
|
|
225438
|
+
var methodBodyScanExtensions = new Set(backendCodeExtensions);
|
|
225438
225439
|
var supplementalIgnoredDirectoryNames = [".vscode-test", ".tmp"];
|
|
225439
225440
|
var batchingEvidencePattern = /\b(?:DataLoader|Promise\.all|findMany\s*\([\s\S]{0,300}\bin\b|where\s*:\s*\{[\s\S]{0,300}\bin\s*:|include\s*:|join\s*\(|leftJoin|innerJoin|JOIN\b)\b/iu;
|
|
225440
225441
|
var queryReadPattern = /\b((?:this\.)?(?:prisma\.(\w+)|([A-Za-z_$][\w$]*Repository|repository))\.(find\w*|count|aggregate|groupBy)\s*\()/giu;
|
|
@@ -225443,6 +225444,7 @@ var boundEvidencePattern = /\b(?:take|limit|page|cursor|skip|offset|PageRequest|
|
|
|
225443
225444
|
var repeatedQueryPattern = /\b((?:this\.)?(?:prisma\.(\w+)|(\w*Repository|repository))\.(find\w*|count|aggregate|groupBy)\s*\(\s*(?:\{[\s\S]{0,300}?\}|\w+)\s*\))/giu;
|
|
225444
225445
|
var tenantPredicatePattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|accountId|account_id|workspaceId|workspace_id|companyId|company_id|customerId|customer_id)\b/u;
|
|
225445
225446
|
var codePaginationEvidencePattern = /\b(?:take|skip|limit|offset|page|perPage|pageSize|cursor|Pageable|PageRequest|paginate|simplePaginate|Limit|Offset|Take|Skip|TOP\s+\d+)\b/iu;
|
|
225447
|
+
var sqlQueryInvocationHintPattern = /\b(?:query|execute|executeQuery|createNativeQuery|createQuery|FromSqlRaw|FromSqlInterpolated|Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext|Raw|text|DB::select|DB::statement|DB::raw|DB::table)\s*\(|\$queryRaw\s*\(|\$executeRaw\s*\(|@Query\s*\(/u;
|
|
225446
225448
|
function getLineStarts(file) {
|
|
225447
225449
|
if (file.lineStarts) {
|
|
225448
225450
|
return file.lineStarts;
|
|
@@ -225666,10 +225668,15 @@ function hasPaginationEvidence(statement) {
|
|
|
225666
225668
|
);
|
|
225667
225669
|
}
|
|
225668
225670
|
function hasEqualityPredicate(statement, columnPattern) {
|
|
225671
|
+
const whereMatch = /\bwhere\b/iu.exec(statement);
|
|
225672
|
+
if (!whereMatch) {
|
|
225673
|
+
return false;
|
|
225674
|
+
}
|
|
225675
|
+
const predicateWindow = statement.slice(whereMatch.index, whereMatch.index + 1200);
|
|
225669
225676
|
return new RegExp(
|
|
225670
|
-
`\\
|
|
225677
|
+
`\\b(?:${columnPattern})\\b\\s*=\\s*(?:[\\w$:@?]+|'[^']+'|"[^"]+"|\\d+)`,
|
|
225671
225678
|
"iu"
|
|
225672
|
-
).test(
|
|
225679
|
+
).test(predicateWindow);
|
|
225673
225680
|
}
|
|
225674
225681
|
function isCatalogIdentifierPointLookup(statement) {
|
|
225675
225682
|
const metadataSourcePattern = /\bfrom\s+(?:information_schema\.(?:schemata|tables|columns|key_column_usage|table_constraints)|pg_catalog\.(?:pg_class|pg_namespace|pg_attribute|pg_constraint|pg_type|pg_enum|pg_tables|pg_indexes)|pg_(?:class|namespace|attribute|constraint|type|enum|tables|indexes))\b/iu;
|
|
@@ -226270,6 +226277,9 @@ function detectRepeatedQueryPattern(method) {
|
|
|
226270
226277
|
}
|
|
226271
226278
|
function extractSqlQueryLiterals(content) {
|
|
226272
226279
|
const queries = [];
|
|
226280
|
+
if (!sqlQueryInvocationHintPattern.test(content)) {
|
|
226281
|
+
return queries;
|
|
226282
|
+
}
|
|
226273
226283
|
const searchableContent = maskSourceComments(content);
|
|
226274
226284
|
const patterns = [
|
|
226275
226285
|
/(?:\b(?:[\w$]+\.)?(?:query|execute|executeQuery|createNativeQuery|createQuery|FromSqlRaw|FromSqlInterpolated|Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext|Raw|text)|\$queryRaw|\$executeRaw)\s*\([^'"`)]{0,180}?(['"`])([\s\S]{0,900}?)\1/giu,
|
|
@@ -226291,7 +226301,7 @@ function extractSqlQueryLiterals(content) {
|
|
|
226291
226301
|
return queries;
|
|
226292
226302
|
}
|
|
226293
226303
|
function maskSourceComments(content) {
|
|
226294
|
-
|
|
226304
|
+
const masked = [];
|
|
226295
226305
|
let index = 0;
|
|
226296
226306
|
let state = "code";
|
|
226297
226307
|
let escaped = false;
|
|
@@ -226300,27 +226310,27 @@ function maskSourceComments(content) {
|
|
|
226300
226310
|
const next = content[index + 1] ?? "";
|
|
226301
226311
|
if (state === "line-comment") {
|
|
226302
226312
|
if (current === "\r" || current === "\n") {
|
|
226303
|
-
masked
|
|
226313
|
+
masked.push(current);
|
|
226304
226314
|
state = "code";
|
|
226305
226315
|
} else {
|
|
226306
|
-
masked
|
|
226316
|
+
masked.push(" ");
|
|
226307
226317
|
}
|
|
226308
226318
|
index += 1;
|
|
226309
226319
|
continue;
|
|
226310
226320
|
}
|
|
226311
226321
|
if (state === "block-comment") {
|
|
226312
226322
|
if (current === "*" && next === "/") {
|
|
226313
|
-
masked
|
|
226323
|
+
masked.push(" ");
|
|
226314
226324
|
index += 2;
|
|
226315
226325
|
state = "code";
|
|
226316
226326
|
continue;
|
|
226317
226327
|
}
|
|
226318
|
-
masked
|
|
226328
|
+
masked.push(current === "\r" || current === "\n" ? current : " ");
|
|
226319
226329
|
index += 1;
|
|
226320
226330
|
continue;
|
|
226321
226331
|
}
|
|
226322
226332
|
if (state === "single" || state === "double" || state === "template") {
|
|
226323
|
-
masked
|
|
226333
|
+
masked.push(current);
|
|
226324
226334
|
if (escaped) {
|
|
226325
226335
|
escaped = false;
|
|
226326
226336
|
} else if (current === "\\") {
|
|
@@ -226332,13 +226342,13 @@ function maskSourceComments(content) {
|
|
|
226332
226342
|
continue;
|
|
226333
226343
|
}
|
|
226334
226344
|
if (current === "/" && next === "/") {
|
|
226335
|
-
masked
|
|
226345
|
+
masked.push(" ");
|
|
226336
226346
|
index += 2;
|
|
226337
226347
|
state = "line-comment";
|
|
226338
226348
|
continue;
|
|
226339
226349
|
}
|
|
226340
226350
|
if (current === "/" && next === "*") {
|
|
226341
|
-
masked
|
|
226351
|
+
masked.push(" ");
|
|
226342
226352
|
index += 2;
|
|
226343
226353
|
state = "block-comment";
|
|
226344
226354
|
continue;
|
|
@@ -226350,10 +226360,10 @@ function maskSourceComments(content) {
|
|
|
226350
226360
|
} else if (current === "`") {
|
|
226351
226361
|
state = "template";
|
|
226352
226362
|
}
|
|
226353
|
-
masked
|
|
226363
|
+
masked.push(current);
|
|
226354
226364
|
index += 1;
|
|
226355
226365
|
}
|
|
226356
|
-
return masked;
|
|
226366
|
+
return masked.join("");
|
|
226357
226367
|
}
|
|
226358
226368
|
function detectCodeSqlQueryShapeFindings(file, config) {
|
|
226359
226369
|
const findings = [];
|
|
@@ -226383,7 +226393,7 @@ function detectCodeSqlQueryShapeFindings(file, config) {
|
|
|
226383
226393
|
target: firstTable ?? "sql-query"
|
|
226384
226394
|
}));
|
|
226385
226395
|
}
|
|
226386
|
-
if (statement.queryType === "select" && !isOperationalOrBatchQueryContext(file) && !hasPaginationEvidence(statement.statement) && !isObviousPointLookup(statement.statement) && !/\bcount\s*\(/i.test(statement.statement)) {
|
|
226396
|
+
if (statement.queryType === "select" && !isOperationalOrBatchQueryContext(file) && !hasPaginationEvidence(statement.statement) && !hasSpringDataRepositoryMethodBoundEvidence(file.content, query.offset) && !isObviousPointLookup(statement.statement) && !/\bcount\s*\(/i.test(statement.statement)) {
|
|
226387
226397
|
findings.push(createCodeFinding({
|
|
226388
226398
|
id: "AP-DQR-003",
|
|
226389
226399
|
message: `Potential unbounded query risk: SELECT query${firstTable ? ` on table '${firstTable}'` : ""} has no LIMIT/OFFSET/FETCH pagination evidence.`,
|
|
@@ -226397,6 +226407,18 @@ function detectCodeSqlQueryShapeFindings(file, config) {
|
|
|
226397
226407
|
}
|
|
226398
226408
|
return findings;
|
|
226399
226409
|
}
|
|
226410
|
+
function hasSpringDataRepositoryMethodBoundEvidence(content, queryOffset) {
|
|
226411
|
+
const annotationOffset = content.lastIndexOf("@Query", queryOffset);
|
|
226412
|
+
if (annotationOffset < 0 || queryOffset - annotationOffset > 2400) {
|
|
226413
|
+
return false;
|
|
226414
|
+
}
|
|
226415
|
+
const semicolonOffset = content.indexOf(";", queryOffset);
|
|
226416
|
+
if (semicolonOffset < queryOffset || semicolonOffset - annotationOffset > 3200) {
|
|
226417
|
+
return false;
|
|
226418
|
+
}
|
|
226419
|
+
const declarationWindow = content.slice(queryOffset, semicolonOffset + 1);
|
|
226420
|
+
return /\b(?:Page|Slice|Window)\s*</u.test(declarationWindow) && /\b(?:Pageable|Limit)\s+\w+\b/u.test(declarationWindow);
|
|
226421
|
+
}
|
|
226400
226422
|
function collectOrmReadEvidence(method) {
|
|
226401
226423
|
const patterns = [
|
|
226402
226424
|
[/\b(?:this\.)?prisma\.\w+\.findMany\s*\(/giu, "prisma.findMany"],
|
|
@@ -226514,7 +226536,11 @@ function detectCodeQueryRiskFindings(files, config, astCache) {
|
|
|
226514
226536
|
if (isProductionBackend) {
|
|
226515
226537
|
findings.push(...detectCodeSqlQueryShapeFindings(file, config));
|
|
226516
226538
|
}
|
|
226517
|
-
|
|
226539
|
+
if (!methodBodyScanExtensions.has(file.extension)) {
|
|
226540
|
+
continue;
|
|
226541
|
+
}
|
|
226542
|
+
const methods = extractMethodBodies(file, astCache);
|
|
226543
|
+
for (const method of methods) {
|
|
226518
226544
|
if (!isProductionBackend) {
|
|
226519
226545
|
continue;
|
|
226520
226546
|
}
|
|
@@ -228136,6 +228162,8 @@ var transactionBoundaryDecoratorPattern = /@(?:Transactional|Transaction)\b|\[(?
|
|
|
228136
228162
|
var explicitTransactionBoundaryPattern = /\b(?:\$transaction|DB::transaction)\s*\(|\b(?:knex|sequelize|typeorm|dataSource|connection|manager|transactionManager)\.transaction\s*\(|\b(?:this\.)?connection\.withTransaction\s*\(|\b(?:startTransaction|beginTransaction|BeginTransaction|BeginTransactionAsync|BeginTx)\s*\(|\bnew\s+TransactionScope\b|\bsession\.begin\s*\(|\bdb\.Transaction\s*\(/iu;
|
|
228137
228163
|
var separateTransactionPropagationPattern = /\b(?:requiresNew|REQUIRES_NEW|Propagation\.REQUIRES_NEW)\b/u;
|
|
228138
228164
|
var businessRulePattern = /\b(?:approve|reject|authorize|eligible|eligibility|policy|discount|limit|quota|balance|risk|compliance|settle|state|status|transition)\b/iu;
|
|
228165
|
+
var repositoryBusinessRulePattern = /\b(?:approve|reject|authorize|eligible|eligibility|policy|discount|quota|balance|risk|compliance|settle|transition)\b/iu;
|
|
228166
|
+
var decisionStructurePattern = /\bif\s*\(|\bswitch\s*\(|\bthrow\s+new\b/u;
|
|
228139
228167
|
var transactionCallbackStartPattern = /\b(?:this\.)?(?:[\w.$:]+\.)?(?:\$transaction|transaction|Transaction)\s*\(\s*(?:async\s*)?(?:function\s*)?\(?\s*\w*\s*\)?\s*(?:=>)?\s*\{/gu;
|
|
228140
228168
|
var explicitDomainModelEvidencePattern = /@(?:Entity|Embeddable|MappedSuperclass|Column|PrimaryGeneratedColumn|ObjectType|Field)\b|\[(?:Table|Key|Required|Column|StringLength|MaxLength)\b[^\]]*\]|\b(?:BaseModel|SQLModel|declarative_base|Mapped\[|Column\s*\(|@dataclass\b|extends\s+Model\b|\$fillable\b|\$casts\b|gorm\.Model|`[^`]*(?:gorm|db):)/u;
|
|
228141
228169
|
var domainFrameworkLeakPattern = /\b(?:ControllerBase|IActionResult|HttpContext|Microsoft\.AspNetCore|APIRouter|FastAPI|Request|Response|Depends|Illuminate\\Http|Illuminate\\Routing|Route::|http\.ResponseWriter|http\.Request|gin\.Context|express|Router|org\.springframework\.web|jakarta\.servlet|HttpServletRequest|@Controller|@RestController|@Get|@Post|DbContext|EntityManager|Session|Repository)\b/u;
|
|
@@ -229281,6 +229309,16 @@ function hasEntitySpecificServiceBusinessRules(entityNames, methods) {
|
|
|
229281
229309
|
return [...entityAliases].some((entityName) => new RegExp(`\\b${entityName}\\b`, "u").test(method.file.content));
|
|
229282
229310
|
});
|
|
229283
229311
|
}
|
|
229312
|
+
function hasScatteredDomainLogicEvidence(method) {
|
|
229313
|
+
const code = maskNonCodeEvidence2(method.body);
|
|
229314
|
+
if (!decisionStructurePattern.test(code)) {
|
|
229315
|
+
return false;
|
|
229316
|
+
}
|
|
229317
|
+
if (hasRole(method.classification, "repository")) {
|
|
229318
|
+
return repositoryBusinessRulePattern.test(code);
|
|
229319
|
+
}
|
|
229320
|
+
return businessRulePattern.test(code);
|
|
229321
|
+
}
|
|
229284
229322
|
function detectDomainFindings(files, classifications, methods, contract, astCache) {
|
|
229285
229323
|
const findings = [];
|
|
229286
229324
|
for (const file of files) {
|
|
@@ -229350,7 +229388,7 @@ function detectDomainFindings(files, classifications, methods, contract, astCach
|
|
|
229350
229388
|
}));
|
|
229351
229389
|
}
|
|
229352
229390
|
}
|
|
229353
|
-
if (isProductionBackendGovernanceScope(method.classification.scope) && (hasRole(method.classification, "controller") || hasRole(method.classification, "repository")) &&
|
|
229391
|
+
if (isProductionBackendGovernanceScope(method.classification.scope) && (hasRole(method.classification, "controller") || hasRole(method.classification, "repository")) && hasScatteredDomainLogicEvidence(method)) {
|
|
229354
229392
|
findings.push(createFinding3({
|
|
229355
229393
|
id: RuleIds2.DOM_LOGIC_SCATTERED,
|
|
229356
229394
|
message: `Business rule evidence appears in a ${hasRole(method.classification, "controller") ? "controller" : "repository"} method '${method.name}'.`,
|
|
@@ -229666,6 +229704,11 @@ function httpMethodFromDecorator(decorators, extension) {
|
|
|
229666
229704
|
}
|
|
229667
229705
|
return value;
|
|
229668
229706
|
}
|
|
229707
|
+
function routeDecoratorOffsetInGroup(decorators, extension) {
|
|
229708
|
+
const pattern = extension === ".java" ? /@(?:GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping|RequestMapping)\b/u : /@(?:Get|Post|Put|Patch|Delete)\b/u;
|
|
229709
|
+
const match = pattern.exec(decorators);
|
|
229710
|
+
return match?.index ?? 0;
|
|
229711
|
+
}
|
|
229669
229712
|
function methodPathFromDecorators(decorators, extension) {
|
|
229670
229713
|
const pattern = extension === ".java" ? /@(?:GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping|RequestMapping)\s*(?:\(([^)]*)\))?/u : /@(?:Get|Post|Put|Patch|Delete)\s*(?:\(([^)]*)\))?/u;
|
|
229671
229714
|
const match = pattern.exec(decorators);
|
|
@@ -229685,11 +229728,12 @@ function extractDecoratorEndpoints(file, contract) {
|
|
|
229685
229728
|
const returnType = file.extension === ".java" ? match[3] ?? "" : match[3] ?? "";
|
|
229686
229729
|
const openBrace = (match.index ?? 0) + match[0].lastIndexOf("{");
|
|
229687
229730
|
const end = findMatchingBrace4(file.content, openBrace);
|
|
229731
|
+
const routeDecoratorOffset = routeDecoratorOffsetInGroup(decorators, file.extension);
|
|
229688
229732
|
endpoints.push({
|
|
229689
229733
|
httpMethod,
|
|
229690
229734
|
path: joinEndpointPath(basePath, methodPathFromDecorators(decorators, file.extension)),
|
|
229691
229735
|
name,
|
|
229692
|
-
line: lineNumberForOffset4(file.content, match.index ?? 0),
|
|
229736
|
+
line: lineNumberForOffset4(file.content, (match.index ?? 0) + routeDecoratorOffset),
|
|
229693
229737
|
decorators,
|
|
229694
229738
|
signature: `${returnType} ${match[0]}`,
|
|
229695
229739
|
body: file.content.slice(openBrace, end + 1),
|
|
@@ -229970,8 +230014,15 @@ function isStaticCollectionBackedEndpoint(endpoint) {
|
|
|
229970
230014
|
}
|
|
229971
230015
|
return isStaticCollectionExpression(stripStaticLiteralNoise(expression));
|
|
229972
230016
|
}
|
|
230017
|
+
function isUnconditionallyTerminalThrowEndpoint(endpoint) {
|
|
230018
|
+
const body = endpoint.body.trim().replace(/^\{\s*/u, "").replace(/\s*\}$/u, "").trim();
|
|
230019
|
+
if (!/^throw\s+new\s+[A-Z]\w*(?:Exception|Error)\s*\([^;{}]*\)\s*;?$/u.test(body)) {
|
|
230020
|
+
return false;
|
|
230021
|
+
}
|
|
230022
|
+
return !/\b(?:if|for|while|switch|try|catch|return|await|yield)\b/u.test(body);
|
|
230023
|
+
}
|
|
229973
230024
|
function detectPaginationFindings(endpoints, contractEndpoints) {
|
|
229974
|
-
return endpoints.filter((endpoint) => isCollectionGet(endpoint) && !hasPaginationEvidence2(endpoint, contractEndpoints) && !isStaticCollectionBackedEndpoint(endpoint)).map((endpoint) => createFinding4({
|
|
230025
|
+
return endpoints.filter((endpoint) => isCollectionGet(endpoint) && !hasPaginationEvidence2(endpoint, contractEndpoints) && !isStaticCollectionBackedEndpoint(endpoint) && !isUnconditionallyTerminalThrowEndpoint(endpoint)).map((endpoint) => createFinding4({
|
|
229975
230026
|
id: RuleIds3.MISSING_PAGINATION,
|
|
229976
230027
|
message: `Collection endpoint ${endpoint.httpMethod.toUpperCase()} ${endpoint.path} lacks visible pagination evidence.`,
|
|
229977
230028
|
endpoint
|
|
@@ -230731,12 +230782,14 @@ function extractTypeScriptSignals(file, astCache) {
|
|
|
230731
230782
|
ts6.forEachChild(node, visit);
|
|
230732
230783
|
};
|
|
230733
230784
|
visit(sourceFile);
|
|
230734
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230785
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230735
230786
|
}
|
|
230736
230787
|
function extractJavaSignals(file) {
|
|
230737
230788
|
const publishes = [];
|
|
230738
230789
|
const handlers2 = [];
|
|
230739
|
-
for (const match of file.content.matchAll(
|
|
230790
|
+
for (const match of file.content.matchAll(
|
|
230791
|
+
/@EventListener\s*(?:\(\s*(?:(?:classes|value)\s*=\s*)?(?:\{\s*)?([A-Za-z_]\w*)\.class\s*(?:\})?\s*\))?/gu
|
|
230792
|
+
)) {
|
|
230740
230793
|
const eventName = match[1] ?? "ApplicationEvent";
|
|
230741
230794
|
handlers2.push({
|
|
230742
230795
|
eventName,
|
|
@@ -230748,6 +230801,21 @@ function extractJavaSignals(file) {
|
|
|
230748
230801
|
publishes: []
|
|
230749
230802
|
});
|
|
230750
230803
|
}
|
|
230804
|
+
for (const match of file.content.matchAll(/\b(?:class|interface)\s+\w+[^{;]*\bApplicationListener\s*<\s*([A-Za-z_]\w*)\s*>/gu)) {
|
|
230805
|
+
const eventName = match[1];
|
|
230806
|
+
if (!eventName) {
|
|
230807
|
+
continue;
|
|
230808
|
+
}
|
|
230809
|
+
handlers2.push({
|
|
230810
|
+
eventName,
|
|
230811
|
+
normalizedName: normalizeEventName(eventName),
|
|
230812
|
+
file,
|
|
230813
|
+
line: lineNumberForOffset5(file, match.index ?? 0),
|
|
230814
|
+
module: file.module,
|
|
230815
|
+
style: classifyEventStyle(eventName),
|
|
230816
|
+
publishes: []
|
|
230817
|
+
});
|
|
230818
|
+
}
|
|
230751
230819
|
for (const match of file.content.matchAll(/(?:await\s+)?(?:\w+\.)?(?:publishEvent|publish|emit)\s*\(\s*(?:(new)\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*\(|(["'])([A-Za-z][\w.]*Event?|[a-z][\w.]+)\3|([A-Z][A-Za-z0-9_]*Event)\b)/gu)) {
|
|
230752
230820
|
const constructedType = match[2]?.split(".").at(-1);
|
|
230753
230821
|
const eventName = constructedType ?? match[4] ?? match[5];
|
|
@@ -230765,7 +230833,23 @@ function extractJavaSignals(file) {
|
|
|
230765
230833
|
assignedOrReturned: false
|
|
230766
230834
|
});
|
|
230767
230835
|
}
|
|
230768
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230836
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: extractJavaEventTypeParents(file) };
|
|
230837
|
+
}
|
|
230838
|
+
function extractJavaEventTypeParents(file) {
|
|
230839
|
+
const parentsByType = /* @__PURE__ */ new Map();
|
|
230840
|
+
for (const match of file.content.matchAll(/\b(?:class|record)\s+([A-Za-z_]\w*)(?:\s*<[^>{}]+>)?\s+extends\s+([A-Za-z_]\w*)/gu)) {
|
|
230841
|
+
const child = match[1];
|
|
230842
|
+
const parent = match[2];
|
|
230843
|
+
if (!child || !parent || !child.endsWith("Event")) {
|
|
230844
|
+
continue;
|
|
230845
|
+
}
|
|
230846
|
+
const normalizedChild = normalizeEventName(child);
|
|
230847
|
+
const normalizedParent = normalizeEventName(parent);
|
|
230848
|
+
const parents = parentsByType.get(normalizedChild) ?? /* @__PURE__ */ new Set();
|
|
230849
|
+
parents.add(normalizedParent);
|
|
230850
|
+
parentsByType.set(normalizedChild, parents);
|
|
230851
|
+
}
|
|
230852
|
+
return parentsByType;
|
|
230769
230853
|
}
|
|
230770
230854
|
function extractPublishSignalsFromText(file, body, baseOffset, pattern) {
|
|
230771
230855
|
const publishes = [];
|
|
@@ -230811,7 +230895,7 @@ function extractCsharpSignals(file) {
|
|
|
230811
230895
|
publishes: extractPublishSignalsFromText(file, classBody, classOpenBrace >= 0 ? classOpenBrace : classStart, csharpPublishPattern)
|
|
230812
230896
|
});
|
|
230813
230897
|
}
|
|
230814
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230898
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230815
230899
|
}
|
|
230816
230900
|
function extractPythonSignals(file) {
|
|
230817
230901
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, pythonPublishPattern);
|
|
@@ -230834,7 +230918,7 @@ function extractPythonSignals(file) {
|
|
|
230834
230918
|
publishes: extractPublishSignalsFromText(file, block, blockStart, pythonPublishPattern)
|
|
230835
230919
|
});
|
|
230836
230920
|
}
|
|
230837
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230921
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230838
230922
|
}
|
|
230839
230923
|
function extractPhpSignals(file) {
|
|
230840
230924
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, phpEventPublishPattern);
|
|
@@ -230859,7 +230943,7 @@ function extractPhpSignals(file) {
|
|
|
230859
230943
|
publishes: extractPublishSignalsFromText(file, classBody, classOpenBrace >= 0 ? classOpenBrace : classStart, phpEventPublishPattern)
|
|
230860
230944
|
});
|
|
230861
230945
|
}
|
|
230862
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230946
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230863
230947
|
}
|
|
230864
230948
|
function extractGoSignals(file) {
|
|
230865
230949
|
const publishes = extractPublishSignalsFromText(file, file.content, 0, goPublishPattern);
|
|
@@ -230879,7 +230963,7 @@ function extractGoSignals(file) {
|
|
|
230879
230963
|
publishes: []
|
|
230880
230964
|
});
|
|
230881
230965
|
}
|
|
230882
|
-
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set() };
|
|
230966
|
+
return { publishes, handlers: handlers2, publicEventNames: /* @__PURE__ */ new Set(), eventTypeParents: /* @__PURE__ */ new Map() };
|
|
230883
230967
|
}
|
|
230884
230968
|
function isTypeScriptLikeExtension(extension) {
|
|
230885
230969
|
return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(extension);
|
|
@@ -230979,6 +231063,7 @@ function collectPublicTypeScriptEventNames(files, contract, astCache) {
|
|
|
230979
231063
|
function collectSignals(files, contract, astCache) {
|
|
230980
231064
|
const publishes = [];
|
|
230981
231065
|
const handlers2 = [];
|
|
231066
|
+
const eventTypeParents = /* @__PURE__ */ new Map();
|
|
230982
231067
|
const publicEventNames = collectPublicTypeScriptEventNames(files, contract, astCache);
|
|
230983
231068
|
for (const file of files) {
|
|
230984
231069
|
let signals;
|
|
@@ -231004,14 +231089,41 @@ function collectSignals(files, contract, astCache) {
|
|
|
231004
231089
|
}
|
|
231005
231090
|
publishes.push(...signals.publishes);
|
|
231006
231091
|
handlers2.push(...signals.handlers);
|
|
231092
|
+
for (const [eventName, parents] of signals.eventTypeParents) {
|
|
231093
|
+
const existing = eventTypeParents.get(eventName) ?? /* @__PURE__ */ new Set();
|
|
231094
|
+
for (const parent of parents) {
|
|
231095
|
+
existing.add(parent);
|
|
231096
|
+
}
|
|
231097
|
+
eventTypeParents.set(eventName, existing);
|
|
231098
|
+
}
|
|
231007
231099
|
}
|
|
231008
|
-
return { publishes, handlers: handlers2, publicEventNames };
|
|
231100
|
+
return { publishes, handlers: handlers2, publicEventNames, eventTypeParents };
|
|
231101
|
+
}
|
|
231102
|
+
function isHandledEventName(normalizedName, handledNames, eventTypeParents) {
|
|
231103
|
+
const queue = [normalizedName];
|
|
231104
|
+
const visited = /* @__PURE__ */ new Set();
|
|
231105
|
+
while (queue.length > 0) {
|
|
231106
|
+
const current = queue.shift();
|
|
231107
|
+
if (!current || visited.has(current)) {
|
|
231108
|
+
continue;
|
|
231109
|
+
}
|
|
231110
|
+
if (handledNames.has(current)) {
|
|
231111
|
+
return true;
|
|
231112
|
+
}
|
|
231113
|
+
visited.add(current);
|
|
231114
|
+
for (const parent of eventTypeParents.get(current) ?? []) {
|
|
231115
|
+
if (!visited.has(parent)) {
|
|
231116
|
+
queue.push(parent);
|
|
231117
|
+
}
|
|
231118
|
+
}
|
|
231119
|
+
}
|
|
231120
|
+
return false;
|
|
231009
231121
|
}
|
|
231010
231122
|
function buildEventFindings(signals) {
|
|
231011
231123
|
const findings = [];
|
|
231012
231124
|
const handledNames = new Set(signals.handlers.map((handler) => handler.normalizedName));
|
|
231013
231125
|
for (const publish of signals.publishes) {
|
|
231014
|
-
if (!
|
|
231126
|
+
if (!isHandledEventName(publish.normalizedName, handledNames, signals.eventTypeParents)) {
|
|
231015
231127
|
if (signals.publicEventNames.has(publish.normalizedName)) {
|
|
231016
231128
|
continue;
|
|
231017
231129
|
}
|
|
@@ -236969,6 +237081,41 @@ function formatRuleLine(ruleId) {
|
|
|
236969
237081
|
function formatFindingLine(finding) {
|
|
236970
237082
|
return `${formatRuleLine(finding.id)} | ${finding.message}`;
|
|
236971
237083
|
}
|
|
237084
|
+
function formatRegressionFindingLine(finding) {
|
|
237085
|
+
const parts = [`${finding.id} ${finding.severity}`];
|
|
237086
|
+
const scope = finding.module && finding.target ? `${finding.module} -> ${finding.target}` : finding.sourceComponentName && finding.targetComponentName ? `${finding.sourceComponentName} -> ${finding.targetComponentName}` : finding.module ?? finding.target ?? finding.table ?? finding.api ?? finding.filePath;
|
|
237087
|
+
if (scope) {
|
|
237088
|
+
parts.push(scope);
|
|
237089
|
+
}
|
|
237090
|
+
if (finding.sourceFile) {
|
|
237091
|
+
parts.push(
|
|
237092
|
+
finding.sourceLine !== void 0 ? `${finding.sourceFile}:${finding.sourceLine}` : finding.sourceFile
|
|
237093
|
+
);
|
|
237094
|
+
}
|
|
237095
|
+
parts.push(finding.message);
|
|
237096
|
+
return parts.join(" | ");
|
|
237097
|
+
}
|
|
237098
|
+
function renderRegressionFindingLines(findings, limit) {
|
|
237099
|
+
if (findings.length === 0) {
|
|
237100
|
+
return "- (none)";
|
|
237101
|
+
}
|
|
237102
|
+
const sorted = [...findings].sort((left, right) => {
|
|
237103
|
+
const idCompare = left.id.localeCompare(right.id);
|
|
237104
|
+
if (idCompare !== 0) {
|
|
237105
|
+
return idCompare;
|
|
237106
|
+
}
|
|
237107
|
+
const sourceCompare = (left.sourceFile ?? "").localeCompare(right.sourceFile ?? "");
|
|
237108
|
+
if (sourceCompare !== 0) {
|
|
237109
|
+
return sourceCompare;
|
|
237110
|
+
}
|
|
237111
|
+
return left.message.localeCompare(right.message);
|
|
237112
|
+
});
|
|
237113
|
+
const rendered = sorted.slice(0, limit).map((finding) => `- ${formatRegressionFindingLine(finding)}`);
|
|
237114
|
+
if (sorted.length > limit) {
|
|
237115
|
+
rendered.push(`- ... ${sorted.length - limit} more`);
|
|
237116
|
+
}
|
|
237117
|
+
return rendered.join("\n");
|
|
237118
|
+
}
|
|
236972
237119
|
function parseFindingKind2(value) {
|
|
236973
237120
|
return value === "violation" || value === "setup-gap" || value === "guidance" ? value : void 0;
|
|
236974
237121
|
}
|
|
@@ -236993,7 +237140,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
|
|
|
236993
237140
|
findingKindByRule.set(finding.id, byRule);
|
|
236994
237141
|
findingKindByRuleAndMessage.set(`${finding.id}::${finding.message}`, kind);
|
|
236995
237142
|
}
|
|
236996
|
-
const
|
|
237143
|
+
const resolveKind3 = (entry) => {
|
|
236997
237144
|
const explicit = readFindingKind(entry);
|
|
236998
237145
|
if (explicit) {
|
|
236999
237146
|
return explicit;
|
|
@@ -237011,28 +237158,28 @@ function renderArchitecturePrCommentMarkdown(input2) {
|
|
|
237011
237158
|
return "violation";
|
|
237012
237159
|
};
|
|
237013
237160
|
const newQualityViolationLines = sortUniqueLines(
|
|
237014
|
-
(input2.driftComparison?.newViolations ?? []).filter((entry) =>
|
|
237161
|
+
(input2.driftComparison?.newViolations ?? []).filter((entry) => resolveKind3(entry) === "violation").map((entry) => formatRuleLine(entry.ruleId))
|
|
237015
237162
|
);
|
|
237016
237163
|
const newSetupGapLines = sortUniqueLines(
|
|
237017
|
-
(input2.driftComparison?.newViolations ?? []).filter((entry) =>
|
|
237164
|
+
(input2.driftComparison?.newViolations ?? []).filter((entry) => resolveKind3(entry) === "setup-gap").map((entry) => formatRuleLine(entry.ruleId))
|
|
237018
237165
|
);
|
|
237019
237166
|
const newGuidanceLines = sortUniqueLines(
|
|
237020
|
-
(input2.driftComparison?.newViolations ?? []).filter((entry) =>
|
|
237167
|
+
(input2.driftComparison?.newViolations ?? []).filter((entry) => resolveKind3(entry) === "guidance").map((entry) => formatRuleLine(entry.ruleId))
|
|
237021
237168
|
);
|
|
237022
237169
|
const resolvedViolationLines = sortUniqueLines(
|
|
237023
|
-
(input2.driftComparison?.resolvedViolations ?? []).filter((entry) =>
|
|
237170
|
+
(input2.driftComparison?.resolvedViolations ?? []).filter((entry) => resolveKind3(entry) === "violation").map((entry) => formatRuleLine(entry.ruleId))
|
|
237024
237171
|
);
|
|
237025
237172
|
const resolvedSetupGapLines = sortUniqueLines(
|
|
237026
|
-
(input2.driftComparison?.resolvedViolations ?? []).filter((entry) =>
|
|
237173
|
+
(input2.driftComparison?.resolvedViolations ?? []).filter((entry) => resolveKind3(entry) === "setup-gap").map((entry) => formatRuleLine(entry.ruleId))
|
|
237027
237174
|
);
|
|
237028
237175
|
const activeQualityViolationLines = sortUniqueLines(
|
|
237029
|
-
input2.summary.findings.filter((entry) =>
|
|
237176
|
+
input2.summary.findings.filter((entry) => resolveKind3({ ruleId: entry.id, message: entry.message }) === "violation").map((entry) => formatFindingLine(entry))
|
|
237030
237177
|
);
|
|
237031
237178
|
const activeSetupGapLines = sortUniqueLines(
|
|
237032
|
-
input2.summary.findings.filter((entry) =>
|
|
237179
|
+
input2.summary.findings.filter((entry) => resolveKind3({ ruleId: entry.id, message: entry.message }) === "setup-gap").map((entry) => formatFindingLine(entry))
|
|
237033
237180
|
);
|
|
237034
237181
|
const activeGuidanceLines = sortUniqueLines(
|
|
237035
|
-
input2.summary.findings.filter((entry) =>
|
|
237182
|
+
input2.summary.findings.filter((entry) => resolveKind3({ ruleId: entry.id, message: entry.message }) === "guidance").map((entry) => formatFindingLine(entry))
|
|
237036
237183
|
);
|
|
237037
237184
|
const activeQualityViolationCount = activeQualityViolationLines.length;
|
|
237038
237185
|
const activeSetupGapCount = activeSetupGapLines.length;
|
|
@@ -237168,6 +237315,37 @@ function renderArchitecturePrCommentMarkdown(input2) {
|
|
|
237168
237315
|
lines.push(`Setup gaps: ${activeSetupGapCount}`);
|
|
237169
237316
|
}
|
|
237170
237317
|
lines.push(trendLine);
|
|
237318
|
+
const baselineComparison = input2.summary.baselineComparison;
|
|
237319
|
+
if (baselineComparison) {
|
|
237320
|
+
lines.push("");
|
|
237321
|
+
lines.push("Architecture Regression Summary");
|
|
237322
|
+
const comparisonAvailable = baselineComparison.baselineAvailable !== false && baselineComparison.status !== "NO_BASELINE";
|
|
237323
|
+
if (!comparisonAvailable) {
|
|
237324
|
+
lines.push("Architecture regression comparison is unavailable.");
|
|
237325
|
+
if (baselineComparison.summary.toLowerCase().includes("no baseline")) {
|
|
237326
|
+
lines.push("No governance baseline exists.");
|
|
237327
|
+
lines.push("Create or refresh the governance baseline with `archpilot baseline refresh`.");
|
|
237328
|
+
}
|
|
237329
|
+
lines.push(`Summary: ${baselineComparison.summary}`);
|
|
237330
|
+
} else {
|
|
237331
|
+
lines.push(`Introduced: ${baselineComparison.newlyIntroducedFindings.length}`);
|
|
237332
|
+
lines.push(`Resolved: ${baselineComparison.resolvedFindings.length}`);
|
|
237333
|
+
lines.push(`Existing: ${baselineComparison.unchangedFindings.length}`);
|
|
237334
|
+
if (baselineComparison.newlyIntroducedFindings.length === 0) {
|
|
237335
|
+
lines.push("");
|
|
237336
|
+
lines.push("No new architecture regressions detected.");
|
|
237337
|
+
} else {
|
|
237338
|
+
lines.push("");
|
|
237339
|
+
lines.push("New architecture regressions");
|
|
237340
|
+
lines.push(renderRegressionFindingLines(baselineComparison.newlyIntroducedFindings, 10));
|
|
237341
|
+
}
|
|
237342
|
+
if (baselineComparison.resolvedFindings.length > 0) {
|
|
237343
|
+
lines.push("");
|
|
237344
|
+
lines.push("Resolved architecture findings");
|
|
237345
|
+
lines.push(renderRegressionFindingLines(baselineComparison.resolvedFindings, 8));
|
|
237346
|
+
}
|
|
237347
|
+
}
|
|
237348
|
+
}
|
|
237171
237349
|
if (input2.driftComparison?.hasPreviousSnapshot) {
|
|
237172
237350
|
lines.push(
|
|
237173
237351
|
`Previous score: ${input2.driftComparison.previousScore ?? "n/a"}${input2.driftComparison.scoreDelta !== void 0 ? ` (${input2.driftComparison.scoreDelta >= 0 ? "+" : ""}${input2.driftComparison.scoreDelta})` : ""}`
|
|
@@ -238332,6 +238510,190 @@ async function checkArchitectureBaseline(workspaceRoot) {
|
|
|
238332
238510
|
// ../core/src/architectureGovernanceBaseline.ts
|
|
238333
238511
|
var path42 = __toESM(require("node:path"));
|
|
238334
238512
|
var import_node_fs36 = require("node:fs");
|
|
238513
|
+
|
|
238514
|
+
// ../core/src/findingRegressionComparison.ts
|
|
238515
|
+
function normalizeToken2(value) {
|
|
238516
|
+
return value.replace(/\\/g, "/").trim().toLowerCase();
|
|
238517
|
+
}
|
|
238518
|
+
function normalizeOptionalToken(value) {
|
|
238519
|
+
if (typeof value !== "string") {
|
|
238520
|
+
return void 0;
|
|
238521
|
+
}
|
|
238522
|
+
const normalized = normalizeToken2(value);
|
|
238523
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
238524
|
+
}
|
|
238525
|
+
function resolveKind(input2) {
|
|
238526
|
+
if (input2.kind === "violation" || input2.kind === "setup-gap" || input2.kind === "guidance") {
|
|
238527
|
+
return input2.kind;
|
|
238528
|
+
}
|
|
238529
|
+
if (input2.classification === "violation" || input2.classification === "setup-gap" || input2.classification === "guidance") {
|
|
238530
|
+
return input2.classification;
|
|
238531
|
+
}
|
|
238532
|
+
if (input2.type === "violation" || input2.type === "setup-gap" || input2.type === "guidance") {
|
|
238533
|
+
return input2.type;
|
|
238534
|
+
}
|
|
238535
|
+
return "violation";
|
|
238536
|
+
}
|
|
238537
|
+
function appendPart(parts, label, value) {
|
|
238538
|
+
const normalized = normalizeOptionalToken(value);
|
|
238539
|
+
if (normalized) {
|
|
238540
|
+
parts.push(`${label}=${normalized}`);
|
|
238541
|
+
}
|
|
238542
|
+
}
|
|
238543
|
+
function normalizeDeductionIdentity(deductionKey) {
|
|
238544
|
+
const normalized = normalizeOptionalToken(deductionKey);
|
|
238545
|
+
if (!normalized) {
|
|
238546
|
+
return void 0;
|
|
238547
|
+
}
|
|
238548
|
+
if (normalized.includes("|")) {
|
|
238549
|
+
const parts2 = normalized.split("|");
|
|
238550
|
+
if (parts2[0] === "quality" || parts2[0] === "setup" || parts2[0] === "guidance") {
|
|
238551
|
+
parts2.shift();
|
|
238552
|
+
}
|
|
238553
|
+
if (parts2[0]?.startsWith("ap-")) {
|
|
238554
|
+
parts2.shift();
|
|
238555
|
+
}
|
|
238556
|
+
if (parts2.length >= 4 && /^\d+$/u.test(parts2[3] ?? "")) {
|
|
238557
|
+
return parts2.filter((_, index) => index !== 3).join("|");
|
|
238558
|
+
}
|
|
238559
|
+
return parts2.join("|");
|
|
238560
|
+
}
|
|
238561
|
+
const parts = normalized.split(":");
|
|
238562
|
+
if (parts[0] === "quality" || parts[0] === "setup" || parts[0] === "guidance") {
|
|
238563
|
+
parts.shift();
|
|
238564
|
+
}
|
|
238565
|
+
if (parts[0]?.startsWith("ap-")) {
|
|
238566
|
+
parts.shift();
|
|
238567
|
+
}
|
|
238568
|
+
return parts.join(":");
|
|
238569
|
+
}
|
|
238570
|
+
function buildSemanticRegressionIdentity(input2) {
|
|
238571
|
+
const parts = [`rule=${normalizeToken2(input2.id)}`, `kind=${resolveKind(input2)}`];
|
|
238572
|
+
appendPart(parts, "findingtype", input2.findingType);
|
|
238573
|
+
appendPart(parts, "module", input2.module);
|
|
238574
|
+
appendPart(parts, "target", input2.target);
|
|
238575
|
+
appendPart(parts, "table", input2.table);
|
|
238576
|
+
appendPart(parts, "api", input2.api);
|
|
238577
|
+
appendPart(parts, "filepath", input2.filePath);
|
|
238578
|
+
appendPart(parts, "sourcefile", input2.sourceFile);
|
|
238579
|
+
appendPart(parts, "dependencytype", input2.dependencyType);
|
|
238580
|
+
appendPart(parts, "sourcecomponentid", input2.sourceComponentId);
|
|
238581
|
+
appendPart(parts, "targetcomponentid", input2.targetComponentId);
|
|
238582
|
+
appendPart(parts, "importspecifier", input2.importSpecifier);
|
|
238583
|
+
appendPart(parts, "resolvedtargetpath", input2.resolvedTargetPath);
|
|
238584
|
+
if (input2.isExternal !== void 0) {
|
|
238585
|
+
parts.push(`external=${input2.isExternal ? "true" : "false"}`);
|
|
238586
|
+
}
|
|
238587
|
+
const deductionIdentity = normalizeDeductionIdentity(input2.deductionKey);
|
|
238588
|
+
if (deductionIdentity) {
|
|
238589
|
+
parts.push(`deduction=${deductionIdentity}`);
|
|
238590
|
+
}
|
|
238591
|
+
if (parts.length <= 2) {
|
|
238592
|
+
return void 0;
|
|
238593
|
+
}
|
|
238594
|
+
return parts.join("|");
|
|
238595
|
+
}
|
|
238596
|
+
function normalizeLegacyKey(key) {
|
|
238597
|
+
const normalized = normalizeOptionalToken(key);
|
|
238598
|
+
if (!normalized) {
|
|
238599
|
+
return void 0;
|
|
238600
|
+
}
|
|
238601
|
+
return `legacy=${normalized}`;
|
|
238602
|
+
}
|
|
238603
|
+
function buildFindingRegressionIdentity(input2) {
|
|
238604
|
+
const persisted = normalizeOptionalToken(input2.regressionIdentity);
|
|
238605
|
+
if (persisted) {
|
|
238606
|
+
return { identity: persisted, source: "persisted" };
|
|
238607
|
+
}
|
|
238608
|
+
const semantic = buildSemanticRegressionIdentity(input2);
|
|
238609
|
+
if (semantic) {
|
|
238610
|
+
return { identity: semantic, source: "semantic" };
|
|
238611
|
+
}
|
|
238612
|
+
const legacy = normalizeLegacyKey(input2.key);
|
|
238613
|
+
if (legacy) {
|
|
238614
|
+
return { identity: legacy, source: "legacy-key" };
|
|
238615
|
+
}
|
|
238616
|
+
return {
|
|
238617
|
+
identity: [
|
|
238618
|
+
`rule=${normalizeToken2(input2.id)}`,
|
|
238619
|
+
`kind=${resolveKind(input2)}`,
|
|
238620
|
+
`message=${normalizeToken2(input2.message ?? "")}`
|
|
238621
|
+
].join("|"),
|
|
238622
|
+
source: "legacy-key"
|
|
238623
|
+
};
|
|
238624
|
+
}
|
|
238625
|
+
function toComparableFindingRegression(input2) {
|
|
238626
|
+
const identity = buildFindingRegressionIdentity(input2);
|
|
238627
|
+
return {
|
|
238628
|
+
identity: identity.identity,
|
|
238629
|
+
id: input2.id,
|
|
238630
|
+
kind: resolveKind(input2),
|
|
238631
|
+
...input2.severity ? { severity: input2.severity } : {},
|
|
238632
|
+
...input2.message ? { message: input2.message } : {},
|
|
238633
|
+
...input2.sourceFile ? { sourceFile: input2.sourceFile.replace(/\\/g, "/") } : {},
|
|
238634
|
+
...input2.sourceLine !== void 0 ? { sourceLine: input2.sourceLine } : {},
|
|
238635
|
+
...input2.sourceColumn !== void 0 ? { sourceColumn: input2.sourceColumn } : {},
|
|
238636
|
+
...input2.module ? { module: input2.module } : {},
|
|
238637
|
+
...input2.target ? { target: input2.target } : {},
|
|
238638
|
+
...input2.findingType ? { findingType: input2.findingType } : {},
|
|
238639
|
+
regressionIdentitySource: identity.source
|
|
238640
|
+
};
|
|
238641
|
+
}
|
|
238642
|
+
function compareComparableFindings(left, right) {
|
|
238643
|
+
const identityCompare = left.identity.localeCompare(right.identity);
|
|
238644
|
+
if (identityCompare !== 0) {
|
|
238645
|
+
return identityCompare;
|
|
238646
|
+
}
|
|
238647
|
+
const idCompare = left.id.localeCompare(right.id);
|
|
238648
|
+
if (idCompare !== 0) {
|
|
238649
|
+
return idCompare;
|
|
238650
|
+
}
|
|
238651
|
+
const sourceCompare = (left.sourceFile ?? "").localeCompare(right.sourceFile ?? "");
|
|
238652
|
+
if (sourceCompare !== 0) {
|
|
238653
|
+
return sourceCompare;
|
|
238654
|
+
}
|
|
238655
|
+
const leftLine = left.sourceLine ?? Number.MAX_SAFE_INTEGER;
|
|
238656
|
+
const rightLine = right.sourceLine ?? Number.MAX_SAFE_INTEGER;
|
|
238657
|
+
if (leftLine !== rightLine) {
|
|
238658
|
+
return leftLine - rightLine;
|
|
238659
|
+
}
|
|
238660
|
+
const leftColumn = left.sourceColumn ?? Number.MAX_SAFE_INTEGER;
|
|
238661
|
+
const rightColumn = right.sourceColumn ?? Number.MAX_SAFE_INTEGER;
|
|
238662
|
+
if (leftColumn !== rightColumn) {
|
|
238663
|
+
return leftColumn - rightColumn;
|
|
238664
|
+
}
|
|
238665
|
+
const severityCompare = (left.severity ?? "").localeCompare(right.severity ?? "");
|
|
238666
|
+
if (severityCompare !== 0) {
|
|
238667
|
+
return severityCompare;
|
|
238668
|
+
}
|
|
238669
|
+
return (left.message ?? "").localeCompare(right.message ?? "");
|
|
238670
|
+
}
|
|
238671
|
+
function dedupeByIdentity(findings, toComparable) {
|
|
238672
|
+
const map = /* @__PURE__ */ new Map();
|
|
238673
|
+
for (const finding of findings) {
|
|
238674
|
+
const comparable = toComparable(finding);
|
|
238675
|
+
const existing = map.get(comparable.identity);
|
|
238676
|
+
if (!existing || compareComparableFindings(comparable, existing.comparable) < 0) {
|
|
238677
|
+
map.set(comparable.identity, { finding, comparable });
|
|
238678
|
+
}
|
|
238679
|
+
}
|
|
238680
|
+
return [...map.values()].sort(
|
|
238681
|
+
(left, right) => compareComparableFindings(left.comparable, right.comparable)
|
|
238682
|
+
);
|
|
238683
|
+
}
|
|
238684
|
+
function compareFindingRegressions(reference, current, options) {
|
|
238685
|
+
const referenceEntries = dedupeByIdentity(reference, options.toReferenceComparable);
|
|
238686
|
+
const currentEntries = dedupeByIdentity(current, options.toCurrentComparable);
|
|
238687
|
+
const referenceIdentities = new Set(referenceEntries.map((entry) => entry.comparable.identity));
|
|
238688
|
+
const currentIdentities = new Set(currentEntries.map((entry) => entry.comparable.identity));
|
|
238689
|
+
return {
|
|
238690
|
+
introduced: currentEntries.filter((entry) => !referenceIdentities.has(entry.comparable.identity)).map((entry) => entry.finding),
|
|
238691
|
+
existing: currentEntries.filter((entry) => referenceIdentities.has(entry.comparable.identity)).map((entry) => entry.finding),
|
|
238692
|
+
resolved: referenceEntries.filter((entry) => !currentIdentities.has(entry.comparable.identity)).map((entry) => entry.finding)
|
|
238693
|
+
};
|
|
238694
|
+
}
|
|
238695
|
+
|
|
238696
|
+
// ../core/src/architectureGovernanceBaseline.ts
|
|
238335
238697
|
function sortUnique9(values) {
|
|
238336
238698
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
238337
238699
|
}
|
|
@@ -238348,13 +238710,51 @@ function baselineFindingKey(entry) {
|
|
|
238348
238710
|
].join("|");
|
|
238349
238711
|
}
|
|
238350
238712
|
function toBaselineFinding(entry) {
|
|
238713
|
+
const regressionIdentity = entry.regressionIdentity ?? buildFindingRegressionIdentity({
|
|
238714
|
+
id: entry.id,
|
|
238715
|
+
kind: entry.kind,
|
|
238716
|
+
severity: entry.severity,
|
|
238717
|
+
message: entry.message,
|
|
238718
|
+
sourceFile: entry.sourceFile,
|
|
238719
|
+
findingType: entry.findingType,
|
|
238720
|
+
module: entry.module,
|
|
238721
|
+
target: entry.target,
|
|
238722
|
+
filePath: entry.filePath,
|
|
238723
|
+
table: entry.table,
|
|
238724
|
+
api: entry.api,
|
|
238725
|
+
dependencyType: entry.dependencyType,
|
|
238726
|
+
sourceComponentId: entry.sourceComponentId,
|
|
238727
|
+
sourceComponentName: entry.sourceComponentName,
|
|
238728
|
+
targetComponentId: entry.targetComponentId,
|
|
238729
|
+
targetComponentName: entry.targetComponentName,
|
|
238730
|
+
importSpecifier: entry.importSpecifier,
|
|
238731
|
+
resolvedTargetPath: entry.resolvedTargetPath,
|
|
238732
|
+
isExternal: entry.isExternal
|
|
238733
|
+
}).identity;
|
|
238351
238734
|
return {
|
|
238352
238735
|
key: baselineFindingKey(entry),
|
|
238736
|
+
regressionIdentity,
|
|
238353
238737
|
id: entry.id,
|
|
238354
238738
|
severity: entry.severity,
|
|
238355
238739
|
kind: entry.kind,
|
|
238356
238740
|
message: entry.message,
|
|
238357
|
-
...entry.sourceFile ? { sourceFile: normalizePath18(entry.sourceFile) } : {}
|
|
238741
|
+
...entry.sourceFile ? { sourceFile: normalizePath18(entry.sourceFile) } : {},
|
|
238742
|
+
...typeof entry.sourceLine === "number" && Number.isFinite(entry.sourceLine) ? { sourceLine: Math.max(1, Math.floor(entry.sourceLine)) } : {},
|
|
238743
|
+
...typeof entry.sourceColumn === "number" && Number.isFinite(entry.sourceColumn) ? { sourceColumn: Math.max(1, Math.floor(entry.sourceColumn)) } : {},
|
|
238744
|
+
...entry.findingType ? { findingType: entry.findingType } : {},
|
|
238745
|
+
...entry.module ? { module: entry.module } : {},
|
|
238746
|
+
...entry.target ? { target: entry.target } : {},
|
|
238747
|
+
...entry.filePath ? { filePath: normalizePath18(entry.filePath) } : {},
|
|
238748
|
+
...entry.table ? { table: entry.table } : {},
|
|
238749
|
+
...entry.api ? { api: entry.api } : {},
|
|
238750
|
+
...entry.dependencyType ? { dependencyType: entry.dependencyType } : {},
|
|
238751
|
+
...entry.sourceComponentId ? { sourceComponentId: entry.sourceComponentId } : {},
|
|
238752
|
+
...entry.sourceComponentName ? { sourceComponentName: entry.sourceComponentName } : {},
|
|
238753
|
+
...entry.targetComponentId !== void 0 ? { targetComponentId: entry.targetComponentId } : {},
|
|
238754
|
+
...entry.targetComponentName !== void 0 ? { targetComponentName: entry.targetComponentName } : {},
|
|
238755
|
+
...entry.importSpecifier ? { importSpecifier: entry.importSpecifier } : {},
|
|
238756
|
+
...entry.resolvedTargetPath !== void 0 ? { resolvedTargetPath: entry.resolvedTargetPath } : {},
|
|
238757
|
+
...entry.isExternal !== void 0 ? { isExternal: entry.isExternal } : {}
|
|
238358
238758
|
};
|
|
238359
238759
|
}
|
|
238360
238760
|
function compareFindings(left, right) {
|
|
@@ -238390,7 +238790,28 @@ function parseSummaryArtifact(value) {
|
|
|
238390
238790
|
severity: entry.severity,
|
|
238391
238791
|
kind: entry.kind,
|
|
238392
238792
|
message: entry.message,
|
|
238393
|
-
...typeof entry.
|
|
238793
|
+
...typeof entry.regressionIdentity === "string" ? { regressionIdentity: entry.regressionIdentity } : {},
|
|
238794
|
+
...typeof entry.sourceFile === "string" ? { sourceFile: entry.sourceFile } : {},
|
|
238795
|
+
...typeof entry.sourceLine === "number" && Number.isFinite(entry.sourceLine) ? { sourceLine: entry.sourceLine } : {},
|
|
238796
|
+
...typeof entry.sourceColumn === "number" && Number.isFinite(entry.sourceColumn) ? { sourceColumn: entry.sourceColumn } : {},
|
|
238797
|
+
...typeof entry.findingType === "string" ? {
|
|
238798
|
+
findingType: entry.findingType
|
|
238799
|
+
} : {},
|
|
238800
|
+
...typeof entry.module === "string" ? { module: entry.module } : {},
|
|
238801
|
+
...typeof entry.target === "string" ? { target: entry.target } : {},
|
|
238802
|
+
...typeof entry.filePath === "string" ? { filePath: entry.filePath } : {},
|
|
238803
|
+
...typeof entry.table === "string" ? { table: entry.table } : {},
|
|
238804
|
+
...typeof entry.api === "string" ? { api: entry.api } : {},
|
|
238805
|
+
...typeof entry.dependencyType === "string" ? {
|
|
238806
|
+
dependencyType: entry.dependencyType
|
|
238807
|
+
} : {},
|
|
238808
|
+
...typeof entry.sourceComponentId === "string" ? { sourceComponentId: entry.sourceComponentId } : {},
|
|
238809
|
+
...typeof entry.sourceComponentName === "string" ? { sourceComponentName: entry.sourceComponentName } : {},
|
|
238810
|
+
...typeof entry.targetComponentId === "string" || entry.targetComponentId === null ? { targetComponentId: entry.targetComponentId } : {},
|
|
238811
|
+
...typeof entry.targetComponentName === "string" || entry.targetComponentName === null ? { targetComponentName: entry.targetComponentName } : {},
|
|
238812
|
+
...typeof entry.importSpecifier === "string" ? { importSpecifier: entry.importSpecifier } : {},
|
|
238813
|
+
...typeof entry.resolvedTargetPath === "string" || entry.resolvedTargetPath === null ? { resolvedTargetPath: entry.resolvedTargetPath } : {},
|
|
238814
|
+
...typeof entry.isExternal === "boolean" ? { isExternal: entry.isExternal } : {}
|
|
238394
238815
|
}));
|
|
238395
238816
|
const suppressionRaw = typed.suppressionSummary && typeof typed.suppressionSummary === "object" ? typed.suppressionSummary : void 0;
|
|
238396
238817
|
const suppressionSummary = suppressionRaw && typeof suppressionRaw.configuredSuppressions === "number" && typeof suppressionRaw.activeSuppressions === "number" && typeof suppressionRaw.expiredSuppressions === "number" && typeof suppressionRaw.unusedSuppressions === "number" && typeof suppressionRaw.findingsSuppressed === "number" ? {
|
|
@@ -238459,6 +238880,57 @@ function buildBaselineFromSummaryArtifact(artifact, nowUtcIso2) {
|
|
|
238459
238880
|
...artifact.impactAnalysis ? { impactAnalysis: artifact.impactAnalysis } : {}
|
|
238460
238881
|
};
|
|
238461
238882
|
}
|
|
238883
|
+
function buildGovernanceBaselineFromReviewSummary(summary, nowUtcIso2) {
|
|
238884
|
+
return {
|
|
238885
|
+
reportVersion: 1,
|
|
238886
|
+
projectName: summary.projectName,
|
|
238887
|
+
capturedAtUtc: nowUtcIso2 ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
238888
|
+
sourceSummaryGeneratedAtUtc: summary.generatedAtUtc,
|
|
238889
|
+
healthScore: summary.healthScore,
|
|
238890
|
+
readinessScore: summary.readinessScore,
|
|
238891
|
+
categoryScores: summary.categoryScores,
|
|
238892
|
+
readinessCategoryScores: summary.readinessCategoryScores,
|
|
238893
|
+
counts: {
|
|
238894
|
+
errors: summary.counts.errors,
|
|
238895
|
+
warnings: summary.counts.warnings,
|
|
238896
|
+
info: summary.counts.info,
|
|
238897
|
+
passed: summary.counts.passed
|
|
238898
|
+
},
|
|
238899
|
+
findingCount: summary.findings.length,
|
|
238900
|
+
remainingViolationsCount: summary.findings.filter((finding) => finding.kind === "violation").length,
|
|
238901
|
+
findings: summary.findings.map(
|
|
238902
|
+
(entry) => toBaselineFinding({
|
|
238903
|
+
id: entry.id,
|
|
238904
|
+
severity: entry.severity,
|
|
238905
|
+
kind: entry.kind,
|
|
238906
|
+
message: entry.message,
|
|
238907
|
+
...entry.sourceFile ? { sourceFile: entry.sourceFile } : {},
|
|
238908
|
+
...entry.sourceLine !== void 0 ? { sourceLine: entry.sourceLine } : {},
|
|
238909
|
+
...entry.sourceColumn !== void 0 ? { sourceColumn: entry.sourceColumn } : {},
|
|
238910
|
+
...entry.findingType ? { findingType: entry.findingType } : {},
|
|
238911
|
+
...entry.module ? { module: entry.module } : {},
|
|
238912
|
+
...entry.target ? { target: entry.target } : {},
|
|
238913
|
+
...entry.filePath ? { filePath: entry.filePath } : {},
|
|
238914
|
+
...entry.table ? { table: entry.table } : {},
|
|
238915
|
+
...entry.api ? { api: entry.api } : {},
|
|
238916
|
+
...entry.dependencyType ? { dependencyType: entry.dependencyType } : {},
|
|
238917
|
+
...entry.sourceComponentId ? { sourceComponentId: entry.sourceComponentId } : {},
|
|
238918
|
+
...entry.sourceComponentName ? { sourceComponentName: entry.sourceComponentName } : {},
|
|
238919
|
+
...entry.targetComponentId !== void 0 ? { targetComponentId: entry.targetComponentId } : {},
|
|
238920
|
+
...entry.targetComponentName !== void 0 ? { targetComponentName: entry.targetComponentName } : {},
|
|
238921
|
+
...entry.importSpecifier ? { importSpecifier: entry.importSpecifier } : {},
|
|
238922
|
+
...entry.resolvedTargetPath !== void 0 ? { resolvedTargetPath: entry.resolvedTargetPath } : {},
|
|
238923
|
+
...entry.isExternal !== void 0 ? { isExternal: entry.isExternal } : {}
|
|
238924
|
+
})
|
|
238925
|
+
).sort(compareFindings),
|
|
238926
|
+
changeRisk: {
|
|
238927
|
+
riskLevel: summary.changeRisk.riskLevel,
|
|
238928
|
+
score: summary.changeRisk.score,
|
|
238929
|
+
summary: summary.changeRisk.summary
|
|
238930
|
+
},
|
|
238931
|
+
...summary.impactAnalysis ? { impactAnalysis: summary.impactAnalysis } : {}
|
|
238932
|
+
};
|
|
238933
|
+
}
|
|
238462
238934
|
function getGovernanceBaselinePath(workspaceRoot) {
|
|
238463
238935
|
return path42.join(workspaceRoot, ".archpilot", "baseline", "baseline.json");
|
|
238464
238936
|
}
|
|
@@ -238542,13 +239014,43 @@ async function readGovernanceBaseline(workspaceRoot) {
|
|
|
238542
239014
|
}
|
|
238543
239015
|
}
|
|
238544
239016
|
function compareFindingsByKey(current, baseline) {
|
|
238545
|
-
const
|
|
238546
|
-
|
|
238547
|
-
|
|
238548
|
-
|
|
238549
|
-
const
|
|
239017
|
+
const comparison = compareFindingRegressions(baseline, current, {
|
|
239018
|
+
toReferenceComparable: toComparableBaselineFinding,
|
|
239019
|
+
toCurrentComparable: toComparableBaselineFinding
|
|
239020
|
+
});
|
|
239021
|
+
const newlyIntroducedFindings = comparison.introduced.sort(compareFindings);
|
|
239022
|
+
const resolvedFindings = comparison.resolved.sort(compareFindings);
|
|
239023
|
+
const unchangedFindings = comparison.existing.sort(compareFindings);
|
|
238550
239024
|
return { newlyIntroducedFindings, resolvedFindings, unchangedFindings };
|
|
238551
239025
|
}
|
|
239026
|
+
function toRegressionInput(entry) {
|
|
239027
|
+
return {
|
|
239028
|
+
id: entry.id,
|
|
239029
|
+
kind: entry.kind,
|
|
239030
|
+
severity: entry.severity,
|
|
239031
|
+
message: entry.message,
|
|
239032
|
+
regressionIdentity: entry.regressionIdentity,
|
|
239033
|
+
key: entry.key,
|
|
239034
|
+
sourceFile: entry.sourceFile,
|
|
239035
|
+
findingType: entry.findingType,
|
|
239036
|
+
module: entry.module,
|
|
239037
|
+
target: entry.target,
|
|
239038
|
+
filePath: entry.filePath,
|
|
239039
|
+
table: entry.table,
|
|
239040
|
+
api: entry.api,
|
|
239041
|
+
dependencyType: entry.dependencyType,
|
|
239042
|
+
sourceComponentId: entry.sourceComponentId,
|
|
239043
|
+
sourceComponentName: entry.sourceComponentName,
|
|
239044
|
+
targetComponentId: entry.targetComponentId,
|
|
239045
|
+
targetComponentName: entry.targetComponentName,
|
|
239046
|
+
importSpecifier: entry.importSpecifier,
|
|
239047
|
+
resolvedTargetPath: entry.resolvedTargetPath,
|
|
239048
|
+
isExternal: entry.isExternal
|
|
239049
|
+
};
|
|
239050
|
+
}
|
|
239051
|
+
function toComparableBaselineFinding(entry) {
|
|
239052
|
+
return toComparableFindingRegression(toRegressionInput(entry));
|
|
239053
|
+
}
|
|
238552
239054
|
function compareWithGovernanceBaseline(currentSummary, baselineLoad) {
|
|
238553
239055
|
const currentFindings = currentSummary.findings.map(
|
|
238554
239056
|
(entry) => toBaselineFinding({
|
|
@@ -238556,7 +239058,23 @@ function compareWithGovernanceBaseline(currentSummary, baselineLoad) {
|
|
|
238556
239058
|
severity: entry.severity,
|
|
238557
239059
|
kind: entry.kind,
|
|
238558
239060
|
message: entry.message,
|
|
238559
|
-
...entry.sourceFile ? { sourceFile: entry.sourceFile } : {}
|
|
239061
|
+
...entry.sourceFile ? { sourceFile: entry.sourceFile } : {},
|
|
239062
|
+
...entry.sourceLine !== void 0 ? { sourceLine: entry.sourceLine } : {},
|
|
239063
|
+
...entry.sourceColumn !== void 0 ? { sourceColumn: entry.sourceColumn } : {},
|
|
239064
|
+
...entry.findingType ? { findingType: entry.findingType } : {},
|
|
239065
|
+
...entry.module ? { module: entry.module } : {},
|
|
239066
|
+
...entry.target ? { target: entry.target } : {},
|
|
239067
|
+
...entry.filePath ? { filePath: entry.filePath } : {},
|
|
239068
|
+
...entry.table ? { table: entry.table } : {},
|
|
239069
|
+
...entry.api ? { api: entry.api } : {},
|
|
239070
|
+
...entry.dependencyType ? { dependencyType: entry.dependencyType } : {},
|
|
239071
|
+
...entry.sourceComponentId ? { sourceComponentId: entry.sourceComponentId } : {},
|
|
239072
|
+
...entry.sourceComponentName ? { sourceComponentName: entry.sourceComponentName } : {},
|
|
239073
|
+
...entry.targetComponentId !== void 0 ? { targetComponentId: entry.targetComponentId } : {},
|
|
239074
|
+
...entry.targetComponentName !== void 0 ? { targetComponentName: entry.targetComponentName } : {},
|
|
239075
|
+
...entry.importSpecifier ? { importSpecifier: entry.importSpecifier } : {},
|
|
239076
|
+
...entry.resolvedTargetPath !== void 0 ? { resolvedTargetPath: entry.resolvedTargetPath } : {},
|
|
239077
|
+
...entry.isExternal !== void 0 ? { isExternal: entry.isExternal } : {}
|
|
238560
239078
|
})
|
|
238561
239079
|
).sort(compareFindings);
|
|
238562
239080
|
const currentRemainingViolations = currentSummary.findings.filter(
|
|
@@ -238717,6 +239235,43 @@ function renderList(values) {
|
|
|
238717
239235
|
}
|
|
238718
239236
|
return values.map((value) => `- ${value}`).join("\n");
|
|
238719
239237
|
}
|
|
239238
|
+
function formatRegressionFinding(finding) {
|
|
239239
|
+
const pieces = [`[${finding.id}]`, `(${finding.severity})`];
|
|
239240
|
+
const scope = finding.module && finding.target ? `${finding.module} -> ${finding.target}` : finding.sourceComponentName && finding.targetComponentName ? `${finding.sourceComponentName} -> ${finding.targetComponentName}` : finding.module ?? finding.target ?? finding.table ?? finding.api ?? finding.filePath;
|
|
239241
|
+
if (scope) {
|
|
239242
|
+
pieces.push(scope);
|
|
239243
|
+
}
|
|
239244
|
+
if (finding.sourceFile) {
|
|
239245
|
+
pieces.push(
|
|
239246
|
+
finding.sourceLine !== void 0 ? `${finding.sourceFile}:${finding.sourceLine}` : finding.sourceFile
|
|
239247
|
+
);
|
|
239248
|
+
}
|
|
239249
|
+
if (finding.message) {
|
|
239250
|
+
pieces.push(finding.message);
|
|
239251
|
+
}
|
|
239252
|
+
return pieces.join(" | ");
|
|
239253
|
+
}
|
|
239254
|
+
function renderRegressionFindingList(findings, limit) {
|
|
239255
|
+
if (findings.length === 0) {
|
|
239256
|
+
return "- (none)";
|
|
239257
|
+
}
|
|
239258
|
+
const sorted = [...findings].sort((left, right) => {
|
|
239259
|
+
const idCompare = left.id.localeCompare(right.id);
|
|
239260
|
+
if (idCompare !== 0) {
|
|
239261
|
+
return idCompare;
|
|
239262
|
+
}
|
|
239263
|
+
const sourceCompare = (left.sourceFile ?? "").localeCompare(right.sourceFile ?? "");
|
|
239264
|
+
if (sourceCompare !== 0) {
|
|
239265
|
+
return sourceCompare;
|
|
239266
|
+
}
|
|
239267
|
+
return (left.message ?? "").localeCompare(right.message ?? "");
|
|
239268
|
+
});
|
|
239269
|
+
const rendered = sorted.slice(0, limit).map((finding) => `- ${formatRegressionFinding(finding)}`);
|
|
239270
|
+
if (sorted.length > limit) {
|
|
239271
|
+
rendered.push(`- ... ${sorted.length - limit} more`);
|
|
239272
|
+
}
|
|
239273
|
+
return rendered.join("\n");
|
|
239274
|
+
}
|
|
238720
239275
|
function renderStatusLine(input2) {
|
|
238721
239276
|
const validationHasIssues = input2.validation.kind === "ok" && (input2.validation.data.counts.errors > 0 || input2.validation.data.counts.warnings > 0 || input2.validation.data.counts.info > 0);
|
|
238722
239277
|
const driftHasChanges = input2.drift.kind === "ok" && (input2.drift.data.summaryCounts.totalChanges ?? input2.drift.data.summaryCounts.modulesAdded + input2.drift.data.summaryCounts.modulesRemoved + input2.drift.data.summaryCounts.dependenciesAdded + input2.drift.data.summaryCounts.dependenciesRemoved + input2.drift.data.summaryCounts.cyclesAdded + input2.drift.data.summaryCounts.cyclesRemoved) > 0;
|
|
@@ -238866,14 +239421,43 @@ function renderArchitecturePrReviewMarkdown(input2) {
|
|
|
238866
239421
|
}
|
|
238867
239422
|
if (input2.validation.kind === "ok" && input2.validation.data.baselineComparison) {
|
|
238868
239423
|
const baseline = input2.validation.data.baselineComparison;
|
|
238869
|
-
|
|
238870
|
-
lines.push(
|
|
238871
|
-
|
|
238872
|
-
|
|
238873
|
-
|
|
238874
|
-
|
|
238875
|
-
|
|
238876
|
-
|
|
239424
|
+
const comparisonAvailable = baseline.baselineAvailable !== false && baseline.status !== "NO_BASELINE";
|
|
239425
|
+
lines.push("## Architecture Regression Summary");
|
|
239426
|
+
if (!comparisonAvailable) {
|
|
239427
|
+
lines.push("- Architecture regression comparison is unavailable.");
|
|
239428
|
+
if (baseline.summary.toLowerCase().includes("no baseline")) {
|
|
239429
|
+
lines.push("- No governance baseline exists.");
|
|
239430
|
+
lines.push("- Create or refresh the governance baseline with `archpilot baseline refresh`.");
|
|
239431
|
+
}
|
|
239432
|
+
lines.push(`- Summary: ${baseline.summary}`);
|
|
239433
|
+
lines.push("");
|
|
239434
|
+
} else {
|
|
239435
|
+
const introducedCount = baseline.newlyIntroducedFindings.length;
|
|
239436
|
+
const resolvedCount = baseline.resolvedFindings.length;
|
|
239437
|
+
const existingCount = baseline.unchangedFindings?.length ?? 0;
|
|
239438
|
+
lines.push("| | Count |");
|
|
239439
|
+
lines.push("| --- | ---: |");
|
|
239440
|
+
lines.push(`| Introduced | ${introducedCount} |`);
|
|
239441
|
+
lines.push(`| Resolved | ${resolvedCount} |`);
|
|
239442
|
+
lines.push(`| Existing | ${existingCount} |`);
|
|
239443
|
+
lines.push("");
|
|
239444
|
+
lines.push(
|
|
239445
|
+
`Existing means current findings already represented by the accepted governance baseline.`
|
|
239446
|
+
);
|
|
239447
|
+
lines.push("");
|
|
239448
|
+
if (introducedCount === 0) {
|
|
239449
|
+
lines.push("No new architecture regressions detected.");
|
|
239450
|
+
} else {
|
|
239451
|
+
lines.push("### New architecture regressions");
|
|
239452
|
+
lines.push(renderRegressionFindingList(baseline.newlyIntroducedFindings, 10));
|
|
239453
|
+
}
|
|
239454
|
+
if (resolvedCount > 0) {
|
|
239455
|
+
lines.push("");
|
|
239456
|
+
lines.push("### Resolved architecture findings");
|
|
239457
|
+
lines.push(renderRegressionFindingList(baseline.resolvedFindings, 8));
|
|
239458
|
+
}
|
|
239459
|
+
lines.push("");
|
|
239460
|
+
}
|
|
238877
239461
|
}
|
|
238878
239462
|
if (input2.validation.kind === "ok" && input2.validation.data.risk) {
|
|
238879
239463
|
const governanceRisk = input2.validation.data.risk;
|
|
@@ -238964,23 +239548,32 @@ function renderArchitecturePrReviewMarkdown(input2) {
|
|
|
238964
239548
|
}
|
|
238965
239549
|
}
|
|
238966
239550
|
if (input2.validation.kind === "ok") {
|
|
238967
|
-
const topFindings = [...input2.validation.data.findings].sort((left, right) => {
|
|
238968
|
-
const severityCompare = severityRank(left.severity) - severityRank(right.severity);
|
|
238969
|
-
if (severityCompare !== 0) {
|
|
238970
|
-
return severityCompare;
|
|
238971
|
-
}
|
|
238972
|
-
const idCompare = left.id.localeCompare(right.id);
|
|
238973
|
-
if (idCompare !== 0) {
|
|
238974
|
-
return idCompare;
|
|
238975
|
-
}
|
|
238976
|
-
return left.message.localeCompare(right.message);
|
|
238977
|
-
}).slice(0, 8);
|
|
238978
239551
|
lines.push("## Validation Findings");
|
|
238979
|
-
|
|
238980
|
-
|
|
238981
|
-
|
|
238982
|
-
|
|
238983
|
-
|
|
239552
|
+
const baseline = input2.validation.data.baselineComparison;
|
|
239553
|
+
const comparisonAvailable = baseline && baseline.baselineAvailable !== false && baseline.status !== "NO_BASELINE";
|
|
239554
|
+
if (comparisonAvailable) {
|
|
239555
|
+
lines.push(`- Current canonical findings: ${input2.validation.data.findings.length}`);
|
|
239556
|
+
lines.push(
|
|
239557
|
+
"- Regression details above prioritize introduced and resolved findings; complete current findings remain in the validation artifacts."
|
|
239558
|
+
);
|
|
239559
|
+
} else {
|
|
239560
|
+
const topFindings = [...input2.validation.data.findings].sort((left, right) => {
|
|
239561
|
+
const severityCompare = severityRank(left.severity) - severityRank(right.severity);
|
|
239562
|
+
if (severityCompare !== 0) {
|
|
239563
|
+
return severityCompare;
|
|
239564
|
+
}
|
|
239565
|
+
const idCompare = left.id.localeCompare(right.id);
|
|
239566
|
+
if (idCompare !== 0) {
|
|
239567
|
+
return idCompare;
|
|
239568
|
+
}
|
|
239569
|
+
return left.message.localeCompare(right.message);
|
|
239570
|
+
}).slice(0, 8);
|
|
239571
|
+
lines.push(
|
|
239572
|
+
topFindings.length === 0 ? "- (none)" : topFindings.map(
|
|
239573
|
+
(finding) => `- [${finding.id}] (${finding.severity}) ${finding.title} | ${finding.message}`
|
|
239574
|
+
).join("\n")
|
|
239575
|
+
);
|
|
239576
|
+
}
|
|
238984
239577
|
lines.push("");
|
|
238985
239578
|
}
|
|
238986
239579
|
if (input2.drift.kind === "ok") {
|
|
@@ -239107,7 +239700,7 @@ function toAnnotatableFinding(workspaceRoot, finding) {
|
|
|
239107
239700
|
if (finding.severity !== "error" && finding.severity !== "warning") {
|
|
239108
239701
|
return void 0;
|
|
239109
239702
|
}
|
|
239110
|
-
if (typeof finding.
|
|
239703
|
+
if (typeof finding.message !== "string") {
|
|
239111
239704
|
return void 0;
|
|
239112
239705
|
}
|
|
239113
239706
|
if (typeof finding.sourceFile !== "string") {
|
|
@@ -239124,7 +239717,7 @@ function toAnnotatableFinding(workspaceRoot, finding) {
|
|
|
239124
239717
|
const column = typeof finding.sourceColumn === "number" && Number.isFinite(finding.sourceColumn) ? Math.max(1, Math.floor(finding.sourceColumn)) : void 0;
|
|
239125
239718
|
return {
|
|
239126
239719
|
id: finding.id,
|
|
239127
|
-
title: finding.title,
|
|
239720
|
+
title: typeof finding.title === "string" ? finding.title : finding.id,
|
|
239128
239721
|
message: finding.message,
|
|
239129
239722
|
severity: finding.severity,
|
|
239130
239723
|
file,
|
|
@@ -239244,9 +239837,47 @@ async function loadFromSummaryReport(workspaceRoot, maxAgeMinutes) {
|
|
|
239244
239837
|
findings: findings.filter((entry) => !!entry && typeof entry === "object")
|
|
239245
239838
|
};
|
|
239246
239839
|
}
|
|
239840
|
+
async function loadFromBaselineComparisonReport(workspaceRoot, maxAgeMinutes) {
|
|
239841
|
+
const comparisonPath = path43.join(
|
|
239842
|
+
workspaceRoot,
|
|
239843
|
+
".archpilot",
|
|
239844
|
+
"reports",
|
|
239845
|
+
"baseline-comparison.json"
|
|
239846
|
+
);
|
|
239847
|
+
let raw;
|
|
239848
|
+
try {
|
|
239849
|
+
raw = await import_node_fs37.promises.readFile(comparisonPath, { encoding: "utf8" });
|
|
239850
|
+
} catch (error) {
|
|
239851
|
+
if (error.code !== "ENOENT") {
|
|
239852
|
+
console.log("ArchPilot inline annotations: unable to read baseline-comparison.json.");
|
|
239853
|
+
}
|
|
239854
|
+
return void 0;
|
|
239855
|
+
}
|
|
239856
|
+
if (!await isFreshArtifact(comparisonPath, maxAgeMinutes)) {
|
|
239857
|
+
console.log(
|
|
239858
|
+
`ArchPilot inline annotations: baseline-comparison.json is stale (older than ${maxAgeMinutes} minutes).`
|
|
239859
|
+
);
|
|
239860
|
+
return void 0;
|
|
239861
|
+
}
|
|
239862
|
+
let parsed;
|
|
239863
|
+
try {
|
|
239864
|
+
parsed = JSON.parse(raw);
|
|
239865
|
+
} catch {
|
|
239866
|
+
console.log("ArchPilot inline annotations: baseline-comparison.json is invalid JSON.");
|
|
239867
|
+
return void 0;
|
|
239868
|
+
}
|
|
239869
|
+
if (parsed.baselineAvailable !== true) {
|
|
239870
|
+
return void 0;
|
|
239871
|
+
}
|
|
239872
|
+
const findings = Array.isArray(parsed.newlyIntroducedFindings) ? parsed.newlyIntroducedFindings : [];
|
|
239873
|
+
return {
|
|
239874
|
+
sourceLabel: ".archpilot/reports/baseline-comparison.json",
|
|
239875
|
+
findings: findings.filter((entry) => !!entry && typeof entry === "object")
|
|
239876
|
+
};
|
|
239877
|
+
}
|
|
239247
239878
|
async function emitGithubInlineArchitectureAnnotations(workspaceRoot) {
|
|
239248
239879
|
const maxAgeMinutes = readMaxArtifactAgeMinutes();
|
|
239249
|
-
const loaded = await loadFromValidationStatus(workspaceRoot, maxAgeMinutes) ?? await loadFromSummaryReport(workspaceRoot, maxAgeMinutes);
|
|
239880
|
+
const loaded = await loadFromBaselineComparisonReport(workspaceRoot, maxAgeMinutes) ?? await loadFromValidationStatus(workspaceRoot, maxAgeMinutes) ?? await loadFromSummaryReport(workspaceRoot, maxAgeMinutes);
|
|
239250
239881
|
if (!loaded) {
|
|
239251
239882
|
const now = formatUtcDate(/* @__PURE__ */ new Date());
|
|
239252
239883
|
console.log(
|
|
@@ -243013,8 +243644,6 @@ var ignoredRootPathPrefixes = [
|
|
|
243013
243644
|
"static",
|
|
243014
243645
|
"assets",
|
|
243015
243646
|
"vendor",
|
|
243016
|
-
"plugins",
|
|
243017
|
-
"plugin",
|
|
243018
243647
|
"themes",
|
|
243019
243648
|
"theme",
|
|
243020
243649
|
"generated",
|
|
@@ -243037,8 +243666,12 @@ function pushEvidence(evidence, message) {
|
|
|
243037
243666
|
function safeReadDirectoryEntries(directoryPath) {
|
|
243038
243667
|
try {
|
|
243039
243668
|
return fs52.readdirSync(directoryPath, { withFileTypes: true });
|
|
243040
|
-
} catch {
|
|
243041
|
-
|
|
243669
|
+
} catch (error) {
|
|
243670
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
243671
|
+
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
243672
|
+
return [];
|
|
243673
|
+
}
|
|
243674
|
+
throw error;
|
|
243042
243675
|
}
|
|
243043
243676
|
}
|
|
243044
243677
|
function safeReadJsonFile(jsonPath) {
|
|
@@ -245612,8 +246245,6 @@ function isIgnoredComponentCandidatePath(componentPath) {
|
|
|
245612
246245
|
"static",
|
|
245613
246246
|
"assets",
|
|
245614
246247
|
"vendor",
|
|
245615
|
-
"plugins",
|
|
245616
|
-
"plugin",
|
|
245617
246248
|
"themes",
|
|
245618
246249
|
"theme",
|
|
245619
246250
|
"generated",
|
|
@@ -245634,6 +246265,36 @@ function pathExists19(pathValue) {
|
|
|
245634
246265
|
return false;
|
|
245635
246266
|
}
|
|
245636
246267
|
}
|
|
246268
|
+
function isSafeMissingPathError(error) {
|
|
246269
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
246270
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
246271
|
+
}
|
|
246272
|
+
function isDirectoryPath(pathValue) {
|
|
246273
|
+
try {
|
|
246274
|
+
return fs58.statSync(pathValue).isDirectory();
|
|
246275
|
+
} catch (error) {
|
|
246276
|
+
if (isSafeMissingPathError(error)) {
|
|
246277
|
+
return false;
|
|
246278
|
+
}
|
|
246279
|
+
throw error;
|
|
246280
|
+
}
|
|
246281
|
+
}
|
|
246282
|
+
function readDirectoryEntriesForTraversal(directoryPath, options) {
|
|
246283
|
+
if (!isDirectoryPath(directoryPath)) {
|
|
246284
|
+
return [];
|
|
246285
|
+
}
|
|
246286
|
+
try {
|
|
246287
|
+
return fs58.readdirSync(directoryPath, {
|
|
246288
|
+
withFileTypes: true,
|
|
246289
|
+
...options?.recursive ? { recursive: true } : {}
|
|
246290
|
+
});
|
|
246291
|
+
} catch (error) {
|
|
246292
|
+
if (isSafeMissingPathError(error)) {
|
|
246293
|
+
return [];
|
|
246294
|
+
}
|
|
246295
|
+
throw error;
|
|
246296
|
+
}
|
|
246297
|
+
}
|
|
245637
246298
|
function hasManifest2(workspaceRoot, componentPath) {
|
|
245638
246299
|
const absoluteRoot = componentPath === "." ? workspaceRoot : path64.join(workspaceRoot, ...componentPath.split("/"));
|
|
245639
246300
|
return [
|
|
@@ -245641,7 +246302,8 @@ function hasManifest2(workspaceRoot, componentPath) {
|
|
|
245641
246302
|
"pom.xml",
|
|
245642
246303
|
"requirements.txt",
|
|
245643
246304
|
"go.mod",
|
|
245644
|
-
"composer.json"
|
|
246305
|
+
"composer.json",
|
|
246306
|
+
"project.json"
|
|
245645
246307
|
].some((fileName) => pathExists19(path64.join(absoluteRoot, fileName)));
|
|
245646
246308
|
}
|
|
245647
246309
|
function safeReadJson(filePath) {
|
|
@@ -245664,6 +246326,10 @@ function recordKeys(value) {
|
|
|
245664
246326
|
function hasObject(value) {
|
|
245665
246327
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
245666
246328
|
}
|
|
246329
|
+
function readStringProperty(value, key) {
|
|
246330
|
+
const field = value?.[key];
|
|
246331
|
+
return typeof field === "string" && field.trim().length > 0 ? field.trim() : void 0;
|
|
246332
|
+
}
|
|
245667
246333
|
function hasPackagePublishSurface(packageJson) {
|
|
245668
246334
|
return hasObject(packageJson?.exports) || typeof packageJson?.main === "string" || typeof packageJson?.module === "string" || typeof packageJson?.types === "string" || hasObject(packageJson?.publishConfig) || Array.isArray(packageJson?.files);
|
|
245669
246335
|
}
|
|
@@ -245686,6 +246352,132 @@ function readProjectJson(workspaceRoot, componentPath) {
|
|
|
245686
246352
|
const absoluteRoot = absoluteComponentRoot(workspaceRoot, componentPath);
|
|
245687
246353
|
return safeReadJson(path64.join(absoluteRoot, "project.json"));
|
|
245688
246354
|
}
|
|
246355
|
+
function readNxWorkspaceLayout(workspaceRoot) {
|
|
246356
|
+
const nxJson = safeReadJson(path64.join(workspaceRoot, "nx.json"));
|
|
246357
|
+
const workspaceLayout = nxJson?.workspaceLayout;
|
|
246358
|
+
if (!hasObject(workspaceLayout)) {
|
|
246359
|
+
return {};
|
|
246360
|
+
}
|
|
246361
|
+
const layout = workspaceLayout;
|
|
246362
|
+
return {
|
|
246363
|
+
...typeof layout.appsDir === "string" && layout.appsDir.trim().length > 0 ? { appsDir: normalizePath25(layout.appsDir.trim()) } : {},
|
|
246364
|
+
...typeof layout.libsDir === "string" && layout.libsDir.trim().length > 0 ? { libsDir: normalizePath25(layout.libsDir.trim()) } : {}
|
|
246365
|
+
};
|
|
246366
|
+
}
|
|
246367
|
+
function readTargetMap(projectJson) {
|
|
246368
|
+
const targets = projectJson?.targets ?? projectJson?.architect;
|
|
246369
|
+
return hasObject(targets) ? targets : {};
|
|
246370
|
+
}
|
|
246371
|
+
function targetExecutorText(target) {
|
|
246372
|
+
if (!hasObject(target)) {
|
|
246373
|
+
return "";
|
|
246374
|
+
}
|
|
246375
|
+
const typed = target;
|
|
246376
|
+
const executor = typeof typed.executor === "string" ? typed.executor : "";
|
|
246377
|
+
const builder = typeof typed.builder === "string" ? typed.builder : "";
|
|
246378
|
+
const options = hasObject(typed.options) ? typed.options : {};
|
|
246379
|
+
const main = typeof options.main === "string" ? options.main : "";
|
|
246380
|
+
const index = typeof options.index === "string" ? options.index : "";
|
|
246381
|
+
const outputPath = typeof options.outputPath === "string" ? options.outputPath : "";
|
|
246382
|
+
return `${executor} ${builder} ${main} ${index} ${outputPath}`.toLowerCase();
|
|
246383
|
+
}
|
|
246384
|
+
function hasNxRuntimeProjectEvidence(projectJson) {
|
|
246385
|
+
const projectType = readStringProperty(projectJson, "projectType");
|
|
246386
|
+
if (projectType === "library") {
|
|
246387
|
+
return false;
|
|
246388
|
+
}
|
|
246389
|
+
const targets = readTargetMap(projectJson);
|
|
246390
|
+
const targetNames = Object.keys(targets);
|
|
246391
|
+
const targetText = targetNames.map((targetName) => `${targetName} ${targetExecutorText(targets[targetName])}`).join(" ");
|
|
246392
|
+
const hasRuntimeTarget = /\b(?:serve|start|preview|worker|package:container|deploy:static)\b/u.test(targetText);
|
|
246393
|
+
const hasBuildEntrypoint = /\bbuild\b/u.test(targetNames.join(" ")) && /(?:\bmain\b|src\/main|src\/index|public\/index|webpack|vite|next|node|container|browser|dev-server)/u.test(targetText);
|
|
246394
|
+
return projectType === "application" || hasRuntimeTarget || hasBuildEntrypoint;
|
|
246395
|
+
}
|
|
246396
|
+
function hasNxSupportOnlyProjectEvidence(projectJson) {
|
|
246397
|
+
const projectType = readStringProperty(projectJson, "projectType");
|
|
246398
|
+
const targets = readTargetMap(projectJson);
|
|
246399
|
+
const targetNames = Object.keys(targets);
|
|
246400
|
+
if (targetNames.length === 0) {
|
|
246401
|
+
return false;
|
|
246402
|
+
}
|
|
246403
|
+
const targetText = targetNames.map((targetName) => `${targetName} ${targetExecutorText(targets[targetName])}`).join(" ");
|
|
246404
|
+
const hasOnlySupportTargets = targetNames.every(
|
|
246405
|
+
(targetName) => /^(?:e2e|test|unit-test|integration-test|lint|typecheck|format|smoke|bench|benchmark)$/u.test(targetName)
|
|
246406
|
+
);
|
|
246407
|
+
const hasTestExecutor = /(?:cypress|playwright|jest|vitest|mocha|karma|protractor)/u.test(targetText);
|
|
246408
|
+
return projectType !== "library" && (hasOnlySupportTargets || hasTestExecutor);
|
|
246409
|
+
}
|
|
246410
|
+
function classifyNxRuntimeKind(projectJson) {
|
|
246411
|
+
if (!hasNxRuntimeProjectEvidence(projectJson)) {
|
|
246412
|
+
return void 0;
|
|
246413
|
+
}
|
|
246414
|
+
const targets = readTargetMap(projectJson);
|
|
246415
|
+
const targetText = Object.entries(targets).map(([targetName, target]) => `${targetName} ${targetExecutorText(target)}`).join(" ");
|
|
246416
|
+
if (/(?:webpack:dev-server|webpack-dev-server|src\/index\.(?:tsx|jsx|ts|js)|public\/index\.html|browser|react|vite|next|angular|deploy:static)/u.test(targetText)) {
|
|
246417
|
+
return "frontend";
|
|
246418
|
+
}
|
|
246419
|
+
if (/(?:@nx\/js:node|@nrwl\/node|src\/main\.(?:ts|js)|target:\s*node|node\b|container|worker|queue)/u.test(targetText)) {
|
|
246420
|
+
return /\bworker\b/u.test(targetText) ? "worker" : "backend";
|
|
246421
|
+
}
|
|
246422
|
+
return void 0;
|
|
246423
|
+
}
|
|
246424
|
+
function collectNxProjectCandidates(workspaceRoot) {
|
|
246425
|
+
if (!pathExists19(path64.join(workspaceRoot, "nx.json"))) {
|
|
246426
|
+
return [];
|
|
246427
|
+
}
|
|
246428
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
246429
|
+
const workspaceLayout = readNxWorkspaceLayout(workspaceRoot);
|
|
246430
|
+
const preferredRoots = new Set(
|
|
246431
|
+
["apps", "packages", "services", "libs", workspaceLayout.appsDir, workspaceLayout.libsDir].filter((entry) => typeof entry === "string" && entry.length > 0).map(normalizePath25)
|
|
246432
|
+
);
|
|
246433
|
+
const maxDepth = 5;
|
|
246434
|
+
const queue = [
|
|
246435
|
+
{ absolutePath: workspaceRoot, relativePath: "", depth: 0 }
|
|
246436
|
+
];
|
|
246437
|
+
const addCandidate = (candidatePath, evidence) => {
|
|
246438
|
+
const normalized = normalizePath25(candidatePath);
|
|
246439
|
+
const existing = candidates.get(normalized) ?? { path: normalized, evidence: [] };
|
|
246440
|
+
addEvidence6(existing.evidence, evidence);
|
|
246441
|
+
candidates.set(normalized, existing);
|
|
246442
|
+
};
|
|
246443
|
+
while (queue.length > 0) {
|
|
246444
|
+
const current = queue.shift();
|
|
246445
|
+
if (!current) {
|
|
246446
|
+
continue;
|
|
246447
|
+
}
|
|
246448
|
+
for (const entry of readDirectoryEntriesForTraversal(current.absolutePath)) {
|
|
246449
|
+
if (!entry.isDirectory()) {
|
|
246450
|
+
continue;
|
|
246451
|
+
}
|
|
246452
|
+
if ([".git", ".archpilot", "node_modules", "dist", "build", "out", "coverage"].includes(entry.name)) {
|
|
246453
|
+
continue;
|
|
246454
|
+
}
|
|
246455
|
+
const relativePath = normalizePath25(current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name);
|
|
246456
|
+
if (current.depth >= maxDepth) {
|
|
246457
|
+
continue;
|
|
246458
|
+
}
|
|
246459
|
+
const projectJsonPath = path64.join(current.absolutePath, entry.name, "project.json");
|
|
246460
|
+
if (pathExists19(projectJsonPath)) {
|
|
246461
|
+
const projectJson = safeReadJson(projectJsonPath);
|
|
246462
|
+
const projectRoot = normalizePath25(readStringProperty(projectJson, "root") ?? relativePath);
|
|
246463
|
+
if (hasNxRuntimeProjectEvidence(projectJson)) {
|
|
246464
|
+
addCandidate(projectRoot, "Detected Nx runtime project metadata");
|
|
246465
|
+
} else if (readStringProperty(projectJson, "sourceRoot")) {
|
|
246466
|
+
addCandidate(projectRoot, "Detected Nx source-bearing project metadata");
|
|
246467
|
+
}
|
|
246468
|
+
}
|
|
246469
|
+
const firstSegment = relativePath.split("/")[0] ?? "";
|
|
246470
|
+
if (current.depth === 0 || preferredRoots.has(firstSegment) || preferredRoots.has(relativePath.split("/").slice(0, 2).join("/"))) {
|
|
246471
|
+
queue.push({
|
|
246472
|
+
absolutePath: path64.join(current.absolutePath, entry.name),
|
|
246473
|
+
relativePath,
|
|
246474
|
+
depth: current.depth + 1
|
|
246475
|
+
});
|
|
246476
|
+
}
|
|
246477
|
+
}
|
|
246478
|
+
}
|
|
246479
|
+
return [...candidates.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
246480
|
+
}
|
|
245689
246481
|
function readTextFileSafe(filePath) {
|
|
245690
246482
|
try {
|
|
245691
246483
|
return fs58.readFileSync(filePath, { encoding: "utf8" });
|
|
@@ -245732,6 +246524,8 @@ function readMavenMetadata(workspaceRoot, componentPath) {
|
|
|
245732
246524
|
testScopedDependencyCount: dependencyBlocks.filter((block) => /<scope>\s*test\s*<\/scope>/iu.test(block)).length,
|
|
245733
246525
|
totalDependencyCount: dependencyBlocks.length,
|
|
245734
246526
|
hasMavenPluginConfiguration: packaging === "maven-plugin" || /maven-plugin-plugin|<goalPrefix>|<mojo/iu.test(normalizedPom),
|
|
246527
|
+
hasAssemblyPackagingConfiguration: /maven-assembly-plugin|<goal>\s*single\s*<\/goal>|<descriptor>[^<]*(?:assembly|dist|distribution)[^<]*<\/descriptor>/iu.test(normalizedPom),
|
|
246528
|
+
hasDeploySkipConfiguration: /<maven\.deploy\.skip>\s*true\s*<\/maven\.deploy\.skip>|<artifactId>\s*maven-deploy-plugin\s*<\/artifactId>[\s\S]*?<skip>\s*true\s*<\/skip>/iu.test(normalizedPom),
|
|
245735
246529
|
hasTestLifecycleConfiguration: /maven-surefire-plugin|maven-failsafe-plugin|integration-test|failsafe|surefire/iu.test(normalizedPom),
|
|
245736
246530
|
hasArquillianEvidence: /arquillian/iu.test(normalizedPom),
|
|
245737
246531
|
hasMainJava: pathExists19(path64.join(absoluteRoot, "src", "main", "java")),
|
|
@@ -245864,6 +246658,12 @@ function buildRootCandidates(input2) {
|
|
|
245864
246658
|
addCandidate(root, `Detected project root ${root}`);
|
|
245865
246659
|
}
|
|
245866
246660
|
if (input2.workspaceRoot) {
|
|
246661
|
+
for (const candidate of collectNxProjectCandidates(input2.workspaceRoot)) {
|
|
246662
|
+
addCandidate(candidate.path, "Detected Nx project metadata");
|
|
246663
|
+
for (const evidence of candidate.evidence) {
|
|
246664
|
+
addCandidate(candidate.path, evidence);
|
|
246665
|
+
}
|
|
246666
|
+
}
|
|
245867
246667
|
const mavenRoots = [".", ...input2.topology.detectedRoots ?? []];
|
|
245868
246668
|
for (const candidate of collectMavenReactorCandidates(input2.workspaceRoot, mavenRoots)) {
|
|
245869
246669
|
addCandidate(
|
|
@@ -245947,10 +246747,7 @@ function isUnderJvmResourceRoot4(componentPath) {
|
|
|
245947
246747
|
return /(^|\/)src\/main\/resources(?:\/|$)/u.test(normalizePath25(componentPath).toLowerCase());
|
|
245948
246748
|
}
|
|
245949
246749
|
function hasFileUnderRoot(root, pattern) {
|
|
245950
|
-
|
|
245951
|
-
return false;
|
|
245952
|
-
}
|
|
245953
|
-
const entries = fs58.readdirSync(root, { recursive: true, withFileTypes: true });
|
|
246750
|
+
const entries = readDirectoryEntriesForTraversal(root, { recursive: true });
|
|
245954
246751
|
return entries.some((entry) => entry.isFile() && pattern.test(entry.name));
|
|
245955
246752
|
}
|
|
245956
246753
|
var javaMainMethodPattern = /\bpublic\s+static\s+void\s+main\s*\(\s*String\s*(?:(?:\[\s*\]\s*)|\.\.\.\s*)[A-Za-z_$][\w$]*\s*(?:\[\s*\])?\s*\)/u;
|
|
@@ -246068,10 +246865,7 @@ function readMavenProductionSourceFiles(workspaceRoot, componentPath) {
|
|
|
246068
246865
|
];
|
|
246069
246866
|
const files = [];
|
|
246070
246867
|
for (const sourceRoot of mainRoots) {
|
|
246071
|
-
|
|
246072
|
-
continue;
|
|
246073
|
-
}
|
|
246074
|
-
const entries = fs58.readdirSync(sourceRoot, { recursive: true, withFileTypes: true });
|
|
246868
|
+
const entries = readDirectoryEntriesForTraversal(sourceRoot, { recursive: true });
|
|
246075
246869
|
for (const entry of entries) {
|
|
246076
246870
|
if (!entry.isFile() || !/\.(?:java|kt|scala)$/iu.test(entry.name)) {
|
|
246077
246871
|
continue;
|
|
@@ -246243,10 +247037,7 @@ function hasRuntimeSourceFiles(workspaceRoot, componentPath) {
|
|
|
246243
247037
|
path64.join(absoluteRoot, "server")
|
|
246244
247038
|
];
|
|
246245
247039
|
for (const sourceRoot of sourceRoots) {
|
|
246246
|
-
|
|
246247
|
-
continue;
|
|
246248
|
-
}
|
|
246249
|
-
const entries = fs58.readdirSync(sourceRoot, { recursive: true, withFileTypes: true });
|
|
247040
|
+
const entries = readDirectoryEntriesForTraversal(sourceRoot, { recursive: true });
|
|
246250
247041
|
if (entries.some((entry) => entry.isFile() && /\.(?:ts|tsx|js|jsx|java|cs|py|php|go)$/iu.test(entry.name))) {
|
|
246251
247042
|
return true;
|
|
246252
247043
|
}
|
|
@@ -246254,10 +247045,7 @@ function hasRuntimeSourceFiles(workspaceRoot, componentPath) {
|
|
|
246254
247045
|
return false;
|
|
246255
247046
|
}
|
|
246256
247047
|
function hasFileMatchingUnderRoot(root, pattern) {
|
|
246257
|
-
|
|
246258
|
-
return false;
|
|
246259
|
-
}
|
|
246260
|
-
const entries = fs58.readdirSync(root, { recursive: true, withFileTypes: true });
|
|
247048
|
+
const entries = readDirectoryEntriesForTraversal(root, { recursive: true });
|
|
246261
247049
|
return entries.some((entry) => entry.isFile() && pattern.test(normalizePath25(path64.join(entry.parentPath, entry.name))));
|
|
246262
247050
|
}
|
|
246263
247051
|
function hasNestRuntimeApplicationEvidence(workspaceRoot, componentPath, packageJson = readPackageJson(workspaceRoot, componentPath)) {
|
|
@@ -246297,16 +247085,19 @@ function hasNestRuntimeApplicationEvidence(workspaceRoot, componentPath, package
|
|
|
246297
247085
|
].filter(Boolean).length;
|
|
246298
247086
|
return hasBootstrapEntrypoint || hasRuntimePlatform && structuralEvidenceCount >= 2 || hasRunnableScript && hasRuntimeSourceShape && structuralEvidenceCount >= 3;
|
|
246299
247087
|
}
|
|
246300
|
-
function
|
|
247088
|
+
function resolveKind2(workspaceRoot, candidate, localProjectKinds) {
|
|
246301
247089
|
const lowerPath = candidate.path.toLowerCase();
|
|
246302
247090
|
const packageJson = readPackageJson(workspaceRoot, candidate.path);
|
|
247091
|
+
const projectJson = readProjectJson(workspaceRoot, candidate.path);
|
|
247092
|
+
const nxProjectType = readStringProperty(projectJson, "projectType");
|
|
246303
247093
|
const maven = readMavenMetadata(workspaceRoot, candidate.path);
|
|
246304
247094
|
const dependencies = new Set(packageDependencyNames(packageJson));
|
|
246305
247095
|
const hasRunnableFrontendEvidence = hasRunnableFrontendComponentEvidence(workspaceRoot, candidate.path);
|
|
246306
247096
|
const hasNestRuntimeEvidence = hasNestRuntimeApplicationEvidence(workspaceRoot, candidate.path, packageJson);
|
|
247097
|
+
const nxRuntimeKind = classifyNxRuntimeKind(projectJson);
|
|
246307
247098
|
const hasPublishSurface = hasPackagePublishSurface(packageJson);
|
|
246308
247099
|
const hasMavenRunnableEvidence = Boolean(
|
|
246309
|
-
maven && (hasMavenMainEntrypoint(workspaceRoot, candidate.path) || hasMavenConfiguredMainClassEntrypoint(workspaceRoot, candidate.path, maven.configuredMainClass) || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypoint(workspaceRoot, candidate.path) || maven.packaging === "war" && hasMavenMainEntrypoint(workspaceRoot, candidate.path))
|
|
247100
|
+
maven && (hasMavenMainEntrypoint(workspaceRoot, candidate.path) || hasMavenConfiguredMainClassEntrypoint(workspaceRoot, candidate.path, maven.configuredMainClass) || maven.configuredMainClass && maven.hasSpringBootStarterDependency || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypoint(workspaceRoot, candidate.path) || maven.packaging === "war" && hasMavenMainEntrypoint(workspaceRoot, candidate.path))
|
|
246310
247101
|
);
|
|
246311
247102
|
const hasMavenLibraryEvidence = Boolean(
|
|
246312
247103
|
maven && !hasMavenRunnableEvidence && (maven.packaging === "jar" || maven.packaging === "maven-plugin" || maven.packaging === "pom") && (hasMavenMainJvmSource(workspaceRoot, candidate.path) || maven.hasMainResources || maven.hasDependencyManagement || maven.hasSpringBootAutoconfigureDependency || maven.hasSpringBootAutoconfigureProcessor || hasMavenAutoConfigurationMetadata(workspaceRoot, candidate.path) || maven.hasDocumentationTooling || maven.hasTestJava || maven.hasTestResources)
|
|
@@ -246314,6 +247105,12 @@ function resolveKind(workspaceRoot, candidate, localProjectKinds) {
|
|
|
246314
247105
|
if (lowerPath.endsWith("/db") || lowerPath.endsWith("/database") || lowerPath.endsWith("/data")) {
|
|
246315
247106
|
return "data";
|
|
246316
247107
|
}
|
|
247108
|
+
if (nxRuntimeKind) {
|
|
247109
|
+
return nxRuntimeKind;
|
|
247110
|
+
}
|
|
247111
|
+
if (nxProjectType === "library") {
|
|
247112
|
+
return "library";
|
|
247113
|
+
}
|
|
246317
247114
|
if (hasMavenLibraryEvidence) {
|
|
246318
247115
|
return "library";
|
|
246319
247116
|
}
|
|
@@ -246413,7 +247210,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246413
247210
|
const scriptText = scripts.join(" ").toLowerCase();
|
|
246414
247211
|
const projectMetadataText = `${projectTags.join(" ")} ${projectTargets.join(" ")}`.toLowerCase();
|
|
246415
247212
|
const dependencyText = [...dependencies, ...devDependencies].join(" ").toLowerCase();
|
|
247213
|
+
const hasRunnableFrontendEvidence = hasRunnableFrontendComponentEvidence(input2.workspaceRoot, input2.candidate.path);
|
|
246416
247214
|
const hasNestRuntimeEvidence = hasNestRuntimeApplicationEvidence(input2.workspaceRoot, input2.candidate.path, packageJson);
|
|
247215
|
+
const nxRuntimeKind = classifyNxRuntimeKind(projectJson);
|
|
247216
|
+
const hasNxSupportOnlyEvidence = hasNxSupportOnlyProjectEvidence(projectJson);
|
|
246417
247217
|
const hasStrongSupportPath = hasAnyToken(pathText, [
|
|
246418
247218
|
/(^|\/)(testing|e2e-testing|test-plugins|cypress-tests|fixtures?|benchmarks?|smoke)(\/|$)/u,
|
|
246419
247219
|
/(^|\/)(dev-server|scaffold|scaffolding|generators?|devkit|tooling|tools|templates?)(\/|$)/u
|
|
@@ -246428,9 +247228,11 @@ function classifyGovernanceRole(input2) {
|
|
|
246428
247228
|
const hasMavenMainEntrypointEvidence = Boolean(maven && hasMavenMainEntrypoint(input2.workspaceRoot, input2.candidate.path));
|
|
246429
247229
|
const hasMavenMainJvmSourceEvidence = Boolean(maven && hasMavenMainJvmSource(input2.workspaceRoot, input2.candidate.path));
|
|
246430
247230
|
const hasMavenAutoConfigurationEvidence = Boolean(maven && (hasMavenAutoConfigurationMetadata(input2.workspaceRoot, input2.candidate.path) || maven.hasSpringBootAutoconfigureDependency || maven.hasSpringBootAutoconfigureProcessor));
|
|
246431
|
-
const hasMavenExecutableConfiguration = Boolean(maven && (hasMavenConfiguredMainClassEntrypoint(input2.workspaceRoot, input2.candidate.path, maven.configuredMainClass) || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypointEvidence || maven.packaging === "war" && hasMavenMainEntrypointEvidence));
|
|
247231
|
+
const hasMavenExecutableConfiguration = Boolean(maven && (hasMavenConfiguredMainClassEntrypoint(input2.workspaceRoot, input2.candidate.path, maven.configuredMainClass) || maven.configuredMainClass && maven.hasSpringBootStarterDependency || maven.hasSpringBootPlugin && maven.hasSpringBootRepackageGoal && hasMavenMainEntrypointEvidence || maven.packaging === "war" && hasMavenMainEntrypointEvidence));
|
|
246432
247232
|
const hasMavenRunnableApplicationEvidence = Boolean(hasMavenMainEntrypointEvidence || hasMavenExecutableConfiguration);
|
|
246433
|
-
const isMavenPomOnly = Boolean(
|
|
247233
|
+
const isMavenPomOnly = Boolean(
|
|
247234
|
+
maven?.packaging === "pom" && !hasMavenRunnableApplicationEvidence && !hasMavenMainSource && !hasMavenTestSource
|
|
247235
|
+
);
|
|
246434
247236
|
const hasMavenTestContext = hasAnyToken(pathText, [
|
|
246435
247237
|
/(^|\/)(test-framework|testsuite|integration-tests?|test-apps)(\/|$)/u
|
|
246436
247238
|
]) && (hasAnyToken(mavenMetadataText, [/\b(test|testsuite|test framework|arquillian|integration test)\b/u]) || Boolean(maven?.hasTestLifecycleConfiguration || maven?.hasArquillianEvidence || hasMavenTestSource));
|
|
@@ -246438,7 +247240,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246438
247240
|
maven?.packaging === "pom" && maven.hasDependencyManagement && !hasMavenMainSource && hasAnyToken(mavenMetadataText, [/\b(bom|bill of materials|dependency management|platform)\b/u])
|
|
246439
247241
|
);
|
|
246440
247242
|
const hasMavenDistributionPackagingEvidence = Boolean(
|
|
246441
|
-
maven
|
|
247243
|
+
maven && !hasMavenMainSource && (maven.hasAssemblyPackagingConfiguration || maven.hasDeploySkipConfiguration && maven.hasDocumentationTooling || hasAnyToken(mavenMetadataText, [/\b(distribution|assembly|release package|packaging bundle)\b/u]))
|
|
246442
247244
|
);
|
|
246443
247245
|
const hasMavenStarterPackagingEvidence = Boolean(
|
|
246444
247246
|
maven && !hasMavenMainJvmSourceEvidence && hasAnyToken(`${pathText} ${mavenMetadataText}`, [/\bstarters?\b|\bspring-boot-starter\b|\bstarter[-\s]/u])
|
|
@@ -246465,6 +247267,18 @@ function classifyGovernanceRole(input2) {
|
|
|
246465
247267
|
runtimeScore += 3;
|
|
246466
247268
|
addEvidence6(evidence, "NestJS runtime application evidence");
|
|
246467
247269
|
}
|
|
247270
|
+
if (input2.kind === "frontend" && hasRunnableFrontendEvidence) {
|
|
247271
|
+
runtimeScore += 3;
|
|
247272
|
+
addEvidence6(evidence, "Runnable frontend application evidence");
|
|
247273
|
+
}
|
|
247274
|
+
if (nxRuntimeKind) {
|
|
247275
|
+
runtimeScore += 3;
|
|
247276
|
+
addEvidence6(evidence, `Nx runtime project evidence: ${nxRuntimeKind}`);
|
|
247277
|
+
}
|
|
247278
|
+
if (hasNxSupportOnlyEvidence) {
|
|
247279
|
+
supportScore += 4;
|
|
247280
|
+
addEvidence6(evidence, "Nx project metadata indicates test/tooling-only workspace");
|
|
247281
|
+
}
|
|
246468
247282
|
if (hasPublishSurface && !isPrivate) {
|
|
246469
247283
|
runtimeScore += 1;
|
|
246470
247284
|
addEvidence6(evidence, "Published package surface signal");
|
|
@@ -246475,7 +247289,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246475
247289
|
if (maven?.hasPom) {
|
|
246476
247290
|
addEvidence6(evidence, `Maven packaging ${maven.packaging ?? "jar"}`);
|
|
246477
247291
|
}
|
|
246478
|
-
if (maven &&
|
|
247292
|
+
if (maven && hasMavenRunnableApplicationEvidence) {
|
|
246479
247293
|
runtimeScore += 3;
|
|
246480
247294
|
addEvidence6(evidence, "Maven executable application evidence");
|
|
246481
247295
|
}
|
|
@@ -246512,6 +247326,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246512
247326
|
supportScore += 1;
|
|
246513
247327
|
addEvidence6(evidence, "Path contains support/tooling role tokens");
|
|
246514
247328
|
}
|
|
247329
|
+
if (maven && hasStrongSupportPath && !hasMavenRunnableApplicationEvidence) {
|
|
247330
|
+
supportScore += 3;
|
|
247331
|
+
addEvidence6(evidence, "Maven module path and metadata indicate support/tooling role");
|
|
247332
|
+
}
|
|
246515
247333
|
if (hasAnyToken(pathText, [/(^|\/)(?:src\/constants\/)?templates?(\/|$)/u])) {
|
|
246516
247334
|
supportScore += 4;
|
|
246517
247335
|
addEvidence6(evidence, "Nested scaffold/template source surface");
|
|
@@ -246544,6 +247362,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246544
247362
|
supportScore += 4;
|
|
246545
247363
|
addEvidence6(evidence, "Maven documentation tooling without JVM runtime source");
|
|
246546
247364
|
}
|
|
247365
|
+
if (maven?.hasDeploySkipConfiguration && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence) {
|
|
247366
|
+
supportScore += 4;
|
|
247367
|
+
addEvidence6(evidence, "Maven deploy-skipped artifact without runtime source");
|
|
247368
|
+
}
|
|
246547
247369
|
if (hasMavenBomEvidence) {
|
|
246548
247370
|
supportScore += 5;
|
|
246549
247371
|
addEvidence6(evidence, "Maven BOM/dependency-management module without runtime source");
|
|
@@ -246572,6 +247394,10 @@ function classifyGovernanceRole(input2) {
|
|
|
246572
247394
|
supportScore += 4;
|
|
246573
247395
|
addEvidence6(evidence, "Maven starter/resource artifact without JVM runtime source");
|
|
246574
247396
|
}
|
|
247397
|
+
if (hasMavenDistributionPackagingEvidence) {
|
|
247398
|
+
supportScore += 4;
|
|
247399
|
+
addEvidence6(evidence, "Maven distribution/release packaging without runtime source");
|
|
247400
|
+
}
|
|
246575
247401
|
if (isPlainResourcesSurface) {
|
|
246576
247402
|
supportScore += 4;
|
|
246577
247403
|
addEvidence6(evidence, "Resources-only surface without runtime source or manifest evidence");
|
|
@@ -246594,7 +247420,7 @@ function classifyGovernanceRole(input2) {
|
|
|
246594
247420
|
supportScore += 3;
|
|
246595
247421
|
addEvidence6(evidence, "Maven documentation/build/distribution packaging evidence without runtime source");
|
|
246596
247422
|
}
|
|
246597
|
-
if (supportScore >= 3 && supportScore > runtimeScore || hasStrongSupportPath && supportScore >= 2 && runtimeScore <= 5 || maven?.packaging === "maven-plugin" && input2.candidate.path !== "." && supportScore >= 5 || maven && supportScore >= 5 && !
|
|
247423
|
+
if (supportScore >= 3 && supportScore > runtimeScore || hasStrongSupportPath && supportScore >= 2 && runtimeScore <= 5 || maven?.packaging === "maven-plugin" && input2.candidate.path !== "." && supportScore >= 5 || maven && supportScore >= 5 && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && maven.hasDeploySkipConfiguration && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && hasStrongSupportPath && !hasMavenMainJvmSourceEvidence && !hasMavenRunnableApplicationEvidence || maven && supportScore >= 4 && hasMavenTestContext || maven && supportScore >= 4 && hasMavenDistributionPackagingEvidence && hasAnyToken(mavenMetadataText, [/\b(docs?|documentation|metadata tests?|licenses?|maven plugins?|builds?)\b/u])) {
|
|
246598
247424
|
return {
|
|
246599
247425
|
governanceRole: "support",
|
|
246600
247426
|
governanceEvidence: uniqueSorted4(evidence),
|
|
@@ -246672,7 +247498,7 @@ function detectComponents(input2) {
|
|
|
246672
247498
|
}
|
|
246673
247499
|
const localProjectKinds = input2.runContext?.detectProjectKinds(absoluteRoot) ?? detectProjectKinds(absoluteRoot);
|
|
246674
247500
|
const stackDetection = input2.runContext?.detectStacks(absoluteRoot) ?? detectStacks(absoluteRoot);
|
|
246675
|
-
const kind =
|
|
247501
|
+
const kind = resolveKind2(input2.workspaceRoot, candidate, localProjectKinds);
|
|
246676
247502
|
const stack = resolveStack(kind, stackDetection);
|
|
246677
247503
|
const evidence = [...candidate.evidence];
|
|
246678
247504
|
if (candidate.architectureRoot?.classification && candidate.architectureRoot.classification !== "unknown") {
|
|
@@ -249938,7 +250764,30 @@ async function runStandardValidationWorkflowForWorkspace(input2) {
|
|
|
249938
250764
|
"Loading governance baseline",
|
|
249939
250765
|
() => readGovernanceBaseline(input2.workspaceRoot)
|
|
249940
250766
|
);
|
|
249941
|
-
|
|
250767
|
+
applyCanonicalValidationSummary(reviewSummary, runResult.status.summary);
|
|
250768
|
+
let effectiveGovernanceBaseline = governanceBaseline;
|
|
250769
|
+
let initialGovernanceBaselinePath;
|
|
250770
|
+
if (governanceBaseline.kind === "missing" && !input2.ciMode) {
|
|
250771
|
+
const baseline = buildGovernanceBaselineFromReviewSummary(reviewSummary);
|
|
250772
|
+
initialGovernanceBaselinePath = await phase(
|
|
250773
|
+
"Creating initial governance baseline",
|
|
250774
|
+
() => writeGovernanceBaseline(input2.workspaceRoot, baseline)
|
|
250775
|
+
);
|
|
250776
|
+
effectiveGovernanceBaseline = {
|
|
250777
|
+
kind: "ok",
|
|
250778
|
+
baseline,
|
|
250779
|
+
baselinePath: initialGovernanceBaselinePath
|
|
250780
|
+
};
|
|
250781
|
+
emitOperationalMessage(
|
|
250782
|
+
input2.onOperationalMessage,
|
|
250783
|
+
"info",
|
|
250784
|
+
"Governance baseline created from initial validation. Future validations will highlight new architecture regressions."
|
|
250785
|
+
);
|
|
250786
|
+
}
|
|
250787
|
+
const baselineComparison = compareWithGovernanceBaseline(
|
|
250788
|
+
reviewSummary,
|
|
250789
|
+
effectiveGovernanceBaseline
|
|
250790
|
+
);
|
|
249942
250791
|
reviewSummary.enforcement = buildEnforcementResult(
|
|
249943
250792
|
reviewSummary.risk,
|
|
249944
250793
|
riskPolicyLoad.config,
|
|
@@ -249959,7 +250808,6 @@ async function runStandardValidationWorkflowForWorkspace(input2) {
|
|
|
249959
250808
|
})
|
|
249960
250809
|
);
|
|
249961
250810
|
reviewSummary.baselineComparison = baselineComparison;
|
|
249962
|
-
applyCanonicalValidationSummary(reviewSummary, runResult.status.summary);
|
|
249963
250811
|
let baselineComparisonPath;
|
|
249964
250812
|
try {
|
|
249965
250813
|
baselineComparisonPath = await writeBaselineComparisonReport(
|
|
@@ -250024,6 +250872,7 @@ async function runStandardValidationWorkflowForWorkspace(input2) {
|
|
|
250024
250872
|
impactAnalysisPath,
|
|
250025
250873
|
baselineComparison,
|
|
250026
250874
|
...baselineComparisonPath ? { baselineComparisonPath } : {},
|
|
250875
|
+
...initialGovernanceBaselinePath ? { initialGovernanceBaselinePath } : {},
|
|
250027
250876
|
...prCommentPath ? { prCommentPath } : {}
|
|
250028
250877
|
};
|
|
250029
250878
|
}
|
|
@@ -250209,6 +251058,7 @@ function parseValidateFlags(args) {
|
|
|
250209
251058
|
json: args.includes("--json"),
|
|
250210
251059
|
changed: args.includes("--changed"),
|
|
250211
251060
|
diff: args.includes("--diff"),
|
|
251061
|
+
regressions: args.includes("--regressions"),
|
|
250212
251062
|
base: base.length > 0 ? base : "main"
|
|
250213
251063
|
};
|
|
250214
251064
|
}
|
|
@@ -250255,8 +251105,8 @@ function readFlagValue(args, flag) {
|
|
|
250255
251105
|
return value && value.length > 0 ? value : void 0;
|
|
250256
251106
|
}
|
|
250257
251107
|
async function readCliPackageVersion() {
|
|
250258
|
-
if ("0.2.
|
|
250259
|
-
return "0.2.
|
|
251108
|
+
if ("0.2.7".trim().length > 0) {
|
|
251109
|
+
return "0.2.7".trim();
|
|
250260
251110
|
}
|
|
250261
251111
|
const candidatePackageJsonPaths = [
|
|
250262
251112
|
path73.join(__dirname, "..", "package.json"),
|
|
@@ -250313,7 +251163,7 @@ function printUsage() {
|
|
|
250313
251163
|
console.error("Usage: archpilot init [--yes]");
|
|
250314
251164
|
console.error(" archpilot init refresh --preview");
|
|
250315
251165
|
console.error(" archpilot init refresh --apply");
|
|
250316
|
-
console.error("Usage: archpilot validate [--ci] [--json] [--changed] [--diff] [--base <branch>]");
|
|
251166
|
+
console.error("Usage: archpilot validate [--ci] [--json] [--regressions] [--changed] [--diff] [--base <branch>]");
|
|
250317
251167
|
console.error(" archpilot impact <file-or-module> [--json] [--stdout] [--module] [--force]");
|
|
250318
251168
|
console.error(" archpilot fix <RULE_ID>");
|
|
250319
251169
|
console.error(" archpilot fix");
|
|
@@ -250400,11 +251250,12 @@ var cliHelpTopics = [
|
|
|
250400
251250
|
{
|
|
250401
251251
|
commandPath: ["validate"],
|
|
250402
251252
|
lines: [
|
|
250403
|
-
"Usage: archpilot validate [--ci] [--json] [--changed] [--diff] [--base <branch>]",
|
|
251253
|
+
"Usage: archpilot validate [--ci] [--json] [--regressions] [--changed] [--diff] [--base <branch>]",
|
|
250404
251254
|
"",
|
|
250405
251255
|
"Options:",
|
|
250406
251256
|
" --ci CI mode",
|
|
250407
251257
|
" --json JSON output",
|
|
251258
|
+
" --regressions show findings introduced or resolved since the governance baseline",
|
|
250408
251259
|
" --changed validate changed files only",
|
|
250409
251260
|
" --diff compare with baseline",
|
|
250410
251261
|
" --base <branch> compare against branch"
|
|
@@ -252481,12 +253332,136 @@ function applyCanonicalValidationSummary2(reviewSummary, validationSummary) {
|
|
|
252481
253332
|
reviewSummary.guidanceFindings = validationSummary.guidanceFindings;
|
|
252482
253333
|
reviewSummary.qualityFindings = validationSummary.qualityFindings;
|
|
252483
253334
|
}
|
|
253335
|
+
function getRegressionComparisonUnavailableReason(comparison) {
|
|
253336
|
+
if (comparison.baselineAvailable) {
|
|
253337
|
+
return void 0;
|
|
253338
|
+
}
|
|
253339
|
+
return comparison.summary.startsWith("Baseline unavailable:") ? "INVALID_BASELINE" : "NO_BASELINE";
|
|
253340
|
+
}
|
|
253341
|
+
function formatRegressionFindingLine2(finding) {
|
|
253342
|
+
const location = finding.module && finding.target ? `${finding.module} -> ${finding.target}` : finding.module ?? finding.target ?? finding.sourceFile ?? finding.filePath ?? finding.table ?? finding.api;
|
|
253343
|
+
const header = `${finding.id} ${finding.severity}`;
|
|
253344
|
+
return [
|
|
253345
|
+
location ? `${header}
|
|
253346
|
+
${location}` : header,
|
|
253347
|
+
finding.message
|
|
253348
|
+
].join("\n");
|
|
253349
|
+
}
|
|
253350
|
+
function renderRegressionFindingSection(title, findings) {
|
|
253351
|
+
const lines = [];
|
|
253352
|
+
lines.push(title);
|
|
253353
|
+
lines.push("-".repeat(title.length));
|
|
253354
|
+
lines.push("");
|
|
253355
|
+
if (findings.length === 0) {
|
|
253356
|
+
lines.push("- (none)");
|
|
253357
|
+
return lines;
|
|
253358
|
+
}
|
|
253359
|
+
for (const finding of findings) {
|
|
253360
|
+
lines.push(formatRegressionFindingLine2(finding));
|
|
253361
|
+
lines.push("");
|
|
253362
|
+
}
|
|
253363
|
+
while (lines.at(-1) === "") {
|
|
253364
|
+
lines.pop();
|
|
253365
|
+
}
|
|
253366
|
+
return lines;
|
|
253367
|
+
}
|
|
253368
|
+
function renderValidationRegressionConsole(comparison) {
|
|
253369
|
+
const unavailableReason = getRegressionComparisonUnavailableReason(comparison);
|
|
253370
|
+
const lines = [];
|
|
253371
|
+
lines.push("Regression Summary");
|
|
253372
|
+
lines.push("------------------");
|
|
253373
|
+
if (unavailableReason) {
|
|
253374
|
+
lines.push("Regression comparison unavailable.");
|
|
253375
|
+
lines.push("");
|
|
253376
|
+
if (unavailableReason === "NO_BASELINE") {
|
|
253377
|
+
lines.push("No governance baseline was found.");
|
|
253378
|
+
lines.push("");
|
|
253379
|
+
lines.push("Create a governance baseline first:");
|
|
253380
|
+
lines.push(" archpilot baseline refresh");
|
|
253381
|
+
} else {
|
|
253382
|
+
lines.push(comparison.summary);
|
|
253383
|
+
}
|
|
253384
|
+
return `${lines.join("\n")}
|
|
253385
|
+
`;
|
|
253386
|
+
}
|
|
253387
|
+
lines.push(`Introduced: ${comparison.newlyIntroducedFindings.length}`);
|
|
253388
|
+
lines.push(`Resolved: ${comparison.resolvedFindings.length}`);
|
|
253389
|
+
lines.push(`Existing: ${comparison.unchangedFindings.length}`);
|
|
253390
|
+
lines.push("");
|
|
253391
|
+
if (comparison.newlyIntroducedFindings.length === 0) {
|
|
253392
|
+
lines.push("No new architecture regressions detected.");
|
|
253393
|
+
} else {
|
|
253394
|
+
lines.push(
|
|
253395
|
+
...renderRegressionFindingSection(
|
|
253396
|
+
"Introduced architecture findings",
|
|
253397
|
+
comparison.newlyIntroducedFindings
|
|
253398
|
+
)
|
|
253399
|
+
);
|
|
253400
|
+
}
|
|
253401
|
+
if (comparison.resolvedFindings.length > 0) {
|
|
253402
|
+
lines.push("");
|
|
253403
|
+
lines.push(...renderRegressionFindingSection("Resolved", comparison.resolvedFindings));
|
|
253404
|
+
}
|
|
253405
|
+
return `${lines.join("\n").trimEnd()}
|
|
253406
|
+
`;
|
|
253407
|
+
}
|
|
253408
|
+
function buildRegressionComparisonJson(comparison) {
|
|
253409
|
+
const unavailableReason = getRegressionComparisonUnavailableReason(comparison);
|
|
253410
|
+
if (unavailableReason) {
|
|
253411
|
+
return {
|
|
253412
|
+
available: false,
|
|
253413
|
+
reason: unavailableReason,
|
|
253414
|
+
introducedCount: 0,
|
|
253415
|
+
resolvedCount: 0,
|
|
253416
|
+
existingCount: 0,
|
|
253417
|
+
introduced: [],
|
|
253418
|
+
resolved: []
|
|
253419
|
+
};
|
|
253420
|
+
}
|
|
253421
|
+
return {
|
|
253422
|
+
available: true,
|
|
253423
|
+
introducedCount: comparison.newlyIntroducedFindings.length,
|
|
253424
|
+
resolvedCount: comparison.resolvedFindings.length,
|
|
253425
|
+
existingCount: comparison.unchangedFindings.length,
|
|
253426
|
+
introduced: comparison.newlyIntroducedFindings,
|
|
253427
|
+
resolved: comparison.resolvedFindings
|
|
253428
|
+
};
|
|
253429
|
+
}
|
|
253430
|
+
function buildScopedRegressionComparisonUnavailable(summary, scopeMode) {
|
|
253431
|
+
return {
|
|
253432
|
+
reportVersion: 1,
|
|
253433
|
+
baselineAvailable: false,
|
|
253434
|
+
status: "NO_BASELINE",
|
|
253435
|
+
summary: `Regression comparison unavailable for ${scopeMode} validation scope. Full governance baselines cannot be compared safely against scoped current findings.`,
|
|
253436
|
+
current: {
|
|
253437
|
+
projectName: summary.projectName,
|
|
253438
|
+
generatedAtUtc: summary.generatedAtUtc,
|
|
253439
|
+
healthScore: summary.healthScore,
|
|
253440
|
+
readinessScore: summary.readinessScore
|
|
253441
|
+
},
|
|
253442
|
+
deltas: {
|
|
253443
|
+
healthScoreDelta: 0,
|
|
253444
|
+
readinessScoreDelta: 0,
|
|
253445
|
+
errorDelta: 0,
|
|
253446
|
+
warningDelta: 0,
|
|
253447
|
+
findingDelta: 0,
|
|
253448
|
+
remainingViolationsDelta: 0
|
|
253449
|
+
},
|
|
253450
|
+
newlyIntroducedFindings: [],
|
|
253451
|
+
resolvedFindings: [],
|
|
253452
|
+
unchangedFindings: []
|
|
253453
|
+
};
|
|
253454
|
+
}
|
|
252484
253455
|
async function runValidateCommand(args) {
|
|
252485
253456
|
const flags = parseValidateFlags(args);
|
|
252486
253457
|
if (flags.changed && flags.diff) {
|
|
252487
253458
|
console.error("Choose one scope mode: --changed or --diff.");
|
|
252488
253459
|
return 1;
|
|
252489
253460
|
}
|
|
253461
|
+
if (flags.regressions && (flags.changed || flags.diff)) {
|
|
253462
|
+
console.error("--regressions cannot currently be combined with --changed/--diff.");
|
|
253463
|
+
return 1;
|
|
253464
|
+
}
|
|
252490
253465
|
if (args.includes("--base") && !flags.diff) {
|
|
252491
253466
|
console.error("--base can only be used with --diff.");
|
|
252492
253467
|
return 1;
|
|
@@ -252643,8 +253618,7 @@ async function runValidateCommand(args) {
|
|
|
252643
253618
|
}
|
|
252644
253619
|
}
|
|
252645
253620
|
});
|
|
252646
|
-
|
|
252647
|
-
baselineComparison = compareWithGovernanceBaseline(reviewSummary, governanceBaseline);
|
|
253621
|
+
baselineComparison = buildScopedRegressionComparisonUnavailable(reviewSummary, scopeMode);
|
|
252648
253622
|
reviewSummary.enforcement = buildEnforcementResult2(
|
|
252649
253623
|
reviewSummary.risk,
|
|
252650
253624
|
riskPolicyLoad.config,
|
|
@@ -252743,6 +253717,7 @@ async function runValidateCommand(args) {
|
|
|
252743
253717
|
impactAnalysis: reviewSummary.impactAnalysis,
|
|
252744
253718
|
impactAnalysisPath: toWorkspaceRelativePath(workspaceRoot, impactAnalysisPath),
|
|
252745
253719
|
baselineComparison,
|
|
253720
|
+
...flags.regressions ? { regressionComparison: buildRegressionComparisonJson(baselineComparison) } : {},
|
|
252746
253721
|
...baselineComparisonPath ? {
|
|
252747
253722
|
baselineComparisonPath: toWorkspaceRelativePath(
|
|
252748
253723
|
workspaceRoot,
|
|
@@ -252787,24 +253762,36 @@ async function runValidateCommand(args) {
|
|
|
252787
253762
|
`
|
|
252788
253763
|
);
|
|
252789
253764
|
}
|
|
252790
|
-
|
|
252791
|
-
|
|
252792
|
-
|
|
252793
|
-
|
|
252794
|
-
|
|
252795
|
-
|
|
252796
|
-
|
|
252797
|
-
|
|
252798
|
-
|
|
252799
|
-
|
|
252800
|
-
|
|
252801
|
-
|
|
252802
|
-
|
|
252803
|
-
|
|
252804
|
-
|
|
252805
|
-
|
|
252806
|
-
|
|
252807
|
-
|
|
253765
|
+
if (flags.regressions) {
|
|
253766
|
+
process.stdout.write("ArchPilot Architecture Review\n\n");
|
|
253767
|
+
process.stdout.write(`Architecture Health Score: ${reviewSummary.healthScore} / 100
|
|
253768
|
+
`);
|
|
253769
|
+
process.stdout.write(`Setup Readiness Score: ${reviewSummary.readinessScore} / 100
|
|
253770
|
+
`);
|
|
253771
|
+
process.stdout.write(`Current findings: ${reviewSummary.findings.length}
|
|
253772
|
+
|
|
253773
|
+
`);
|
|
253774
|
+
process.stdout.write(renderValidationRegressionConsole(baselineComparison));
|
|
253775
|
+
} else {
|
|
253776
|
+
process.stdout.write(
|
|
253777
|
+
renderArchitectureReviewConsole(reviewSummary, {
|
|
253778
|
+
...reportArtifacts.reportWriteError ? { reportWriteError: reportArtifacts.reportWriteError } : {
|
|
253779
|
+
reportPaths: {
|
|
253780
|
+
markdownPath: reportArtifacts.reviewMarkdownPath,
|
|
253781
|
+
jsonPath: reportArtifacts.reviewJsonPath,
|
|
253782
|
+
compactMarkdownPath: reportArtifacts.reviewCompactMarkdownPath
|
|
253783
|
+
}
|
|
253784
|
+
},
|
|
253785
|
+
remediation,
|
|
253786
|
+
discoveredAdrs,
|
|
253787
|
+
healthTrend: runResult.status.summary.healthTrend,
|
|
253788
|
+
driftComparison: runResult.status.driftComparison,
|
|
253789
|
+
adrSummary: runResult.status.adrSummary,
|
|
253790
|
+
suppressionSummary: runResult.status.suppressionSummary,
|
|
253791
|
+
baselineComparison
|
|
253792
|
+
})
|
|
253793
|
+
);
|
|
253794
|
+
}
|
|
252808
253795
|
process.stdout.write("\n");
|
|
252809
253796
|
process.stdout.write(renderSetupNextStepsConsole(nextSteps));
|
|
252810
253797
|
process.stdout.write(`${setupNextStepsReportPointerLine}
|