@archpilotlabs/archpilot 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13660,11 +13660,11 @@ ${lanes.join("\n")}
13660
13660
  return toComponents;
13661
13661
  }
13662
13662
  const components = toComponents.slice(start);
13663
- const relative17 = [];
13663
+ const relative18 = [];
13664
13664
  for (; start < fromComponents.length; start++) {
13665
- relative17.push("..");
13665
+ relative18.push("..");
13666
13666
  }
13667
- return ["", ...relative17, ...components];
13667
+ return ["", ...relative18, ...components];
13668
13668
  }
13669
13669
  function getRelativePathFromDirectory(fromDirectory, to, getCanonicalFileNameOrIgnoreCase) {
13670
13670
  Debug.assert(getRootLength(fromDirectory) > 0 === getRootLength(to) > 0, "Paths must either both be absolute or both be relative");
@@ -52233,11 +52233,11 @@ ${lanes.join("\n")}
52233
52233
  if (i < rootLength) {
52234
52234
  return void 0;
52235
52235
  }
52236
- const sep = directory.lastIndexOf(directorySeparator, i - 1);
52237
- if (sep === -1) {
52236
+ const sep2 = directory.lastIndexOf(directorySeparator, i - 1);
52237
+ if (sep2 === -1) {
52238
52238
  return void 0;
52239
52239
  }
52240
- return directory.substr(0, Math.max(sep, rootLength));
52240
+ return directory.substr(0, Math.max(sep2, rootLength));
52241
52241
  }
52242
52242
  }
52243
52243
  }
@@ -58143,9 +58143,9 @@ ${lanes.join("\n")}
58143
58143
  if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) {
58144
58144
  return;
58145
58145
  }
58146
- const relative17 = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName);
58146
+ const relative18 = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName);
58147
58147
  for (const symlinkDirectory of symlinkDirectories) {
58148
- const option = resolvePath(symlinkDirectory, relative17);
58148
+ const option = resolvePath(symlinkDirectory, relative18);
58149
58149
  const result2 = cb(option, target === referenceRedirect);
58150
58150
  shouldFilterIgnoredPaths = true;
58151
58151
  if (result2) return result2;
@@ -127982,7 +127982,7 @@ ${lanes.join("\n")}
127982
127982
  }
127983
127983
  }
127984
127984
  function createImportCallExpressionAMD(arg, containsLexicalThis) {
127985
- const resolve9 = factory2.createUniqueName("resolve");
127985
+ const resolve10 = factory2.createUniqueName("resolve");
127986
127986
  const reject = factory2.createUniqueName("reject");
127987
127987
  const parameters = [
127988
127988
  factory2.createParameterDeclaration(
@@ -127991,7 +127991,7 @@ ${lanes.join("\n")}
127991
127991
  /*dotDotDotToken*/
127992
127992
  void 0,
127993
127993
  /*name*/
127994
- resolve9
127994
+ resolve10
127995
127995
  ),
127996
127996
  factory2.createParameterDeclaration(
127997
127997
  /*modifiers*/
@@ -128008,7 +128008,7 @@ ${lanes.join("\n")}
128008
128008
  factory2.createIdentifier("require"),
128009
128009
  /*typeArguments*/
128010
128010
  void 0,
128011
- [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve9, reject]
128011
+ [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve10, reject]
128012
128012
  )
128013
128013
  )
128014
128014
  ]);
