@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.mjs
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
fileExists,
|
|
47
47
|
findFiles,
|
|
48
48
|
formatOutline,
|
|
49
|
+
getDefaultRegistry,
|
|
49
50
|
getOutline,
|
|
50
51
|
getParser,
|
|
51
52
|
parseFile,
|
|
@@ -56,11 +57,108 @@ import {
|
|
|
56
57
|
runAll,
|
|
57
58
|
validateDependencies,
|
|
58
59
|
violationId
|
|
59
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-4UI65RLE.mjs";
|
|
60
61
|
|
|
61
62
|
// src/index.ts
|
|
62
63
|
export * from "@harness-engineering/types";
|
|
63
64
|
|
|
65
|
+
// src/shared/port.ts
|
|
66
|
+
var WHATWG_BAD_PORTS = Object.freeze([
|
|
67
|
+
1,
|
|
68
|
+
7,
|
|
69
|
+
9,
|
|
70
|
+
11,
|
|
71
|
+
13,
|
|
72
|
+
15,
|
|
73
|
+
17,
|
|
74
|
+
19,
|
|
75
|
+
20,
|
|
76
|
+
21,
|
|
77
|
+
22,
|
|
78
|
+
23,
|
|
79
|
+
25,
|
|
80
|
+
37,
|
|
81
|
+
42,
|
|
82
|
+
43,
|
|
83
|
+
53,
|
|
84
|
+
69,
|
|
85
|
+
77,
|
|
86
|
+
79,
|
|
87
|
+
87,
|
|
88
|
+
95,
|
|
89
|
+
101,
|
|
90
|
+
102,
|
|
91
|
+
103,
|
|
92
|
+
104,
|
|
93
|
+
109,
|
|
94
|
+
110,
|
|
95
|
+
111,
|
|
96
|
+
113,
|
|
97
|
+
115,
|
|
98
|
+
117,
|
|
99
|
+
119,
|
|
100
|
+
123,
|
|
101
|
+
135,
|
|
102
|
+
137,
|
|
103
|
+
139,
|
|
104
|
+
143,
|
|
105
|
+
161,
|
|
106
|
+
179,
|
|
107
|
+
389,
|
|
108
|
+
427,
|
|
109
|
+
465,
|
|
110
|
+
512,
|
|
111
|
+
513,
|
|
112
|
+
514,
|
|
113
|
+
515,
|
|
114
|
+
526,
|
|
115
|
+
530,
|
|
116
|
+
531,
|
|
117
|
+
532,
|
|
118
|
+
540,
|
|
119
|
+
548,
|
|
120
|
+
554,
|
|
121
|
+
556,
|
|
122
|
+
563,
|
|
123
|
+
587,
|
|
124
|
+
601,
|
|
125
|
+
636,
|
|
126
|
+
989,
|
|
127
|
+
990,
|
|
128
|
+
993,
|
|
129
|
+
995,
|
|
130
|
+
1719,
|
|
131
|
+
1720,
|
|
132
|
+
1723,
|
|
133
|
+
2049,
|
|
134
|
+
3659,
|
|
135
|
+
4045,
|
|
136
|
+
4190,
|
|
137
|
+
5060,
|
|
138
|
+
5061,
|
|
139
|
+
6e3,
|
|
140
|
+
6566,
|
|
141
|
+
6665,
|
|
142
|
+
6666,
|
|
143
|
+
6667,
|
|
144
|
+
6668,
|
|
145
|
+
6669,
|
|
146
|
+
6679,
|
|
147
|
+
6697,
|
|
148
|
+
10080
|
|
149
|
+
]);
|
|
150
|
+
var BAD_PORT_SET = new Set(WHATWG_BAD_PORTS);
|
|
151
|
+
function isBadPort(port) {
|
|
152
|
+
return BAD_PORT_SET.has(port);
|
|
153
|
+
}
|
|
154
|
+
function assertPortUsable(port, label = "server") {
|
|
155
|
+
if (isBadPort(port)) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`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.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
64
162
|
// src/validation/file-structure.ts
|
|
65
163
|
async function validateFileStructure(projectPath, conventions) {
|
|
66
164
|
const missing = [];
|
|
@@ -436,7 +534,7 @@ function isAgnixDisabled() {
|
|
|
436
534
|
return v === "1" || v === "true";
|
|
437
535
|
}
|
|
438
536
|
function runAgnix(cwd, strict, binPath, timeoutMs = DEFAULT_AGNIX_TIMEOUT_MS, spawnFn = spawn) {
|
|
439
|
-
return new Promise((
|
|
537
|
+
return new Promise((resolve10) => {
|
|
440
538
|
const args = ["--format", "json"];
|
|
441
539
|
if (strict) args.push("--strict");
|
|
442
540
|
args.push(cwd);
|
|
@@ -450,7 +548,7 @@ function runAgnix(cwd, strict, binPath, timeoutMs = DEFAULT_AGNIX_TIMEOUT_MS, sp
|
|
|
450
548
|
if (settled) return;
|
|
451
549
|
settled = true;
|
|
452
550
|
clearTimeout(timer);
|
|
453
|
-
|
|
551
|
+
resolve10(outcome);
|
|
454
552
|
};
|
|
455
553
|
const timer = setTimeout(() => {
|
|
456
554
|
child.kill("SIGKILL");
|
|
@@ -1615,8 +1713,82 @@ function validateRoadmapMode(config, projectRoot) {
|
|
|
1615
1713
|
return Ok(void 0);
|
|
1616
1714
|
}
|
|
1617
1715
|
|
|
1618
|
-
// src/
|
|
1716
|
+
// src/validation/branch.ts
|
|
1619
1717
|
import { minimatch } from "minimatch";
|
|
1718
|
+
var KEBAB_CASE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
1719
|
+
var TICKET_ID = /^([A-Z0-9]+-[0-9]+)-(.*)$/;
|
|
1720
|
+
function validateBranchName(branchName, config) {
|
|
1721
|
+
for (const pattern of config.ignore) {
|
|
1722
|
+
if (minimatch(branchName, pattern)) {
|
|
1723
|
+
return { valid: true, branchName };
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
if (config.customRegex) {
|
|
1727
|
+
const regex = new RegExp(config.customRegex);
|
|
1728
|
+
if (!regex.test(branchName)) {
|
|
1729
|
+
return {
|
|
1730
|
+
valid: false,
|
|
1731
|
+
branchName,
|
|
1732
|
+
message: `Branch name "${branchName}" does not match the custom regex: ${config.customRegex}`
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
return { valid: true, branchName };
|
|
1736
|
+
}
|
|
1737
|
+
const parts = branchName.split("/");
|
|
1738
|
+
if (parts.length < 2) {
|
|
1739
|
+
return {
|
|
1740
|
+
valid: false,
|
|
1741
|
+
branchName,
|
|
1742
|
+
message: `Branch name "${branchName}" must have a prefix followed by a slash (e.g., "feat/my-feature").`,
|
|
1743
|
+
suggestion: `Try renaming to "feat/${branchName}" or "fix/${branchName}".`
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
const prefix = parts[0];
|
|
1747
|
+
const slug = parts.slice(1).join("/");
|
|
1748
|
+
if (!config.prefixes.includes(prefix)) {
|
|
1749
|
+
return {
|
|
1750
|
+
valid: false,
|
|
1751
|
+
branchName,
|
|
1752
|
+
message: `Prefix "${prefix}" is not allowed.`,
|
|
1753
|
+
suggestion: `Allowed prefixes: ${config.prefixes.join(", ")}.`
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
if (config.enforceKebabCase) {
|
|
1757
|
+
for (const part of slug.split("/")) {
|
|
1758
|
+
const ticketMatch = part.match(TICKET_ID);
|
|
1759
|
+
if (ticketMatch) {
|
|
1760
|
+
const rest = ticketMatch[2];
|
|
1761
|
+
if (rest && !KEBAB_CASE.test(rest)) {
|
|
1762
|
+
return {
|
|
1763
|
+
valid: false,
|
|
1764
|
+
branchName,
|
|
1765
|
+
message: `Branch slug part "${part}" does not follow kebab-case after the ticket ID.`,
|
|
1766
|
+
suggestion: `Ensure the description after "${ticketMatch[1]}" uses kebab-case (lowercase, single hyphens, no leading/trailing hyphen).`
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
} else if (!KEBAB_CASE.test(part)) {
|
|
1770
|
+
return {
|
|
1771
|
+
valid: false,
|
|
1772
|
+
branchName,
|
|
1773
|
+
message: `Branch slug part "${part}" must be in kebab-case (lowercase, single hyphens, no leading/trailing hyphen).`,
|
|
1774
|
+
suggestion: `Change "${part}" to match the convention.`
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
if (typeof config.maxLength === "number" && config.maxLength > 0 && slug.length > config.maxLength) {
|
|
1780
|
+
return {
|
|
1781
|
+
valid: false,
|
|
1782
|
+
branchName,
|
|
1783
|
+
message: `Branch slug is ${slug.length} characters; max allowed is ${config.maxLength}.`,
|
|
1784
|
+
suggestion: `Shorten the description after "${prefix}/" to ${config.maxLength} characters or fewer.`
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
return { valid: true, branchName };
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// src/context/doc-coverage.ts
|
|
1791
|
+
import { minimatch as minimatch2 } from "minimatch";
|
|
1620
1792
|
import { basename as basename2 } from "path";
|
|
1621
1793
|
function determineImportance(filePath) {
|
|
1622
1794
|
const name = basename2(filePath).toLowerCase();
|
|
@@ -1659,7 +1831,7 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
1659
1831
|
const filteredSourceFiles = sourceFiles.filter((file) => {
|
|
1660
1832
|
const relativePath = relativePosix(sourceDir, file);
|
|
1661
1833
|
return !excludePatterns.some((pattern) => {
|
|
1662
|
-
return
|
|
1834
|
+
return minimatch2(relativePath, pattern, { dot: true }) || minimatch2(file, pattern, { dot: true });
|
|
1663
1835
|
});
|
|
1664
1836
|
});
|
|
1665
1837
|
const docFiles = await findFiles("**/*.md", docsDir);
|
|
@@ -2912,8 +3084,12 @@ function parseProtectedRegions(files) {
|
|
|
2912
3084
|
}
|
|
2913
3085
|
|
|
2914
3086
|
// src/entropy/snapshot.ts
|
|
3087
|
+
import { skipDirGlobs } from "@harness-engineering/graph";
|
|
3088
|
+
import { resolve as resolve5 } from "path";
|
|
3089
|
+
import { minimatch as minimatch3 } from "minimatch";
|
|
3090
|
+
|
|
3091
|
+
// src/entropy/entry-points.ts
|
|
2915
3092
|
import { join as join15, resolve as resolve4 } from "path";
|
|
2916
|
-
import { minimatch as minimatch2 } from "minimatch";
|
|
2917
3093
|
function collectFieldEntries(rootDir, field) {
|
|
2918
3094
|
if (typeof field === "string") return [resolve4(rootDir, field)];
|
|
2919
3095
|
if (typeof field === "object" && field !== null) {
|
|
@@ -2927,47 +3103,263 @@ function extractPackageEntries(rootDir, pkg) {
|
|
|
2927
3103
|
if (entries.length === 0 && typeof pkg["main"] === "string") {
|
|
2928
3104
|
entries.push(resolve4(rootDir, pkg["main"]));
|
|
2929
3105
|
}
|
|
2930
|
-
if (pkg["bin"])
|
|
2931
|
-
entries.push(...collectFieldEntries(rootDir, pkg["bin"]));
|
|
2932
|
-
}
|
|
3106
|
+
if (pkg["bin"]) entries.push(...collectFieldEntries(rootDir, pkg["bin"]));
|
|
2933
3107
|
return entries;
|
|
2934
3108
|
}
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
3109
|
+
var TS_HINTS = ['Add "exports" or "main" to package.json', "Create src/index.ts"];
|
|
3110
|
+
var TS_CONVENTIONS = ["src/index.ts", "src/main.ts", "src/index.tsx", "index.ts", "main.ts"];
|
|
3111
|
+
async function readPackageJsonEntries(rootDir, pkgPath) {
|
|
3112
|
+
const content = await readFileContent(pkgPath);
|
|
3113
|
+
if (!content.ok) return [];
|
|
3114
|
+
try {
|
|
3115
|
+
const pkg = JSON.parse(content.value);
|
|
3116
|
+
return extractPackageEntries(rootDir, pkg);
|
|
3117
|
+
} catch {
|
|
3118
|
+
return [];
|
|
2938
3119
|
}
|
|
3120
|
+
}
|
|
3121
|
+
async function resolveTypeScript(rootDir) {
|
|
2939
3122
|
const pkgPath = join15(rootDir, "package.json");
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
const entries = extractPackageEntries(rootDir, pkg);
|
|
2946
|
-
if (entries.length > 0) return Ok(entries);
|
|
2947
|
-
} catch {
|
|
2948
|
-
}
|
|
3123
|
+
const detected = await fileExists(pkgPath);
|
|
3124
|
+
if (detected) {
|
|
3125
|
+
const entries = await readPackageJsonEntries(rootDir, pkgPath);
|
|
3126
|
+
if (entries.length > 0) {
|
|
3127
|
+
return { language: "typescript", detected: true, entries, hints: TS_HINTS };
|
|
2949
3128
|
}
|
|
2950
3129
|
}
|
|
2951
|
-
const
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
return Ok([convPath]);
|
|
3130
|
+
for (const conv of TS_CONVENTIONS) {
|
|
3131
|
+
const p = join15(rootDir, conv);
|
|
3132
|
+
if (await fileExists(p)) {
|
|
3133
|
+
return { language: "typescript", detected: true, entries: [p], hints: TS_HINTS };
|
|
2956
3134
|
}
|
|
2957
3135
|
}
|
|
3136
|
+
return { language: "typescript", detected, entries: [], hints: TS_HINTS };
|
|
3137
|
+
}
|
|
3138
|
+
var PYTHON_HINTS = [
|
|
3139
|
+
"Add an entry to [project.scripts] in pyproject.toml",
|
|
3140
|
+
"Create main.py or <package>/__main__.py"
|
|
3141
|
+
];
|
|
3142
|
+
var PYTHON_CONVENTIONS = [
|
|
3143
|
+
"__main__.py",
|
|
3144
|
+
"main.py",
|
|
3145
|
+
"app.py",
|
|
3146
|
+
"src/__main__.py",
|
|
3147
|
+
"src/main.py",
|
|
3148
|
+
"src/app.py"
|
|
3149
|
+
];
|
|
3150
|
+
async function detectPython(rootDir) {
|
|
3151
|
+
return await fileExists(join15(rootDir, "pyproject.toml")) || await fileExists(join15(rootDir, "setup.py")) || await fileExists(join15(rootDir, "requirements.txt"));
|
|
3152
|
+
}
|
|
3153
|
+
async function readPyProject(rootDir) {
|
|
3154
|
+
const pyproject = join15(rootDir, "pyproject.toml");
|
|
3155
|
+
if (!await fileExists(pyproject)) return { scriptTargets: [] };
|
|
3156
|
+
const content = await readFileContent(pyproject);
|
|
3157
|
+
if (!content.ok) return { scriptTargets: [] };
|
|
3158
|
+
return parsePyProject(content.value);
|
|
3159
|
+
}
|
|
3160
|
+
async function resolveScriptTargetEntry(rootDir, target) {
|
|
3161
|
+
const mod = target.split(":")[0];
|
|
3162
|
+
if (!mod) return void 0;
|
|
3163
|
+
const relPath2 = mod.replaceAll(".", "/") + ".py";
|
|
3164
|
+
for (const candidate of [join15(rootDir, relPath2), join15(rootDir, "src", relPath2)]) {
|
|
3165
|
+
if (await fileExists(candidate)) return candidate;
|
|
3166
|
+
}
|
|
3167
|
+
return void 0;
|
|
3168
|
+
}
|
|
3169
|
+
async function resolvePythonFromScripts(rootDir, targets) {
|
|
3170
|
+
const entries = [];
|
|
3171
|
+
for (const target of targets) {
|
|
3172
|
+
const entry = await resolveScriptTargetEntry(rootDir, target);
|
|
3173
|
+
if (entry) entries.push(entry);
|
|
3174
|
+
}
|
|
3175
|
+
return entries;
|
|
3176
|
+
}
|
|
3177
|
+
async function resolvePythonFromProjectName(rootDir, projectName) {
|
|
3178
|
+
if (!projectName) return [];
|
|
3179
|
+
const normalized = projectName.replaceAll("-", "_");
|
|
3180
|
+
const candidates = [
|
|
3181
|
+
join15(rootDir, normalized, "__init__.py"),
|
|
3182
|
+
join15(rootDir, normalized, "__main__.py"),
|
|
3183
|
+
join15(rootDir, "src", normalized, "__init__.py"),
|
|
3184
|
+
join15(rootDir, "src", normalized, "__main__.py")
|
|
3185
|
+
];
|
|
3186
|
+
const entries = [];
|
|
3187
|
+
for (const c of candidates) {
|
|
3188
|
+
if (await fileExists(c)) entries.push(c);
|
|
3189
|
+
}
|
|
3190
|
+
return entries;
|
|
3191
|
+
}
|
|
3192
|
+
async function resolvePythonConventions(rootDir) {
|
|
3193
|
+
const entries = [];
|
|
3194
|
+
for (const conv of PYTHON_CONVENTIONS) {
|
|
3195
|
+
const p = join15(rootDir, conv);
|
|
3196
|
+
if (await fileExists(p)) entries.push(p);
|
|
3197
|
+
}
|
|
3198
|
+
return entries;
|
|
3199
|
+
}
|
|
3200
|
+
async function findPythonTopLevelPackages(rootDir) {
|
|
3201
|
+
const found = await findFiles("*/__init__.py", rootDir);
|
|
3202
|
+
if (found.length > 0) return found;
|
|
3203
|
+
return findFiles("src/*/__init__.py", rootDir);
|
|
3204
|
+
}
|
|
3205
|
+
async function resolvePython(rootDir) {
|
|
3206
|
+
if (!await detectPython(rootDir)) {
|
|
3207
|
+
return { language: "python", detected: false, entries: [], hints: PYTHON_HINTS };
|
|
3208
|
+
}
|
|
3209
|
+
const info = await readPyProject(rootDir);
|
|
3210
|
+
const strategies = [
|
|
3211
|
+
() => resolvePythonFromScripts(rootDir, info.scriptTargets),
|
|
3212
|
+
() => resolvePythonFromProjectName(rootDir, info.projectName),
|
|
3213
|
+
() => resolvePythonConventions(rootDir),
|
|
3214
|
+
() => findPythonTopLevelPackages(rootDir)
|
|
3215
|
+
];
|
|
3216
|
+
for (const strategy of strategies) {
|
|
3217
|
+
const entries = await strategy();
|
|
3218
|
+
if (entries.length > 0) {
|
|
3219
|
+
return { language: "python", detected: true, entries, hints: PYTHON_HINTS };
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
return { language: "python", detected: true, entries: [], hints: PYTHON_HINTS };
|
|
3223
|
+
}
|
|
3224
|
+
async function resolveGo(rootDir) {
|
|
3225
|
+
const hints = ["Create main.go at the project root, or use the cmd/<name>/main.go layout"];
|
|
3226
|
+
const detected = await fileExists(join15(rootDir, "go.mod"));
|
|
3227
|
+
if (!detected) return { language: "go", detected: false, entries: [], hints };
|
|
3228
|
+
const entries = [];
|
|
3229
|
+
const mainGo = join15(rootDir, "main.go");
|
|
3230
|
+
if (await fileExists(mainGo)) entries.push(mainGo);
|
|
3231
|
+
entries.push(...await findFiles("cmd/*/main.go", rootDir));
|
|
3232
|
+
return { language: "go", detected: true, entries, hints };
|
|
3233
|
+
}
|
|
3234
|
+
async function resolveRust(rootDir) {
|
|
3235
|
+
const hints = [
|
|
3236
|
+
"Create src/main.rs or src/lib.rs",
|
|
3237
|
+
"Declare [[bin]] entries with a `path` in Cargo.toml"
|
|
3238
|
+
];
|
|
3239
|
+
const cargoPath = join15(rootDir, "Cargo.toml");
|
|
3240
|
+
const detected = await fileExists(cargoPath);
|
|
3241
|
+
if (!detected) return { language: "rust", detected: false, entries: [], hints };
|
|
3242
|
+
const entries = [];
|
|
3243
|
+
const content = await readFileContent(cargoPath);
|
|
3244
|
+
if (content.ok) {
|
|
3245
|
+
for (const bp of parseCargoBinPaths(content.value)) {
|
|
3246
|
+
const abs = resolve4(rootDir, bp);
|
|
3247
|
+
if (await fileExists(abs)) entries.push(abs);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
if (entries.length === 0) {
|
|
3251
|
+
for (const conv of ["src/main.rs", "src/lib.rs"]) {
|
|
3252
|
+
const p = join15(rootDir, conv);
|
|
3253
|
+
if (await fileExists(p)) entries.push(p);
|
|
3254
|
+
}
|
|
3255
|
+
entries.push(...await findFiles("src/bin/*.rs", rootDir));
|
|
3256
|
+
}
|
|
3257
|
+
return { language: "rust", detected: true, entries, hints };
|
|
3258
|
+
}
|
|
3259
|
+
async function resolveJava(rootDir) {
|
|
3260
|
+
const hints = [
|
|
3261
|
+
"Place an entry class at src/main/java/**/Main.java (or *Application.java for Spring Boot)"
|
|
3262
|
+
];
|
|
3263
|
+
const detected = await fileExists(join15(rootDir, "pom.xml")) || await fileExists(join15(rootDir, "build.gradle")) || await fileExists(join15(rootDir, "build.gradle.kts"));
|
|
3264
|
+
if (!detected) return { language: "java", detected: false, entries: [], hints };
|
|
3265
|
+
const entries = [];
|
|
3266
|
+
entries.push(...await findFiles("src/main/java/**/Main.java", rootDir));
|
|
3267
|
+
entries.push(...await findFiles("src/main/java/**/*Application.java", rootDir));
|
|
3268
|
+
return { language: "java", detected: true, entries, hints };
|
|
3269
|
+
}
|
|
3270
|
+
function parseTomlLine(raw) {
|
|
3271
|
+
const line = raw.replace(/(^|\s)#.*$/, "").trim();
|
|
3272
|
+
if (!line) return {};
|
|
3273
|
+
const sectionMatch = /^\[([^\]]+)\]$/.exec(line);
|
|
3274
|
+
if (sectionMatch) return { section: sectionMatch[1] ?? "" };
|
|
3275
|
+
const eq = line.indexOf("=");
|
|
3276
|
+
if (eq <= 0) return {};
|
|
3277
|
+
return {
|
|
3278
|
+
key: line.slice(0, eq).trim(),
|
|
3279
|
+
value: stripTomlString2(line.slice(eq + 1).trim())
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
function parsePyProject(content) {
|
|
3283
|
+
const result = { scriptTargets: [] };
|
|
3284
|
+
let section = null;
|
|
3285
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
3286
|
+
const parsed = parseTomlLine(raw);
|
|
3287
|
+
if (parsed.section !== void 0) {
|
|
3288
|
+
section = parsed.section;
|
|
3289
|
+
continue;
|
|
3290
|
+
}
|
|
3291
|
+
if (parsed.key === void 0 || parsed.value === void 0) continue;
|
|
3292
|
+
if (section === "project" && parsed.key === "name") result.projectName = parsed.value;
|
|
3293
|
+
else if (section === "project.scripts") result.scriptTargets.push(parsed.value);
|
|
3294
|
+
}
|
|
3295
|
+
return result;
|
|
3296
|
+
}
|
|
3297
|
+
function parseCargoBinPaths(content) {
|
|
3298
|
+
const paths = [];
|
|
3299
|
+
let inBin = false;
|
|
3300
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
3301
|
+
const line = raw.replace(/(^|\s)#.*$/, "").trim();
|
|
3302
|
+
if (!line) continue;
|
|
3303
|
+
if (line === "[[bin]]") {
|
|
3304
|
+
inBin = true;
|
|
3305
|
+
continue;
|
|
3306
|
+
}
|
|
3307
|
+
if (line.startsWith("[")) {
|
|
3308
|
+
inBin = false;
|
|
3309
|
+
continue;
|
|
3310
|
+
}
|
|
3311
|
+
if (!inBin) continue;
|
|
3312
|
+
const eq = line.indexOf("=");
|
|
3313
|
+
if (eq <= 0) continue;
|
|
3314
|
+
const key = line.slice(0, eq).trim();
|
|
3315
|
+
if (key === "path") paths.push(stripTomlString2(line.slice(eq + 1).trim()));
|
|
3316
|
+
}
|
|
3317
|
+
return paths;
|
|
3318
|
+
}
|
|
3319
|
+
function stripTomlString2(value) {
|
|
3320
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3321
|
+
return value.slice(1, -1);
|
|
3322
|
+
}
|
|
3323
|
+
return value;
|
|
3324
|
+
}
|
|
3325
|
+
async function resolveEntryPoints(rootDir, explicitEntries) {
|
|
3326
|
+
if (explicitEntries && explicitEntries.length > 0) {
|
|
3327
|
+
return Ok(explicitEntries.map((e) => resolve4(rootDir, e)));
|
|
3328
|
+
}
|
|
3329
|
+
const resolvers = [resolveTypeScript, resolvePython, resolveGo, resolveRust, resolveJava];
|
|
3330
|
+
const resolutions = [];
|
|
3331
|
+
for (const resolver of resolvers) {
|
|
3332
|
+
const res = await resolver(rootDir);
|
|
3333
|
+
resolutions.push(res);
|
|
3334
|
+
if (res.entries.length > 0) return Ok(res.entries);
|
|
3335
|
+
}
|
|
3336
|
+
const detectedLangs = resolutions.filter((r) => r.detected);
|
|
3337
|
+
const suggestions = detectedLangs.length > 0 ? detectedLangs.flatMap((r) => r.hints) : resolutions.flatMap((r) => r.hints);
|
|
3338
|
+
suggestions.push("Specify entryPoints in config");
|
|
3339
|
+
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";
|
|
2958
3340
|
return Err(
|
|
2959
3341
|
createEntropyError(
|
|
2960
3342
|
"ENTRY_POINT_NOT_FOUND",
|
|
2961
3343
|
"Could not resolve entry points",
|
|
2962
|
-
{ reason
|
|
2963
|
-
|
|
2964
|
-
'Add "exports" or "main" to package.json',
|
|
2965
|
-
"Create src/index.ts",
|
|
2966
|
-
"Specify entryPoints in config"
|
|
2967
|
-
]
|
|
3344
|
+
{ reason },
|
|
3345
|
+
suggestions
|
|
2968
3346
|
)
|
|
2969
3347
|
);
|
|
2970
3348
|
}
|
|
3349
|
+
|
|
3350
|
+
// src/entropy/snapshot.ts
|
|
3351
|
+
var DEFAULT_INCLUDE_PATTERNS = [
|
|
3352
|
+
"**/*.ts",
|
|
3353
|
+
"**/*.tsx",
|
|
3354
|
+
"**/*.js",
|
|
3355
|
+
"**/*.jsx",
|
|
3356
|
+
"**/*.mjs",
|
|
3357
|
+
"**/*.cjs",
|
|
3358
|
+
"**/*.py",
|
|
3359
|
+
"**/*.go",
|
|
3360
|
+
"**/*.rs",
|
|
3361
|
+
"**/*.java"
|
|
3362
|
+
];
|
|
2971
3363
|
function extractCodeBlocks(content) {
|
|
2972
3364
|
const blocks = [];
|
|
2973
3365
|
const lines = content.split("\n");
|
|
@@ -3061,6 +3453,7 @@ function extractSymbolsFromNode(node) {
|
|
|
3061
3453
|
return [];
|
|
3062
3454
|
}
|
|
3063
3455
|
function extractInternalSymbols(ast) {
|
|
3456
|
+
if (ast.language !== "typescript" && ast.language !== "javascript") return [];
|
|
3064
3457
|
const body = ast.body;
|
|
3065
3458
|
if (!body?.body) return [];
|
|
3066
3459
|
const nodes = body.body;
|
|
@@ -3071,6 +3464,7 @@ function toJSDocComment(comment) {
|
|
|
3071
3464
|
return { content: comment.value, line: comment.loc?.start?.line || 0 };
|
|
3072
3465
|
}
|
|
3073
3466
|
function extractJSDocComments(ast) {
|
|
3467
|
+
if (ast.language !== "typescript" && ast.language !== "javascript") return [];
|
|
3074
3468
|
const body = ast.body;
|
|
3075
3469
|
if (!body?.comments) return [];
|
|
3076
3470
|
return body.comments.flatMap((c) => {
|
|
@@ -3129,19 +3523,16 @@ function extractAllCodeReferences(docs) {
|
|
|
3129
3523
|
}
|
|
3130
3524
|
async function buildSnapshot(config) {
|
|
3131
3525
|
const startTime = Date.now();
|
|
3132
|
-
const
|
|
3133
|
-
const rootDir = resolve4(config.rootDir);
|
|
3526
|
+
const rootDir = resolve5(config.rootDir);
|
|
3134
3527
|
const entryPointsResult = await resolveEntryPoints(rootDir, config.entryPoints);
|
|
3135
3528
|
if (!entryPointsResult.ok) {
|
|
3136
3529
|
return Err(entryPointsResult.error);
|
|
3137
3530
|
}
|
|
3138
|
-
const
|
|
3139
|
-
const
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
"**/*.spec.ts"
|
|
3144
|
-
];
|
|
3531
|
+
const registry = getDefaultRegistry();
|
|
3532
|
+
const singleParser = config.parser;
|
|
3533
|
+
const parserForFile = (filePath) => singleParser ?? registry.getForFile(filePath);
|
|
3534
|
+
const includePatterns = config.include || DEFAULT_INCLUDE_PATTERNS;
|
|
3535
|
+
const excludePatterns = config.exclude || [...skipDirGlobs(), "**/*.test.ts", "**/*.spec.ts"];
|
|
3145
3536
|
let sourceFilePaths = [];
|
|
3146
3537
|
for (const pattern of includePatterns) {
|
|
3147
3538
|
const files2 = await findFiles(pattern, rootDir);
|
|
@@ -3149,14 +3540,16 @@ async function buildSnapshot(config) {
|
|
|
3149
3540
|
}
|
|
3150
3541
|
sourceFilePaths = sourceFilePaths.filter((f) => {
|
|
3151
3542
|
const rel = relativePosix(rootDir, f);
|
|
3152
|
-
return !excludePatterns.some((p) =>
|
|
3543
|
+
return !excludePatterns.some((p) => minimatch3(rel, p));
|
|
3153
3544
|
});
|
|
3154
3545
|
const files = [];
|
|
3155
3546
|
for (const filePath of sourceFilePaths) {
|
|
3156
|
-
const
|
|
3547
|
+
const fileParser = parserForFile(filePath);
|
|
3548
|
+
if (!fileParser) continue;
|
|
3549
|
+
const parseResult = await fileParser.parseFile(filePath);
|
|
3157
3550
|
if (!parseResult.ok) continue;
|
|
3158
|
-
const importsResult =
|
|
3159
|
-
const exportsResult =
|
|
3551
|
+
const importsResult = fileParser.extractImports(parseResult.value);
|
|
3552
|
+
const exportsResult = fileParser.extractExports(parseResult.value);
|
|
3160
3553
|
const internalSymbols = extractInternalSymbols(parseResult.value);
|
|
3161
3554
|
const jsDocComments = extractJSDocComments(parseResult.value);
|
|
3162
3555
|
files.push({
|
|
@@ -3168,7 +3561,7 @@ async function buildSnapshot(config) {
|
|
|
3168
3561
|
jsDocComments
|
|
3169
3562
|
});
|
|
3170
3563
|
}
|
|
3171
|
-
const graphResult = await buildDependencyGraph(sourceFilePaths,
|
|
3564
|
+
const graphResult = await buildDependencyGraph(sourceFilePaths, singleParser ?? registry);
|
|
3172
3565
|
const dependencyGraph = graphResult.ok ? graphResult.value : { nodes: [], edges: [] };
|
|
3173
3566
|
const docPatterns = config.docPaths || ["docs/**/*.md", "README.md", "**/README.md"];
|
|
3174
3567
|
let docFilePaths = [];
|
|
@@ -3201,7 +3594,7 @@ async function buildSnapshot(config) {
|
|
|
3201
3594
|
}
|
|
3202
3595
|
|
|
3203
3596
|
// src/entropy/detectors/drift.ts
|
|
3204
|
-
import { dirname as dirname5, resolve as
|
|
3597
|
+
import { dirname as dirname5, resolve as resolve6 } from "path";
|
|
3205
3598
|
function initLevenshteinMatrix(aLen, bLen) {
|
|
3206
3599
|
const matrix = [];
|
|
3207
3600
|
for (let i = 0; i <= bLen; i++) {
|
|
@@ -3313,7 +3706,7 @@ async function checkStructureDrift(snapshot, _config) {
|
|
|
3313
3706
|
for (const doc of snapshot.docs) {
|
|
3314
3707
|
const fileLinks = extractFileLinks(doc.content);
|
|
3315
3708
|
for (const { link, line } of fileLinks) {
|
|
3316
|
-
const resolvedPath =
|
|
3709
|
+
const resolvedPath = resolve6(dirname5(doc.path), link);
|
|
3317
3710
|
const exists = await fileExists(resolvedPath);
|
|
3318
3711
|
if (!exists) {
|
|
3319
3712
|
drifts.push({
|
|
@@ -3404,7 +3797,7 @@ async function detectDocDrift(snapshot, config, graphDriftData) {
|
|
|
3404
3797
|
}
|
|
3405
3798
|
|
|
3406
3799
|
// src/entropy/detectors/dead-code.ts
|
|
3407
|
-
import { dirname as dirname6, extname, resolve as
|
|
3800
|
+
import { dirname as dirname6, extname, resolve as resolve7 } from "path";
|
|
3408
3801
|
var JS_EXT_FALLBACKS = {
|
|
3409
3802
|
".js": [".ts", ".tsx", ".jsx"],
|
|
3410
3803
|
".jsx": [".tsx"],
|
|
@@ -3424,7 +3817,7 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
|
|
|
3424
3817
|
}
|
|
3425
3818
|
const hasFile = fileIndex ? (p) => fileIndex.has(p) : (p) => snapshot.files.some((f) => f.path === p);
|
|
3426
3819
|
const fromDir = dirname6(fromFile);
|
|
3427
|
-
const resolved =
|
|
3820
|
+
const resolved = resolve7(fromDir, importSource);
|
|
3428
3821
|
const sourceExt = extname(resolved);
|
|
3429
3822
|
const fallbacks = JS_EXT_FALLBACKS[sourceExt];
|
|
3430
3823
|
if (fallbacks) {
|
|
@@ -3434,7 +3827,7 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
|
|
|
3434
3827
|
if (hasFile(candidate)) return candidate;
|
|
3435
3828
|
}
|
|
3436
3829
|
for (const indexExt of [".ts", ".tsx", ".jsx"]) {
|
|
3437
|
-
const indexPath2 =
|
|
3830
|
+
const indexPath2 = resolve7(base, "index" + indexExt);
|
|
3438
3831
|
if (hasFile(indexPath2)) return indexPath2;
|
|
3439
3832
|
}
|
|
3440
3833
|
}
|
|
@@ -3445,7 +3838,7 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
|
|
|
3445
3838
|
if (hasFile(candidate)) return candidate;
|
|
3446
3839
|
}
|
|
3447
3840
|
for (const indexExt of [".ts", ".tsx"]) {
|
|
3448
|
-
const indexPath2 =
|
|
3841
|
+
const indexPath2 = resolve7(resolved, "index" + indexExt);
|
|
3449
3842
|
if (hasFile(indexPath2)) return indexPath2;
|
|
3450
3843
|
}
|
|
3451
3844
|
}
|
|
@@ -3759,10 +4152,10 @@ async function detectDeadCode(snapshot, graphDeadCodeData, protectedRegions) {
|
|
|
3759
4152
|
}
|
|
3760
4153
|
|
|
3761
4154
|
// src/entropy/detectors/patterns.ts
|
|
3762
|
-
import { minimatch as
|
|
4155
|
+
import { minimatch as minimatch4 } from "minimatch";
|
|
3763
4156
|
function fileMatchesPattern(filePath, pattern, rootDir) {
|
|
3764
4157
|
const relativePath = relativePosix(rootDir, filePath);
|
|
3765
|
-
return
|
|
4158
|
+
return minimatch4(relativePath, pattern);
|
|
3766
4159
|
}
|
|
3767
4160
|
var CONVENTION_DESCRIPTIONS = {
|
|
3768
4161
|
camelCase: "camelCase (e.g., myFunction)",
|
|
@@ -3962,6 +4355,7 @@ async function detectPatternViolations(snapshot, config) {
|
|
|
3962
4355
|
// src/entropy/detectors/size-budget.ts
|
|
3963
4356
|
import { readdirSync, statSync as statSync2 } from "fs";
|
|
3964
4357
|
import { join as join16 } from "path";
|
|
4358
|
+
import { DEFAULT_SKIP_DIRS } from "@harness-engineering/graph";
|
|
3965
4359
|
function parseSize(size) {
|
|
3966
4360
|
const match = size.trim().match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB|B)?$/i);
|
|
3967
4361
|
if (!match) return 0;
|
|
@@ -3987,7 +4381,7 @@ function dirSize(dirPath) {
|
|
|
3987
4381
|
return 0;
|
|
3988
4382
|
}
|
|
3989
4383
|
for (const entry of entries) {
|
|
3990
|
-
if (entry
|
|
4384
|
+
if (DEFAULT_SKIP_DIRS.has(entry)) continue;
|
|
3991
4385
|
const fullPath = join16(dirPath, entry);
|
|
3992
4386
|
try {
|
|
3993
4387
|
const stat2 = statSync2(fullPath);
|
|
@@ -4164,10 +4558,7 @@ var EntropyAnalyzer = class {
|
|
|
4164
4558
|
snapshot;
|
|
4165
4559
|
report;
|
|
4166
4560
|
constructor(config) {
|
|
4167
|
-
this.config = {
|
|
4168
|
-
...config,
|
|
4169
|
-
parser: config.parser || new TypeScriptParser()
|
|
4170
|
-
};
|
|
4561
|
+
this.config = { ...config };
|
|
4171
4562
|
}
|
|
4172
4563
|
/**
|
|
4173
4564
|
* Run full entropy analysis.
|
|
@@ -5176,7 +5567,7 @@ var RegressionDetector = class {
|
|
|
5176
5567
|
// src/performance/critical-path.ts
|
|
5177
5568
|
import * as fs7 from "fs";
|
|
5178
5569
|
import * as path4 from "path";
|
|
5179
|
-
|
|
5570
|
+
import { DEFAULT_SKIP_DIRS as DEFAULT_SKIP_DIRS2 } from "@harness-engineering/graph";
|
|
5180
5571
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
5181
5572
|
var FUNCTION_DECL_RE = /(?:export\s+)?(?:async\s+)?function\s+(\w+)/;
|
|
5182
5573
|
var CONST_DECL_RE = /(?:export\s+)?(?:const|let)\s+(\w+)\s*=/;
|
|
@@ -5243,7 +5634,7 @@ var CriticalPathResolver = class {
|
|
|
5243
5634
|
}
|
|
5244
5635
|
for (const item of items) {
|
|
5245
5636
|
if (item.isDirectory()) {
|
|
5246
|
-
if (
|
|
5637
|
+
if (DEFAULT_SKIP_DIRS2.has(item.name)) continue;
|
|
5247
5638
|
this.walkDir(path4.join(dir, item.name), entries);
|
|
5248
5639
|
} else if (item.isFile() && SOURCE_EXTENSIONS.has(path4.extname(item.name))) {
|
|
5249
5640
|
this.scanFile(path4.join(dir, item.name), entries);
|
|
@@ -8262,7 +8653,7 @@ function checkOverlap(newEntry, existingEntries, options) {
|
|
|
8262
8653
|
var LOCK_RETRIES = 3;
|
|
8263
8654
|
var LOCK_BACKOFFS = [50, 100, 200];
|
|
8264
8655
|
function sleep(ms) {
|
|
8265
|
-
return new Promise((
|
|
8656
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
8266
8657
|
}
|
|
8267
8658
|
async function acquireFileLock(lockPath) {
|
|
8268
8659
|
for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
|
|
@@ -9475,7 +9866,7 @@ async function runMultiTurnPipeline(initialContext, turnExecutor, options) {
|
|
|
9475
9866
|
|
|
9476
9867
|
// src/security/scanner.ts
|
|
9477
9868
|
import * as fs28 from "fs/promises";
|
|
9478
|
-
import { minimatch as
|
|
9869
|
+
import { minimatch as minimatch5 } from "minimatch";
|
|
9479
9870
|
|
|
9480
9871
|
// src/security/rules/registry.ts
|
|
9481
9872
|
var RuleRegistry = class {
|
|
@@ -9507,13 +9898,15 @@ var RuleRegistry = class {
|
|
|
9507
9898
|
|
|
9508
9899
|
// src/security/config.ts
|
|
9509
9900
|
import { z as z10 } from "zod";
|
|
9901
|
+
import { skipDirGlobs as skipDirGlobs3 } from "@harness-engineering/graph";
|
|
9510
9902
|
|
|
9511
9903
|
// src/security/types.ts
|
|
9904
|
+
import { skipDirGlobs as skipDirGlobs2 } from "@harness-engineering/graph";
|
|
9512
9905
|
var DEFAULT_SECURITY_CONFIG = {
|
|
9513
9906
|
enabled: true,
|
|
9514
9907
|
strict: false,
|
|
9515
9908
|
rules: {},
|
|
9516
|
-
exclude: [
|
|
9909
|
+
exclude: [...skipDirGlobs2(), "**/*.test.ts", "**/fixtures/**"]
|
|
9517
9910
|
};
|
|
9518
9911
|
|
|
9519
9912
|
// src/security/config.ts
|
|
@@ -9522,7 +9915,7 @@ var SecurityConfigSchema = z10.object({
|
|
|
9522
9915
|
enabled: z10.boolean().default(true),
|
|
9523
9916
|
strict: z10.boolean().default(false),
|
|
9524
9917
|
rules: z10.record(z10.string(), RuleOverrideSchema).optional().default({}),
|
|
9525
|
-
exclude: z10.array(z10.string()).optional().default([
|
|
9918
|
+
exclude: z10.array(z10.string()).optional().default([...skipDirGlobs3(), "**/*.test.ts", "**/fixtures/**"]),
|
|
9526
9919
|
external: z10.object({
|
|
9527
9920
|
semgrep: z10.object({
|
|
9528
9921
|
enabled: z10.union([z10.literal("auto"), z10.boolean()]).default("auto"),
|
|
@@ -10433,7 +10826,7 @@ var SecurityScanner = class {
|
|
|
10433
10826
|
const applicableRules = this.activeRules.filter((rule) => {
|
|
10434
10827
|
if (!rule.fileGlob) return true;
|
|
10435
10828
|
const globs = rule.fileGlob.split(",").map((g) => g.trim());
|
|
10436
|
-
return globs.some((glob5) =>
|
|
10829
|
+
return globs.some((glob5) => minimatch5(filePath, glob5, { dot: true }));
|
|
10437
10830
|
});
|
|
10438
10831
|
return this.scanLinesWithRules(lines, applicableRules, filePath, startLine);
|
|
10439
10832
|
}
|
|
@@ -11441,6 +11834,7 @@ var SecurityTimelineManager = class _SecurityTimelineManager {
|
|
|
11441
11834
|
|
|
11442
11835
|
// src/ci/check-orchestrator.ts
|
|
11443
11836
|
import * as path25 from "path";
|
|
11837
|
+
import { skipDirGlobs as skipDirGlobs4 } from "@harness-engineering/graph";
|
|
11444
11838
|
import { GraphStore, queryTraceability } from "@harness-engineering/graph";
|
|
11445
11839
|
var ALL_CHECKS = [
|
|
11446
11840
|
"validate",
|
|
@@ -11518,8 +11912,7 @@ async function runDocsCheck(projectRoot, config) {
|
|
|
11518
11912
|
docsDir,
|
|
11519
11913
|
sourceDir: projectRoot,
|
|
11520
11914
|
excludePatterns: entropyConfig.excludePatterns || [
|
|
11521
|
-
|
|
11522
|
-
"**/dist/**",
|
|
11915
|
+
...skipDirGlobs4(),
|
|
11523
11916
|
"**/*.test.ts",
|
|
11524
11917
|
"**/fixtures/**"
|
|
11525
11918
|
]
|
|
@@ -11584,12 +11977,7 @@ async function runSecurityCheck(projectRoot, config) {
|
|
|
11584
11977
|
const { glob: globFn } = await import("glob");
|
|
11585
11978
|
const sourceFiles = await globFn("**/*.{ts,tsx,js,jsx,go,py}", {
|
|
11586
11979
|
cwd: projectRoot,
|
|
11587
|
-
ignore: securityConfig.exclude ?? [
|
|
11588
|
-
"**/node_modules/**",
|
|
11589
|
-
"**/dist/**",
|
|
11590
|
-
"**/*.test.ts",
|
|
11591
|
-
"**/fixtures/**"
|
|
11592
|
-
],
|
|
11980
|
+
ignore: securityConfig.exclude ?? [...skipDirGlobs4(), "**/*.test.ts", "**/fixtures/**"],
|
|
11593
11981
|
absolute: true
|
|
11594
11982
|
});
|
|
11595
11983
|
const scanResult = await scanner.scanFiles(sourceFiles);
|
|
@@ -14463,7 +14851,7 @@ function parseRepoParts(repo) {
|
|
|
14463
14851
|
return { owner: parts[0], repo: parts[1] };
|
|
14464
14852
|
}
|
|
14465
14853
|
function sleep2(ms) {
|
|
14466
|
-
return new Promise((
|
|
14854
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
14467
14855
|
}
|
|
14468
14856
|
async function fetchWithRetry(fetchFn, input, init, opts = RETRY_DEFAULTS) {
|
|
14469
14857
|
let lastResponse;
|
|
@@ -14997,8 +15385,8 @@ var syncMutex = Promise.resolve();
|
|
|
14997
15385
|
async function fullSync(roadmapPath, adapter2, config, options) {
|
|
14998
15386
|
const previousSync = syncMutex;
|
|
14999
15387
|
let releaseMutex;
|
|
15000
|
-
syncMutex = new Promise((
|
|
15001
|
-
releaseMutex =
|
|
15388
|
+
syncMutex = new Promise((resolve10) => {
|
|
15389
|
+
releaseMutex = resolve10;
|
|
15002
15390
|
});
|
|
15003
15391
|
await previousSync;
|
|
15004
15392
|
try {
|
|
@@ -17766,7 +18154,7 @@ var POSTHOG_BATCH_URL = "https://app.posthog.com/batch";
|
|
|
17766
18154
|
var MAX_ATTEMPTS = 3;
|
|
17767
18155
|
var TIMEOUT_MS = 5e3;
|
|
17768
18156
|
function sleep3(ms) {
|
|
17769
|
-
return new Promise((
|
|
18157
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
17770
18158
|
}
|
|
17771
18159
|
async function send(events, apiKey) {
|
|
17772
18160
|
if (events.length === 0) return;
|
|
@@ -18676,6 +19064,7 @@ export {
|
|
|
18676
19064
|
ViolationHistorySchema,
|
|
18677
19065
|
ViolationSchema,
|
|
18678
19066
|
ViolationSnapshotSchema,
|
|
19067
|
+
WHATWG_BAD_PORTS,
|
|
18679
19068
|
acquireCompoundLock,
|
|
18680
19069
|
addProvenance,
|
|
18681
19070
|
agentConfigRules,
|
|
@@ -18701,6 +19090,7 @@ export {
|
|
|
18701
19090
|
archiveStream,
|
|
18702
19091
|
assembleCandidateReport,
|
|
18703
19092
|
assembleReport,
|
|
19093
|
+
assertPortUsable,
|
|
18704
19094
|
assertSanitized,
|
|
18705
19095
|
assignFeature,
|
|
18706
19096
|
buildDependencyGraph,
|
|
@@ -18815,6 +19205,7 @@ export {
|
|
|
18815
19205
|
goRules,
|
|
18816
19206
|
injectionRules,
|
|
18817
19207
|
insecureDefaultsRules,
|
|
19208
|
+
isBadPort,
|
|
18818
19209
|
isDuplicateFinding,
|
|
18819
19210
|
isRegression,
|
|
18820
19211
|
isSanitizedResult,
|
|
@@ -18948,6 +19339,7 @@ export {
|
|
|
18948
19339
|
validateAgentConfigs,
|
|
18949
19340
|
validateAgentsMap,
|
|
18950
19341
|
validateBoundaries,
|
|
19342
|
+
validateBranchName,
|
|
18951
19343
|
validateCommitMessage,
|
|
18952
19344
|
validateConfig,
|
|
18953
19345
|
validateDependencies,
|