@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/architecture/matchers.js +4 -2
- package/dist/architecture/matchers.mjs +1 -1
- package/dist/{chunk-NC4RPKD4.mjs → chunk-4UI65RLE.mjs} +5 -2
- package/dist/index.d.mts +60 -1
- package/dist/index.d.ts +60 -1
- package/dist/index.js +491 -94
- package/dist/index.mjs +470 -78
- package/package.json +3 -3
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((
|
|
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
|
-
|
|
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/
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
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
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
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
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
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
|
|
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
|
|
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
|
|
4793
|
-
const
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
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,
|
|
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
|
|
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 =
|
|
4813
|
-
const exportsResult =
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
5081
|
-
const resolved = (0,
|
|
5082
|
-
const sourceExt = (0,
|
|
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,
|
|
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,
|
|
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
|
|
5812
|
+
var import_minimatch5 = require("minimatch");
|
|
5417
5813
|
function fileMatchesPattern(filePath, pattern, rootDir) {
|
|
5418
5814
|
const relativePath = relativePosix(rootDir, filePath);
|
|
5419
|
-
return (0,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
7034
|
+
const backupPath = (0, import_path10.join)(backupDir, `${Date.now()}-${(0, import_path10.basename)(filePath)}`);
|
|
6641
7035
|
try {
|
|
6642
|
-
await mkdir2((0,
|
|
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
|
|
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 (
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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((
|
|
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
|
|
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: [
|
|
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([
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
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((
|
|
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((
|
|
18269
|
-
releaseMutex =
|
|
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
|
|
21185
|
+
var import_graph10 = require("@harness-engineering/graph");
|
|
20793
21186
|
var STABILITY_LOOKUP = {};
|
|
20794
|
-
for (const [key, tier] of Object.entries(
|
|
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((
|
|
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,
|