@archpilotlabs/archpilot 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/archpilot-cli.js +823 -70
  2. package/package.json +1 -1
@@ -213475,7 +213475,264 @@ async function listModuleDirectoryNames(workspaceRoot, modulesRootRelativePath =
213475
213475
  const entries = await import_node_fs.promises.readdir(modulesRoot, { withFileTypes: true });
213476
213476
  return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort((left, right) => left.localeCompare(right));
213477
213477
  }
213478
+ var ignoredModuleDirectoryNames = /* @__PURE__ */ new Set([
213479
+ ".git",
213480
+ ".archpilot",
213481
+ ".vscode",
213482
+ ".vscode-test",
213483
+ "node_modules",
213484
+ "dist",
213485
+ "build",
213486
+ "out",
213487
+ "coverage",
213488
+ ".next",
213489
+ "generated",
213490
+ "target",
213491
+ "vendor",
213492
+ ".venv",
213493
+ "venv",
213494
+ "__pycache__"
213495
+ ]);
213496
+ var noisyModuleDirectoryNames = /* @__PURE__ */ new Set([
213497
+ "components",
213498
+ "hooks",
213499
+ "utils",
213500
+ "util",
213501
+ "lib",
213502
+ "common",
213503
+ "shared",
213504
+ "shared-ui",
213505
+ "types",
213506
+ "constants",
213507
+ "config",
213508
+ "test",
213509
+ "tests",
213510
+ "__tests__",
213511
+ "fixtures",
213512
+ "mocks",
213513
+ "__mocks__",
213514
+ "generated",
213515
+ "dist",
213516
+ "build",
213517
+ "out",
213518
+ "node_modules"
213519
+ ]);
213520
+ var sourceFileExtensions = /* @__PURE__ */ new Set([
213521
+ ".ts",
213522
+ ".tsx",
213523
+ ".js",
213524
+ ".jsx",
213525
+ ".vue",
213526
+ ".java",
213527
+ ".py",
213528
+ ".php",
213529
+ ".go",
213530
+ ".cs",
213531
+ ".rb",
213532
+ ".kt",
213533
+ ".swift",
213534
+ ".rs"
213535
+ ]);
213536
+ var publicEntrypointNames = /* @__PURE__ */ new Set([
213537
+ "index.ts",
213538
+ "index.tsx",
213539
+ "index.js",
213540
+ "index.jsx",
213541
+ "index.vue",
213542
+ "__init__.py",
213543
+ "main.go",
213544
+ "mod.ts",
213545
+ "mod.js"
213546
+ ]);
213547
+ function isIgnoredDirectoryName(directoryName) {
213548
+ return ignoredModuleDirectoryNames.has(directoryName.toLowerCase());
213549
+ }
213550
+ function isNoisyModuleName(moduleName) {
213551
+ return noisyModuleDirectoryNames.has(moduleName.toLowerCase());
213552
+ }
213553
+ function toPathSegments(relativePath) {
213554
+ return normalizePath(relativePath).split("/").filter((segment) => segment.length > 0);
213555
+ }
213556
+ function toModuleIdFromPath(relativePath, fallbackRoot) {
213557
+ const segments = toPathSegments(relativePath);
213558
+ const lowerSegments = segments.map((segment) => segment.toLowerCase());
213559
+ const sourceIndex = lowerSegments.lastIndexOf("src");
213560
+ if (sourceIndex >= 0 && sourceIndex + 2 < segments.length) {
213561
+ const parent = segments[sourceIndex - 1];
213562
+ const container = lowerSegments[sourceIndex + 1];
213563
+ if (["modules", "features"].includes(container)) {
213564
+ return [parent, segments[sourceIndex + 2]].filter(Boolean).join("/");
213565
+ }
213566
+ if (["domain", "domains", "application", "infrastructure"].includes(container)) {
213567
+ return [segments[sourceIndex + 1], segments[sourceIndex + 2]].join("/");
213568
+ }
213569
+ return [parent, segments[sourceIndex + 1]].filter(Boolean).join("/");
213570
+ }
213571
+ if (sourceIndex >= 0 && sourceIndex + 1 < segments.length) {
213572
+ const parent = segments[sourceIndex - 1];
213573
+ return [parent, segments[sourceIndex + 1]].filter(Boolean).join("/");
213574
+ }
213575
+ if (segments[0] === "src" && segments.length >= 3) {
213576
+ return `${segments[1]}/${segments[2]}`;
213577
+ }
213578
+ if (fallbackRoot) {
213579
+ const rootSegments = toPathSegments(fallbackRoot);
213580
+ const relativeSegments = segments.slice(rootSegments.length);
213581
+ if (relativeSegments.length > 0) {
213582
+ return relativeSegments.join("/");
213583
+ }
213584
+ }
213585
+ return segments.slice(-1)[0] ?? relativePath;
213586
+ }
213587
+ function isKnownNestedModuleRoot(relativePath) {
213588
+ const segments = toPathSegments(relativePath).map((segment) => segment.toLowerCase());
213589
+ if (segments.length < 2) {
213590
+ return false;
213591
+ }
213592
+ const lastParent = segments[segments.length - 2];
213593
+ if (["modules", "features", "domain", "domains", "application", "infrastructure"].includes(lastParent)) {
213594
+ return true;
213595
+ }
213596
+ if (segments.length >= 3 && segments[segments.length - 3] === "src") {
213597
+ return true;
213598
+ }
213599
+ return false;
213600
+ }
213601
+ async function inspectPotentialModuleRoot(absolutePath) {
213602
+ let sourceFileCount = 0;
213603
+ let hasPublicEntrypoint = false;
213604
+ const queue = [{ absolutePath, depth: 0 }];
213605
+ while (queue.length > 0) {
213606
+ const current = queue.shift();
213607
+ if (!current) {
213608
+ continue;
213609
+ }
213610
+ let entries;
213611
+ try {
213612
+ entries = await import_node_fs.promises.readdir(current.absolutePath, { withFileTypes: true });
213613
+ } catch {
213614
+ continue;
213615
+ }
213616
+ for (const entry of entries) {
213617
+ const entryPath = path.join(current.absolutePath, entry.name);
213618
+ if (entry.isDirectory()) {
213619
+ if (current.depth >= 2 || isIgnoredDirectoryName(entry.name)) {
213620
+ continue;
213621
+ }
213622
+ queue.push({ absolutePath: entryPath, depth: current.depth + 1 });
213623
+ continue;
213624
+ }
213625
+ if (!entry.isFile()) {
213626
+ continue;
213627
+ }
213628
+ if (sourceFileExtensions.has(path.extname(entry.name).toLowerCase())) {
213629
+ sourceFileCount += 1;
213630
+ }
213631
+ if (current.depth === 0 && publicEntrypointNames.has(entry.name.toLowerCase())) {
213632
+ hasPublicEntrypoint = true;
213633
+ }
213634
+ }
213635
+ }
213636
+ return { sourceFileCount, hasPublicEntrypoint };
213637
+ }
213638
+ async function addModuleIfStrongCandidate(workspaceRoot, discovered, sourcePath, moduleId, options) {
213639
+ const normalizedSourcePath = normalizePath(sourcePath);
213640
+ const name = normalizedSourcePath.split("/").pop() ?? moduleId;
213641
+ if (options?.allowNoisyNames !== true && isNoisyModuleName(name)) {
213642
+ return;
213643
+ }
213644
+ const absolutePath = path.join(workspaceRoot, ...normalizedSourcePath.split("/"));
213645
+ const inspected = await inspectPotentialModuleRoot(absolutePath);
213646
+ const hasStrongEvidence = inspected.sourceFileCount >= 2 || inspected.hasPublicEntrypoint || isKnownNestedModuleRoot(normalizedSourcePath);
213647
+ if (options?.requireStrongEvidence !== false && !hasStrongEvidence) {
213648
+ return;
213649
+ }
213650
+ const normalizedModuleId = normalizePath(moduleId || toModuleIdFromPath(normalizedSourcePath, options?.fallbackRoot));
213651
+ if (!normalizedModuleId || options?.allowNoisyNames !== true && isNoisyModuleName(normalizedModuleId.split("/").pop() ?? normalizedModuleId)) {
213652
+ return;
213653
+ }
213654
+ if (!discovered.has(normalizedModuleId)) {
213655
+ discovered.set(normalizedModuleId, {
213656
+ moduleId: normalizedModuleId,
213657
+ sourcePath: normalizedSourcePath
213658
+ });
213659
+ }
213660
+ }
213661
+ async function addChildrenFromRoot(workspaceRoot, discovered, rootRelativePath, options) {
213662
+ const normalizedRoot = normalizePath(rootRelativePath);
213663
+ const absoluteRoot = path.join(workspaceRoot, ...normalizedRoot.split("/"));
213664
+ if (!await pathExists(absoluteRoot)) {
213665
+ return;
213666
+ }
213667
+ const entries = (await import_node_fs.promises.readdir(absoluteRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && !isIgnoredDirectoryName(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
213668
+ for (const entry of entries) {
213669
+ const sourcePath = `${normalizedRoot}/${entry.name}`;
213670
+ const moduleId = options?.includeParentPrefix && options.parentId ? `${options.parentId}/${entry.name}` : toModuleIdFromPath(sourcePath, normalizedRoot);
213671
+ await addModuleIfStrongCandidate(workspaceRoot, discovered, sourcePath, moduleId, {
213672
+ fallbackRoot: normalizedRoot,
213673
+ ...options?.requireStrongEvidence !== void 0 ? { requireStrongEvidence: options.requireStrongEvidence } : {},
213674
+ ...options?.allowNoisyNames !== void 0 ? { allowNoisyNames: options.allowNoisyNames } : {}
213675
+ });
213676
+ }
213677
+ }
213678
+ async function addMonorepoContainerModules(workspaceRoot, discovered, container) {
213679
+ const absoluteContainer = path.join(workspaceRoot, container);
213680
+ if (!await pathExists(absoluteContainer)) {
213681
+ return;
213682
+ }
213683
+ const entries = (await import_node_fs.promises.readdir(absoluteContainer, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && !isIgnoredDirectoryName(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
213684
+ for (const entry of entries) {
213685
+ const packagePath = `${container}/${entry.name}`;
213686
+ await addModuleIfStrongCandidate(workspaceRoot, discovered, packagePath, entry.name, {
213687
+ requireStrongEvidence: false
213688
+ });
213689
+ for (const sourceRoot of [
213690
+ `${packagePath}/src`,
213691
+ `${packagePath}/src/modules`,
213692
+ `${packagePath}/src/features`,
213693
+ `${packagePath}/src/domain`,
213694
+ `${packagePath}/src/domains`,
213695
+ `${packagePath}/src/application`,
213696
+ `${packagePath}/src/infrastructure`
213697
+ ]) {
213698
+ await addChildrenFromRoot(workspaceRoot, discovered, sourceRoot, {
213699
+ parentId: entry.name,
213700
+ includeParentPrefix: true
213701
+ });
213702
+ }
213703
+ }
213704
+ }
213705
+ async function discoverHierarchicalModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules") {
213706
+ const discovered = /* @__PURE__ */ new Map();
213707
+ await addChildrenFromRoot(workspaceRoot, discovered, normalizePath(modulesRootRelativePath), {
213708
+ requireStrongEvidence: false,
213709
+ allowNoisyNames: normalizePath(modulesRootRelativePath) === "src"
213710
+ });
213711
+ for (const root of [
213712
+ "src/modules",
213713
+ "src/features",
213714
+ "src/domain",
213715
+ "src/domains",
213716
+ "src/application",
213717
+ "src/infrastructure"
213718
+ ]) {
213719
+ await addChildrenFromRoot(workspaceRoot, discovered, root);
213720
+ }
213721
+ for (const container of ["packages", "apps", "services"]) {
213722
+ await addMonorepoContainerModules(workspaceRoot, discovered, container);
213723
+ }
213724
+ return [...discovered.values()].sort((left, right) => left.moduleId.localeCompare(right.moduleId));
213725
+ }
213478
213726
  async function discoverModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules") {
213727
+ const hierarchicalModules = await discoverHierarchicalModuleRoots(workspaceRoot, modulesRootRelativePath);
213728
+ if (hierarchicalModules.length > 0) {
213729
+ return new Map(
213730
+ hierarchicalModules.map((entry) => [
213731
+ entry.moduleId,
213732
+ path.join(workspaceRoot, ...entry.sourcePath.split("/"))
213733
+ ])
213734
+ );
213735
+ }
213479
213736
  const moduleDirectories = await listModuleDirectoryNames(workspaceRoot, modulesRootRelativePath);
213480
213737
  const modulesRoot = path.join(workspaceRoot, ...modulesRootRelativePath.split("/"));
213481
213738
  return new Map(
@@ -214854,7 +215111,8 @@ function buildArchitectureContract(base, overrides) {
214854
215111
  }
214855
215112
  function buildDefaultModuleContractPath(moduleName, contract) {
214856
215113
  const contractsRoot = resolveContractsRootFromContract(contract);
214857
- return `${contractsRoot}/${moduleName}.contract.json`;
215114
+ const safeModuleName = moduleName.replace(/\\/g, "/").split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
215115
+ return `${contractsRoot}/${safeModuleName}.contract.json`;
214858
215116
  }
214859
215117
  async function loadArchitectureContract(workspaceRoot) {
214860
215118
  const configPath = path7.join(workspaceRoot, ".archpilot", "architecture.json");
@@ -214985,8 +215243,63 @@ var DependencyRulesConfigError = class extends Error {
214985
215243
  function normalizePath2(filePath) {
214986
215244
  return filePath.replace(/\\/g, "/");
214987
215245
  }
214988
- function getModulesRoot(workspaceRoot, modulesRootRelativePath = "src/modules") {
214989
- return path8.join(workspaceRoot, ...modulesRootRelativePath.split("/"));
215246
+ function toSafeContractModuleFileStem(moduleName) {
215247
+ return normalizePath2(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
215248
+ }
215249
+ function normalizeAbsolutePath(filePath) {
215250
+ return normalizePath2(path8.resolve(filePath)).toLowerCase();
215251
+ }
215252
+ function isPathInsideOrEqual(childPath, parentPath) {
215253
+ const child = normalizeAbsolutePath(childPath);
215254
+ const parent = normalizeAbsolutePath(parentPath);
215255
+ return child === parent || child.startsWith(`${parent}/`);
215256
+ }
215257
+ function isParentChildModuleRelationship(leftModule, rightModule) {
215258
+ if (leftModule === rightModule) {
215259
+ return false;
215260
+ }
215261
+ return leftModule.startsWith(`${rightModule}/`) || rightModule.startsWith(`${leftModule}/`);
215262
+ }
215263
+ function isPeerModuleImport(dependencyImport) {
215264
+ return !isParentChildModuleRelationship(
215265
+ dependencyImport.sourceModule,
215266
+ dependencyImport.targetModule
215267
+ );
215268
+ }
215269
+ function filterPeerModuleImports(imports) {
215270
+ return imports.filter(isPeerModuleImport);
215271
+ }
215272
+ function buildModuleHierarchyEdges(moduleIds) {
215273
+ const moduleIdSet = new Set(moduleIds);
215274
+ const edges = [];
215275
+ for (const moduleId of moduleIds) {
215276
+ const parentModule = moduleId.split("/").slice(0, -1).map((_, index, segments) => segments.slice(0, segments.length - index).join("/")).find((candidate) => moduleIdSet.has(candidate));
215277
+ if (!parentModule) {
215278
+ continue;
215279
+ }
215280
+ edges.push({ parentModule, childModule: moduleId });
215281
+ }
215282
+ return edges.sort((left, right) => {
215283
+ const parentCompare = left.parentModule.localeCompare(right.parentModule);
215284
+ if (parentCompare !== 0) {
215285
+ return parentCompare;
215286
+ }
215287
+ return left.childModule.localeCompare(right.childModule);
215288
+ });
215289
+ }
215290
+ function buildChildModulesByParent(hierarchyEdges) {
215291
+ const byParent = /* @__PURE__ */ new Map();
215292
+ for (const edge of hierarchyEdges) {
215293
+ const children = byParent.get(edge.parentModule) ?? /* @__PURE__ */ new Set();
215294
+ children.add(edge.childModule);
215295
+ byParent.set(edge.parentModule, children);
215296
+ }
215297
+ return new Map(
215298
+ [...byParent.entries()].map(([parentModule, childModules]) => [
215299
+ parentModule,
215300
+ sortUnique2(childModules)
215301
+ ])
215302
+ );
214990
215303
  }
214991
215304
  function getScriptKind(filePath) {
214992
215305
  const extension = path8.extname(filePath).toLowerCase();
@@ -215027,6 +215340,37 @@ async function readTextFileIfExists2(filePath) {
215027
215340
  return void 0;
215028
215341
  }
215029
215342
  }
215343
+ async function readPackageName(packageJsonPath) {
215344
+ const contents = await readTextFileIfExists2(packageJsonPath);
215345
+ if (!contents) {
215346
+ return void 0;
215347
+ }
215348
+ try {
215349
+ const parsed = JSON.parse(contents);
215350
+ return typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : void 0;
215351
+ } catch {
215352
+ return void 0;
215353
+ }
215354
+ }
215355
+ async function buildWorkspacePackageAliasMap(moduleRoots) {
215356
+ const aliases = [];
215357
+ for (const [moduleId, moduleRoot] of [...moduleRoots.entries()].sort(
215358
+ ([left], [right]) => left.localeCompare(right)
215359
+ )) {
215360
+ const packageName = await readPackageName(path8.join(moduleRoot, "package.json"));
215361
+ if (!packageName) {
215362
+ continue;
215363
+ }
215364
+ aliases.push({ packageName, moduleId, moduleRoot });
215365
+ }
215366
+ return aliases.sort((left, right) => {
215367
+ const lengthCompare = right.packageName.length - left.packageName.length;
215368
+ if (lengthCompare !== 0) {
215369
+ return lengthCompare;
215370
+ }
215371
+ return left.packageName.localeCompare(right.packageName);
215372
+ });
215373
+ }
215030
215374
  function validateDependencyModuleRules(moduleName, value) {
215031
215375
  if (!value || typeof value !== "object" || Array.isArray(value)) {
215032
215376
  throw new DependencyRulesConfigError(
@@ -215500,7 +215844,32 @@ async function resolveImportPath(basePath, adapter) {
215500
215844
  }
215501
215845
  return void 0;
215502
215846
  }
215503
- async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, sourceFilePath, importSpecifier, adapter) {
215847
+ function resolvePackageAliasRemainder(packageName, importSpecifier) {
215848
+ if (importSpecifier === packageName) {
215849
+ return "";
215850
+ }
215851
+ if (importSpecifier.startsWith(`${packageName}/`)) {
215852
+ return importSpecifier.slice(packageName.length + 1);
215853
+ }
215854
+ return void 0;
215855
+ }
215856
+ async function resolveWorkspacePackageImportPath(importSpecifier, workspacePackageAliases, adapter) {
215857
+ const packageAlias = workspacePackageAliases.map((alias2) => ({
215858
+ alias: alias2,
215859
+ remainder: resolvePackageAliasRemainder(alias2.packageName, importSpecifier)
215860
+ })).find(
215861
+ (candidate) => candidate.remainder !== void 0
215862
+ );
215863
+ if (!packageAlias) {
215864
+ return void 0;
215865
+ }
215866
+ const { alias, remainder } = packageAlias;
215867
+ if (remainder.length === 0) {
215868
+ return resolveImportPath(alias.moduleRoot, adapter);
215869
+ }
215870
+ return void 0;
215871
+ }
215872
+ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, workspacePackageAliases, sourceFilePath, importSpecifier, adapter) {
215504
215873
  let basePath;
215505
215874
  const normalizedModulesRoot = normalizePath2(modulesRootRelativePath).replace(/^\/+/, "");
215506
215875
  if (usesJavaImportParser(adapter) && !importSpecifier.startsWith(".")) {
@@ -215555,6 +215924,22 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
215555
215924
  basePath = path8.join(workspaceRoot, importSpecifier.slice(1));
215556
215925
  } else if (normalizedModulesRoot.startsWith("src/") && importSpecifier.startsWith(`${normalizedModulesRoot.slice("src/".length)}/`)) {
215557
215926
  basePath = path8.join(workspaceRoot, "src", importSpecifier);
215927
+ } else {
215928
+ const workspacePackageImportPath = await resolveWorkspacePackageImportPath(
215929
+ importSpecifier,
215930
+ workspacePackageAliases,
215931
+ adapter
215932
+ );
215933
+ if (workspacePackageImportPath) {
215934
+ basePath = workspacePackageImportPath;
215935
+ } else {
215936
+ const moduleImportTarget = [...moduleRoots.entries()].filter(([moduleId]) => importSpecifier === moduleId || importSpecifier.startsWith(`${moduleId}/`)).sort((left, right) => right[0].length - left[0].length || left[0].localeCompare(right[0]))[0];
215937
+ if (moduleImportTarget) {
215938
+ const [moduleId, moduleRoot] = moduleImportTarget;
215939
+ const remainder = importSpecifier === moduleId ? "" : importSpecifier.slice(moduleId.length + 1);
215940
+ basePath = path8.join(moduleRoot, ...remainder.split("/").filter((segment) => segment.length > 0));
215941
+ }
215942
+ }
215558
215943
  }
215559
215944
  if (!basePath) {
215560
215945
  return void 0;
@@ -215563,17 +215948,8 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
215563
215948
  if (!resolvedPath) {
215564
215949
  return void 0;
215565
215950
  }
215566
- const modulesRoot = getModulesRoot(workspaceRoot, modulesRootRelativePath);
215567
- const relativeToModulesRoot = normalizePath2(path8.relative(modulesRoot, resolvedPath));
215568
- if (relativeToModulesRoot === "" || relativeToModulesRoot.startsWith("../") || relativeToModulesRoot.startsWith("..\\")) {
215569
- return void 0;
215570
- }
215571
- const segments = relativeToModulesRoot.split("/");
215572
- if (segments.length === 0) {
215573
- return void 0;
215574
- }
215575
- const targetModule = segments[0];
215576
- if (!moduleRoots.has(targetModule)) {
215951
+ const targetModuleEntry = [...moduleRoots.entries()].filter(([, moduleRoot]) => isPathInsideOrEqual(resolvedPath, moduleRoot)).sort((left, right) => right[1].length - left[1].length || left[0].localeCompare(right[0]))[0];
215952
+ if (!targetModuleEntry) {
215577
215953
  const standaloneTargetModule = explicitStandaloneModuleByPath.get(
215578
215954
  normalizePath2(path8.relative(workspaceRoot, resolvedPath))
215579
215955
  );
@@ -215586,7 +215962,11 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
215586
215962
  isPublicImport: true
215587
215963
  };
215588
215964
  }
215589
- const targetSubPath = segments.slice(1).join("/");
215965
+ const [targetModule, targetModuleRoot] = targetModuleEntry;
215966
+ const targetSubPath = normalizePath2(path8.relative(targetModuleRoot, resolvedPath));
215967
+ if (targetSubPath === "" || targetSubPath.startsWith("../") || targetSubPath.startsWith("..\\")) {
215968
+ return void 0;
215969
+ }
215590
215970
  const indexEntrypointCandidates = adapter.dependencyParsingFileExtensions.map(
215591
215971
  (extension) => `index${extension}`
215592
215972
  );
@@ -215599,7 +215979,7 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
215599
215979
  isPublicImport
215600
215980
  };
215601
215981
  }
215602
- async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, adapter, options) {
215982
+ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, workspacePackageAliases, adapter, options) {
215603
215983
  const imports = [];
215604
215984
  const includeTestFiles = options?.includeTestFiles === true;
215605
215985
  if (!supportsDependencyImportParsing(adapter)) {
@@ -215608,7 +215988,10 @@ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath,
215608
215988
  for (const [moduleName, moduleRoot] of [...moduleRoots.entries()].sort(
215609
215989
  ([left], [right]) => left.localeCompare(right)
215610
215990
  )) {
215611
- const sourceFiles = await collectSourceFiles(moduleRoot, adapter);
215991
+ const childModuleRoots = [...moduleRoots.entries()].filter(([childModuleName, childModuleRoot]) => childModuleName !== moduleName && isPathInsideOrEqual(childModuleRoot, moduleRoot)).map(([, childModuleRoot]) => childModuleRoot);
215992
+ const sourceFiles = (await collectSourceFiles(moduleRoot, adapter)).filter(
215993
+ (sourceFile) => !childModuleRoots.some((childModuleRoot) => isPathInsideOrEqual(sourceFile, childModuleRoot))
215994
+ );
215612
215995
  for (const sourceFilePath of sourceFiles) {
215613
215996
  const sourceFileRelativePath = normalizePath2(
215614
215997
  path8.relative(workspaceRoot, sourceFilePath)
@@ -215631,6 +216014,7 @@ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath,
215631
216014
  modulesRootRelativePath,
215632
216015
  moduleRoots,
215633
216016
  explicitStandaloneModuleByPath,
216017
+ workspacePackageAliases,
215634
216018
  sourceFilePath,
215635
216019
  importReference.specifier,
215636
216020
  adapter
@@ -215776,7 +216160,7 @@ async function loadModuleArchitectureContract(workspaceRoot, architectureContrac
215776
216160
  const registryEntry = architectureContract.modules[moduleName];
215777
216161
  const contractPath = registryEntry?.contract ?? path8.posix.join(
215778
216162
  resolveContractsRootFromContract(architectureContract),
215779
- `${moduleName}.contract.json`
216163
+ `${toSafeContractModuleFileStem(moduleName)}.contract.json`
215780
216164
  );
215781
216165
  const fullContractPath = path8.join(workspaceRoot, ...contractPath.split("/"));
215782
216166
  const content = await readTextFileIfExists2(fullContractPath);
@@ -215923,6 +216307,7 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215923
216307
  workspaceRoot,
215924
216308
  architectureContract
215925
216309
  );
216310
+ const workspacePackageAliases = await buildWorkspacePackageAliasMap(moduleRoots);
215926
216311
  const moduleIds = sortUnique2([...moduleRoots.keys(), ...explicitStandaloneModuleByPath.values()]);
215927
216312
  const registeredModuleIds = new Set(moduleIds);
215928
216313
  const imports = await collectCrossModuleImports(
@@ -215930,9 +216315,11 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215930
216315
  modulesRoot,
215931
216316
  moduleRoots,
215932
216317
  explicitStandaloneModuleByPath,
216318
+ workspacePackageAliases,
215933
216319
  adapter
215934
216320
  );
215935
- const actualBySource = buildActualImportedModuleSetBySource(imports, registeredModuleIds);
216321
+ const peerImports = filterPeerModuleImports(imports);
216322
+ const actualBySource = buildActualImportedModuleSetBySource(peerImports, registeredModuleIds);
215936
216323
  const moduleContractCache = /* @__PURE__ */ new Map();
215937
216324
  const declaredBySource = /* @__PURE__ */ new Map();
215938
216325
  const hasContractByModule = /* @__PURE__ */ new Map();
@@ -215950,7 +216337,7 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215950
216337
  new Set(
215951
216338
  sortUnique2(
215952
216339
  sourceContract.contract.dependsOn.filter(
215953
- (dependencyModule) => registeredModuleIds.has(dependencyModule)
216340
+ (dependencyModule) => registeredModuleIds.has(dependencyModule) && !isParentChildModuleRelationship(moduleId, dependencyModule)
215954
216341
  )
215955
216342
  )
215956
216343
  )
@@ -215962,6 +216349,11 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215962
216349
  }
215963
216350
  const inboundDeclared = buildInboundDependencyMap(declaredBySource, moduleIds);
215964
216351
  const inboundActual = buildInboundDependencyMap(actualBySource, moduleIds);
216352
+ const hierarchyEdges = buildModuleHierarchyEdges(moduleIds);
216353
+ const childModulesByParent = buildChildModulesByParent(hierarchyEdges);
216354
+ const parentModuleByChild = new Map(
216355
+ hierarchyEdges.map((edge) => [edge.childModule, edge.parentModule])
216356
+ );
215965
216357
  return {
215966
216358
  modules: moduleIds.map((moduleId) => {
215967
216359
  const declaredDependencies = sortUnique2(declaredBySource.get(moduleId) ?? []);
@@ -215975,6 +216367,8 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215975
216367
  return {
215976
216368
  module: moduleId,
215977
216369
  hasContract: hasContractByModule.get(moduleId) ?? false,
216370
+ ...parentModuleByChild.has(moduleId) ? { parentModule: parentModuleByChild.get(moduleId) } : {},
216371
+ childModules: childModulesByParent.get(moduleId) ?? [],
215978
216372
  declaredDependencies,
215979
216373
  actualDependencies,
215980
216374
  inboundDeclaredFrom: inboundDeclared.get(moduleId) ?? [],
@@ -215982,7 +216376,8 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
215982
216376
  unusedDeclaredDependencies,
215983
216377
  undeclaredActualDependencies
215984
216378
  };
215985
- })
216379
+ }),
216380
+ hierarchyEdges
215986
216381
  };
215987
216382
  }
215988
216383
  async function validateDependencyContractBoundaries(workspaceRoot, architectureContract, options) {
@@ -215996,19 +216391,22 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
215996
216391
  workspaceRoot,
215997
216392
  architectureContract
215998
216393
  );
216394
+ const workspacePackageAliases = await buildWorkspacePackageAliasMap(moduleRoots);
215999
216395
  const imports = await collectCrossModuleImports(
216000
216396
  workspaceRoot,
216001
216397
  modulesRoot,
216002
216398
  moduleRoots,
216003
216399
  explicitStandaloneModuleByPath,
216400
+ workspacePackageAliases,
216004
216401
  adapter
216005
216402
  );
216403
+ const peerImports = filterPeerModuleImports(imports);
216006
216404
  const findings = [];
216007
216405
  const moduleContractCache = /* @__PURE__ */ new Map();
216008
216406
  if (options.checkDeclaredDependencies) {
216009
216407
  const failures = [];
216010
216408
  const skippedFindings = /* @__PURE__ */ new Map();
216011
- for (const dependencyImport of imports) {
216409
+ for (const dependencyImport of peerImports) {
216012
216410
  const sourceContract = await loadModuleArchitectureContract(
216013
216411
  workspaceRoot,
216014
216412
  architectureContract,
@@ -216080,7 +216478,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216080
216478
  }
216081
216479
  if (failures.length > 0) {
216082
216480
  findings.push(...failures);
216083
- } else if (imports.length === 0) {
216481
+ } else if (peerImports.length === 0) {
216084
216482
  findings.push({
216085
216483
  result: makeValidationResult(
216086
216484
  "AP-DEP-004",
@@ -216105,7 +216503,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216105
216503
  if (options.checkPublicSurfaceImports) {
216106
216504
  const failures = [];
216107
216505
  const skippedFindings = /* @__PURE__ */ new Map();
216108
- for (const dependencyImport of imports) {
216506
+ for (const dependencyImport of peerImports) {
216109
216507
  const sourceContract = await loadModuleArchitectureContract(
216110
216508
  workspaceRoot,
216111
216509
  architectureContract,
@@ -216172,17 +216570,18 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216172
216570
  }
216173
216571
  continue;
216174
216572
  }
216175
- if (targetContract.contract.publicEntrypoints.length > 0 && normalizePath2(dependencyImport.resolvedTargetRelativePath) !== buildModuleIndexEntrypointPath(
216176
- modulesRoot,
216177
- dependencyImport.targetModule,
216178
- adapter
216573
+ if (targetContract.contract.publicEntrypoints.length > 0 && !isImportWithinPublicEntrypoints(
216574
+ dependencyImport.resolvedTargetRelativePath,
216575
+ targetContract.contract.publicEntrypoints
216179
216576
  )) {
216577
+ const expectedEntrypoint = targetContract.contract.publicEntrypoints[0] ?? buildModuleIndexEntrypointPath(modulesRoot, dependencyImport.targetModule, adapter);
216578
+ const publicEntrypointLabel = expectedEntrypoint.endsWith("/index.ts") ? "index.ts public entrypoint" : "public entrypoint";
216180
216579
  failures.push({
216181
216580
  result: makeValidationResult(
216182
216581
  "AP-DEP-005",
216183
216582
  "error",
216184
216583
  false,
216185
- `Module '${dependencyImport.sourceModule}' must import module '${dependencyImport.targetModule}' via its index.ts public entrypoint: ${buildModuleIndexEntrypointPath(modulesRoot, dependencyImport.targetModule, adapter)}.`,
216584
+ `Module '${dependencyImport.sourceModule}' must import module '${dependencyImport.targetModule}' via its ${publicEntrypointLabel}: ${expectedEntrypoint}.`,
216186
216585
  {
216187
216586
  findingType: "module-dependency",
216188
216587
  module: dependencyImport.sourceModule,
@@ -216223,7 +216622,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216223
216622
  }
216224
216623
  if (failures.length > 0) {
216225
216624
  findings.push(...failures);
216226
- } else if (imports.length === 0) {
216625
+ } else if (peerImports.length === 0) {
216227
216626
  findings.push({
216228
216627
  result: makeValidationResult(
216229
216628
  "AP-DEP-005",
@@ -216252,7 +216651,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216252
216651
  ...explicitStandaloneModuleByPath.values()
216253
216652
  ]);
216254
216653
  const importedBySource = buildActualImportedModuleSetBySource(
216255
- imports,
216654
+ peerImports,
216256
216655
  registeredModuleIds
216257
216656
  );
216258
216657
  for (const moduleName of [...registeredModuleIds].sort(
@@ -216267,7 +216666,9 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
216267
216666
  if (sourceContract.status !== "ok" || !sourceContract.contract) {
216268
216667
  continue;
216269
216668
  }
216270
- const declaredDependencies = [...sourceContract.contract.dependsOn].filter((dependencyModule) => registeredModuleIds.has(dependencyModule)).sort((left, right) => left.localeCompare(right));
216669
+ const declaredDependencies = [...sourceContract.contract.dependsOn].filter(
216670
+ (dependencyModule) => registeredModuleIds.has(dependencyModule) && !isParentChildModuleRelationship(moduleName, dependencyModule)
216671
+ ).sort((left, right) => left.localeCompare(right));
216271
216672
  if (declaredDependencies.length === 0) {
216272
216673
  continue;
216273
216674
  }
@@ -216322,13 +216723,16 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
216322
216723
  workspaceRoot,
216323
216724
  parsedArchitectureContract
216324
216725
  );
216726
+ const workspacePackageAliases = await buildWorkspacePackageAliasMap(moduleRoots);
216325
216727
  const imports = await collectCrossModuleImports(
216326
216728
  workspaceRoot,
216327
216729
  modulesRootRelativePath,
216328
216730
  moduleRoots,
216329
216731
  explicitStandaloneModuleByPath,
216732
+ workspacePackageAliases,
216330
216733
  adapter
216331
216734
  );
216735
+ const peerImports = filterPeerModuleImports(imports);
216332
216736
  const findings = [];
216333
216737
  let dependencyRules;
216334
216738
  let dependencyRulesSkipReason;
@@ -216349,7 +216753,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
216349
216753
  }
216350
216754
  }
216351
216755
  if (options.checkCircularDependencies) {
216352
- const cycles = detectCircularDependencies([...moduleRoots.keys()], imports);
216756
+ const cycles = detectCircularDependencies([...moduleRoots.keys()], peerImports);
216353
216757
  if (cycles.length === 0) {
216354
216758
  findings.push({
216355
216759
  result: makeValidationResult(
@@ -216381,7 +216785,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
216381
216785
  })
216382
216786
  );
216383
216787
  } else {
216384
- const violations = imports.filter((dependencyImport) => {
216788
+ const violations = peerImports.filter((dependencyImport) => {
216385
216789
  const moduleRules = dependencyRules.modules[dependencyImport.sourceModule];
216386
216790
  if (!moduleRules) {
216387
216791
  return false;
@@ -216433,7 +216837,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
216433
216837
  })
216434
216838
  );
216435
216839
  } else {
216436
- const violations = imports.filter((dependencyImport) => {
216840
+ const violations = peerImports.filter((dependencyImport) => {
216437
216841
  const moduleRules = dependencyRules.modules[dependencyImport.sourceModule];
216438
216842
  return moduleRules?.publicEntrypointsOnly === true && !dependencyImport.isPublicImport;
216439
216843
  });
@@ -216481,6 +216885,7 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
216481
216885
  workspaceRoot,
216482
216886
  parsedArchitectureContract
216483
216887
  );
216888
+ const workspacePackageAliases = await buildWorkspacePackageAliasMap(moduleRoots);
216484
216889
  const discoveredModules = sortUnique2([
216485
216890
  ...moduleRoots.keys(),
216486
216891
  ...explicitStandaloneModuleByPath.values()
@@ -216493,9 +216898,10 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
216493
216898
  modulesRootRelativePath,
216494
216899
  moduleRoots,
216495
216900
  explicitStandaloneModuleByPath,
216901
+ workspacePackageAliases,
216496
216902
  adapter
216497
216903
  );
216498
- const imports = allImports.filter(
216904
+ const imports = filterPeerModuleImports(allImports).filter(
216499
216905
  (dependencyImport) => moduleSet.has(dependencyImport.sourceModule) && moduleSet.has(dependencyImport.targetModule)
216500
216906
  ).sort((left, right) => {
216501
216907
  const sourceCompare = left.sourceModule.localeCompare(right.sourceModule);
@@ -216548,6 +216954,7 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
216548
216954
  return {
216549
216955
  modules,
216550
216956
  edges,
216957
+ hierarchyEdges: buildModuleHierarchyEdges(modules),
216551
216958
  cycles,
216552
216959
  imports
216553
216960
  };
@@ -219949,11 +220356,11 @@ src/
219949
220356
  },
219950
220357
  DEP_ISOLATED_MODULE_DETECTED: {
219951
220358
  id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
219952
- title: "Isolated module detected",
220359
+ title: "Potential orphan module detected",
219953
220360
  category: "dependency",
219954
220361
  defaultSeverity: "warning",
219955
- description: "Checks whether a registered module has no declared or actual inbound/outbound module dependencies.",
219956
- recommendedFix: "Connect the module to the architecture through legitimate dependencies, or remove it if it is unused."
220362
+ description: "Checks whether a registered module has no peer-module dependencies and little evidence of intentional architectural use.",
220363
+ recommendedFix: "Add intentional-use evidence such as a contract, README, public entrypoint, package entrypoint, or remove the module if it is stale."
219957
220364
  },
219958
220365
  DEP_TRANSITIVE_CIRCULAR_MODULE_DEPENDENCY: {
219959
220366
  id: ValidationRuleIds.DEP_TRANSITIVE_CIRCULAR_MODULE_DEPENDENCY,
@@ -221172,8 +221579,17 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
221172
221579
  const modulesRootRelativePath2 = await getConfiguredModulesRoot(workspaceRoot, contract);
221173
221580
  const modulesRoot = path21.join(workspaceRoot, ...modulesRootRelativePath2.split("/"));
221174
221581
  if (await pathExists7(modulesRoot)) {
221175
- const moduleEntries = await import_node_fs20.promises.readdir(modulesRoot, { withFileTypes: true });
221176
- const moduleDirectories2 = moduleEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => left.localeCompare(right));
221582
+ const hierarchicalModules = await discoverHierarchicalModuleRoots(
221583
+ workspaceRoot,
221584
+ modulesRootRelativePath2
221585
+ );
221586
+ const moduleDirectories2 = hierarchicalModules.length > 0 ? hierarchicalModules.map((entry) => ({
221587
+ moduleName: entry.moduleId,
221588
+ sourcePath: entry.sourcePath
221589
+ })) : (await import_node_fs20.promises.readdir(modulesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => ({
221590
+ moduleName: entry.name,
221591
+ sourcePath: `${modulesRootRelativePath2}/${entry.name}`
221592
+ })).sort((left, right) => left.moduleName.localeCompare(right.moduleName));
221177
221593
  const dependencySummary = await buildDependencyGraphSummary(workspaceRoot, contract, {
221178
221594
  modulesRootRelativePath: modulesRootRelativePath2
221179
221595
  });
@@ -221181,8 +221597,9 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
221181
221597
  dependencySummary.modules.filter((moduleSummary) => moduleSummary.inboundDeclaredFrom.length > 0).map((moduleSummary) => moduleSummary.module)
221182
221598
  );
221183
221599
  const incompleteModules = [];
221184
- for (const moduleName of moduleDirectories2) {
221185
- const moduleDir = path21.join(modulesRoot, moduleName);
221600
+ for (const moduleDirectory of moduleDirectories2) {
221601
+ const moduleName = moduleDirectory.moduleName;
221602
+ const moduleDir = path21.join(workspaceRoot, ...moduleDirectory.sourcePath.split("/"));
221186
221603
  const readmeExists = await pathExists7(path21.join(moduleDir, "README.md"));
221187
221604
  const indexExists = await pathExists7(path21.join(moduleDir, "index.ts"));
221188
221605
  const registryPublicEntrypoints = (contract.modules[moduleName]?.publicEntrypoints ?? []).filter((entry) => typeof entry === "string").map((entry) => normalizeEntrypoint(entry));
@@ -221311,18 +221728,111 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
221311
221728
  return [];
221312
221729
  }
221313
221730
  const isolatedResults = [];
221314
- const isolationExemptInfrastructureModules = /* @__PURE__ */ new Set(["ci", "policy", "validation"]);
221731
+ const sourceFileExtensions4 = /* @__PURE__ */ new Set([
221732
+ ".ts",
221733
+ ".tsx",
221734
+ ".js",
221735
+ ".jsx",
221736
+ ".mjs",
221737
+ ".cjs",
221738
+ ".mts",
221739
+ ".cts",
221740
+ ".py",
221741
+ ".go",
221742
+ ".java",
221743
+ ".kt",
221744
+ ".kts",
221745
+ ".cs",
221746
+ ".php",
221747
+ ".rb",
221748
+ ".vue",
221749
+ ".svelte"
221750
+ ]);
221315
221751
  const isTestLikeModule = (moduleName) => {
221316
221752
  const normalized = moduleName.toLowerCase();
221317
221753
  return normalized === "test" || normalized === "tests" || normalized.endsWith("-test") || normalized.endsWith("-tests");
221318
221754
  };
221755
+ const collectModuleSourceEvidence2 = async (directoryPath) => {
221756
+ let entries;
221757
+ try {
221758
+ entries = await import_node_fs20.promises.readdir(directoryPath, { withFileTypes: true });
221759
+ } catch {
221760
+ return { sourceFileCount: 0, hasReadme: false, hasEntrypointFile: false };
221761
+ }
221762
+ let sourceFileCount = 0;
221763
+ let hasReadme = false;
221764
+ let hasEntrypointFile = false;
221765
+ for (const entry of entries) {
221766
+ const fullPath = path21.join(directoryPath, entry.name);
221767
+ if (entry.isDirectory()) {
221768
+ if (["node_modules", "dist", "out", "build", "coverage", ".git"].includes(entry.name)) {
221769
+ continue;
221770
+ }
221771
+ const nested = await collectModuleSourceEvidence2(fullPath);
221772
+ sourceFileCount += nested.sourceFileCount;
221773
+ hasReadme ||= nested.hasReadme;
221774
+ hasEntrypointFile ||= nested.hasEntrypointFile;
221775
+ continue;
221776
+ }
221777
+ if (!entry.isFile()) {
221778
+ continue;
221779
+ }
221780
+ const lowerName = entry.name.toLowerCase();
221781
+ if (lowerName === "readme.md" || lowerName === "readme.mdx") {
221782
+ hasReadme = true;
221783
+ }
221784
+ if (/^(index|main|app|extension|cli)\.[cm]?[jt]sx?$/iu.test(entry.name)) {
221785
+ hasEntrypointFile = true;
221786
+ }
221787
+ if (sourceFileExtensions4.has(path21.extname(entry.name).toLowerCase())) {
221788
+ sourceFileCount += 1;
221789
+ }
221790
+ }
221791
+ return { sourceFileCount, hasReadme, hasEntrypointFile };
221792
+ };
221793
+ const readPackageJsonIfExists2 = async (moduleDirectoryPath) => {
221794
+ const content = await readTextFileIfExists3(path21.join(moduleDirectoryPath, "package.json"));
221795
+ if (!content) {
221796
+ return void 0;
221797
+ }
221798
+ try {
221799
+ const parsed = JSON.parse(content);
221800
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
221801
+ } catch {
221802
+ return void 0;
221803
+ }
221804
+ };
221805
+ const hasPackageEntrypoint2 = async (moduleDirectoryPath) => {
221806
+ const packageJson = await readPackageJsonIfExists2(moduleDirectoryPath);
221807
+ if (!packageJson) {
221808
+ return false;
221809
+ }
221810
+ return ["main", "module", "browser", "types", "bin", "exports"].some(
221811
+ (field) => packageJson[field] !== void 0
221812
+ );
221813
+ };
221814
+ const hasKnownBoundaryRole2 = (moduleName) => {
221815
+ const normalized = moduleName.toLowerCase();
221816
+ const compact = normalized.replace(/[-_/]/gu, "");
221817
+ const segments = normalized.split(/[/-]/u);
221818
+ return ["adr", "ci", "compliance", "config", "governance", "policy", "validation", "smartinit"].some(
221819
+ (role) => compact.includes(role) || segments.includes(role)
221820
+ );
221821
+ };
221822
+ const hasConfiguredPublicEntrypoint2 = (moduleName) => {
221823
+ const publicEntrypoints = contract.modules[moduleName]?.publicEntrypoints;
221824
+ return Array.isArray(publicEntrypoints) && publicEntrypoints.some(
221825
+ (entry) => typeof entry === "string" && entry.trim().length > 0
221826
+ );
221827
+ };
221828
+ const hasIntentionalIndependentEvidence2 = async (moduleSummary, moduleDirectoryPath) => {
221829
+ const sourceEvidence = await collectModuleSourceEvidence2(moduleDirectoryPath);
221830
+ return moduleSummary.hasContract || hasConfiguredPublicEntrypoint2(moduleSummary.module) || sourceEvidence.hasReadme || sourceEvidence.hasEntrypointFile || await hasPackageEntrypoint2(moduleDirectoryPath) || moduleSummary.childModules.length > 0 || moduleSummary.parentModule !== void 0 && moduleSummary.childModules.length === 0 && sourceEvidence.sourceFileCount > 0 || hasKnownBoundaryRole2(moduleSummary.module) || sourceEvidence.sourceFileCount >= 2;
221831
+ };
221319
221832
  for (const moduleSummary of dependencyGraphSummary.modules) {
221320
221833
  if (isTestLikeModule(moduleSummary.module)) {
221321
221834
  continue;
221322
221835
  }
221323
- if (isolationExemptInfrastructureModules.has(moduleSummary.module.toLowerCase())) {
221324
- continue;
221325
- }
221326
221836
  const registryEntry = contract.modules[moduleSummary.module];
221327
221837
  if (!registryEntry?.path) {
221328
221838
  continue;
@@ -221336,11 +221846,14 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
221336
221846
  if (!isIsolated) {
221337
221847
  continue;
221338
221848
  }
221849
+ if (await hasIntentionalIndependentEvidence2(moduleSummary, moduleDirectoryPath)) {
221850
+ continue;
221851
+ }
221339
221852
  isolatedResults.push({
221340
221853
  id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
221341
221854
  severity: "warning",
221342
221855
  passed: false,
221343
- message: `Module '${moduleSummary.module}' is isolated: it has no declared or actual inbound/outbound module dependencies.`,
221856
+ message: `Module '${moduleSummary.module}' is a potential orphan: it has no declared or actual inbound/outbound module dependencies and little evidence of intentional architectural use.`,
221344
221857
  findingType: "module-dependency",
221345
221858
  module: moduleSummary.module
221346
221859
  });
@@ -221353,7 +221866,7 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
221353
221866
  id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
221354
221867
  severity: "warning",
221355
221868
  passed: true,
221356
- message: "No isolated modules detected among registered modules with existing registry paths."
221869
+ message: "No potential orphan modules detected among registered modules with existing registry paths."
221357
221870
  }
221358
221871
  ];
221359
221872
  }
@@ -222135,7 +222648,10 @@ function filterDependencyGraphSummaryByModuleScope(dependencyGraphSummary, modul
222135
222648
  )
222136
222649
  }));
222137
222650
  return {
222138
- modules: scopedModules
222651
+ modules: scopedModules,
222652
+ hierarchyEdges: dependencyGraphSummary.hierarchyEdges.filter(
222653
+ (edge) => scopeSet.has(edge.parentModule) && scopeSet.has(edge.childModule)
222654
+ )
222139
222655
  };
222140
222656
  }
222141
222657
  async function runArchitectureValidationForWorkspace(workspaceRoot, options) {
@@ -225136,9 +225652,32 @@ async function readTextFileIfExists4(filePath) {
225136
225652
  return void 0;
225137
225653
  }
225138
225654
  }
225655
+ var sourceFileExtensions2 = /* @__PURE__ */ new Set([
225656
+ ".ts",
225657
+ ".tsx",
225658
+ ".js",
225659
+ ".jsx",
225660
+ ".mjs",
225661
+ ".cjs",
225662
+ ".mts",
225663
+ ".cts",
225664
+ ".py",
225665
+ ".go",
225666
+ ".java",
225667
+ ".kt",
225668
+ ".kts",
225669
+ ".cs",
225670
+ ".php",
225671
+ ".rb",
225672
+ ".vue",
225673
+ ".svelte"
225674
+ ]);
225139
225675
  function sortUnique3(values) {
225140
225676
  return [...new Set(values)].sort((left, right) => left.localeCompare(right));
225141
225677
  }
225678
+ function toSafeContractModuleFileStem2(moduleName) {
225679
+ return normalizePath5(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
225680
+ }
225142
225681
  function getModuleRegistry(contract) {
225143
225682
  const modules = contract?.modules;
225144
225683
  if (!modules || typeof modules !== "object" || Array.isArray(modules)) {
@@ -225149,6 +225688,83 @@ function getModuleRegistry(contract) {
225149
225688
  function normalizePublicEntrypointList(entries) {
225150
225689
  return sortUnique3(entries.map((entry) => normalizePath5(entry.trim())).filter((entry) => entry.length > 0));
225151
225690
  }
225691
+ function hasConfiguredPublicEntrypoint(registryEntry) {
225692
+ return Array.isArray(registryEntry?.publicEntrypoints) && registryEntry.publicEntrypoints.some(
225693
+ (entry) => typeof entry === "string" && entry.trim().length > 0
225694
+ );
225695
+ }
225696
+ async function readPackageJsonIfExists(moduleDirectoryPath) {
225697
+ const content = await readTextFileIfExists4(path26.join(moduleDirectoryPath, "package.json"));
225698
+ if (!content) {
225699
+ return void 0;
225700
+ }
225701
+ try {
225702
+ const parsed = JSON.parse(content);
225703
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
225704
+ } catch {
225705
+ return void 0;
225706
+ }
225707
+ }
225708
+ async function collectModuleSourceEvidence(directoryPath) {
225709
+ let entries;
225710
+ try {
225711
+ entries = await import_node_fs24.promises.readdir(directoryPath, { withFileTypes: true });
225712
+ } catch {
225713
+ return { sourceFileCount: 0, hasReadme: false, hasEntrypointFile: false };
225714
+ }
225715
+ let sourceFileCount = 0;
225716
+ let hasReadme = false;
225717
+ let hasEntrypointFile = false;
225718
+ for (const entry of entries) {
225719
+ const fullPath = path26.join(directoryPath, entry.name);
225720
+ if (entry.isDirectory()) {
225721
+ if (["node_modules", "dist", "out", "build", "coverage", ".git"].includes(entry.name)) {
225722
+ continue;
225723
+ }
225724
+ const nested = await collectModuleSourceEvidence(fullPath);
225725
+ sourceFileCount += nested.sourceFileCount;
225726
+ hasReadme ||= nested.hasReadme;
225727
+ hasEntrypointFile ||= nested.hasEntrypointFile;
225728
+ continue;
225729
+ }
225730
+ if (!entry.isFile()) {
225731
+ continue;
225732
+ }
225733
+ const lowerName = entry.name.toLowerCase();
225734
+ if (lowerName === "readme.md" || lowerName === "readme.mdx") {
225735
+ hasReadme = true;
225736
+ }
225737
+ if (/^(index|main|app|extension|cli)\.[cm]?[jt]sx?$/iu.test(entry.name)) {
225738
+ hasEntrypointFile = true;
225739
+ }
225740
+ if (sourceFileExtensions2.has(path26.extname(entry.name).toLowerCase())) {
225741
+ sourceFileCount += 1;
225742
+ }
225743
+ }
225744
+ return { sourceFileCount, hasReadme, hasEntrypointFile };
225745
+ }
225746
+ function hasKnownBoundaryRole(moduleName) {
225747
+ const normalized = moduleName.toLowerCase();
225748
+ const compact = normalized.replace(/[-_/]/gu, "");
225749
+ const segments = normalized.split(/[/-]/u);
225750
+ return ["adr", "ci", "compliance", "config", "governance", "policy", "validation", "smartinit"].some(
225751
+ (role) => compact.includes(role) || segments.includes(role)
225752
+ );
225753
+ }
225754
+ async function hasPackageEntrypoint(moduleDirectoryPath) {
225755
+ const packageJson = await readPackageJsonIfExists(moduleDirectoryPath);
225756
+ if (!packageJson) {
225757
+ return false;
225758
+ }
225759
+ return ["main", "module", "browser", "types", "bin", "exports"].some(
225760
+ (field) => packageJson[field] !== void 0
225761
+ );
225762
+ }
225763
+ async function hasIntentionalIndependentEvidence(args) {
225764
+ const moduleDirectoryPath = path26.join(args.workspaceRoot, ...args.moduleEntry.sourcePath.split("/"));
225765
+ const evidence = await collectModuleSourceEvidence(moduleDirectoryPath);
225766
+ return args.moduleEntry.contractExists || args.moduleEntry.hasPublicEntrypoint === true || evidence.hasReadme || evidence.hasEntrypointFile || await hasPackageEntrypoint(moduleDirectoryPath) || args.hasChildren || args.isLeafChild && evidence.sourceFileCount > 0 || hasKnownBoundaryRole(args.moduleEntry.moduleName) || evidence.sourceFileCount >= 2;
225767
+ }
225152
225768
  async function loadModuleContractPublicEntrypoints(workspaceRoot, contractPath) {
225153
225769
  const fullContractPath = path26.join(workspaceRoot, ...contractPath.split("/"));
225154
225770
  const content = await readTextFileIfExists4(fullContractPath);
@@ -225189,7 +225805,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
225189
225805
  const discovered = [];
225190
225806
  const discoveredNames = /* @__PURE__ */ new Set();
225191
225807
  const toContractPath = (moduleName, registryEntry) => normalizePath5(
225192
- typeof registryEntry?.contract === "string" ? registryEntry.contract : `${contractsRoot}/${moduleName}.contract.json`
225808
+ typeof registryEntry?.contract === "string" ? registryEntry.contract : `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`
225193
225809
  );
225194
225810
  const resolveMissingPublicEntrypointAlignment = async (registryEntry, contractPath) => {
225195
225811
  if (!Array.isArray(registryEntry?.publicEntrypoints)) {
@@ -225233,7 +225849,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
225233
225849
  continue;
225234
225850
  }
225235
225851
  const contractPath = normalizePath5(
225236
- typeof registryEntry.contract === "string" ? registryEntry.contract : `${contractsRoot}/${moduleName}.contract.json`
225852
+ typeof registryEntry.contract === "string" ? registryEntry.contract : `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`
225237
225853
  );
225238
225854
  const contractExists = await pathExists10(path26.join(workspaceRoot, ...contractPath.split("/")));
225239
225855
  const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(
@@ -225248,6 +225864,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
225248
225864
  ...resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract) } : {},
225249
225865
  contractPath,
225250
225866
  contractExists,
225867
+ hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
225251
225868
  ...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
225252
225869
  });
225253
225870
  discoveredNames.add(moduleName);
@@ -225272,18 +225889,56 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
225272
225889
  ...resolveModuleScopeForPath(workspaceRoot, sourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, sourcePath, contract) } : {},
225273
225890
  contractPath,
225274
225891
  contractExists,
225892
+ hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
225275
225893
  ...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
225276
225894
  });
225277
225895
  discoveredNames.add(moduleName);
225278
225896
  }
225897
+ for (const moduleRoot of await discoverHierarchicalModuleRoots(workspaceRoot, normalizedModulesRoot)) {
225898
+ if (discoveredNames.has(moduleRoot.moduleId)) {
225899
+ continue;
225900
+ }
225901
+ const registryEntry = moduleRegistry[moduleRoot.moduleId];
225902
+ const contractPath = toContractPath(moduleRoot.moduleId, registryEntry);
225903
+ const contractExists = await pathExists10(path26.join(workspaceRoot, ...contractPath.split("/")));
225904
+ const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(
225905
+ registryEntry,
225906
+ contractPath
225907
+ );
225908
+ discovered.push({
225909
+ moduleName: moduleRoot.moduleId,
225910
+ sourcePath: moduleRoot.sourcePath,
225911
+ discoverySource: "architecture.json",
225912
+ sourcePathExists: true,
225913
+ ...resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath, contract) } : {},
225914
+ contractPath,
225915
+ contractExists,
225916
+ hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
225917
+ ...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
225918
+ });
225919
+ discoveredNames.add(moduleRoot.moduleId);
225920
+ }
225279
225921
  return discovered.sort((left, right) => left.moduleName.localeCompare(right.moduleName));
225280
225922
  }
225281
225923
  async function discoverModulesFromFallbackScan(workspaceRoot, modulesRoot = "src/modules", contractsRoot = ".archpilot/contracts") {
225282
- const moduleNames = await listModuleDirectoryNames(workspaceRoot, modulesRoot);
225924
+ const hierarchicalModules = await discoverHierarchicalModuleRoots(workspaceRoot, modulesRoot);
225925
+ const moduleNames = hierarchicalModules.length > 0 ? [] : await listModuleDirectoryNames(workspaceRoot, modulesRoot);
225283
225926
  const discovered = [];
225927
+ for (const moduleRoot of hierarchicalModules) {
225928
+ const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem2(moduleRoot.moduleId)}.contract.json`;
225929
+ discovered.push({
225930
+ moduleName: moduleRoot.moduleId,
225931
+ sourcePath: moduleRoot.sourcePath,
225932
+ discoverySource: "inferred-scan",
225933
+ sourcePathExists: true,
225934
+ ...resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath) ? { scope: resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath) } : {},
225935
+ contractPath,
225936
+ contractExists: await pathExists10(path26.join(workspaceRoot, ...contractPath.split("/")))
225937
+ });
225938
+ }
225284
225939
  for (const moduleName of moduleNames) {
225285
225940
  const sourcePath = `${modulesRoot}/${moduleName}`;
225286
- const contractPath = `${contractsRoot}/${moduleName}.contract.json`;
225941
+ const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`;
225287
225942
  discovered.push({
225288
225943
  moduleName,
225289
225944
  sourcePath,
@@ -225381,14 +226036,39 @@ async function generateArchitectureMap(workspaceRoot, options) {
225381
226036
  moduleFilter: moduleIds
225382
226037
  });
225383
226038
  const edges = dependencySnapshot.edges.map((edge) => toArchitectureMapEdge(edge));
226039
+ const hierarchyEdges = dependencySnapshot.hierarchyEdges;
225384
226040
  const parsedCycles = dependencySnapshot.cycles.map((cycle) => parseCycleString(cycle)).filter((cycle) => cycle.length > 1).sort((left, right) => left.join("->").localeCompare(right.join("->")));
225385
226041
  const incomingMap = buildIncomingMap(modules, edges);
225386
226042
  const outgoingMap = buildOutgoingMap(modules, edges);
225387
226043
  const cycleMembership = new Set(parsedCycles.flatMap((cycle) => cycle));
225388
- const hotspotSummary = modules.map((moduleEntry) => {
226044
+ const hierarchyParentByChild = new Map(
226045
+ hierarchyEdges.map((edge) => [edge.childModule, edge.parentModule])
226046
+ );
226047
+ const childModulesByParent = /* @__PURE__ */ new Map();
226048
+ for (const edge of hierarchyEdges) {
226049
+ const children = childModulesByParent.get(edge.parentModule) ?? [];
226050
+ children.push(edge.childModule);
226051
+ childModulesByParent.set(edge.parentModule, children);
226052
+ }
226053
+ const independentModuleNames = [];
226054
+ const potentialOrphanModuleNames = [];
226055
+ const hotspotSummary = await Promise.all(modules.map(async (moduleEntry) => {
225389
226056
  const incomingDependencyCount = incomingMap.get(moduleEntry.moduleName)?.length ?? 0;
225390
226057
  const outgoingDependencyCount = outgoingMap.get(moduleEntry.moduleName)?.length ?? 0;
225391
- const orphan = incomingDependencyCount === 0 && outgoingDependencyCount === 0;
226058
+ const hasNoPeerUsage = incomingDependencyCount === 0 && outgoingDependencyCount === 0;
226059
+ const hasIntentionalEvidence = hasNoPeerUsage ? await hasIntentionalIndependentEvidence({
226060
+ workspaceRoot,
226061
+ moduleEntry,
226062
+ hasChildren: (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) > 0,
226063
+ isLeafChild: hierarchyParentByChild.has(moduleEntry.moduleName) && (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) === 0
226064
+ }) : false;
226065
+ const orphan = hasNoPeerUsage && !hasIntentionalEvidence;
226066
+ if (hasNoPeerUsage && hasIntentionalEvidence) {
226067
+ independentModuleNames.push(moduleEntry.moduleName);
226068
+ }
226069
+ if (orphan) {
226070
+ potentialOrphanModuleNames.push(moduleEntry.moduleName);
226071
+ }
225392
226072
  return {
225393
226073
  moduleName: moduleEntry.moduleName,
225394
226074
  incomingDependencyCount,
@@ -225400,7 +226080,7 @@ async function generateArchitectureMap(workspaceRoot, options) {
225400
226080
  missingPublicEntrypointAlignment: moduleEntry.missingPublicEntrypointAlignment
225401
226081
  } : {}
225402
226082
  };
225403
- });
226083
+ }));
225404
226084
  const mostDependedOnModules = sortRankedCounts(
225405
226085
  hotspotSummary.filter((entry) => entry.incomingDependencyCount > 0).map((entry) => ({
225406
226086
  moduleName: entry.moduleName,
@@ -225416,9 +226096,9 @@ async function generateArchitectureMap(workspaceRoot, options) {
225416
226096
  const modulesInCircularDependencies = sortUnique3(
225417
226097
  hotspotSummary.filter((entry) => entry.participatesInCycle).map((entry) => entry.moduleName)
225418
226098
  );
225419
- const orphanModules = sortUnique3(
225420
- hotspotSummary.filter((entry) => entry.orphan).map((entry) => entry.moduleName)
225421
- );
226099
+ const independentModules = sortUnique3(independentModuleNames);
226100
+ const potentialOrphanModules = sortUnique3(potentialOrphanModuleNames);
226101
+ const orphanModules = potentialOrphanModules;
225422
226102
  const missingContracts = sortUnique3(
225423
226103
  hotspotSummary.filter((entry) => entry.missingContract).map((entry) => entry.moduleName)
225424
226104
  );
@@ -225441,11 +226121,14 @@ async function generateArchitectureMap(workspaceRoot, options) {
225441
226121
  modules,
225442
226122
  moduleHotspotSummary: hotspotSummary,
225443
226123
  edges,
226124
+ hierarchyEdges,
225444
226125
  cycles: parsedCycles,
225445
226126
  hotspots: {
225446
226127
  mostDependedOnModules,
225447
226128
  highestOutgoingFanOutModules,
225448
226129
  modulesInCircularDependencies,
226130
+ independentModules,
226131
+ potentialOrphanModules,
225449
226132
  orphanModules,
225450
226133
  missingContracts,
225451
226134
  highlyConnectedModules,
@@ -225455,6 +226138,8 @@ async function generateArchitectureMap(workspaceRoot, options) {
225455
226138
  moduleCount: modules.length,
225456
226139
  edgeCount: edges.length,
225457
226140
  cycleCount: parsedCycles.length,
226141
+ independentCount: independentModules.length,
226142
+ potentialOrphanCount: potentialOrphanModules.length,
225458
226143
  orphanCount: orphanModules.length,
225459
226144
  highlyConnectedCount: highlyConnectedModules.length,
225460
226145
  missingContractCount: missingContracts.length
@@ -225470,6 +226155,11 @@ async function generateArchitectureMap(workspaceRoot, options) {
225470
226155
  importCount: edge.importCount,
225471
226156
  publicImportCount: edge.publicImportCount,
225472
226157
  nonPublicImportCount: edge.nonPublicImportCount
226158
+ })),
226159
+ hierarchyEdges: hierarchyEdges.map((edge) => ({
226160
+ source: edge.parentModule,
226161
+ target: edge.childModule,
226162
+ relationship: "contains"
225473
226163
  }))
225474
226164
  },
225475
226165
  notes: {
@@ -230500,6 +231190,9 @@ async function pathExists13(targetPath) {
230500
231190
  function sortUnique12(values) {
230501
231191
  return [...new Set(values)].sort((left, right) => left.localeCompare(right));
230502
231192
  }
231193
+ function toSafeContractModuleFileStem3(moduleName) {
231194
+ return normalizePath11(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
231195
+ }
230503
231196
  function wildcardToRegex(pattern) {
230504
231197
  const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
230505
231198
  return new RegExp(`^${escaped.replace(/\*/g, ".*")}$`, "u");
@@ -230581,7 +231274,10 @@ function resolveContractPath(contract, moduleName) {
230581
231274
  return normalizePath11(configured);
230582
231275
  }
230583
231276
  return normalizePath11(
230584
- path44.posix.join(resolveContractsRootFromContract(contract), `${moduleName}.contract.json`)
231277
+ path44.posix.join(
231278
+ resolveContractsRootFromContract(contract),
231279
+ `${toSafeContractModuleFileStem3(moduleName)}.contract.json`
231280
+ )
230585
231281
  );
230586
231282
  }
230587
231283
  function createModuleContract(input2) {
@@ -230593,6 +231289,23 @@ function createModuleContract(input2) {
230593
231289
  exposedApis: []
230594
231290
  };
230595
231291
  }
231292
+ async function readExistingModuleContractPublicEntrypoints(workspaceRoot, contractPath) {
231293
+ try {
231294
+ const raw = await import_node_fs39.promises.readFile(toAbsolutePath(workspaceRoot, contractPath), {
231295
+ encoding: "utf8"
231296
+ });
231297
+ const parsed = JSON.parse(raw);
231298
+ if (!Array.isArray(parsed.publicEntrypoints)) {
231299
+ return void 0;
231300
+ }
231301
+ if (parsed.publicEntrypoints.some((entry) => typeof entry !== "string")) {
231302
+ return void 0;
231303
+ }
231304
+ return sortUnique12(parsed.publicEntrypoints.map((entry) => normalizePath11(entry)));
231305
+ } catch {
231306
+ return void 0;
231307
+ }
231308
+ }
230596
231309
  function isRegistryEntryDifferent(input2) {
230597
231310
  const moduleRegistry = getModuleRegistry2(input2.contract);
230598
231311
  const existing = moduleRegistry[input2.moduleName] ?? {};
@@ -230619,7 +231332,15 @@ async function generateMissingModuleContracts(workspaceRoot) {
230619
231332
  )) {
230620
231333
  const contractPath = resolveContractPath(contract, moduleEntry.moduleName);
230621
231334
  const sourcePath = normalizePath11(moduleEntry.sourcePath);
230622
- const publicEntrypoints = await inferModulePublicEntrypoints(
231335
+ const absoluteContractPath = toAbsolutePath(workspaceRoot, contractPath);
231336
+ const contractExists = await pathExists13(absoluteContractPath);
231337
+ const existingContractPublicEntrypoints = contractExists ? await readExistingModuleContractPublicEntrypoints(workspaceRoot, contractPath) : void 0;
231338
+ const configuredPublicEntrypoints = !contractExists && Array.isArray(getModuleRegistry2(contract)[moduleEntry.moduleName]?.publicEntrypoints) ? sortUnique12(
231339
+ getModuleRegistry2(contract)[moduleEntry.moduleName]?.publicEntrypoints?.map(
231340
+ (entry) => normalizePath11(entry)
231341
+ ) ?? []
231342
+ ) : void 0;
231343
+ const publicEntrypoints = existingContractPublicEntrypoints ?? configuredPublicEntrypoints ?? await inferModulePublicEntrypoints(
230623
231344
  workspaceRoot,
230624
231345
  sourcePath,
230625
231346
  adapter
@@ -230629,8 +231350,7 @@ async function generateMissingModuleContracts(workspaceRoot) {
230629
231350
  dependsOn: dependsOnBySource.get(moduleEntry.moduleName) ?? [],
230630
231351
  publicEntrypoints
230631
231352
  });
230632
- const absoluteContractPath = toAbsolutePath(workspaceRoot, contractPath);
230633
- if (await pathExists13(absoluteContractPath)) {
231353
+ if (contractExists) {
230634
231354
  skippedExistingContracts.push(contractPath);
230635
231355
  } else {
230636
231356
  await import_node_fs39.promises.mkdir(path44.dirname(absoluteContractPath), { recursive: true });
@@ -232776,7 +233496,7 @@ var appRouteReservedDirectoryNames = /* @__PURE__ */ new Set([
232776
233496
  "common",
232777
233497
  "shared-ui"
232778
233498
  ]);
232779
- var sourceFileExtensions = /* @__PURE__ */ new Set([
233499
+ var sourceFileExtensions3 = /* @__PURE__ */ new Set([
232780
233500
  ".ts",
232781
233501
  ".tsx",
232782
233502
  ".js",
@@ -232894,7 +233614,7 @@ function inspectModuleFolder(absolutePath) {
232894
233614
  continue;
232895
233615
  }
232896
233616
  const extension = path53.extname(entry.name).toLowerCase();
232897
- if (sourceFileExtensions.has(extension)) {
233617
+ if (sourceFileExtensions3.has(extension)) {
232898
233618
  hasSourceFiles = true;
232899
233619
  sourceFileCount += 1;
232900
233620
  }
@@ -232974,14 +233694,17 @@ function collectModuleCandidatesFromRoot(workspaceRoot, modulesRootRelative, def
232974
233694
  if (skipFrontendUtilities && frontendUtilityDirectoryNames.has(entry.name.toLowerCase())) {
232975
233695
  continue;
232976
233696
  }
232977
- const moduleName = entry.name;
232978
- const moduleRelativePath = normalizePath13(`${modulesRootRelative}/${moduleName}`);
233697
+ const rootSegments = modulesRootRelative.split("/").filter((segment) => segment.length > 0);
233698
+ const sourceIndex = rootSegments.lastIndexOf("src");
233699
+ const rootLeaf = rootSegments[rootSegments.length - 1]?.toLowerCase();
233700
+ const parentName = sourceIndex > 0 && (rootLeaf === "src" || ["modules", "features"].includes(rootLeaf ?? "")) ? rootSegments[sourceIndex - 1] : void 0;
233701
+ const moduleName = parentName && parentName !== "src" ? `${parentName}/${entry.name}` : ["domain", "domains", "application", "infrastructure"].includes(rootLeaf ?? "") ? `${rootSegments[rootSegments.length - 1]}/${entry.name}` : entry.name;
232979
233702
  const moduleAbsolutePath = path53.join(absoluteRoot, entry.name);
232980
233703
  const inspected = inspectModuleFolder(moduleAbsolutePath);
232981
233704
  const detected = makeDetectedModule(
232982
233705
  workspaceRoot,
232983
233706
  moduleName,
232984
- moduleRelativePath,
233707
+ normalizePath13(`${modulesRootRelative}/${entry.name}`),
232985
233708
  modulesRootRelative,
232986
233709
  inspected.hasSourceFiles,
232987
233710
  inspected.hasRoleFiles,
@@ -233042,6 +233765,10 @@ function collectExplicitRoots(workspaceRoot) {
233042
233765
  for (const root of [
233043
233766
  "src/modules",
233044
233767
  "src/features",
233768
+ "src/domain",
233769
+ "src/domains",
233770
+ "src/application",
233771
+ "src/infrastructure",
233045
233772
  "src/app",
233046
233773
  "app",
233047
233774
  "backend/src/modules",
@@ -233068,8 +233795,13 @@ function collectExplicitRoots(workspaceRoot) {
233068
233795
  continue;
233069
233796
  }
233070
233797
  for (const candidate of [
233798
+ `apps/${appEntry.name}/src`,
233071
233799
  `apps/${appEntry.name}/src/modules`,
233072
233800
  `apps/${appEntry.name}/src/features`,
233801
+ `apps/${appEntry.name}/src/domain`,
233802
+ `apps/${appEntry.name}/src/domains`,
233803
+ `apps/${appEntry.name}/src/application`,
233804
+ `apps/${appEntry.name}/src/infrastructure`,
233073
233805
  `apps/${appEntry.name}/app`,
233074
233806
  `apps/${appEntry.name}/src/app`
233075
233807
  ]) {
@@ -233078,6 +233810,27 @@ function collectExplicitRoots(workspaceRoot) {
233078
233810
  }
233079
233811
  }
233080
233812
  }
233813
+ for (const container of ["packages", "services"]) {
233814
+ const containerRoot = path53.join(workspaceRoot, container);
233815
+ for (const containerEntry of safeReadDirEntries(containerRoot)) {
233816
+ if (!containerEntry.isDirectory() || ignoredDirectoryNames4.has(containerEntry.name)) {
233817
+ continue;
233818
+ }
233819
+ for (const candidate of [
233820
+ `${container}/${containerEntry.name}/src`,
233821
+ `${container}/${containerEntry.name}/src/modules`,
233822
+ `${container}/${containerEntry.name}/src/features`,
233823
+ `${container}/${containerEntry.name}/src/domain`,
233824
+ `${container}/${containerEntry.name}/src/domains`,
233825
+ `${container}/${containerEntry.name}/src/application`,
233826
+ `${container}/${containerEntry.name}/src/infrastructure`
233827
+ ]) {
233828
+ if (pathExists15(path53.join(workspaceRoot, ...candidate.split("/")))) {
233829
+ roots.push(candidate);
233830
+ }
233831
+ }
233832
+ }
233833
+ }
233081
233834
  return uniqueSorted(roots);
233082
233835
  }
233083
233836
  function collectJavaPackageRoots(workspaceRoot) {