@@ -214726,8 +214726,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
214726
214726
  installPackage(options) {
214727
214727
  this.packageInstallId++;
214728
214728
  const request3 = { kind: "installPackage", ...options, id: this.packageInstallId };
214729
- const promise = new Promise((resolve9, reject) => {
214730
- (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve9, reject });
214729
+ const promise = new Promise((resolve10, reject) => {
214730
+ (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve10, reject });
214731
214731
  });
214732
214732
  this.installer.send(request3);
214733
214733
  return promise;
@@ -215444,6 +215444,8 @@ function classifyValidationSourceScope(relativePath) {
215444
215444
  const isFixture = hasPathSegment(normalized, /^(?:fixtures?|__fixtures__)$/u);
215445
215445
  const isTestPlugin = hasPathSegment(normalized, /^(?:test-plugins?|testing-plugins?)$/u);
215446
215446
  const isExamplePlugin = hasPathSegment(normalized, /^example-plugins?$/u) || hasTopLevelPathSegment(normalized, /^examples?$/u);
215447
+ const isMavenIntegrationTestModule = hasTopLevelPathSegment(normalized, /^[a-z0-9_.-]+-integration-tests?$/u) || hasTopLevelPathSegment(normalized, /^[a-z0-9_.-]+-it$/u);
215448
+ const isMavenExampleModule = hasTopLevelPathSegment(normalized, /^[a-z0-9_.-]+-examples?$/u);
215447
215449
  const isGenerated = hasPathSegment(normalized, /^(?:generated|__generated__|gen|templates?)$/u) || /\.(?:generated|gen|g)\.(?:ts|tsx|js|jsx|java|cs|py|php|go)$/u.test(fileName) || /\.d\.ts$/u.test(fileName);
215448
215450
  const isMigration = hasPathSegment(normalized, /^(?:migrations?|schema-migrations?|data-migrations|migration-utils?)$/u);
215449
215451
  const isCliTooling = hasPathSegment(normalized, /^(?:cli|bin|scripts?|tools?|scaffold|scaffolding|generators?)$/u) || /(?:^|[./_-])(?:cli|script|tool|generator|scaffold)(?:[./_-]|$)/u.test(fileName);
@@ -215454,11 +215456,11 @@ function classifyValidationSourceScope(relativePath) {
215454
215456
  category = "generated";
215455
215457
  } else if (isE2e) {
215456
215458
  category = "e2e";
215457
- } else if (isTestFile || hasPathSegment(normalized, /^(?:test|tests|__tests__|spec|specs|__mocks__|cypress|cypress-tests)$/u)) {
215459
+ } else if (isTestFile || isMavenIntegrationTestModule || hasPathSegment(normalized, /^(?:test|tests|__tests__|spec|specs|__mocks__|cypress|cypress-tests)$/u)) {
215458
215460
  category = "test";
215459
215461
  } else if (isTestPlugin) {
215460
215462
  category = "test-plugin";
215461
- } else if (isExamplePlugin) {
215463
+ } else if (isExamplePlugin || isMavenExampleModule) {
215462
215464
  category = "example-plugin";
215463
215465
  } else if (isFixture) {
215464
215466
  category = "fixture";
@@ -215970,6 +215972,41 @@ async function buildExplicitStandaloneModulePathMap(workspaceRoot, architectureC
215970
215972
  function isTestSourcePath(relativePath) {
215971
215973
  return classifyValidationSourceScope(relativePath).isTestLike;
215972
215974
  }
215975
+ function hasStandardTestSourceRoot(relativePath) {
215976
+ const normalized = normalizePath4(relativePath);
215977
+ return /(?:^|\/)src\/(?:test|it|integration-test|integration-tests)\//u.test(normalized) || /(?:^|\/)(?:test|tests|__tests__|spec|specs|e2e|cypress)\//u.test(normalized) || /\.(?:spec|test|e2e-spec|integration-test)\.(?:ts|tsx|js|jsx|mjs|cjs|java|cs|py|php|go)$/u.test(
215978
+ normalized.split("/").at(-1) ?? normalized
215979
+ );
215980
+ }
215981
+ function shouldSkipDependencySource(relativePath, moduleRoot, workspaceRoot, includeTestFiles, includeConfiguredNonProductionModuleSources) {
215982
+ if (includeTestFiles) {
215983
+ return false;
215984
+ }
215985
+ const moduleRootRelativePath = normalizePath4(path7.relative(workspaceRoot, moduleRoot));
215986
+ const moduleRootScope = classifyValidationSourceScope(moduleRootRelativePath);
215987
+ if (hasStandardTestSourceRoot(relativePath)) {
215988
+ return !includeConfiguredNonProductionModuleSources || moduleRootScope.isProduction || moduleRootScope.isTestLike;
215989
+ }
215990
+ if (!isTestSourcePath(relativePath)) {
215991
+ return false;
215992
+ }
215993
+ return !includeConfiguredNonProductionModuleSources || !moduleRootScope.isTestLike;
215994
+ }
215995
+ function filterImportsForBoundaryChecks(imports, moduleRoots, workspaceRoot) {
215996
+ return imports.filter((dependencyImport) => {
215997
+ const moduleRoot = moduleRoots.get(dependencyImport.sourceModule);
215998
+ if (!moduleRoot) {
215999
+ return true;
216000
+ }
216001
+ return !shouldSkipDependencySource(
216002
+ dependencyImport.sourceFileRelativePath,
216003
+ moduleRoot,
216004
+ workspaceRoot,
216005
+ false,
216006
+ false
216007
+ );
216008
+ });
216009
+ }
215973
216010
  async function collectSourceFiles(directoryPath, adapter, scanRootPath = directoryPath, excludedDirectoryRoots = []) {
215974
216011
  const entries = await import_node_fs6.promises.readdir(directoryPath, { withFileTypes: true });
215975
216012
  entries.sort((left, right) => left.name.localeCompare(right.name));
@@ -216197,7 +216234,7 @@ function extractJavaPackageName(sourceText) {
216197
216234
  const match = /^\s*package\s+([a-zA-Z_][\w.]*)\s*;/mu.exec(sourceText);
216198
216235
  return match?.[1];
216199
216236
  }
216200
- async function buildJavaImportIndex(workspaceRoot, moduleRoots, adapter) {
216237
+ async function buildJavaImportIndex(workspaceRoot, moduleRoots, adapter, options) {
216201
216238
  const classes = /* @__PURE__ */ new Map();
216202
216239
  const packageCandidates = /* @__PURE__ */ new Map();
216203
216240
  for (const [moduleId, moduleRoot] of [...moduleRoots.entries()].sort(
@@ -216207,7 +216244,13 @@ async function buildJavaImportIndex(workspaceRoot, moduleRoots, adapter) {
216207
216244
  const sourceFiles = await collectSourceFiles(moduleRoot, adapter, moduleRoot, childModuleRoots);
216208
216245
  for (const sourceFilePath of sourceFiles) {
216209
216246
  const relativePath = normalizePath4(path7.relative(workspaceRoot, sourceFilePath));
216210
- if (isTestSourcePath(relativePath)) {
216247
+ if (shouldSkipDependencySource(
216248
+ relativePath,
216249
+ moduleRoot,
216250
+ workspaceRoot,
216251
+ false,
216252
+ options?.includeConfiguredNonProductionModuleSources === true
216253
+ )) {
216211
216254
  continue;
216212
216255
  }
216213
216256
  const sourceText = await readTextFileIfExists2(sourceFilePath);
@@ -216850,10 +216893,13 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
216850
216893
  async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, workspacePackageAliases, adapter, options) {
216851
216894
  const imports = [];
216852
216895
  const includeTestFiles = options?.includeTestFiles === true;
216896
+ const includeConfiguredNonProductionModuleSources = options?.includeConfiguredNonProductionModuleSources === true;
216853
216897
  if (!supportsDependencyImportParsing(adapter)) {
216854
216898
  return imports;
216855
216899
  }
216856
- const javaImportIndex = usesJavaImportParser(adapter) ? await buildJavaImportIndex(workspaceRoot, moduleRoots, adapter) : void 0;
216900
+ const javaImportIndex = usesJavaImportParser(adapter) ? await buildJavaImportIndex(workspaceRoot, moduleRoots, adapter, {
216901
+ includeConfiguredNonProductionModuleSources
216902
+ }) : void 0;
216857
216903
  for (const [moduleName, moduleRoot] of [...moduleRoots.entries()].sort(
216858
216904
  ([left], [right]) => left.localeCompare(right)
216859
216905
  )) {
@@ -216868,7 +216914,13 @@ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath,
216868
216914
  const sourceFileRelativePath = normalizePath4(
216869
216915
  path7.relative(workspaceRoot, sourceFilePath)
216870
216916
  );
216871
- if (!includeTestFiles && isTestSourcePath(sourceFileRelativePath)) {
216917
+ if (shouldSkipDependencySource(
216918
+ sourceFileRelativePath,
216919
+ moduleRoot,
216920
+ workspaceRoot,
216921
+ includeTestFiles,
216922
+ includeConfiguredNonProductionModuleSources
216923
+ )) {
216872
216924
  continue;
216873
216925
  }
216874
216926
  const sourceText = await readTextFileIfExists2(sourceFilePath);
@@ -217418,7 +217470,10 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
217418
217470
  explicitStandaloneModuleByPath,
217419
217471
  workspacePackageAliases,
217420
217472
  adapter,
217421
- { resolutionContext }
217473
+ {
217474
+ includeConfiguredNonProductionModuleSources: true,
217475
+ resolutionContext
217476
+ }
217422
217477
  );
217423
217478
  options?.onCollectedImports?.(imports);
217424
217479
  options?.onResolutionStats?.(resolutionContext.getStats());
@@ -217522,10 +217577,11 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
217522
217577
  workspacePackageAliases,
217523
217578
  adapter
217524
217579
  );
217580
+ const boundaryImports = filterImportsForBoundaryChecks(imports, moduleRoots, workspaceRoot);
217525
217581
  const dependencyContextResolver = createArchitectureDependencyContextResolver(
217526
217582
  architectureContract
217527
217583
  );
217528
- const peerImports = filterPeerModuleImports(imports);
217584
+ const peerImports = filterPeerModuleImports(boundaryImports);
217529
217585
  const moduleScopedPeerImports = peerImports.filter(
217530
217586
  (dependencyImport) => isModuleScopedDependencyImport(
217531
217587
  architectureContract,
@@ -217836,7 +217892,8 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
217836
217892
  workspaceRoot,
217837
217893
  canonicalModuleRoots
217838
217894
  ),
217839
- adapter
217895
+ adapter,
217896
+ { includeConfiguredNonProductionModuleSources: true }
217840
217897
  );
217841
217898
  const canonicalPeerImports = filterPeerModuleImports(canonicalImports).filter(
217842
217899
  (dependencyImport) => isModuleScopedDependencyImport(architectureContract, dependencyImport)
@@ -217934,8 +217991,9 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
217934
217991
  workspacePackageAliases,
217935
217992
  adapter
217936
217993
  );
217994
+ const boundaryImports = filterImportsForBoundaryChecks(imports, moduleRoots, workspaceRoot);
217937
217995
  const dependencyContextResolver = parsedArchitectureContract ? createArchitectureDependencyContextResolver(parsedArchitectureContract) : void 0;
217938
- const peerImports = filterPeerModuleImports(imports);
217996
+ const peerImports = filterPeerModuleImports(boundaryImports);
217939
217997
  const moduleScopedPeerImports = peerImports.filter(
217940
217998
  (dependencyImport) => isModuleScopedDependencyImport(
217941
217999
  parsedArchitectureContract,
@@ -218191,7 +218249,8 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
218191
218249
  moduleRoots,
218192
218250
  explicitStandaloneModuleByPath,
218193
218251
  workspacePackageAliases,
218194
- adapter
218252
+ adapter,
218253
+ { includeConfiguredNonProductionModuleSources: true }
218195
218254
  );
218196
218255
  const imports = filterPeerModuleImports(allImports).filter(
218197
218256
  (dependencyImport) => moduleSet.has(dependencyImport.sourceModule) && moduleSet.has(dependencyImport.targetModule)
@@ -222217,7 +222276,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
222217
222276
  "AP-ARCH-005",
222218
222277
  "error",
222219
222278
  true,
222220
- "No modules are registered in architecture.json. Module registry path checks are not applicable."
222279
+ "No explicit root modules are registered in architecture.json. Root module registry path checks are not applicable; component-backed contracts are validated by dependency checks."
222221
222280
  )
222222
222281
  });
222223
222282
  }
@@ -222227,7 +222286,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
222227
222286
  "AP-ARCH-006",
222228
222287
  "error",
222229
222288
  true,
222230
- "No modules are registered in architecture.json. Module contract file checks are not applicable."
222289
+ "No explicit root modules are registered in architecture.json. Root module contract file checks are not applicable; component-backed contracts are validated by dependency checks."
222231
222290
  )
222232
222291
  });
222233
222292
  }
@@ -222237,7 +222296,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
222237
222296
  "AP-ARCH-007",
222238
222297
  "error",
222239
222298
  true,
222240
- "No modules are registered in architecture.json. Module contract identity checks are not applicable."
222299
+ "No explicit root modules are registered in architecture.json. Root module contract identity checks are not applicable; component-backed contracts are validated by dependency checks."
222241
222300
  )
222242
222301
  });
222243
222302
  }
@@ -222247,7 +222306,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
222247
222306
  "AP-ARCH-008",
222248
222307
  "error",
222249
222308
  true,
222250
- "No modules are registered in architecture.json. Module public entrypoint alignment checks are not applicable."
222309
+ "No explicit root modules are registered in architecture.json. Root module public entrypoint alignment checks are not applicable; component-backed contracts are validated by dependency checks."
222251
222310
  )
