@harness-engineering/core 0.13.0 → 0.13.1
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.d.mts +1 -1
- package/dist/architecture/matchers.d.ts +1 -1
- package/dist/architecture/matchers.js +27 -35
- package/dist/architecture/matchers.mjs +1 -1
- package/dist/{chunk-ZHGBWFYD.mjs → chunk-D6VFA6AS.mjs} +22 -29
- package/dist/index.d.mts +85 -83
- package/dist/index.d.ts +85 -83
- package/dist/index.js +300 -273
- package/dist/index.mjs +267 -235
- package/dist/{matchers-Dj1t5vpg.d.mts → matchers-D20x48U9.d.mts} +46 -46
- package/dist/{matchers-Dj1t5vpg.d.ts → matchers-D20x48U9.d.ts} +46 -46
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -273,6 +273,7 @@ var import_types = require("@harness-engineering/types");
|
|
|
273
273
|
// src/shared/fs-utils.ts
|
|
274
274
|
var import_fs = require("fs");
|
|
275
275
|
var import_util = require("util");
|
|
276
|
+
var import_node_path = require("path");
|
|
276
277
|
var import_glob = require("glob");
|
|
277
278
|
var accessAsync = (0, import_util.promisify)(import_fs.access);
|
|
278
279
|
var readFileAsync = (0, import_util.promisify)(import_fs.readFile);
|
|
@@ -295,6 +296,9 @@ async function readFileContent(path20) {
|
|
|
295
296
|
async function findFiles(pattern, cwd = process.cwd()) {
|
|
296
297
|
return (0, import_glob.glob)(pattern, { cwd, absolute: true });
|
|
297
298
|
}
|
|
299
|
+
function relativePosix(from, to) {
|
|
300
|
+
return (0, import_node_path.relative)(from, to).replaceAll("\\", "/");
|
|
301
|
+
}
|
|
298
302
|
|
|
299
303
|
// src/validation/file-structure.ts
|
|
300
304
|
async function validateFileStructure(projectPath, conventions) {
|
|
@@ -656,7 +660,7 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
656
660
|
try {
|
|
657
661
|
const sourceFiles = await findFiles("**/*.{ts,js,tsx,jsx}", sourceDir);
|
|
658
662
|
const filteredSourceFiles = sourceFiles.filter((file) => {
|
|
659
|
-
const relativePath = (
|
|
663
|
+
const relativePath = relativePosix(sourceDir, file);
|
|
660
664
|
return !excludePatterns.some((pattern) => {
|
|
661
665
|
return (0, import_minimatch.minimatch)(relativePath, pattern, { dot: true }) || (0, import_minimatch.minimatch)(file, pattern, { dot: true });
|
|
662
666
|
});
|
|
@@ -679,7 +683,7 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
679
683
|
const undocumented = [];
|
|
680
684
|
const gaps = [];
|
|
681
685
|
for (const sourceFile of filteredSourceFiles) {
|
|
682
|
-
const relativePath = (
|
|
686
|
+
const relativePath = relativePosix(sourceDir, sourceFile);
|
|
683
687
|
const fileName = (0, import_path2.basename)(sourceFile);
|
|
684
688
|
const isDocumented = documentedPaths.has(relativePath) || documentedPaths.has(fileName) || documentedPaths.has(`src/${relativePath}`);
|
|
685
689
|
if (isDocumented) {
|
|
@@ -739,7 +743,7 @@ async function validateKnowledgeMap(rootDir = process.cwd()) {
|
|
|
739
743
|
totalLinks: agentsTotalLinks
|
|
740
744
|
} = agentsResult.value;
|
|
741
745
|
const existingFiles = await findFiles("**/*", rootDir);
|
|
742
|
-
const relativeExistingFiles = existingFiles.map((f) => (
|
|
746
|
+
const relativeExistingFiles = existingFiles.map((f) => relativePosix(rootDir, f));
|
|
743
747
|
const brokenLinks = agentsBrokenLinks.map((link) => {
|
|
744
748
|
const section = sections.find(
|
|
745
749
|
(s) => s.links.some((l) => l.path === link.path && l.line === link.line)
|
|
@@ -780,7 +784,7 @@ var DEFAULT_SECTIONS = [
|
|
|
780
784
|
function groupByDirectory(files, rootDir) {
|
|
781
785
|
const groups = /* @__PURE__ */ new Map();
|
|
782
786
|
for (const file of files) {
|
|
783
|
-
const relativePath = (
|
|
787
|
+
const relativePath = relativePosix(rootDir, file);
|
|
784
788
|
const dir = (0, import_path4.dirname)(relativePath);
|
|
785
789
|
if (!groups.has(dir)) {
|
|
786
790
|
groups.set(dir, []);
|
|
@@ -836,7 +840,7 @@ async function generateAgentsMap(config, graphSections) {
|
|
|
836
840
|
allFiles.push(...files);
|
|
837
841
|
}
|
|
838
842
|
const filteredFiles = allFiles.filter((file) => {
|
|
839
|
-
const relativePath = (
|
|
843
|
+
const relativePath = relativePosix(rootDir, file);
|
|
840
844
|
return !matchesExcludePattern(relativePath, excludePaths);
|
|
841
845
|
});
|
|
842
846
|
lines.push("## Repository Structure");
|
|
@@ -864,11 +868,11 @@ async function generateAgentsMap(config, graphSections) {
|
|
|
864
868
|
}
|
|
865
869
|
const sectionFiles = await findFiles(section.pattern, rootDir);
|
|
866
870
|
const filteredSectionFiles = sectionFiles.filter((file) => {
|
|
867
|
-
const relativePath = (
|
|
871
|
+
const relativePath = relativePosix(rootDir, file);
|
|
868
872
|
return !matchesExcludePattern(relativePath, excludePaths);
|
|
869
873
|
});
|
|
870
874
|
for (const file of filteredSectionFiles.slice(0, 20)) {
|
|
871
|
-
lines.push(formatFileLink((
|
|
875
|
+
lines.push(formatFileLink(relativePosix(rootDir, file)));
|
|
872
876
|
}
|
|
873
877
|
if (filteredSectionFiles.length > 20) {
|
|
874
878
|
lines.push(`- _... and ${filteredSectionFiles.length - 20} more files_`);
|
|
@@ -1139,8 +1143,8 @@ async function buildDependencyGraph(files, parser, graphDependencyData) {
|
|
|
1139
1143
|
function checkLayerViolations(graph, layers, rootDir) {
|
|
1140
1144
|
const violations = [];
|
|
1141
1145
|
for (const edge of graph.edges) {
|
|
1142
|
-
const fromRelative = (
|
|
1143
|
-
const toRelative = (
|
|
1146
|
+
const fromRelative = relativePosix(rootDir, edge.from);
|
|
1147
|
+
const toRelative = relativePosix(rootDir, edge.to);
|
|
1144
1148
|
const fromLayer = resolveFileToLayer(fromRelative, layers);
|
|
1145
1149
|
const toLayer = resolveFileToLayer(toRelative, layers);
|
|
1146
1150
|
if (!fromLayer || !toLayer) continue;
|
|
@@ -2335,7 +2339,7 @@ async function buildSnapshot(config) {
|
|
|
2335
2339
|
sourceFilePaths.push(...files2);
|
|
2336
2340
|
}
|
|
2337
2341
|
sourceFilePaths = sourceFilePaths.filter((f) => {
|
|
2338
|
-
const rel = (
|
|
2342
|
+
const rel = relativePosix(rootDir, f);
|
|
2339
2343
|
return !excludePatterns.some((p) => (0, import_minimatch3.minimatch)(rel, p));
|
|
2340
2344
|
});
|
|
2341
2345
|
const files = [];
|
|
@@ -2867,9 +2871,8 @@ async function detectDeadCode(snapshot, graphDeadCodeData) {
|
|
|
2867
2871
|
|
|
2868
2872
|
// src/entropy/detectors/patterns.ts
|
|
2869
2873
|
var import_minimatch4 = require("minimatch");
|
|
2870
|
-
var import_path9 = require("path");
|
|
2871
2874
|
function fileMatchesPattern(filePath, pattern, rootDir) {
|
|
2872
|
-
const relativePath = (
|
|
2875
|
+
const relativePath = relativePosix(rootDir, filePath);
|
|
2873
2876
|
return (0, import_minimatch4.minimatch)(relativePath, pattern);
|
|
2874
2877
|
}
|
|
2875
2878
|
function checkConfigPattern(pattern, file, rootDir) {
|
|
@@ -3465,7 +3468,7 @@ async function detectCouplingViolations(snapshot, config, graphData) {
|
|
|
3465
3468
|
|
|
3466
3469
|
// src/entropy/detectors/size-budget.ts
|
|
3467
3470
|
var import_node_fs = require("fs");
|
|
3468
|
-
var
|
|
3471
|
+
var import_node_path2 = require("path");
|
|
3469
3472
|
function parseSize(size) {
|
|
3470
3473
|
const match = size.trim().match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB|B)?$/i);
|
|
3471
3474
|
if (!match) return 0;
|
|
@@ -3492,7 +3495,7 @@ function dirSize(dirPath) {
|
|
|
3492
3495
|
}
|
|
3493
3496
|
for (const entry of entries) {
|
|
3494
3497
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
3495
|
-
const fullPath = (0,
|
|
3498
|
+
const fullPath = (0, import_node_path2.join)(dirPath, entry);
|
|
3496
3499
|
try {
|
|
3497
3500
|
const stat = (0, import_node_fs.statSync)(fullPath);
|
|
3498
3501
|
if (stat.isDirectory()) {
|
|
@@ -3512,7 +3515,7 @@ async function detectSizeBudgetViolations(rootDir, config) {
|
|
|
3512
3515
|
let packagesChecked = 0;
|
|
3513
3516
|
for (const [pkgPath, budget] of Object.entries(budgets)) {
|
|
3514
3517
|
packagesChecked++;
|
|
3515
|
-
const distPath = (0,
|
|
3518
|
+
const distPath = (0, import_node_path2.join)(rootDir, pkgPath, "dist");
|
|
3516
3519
|
const currentSize = dirSize(distPath);
|
|
3517
3520
|
if (budget.warn) {
|
|
3518
3521
|
const budgetBytes = parseSize(budget.warn);
|
|
@@ -3893,7 +3896,7 @@ var EntropyAnalyzer = class {
|
|
|
3893
3896
|
// src/entropy/fixers/safe-fixes.ts
|
|
3894
3897
|
var fs3 = __toESM(require("fs"));
|
|
3895
3898
|
var import_util2 = require("util");
|
|
3896
|
-
var
|
|
3899
|
+
var import_path9 = require("path");
|
|
3897
3900
|
var readFile5 = (0, import_util2.promisify)(fs3.readFile);
|
|
3898
3901
|
var writeFile3 = (0, import_util2.promisify)(fs3.writeFile);
|
|
3899
3902
|
var unlink2 = (0, import_util2.promisify)(fs3.unlink);
|
|
@@ -3909,7 +3912,7 @@ function createDeadFileFixes(deadCodeReport) {
|
|
|
3909
3912
|
return deadCodeReport.deadFiles.map((file) => ({
|
|
3910
3913
|
type: "dead-files",
|
|
3911
3914
|
file: file.path,
|
|
3912
|
-
description: `Delete dead file (${file.reason}): ${(0,
|
|
3915
|
+
description: `Delete dead file (${file.reason}): ${(0, import_path9.basename)(file.path)}`,
|
|
3913
3916
|
action: "delete-file",
|
|
3914
3917
|
safe: true,
|
|
3915
3918
|
reversible: true
|
|
@@ -3992,9 +3995,9 @@ function previewFix(fix) {
|
|
|
3992
3995
|
}
|
|
3993
3996
|
}
|
|
3994
3997
|
async function createBackup(filePath, backupDir) {
|
|
3995
|
-
const backupPath = (0,
|
|
3998
|
+
const backupPath = (0, import_path9.join)(backupDir, `${Date.now()}-${(0, import_path9.basename)(filePath)}`);
|
|
3996
3999
|
try {
|
|
3997
|
-
await mkdir2((0,
|
|
4000
|
+
await mkdir2((0, import_path9.dirname)(backupPath), { recursive: true });
|
|
3998
4001
|
await copyFile2(filePath, backupPath);
|
|
3999
4002
|
return (0, import_types.Ok)(backupPath);
|
|
4000
4003
|
} catch (e) {
|
|
@@ -4330,11 +4333,11 @@ function validatePatternConfig(config) {
|
|
|
4330
4333
|
|
|
4331
4334
|
// src/performance/baseline-manager.ts
|
|
4332
4335
|
var import_node_fs2 = require("fs");
|
|
4333
|
-
var
|
|
4336
|
+
var import_node_path3 = require("path");
|
|
4334
4337
|
var BaselineManager = class {
|
|
4335
4338
|
baselinesPath;
|
|
4336
4339
|
constructor(projectRoot) {
|
|
4337
|
-
this.baselinesPath = (0,
|
|
4340
|
+
this.baselinesPath = (0, import_node_path3.join)(projectRoot, ".harness", "perf", "baselines.json");
|
|
4338
4341
|
}
|
|
4339
4342
|
/**
|
|
4340
4343
|
* Load the baselines file from disk.
|
|
@@ -4374,7 +4377,7 @@ var BaselineManager = class {
|
|
|
4374
4377
|
updatedFrom: commitHash,
|
|
4375
4378
|
benchmarks
|
|
4376
4379
|
};
|
|
4377
|
-
const dir = (0,
|
|
4380
|
+
const dir = (0, import_node_path3.dirname)(this.baselinesPath);
|
|
4378
4381
|
if (!(0, import_node_fs2.existsSync)(dir)) {
|
|
4379
4382
|
(0, import_node_fs2.mkdirSync)(dir, { recursive: true });
|
|
4380
4383
|
}
|
|
@@ -5365,7 +5368,7 @@ async function requestMultiplePeerReviews(requests) {
|
|
|
5365
5368
|
|
|
5366
5369
|
// src/feedback/logging/file-sink.ts
|
|
5367
5370
|
var import_fs2 = require("fs");
|
|
5368
|
-
var
|
|
5371
|
+
var import_path10 = require("path");
|
|
5369
5372
|
var FileSink = class {
|
|
5370
5373
|
name = "file";
|
|
5371
5374
|
filePath;
|
|
@@ -5388,7 +5391,7 @@ var FileSink = class {
|
|
|
5388
5391
|
}
|
|
5389
5392
|
ensureDirectory() {
|
|
5390
5393
|
if (!this.initialized) {
|
|
5391
|
-
const dir = (0,
|
|
5394
|
+
const dir = (0, import_path10.dirname)(this.filePath);
|
|
5392
5395
|
if (!(0, import_fs2.existsSync)(dir)) {
|
|
5393
5396
|
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
5394
5397
|
}
|
|
@@ -5535,14 +5538,10 @@ var ConstraintRuleSchema = import_zod3.z.object({
|
|
|
5535
5538
|
// forward-compat for governs edges
|
|
5536
5539
|
});
|
|
5537
5540
|
|
|
5538
|
-
// src/architecture/collectors/circular-deps.ts
|
|
5539
|
-
var import_node_path3 = require("path");
|
|
5540
|
-
|
|
5541
5541
|
// src/architecture/collectors/hash.ts
|
|
5542
5542
|
var import_node_crypto = require("crypto");
|
|
5543
5543
|
function violationId(relativePath, category, normalizedDetail) {
|
|
5544
|
-
const
|
|
5545
|
-
const input = `${path20}:${category}:${normalizedDetail}`;
|
|
5544
|
+
const input = `${relativePath}:${category}:${normalizedDetail}`;
|
|
5546
5545
|
return (0, import_node_crypto.createHash)("sha256").update(input).digest("hex");
|
|
5547
5546
|
}
|
|
5548
5547
|
function constraintRuleId(category, scope, description) {
|
|
@@ -5606,8 +5605,8 @@ var CircularDepsCollector = class {
|
|
|
5606
5605
|
}
|
|
5607
5606
|
const { cycles, largestCycle } = result.value;
|
|
5608
5607
|
const violations = cycles.map((cycle) => {
|
|
5609
|
-
const cyclePath = cycle.cycle.map((f) => (
|
|
5610
|
-
const firstFile = (
|
|
5608
|
+
const cyclePath = cycle.cycle.map((f) => relativePosix(rootDir, f)).join(" -> ");
|
|
5609
|
+
const firstFile = relativePosix(rootDir, cycle.cycle[0]);
|
|
5611
5610
|
return {
|
|
5612
5611
|
id: violationId(firstFile, this.category, cyclePath),
|
|
5613
5612
|
file: firstFile,
|
|
@@ -5628,7 +5627,6 @@ var CircularDepsCollector = class {
|
|
|
5628
5627
|
};
|
|
5629
5628
|
|
|
5630
5629
|
// src/architecture/collectors/layer-violations.ts
|
|
5631
|
-
var import_node_path4 = require("path");
|
|
5632
5630
|
var LayerViolationCollector = class {
|
|
5633
5631
|
category = "layer-violations";
|
|
5634
5632
|
getRules(_config, _rootDir) {
|
|
@@ -5672,8 +5670,8 @@ var LayerViolationCollector = class {
|
|
|
5672
5670
|
(v) => v.reason === "WRONG_LAYER"
|
|
5673
5671
|
);
|
|
5674
5672
|
const violations = layerViolations.map((v) => {
|
|
5675
|
-
const relFile = (
|
|
5676
|
-
const relImport = (
|
|
5673
|
+
const relFile = relativePosix(rootDir, v.file);
|
|
5674
|
+
const relImport = relativePosix(rootDir, v.imports);
|
|
5677
5675
|
const detail = `${v.fromLayer} -> ${v.toLayer}: ${relFile} imports ${relImport}`;
|
|
5678
5676
|
return {
|
|
5679
5677
|
id: violationId(relFile, this.category, detail),
|
|
@@ -5695,7 +5693,6 @@ var LayerViolationCollector = class {
|
|
|
5695
5693
|
};
|
|
5696
5694
|
|
|
5697
5695
|
// src/architecture/collectors/complexity.ts
|
|
5698
|
-
var import_node_path5 = require("path");
|
|
5699
5696
|
var ComplexityCollector = class {
|
|
5700
5697
|
category = "complexity";
|
|
5701
5698
|
getRules(_config, _rootDir) {
|
|
@@ -5756,7 +5753,7 @@ var ComplexityCollector = class {
|
|
|
5756
5753
|
(v) => v.severity === "error" || v.severity === "warning"
|
|
5757
5754
|
);
|
|
5758
5755
|
const violations = filtered.map((v) => {
|
|
5759
|
-
const relFile = (
|
|
5756
|
+
const relFile = relativePosix(rootDir, v.file);
|
|
5760
5757
|
const idDetail = `${v.metric}:${v.function}`;
|
|
5761
5758
|
return {
|
|
5762
5759
|
id: violationId(relFile, this.category, idDetail),
|
|
@@ -5782,7 +5779,6 @@ var ComplexityCollector = class {
|
|
|
5782
5779
|
};
|
|
5783
5780
|
|
|
5784
5781
|
// src/architecture/collectors/coupling.ts
|
|
5785
|
-
var import_node_path6 = require("path");
|
|
5786
5782
|
var CouplingCollector = class {
|
|
5787
5783
|
category = "coupling";
|
|
5788
5784
|
getRules(_config, _rootDir) {
|
|
@@ -5833,7 +5829,7 @@ var CouplingCollector = class {
|
|
|
5833
5829
|
(v) => v.severity === "error" || v.severity === "warning"
|
|
5834
5830
|
);
|
|
5835
5831
|
const violations = filtered.map((v) => {
|
|
5836
|
-
const relFile = (
|
|
5832
|
+
const relFile = relativePosix(rootDir, v.file);
|
|
5837
5833
|
const idDetail = `${v.metric}`;
|
|
5838
5834
|
return {
|
|
5839
5835
|
id: violationId(relFile, this.category, idDetail),
|
|
@@ -5856,7 +5852,6 @@ var CouplingCollector = class {
|
|
|
5856
5852
|
};
|
|
5857
5853
|
|
|
5858
5854
|
// src/architecture/collectors/forbidden-imports.ts
|
|
5859
|
-
var import_node_path7 = require("path");
|
|
5860
5855
|
var ForbiddenImportCollector = class {
|
|
5861
5856
|
category = "forbidden-imports";
|
|
5862
5857
|
getRules(_config, _rootDir) {
|
|
@@ -5900,8 +5895,8 @@ var ForbiddenImportCollector = class {
|
|
|
5900
5895
|
(v) => v.reason === "FORBIDDEN_IMPORT"
|
|
5901
5896
|
);
|
|
5902
5897
|
const violations = forbidden.map((v) => {
|
|
5903
|
-
const relFile = (
|
|
5904
|
-
const relImport = (
|
|
5898
|
+
const relFile = relativePosix(rootDir, v.file);
|
|
5899
|
+
const relImport = relativePosix(rootDir, v.imports);
|
|
5905
5900
|
const detail = `forbidden import: ${relFile} -> ${relImport}`;
|
|
5906
5901
|
return {
|
|
5907
5902
|
id: violationId(relFile, this.category, detail),
|
|
@@ -5924,7 +5919,7 @@ var ForbiddenImportCollector = class {
|
|
|
5924
5919
|
|
|
5925
5920
|
// src/architecture/collectors/module-size.ts
|
|
5926
5921
|
var import_promises2 = require("fs/promises");
|
|
5927
|
-
var
|
|
5922
|
+
var import_node_path4 = require("path");
|
|
5928
5923
|
async function discoverModules(rootDir) {
|
|
5929
5924
|
const modules = [];
|
|
5930
5925
|
async function scanDir(dir) {
|
|
@@ -5940,7 +5935,7 @@ async function discoverModules(rootDir) {
|
|
|
5940
5935
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") {
|
|
5941
5936
|
continue;
|
|
5942
5937
|
}
|
|
5943
|
-
const fullPath = (0,
|
|
5938
|
+
const fullPath = (0, import_node_path4.join)(dir, entry.name);
|
|
5944
5939
|
if (entry.isDirectory()) {
|
|
5945
5940
|
subdirs.push(fullPath);
|
|
5946
5941
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) && !entry.name.endsWith(".test.ts") && !entry.name.endsWith(".test.tsx") && !entry.name.endsWith(".spec.ts")) {
|
|
@@ -5957,10 +5952,10 @@ async function discoverModules(rootDir) {
|
|
|
5957
5952
|
}
|
|
5958
5953
|
}
|
|
5959
5954
|
modules.push({
|
|
5960
|
-
modulePath: (
|
|
5955
|
+
modulePath: relativePosix(rootDir, dir),
|
|
5961
5956
|
fileCount: tsFiles.length,
|
|
5962
5957
|
totalLoc,
|
|
5963
|
-
files: tsFiles.map((f) => (
|
|
5958
|
+
files: tsFiles.map((f) => relativePosix(rootDir, f))
|
|
5964
5959
|
});
|
|
5965
5960
|
}
|
|
5966
5961
|
for (const sub of subdirs) {
|
|
@@ -6052,16 +6047,16 @@ var ModuleSizeCollector = class {
|
|
|
6052
6047
|
|
|
6053
6048
|
// src/architecture/collectors/dep-depth.ts
|
|
6054
6049
|
var import_promises3 = require("fs/promises");
|
|
6055
|
-
var
|
|
6050
|
+
var import_node_path5 = require("path");
|
|
6056
6051
|
function extractImportSources(content, filePath) {
|
|
6057
6052
|
const importRegex = /(?:import|export)\s+.*?from\s+['"](\.[^'"]+)['"]/g;
|
|
6058
6053
|
const dynamicRegex = /import\s*\(\s*['"](\.[^'"]+)['"]\s*\)/g;
|
|
6059
6054
|
const sources = [];
|
|
6060
|
-
const dir = (0,
|
|
6055
|
+
const dir = (0, import_node_path5.dirname)(filePath);
|
|
6061
6056
|
for (const regex of [importRegex, dynamicRegex]) {
|
|
6062
6057
|
let match;
|
|
6063
6058
|
while ((match = regex.exec(content)) !== null) {
|
|
6064
|
-
let resolved = (0,
|
|
6059
|
+
let resolved = (0, import_node_path5.resolve)(dir, match[1]);
|
|
6065
6060
|
if (!resolved.endsWith(".ts") && !resolved.endsWith(".tsx")) {
|
|
6066
6061
|
resolved += ".ts";
|
|
6067
6062
|
}
|
|
@@ -6082,7 +6077,7 @@ async function collectTsFiles(dir) {
|
|
|
6082
6077
|
for (const entry of entries) {
|
|
6083
6078
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist")
|
|
6084
6079
|
continue;
|
|
6085
|
-
const fullPath = (0,
|
|
6080
|
+
const fullPath = (0, import_node_path5.join)(d, entry.name);
|
|
6086
6081
|
if (entry.isDirectory()) {
|
|
6087
6082
|
await scan(fullPath);
|
|
6088
6083
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) && !entry.name.endsWith(".test.ts") && !entry.name.endsWith(".test.tsx") && !entry.name.endsWith(".spec.ts")) {
|
|
@@ -6136,7 +6131,7 @@ var DepDepthCollector = class {
|
|
|
6136
6131
|
}
|
|
6137
6132
|
const moduleMap = /* @__PURE__ */ new Map();
|
|
6138
6133
|
for (const file of allFiles) {
|
|
6139
|
-
const relDir = (
|
|
6134
|
+
const relDir = relativePosix(rootDir, (0, import_node_path5.dirname)(file));
|
|
6140
6135
|
if (!moduleMap.has(relDir)) moduleMap.set(relDir, []);
|
|
6141
6136
|
moduleMap.get(relDir).push(file);
|
|
6142
6137
|
}
|
|
@@ -6280,11 +6275,11 @@ function detectStaleConstraints(store, windowDays = 30, category) {
|
|
|
6280
6275
|
// src/architecture/baseline-manager.ts
|
|
6281
6276
|
var import_node_fs3 = require("fs");
|
|
6282
6277
|
var import_node_crypto2 = require("crypto");
|
|
6283
|
-
var
|
|
6278
|
+
var import_node_path6 = require("path");
|
|
6284
6279
|
var ArchBaselineManager = class {
|
|
6285
6280
|
baselinesPath;
|
|
6286
6281
|
constructor(projectRoot, baselinePath) {
|
|
6287
|
-
this.baselinesPath = baselinePath ? (0,
|
|
6282
|
+
this.baselinesPath = baselinePath ? (0, import_node_path6.join)(projectRoot, baselinePath) : (0, import_node_path6.join)(projectRoot, ".harness", "arch", "baselines.json");
|
|
6288
6283
|
}
|
|
6289
6284
|
/**
|
|
6290
6285
|
* Snapshot the current metric results into an ArchBaseline.
|
|
@@ -6345,7 +6340,7 @@ var ArchBaselineManager = class {
|
|
|
6345
6340
|
* Uses atomic write (write to temp file, then rename) to prevent corruption.
|
|
6346
6341
|
*/
|
|
6347
6342
|
save(baseline) {
|
|
6348
|
-
const dir = (0,
|
|
6343
|
+
const dir = (0, import_node_path6.dirname)(this.baselinesPath);
|
|
6349
6344
|
if (!(0, import_node_fs3.existsSync)(dir)) {
|
|
6350
6345
|
(0, import_node_fs3.mkdirSync)(dir, { recursive: true });
|
|
6351
6346
|
}
|
|
@@ -8399,238 +8394,270 @@ var ALL_CHECKS = [
|
|
|
8399
8394
|
"phase-gate",
|
|
8400
8395
|
"arch"
|
|
8401
8396
|
];
|
|
8402
|
-
async function
|
|
8403
|
-
const start = Date.now();
|
|
8397
|
+
async function runValidateCheck(projectRoot, config) {
|
|
8404
8398
|
const issues = [];
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
if (result.value.errors) {
|
|
8414
|
-
for (const err of result.value.errors) {
|
|
8415
|
-
issues.push({ severity: "error", message: err.message });
|
|
8416
|
-
}
|
|
8417
|
-
}
|
|
8418
|
-
for (const section of result.value.missingSections) {
|
|
8419
|
-
issues.push({ severity: "warning", message: `Missing section: ${section}` });
|
|
8420
|
-
}
|
|
8421
|
-
for (const link of result.value.brokenLinks) {
|
|
8422
|
-
issues.push({
|
|
8423
|
-
severity: "warning",
|
|
8424
|
-
message: `Broken link: ${link.text} \u2192 ${link.path}`,
|
|
8425
|
-
file: link.path
|
|
8426
|
-
});
|
|
8427
|
-
}
|
|
8428
|
-
}
|
|
8429
|
-
break;
|
|
8399
|
+
const agentsPath = path12.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
|
|
8400
|
+
const result = await validateAgentsMap(agentsPath);
|
|
8401
|
+
if (!result.ok) {
|
|
8402
|
+
issues.push({ severity: "error", message: result.error.message });
|
|
8403
|
+
} else if (!result.value.valid) {
|
|
8404
|
+
if (result.value.errors) {
|
|
8405
|
+
for (const err of result.value.errors) {
|
|
8406
|
+
issues.push({ severity: "error", message: err.message });
|
|
8430
8407
|
}
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8408
|
+
}
|
|
8409
|
+
for (const section of result.value.missingSections) {
|
|
8410
|
+
issues.push({ severity: "warning", message: `Missing section: ${section}` });
|
|
8411
|
+
}
|
|
8412
|
+
for (const link of result.value.brokenLinks) {
|
|
8413
|
+
issues.push({
|
|
8414
|
+
severity: "warning",
|
|
8415
|
+
message: `Broken link: ${link.text} \u2192 ${link.path}`,
|
|
8416
|
+
file: link.path
|
|
8417
|
+
});
|
|
8418
|
+
}
|
|
8419
|
+
}
|
|
8420
|
+
return issues;
|
|
8421
|
+
}
|
|
8422
|
+
async function runDepsCheck(projectRoot, config) {
|
|
8423
|
+
const issues = [];
|
|
8424
|
+
const rawLayers = config.layers;
|
|
8425
|
+
if (rawLayers && rawLayers.length > 0) {
|
|
8426
|
+
const parser = new TypeScriptParser();
|
|
8427
|
+
const layers = rawLayers.map(
|
|
8428
|
+
(l) => defineLayer(
|
|
8429
|
+
l.name,
|
|
8430
|
+
Array.isArray(l.patterns) ? l.patterns : [l.pattern],
|
|
8431
|
+
l.allowedDependencies
|
|
8432
|
+
)
|
|
8433
|
+
);
|
|
8434
|
+
const result = await validateDependencies({
|
|
8435
|
+
layers,
|
|
8436
|
+
rootDir: projectRoot,
|
|
8437
|
+
parser
|
|
8438
|
+
});
|
|
8439
|
+
if (!result.ok) {
|
|
8440
|
+
issues.push({ severity: "error", message: result.error.message });
|
|
8441
|
+
} else if (result.value.violations.length > 0) {
|
|
8442
|
+
for (const v of result.value.violations) {
|
|
8443
|
+
issues.push({
|
|
8444
|
+
severity: "error",
|
|
8445
|
+
message: `${v.reason}: ${v.file} imports ${v.imports} (${v.fromLayer} \u2192 ${v.toLayer})`,
|
|
8446
|
+
file: v.file,
|
|
8447
|
+
line: v.line
|
|
8448
|
+
});
|
|
8461
8449
|
}
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8450
|
+
}
|
|
8451
|
+
}
|
|
8452
|
+
return issues;
|
|
8453
|
+
}
|
|
8454
|
+
async function runDocsCheck(projectRoot, config) {
|
|
8455
|
+
const issues = [];
|
|
8456
|
+
const docsDir = path12.join(projectRoot, config.docsDir ?? "docs");
|
|
8457
|
+
const entropyConfig = config.entropy || {};
|
|
8458
|
+
const result = await checkDocCoverage("project", {
|
|
8459
|
+
docsDir,
|
|
8460
|
+
sourceDir: projectRoot,
|
|
8461
|
+
excludePatterns: entropyConfig.excludePatterns || [
|
|
8462
|
+
"**/node_modules/**",
|
|
8463
|
+
"**/dist/**",
|
|
8464
|
+
"**/*.test.ts",
|
|
8465
|
+
"**/fixtures/**"
|
|
8466
|
+
]
|
|
8467
|
+
});
|
|
8468
|
+
if (!result.ok) {
|
|
8469
|
+
issues.push({ severity: "warning", message: result.error.message });
|
|
8470
|
+
} else if (result.value.gaps.length > 0) {
|
|
8471
|
+
for (const gap of result.value.gaps) {
|
|
8472
|
+
issues.push({
|
|
8473
|
+
severity: "warning",
|
|
8474
|
+
message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
|
|
8475
|
+
file: gap.file
|
|
8476
|
+
});
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
return issues;
|
|
8480
|
+
}
|
|
8481
|
+
async function runEntropyCheck(projectRoot, _config) {
|
|
8482
|
+
const issues = [];
|
|
8483
|
+
const analyzer = new EntropyAnalyzer({
|
|
8484
|
+
rootDir: projectRoot,
|
|
8485
|
+
analyze: { drift: true, deadCode: true, patterns: false }
|
|
8486
|
+
});
|
|
8487
|
+
const result = await analyzer.analyze();
|
|
8488
|
+
if (!result.ok) {
|
|
8489
|
+
issues.push({ severity: "warning", message: result.error.message });
|
|
8490
|
+
} else {
|
|
8491
|
+
const report = result.value;
|
|
8492
|
+
if (report.drift) {
|
|
8493
|
+
for (const drift of report.drift.drifts) {
|
|
8494
|
+
issues.push({
|
|
8495
|
+
severity: "warning",
|
|
8496
|
+
message: `Doc drift (${drift.type}): ${drift.details}`,
|
|
8497
|
+
file: drift.docFile,
|
|
8498
|
+
line: drift.line
|
|
8474
8499
|
});
|
|
8475
|
-
if (!result.ok) {
|
|
8476
|
-
issues.push({ severity: "warning", message: result.error.message });
|
|
8477
|
-
} else if (result.value.gaps.length > 0) {
|
|
8478
|
-
for (const gap of result.value.gaps) {
|
|
8479
|
-
issues.push({
|
|
8480
|
-
severity: "warning",
|
|
8481
|
-
message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
|
|
8482
|
-
file: gap.file
|
|
8483
|
-
});
|
|
8484
|
-
}
|
|
8485
|
-
}
|
|
8486
|
-
break;
|
|
8487
8500
|
}
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8501
|
+
}
|
|
8502
|
+
if (report.deadCode) {
|
|
8503
|
+
for (const dead of report.deadCode.deadExports) {
|
|
8504
|
+
issues.push({
|
|
8505
|
+
severity: "warning",
|
|
8506
|
+
message: `Dead export: ${dead.name}`,
|
|
8507
|
+
file: dead.file,
|
|
8508
|
+
line: dead.line
|
|
8492
8509
|
});
|
|
8493
|
-
const result = await analyzer.analyze();
|
|
8494
|
-
if (!result.ok) {
|
|
8495
|
-
issues.push({ severity: "warning", message: result.error.message });
|
|
8496
|
-
} else {
|
|
8497
|
-
const report = result.value;
|
|
8498
|
-
if (report.drift) {
|
|
8499
|
-
for (const drift of report.drift.drifts) {
|
|
8500
|
-
issues.push({
|
|
8501
|
-
severity: "warning",
|
|
8502
|
-
message: `Doc drift (${drift.type}): ${drift.details}`,
|
|
8503
|
-
file: drift.docFile,
|
|
8504
|
-
line: drift.line
|
|
8505
|
-
});
|
|
8506
|
-
}
|
|
8507
|
-
}
|
|
8508
|
-
if (report.deadCode) {
|
|
8509
|
-
for (const dead of report.deadCode.deadExports) {
|
|
8510
|
-
issues.push({
|
|
8511
|
-
severity: "warning",
|
|
8512
|
-
message: `Dead export: ${dead.name}`,
|
|
8513
|
-
file: dead.file,
|
|
8514
|
-
line: dead.line
|
|
8515
|
-
});
|
|
8516
|
-
}
|
|
8517
|
-
}
|
|
8518
|
-
}
|
|
8519
|
-
break;
|
|
8520
8510
|
}
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8511
|
+
}
|
|
8512
|
+
}
|
|
8513
|
+
return issues;
|
|
8514
|
+
}
|
|
8515
|
+
async function runSecurityCheck(projectRoot, config) {
|
|
8516
|
+
const issues = [];
|
|
8517
|
+
const securityConfig = parseSecurityConfig(config.security);
|
|
8518
|
+
if (!securityConfig.enabled) return issues;
|
|
8519
|
+
const scanner = new SecurityScanner(securityConfig);
|
|
8520
|
+
scanner.configureForProject(projectRoot);
|
|
8521
|
+
const { glob: globFn } = await import("glob");
|
|
8522
|
+
const sourceFiles = await globFn("**/*.{ts,tsx,js,jsx,go,py}", {
|
|
8523
|
+
cwd: projectRoot,
|
|
8524
|
+
ignore: securityConfig.exclude ?? [
|
|
8525
|
+
"**/node_modules/**",
|
|
8526
|
+
"**/dist/**",
|
|
8527
|
+
"**/*.test.ts",
|
|
8528
|
+
"**/fixtures/**"
|
|
8529
|
+
],
|
|
8530
|
+
absolute: true
|
|
8531
|
+
});
|
|
8532
|
+
const scanResult = await scanner.scanFiles(sourceFiles);
|
|
8533
|
+
for (const finding of scanResult.findings) {
|
|
8534
|
+
issues.push({
|
|
8535
|
+
severity: finding.severity === "info" ? "warning" : finding.severity,
|
|
8536
|
+
message: `[${finding.ruleId}] ${finding.message}: ${finding.match}`,
|
|
8537
|
+
file: finding.file,
|
|
8538
|
+
line: finding.line
|
|
8539
|
+
});
|
|
8540
|
+
}
|
|
8541
|
+
return issues;
|
|
8542
|
+
}
|
|
8543
|
+
async function runPerfCheck(projectRoot, config) {
|
|
8544
|
+
const issues = [];
|
|
8545
|
+
const perfConfig = config.performance || {};
|
|
8546
|
+
const perfAnalyzer = new EntropyAnalyzer({
|
|
8547
|
+
rootDir: projectRoot,
|
|
8548
|
+
analyze: {
|
|
8549
|
+
complexity: perfConfig.complexity || true,
|
|
8550
|
+
coupling: perfConfig.coupling || true,
|
|
8551
|
+
sizeBudget: perfConfig.sizeBudget || false
|
|
8552
|
+
}
|
|
8553
|
+
});
|
|
8554
|
+
const perfResult = await perfAnalyzer.analyze();
|
|
8555
|
+
if (!perfResult.ok) {
|
|
8556
|
+
issues.push({ severity: "warning", message: perfResult.error.message });
|
|
8557
|
+
} else {
|
|
8558
|
+
const perfReport = perfResult.value;
|
|
8559
|
+
if (perfReport.complexity) {
|
|
8560
|
+
for (const v of perfReport.complexity.violations) {
|
|
8561
|
+
issues.push({
|
|
8562
|
+
severity: v.severity === "info" ? "warning" : v.severity,
|
|
8563
|
+
message: `[Tier ${v.tier}] ${v.metric}: ${v.function} in ${v.file} (${v.value} > ${v.threshold})`,
|
|
8564
|
+
file: v.file,
|
|
8565
|
+
line: v.line
|
|
8536
8566
|
});
|
|
8537
|
-
const scanResult = await scanner.scanFiles(sourceFiles);
|
|
8538
|
-
for (const finding of scanResult.findings) {
|
|
8539
|
-
issues.push({
|
|
8540
|
-
severity: finding.severity === "info" ? "warning" : finding.severity,
|
|
8541
|
-
message: `[${finding.ruleId}] ${finding.message}: ${finding.match}`,
|
|
8542
|
-
file: finding.file,
|
|
8543
|
-
line: finding.line
|
|
8544
|
-
});
|
|
8545
|
-
}
|
|
8546
|
-
break;
|
|
8547
8567
|
}
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
sizeBudget: perfConfig.sizeBudget || false
|
|
8556
|
-
}
|
|
8568
|
+
}
|
|
8569
|
+
if (perfReport.coupling) {
|
|
8570
|
+
for (const v of perfReport.coupling.violations) {
|
|
8571
|
+
issues.push({
|
|
8572
|
+
severity: v.severity === "info" ? "warning" : v.severity,
|
|
8573
|
+
message: `[Tier ${v.tier}] ${v.metric}: ${v.file} (${v.value} > ${v.threshold})`,
|
|
8574
|
+
file: v.file
|
|
8557
8575
|
});
|
|
8558
|
-
const perfResult = await perfAnalyzer.analyze();
|
|
8559
|
-
if (!perfResult.ok) {
|
|
8560
|
-
issues.push({ severity: "warning", message: perfResult.error.message });
|
|
8561
|
-
} else {
|
|
8562
|
-
const perfReport = perfResult.value;
|
|
8563
|
-
if (perfReport.complexity) {
|
|
8564
|
-
for (const v of perfReport.complexity.violations) {
|
|
8565
|
-
issues.push({
|
|
8566
|
-
severity: v.severity === "info" ? "warning" : v.severity,
|
|
8567
|
-
message: `[Tier ${v.tier}] ${v.metric}: ${v.function} in ${v.file} (${v.value} > ${v.threshold})`,
|
|
8568
|
-
file: v.file,
|
|
8569
|
-
line: v.line
|
|
8570
|
-
});
|
|
8571
|
-
}
|
|
8572
|
-
}
|
|
8573
|
-
if (perfReport.coupling) {
|
|
8574
|
-
for (const v of perfReport.coupling.violations) {
|
|
8575
|
-
issues.push({
|
|
8576
|
-
severity: v.severity === "info" ? "warning" : v.severity,
|
|
8577
|
-
message: `[Tier ${v.tier}] ${v.metric}: ${v.file} (${v.value} > ${v.threshold})`,
|
|
8578
|
-
file: v.file
|
|
8579
|
-
});
|
|
8580
|
-
}
|
|
8581
|
-
}
|
|
8582
|
-
}
|
|
8583
|
-
break;
|
|
8584
8576
|
}
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8577
|
+
}
|
|
8578
|
+
}
|
|
8579
|
+
return issues;
|
|
8580
|
+
}
|
|
8581
|
+
async function runPhaseGateCheck(_projectRoot, config) {
|
|
8582
|
+
const issues = [];
|
|
8583
|
+
const phaseGates = config.phaseGates;
|
|
8584
|
+
if (!phaseGates?.enabled) {
|
|
8585
|
+
return issues;
|
|
8586
|
+
}
|
|
8587
|
+
issues.push({
|
|
8588
|
+
severity: "warning",
|
|
8589
|
+
message: "Phase gate is enabled but requires CLI context. Run `harness check-phase-gate` separately for full validation."
|
|
8590
|
+
});
|
|
8591
|
+
return issues;
|
|
8592
|
+
}
|
|
8593
|
+
async function runArchCheck(projectRoot, config) {
|
|
8594
|
+
const issues = [];
|
|
8595
|
+
const rawArchConfig = config.architecture;
|
|
8596
|
+
const archConfig = ArchConfigSchema.parse(rawArchConfig ?? {});
|
|
8597
|
+
if (!archConfig.enabled) return issues;
|
|
8598
|
+
const results = await runAll(archConfig, projectRoot);
|
|
8599
|
+
const baselineManager = new ArchBaselineManager(projectRoot, archConfig.baselinePath);
|
|
8600
|
+
const baseline = baselineManager.load();
|
|
8601
|
+
if (baseline) {
|
|
8602
|
+
const diffResult = diff(results, baseline);
|
|
8603
|
+
if (!diffResult.passed) {
|
|
8604
|
+
for (const v of diffResult.newViolations) {
|
|
8590
8605
|
issues.push({
|
|
8591
|
-
severity:
|
|
8592
|
-
message:
|
|
8606
|
+
severity: v.severity,
|
|
8607
|
+
message: `[${v.category || "arch"}] NEW: ${v.detail}`,
|
|
8608
|
+
file: v.file
|
|
8593
8609
|
});
|
|
8594
|
-
break;
|
|
8595
8610
|
}
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
const baselineManager = new ArchBaselineManager(projectRoot, archConfig.baselinePath);
|
|
8602
|
-
const baseline = baselineManager.load();
|
|
8603
|
-
if (baseline) {
|
|
8604
|
-
const diffResult = diff(results, baseline);
|
|
8605
|
-
if (!diffResult.passed) {
|
|
8606
|
-
for (const v of diffResult.newViolations) {
|
|
8607
|
-
issues.push({
|
|
8608
|
-
severity: v.severity,
|
|
8609
|
-
message: `[${v.category || "arch"}] NEW: ${v.detail}`,
|
|
8610
|
-
file: v.file
|
|
8611
|
-
});
|
|
8612
|
-
}
|
|
8613
|
-
for (const r of diffResult.regressions) {
|
|
8614
|
-
issues.push({
|
|
8615
|
-
severity: "error",
|
|
8616
|
-
message: `[${r.category}] REGRESSION: ${r.currentValue} > ${r.baselineValue} (delta: ${r.delta})`
|
|
8617
|
-
});
|
|
8618
|
-
}
|
|
8619
|
-
}
|
|
8620
|
-
} else {
|
|
8621
|
-
for (const result of results) {
|
|
8622
|
-
for (const v of result.violations) {
|
|
8623
|
-
issues.push({
|
|
8624
|
-
severity: v.severity,
|
|
8625
|
-
message: `[${result.category}] ${v.detail}`,
|
|
8626
|
-
file: v.file
|
|
8627
|
-
});
|
|
8628
|
-
}
|
|
8629
|
-
}
|
|
8630
|
-
}
|
|
8631
|
-
break;
|
|
8611
|
+
for (const r of diffResult.regressions) {
|
|
8612
|
+
issues.push({
|
|
8613
|
+
severity: "error",
|
|
8614
|
+
message: `[${r.category}] REGRESSION: ${r.currentValue} > ${r.baselineValue} (delta: ${r.delta})`
|
|
8615
|
+
});
|
|
8632
8616
|
}
|
|
8633
8617
|
}
|
|
8618
|
+
} else {
|
|
8619
|
+
for (const result of results) {
|
|
8620
|
+
for (const v of result.violations) {
|
|
8621
|
+
issues.push({
|
|
8622
|
+
severity: v.severity,
|
|
8623
|
+
message: `[${result.category}] ${v.detail}`,
|
|
8624
|
+
file: v.file
|
|
8625
|
+
});
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
}
|
|
8629
|
+
return issues;
|
|
8630
|
+
}
|
|
8631
|
+
async function runSingleCheck(name, projectRoot, config) {
|
|
8632
|
+
const start = Date.now();
|
|
8633
|
+
const issues = [];
|
|
8634
|
+
try {
|
|
8635
|
+
switch (name) {
|
|
8636
|
+
case "validate":
|
|
8637
|
+
issues.push(...await runValidateCheck(projectRoot, config));
|
|
8638
|
+
break;
|
|
8639
|
+
case "deps":
|
|
8640
|
+
issues.push(...await runDepsCheck(projectRoot, config));
|
|
8641
|
+
break;
|
|
8642
|
+
case "docs":
|
|
8643
|
+
issues.push(...await runDocsCheck(projectRoot, config));
|
|
8644
|
+
break;
|
|
8645
|
+
case "entropy":
|
|
8646
|
+
issues.push(...await runEntropyCheck(projectRoot, config));
|
|
8647
|
+
break;
|
|
8648
|
+
case "security":
|
|
8649
|
+
issues.push(...await runSecurityCheck(projectRoot, config));
|
|
8650
|
+
break;
|
|
8651
|
+
case "perf":
|
|
8652
|
+
issues.push(...await runPerfCheck(projectRoot, config));
|
|
8653
|
+
break;
|
|
8654
|
+
case "phase-gate":
|
|
8655
|
+
issues.push(...await runPhaseGateCheck(projectRoot, config));
|
|
8656
|
+
break;
|
|
8657
|
+
case "arch":
|
|
8658
|
+
issues.push(...await runArchCheck(projectRoot, config));
|
|
8659
|
+
break;
|
|
8660
|
+
}
|
|
8634
8661
|
} catch (error) {
|
|
8635
8662
|
issues.push({
|
|
8636
8663
|
severity: "error",
|
|
@@ -9005,7 +9032,7 @@ async function readContextFile(projectRoot, filePath, reason) {
|
|
|
9005
9032
|
if (!result.ok) return null;
|
|
9006
9033
|
const content = result.value;
|
|
9007
9034
|
const lines = content.split("\n").length;
|
|
9008
|
-
const relPath = path14.isAbsolute(filePath) ?
|
|
9035
|
+
const relPath = path14.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
|
|
9009
9036
|
return { path: relPath, content, reason, lines };
|
|
9010
9037
|
}
|
|
9011
9038
|
function extractImportSources2(content) {
|
|
@@ -9023,7 +9050,7 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
|
|
|
9023
9050
|
const fromDir = path14.dirname(path14.join(projectRoot, fromFile));
|
|
9024
9051
|
const basePath = path14.resolve(fromDir, importSource);
|
|
9025
9052
|
if (!isWithinProject(basePath, projectRoot)) return null;
|
|
9026
|
-
const relBase =
|
|
9053
|
+
const relBase = relativePosix(projectRoot, basePath);
|
|
9027
9054
|
const candidates = [
|
|
9028
9055
|
relBase + ".ts",
|
|
9029
9056
|
relBase + ".tsx",
|
|
@@ -9042,7 +9069,7 @@ async function findTestFiles(projectRoot, sourceFile) {
|
|
|
9042
9069
|
const baseName = path14.basename(sourceFile, path14.extname(sourceFile));
|
|
9043
9070
|
const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
|
|
9044
9071
|
const results = await findFiles(pattern, projectRoot);
|
|
9045
|
-
return results.map((f) =>
|
|
9072
|
+
return results.map((f) => relativePosix(projectRoot, f));
|
|
9046
9073
|
}
|
|
9047
9074
|
async function gatherImportContext(projectRoot, changedFiles, budget) {
|
|
9048
9075
|
const contextFiles = [];
|
|
@@ -10904,7 +10931,7 @@ Run "harness update" to upgrade.`;
|
|
|
10904
10931
|
}
|
|
10905
10932
|
|
|
10906
10933
|
// src/index.ts
|
|
10907
|
-
var VERSION = "0.
|
|
10934
|
+
var VERSION = "0.13.0";
|
|
10908
10935
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10909
10936
|
0 && (module.exports = {
|
|
10910
10937
|
AGENT_DESCRIPTORS,
|