@harness-engineering/core 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -184,6 +184,7 @@ __export(index_exports, {
184
184
  ViolationHistorySchema: () => ViolationHistorySchema,
185
185
  ViolationSchema: () => ViolationSchema,
186
186
  ViolationSnapshotSchema: () => ViolationSnapshotSchema,
187
+ WHATWG_BAD_PORTS: () => WHATWG_BAD_PORTS,
187
188
  acquireCompoundLock: () => acquireCompoundLock,
188
189
  addProvenance: () => addProvenance,
189
190
  agentConfigRules: () => agentConfigRules,
@@ -209,6 +210,7 @@ __export(index_exports, {
209
210
  archiveStream: () => archiveStream,
210
211
  assembleCandidateReport: () => assembleCandidateReport,
211
212
  assembleReport: () => assembleReport,
213
+ assertPortUsable: () => assertPortUsable,
212
214
  assertSanitized: () => assertSanitized,
213
215
  assignFeature: () => assignFeature,
214
216
  buildDependencyGraph: () => buildDependencyGraph,
@@ -323,6 +325,7 @@ __export(index_exports, {
323
325
  goRules: () => goRules,
324
326
  injectionRules: () => injectionRules,
325
327
  insecureDefaultsRules: () => insecureDefaultsRules,
328
+ isBadPort: () => isBadPort,
326
329
  isDuplicateFinding: () => isDuplicateFinding,
327
330
  isRegression: () => isRegression,
328
331
  isSanitizedResult: () => isSanitizedResult,
@@ -456,6 +459,7 @@ __export(index_exports, {
456
459
  validateAgentConfigs: () => validateAgentConfigs,
457
460
  validateAgentsMap: () => validateAgentsMap,
458
461
  validateBoundaries: () => validateBoundaries,
462
+ validateBranchName: () => validateBranchName,
459
463
  validateCommitMessage: () => validateCommitMessage,
460
464
  validateConfig: () => validateConfig,
461
465
  validateDependencies: () => validateDependencies,
@@ -1404,6 +1408,103 @@ function getDefaultRegistry() {
1404
1408
  return registry;
1405
1409
  }
1406
1410
 
1411
+ // src/shared/port.ts
1412
+ var WHATWG_BAD_PORTS = Object.freeze([
1413
+ 1,
1414
+ 7,
1415
+ 9,
1416
+ 11,
1417
+ 13,
1418
+ 15,
1419
+ 17,
1420
+ 19,
1421
+ 20,
1422
+ 21,
1423
+ 22,
1424
+ 23,
1425
+ 25,
1426
+ 37,
1427
+ 42,
1428
+ 43,
1429
+ 53,
1430
+ 69,
1431
+ 77,
1432
+ 79,
1433
+ 87,
1434
+ 95,
1435
+ 101,
1436
+ 102,
1437
+ 103,
1438
+ 104,
1439
+ 109,
1440
+ 110,
1441
+ 111,
1442
+ 113,
1443
+ 115,
1444
+ 117,
1445
+ 119,
1446
+ 123,
1447
+ 135,
1448
+ 137,
1449
+ 139,
1450
+ 143,
1451
+ 161,
1452
+ 179,
1453
+ 389,
1454
+ 427,
1455
+ 465,
1456
+ 512,
1457
+ 513,
1458
+ 514,
1459
+ 515,
1460
+ 526,
1461
+ 530,
1462
+ 531,
1463
+ 532,
1464
+ 540,
1465
+ 548,
1466
+ 554,
1467
+ 556,
1468
+ 563,
1469
+ 587,
1470
+ 601,
1471
+ 636,
1472
+ 989,
1473
+ 990,
1474
+ 993,
1475
+ 995,
1476
+ 1719,
1477
+ 1720,
1478
+ 1723,
1479
+ 2049,
1480
+ 3659,
1481
+ 4045,
1482
+ 4190,
1483
+ 5060,
1484
+ 5061,
1485
+ 6e3,
1486
+ 6566,
1487
+ 6665,
1488
+ 6666,
1489
+ 6667,
1490
+ 6668,
1491
+ 6669,
1492
+ 6679,
1493
+ 6697,
1494
+ 10080
1495
+ ]);
1496
+ var BAD_PORT_SET = new Set(WHATWG_BAD_PORTS);
1497
+ function isBadPort(port) {
1498
+ return BAD_PORT_SET.has(port);
1499
+ }
1500
+ function assertPortUsable(port, label = "server") {
1501
+ if (isBadPort(port)) {
1502
+ throw new Error(
1503
+ `Refusing to bind ${label} to port ${port}: this port is on the WHATWG fetch bad-ports list, so browsers and Node's fetch() will reject every connection with "bad port". Choose a different port. See https://fetch.spec.whatwg.org/#port-blocking for the full list.`
1504
+ );
1505
+ }
1506
+ }
1507
+
1407
1508
  // src/validation/file-structure.ts
1408
1509
  async function validateFileStructure(projectPath, conventions) {
1409
1510
  const missing = [];
@@ -1779,7 +1880,7 @@ function isAgnixDisabled() {
1779
1880
  return v === "1" || v === "true";
1780
1881
  }
1781
1882
  function runAgnix(cwd, strict, binPath, timeoutMs = DEFAULT_AGNIX_TIMEOUT_MS, spawnFn = import_node_child_process.spawn) {
1782
- return new Promise((resolve11) => {
1883
+ return new Promise((resolve12) => {
1783
1884
  const args = ["--format", "json"];
1784
1885
  if (strict) args.push("--strict");
1785
1886
  args.push(cwd);
@@ -1793,7 +1894,7 @@ function runAgnix(cwd, strict, binPath, timeoutMs = DEFAULT_AGNIX_TIMEOUT_MS, sp
1793
1894
  if (settled) return;
1794
1895
  settled = true;
1795
1896
  clearTimeout(timer);
1796
- resolve11(outcome);
1897
+ resolve12(outcome);
1797
1898
  };
1798
1899
  const timer = setTimeout(() => {
1799
1900
  child.kill("SIGKILL");
@@ -2958,8 +3059,82 @@ function validateRoadmapMode(config, projectRoot) {
2958
3059
  return (0, import_types.Ok)(void 0);
2959
3060
  }
2960
3061
 
2961
- // src/context/doc-coverage.ts
3062
+ // src/validation/branch.ts
2962
3063
  var import_minimatch = require("minimatch");
3064
+ var KEBAB_CASE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
3065
+ var TICKET_ID = /^([A-Z0-9]+-[0-9]+)-(.*)$/;
3066
+ function validateBranchName(branchName, config) {
3067
+ for (const pattern of config.ignore) {
3068
+ if ((0, import_minimatch.minimatch)(branchName, pattern)) {
3069
+ return { valid: true, branchName };
3070
+ }
3071
+ }
3072
+ if (config.customRegex) {
3073
+ const regex = new RegExp(config.customRegex);
3074
+ if (!regex.test(branchName)) {
3075
+ return {
3076
+ valid: false,
3077
+ branchName,
3078
+ message: `Branch name "${branchName}" does not match the custom regex: ${config.customRegex}`
3079
+ };
3080
+ }
3081
+ return { valid: true, branchName };
3082
+ }
3083
+ const parts = branchName.split("/");
3084
+ if (parts.length < 2) {
3085
+ return {
3086
+ valid: false,
3087
+ branchName,
3088
+ message: `Branch name "${branchName}" must have a prefix followed by a slash (e.g., "feat/my-feature").`,
3089
+ suggestion: `Try renaming to "feat/${branchName}" or "fix/${branchName}".`
3090
+ };
3091
+ }
3092
+ const prefix = parts[0];
3093
+ const slug = parts.slice(1).join("/");
3094
+ if (!config.prefixes.includes(prefix)) {
3095
+ return {
3096
+ valid: false,
3097
+ branchName,
3098
+ message: `Prefix "${prefix}" is not allowed.`,
3099
+ suggestion: `Allowed prefixes: ${config.prefixes.join(", ")}.`
3100
+ };
3101
+ }
3102
+ if (config.enforceKebabCase) {
3103
+ for (const part of slug.split("/")) {
3104
+ const ticketMatch = part.match(TICKET_ID);
3105
+ if (ticketMatch) {
3106
+ const rest = ticketMatch[2];
3107
+ if (rest && !KEBAB_CASE.test(rest)) {
3108
+ return {
3109
+ valid: false,
3110
+ branchName,
3111
+ message: `Branch slug part "${part}" does not follow kebab-case after the ticket ID.`,
3112
+ suggestion: `Ensure the description after "${ticketMatch[1]}" uses kebab-case (lowercase, single hyphens, no leading/trailing hyphen).`
3113
+ };
3114
+ }
3115
+ } else if (!KEBAB_CASE.test(part)) {
3116
+ return {
3117
+ valid: false,
3118
+ branchName,
3119
+ message: `Branch slug part "${part}" must be in kebab-case (lowercase, single hyphens, no leading/trailing hyphen).`,
3120
+ suggestion: `Change "${part}" to match the convention.`
3121
+ };
3122
+ }
3123
+ }
3124
+ }
3125
+ if (typeof config.maxLength === "number" && config.maxLength > 0 && slug.length > config.maxLength) {
3126
+ return {
3127
+ valid: false,
3128
+ branchName,
3129
+ message: `Branch slug is ${slug.length} characters; max allowed is ${config.maxLength}.`,
3130
+ suggestion: `Shorten the description after "${prefix}/" to ${config.maxLength} characters or fewer.`
3131
+ };
3132
+ }
3133
+ return { valid: true, branchName };
3134
+ }
3135
+
3136
+ // src/context/doc-coverage.ts
3137
+ var import_minimatch2 = require("minimatch");
2963
3138
  var import_path2 = require("path");
2964
3139
  function determineImportance(filePath) {
2965
3140
  const name = (0, import_path2.basename)(filePath).toLowerCase();
@@ -3002,7 +3177,7 @@ async function checkDocCoverage(domain, options = {}) {
3002
3177
  const filteredSourceFiles = sourceFiles.filter((file) => {
3003
3178
  const relativePath = relativePosix(sourceDir, file);
3004
3179
  return !excludePatterns.some((pattern) => {
3005
- return (0, import_minimatch.minimatch)(relativePath, pattern, { dot: true }) || (0, import_minimatch.minimatch)(file, pattern, { dot: true });
3180
+ return (0, import_minimatch2.minimatch)(relativePath, pattern, { dot: true }) || (0, import_minimatch2.minimatch)(file, pattern, { dot: true });
3006
3181
  });
3007
3182
  });
3008
3183
  const docFiles = await findFiles("**/*.md", docsDir);
@@ -3536,7 +3711,7 @@ function getPhaseCategories(phase) {
3536
3711
  }
3537
3712
 
3538
3713
  // src/constraints/layers.ts
3539
- var import_minimatch2 = require("minimatch");
3714
+ var import_minimatch3 = require("minimatch");
3540
3715
  function defineLayer(name, patterns, allowedDependencies) {
3541
3716
  return {
3542
3717
  name,
@@ -3547,7 +3722,7 @@ function defineLayer(name, patterns, allowedDependencies) {
3547
3722
  function resolveFileToLayer(file, layers) {
3548
3723
  for (const layer of layers) {
3549
3724
  for (const pattern of layer.patterns) {
3550
- if ((0, import_minimatch2.minimatch)(file, pattern)) {
3725
+ if ((0, import_minimatch3.minimatch)(file, pattern)) {
3551
3726
  return layer;
3552
3727
  }
3553
3728
  }
@@ -4566,8 +4741,12 @@ function parseProtectedRegions(files) {
4566
4741
  }
4567
4742
 
4568
4743
  // src/entropy/snapshot.ts
4744
+ var import_graph = require("@harness-engineering/graph");
4745
+ var import_path7 = require("path");
4746
+ var import_minimatch4 = require("minimatch");
4747
+
4748
+ // src/entropy/entry-points.ts
4569
4749
  var import_path6 = require("path");
4570
- var import_minimatch3 = require("minimatch");
4571
4750
  function collectFieldEntries(rootDir, field) {
4572
4751
  if (typeof field === "string") return [(0, import_path6.resolve)(rootDir, field)];
4573
4752
  if (typeof field === "object" && field !== null) {
@@ -4581,47 +4760,263 @@ function extractPackageEntries(rootDir, pkg) {
4581
4760
  if (entries.length === 0 && typeof pkg["main"] === "string") {
4582
4761
  entries.push((0, import_path6.resolve)(rootDir, pkg["main"]));
4583
4762
  }
4584
- if (pkg["bin"]) {
4585
- entries.push(...collectFieldEntries(rootDir, pkg["bin"]));
4586
- }
4763
+ if (pkg["bin"]) entries.push(...collectFieldEntries(rootDir, pkg["bin"]));
4587
4764
  return entries;
4588
4765
  }
4589
- async function resolveEntryPoints(rootDir, explicitEntries) {
4590
- if (explicitEntries && explicitEntries.length > 0) {
4591
- return (0, import_types.Ok)(explicitEntries.map((e) => (0, import_path6.resolve)(rootDir, e)));
4766
+ var TS_HINTS = ['Add "exports" or "main" to package.json', "Create src/index.ts"];
4767
+ var TS_CONVENTIONS = ["src/index.ts", "src/main.ts", "src/index.tsx", "index.ts", "main.ts"];
4768
+ async function readPackageJsonEntries(rootDir, pkgPath) {
4769
+ const content = await readFileContent(pkgPath);
4770
+ if (!content.ok) return [];
4771
+ try {
4772
+ const pkg = JSON.parse(content.value);
4773
+ return extractPackageEntries(rootDir, pkg);
4774
+ } catch {
4775
+ return [];
4592
4776
  }
4777
+ }
4778
+ async function resolveTypeScript(rootDir) {
4593
4779
  const pkgPath = (0, import_path6.join)(rootDir, "package.json");
4594
- if (await fileExists(pkgPath)) {
4595
- const pkgContent = await readFileContent(pkgPath);
4596
- if (pkgContent.ok) {
4597
- try {
4598
- const pkg = JSON.parse(pkgContent.value);
4599
- const entries = extractPackageEntries(rootDir, pkg);
4600
- if (entries.length > 0) return (0, import_types.Ok)(entries);
4601
- } catch {
4602
- }
4780
+ const detected = await fileExists(pkgPath);
4781
+ if (detected) {
4782
+ const entries = await readPackageJsonEntries(rootDir, pkgPath);
4783
+ if (entries.length > 0) {
4784
+ return { language: "typescript", detected: true, entries, hints: TS_HINTS };
4785
+ }
4786
+ }
4787
+ for (const conv of TS_CONVENTIONS) {
4788
+ const p = (0, import_path6.join)(rootDir, conv);
4789
+ if (await fileExists(p)) {
4790
+ return { language: "typescript", detected: true, entries: [p], hints: TS_HINTS };
4791
+ }
4792
+ }
4793
+ return { language: "typescript", detected, entries: [], hints: TS_HINTS };
4794
+ }
4795
+ var PYTHON_HINTS = [
4796
+ "Add an entry to [project.scripts] in pyproject.toml",
4797
+ "Create main.py or <package>/__main__.py"
4798
+ ];
4799
+ var PYTHON_CONVENTIONS = [
4800
+ "__main__.py",
4801
+ "main.py",
4802
+ "app.py",
4803
+ "src/__main__.py",
4804
+ "src/main.py",
4805
+ "src/app.py"
4806
+ ];
4807
+ async function detectPython(rootDir) {
4808
+ return await fileExists((0, import_path6.join)(rootDir, "pyproject.toml")) || await fileExists((0, import_path6.join)(rootDir, "setup.py")) || await fileExists((0, import_path6.join)(rootDir, "requirements.txt"));
4809
+ }
4810
+ async function readPyProject(rootDir) {
4811
+ const pyproject = (0, import_path6.join)(rootDir, "pyproject.toml");
4812
+ if (!await fileExists(pyproject)) return { scriptTargets: [] };
4813
+ const content = await readFileContent(pyproject);
4814
+ if (!content.ok) return { scriptTargets: [] };
4815
+ return parsePyProject(content.value);
4816
+ }
4817
+ async function resolveScriptTargetEntry(rootDir, target) {
4818
+ const mod = target.split(":")[0];
4819
+ if (!mod) return void 0;
4820
+ const relPath2 = mod.replaceAll(".", "/") + ".py";
4821
+ for (const candidate of [(0, import_path6.join)(rootDir, relPath2), (0, import_path6.join)(rootDir, "src", relPath2)]) {
4822
+ if (await fileExists(candidate)) return candidate;
4823
+ }
4824
+ return void 0;
4825
+ }
4826
+ async function resolvePythonFromScripts(rootDir, targets) {
4827
+ const entries = [];
4828
+ for (const target of targets) {
4829
+ const entry = await resolveScriptTargetEntry(rootDir, target);
4830
+ if (entry) entries.push(entry);
4831
+ }
4832
+ return entries;
4833
+ }
4834
+ async function resolvePythonFromProjectName(rootDir, projectName) {
4835
+ if (!projectName) return [];
4836
+ const normalized = projectName.replaceAll("-", "_");
4837
+ const candidates = [
4838
+ (0, import_path6.join)(rootDir, normalized, "__init__.py"),
4839
+ (0, import_path6.join)(rootDir, normalized, "__main__.py"),
4840
+ (0, import_path6.join)(rootDir, "src", normalized, "__init__.py"),
4841
+ (0, import_path6.join)(rootDir, "src", normalized, "__main__.py")
4842
+ ];
4843
+ const entries = [];
4844
+ for (const c of candidates) {
4845
+ if (await fileExists(c)) entries.push(c);
4846
+ }
4847
+ return entries;
4848
+ }
4849
+ async function resolvePythonConventions(rootDir) {
4850
+ const entries = [];
4851
+ for (const conv of PYTHON_CONVENTIONS) {
4852
+ const p = (0, import_path6.join)(rootDir, conv);
4853
+ if (await fileExists(p)) entries.push(p);
4854
+ }
4855
+ return entries;
4856
+ }
4857
+ async function findPythonTopLevelPackages(rootDir) {
4858
+ const found = await findFiles("*/__init__.py", rootDir);
4859
+ if (found.length > 0) return found;
4860
+ return findFiles("src/*/__init__.py", rootDir);
4861
+ }
4862
+ async function resolvePython(rootDir) {
4863
+ if (!await detectPython(rootDir)) {
4864
+ return { language: "python", detected: false, entries: [], hints: PYTHON_HINTS };
4865
+ }
4866
+ const info = await readPyProject(rootDir);
4867
+ const strategies = [
4868
+ () => resolvePythonFromScripts(rootDir, info.scriptTargets),
4869
+ () => resolvePythonFromProjectName(rootDir, info.projectName),
4870
+ () => resolvePythonConventions(rootDir),
4871
+ () => findPythonTopLevelPackages(rootDir)
4872
+ ];
4873
+ for (const strategy of strategies) {
4874
+ const entries = await strategy();
4875
+ if (entries.length > 0) {
4876
+ return { language: "python", detected: true, entries, hints: PYTHON_HINTS };
4603
4877
  }
4604
4878
  }
4605
- const conventions = ["src/index.ts", "src/main.ts", "index.ts", "main.ts"];
4606
- for (const conv of conventions) {
4607
- const convPath = (0, import_path6.join)(rootDir, conv);
4608
- if (await fileExists(convPath)) {
4609
- return (0, import_types.Ok)([convPath]);
4879
+ return { language: "python", detected: true, entries: [], hints: PYTHON_HINTS };
4880
+ }
4881
+ async function resolveGo(rootDir) {
4882
+ const hints = ["Create main.go at the project root, or use the cmd/<name>/main.go layout"];
4883
+ const detected = await fileExists((0, import_path6.join)(rootDir, "go.mod"));
4884
+ if (!detected) return { language: "go", detected: false, entries: [], hints };
4885
+ const entries = [];
4886
+ const mainGo = (0, import_path6.join)(rootDir, "main.go");
4887
+ if (await fileExists(mainGo)) entries.push(mainGo);
4888
+ entries.push(...await findFiles("cmd/*/main.go", rootDir));
4889
+ return { language: "go", detected: true, entries, hints };
4890
+ }
4891
+ async function resolveRust(rootDir) {
4892
+ const hints = [
4893
+ "Create src/main.rs or src/lib.rs",
4894
+ "Declare [[bin]] entries with a `path` in Cargo.toml"
4895
+ ];
4896
+ const cargoPath = (0, import_path6.join)(rootDir, "Cargo.toml");
4897
+ const detected = await fileExists(cargoPath);
4898
+ if (!detected) return { language: "rust", detected: false, entries: [], hints };
4899
+ const entries = [];
4900
+ const content = await readFileContent(cargoPath);
4901
+ if (content.ok) {
4902
+ for (const bp of parseCargoBinPaths(content.value)) {
4903
+ const abs = (0, import_path6.resolve)(rootDir, bp);
4904
+ if (await fileExists(abs)) entries.push(abs);
4610
4905
  }
4611
4906
  }
4907
+ if (entries.length === 0) {
4908
+ for (const conv of ["src/main.rs", "src/lib.rs"]) {
4909
+ const p = (0, import_path6.join)(rootDir, conv);
4910
+ if (await fileExists(p)) entries.push(p);
4911
+ }
4912
+ entries.push(...await findFiles("src/bin/*.rs", rootDir));
4913
+ }
4914
+ return { language: "rust", detected: true, entries, hints };
4915
+ }
4916
+ async function resolveJava(rootDir) {
4917
+ const hints = [
4918
+ "Place an entry class at src/main/java/**/Main.java (or *Application.java for Spring Boot)"
4919
+ ];
4920
+ const detected = await fileExists((0, import_path6.join)(rootDir, "pom.xml")) || await fileExists((0, import_path6.join)(rootDir, "build.gradle")) || await fileExists((0, import_path6.join)(rootDir, "build.gradle.kts"));
4921
+ if (!detected) return { language: "java", detected: false, entries: [], hints };
4922
+ const entries = [];
4923
+ entries.push(...await findFiles("src/main/java/**/Main.java", rootDir));
4924
+ entries.push(...await findFiles("src/main/java/**/*Application.java", rootDir));
4925
+ return { language: "java", detected: true, entries, hints };
4926
+ }
4927
+ function parseTomlLine(raw) {
4928
+ const line = raw.replace(/(^|\s)#.*$/, "").trim();
4929
+ if (!line) return {};
4930
+ const sectionMatch = /^\[([^\]]+)\]$/.exec(line);
4931
+ if (sectionMatch) return { section: sectionMatch[1] ?? "" };
4932
+ const eq = line.indexOf("=");
4933
+ if (eq <= 0) return {};
4934
+ return {
4935
+ key: line.slice(0, eq).trim(),
4936
+ value: stripTomlString2(line.slice(eq + 1).trim())
4937
+ };
4938
+ }
4939
+ function parsePyProject(content) {
4940
+ const result = { scriptTargets: [] };
4941
+ let section = null;
4942
+ for (const raw of content.split(/\r?\n/)) {
4943
+ const parsed = parseTomlLine(raw);
4944
+ if (parsed.section !== void 0) {
4945
+ section = parsed.section;
4946
+ continue;
4947
+ }
4948
+ if (parsed.key === void 0 || parsed.value === void 0) continue;
4949
+ if (section === "project" && parsed.key === "name") result.projectName = parsed.value;
4950
+ else if (section === "project.scripts") result.scriptTargets.push(parsed.value);
4951
+ }
4952
+ return result;
4953
+ }
4954
+ function parseCargoBinPaths(content) {
4955
+ const paths = [];
4956
+ let inBin = false;
4957
+ for (const raw of content.split(/\r?\n/)) {
4958
+ const line = raw.replace(/(^|\s)#.*$/, "").trim();
4959
+ if (!line) continue;
4960
+ if (line === "[[bin]]") {
4961
+ inBin = true;
4962
+ continue;
4963
+ }
4964
+ if (line.startsWith("[")) {
4965
+ inBin = false;
4966
+ continue;
4967
+ }
4968
+ if (!inBin) continue;
4969
+ const eq = line.indexOf("=");
4970
+ if (eq <= 0) continue;
4971
+ const key = line.slice(0, eq).trim();
4972
+ if (key === "path") paths.push(stripTomlString2(line.slice(eq + 1).trim()));
4973
+ }
4974
+ return paths;
4975
+ }
4976
+ function stripTomlString2(value) {
4977
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
4978
+ return value.slice(1, -1);
4979
+ }
4980
+ return value;
4981
+ }
4982
+ async function resolveEntryPoints(rootDir, explicitEntries) {
4983
+ if (explicitEntries && explicitEntries.length > 0) {
4984
+ return (0, import_types.Ok)(explicitEntries.map((e) => (0, import_path6.resolve)(rootDir, e)));
4985
+ }
4986
+ const resolvers = [resolveTypeScript, resolvePython, resolveGo, resolveRust, resolveJava];
4987
+ const resolutions = [];
4988
+ for (const resolver of resolvers) {
4989
+ const res = await resolver(rootDir);
4990
+ resolutions.push(res);
4991
+ if (res.entries.length > 0) return (0, import_types.Ok)(res.entries);
4992
+ }
4993
+ const detectedLangs = resolutions.filter((r) => r.detected);
4994
+ const suggestions = detectedLangs.length > 0 ? detectedLangs.flatMap((r) => r.hints) : resolutions.flatMap((r) => r.hints);
4995
+ suggestions.push("Specify entryPoints in config");
4996
+ const reason = detectedLangs.length > 0 ? `Detected ${detectedLangs.map((r) => r.language).join(", ")} project but found no entry points` : "No language manifest (package.json, pyproject.toml, go.mod, Cargo.toml, pom.xml) and no conventional entry files found";
4612
4997
  return (0, import_types.Err)(
4613
4998
  createEntropyError(
4614
4999
  "ENTRY_POINT_NOT_FOUND",
4615
5000
  "Could not resolve entry points",
4616
- { reason: "No package.json exports/main and no conventional entry files found" },
4617
- [
4618
- 'Add "exports" or "main" to package.json',
4619
- "Create src/index.ts",
4620
- "Specify entryPoints in config"
4621
- ]
5001
+ { reason },
5002
+ suggestions
4622
5003
  )
4623
5004
  );
4624
5005
  }
5006
+
5007
+ // src/entropy/snapshot.ts
5008
+ var DEFAULT_INCLUDE_PATTERNS = [
5009
+ "**/*.ts",
5010
+ "**/*.tsx",
5011
+ "**/*.js",
5012
+ "**/*.jsx",
5013
+ "**/*.mjs",
5014
+ "**/*.cjs",
5015
+ "**/*.py",
5016
+ "**/*.go",
5017
+ "**/*.rs",
5018
+ "**/*.java"
5019
+ ];
4625
5020
  function extractCodeBlocks(content) {
4626
5021
  const blocks = [];
4627
5022
  const lines = content.split("\n");
@@ -4715,6 +5110,7 @@ function extractSymbolsFromNode(node) {
4715
5110
  return [];
4716
5111
  }
4717
5112
  function extractInternalSymbols(ast) {
5113
+ if (ast.language !== "typescript" && ast.language !== "javascript") return [];
4718
5114
  const body = ast.body;
4719
5115
  if (!body?.body) return [];
4720
5116
  const nodes = body.body;
@@ -4725,6 +5121,7 @@ function toJSDocComment(comment) {
4725
5121
  return { content: comment.value, line: comment.loc?.start?.line || 0 };
4726
5122
  }
4727
5123
  function extractJSDocComments(ast) {
5124
+ if (ast.language !== "typescript" && ast.language !== "javascript") return [];
4728
5125
  const body = ast.body;
4729
5126
  if (!body?.comments) return [];
4730
5127
  return body.comments.flatMap((c) => {
@@ -4783,19 +5180,16 @@ function extractAllCodeReferences(docs) {
4783
5180
  }
4784
5181
  async function buildSnapshot(config) {
4785
5182
  const startTime = Date.now();
4786
- const parser = config.parser || new TypeScriptParser();
4787
- const rootDir = (0, import_path6.resolve)(config.rootDir);
5183
+ const rootDir = (0, import_path7.resolve)(config.rootDir);
4788
5184
  const entryPointsResult = await resolveEntryPoints(rootDir, config.entryPoints);
4789
5185
  if (!entryPointsResult.ok) {
4790
5186
  return (0, import_types.Err)(entryPointsResult.error);
4791
5187
  }
4792
- const includePatterns = config.include || ["**/*.ts", "**/*.tsx"];
4793
- const excludePatterns = config.exclude || [
4794
- "node_modules/**",
4795
- "dist/**",
4796
- "**/*.test.ts",
4797
- "**/*.spec.ts"
4798
- ];
5188
+ const registry = getDefaultRegistry();
5189
+ const singleParser = config.parser;
5190
+ const parserForFile = (filePath) => singleParser ?? registry.getForFile(filePath);
5191
+ const includePatterns = config.include || DEFAULT_INCLUDE_PATTERNS;
5192
+ const excludePatterns = config.exclude || [...(0, import_graph.skipDirGlobs)(), "**/*.test.ts", "**/*.spec.ts"];
4799
5193
  let sourceFilePaths = [];
4800
5194
  for (const pattern of includePatterns) {
4801
5195
  const files2 = await findFiles(pattern, rootDir);
@@ -4803,14 +5197,16 @@ async function buildSnapshot(config) {
4803
5197
  }
4804
5198
  sourceFilePaths = sourceFilePaths.filter((f) => {
4805
5199
  const rel = relativePosix(rootDir, f);
4806
- return !excludePatterns.some((p) => (0, import_minimatch3.minimatch)(rel, p));
5200
+ return !excludePatterns.some((p) => (0, import_minimatch4.minimatch)(rel, p));
4807
5201
  });
4808
5202
  const files = [];
4809
5203
  for (const filePath of sourceFilePaths) {
4810
- const parseResult = await parser.parseFile(filePath);
5204
+ const fileParser = parserForFile(filePath);
5205
+ if (!fileParser) continue;
5206
+ const parseResult = await fileParser.parseFile(filePath);
4811
5207
  if (!parseResult.ok) continue;
4812
- const importsResult = parser.extractImports(parseResult.value);
4813
- const exportsResult = parser.extractExports(parseResult.value);
5208
+ const importsResult = fileParser.extractImports(parseResult.value);
5209
+ const exportsResult = fileParser.extractExports(parseResult.value);
4814
5210
  const internalSymbols = extractInternalSymbols(parseResult.value);
4815
5211
  const jsDocComments = extractJSDocComments(parseResult.value);
4816
5212
  files.push({
@@ -4822,7 +5218,7 @@ async function buildSnapshot(config) {
4822
5218
  jsDocComments
4823
5219
  });
4824
5220
  }
4825
- const graphResult = await buildDependencyGraph(sourceFilePaths, parser);
5221
+ const graphResult = await buildDependencyGraph(sourceFilePaths, singleParser ?? registry);
4826
5222
  const dependencyGraph = graphResult.ok ? graphResult.value : { nodes: [], edges: [] };
4827
5223
  const docPatterns = config.docPaths || ["docs/**/*.md", "README.md", "**/README.md"];
4828
5224
  let docFilePaths = [];
@@ -4855,7 +5251,7 @@ async function buildSnapshot(config) {
4855
5251
  }
4856
5252
 
4857
5253
  // src/entropy/detectors/drift.ts
4858
- var import_path7 = require("path");
5254
+ var import_path8 = require("path");
4859
5255
  function initLevenshteinMatrix(aLen, bLen) {
4860
5256
  const matrix = [];
4861
5257
  for (let i = 0; i <= bLen; i++) {
@@ -4967,7 +5363,7 @@ async function checkStructureDrift(snapshot, _config) {
4967
5363
  for (const doc of snapshot.docs) {
4968
5364
  const fileLinks = extractFileLinks(doc.content);
4969
5365
  for (const { link, line } of fileLinks) {
4970
- const resolvedPath = (0, import_path7.resolve)((0, import_path7.dirname)(doc.path), link);
5366
+ const resolvedPath = (0, import_path8.resolve)((0, import_path8.dirname)(doc.path), link);
4971
5367
  const exists = await fileExists(resolvedPath);
4972
5368
  if (!exists) {
4973
5369
  drifts.push({
@@ -5058,7 +5454,7 @@ async function detectDocDrift(snapshot, config, graphDriftData) {
5058
5454
  }
5059
5455
 
5060
5456
  // src/entropy/detectors/dead-code.ts
5061
- var import_path8 = require("path");
5457
+ var import_path9 = require("path");
5062
5458
  var JS_EXT_FALLBACKS2 = {
5063
5459
  ".js": [".ts", ".tsx", ".jsx"],
5064
5460
  ".jsx": [".tsx"],
@@ -5077,9 +5473,9 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
5077
5473
  return null;
5078
5474
  }
5079
5475
  const hasFile = fileIndex ? (p) => fileIndex.has(p) : (p) => snapshot.files.some((f) => f.path === p);
5080
- const fromDir = (0, import_path8.dirname)(fromFile);
5081
- const resolved = (0, import_path8.resolve)(fromDir, importSource);
5082
- const sourceExt = (0, import_path8.extname)(resolved);
5476
+ const fromDir = (0, import_path9.dirname)(fromFile);
5477
+ const resolved = (0, import_path9.resolve)(fromDir, importSource);
5478
+ const sourceExt = (0, import_path9.extname)(resolved);
5083
5479
  const fallbacks = JS_EXT_FALLBACKS2[sourceExt];
5084
5480
  if (fallbacks) {
5085
5481
  const base = resolved.slice(0, -sourceExt.length);
@@ -5088,7 +5484,7 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
5088
5484
  if (hasFile(candidate)) return candidate;
5089
5485
  }
5090
5486
  for (const indexExt of [".ts", ".tsx", ".jsx"]) {
5091
- const indexPath2 = (0, import_path8.resolve)(base, "index" + indexExt);
5487
+ const indexPath2 = (0, import_path9.resolve)(base, "index" + indexExt);
5092
5488
  if (hasFile(indexPath2)) return indexPath2;
5093
5489
  }
5094
5490
  }
@@ -5099,7 +5495,7 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
5099
5495
  if (hasFile(candidate)) return candidate;
5100
5496
  }
5101
5497
  for (const indexExt of [".ts", ".tsx"]) {
5102
- const indexPath2 = (0, import_path8.resolve)(resolved, "index" + indexExt);
5498
+ const indexPath2 = (0, import_path9.resolve)(resolved, "index" + indexExt);
5103
5499
  if (hasFile(indexPath2)) return indexPath2;
5104
5500
  }
5105
5501
  }
@@ -5413,10 +5809,10 @@ async function detectDeadCode(snapshot, graphDeadCodeData, protectedRegions) {
5413
5809
  }
5414
5810
 
5415
5811
  // src/entropy/detectors/patterns.ts
5416
- var import_minimatch4 = require("minimatch");
5812
+ var import_minimatch5 = require("minimatch");
5417
5813
  function fileMatchesPattern(filePath, pattern, rootDir) {
5418
5814
  const relativePath = relativePosix(rootDir, filePath);
5419
- return (0, import_minimatch4.minimatch)(relativePath, pattern);
5815
+ return (0, import_minimatch5.minimatch)(relativePath, pattern);
5420
5816
  }
5421
5817
  var CONVENTION_DESCRIPTIONS = {
5422
5818
  camelCase: "camelCase (e.g., myFunction)",
@@ -6085,6 +6481,7 @@ async function detectCouplingViolations(snapshot, config, graphData) {
6085
6481
  // src/entropy/detectors/size-budget.ts
6086
6482
  var import_node_fs12 = require("fs");
6087
6483
  var import_node_path12 = require("path");
6484
+ var import_graph2 = require("@harness-engineering/graph");
6088
6485
  function parseSize(size) {
6089
6486
  const match = size.trim().match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB|B)?$/i);
6090
6487
  if (!match) return 0;
@@ -6110,7 +6507,7 @@ function dirSize(dirPath) {
6110
6507
  return 0;
6111
6508
  }
6112
6509
  for (const entry of entries) {
6113
- if (entry === "node_modules" || entry === ".git") continue;
6510
+ if (import_graph2.DEFAULT_SKIP_DIRS.has(entry)) continue;
6114
6511
  const fullPath = (0, import_node_path12.join)(dirPath, entry);
6115
6512
  try {
6116
6513
  const stat2 = (0, import_node_fs12.statSync)(fullPath);
@@ -6287,10 +6684,7 @@ var EntropyAnalyzer = class {
6287
6684
  snapshot;
6288
6685
  report;
6289
6686
  constructor(config) {
6290
- this.config = {
6291
- ...config,
6292
- parser: config.parser || new TypeScriptParser()
6293
- };
6687
+ this.config = { ...config };
6294
6688
  }
6295
6689
  /**
6296
6690
  * Run full entropy analysis.
@@ -6520,7 +6914,7 @@ var EntropyAnalyzer = class {
6520
6914
  // src/entropy/fixers/safe-fixes.ts
6521
6915
  var fs6 = __toESM(require("fs"));
6522
6916
  var import_util2 = require("util");
6523
- var import_path9 = require("path");
6917
+ var import_path10 = require("path");
6524
6918
  var readFile8 = (0, import_util2.promisify)(fs6.readFile);
6525
6919
  var writeFile3 = (0, import_util2.promisify)(fs6.writeFile);
6526
6920
  var unlink2 = (0, import_util2.promisify)(fs6.unlink);
@@ -6536,7 +6930,7 @@ function createDeadFileFixes(deadCodeReport) {
6536
6930
  return deadCodeReport.deadFiles.map((file) => ({
6537
6931
  type: "dead-files",
6538
6932
  file: file.path,
6539
- description: `Delete dead file (${file.reason}): ${(0, import_path9.basename)(file.path)}`,
6933
+ description: `Delete dead file (${file.reason}): ${(0, import_path10.basename)(file.path)}`,
6540
6934
  action: "delete-file",
6541
6935
  safe: true,
6542
6936
  reversible: true
@@ -6637,9 +7031,9 @@ function previewFix(fix) {
6637
7031
  }
6638
7032
  }
6639
7033
  async function createBackup(filePath, backupDir) {
6640
- const backupPath = (0, import_path9.join)(backupDir, `${Date.now()}-${(0, import_path9.basename)(filePath)}`);
7034
+ const backupPath = (0, import_path10.join)(backupDir, `${Date.now()}-${(0, import_path10.basename)(filePath)}`);
6641
7035
  try {
6642
- await mkdir2((0, import_path9.dirname)(backupPath), { recursive: true });
7036
+ await mkdir2((0, import_path10.dirname)(backupPath), { recursive: true });
6643
7037
  await copyFile2(filePath, backupPath);
6644
7038
  return (0, import_types.Ok)(backupPath);
6645
7039
  } catch (e) {
@@ -7299,7 +7693,7 @@ var RegressionDetector = class {
7299
7693
  // src/performance/critical-path.ts
7300
7694
  var fs7 = __toESM(require("fs"));
7301
7695
  var path4 = __toESM(require("path"));
7302
- var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git"]);
7696
+ var import_graph3 = require("@harness-engineering/graph");
7303
7697
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
7304
7698
  var FUNCTION_DECL_RE = /(?:export\s+)?(?:async\s+)?function\s+(\w+)/;
7305
7699
  var CONST_DECL_RE = /(?:export\s+)?(?:const|let)\s+(\w+)\s*=/;
@@ -7366,7 +7760,7 @@ var CriticalPathResolver = class {
7366
7760
  }
7367
7761
  for (const item of items) {
7368
7762
  if (item.isDirectory()) {
7369
- if (SKIP_DIRS.has(item.name)) continue;
7763
+ if (import_graph3.DEFAULT_SKIP_DIRS.has(item.name)) continue;
7370
7764
  this.walkDir(path4.join(dir, item.name), entries);
7371
7765
  } else if (item.isFile() && SOURCE_EXTENSIONS.has(path4.extname(item.name))) {
7372
7766
  this.scanFile(path4.join(dir, item.name), entries);
@@ -8127,7 +8521,7 @@ async function requestMultiplePeerReviews(requests) {
8127
8521
 
8128
8522
  // src/feedback/logging/file-sink.ts
8129
8523
  var import_fs2 = require("fs");
8130
- var import_path10 = require("path");
8524
+ var import_path11 = require("path");
8131
8525
  var FileSink = class {
8132
8526
  name = "file";
8133
8527
  filePath;
@@ -8150,7 +8544,7 @@ var FileSink = class {
8150
8544
  }
8151
8545
  ensureDirectory() {
8152
8546
  if (!this.initialized) {
8153
- const dir = (0, import_path10.dirname)(this.filePath);
8547
+ const dir = (0, import_path11.dirname)(this.filePath);
8154
8548
  if (!(0, import_fs2.existsSync)(dir)) {
8155
8549
  (0, import_fs2.mkdirSync)(dir, { recursive: true });
8156
8550
  }
@@ -8688,8 +9082,9 @@ var ForbiddenImportCollector = class {
8688
9082
  // src/architecture/collectors/module-size.ts
8689
9083
  var import_promises2 = require("fs/promises");
8690
9084
  var import_node_path14 = require("path");
9085
+ var import_graph4 = require("@harness-engineering/graph");
8691
9086
  function isSkippedEntry(name) {
8692
- return name.startsWith(".") || name === "node_modules" || name === "dist";
9087
+ return name.startsWith(".") || import_graph4.DEFAULT_SKIP_DIRS.has(name);
8693
9088
  }
8694
9089
  function isTsSourceFile(name) {
8695
9090
  if (!name.endsWith(".ts") && !name.endsWith(".tsx")) return false;
@@ -8829,6 +9224,7 @@ var ModuleSizeCollector = class {
8829
9224
  // src/architecture/collectors/dep-depth.ts
8830
9225
  var import_promises3 = require("fs/promises");
8831
9226
  var import_node_path15 = require("path");
9227
+ var import_graph5 = require("@harness-engineering/graph");
8832
9228
  function extractImportSources(content, filePath) {
8833
9229
  const importRegex = /(?:import|export)\s+.*?from\s+['"](\.[^'"]+)['"]/g;
8834
9230
  const dynamicRegex = /import\s*\(\s*['"](\.[^'"]+)['"]\s*\)/g;
@@ -8847,7 +9243,7 @@ function extractImportSources(content, filePath) {
8847
9243
  return sources;
8848
9244
  }
8849
9245
  function isSkippedEntry2(name) {
8850
- return name.startsWith(".") || name === "node_modules" || name === "dist";
9246
+ return name.startsWith(".") || import_graph5.DEFAULT_SKIP_DIRS.has(name);
8851
9247
  }
8852
9248
  function isTsSourceFile2(name) {
8853
9249
  if (!name.endsWith(".ts") && !name.endsWith(".tsx")) return false;
@@ -11530,7 +11926,7 @@ function checkOverlap(newEntry, existingEntries, options) {
11530
11926
  var LOCK_RETRIES = 3;
11531
11927
  var LOCK_BACKOFFS = [50, 100, 200];
11532
11928
  function sleep(ms) {
11533
- return new Promise((resolve11) => setTimeout(resolve11, ms));
11929
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
11534
11930
  }
11535
11931
  async function acquireFileLock(lockPath) {
11536
11932
  for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
@@ -12743,7 +13139,7 @@ async function runMultiTurnPipeline(initialContext, turnExecutor, options) {
12743
13139
 
12744
13140
  // src/security/scanner.ts
12745
13141
  var fs28 = __toESM(require("fs/promises"));
12746
- var import_minimatch5 = require("minimatch");
13142
+ var import_minimatch6 = require("minimatch");
12747
13143
 
12748
13144
  // src/security/rules/registry.ts
12749
13145
  var RuleRegistry = class {
@@ -12775,13 +13171,15 @@ var RuleRegistry = class {
12775
13171
 
12776
13172
  // src/security/config.ts
12777
13173
  var import_zod11 = require("zod");
13174
+ var import_graph7 = require("@harness-engineering/graph");
12778
13175
 
12779
13176
  // src/security/types.ts
13177
+ var import_graph6 = require("@harness-engineering/graph");
12780
13178
  var DEFAULT_SECURITY_CONFIG = {
12781
13179
  enabled: true,
12782
13180
  strict: false,
12783
13181
  rules: {},
12784
- exclude: ["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]
13182
+ exclude: [...(0, import_graph6.skipDirGlobs)(), "**/*.test.ts", "**/fixtures/**"]
12785
13183
  };
12786
13184
 
12787
13185
  // src/security/config.ts
@@ -12790,7 +13188,7 @@ var SecurityConfigSchema = import_zod11.z.object({
12790
13188
  enabled: import_zod11.z.boolean().default(true),
12791
13189
  strict: import_zod11.z.boolean().default(false),
12792
13190
  rules: import_zod11.z.record(import_zod11.z.string(), RuleOverrideSchema).optional().default({}),
12793
- exclude: import_zod11.z.array(import_zod11.z.string()).optional().default(["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]),
13191
+ exclude: import_zod11.z.array(import_zod11.z.string()).optional().default([...(0, import_graph7.skipDirGlobs)(), "**/*.test.ts", "**/fixtures/**"]),
12794
13192
  external: import_zod11.z.object({
12795
13193
  semgrep: import_zod11.z.object({
12796
13194
  enabled: import_zod11.z.union([import_zod11.z.literal("auto"), import_zod11.z.boolean()]).default("auto"),
@@ -13701,7 +14099,7 @@ var SecurityScanner = class {
13701
14099
  const applicableRules = this.activeRules.filter((rule) => {
13702
14100
  if (!rule.fileGlob) return true;
13703
14101
  const globs = rule.fileGlob.split(",").map((g) => g.trim());
13704
- return globs.some((glob6) => (0, import_minimatch5.minimatch)(filePath, glob6, { dot: true }));
14102
+ return globs.some((glob6) => (0, import_minimatch6.minimatch)(filePath, glob6, { dot: true }));
13705
14103
  });
13706
14104
  return this.scanLinesWithRules(lines, applicableRules, filePath, startLine);
13707
14105
  }
@@ -14709,7 +15107,8 @@ var SecurityTimelineManager = class _SecurityTimelineManager {
14709
15107
 
14710
15108
  // src/ci/check-orchestrator.ts
14711
15109
  var path25 = __toESM(require("path"));
14712
- var import_graph = require("@harness-engineering/graph");
15110
+ var import_graph8 = require("@harness-engineering/graph");
15111
+ var import_graph9 = require("@harness-engineering/graph");
14713
15112
  var ALL_CHECKS = [
14714
15113
  "validate",
14715
15114
  "deps",
@@ -14786,8 +15185,7 @@ async function runDocsCheck(projectRoot, config) {
14786
15185
  docsDir,
14787
15186
  sourceDir: projectRoot,
14788
15187
  excludePatterns: entropyConfig.excludePatterns || [
14789
- "**/node_modules/**",
14790
- "**/dist/**",
15188
+ ...(0, import_graph8.skipDirGlobs)(),
14791
15189
  "**/*.test.ts",
14792
15190
  "**/fixtures/**"
14793
15191
  ]
@@ -14852,12 +15250,7 @@ async function runSecurityCheck(projectRoot, config) {
14852
15250
  const { glob: globFn } = await import("glob");
14853
15251
  const sourceFiles = await globFn("**/*.{ts,tsx,js,jsx,go,py}", {
14854
15252
  cwd: projectRoot,
14855
- ignore: securityConfig.exclude ?? [
14856
- "**/node_modules/**",
14857
- "**/dist/**",
14858
- "**/*.test.ts",
14859
- "**/fixtures/**"
14860
- ],
15253
+ ignore: securityConfig.exclude ?? [...(0, import_graph8.skipDirGlobs)(), "**/*.test.ts", "**/fixtures/**"],
14861
15254
  absolute: true
14862
15255
  });
14863
15256
  const scanResult = await scanner.scanFiles(sourceFiles);
@@ -14966,12 +15359,12 @@ async function runTraceabilityCheck(projectRoot, config) {
14966
15359
  const traceConfig = config.traceability || {};
14967
15360
  if (traceConfig.enabled === false) return issues;
14968
15361
  const graphDir = path25.join(projectRoot, ".harness", "graph");
14969
- const store = new import_graph.GraphStore();
15362
+ const store = new import_graph9.GraphStore();
14970
15363
  const loaded = await store.load(graphDir);
14971
15364
  if (!loaded) {
14972
15365
  return issues;
14973
15366
  }
14974
- const results = (0, import_graph.queryTraceability)(store);
15367
+ const results = (0, import_graph9.queryTraceability)(store);
14975
15368
  if (results.length === 0) return issues;
14976
15369
  const minCoverage = traceConfig.minCoverage ?? 0;
14977
15370
  const severity = traceConfig.severity ?? "warning";
@@ -17731,7 +18124,7 @@ function parseRepoParts(repo) {
17731
18124
  return { owner: parts[0], repo: parts[1] };
17732
18125
  }
17733
18126
  function sleep2(ms) {
17734
- return new Promise((resolve11) => setTimeout(resolve11, ms));
18127
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
17735
18128
  }
17736
18129
  async function fetchWithRetry(fetchFn, input, init, opts = RETRY_DEFAULTS) {
17737
18130
  let lastResponse;
@@ -18265,8 +18658,8 @@ var syncMutex = Promise.resolve();
18265
18658
  async function fullSync(roadmapPath, adapter2, config, options) {
18266
18659
  const previousSync = syncMutex;
18267
18660
  let releaseMutex;
18268
- syncMutex = new Promise((resolve11) => {
18269
- releaseMutex = resolve11;
18661
+ syncMutex = new Promise((resolve12) => {
18662
+ releaseMutex = resolve12;
18270
18663
  });
18271
18664
  await previousSync;
18272
18665
  try {
@@ -20789,9 +21182,9 @@ function paginate(items, offset, limit) {
20789
21182
  }
20790
21183
 
20791
21184
  // src/caching/stability.ts
20792
- var import_graph2 = require("@harness-engineering/graph");
21185
+ var import_graph10 = require("@harness-engineering/graph");
20793
21186
  var STABILITY_LOOKUP = {};
20794
- for (const [key, tier] of Object.entries(import_graph2.NODE_STABILITY)) {
21187
+ for (const [key, tier] of Object.entries(import_graph10.NODE_STABILITY)) {
20795
21188
  STABILITY_LOOKUP[key] = tier;
20796
21189
  STABILITY_LOOKUP[key.toLowerCase()] = tier;
20797
21190
  }
@@ -21034,7 +21427,7 @@ var POSTHOG_BATCH_URL = "https://app.posthog.com/batch";
21034
21427
  var MAX_ATTEMPTS = 3;
21035
21428
  var TIMEOUT_MS = 5e3;
21036
21429
  function sleep3(ms) {
21037
- return new Promise((resolve11) => setTimeout(resolve11, ms));
21430
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
21038
21431
  }
21039
21432
  async function send(events, apiKey) {
21040
21433
  if (events.length === 0) return;
@@ -21946,6 +22339,7 @@ function assembleCandidateReport(input) {
21946
22339
  ViolationHistorySchema,
21947
22340
  ViolationSchema,
21948
22341
  ViolationSnapshotSchema,
22342
+ WHATWG_BAD_PORTS,
21949
22343
  acquireCompoundLock,
21950
22344
  addProvenance,
21951
22345
  agentConfigRules,
@@ -21971,6 +22365,7 @@ function assembleCandidateReport(input) {
21971
22365
  archiveStream,
21972
22366
  assembleCandidateReport,
21973
22367
  assembleReport,
22368
+ assertPortUsable,
21974
22369
  assertSanitized,
21975
22370
  assignFeature,
21976
22371
  buildDependencyGraph,
@@ -22085,6 +22480,7 @@ function assembleCandidateReport(input) {
22085
22480
  goRules,
22086
22481
  injectionRules,
22087
22482
  insecureDefaultsRules,
22483
+ isBadPort,
22088
22484
  isDuplicateFinding,
22089
22485
  isRegression,
22090
22486
  isSanitizedResult,
@@ -22218,6 +22614,7 @@ function assembleCandidateReport(input) {
22218
22614
  validateAgentConfigs,
22219
22615
  validateAgentsMap,
22220
22616
  validateBoundaries,
22617
+ validateBranchName,
22221
22618
  validateCommitMessage,
22222
22619
  validateConfig,
22223
22620
  validateDependencies,