222252
222311
  });
222253
222312
  }
@@ -223196,7 +223255,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223196
223255
  "info",
223197
223256
  `Remote policy configured. Loading policy from ${policySourceUrl}.`
223198
223257
  );
223199
- return new Promise((resolve9) => {
223258
+ return new Promise((resolve10) => {
223200
223259
  const request3 = https.request(
223201
223260
  {
223202
223261
  protocol: validated.url.protocol,
@@ -223223,7 +223282,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223223
223282
  "warn",
223224
223283
  `Remote policy request failed with HTTP ${statusCode}. Using local policy only.`
223225
223284
  );
223226
- resolve9({
223285
+ resolve10({
223227
223286
  message: `Remote policy request failed with HTTP ${statusCode}. Using local policy only.`
223228
223287
  });
223229
223288
  return;
@@ -223237,7 +223296,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223237
223296
  "warn",
223238
223297
  "Remote policy payload is invalid JSON. Using local policy only."
223239
223298
  );
223240
- resolve9({
223299
+ resolve10({
223241
223300
  message: "Remote policy payload is invalid JSON. Using local policy only."
223242
223301
  });
223243
223302
  return;
@@ -223249,7 +223308,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223249
223308
  "warn",
223250
223309
  "Remote policy payload has an invalid structure. Using local policy only."
223251
223310
  );
223252
- resolve9({
223311
+ resolve10({
223253
223312
  message: "Remote policy payload has an invalid structure. Using local policy only."
223254
223313
  });
223255
223314
  return;
@@ -223259,7 +223318,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223259
223318
  "info",
223260
223319
  "Remote policy loaded successfully."
223261
223320
  );
223262
- resolve9({
223321
+ resolve10({
223263
223322
  policy: normalized,
223264
223323
  message: "Remote policy loaded successfully."
223265
223324
  });
@@ -223275,7 +223334,7 @@ async function loadRemotePolicyWithStatus(policySourceUrl, options) {
223275
223334
  "warn",
223276
223335
  "Remote policy unavailable. Using local policy only."
223277
223336
  );
223278
- resolve9({
223337
+ resolve10({
223279
223338
  message: "Remote policy unavailable. Using local policy only."
223280
223339
  });
223281
223340
  });
@@ -225601,6 +225660,15 @@ function hasPaginationEvidence(statement) {
225601
225660
  statement
225602
225661
  );
225603
225662
  }
225663
+ function hasEqualityPredicate(statement, columnPattern) {
225664
+ return new RegExp(
225665
+ `\\bwhere\\b[\\s\\S]*\\b(?:${columnPattern})\\b\\s*=\\s*(?:[\\w$:@?]+|'[^']+'|"[^"]+"|\\d+)`,
225666
+ "iu"
225667
+ ).test(statement);
225668
+ }
225669
+ function isCatalogIdentifierPointLookup(statement) {
225670
+ return /\bfrom\s+information_schema\.schemata\b/iu.test(statement) && hasEqualityPredicate(statement, "schema_name");
225671
+ }
225604
225672
  function isObviousPointLookup(statement) {
225605
225673
  const normalized = statement.toLowerCase();
225606
225674
  if (!normalized.includes("where")) {
@@ -225609,7 +225677,7 @@ function isObviousPointLookup(statement) {
225609
225677
  if (normalized.includes(" or ")) {
225610
225678
  return false;
225611
225679
  }
225612
- return /\bwhere\b[\s\S]*\b([a-z_]*id)\b\s*=\s*([\w$:@?]+|'[^']+'|\d+)/i.test(normalized);
225680
+ return hasEqualityPredicate(normalized, "id|uuid|slug|email|identifier") || isCatalogIdentifierPointLookup(normalized);
225613
225681
  }
225614
225682
  function listModulePathEntries(contract) {
225615
225683
  return Object.entries(contract.modules ?? {}).map(([moduleName, reference]) => {
@@ -226190,13 +226258,14 @@ function detectRepeatedQueryPattern(method) {
226190
226258
  }
226191
226259
  function extractSqlQueryLiterals(content) {
226192
226260
  const queries = [];
226261
+ const searchableContent = maskSourceComments(content);
226193
226262
  const patterns = [
226194
226263
  /(?:\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,
226195
226264
  /\b(?:DB::select|DB::statement|DB::raw|DB::table)\s*\([^'"`)]{0,180}?(['"`])([\s\S]{0,900}?)\1/gu,
226196
226265
  /@Query\s*\(\s*(['"`])([\s\S]{0,900}?)\1/gu
226197
226266
  ];
226198
226267
  for (const pattern of patterns) {
226199
- for (const match of content.matchAll(pattern)) {
226268
+ for (const match of searchableContent.matchAll(pattern)) {
226200
226269
  const sql = match[2];
226201
226270
  if (!sql || !/\b(?:select|update|delete|insert)\b/iu.test(sql)) {
226202
226271
  continue;
@@ -226209,6 +226278,71 @@ function extractSqlQueryLiterals(content) {
226209
226278
  }
226210
226279
  return queries;
226211
226280
  }
226281
+ function maskSourceComments(content) {
226282
+ let masked = "";
226283
+ let index = 0;
226284
+ let state = "code";
226285
+ let escaped = false;
226286
+ while (index < content.length) {
226287
+ const current = content[index] ?? "";
226288
+ const next = content[index + 1] ?? "";
226289
+ if (state === "line-comment") {
226290
+ if (current === "\r" || current === "\n") {
226291
+ masked += current;
226292
+ state = "code";
226293
+ } else {
226294
+ masked += " ";
226295
+ }
226296
+ index += 1;
226297
+ continue;
226298
+ }
226299
+ if (state === "block-comment") {
226300
+ if (current === "*" && next === "/") {
226301
+ masked += " ";
226302
+ index += 2;
226303
+ state = "code";
226304
+ continue;
226305
+ }
226306
+ masked += current === "\r" || current === "\n" ? current : " ";
226307
+ index += 1;
226308
+ continue;
226309
+ }
226310
+ if (state === "single" || state === "double" || state === "template") {
226311
+ masked += current;
226312
+ if (escaped) {
226313
+ escaped = false;
226314
+ } else if (current === "\\") {
226315
+ escaped = true;
226316
+ } else if (state === "single" && current === "'" || state === "double" && current === '"' || state === "template" && current === "`") {
226317
+ state = "code";
226318
+ }
226319
+ index += 1;
226320
+ continue;
226321
+ }
226322
+ if (current === "/" && next === "/") {
226323
+ masked += " ";
226324
+ index += 2;
226325
+ state = "line-comment";
226326
+ continue;
226327
+ }
226328
+ if (current === "/" && next === "*") {
226329
+ masked += " ";
226330
+ index += 2;
226331
+ state = "block-comment";
226332
+ continue;
226333
+ }
226334
+ if (current === "'") {
226335
+ state = "single";
226336
+ } else if (current === '"') {
226337
+ state = "double";
226338
+ } else if (current === "`") {
226339
+ state = "template";
226340
+ }
226341
+ masked += current;
226342
+ index += 1;
226343
+ }
226344
+ return masked;
226345
+ }
226212
226346
  function detectCodeSqlQueryShapeFindings(file, config) {
226213
226347
  const findings = [];
226214
226348
  for (const query of extractSqlQueryLiterals(file.content)) {
@@ -226298,12 +226432,18 @@ function hasAssignedBuilderBoundedTerminal(methodBody, snippet) {
226298
226432
  }
226299
226433
  return new RegExp(`\\b${variableName}\\s*\\.\\s*(?:getOne|getRawOne|loadOne|getCount|getExists)\\s*\\(`, "iu").test(methodBody);
226300
226434
  }
226435
+ function hasIdentifierPredicateEvidence(snippet) {
226436
+ return /\.(?:where|andWhere|orWhere)\s*\(\s*['"`][^'"`]{0,240}\b(?:\w*id|uuid|slug|email|identifier)\b[^'"`]{0,120}(?:=| in\b|IN\b)/iu.test(snippet) || /\bwhere\s*:\s*\{[\s\S]{0,420}\b(?:id|uuid|slug|email|identifier|channelId|orderId|customerId|userId|productId|variantId)\b\s*[:=]/iu.test(snippet);
226437
+ }
226438
+ function hasQueryBuilderTerminalEvidence(snippet, methodBody) {
226439
+ return /\.(?:getMany|getRawMany|loadMany|getOne|getRawOne|loadOne|getCount|getExists|execute)\s*\(/iu.test(snippet) || hasAssignedBuilderBoundedTerminal(methodBody, snippet);
226440
+ }
226301
226441
  function isNonCollectionOrmRead(label, snippet, methodBody = snippet) {
226302
226442
  const terminal = getOrmTerminalOperation(snippet);
226303
226443
  return /\b(?:findOne|findOneOrFail|findOneBy|findOneByOrFail|findUnique|findFirst|count|exists|aggregate)\b/iu.test(label) || !!terminal && /^(?:getOne|getRawOne|loadOne|getCount|getExists|findOne|findOneOrFail|findOneBy|findOneByOrFail|findUnique|findFirst|count|exists|update|delete|remove|save|insert|execute)$/iu.test(terminal) || isScopedRelationLoad(snippet) || hasAssignedBuilderBoundedTerminal(methodBody, snippet);
226304
226444
  }
226305
226445
  function hasOrmBoundEvidence(snippet) {
226306
- return codePaginationEvidencePattern.test(snippet) || /\.(?:take|limit|offset|skip)\s*\(/iu.test(snippet) || /\b(?:maxResults|setMaxResults|firstResult|setFirstResult)\s*\(/iu.test(snippet) || /\b(?:pageSize|perPage|limit|take)\s*[:=]\s*\d+\b/iu.test(snippet);
226446
+ return codePaginationEvidencePattern.test(snippet) || /\.(?:take|limit|offset|skip)\s*\(/iu.test(snippet) || /\b(?:maxResults|setMaxResults|firstResult|setFirstResult)\s*\(/iu.test(snippet) || /\b(?:pageSize|perPage|limit|take)\s*[:=]\s*\d+\b/iu.test(snippet) || hasIdentifierPredicateEvidence(snippet);
226307
226447
  }
226308
226448
  function getOrmQueryTarget(method, label, snippet) {
226309
226449
  const terminal = getOrmTerminalOperation(snippet);
@@ -226326,6 +226466,9 @@ function getOrmQueryLabel(method, label, snippet) {
226326
226466
  function detectOrmQueryShapeFindings(method, config) {
226327
226467
  const findings = [];
226328
226468
  for (const evidence of collectOrmReadEvidence(method)) {
226469
+ if (evidence.label === "node.query" && !hasQueryBuilderTerminalEvidence(evidence.snippet, method.body)) {
226470
+ continue;
226471
+ }
226329
226472
  if (config.tenantModel === "same_db_same_schema" && !tenantPredicatePattern.test(evidence.snippet)) {
226330
226473
  findings.push(createCodeFinding({
226331
226474
  id: "AP-DQR-001",
@@ -227034,7 +227177,7 @@ function detectControllerBusinessLogic(entry, classification, moduleName, contex
227034
227177
  });
227035
227178
  }
227036
227179
  function detectRepositoryBusinessLogic(entry, classification, moduleName) {
227037
- if (!classification.isRepository) {
227180
+ if (!classification.isRepository || !isProductionBackendGovernanceScope(classification.scope)) {
227038
227181
  return void 0;
227039
227182
  }
227040
227183
  if (entry.extension === ".java" && isPureSpringDataRepositoryInterface(entry.content)) {
@@ -227362,7 +227505,7 @@ var publicEvidencePattern = /@Public\b|@PermitAll\b|\[AllowAnonymous\b[^\]]*\]|p
227362
227505
  var roleEvidencePattern = /@(?:Roles|Permissions|RequirePermission|PreAuthorize|Secured|RolesAllowed)\s*(?:\(|\b)([^)\n]*)|\[Authorize\s*\([^)\]]*(?:Roles|Policy)\s*=|(?:requireRole\w*|RequireRole\w*|require_role|RoleChecker|adminMiddleware|can:|permission:|scopes?\s*=|Security\s*\([^)]*scopes)\b/u;
227363
227506
  var tenantSignalPattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|workspaceId|workspace_id|accountId|account_id|companyId|company_id|customerId|customer_id|TenantContext|CurrentTenant|TenantResolver|TenantProvider|request\.tenant|req\.tenant|user\.tenantId|user\.tenant_id|user\.organizationId|user\.organization_id|user\.orgId|user\.accountId|user\.workspaceId|user\.companyId|user\.customerId|HibernateFilter|CurrentTenant)\b/u;
227364
227507
  var tenantPredicateEvidencePattern = /\b(?:tenantId|tenant_id|organizationId|organization_id|orgId|org_id|workspaceId|workspace_id|accountId|account_id|companyId|company_id|customerId|customer_id|TenantContext|CurrentTenant|TenantResolver|TenantProvider|request\.tenant|req\.tenant|user\.tenantId|user\.tenant_id|user\.organizationId|user\.organization_id|user\.orgId|user\.accountId|user\.workspaceId|user\.companyId|user\.customerId|HibernateFilter|CurrentTenant)\b/u;
227365
- var repositoryRolePattern = /\b(?:role|roles|permission|permissions|isAdmin|hasRole|hasPermission|SecurityContextHolder|Authentication|Principal)\b/u;
227508
+ var executableAuthorizationDecisionPattern = /@(?:PreAuthorize|PostAuthorize|Secured|RolesAllowed)\b|\[(?:Authorize)\b[^\]]*(?:Roles|Policy)\s*=|\b(?:hasRole|hasAuthority|hasPermission|isUserInRole|checkPermission|requireRole\w*|RequireRole\w*|require_role|canActivate|authorize|assertAuthorized|PermissionChecker|AccessDecisionManager|SecurityContextHolder\.getContext\(\)\.getAuthentication)\s*\(|\b(?:user|principal|currentUser|account)\.(?:role|roles|permission|permissions|isAdmin)\b\s*(?:[=!]==?|\.includes\s*\(|\.contains\s*\()/u;
227366
227509
  function normalizePath12(value) {
227367
227510
  return value.replace(/\\/g, "/");
227368
227511
  }
@@ -227790,7 +227933,7 @@ function detectAuthorizationFindings(files, contract, astCache) {
227790
227933
  }
227791
227934
  }
227792
227935
  for (const file of files.filter((candidate) => isRepositoryFile(candidate, astCache))) {
227793
- const roleMatch = repositoryRolePattern.exec(file.content);
227936
+ const roleMatch = executableAuthorizationDecisionPattern.exec(file.content);
227794
227937
  if (!roleMatch) {
227795
227938
  continue;
227796
227939
  }
@@ -230589,8 +230732,9 @@ function extractJavaSignals(file) {
230589
230732
  publishes: []
230590
230733
  });
230591
230734
  }
230592
- for (const match of file.content.matchAll(/(?:await\s+)?(?:\w+\.)?(?:publishEvent|publish|emit)\s*\(\s*(?:new\s+)?(["']?)([A-Za-z][\w.]*Event?|[a-z][\w.]+)\1/gu)) {
230593
- const eventName = match[2];
230735
+ 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)) {
230736
+ const constructedType = match[2]?.split(".").at(-1);
230737
+ const eventName = constructedType ?? match[4] ?? match[5];
230594
230738
  if (!eventName) {
230595
230739
  continue;
230596
230740
  }
@@ -234446,7 +234590,7 @@ ${infoLines.join("\n")}
234446
234590
  ## Passed Checks
234447
234591
  ${passedLines.join("\n")}
234448
234592
 
234449
- ## Module Dependency Summary
234593
+ ## Module / Component Contract Dependency Summary
234450
234594
  ${dependencyGraphLines.join("\n")}
234451
234595
 
234452
234596
  ## Disabled Rules
@@ -236682,7 +236826,7 @@ ${appliedFixesSection}
236682
236826
  ## Remaining Violations
236683
236827
  ${remainingViolationsLine}
236684
236828
 
236685
- ## Module Dependency Summary
236829
+ ## Module / Component Contract Dependency Summary
236686
236830
  ${moduleCatalog.length === 0 ? "- Module details are not available in this run." : moduleCatalog.map(
236687
236831
  (entry) => `- ${entry.moduleName} | Role: ${entry.role} | Path: ${entry.path ?? "(not configured)"} | Contract: ${entry.hasContract ? "yes" : "no"} | Declared deps: ${entry.declaredDependencyCount} | Actual deps: ${entry.actualDependencyCount} | Used by: ${entry.inboundDependencyCount}`
236688
236832
  ).join("\n")}
@@ -238934,11 +239078,11 @@ function normalizeAnnotationPath(workspaceRoot, sourceFile) {
238934
239078
  if (!path43.isAbsolute(sourceFile)) {
238935
239079
  return normalized;
238936
239080
  }
238937
- const relative17 = path43.relative(workspaceRoot, sourceFile).replace(/\\/g, "/");
238938
- if (relative17.startsWith("..") || path43.isAbsolute(relative17)) {
239081
+ const relative18 = path43.relative(workspaceRoot, sourceFile).replace(/\\/g, "/");
239082
+ if (relative18.startsWith("..") || path43.isAbsolute(relative18)) {
238939
239083
  return void 0;
238940
239084
  }
238941
- return relative17;
239085
+ return relative18;
238942
239086
  }
238943
239087
  function toAnnotatableFinding(workspaceRoot, finding) {
238944
239088
  if (typeof finding.id !== "string" || !finding.id.startsWith("AP-DEP-")) {
@@ -239122,7 +239266,7 @@ async function emitGithubInlineArchitectureAnnotations(workspaceRoot) {
239122
239266
  var reviewCommentMarker = "<!-- archpilot-pr-review -->";
239123
239267
  var legacyReviewCommentMarker = "<!-- ARCHPILOT_REVIEW_COMMENT -->";
239124
239268
  function requestGithubApi(options) {
239125
- return new Promise((resolve9, reject) => {
239269
+ return new Promise((resolve10, reject) => {
239126
239270
  const payload = options.body !== void 0 ? JSON.stringify(options.body) : void 0;
239127
239271
  const request3 = https2.request(
239128
239272
  {
@@ -239143,7 +239287,7 @@ function requestGithubApi(options) {
239143
239287
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
239144
239288
  });
239145
239289
  response.on("end", () => {
239146
- resolve9({
239290
+ resolve10({
239147
239291
  statusCode: response.statusCode ?? 0,
239148
239292
  body: Buffer.concat(chunks).toString("utf8")
239149
239293
  });
@@ -245420,6 +245564,9 @@ function addEvidence6(evidence, value) {
245420
245564
  evidence.push(value);
245421
245565
  }
245422
245566
  }
245567
+ function hasDeclaredMavenReactorEvidence(candidate) {
245568
+ return candidate.evidence.some((entry) => /Declared (?:by )?Maven|nested Maven reactor/iu.test(entry));
245569
+ }
245423
245570
  function isIgnoredComponentCandidatePath(componentPath) {
245424
245571
  const normalized = normalizePath25(componentPath).replace(/^\.\//u, "");
245425
245572
  if (normalized === "." || normalized.length === 0) {
@@ -245459,7 +245606,9 @@ function isIgnoredComponentCandidatePath(componentPath) {
245459
245606
  "build",
245460
245607
  "coverage"
245461
245608
  ];
245462
- return ignoredRootSegments.includes(firstSegment ?? "") || segments.some((segment) => ignoredSupportingSegments.includes(segment.toLowerCase()));
245609
+ const isExampleContainer = firstSegment === "examples" || firstSegment === "example";
245610
+ const isIgnoredRootSegment = ignoredRootSegments.includes(firstSegment ?? "") && (!isExampleContainer || segments.length === 1);
245611
+ return isIgnoredRootSegment || segments.some((segment) => ignoredSupportingSegments.includes(segment.toLowerCase()));
245463
245612
  }
245464
245613
  function pathExists19(pathValue) {
245465
245614
  try {
@@ -245523,6 +245672,9 @@ function readFirstXmlTag(value, tagName) {
245523
245672
  const match = value.match(new RegExp(`<${tagName}(?:\\s[^>]*)?>([\\s\\S]*?)</${tagName}>`, "iu"));
245524
245673
  return match?.[1]?.trim().replace(/\s+/gu, " ");
245525
245674
  }
245675
+ function readXmlTagValues(value, tagName) {
245676
+ return [...value.matchAll(new RegExp(`<${tagName}(?:\\s[^>]*)?>([\\s\\S]*?)</${tagName}>`, "giu"))].map((match) => match[1]?.trim().replace(/\s+/gu, " ") ?? "").filter((entry) => entry.length > 0);
245677
+ }
245526
245678
  function readMavenMetadata(workspaceRoot, componentPath) {
245527
245679
  if (isUnderJvmResourceRoot4(componentPath)) {
245528
245680
  return void 0;
@@ -245560,6 +245712,95 @@ function readMavenMetadata(workspaceRoot, componentPath) {
245560
245712
  hasTestResources: pathExists19(path64.join(absoluteRoot, "src", "test", "resources"))
245561
245713
  };
245562
245714
  }
245715
+ function workspaceRelativePath(workspaceRoot, absolutePathValue) {
245716
+ const relative18 = path64.relative(workspaceRoot, absolutePathValue);
245717
+ if (relative18.length === 0) {
245718
+ return ".";
245719
+ }
245720
+ if (relative18.startsWith("..") || path64.isAbsolute(relative18)) {
245721
+ return void 0;
245722
+ }
245723
+ return normalizePath25(relative18);
245724
+ }
245725
+ function canonicalRealPath(filePath) {
245726
+ try {
245727
+ return fs58.realpathSync.native(filePath);
245728
+ } catch {
245729
+ return void 0;
245730
+ }
245731
+ }
245732
+ function readMavenDeclaredModules(pomPath) {
245733
+ const pomXml = readTextFileSafe(pomPath);
245734
+ if (!pomXml) {
245735
+ return [];
245736
+ }
245737
+ return uniqueSorted4(
245738
+ readXmlTagValues(stripXmlComments(pomXml), "module").filter((modulePath) => !/[${}]/u.test(modulePath))
245739
+ );
245740
+ }
245741
+ function collectMavenReactorCandidates(workspaceRoot, rootPaths) {
245742
+ const candidates = /* @__PURE__ */ new Map();
245743
+ const visitedPomPaths = /* @__PURE__ */ new Set();
245744
+ const workspaceRealPath = canonicalRealPath(workspaceRoot) ?? path64.resolve(workspaceRoot);
245745
+ const workspaceRealPathForCompare = process.platform === "win32" ? workspaceRealPath.toLowerCase() : workspaceRealPath;
245746
+ const maxVisitedPoms = 500;
245747
+ const addCandidate = (candidatePath, evidence, parentPath) => {
245748
+ const normalized = normalizePath25(candidatePath);
245749
+ const existing = candidates.get(normalized) ?? { path: normalized, evidence: [] };
245750
+ addEvidence6(existing.evidence, evidence);
245751
+ if (parentPath && !existing.parentPath) {
245752
+ existing.parentPath = parentPath;
245753
+ }
245754
+ candidates.set(normalized, existing);
245755
+ };
245756
+ const visitPom = (pomPath, parentPath) => {
245757
+ if (visitedPomPaths.size >= maxVisitedPoms) {
245758
+ return;
245759
+ }
245760
+ const realPomPath = canonicalRealPath(pomPath);
245761
+ if (!realPomPath || visitedPomPaths.has(realPomPath)) {
245762
+ return;
245763
+ }
245764
+ const realPomPathForCompare = process.platform === "win32" ? realPomPath.toLowerCase() : realPomPath;
245765
+ if (realPomPathForCompare !== workspaceRealPathForCompare && !realPomPathForCompare.startsWith(`${workspaceRealPathForCompare}${path64.sep}`)) {
245766
+ return;
245767
+ }
245768
+ visitedPomPaths.add(realPomPath);
245769
+ const pomDirectory = path64.dirname(pomPath);
245770
+ const relativePomDirectory = workspaceRelativePath(workspaceRoot, pomDirectory);
245771
+ if (!relativePomDirectory) {
245772
+ return;
245773
+ }
245774
+ addCandidate(
245775
+ relativePomDirectory,
245776
+ parentPath ? `Declared by Maven reactor parent ${parentPath}` : "Detected Maven reactor root",
245777
+ parentPath
245778
+ );
245779
+ for (const declaredModule of readMavenDeclaredModules(pomPath)) {
245780
+ const childDirectory = path64.resolve(pomDirectory, declaredModule);
245781
+ const childRelativePath = workspaceRelativePath(workspaceRoot, childDirectory);
245782
+ if (!childRelativePath || isUnderJvmResourceRoot4(childRelativePath)) {
245783
+ continue;
245784
+ }
245785
+ const childPom = path64.join(childDirectory, "pom.xml");
245786
+ if (!pathExists19(childPom)) {
245787
+ addCandidate(childRelativePath, `Declared Maven module '${declaredModule}' is missing pom.xml`, relativePomDirectory);
245788
+ continue;
245789
+ }
245790
+ addCandidate(childRelativePath, `Declared Maven module '${declaredModule}' from ${relativePomDirectory}`, relativePomDirectory);
245791
+ visitPom(childPom, relativePomDirectory);
245792
+ }
245793
+ };
245794
+ for (const rootPath of uniqueSorted4(rootPaths)) {
245795
+ const normalizedRoot = normalizePath25(rootPath);
245796
+ const absoluteRoot = normalizedRoot === "." ? workspaceRoot : path64.join(workspaceRoot, ...normalizedRoot.split("/"));
245797
+ const pomPath = path64.join(absoluteRoot, "pom.xml");
245798
+ if (pathExists19(pomPath)) {
245799
+ visitPom(pomPath);
245800
+ }
245801
+ }
245802
+ return [...candidates.values()].sort((left, right) => left.path.localeCompare(right.path));
245803
+ }
245563
245804
  function toComponentRoot(modulePath) {
245564
245805
  const normalized = normalizePath25(modulePath);
245565
245806
  const segments = normalized.split("/").filter((segment) => segment.length > 0);
@@ -245594,6 +245835,18 @@ function buildRootCandidates(input2) {
245594
245835
  for (const root of input2.topology.detectedRoots ?? []) {
245595
245836
  addCandidate(root, `Detected project root ${root}`);
245596
245837
  }
245838
+ if (input2.workspaceRoot) {
245839
+ const mavenRoots = [".", ...input2.topology.detectedRoots ?? []];
245840
+ for (const candidate of collectMavenReactorCandidates(input2.workspaceRoot, mavenRoots)) {
245841
+ addCandidate(
245842
+ candidate.path,
245843
+ candidate.parentPath ? `Detected nested Maven reactor module under ${candidate.parentPath}` : "Detected Maven reactor module"
245844
+ );
245845
+ for (const evidence of candidate.evidence) {
245846
+ addCandidate(candidate.path, evidence);
245847
+ }
245848
+ }
245849
+ }
245597
245850
  for (const moduleEntry of input2.modules?.modules ?? []) {
245598
245851
  const componentRoot = toComponentRoot(moduleEntry.path);
245599
245852
  if (componentRoot) {
@@ -246102,6 +246355,9 @@ function classifyGovernanceRole(input2) {
246102
246355
  const hasMavenDistributionPackagingEvidence = Boolean(
246103
246356
  maven?.packaging === "pom" && !hasMavenMainSource && hasAnyToken(pathText, [/(^|\/)(distribution|dist|downloads|assembl(y|ies)|feature-packs?)(\/|$)/u])
246104
246357
  );
246358
+ const hasMavenStarterPackagingEvidence = Boolean(
246359
+ maven && !hasMavenMainJvmSourceEvidence && hasAnyToken(`${pathText} ${mavenMetadataText}`, [/\bstarters?\b|\bspring-boot-starter\b|\bstarter[-\s]/u])
246360
+ );
246105
246361
  if (input2.candidate.architectureRoot?.classification === "backend_app" || input2.candidate.architectureRoot?.classification === "frontend_app") {
246106
246362
  runtimeScore += 3;
246107
246363
  addEvidence6(evidence, `Runtime architecture root signal: ${input2.candidate.architectureRoot.classification}`);
@@ -246211,6 +246467,10 @@ function classifyGovernanceRole(input2) {
246211
246467
  supportScore += 1;
246212
246468
  addEvidence6(evidence, "Maven POM-only aggregator/packaging module");
246213
246469
  }
246470
+ if (hasMavenStarterPackagingEvidence) {
246471
+ supportScore += 4;
246472
+ addEvidence6(evidence, "Maven starter/resource artifact without JVM runtime source");
246473
+ }
246214
246474
  if (isPlainResourcesSurface) {
246215
246475
  supportScore += 4;
246216
246476
  addEvidence6(evidence, "Resources-only surface without runtime source or manifest evidence");
@@ -246222,6 +246482,13 @@ function classifyGovernanceRole(input2) {
246222
246482
  selectedByDefault: false
246223
246483
  };
246224
246484
  }
246485
+ if (hasMavenStarterPackagingEvidence && !hasMavenMainJvmSourceEvidence) {
246486
+ return {
246487
+ governanceRole: "support",
246488
+ governanceEvidence: uniqueSorted4(evidence),
246489
+ selectedByDefault: false
246490
+ };
246491
+ }
246225
246492
  if (hasMavenDistributionPackagingEvidence && hasAnyToken(mavenMetadataText, [/\b(docs?|documentation|metadata tests?|licenses?|maven plugins?|builds?)\b/u])) {
246226
246493
  supportScore += 3;
246227
246494
  addEvidence6(evidence, "Maven documentation/build/distribution packaging evidence without runtime source");
@@ -246281,7 +246548,7 @@ function detectComponents(input2) {
246281
246548
  const manifestBackedRoots = new Set(
246282
246549
  (input2.topology.detectedRoots ?? []).filter((root) => !isUnderJvmResourceRoot4(root))
246283
246550
  );
246284
- const rootCandidates = buildRootCandidates(input2).filter((candidate) => !ignoreMatcher.isIgnored(candidate.path)).filter((candidate) => !isIgnoredComponentCandidatePath(candidate.path)).filter((candidate) => !(isUnderJvmResourceRoot4(candidate.path) && !hasRuntimeSourceFiles(input2.workspaceRoot, candidate.path))).filter((candidate) => {
246551
+ const rootCandidates = buildRootCandidates({ ...input2, workspaceRoot: input2.workspaceRoot }).filter((candidate) => !ignoreMatcher.isIgnored(candidate.path) || hasDeclaredMavenReactorEvidence(candidate)).filter((candidate) => !isIgnoredComponentCandidatePath(candidate.path)).filter((candidate) => !(isUnderJvmResourceRoot4(candidate.path) && !hasRuntimeSourceFiles(input2.workspaceRoot, candidate.path))).filter((candidate) => {
246285
246552
  if (input2.topology.topology !== "monorepo" || manifestBackedRoots.size === 0) {
246286
246553
  return true;
246287
246554
  }
@@ -246579,7 +246846,7 @@ function isCliSupportCandidate(component, allComponents) {
246579
246846
  }
246580
246847
  function hasIndependentRuntimeEvidence(component) {
246581
246848
  const text = componentEvidenceText(component);
246582
- return component.governanceRole === "runtime" && (/Maven executable application evidence/iu.test(text) || /Maven deployable WAR artifact/iu.test(text) || /Published package surface signal/iu.test(text) && !/Path contains support\/tooling role tokens/iu.test(text));
246849
+ return component.governanceRole === "runtime" && (/Maven executable application evidence/iu.test(text) || /Maven deployable WAR artifact/iu.test(text) || /Maven library main source\/resource surface/iu.test(text) || /Maven Spring Boot auto-configuration\/starter library evidence/iu.test(text) || /Published package surface signal/iu.test(text) && !/Path contains support\/tooling role tokens/iu.test(text));
246583
246850
  }
246584
246851
  function hasSupportRoleEvidence(component) {
246585
246852
  const text = componentEvidenceText(component);
@@ -246789,7 +247056,20 @@ function hasAttributableBackendRoot(detection) {
246789
247056
  return getBackendComponents(detection).length > 0;
246790
247057
  }
246791
247058
  function isGenericLibraryStack(stack) {
246792
- return stack === "node_typescript" || stack === "node_javascript" || stack === "python" || stack === "go" || stack === "kotlin" || stack === "terraform" || stack === "ansible";
247059
+ return stack === "node_typescript" || stack === "node_javascript" || stack === "library_generic" || stack === "java" || stack === "spring" || stack === "python" || stack === "go" || stack === "kotlin" || stack === "kotlin_spring" || stack === "terraform" || stack === "ansible";
247060
+ }
247061
+ function preferredLibraryStack(stacks) {
247062
+ const uniqueStacks = uniqueInOrder2(stacks);
247063
+ if (uniqueStacks.length <= 1) {
247064
+ return isJvmLibraryStack(uniqueStacks[0]) ? "library_generic" : uniqueStacks[0];
247065
+ }
247066
+ if (uniqueStacks.some(isJvmLibraryStack) && uniqueStacks.every((candidate) => isJvmLibraryStack(candidate) || candidate === "node_typescript" || candidate === "node_javascript")) {
247067
+ return "library_generic";
247068
+ }
247069
+ return void 0;
247070
+ }
247071
+ function isJvmLibraryStack(stack) {
247072
+ return stack === "java" || stack === "spring";
246793
247073
  }
246794
247074
  function hasProjectKindEvidence(detection, patterns) {
246795
247075
  const evidence = detection.projectKinds?.evidence ?? [];
@@ -247211,7 +247491,7 @@ function resolveStackSelections(detection, projectKinds) {
247211
247491
  const libraryComponentStacks = uniqueInOrder2(
247212
247492
  libraryComponents.map((component) => component.stack).filter((stack) => isGenericLibraryStack(stack))
247213
247493
  );
247214
- const selectedLibrary = detection.topology.topology === "monorepo" ? libraryComponentStacks.length === 1 ? libraryComponentStacks[0] : void 0 : detection.stacks.selectedAdapterId;
247494
+ const selectedLibrary = detection.topology.topology === "monorepo" ? preferredLibraryStack(libraryComponentStacks) : detection.stacks.selectedAdapterId;
247215
247495
  if (isGenericLibraryStack(selectedLibrary)) {
247216
247496
  selections.library = selectedLibrary;
247217
247497
  }
@@ -247233,7 +247513,7 @@ function resolveProjectProfiles(detection, projectKinds, stackSelections, apiSty
247233
247513
  selectedAdapterId: stackId,
247234
247514
  selectedAdapterCategory: getStackAdapterById(stackId).category,
247235
247515
  projectKinds: [kind],
247236
- apiStyleHint: kind === "backend" && apiStyle ? apiStyle : resolveRoleApiStyleHint(detection, stackId, component),
247516
+ apiStyleHint: kind === "backend" && apiStyle ? apiStyle : stackId === "library_generic" ? void 0 : resolveRoleApiStyleHint(detection, stackId, component),
247237
247517
  databaseHints: detection.toolingHints?.databaseHints,
247238
247518
  toolingHints: detection.toolingHints?.toolingHints,
247239
247519
  repoTopology: detection.topology.topology === "unknown" ? "single_project" : detection.topology.topology