@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/index.mjs CHANGED
@@ -36,11 +36,12 @@ import {
36
36
  fileExists,
37
37
  findFiles,
38
38
  readFileContent,
39
+ relativePosix,
39
40
  resolveFileToLayer,
40
41
  runAll,
41
42
  validateDependencies,
42
43
  violationId
43
- } from "./chunk-ZHGBWFYD.mjs";
44
+ } from "./chunk-D6VFA6AS.mjs";
44
45
 
45
46
  // src/index.ts
46
47
  export * from "@harness-engineering/types";
@@ -365,7 +366,7 @@ async function validateAgentsMap(path20 = "./AGENTS.md") {
365
366
 
366
367
  // src/context/doc-coverage.ts
367
368
  import { minimatch } from "minimatch";
368
- import { basename, relative } from "path";
369
+ import { basename } from "path";
369
370
  function determineImportance(filePath) {
370
371
  const name = basename(filePath).toLowerCase();
371
372
  if (name === "index.ts" || name === "index.js" || name === "main.ts") {
@@ -405,7 +406,7 @@ async function checkDocCoverage(domain, options = {}) {
405
406
  try {
406
407
  const sourceFiles = await findFiles("**/*.{ts,js,tsx,jsx}", sourceDir);
407
408
  const filteredSourceFiles = sourceFiles.filter((file) => {
408
- const relativePath = relative(sourceDir, file);
409
+ const relativePath = relativePosix(sourceDir, file);
409
410
  return !excludePatterns.some((pattern) => {
410
411
  return minimatch(relativePath, pattern, { dot: true }) || minimatch(file, pattern, { dot: true });
411
412
  });
@@ -428,7 +429,7 @@ async function checkDocCoverage(domain, options = {}) {
428
429
  const undocumented = [];
429
430
  const gaps = [];
430
431
  for (const sourceFile of filteredSourceFiles) {
431
- const relativePath = relative(sourceDir, sourceFile);
432
+ const relativePath = relativePosix(sourceDir, sourceFile);
432
433
  const fileName = basename(sourceFile);
433
434
  const isDocumented = documentedPaths.has(relativePath) || documentedPaths.has(fileName) || documentedPaths.has(`src/${relativePath}`);
434
435
  if (isDocumented) {
@@ -464,7 +465,7 @@ async function checkDocCoverage(domain, options = {}) {
464
465
  }
465
466
 
466
467
  // src/context/knowledge-map.ts
467
- import { join as join2, basename as basename2, relative as relative2 } from "path";
468
+ import { join as join2, basename as basename2 } from "path";
468
469
  function suggestFix(path20, existingFiles) {
469
470
  const targetName = basename2(path20).toLowerCase();
470
471
  const similar = existingFiles.find((file) => {
@@ -488,7 +489,7 @@ async function validateKnowledgeMap(rootDir = process.cwd()) {
488
489
  totalLinks: agentsTotalLinks
489
490
  } = agentsResult.value;
490
491
  const existingFiles = await findFiles("**/*", rootDir);
491
- const relativeExistingFiles = existingFiles.map((f) => relative2(rootDir, f));
492
+ const relativeExistingFiles = existingFiles.map((f) => relativePosix(rootDir, f));
492
493
  const brokenLinks = agentsBrokenLinks.map((link) => {
493
494
  const section = sections.find(
494
495
  (s) => s.links.some((l) => l.path === link.path && l.line === link.line)
@@ -513,7 +514,7 @@ async function validateKnowledgeMap(rootDir = process.cwd()) {
513
514
  }
514
515
 
515
516
  // src/context/generate.ts
516
- import { relative as relative3, basename as basename3, dirname as dirname2 } from "path";
517
+ import { basename as basename3, dirname as dirname2 } from "path";
517
518
  var DEFAULT_SECTIONS = [
518
519
  {
519
520
  name: "Documentation",
@@ -529,7 +530,7 @@ var DEFAULT_SECTIONS = [
529
530
  function groupByDirectory(files, rootDir) {
530
531
  const groups = /* @__PURE__ */ new Map();
531
532
  for (const file of files) {
532
- const relativePath = relative3(rootDir, file);
533
+ const relativePath = relativePosix(rootDir, file);
533
534
  const dir = dirname2(relativePath);
534
535
  if (!groups.has(dir)) {
535
536
  groups.set(dir, []);
@@ -585,7 +586,7 @@ async function generateAgentsMap(config, graphSections) {
585
586
  allFiles.push(...files);
586
587
  }
587
588
  const filteredFiles = allFiles.filter((file) => {
588
- const relativePath = relative3(rootDir, file);
589
+ const relativePath = relativePosix(rootDir, file);
589
590
  return !matchesExcludePattern(relativePath, excludePaths);
590
591
  });
591
592
  lines.push("## Repository Structure");
@@ -613,11 +614,11 @@ async function generateAgentsMap(config, graphSections) {
613
614
  }
614
615
  const sectionFiles = await findFiles(section.pattern, rootDir);
615
616
  const filteredSectionFiles = sectionFiles.filter((file) => {
616
- const relativePath = relative3(rootDir, file);
617
+ const relativePath = relativePosix(rootDir, file);
617
618
  return !matchesExcludePattern(relativePath, excludePaths);
618
619
  });
619
620
  for (const file of filteredSectionFiles.slice(0, 20)) {
620
- lines.push(formatFileLink(relative3(rootDir, file)));
621
+ lines.push(formatFileLink(relativePosix(rootDir, file)));
621
622
  }
622
623
  if (filteredSectionFiles.length > 20) {
623
624
  lines.push(`- _... and ${filteredSectionFiles.length - 20} more files_`);
@@ -1572,7 +1573,7 @@ var TypeScriptParser = class {
1572
1573
  };
1573
1574
 
1574
1575
  // src/entropy/snapshot.ts
1575
- import { join as join3, resolve, relative as relative4 } from "path";
1576
+ import { join as join3, resolve } from "path";
1576
1577
  import { minimatch as minimatch2 } from "minimatch";
1577
1578
  async function resolveEntryPoints(rootDir, explicitEntries) {
1578
1579
  if (explicitEntries && explicitEntries.length > 0) {
@@ -1836,7 +1837,7 @@ async function buildSnapshot(config) {
1836
1837
  sourceFilePaths.push(...files2);
1837
1838
  }
1838
1839
  sourceFilePaths = sourceFilePaths.filter((f) => {
1839
- const rel = relative4(rootDir, f);
1840
+ const rel = relativePosix(rootDir, f);
1840
1841
  return !excludePatterns.some((p) => minimatch2(rel, p));
1841
1842
  });
1842
1843
  const files = [];
@@ -2368,9 +2369,8 @@ async function detectDeadCode(snapshot, graphDeadCodeData) {
2368
2369
 
2369
2370
  // src/entropy/detectors/patterns.ts
2370
2371
  import { minimatch as minimatch3 } from "minimatch";
2371
- import { relative as relative5 } from "path";
2372
2372
  function fileMatchesPattern(filePath, pattern, rootDir) {
2373
- const relativePath = relative5(rootDir, filePath);
2373
+ const relativePath = relativePosix(rootDir, filePath);
2374
2374
  return minimatch3(relativePath, pattern);
2375
2375
  }
2376
2376
  function checkConfigPattern(pattern, file, rootDir) {
@@ -6405,238 +6405,270 @@ var ALL_CHECKS = [
6405
6405
  "phase-gate",
6406
6406
  "arch"
6407
6407
  ];
6408
- async function runSingleCheck(name, projectRoot, config) {
6409
- const start = Date.now();
6408
+ async function runValidateCheck(projectRoot, config) {
6410
6409
  const issues = [];
6411
- try {
6412
- switch (name) {
6413
- case "validate": {
6414
- const agentsPath = path12.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
6415
- const result = await validateAgentsMap(agentsPath);
6416
- if (!result.ok) {
6417
- issues.push({ severity: "error", message: result.error.message });
6418
- } else if (!result.value.valid) {
6419
- if (result.value.errors) {
6420
- for (const err of result.value.errors) {
6421
- issues.push({ severity: "error", message: err.message });
6422
- }
6423
- }
6424
- for (const section of result.value.missingSections) {
6425
- issues.push({ severity: "warning", message: `Missing section: ${section}` });
6426
- }
6427
- for (const link of result.value.brokenLinks) {
6428
- issues.push({
6429
- severity: "warning",
6430
- message: `Broken link: ${link.text} \u2192 ${link.path}`,
6431
- file: link.path
6432
- });
6433
- }
6434
- }
6435
- break;
6410
+ const agentsPath = path12.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
6411
+ const result = await validateAgentsMap(agentsPath);
6412
+ if (!result.ok) {
6413
+ issues.push({ severity: "error", message: result.error.message });
6414
+ } else if (!result.value.valid) {
6415
+ if (result.value.errors) {
6416
+ for (const err of result.value.errors) {
6417
+ issues.push({ severity: "error", message: err.message });
6418
+ }
6419
+ }
6420
+ for (const section of result.value.missingSections) {
6421
+ issues.push({ severity: "warning", message: `Missing section: ${section}` });
6422
+ }
6423
+ for (const link of result.value.brokenLinks) {
6424
+ issues.push({
6425
+ severity: "warning",
6426
+ message: `Broken link: ${link.text} \u2192 ${link.path}`,
6427
+ file: link.path
6428
+ });
6429
+ }
6430
+ }
6431
+ return issues;
6432
+ }
6433
+ async function runDepsCheck(projectRoot, config) {
6434
+ const issues = [];
6435
+ const rawLayers = config.layers;
6436
+ if (rawLayers && rawLayers.length > 0) {
6437
+ const parser = new TypeScriptParser();
6438
+ const layers = rawLayers.map(
6439
+ (l) => defineLayer(
6440
+ l.name,
6441
+ Array.isArray(l.patterns) ? l.patterns : [l.pattern],
6442
+ l.allowedDependencies
6443
+ )
6444
+ );
6445
+ const result = await validateDependencies({
6446
+ layers,
6447
+ rootDir: projectRoot,
6448
+ parser
6449
+ });
6450
+ if (!result.ok) {
6451
+ issues.push({ severity: "error", message: result.error.message });
6452
+ } else if (result.value.violations.length > 0) {
6453
+ for (const v of result.value.violations) {
6454
+ issues.push({
6455
+ severity: "error",
6456
+ message: `${v.reason}: ${v.file} imports ${v.imports} (${v.fromLayer} \u2192 ${v.toLayer})`,
6457
+ file: v.file,
6458
+ line: v.line
6459
+ });
6436
6460
  }
6437
- case "deps": {
6438
- const rawLayers = config.layers;
6439
- if (rawLayers && rawLayers.length > 0) {
6440
- const parser = new TypeScriptParser();
6441
- const layers = rawLayers.map(
6442
- (l) => defineLayer(
6443
- l.name,
6444
- Array.isArray(l.patterns) ? l.patterns : [l.pattern],
6445
- l.allowedDependencies
6446
- )
6447
- );
6448
- const result = await validateDependencies({
6449
- layers,
6450
- rootDir: projectRoot,
6451
- parser
6452
- });
6453
- if (!result.ok) {
6454
- issues.push({ severity: "error", message: result.error.message });
6455
- } else if (result.value.violations.length > 0) {
6456
- for (const v of result.value.violations) {
6457
- issues.push({
6458
- severity: "error",
6459
- message: `${v.reason}: ${v.file} imports ${v.imports} (${v.fromLayer} \u2192 ${v.toLayer})`,
6460
- file: v.file,
6461
- line: v.line
6462
- });
6463
- }
6464
- }
6465
- }
6466
- break;
6461
+ }
6462
+ }
6463
+ return issues;
6464
+ }
6465
+ async function runDocsCheck(projectRoot, config) {
6466
+ const issues = [];
6467
+ const docsDir = path12.join(projectRoot, config.docsDir ?? "docs");
6468
+ const entropyConfig = config.entropy || {};
6469
+ const result = await checkDocCoverage("project", {
6470
+ docsDir,
6471
+ sourceDir: projectRoot,
6472
+ excludePatterns: entropyConfig.excludePatterns || [
6473
+ "**/node_modules/**",
6474
+ "**/dist/**",
6475
+ "**/*.test.ts",
6476
+ "**/fixtures/**"
6477
+ ]
6478
+ });
6479
+ if (!result.ok) {
6480
+ issues.push({ severity: "warning", message: result.error.message });
6481
+ } else if (result.value.gaps.length > 0) {
6482
+ for (const gap of result.value.gaps) {
6483
+ issues.push({
6484
+ severity: "warning",
6485
+ message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6486
+ file: gap.file
6487
+ });
6488
+ }
6489
+ }
6490
+ return issues;
6491
+ }
6492
+ async function runEntropyCheck(projectRoot, _config) {
6493
+ const issues = [];
6494
+ const analyzer = new EntropyAnalyzer({
6495
+ rootDir: projectRoot,
6496
+ analyze: { drift: true, deadCode: true, patterns: false }
6497
+ });
6498
+ const result = await analyzer.analyze();
6499
+ if (!result.ok) {
6500
+ issues.push({ severity: "warning", message: result.error.message });
6501
+ } else {
6502
+ const report = result.value;
6503
+ if (report.drift) {
6504
+ for (const drift of report.drift.drifts) {
6505
+ issues.push({
6506
+ severity: "warning",
6507
+ message: `Doc drift (${drift.type}): ${drift.details}`,
6508
+ file: drift.docFile,
6509
+ line: drift.line
6510
+ });
6467
6511
  }
6468
- case "docs": {
6469
- const docsDir = path12.join(projectRoot, config.docsDir ?? "docs");
6470
- const entropyConfig = config.entropy || {};
6471
- const result = await checkDocCoverage("project", {
6472
- docsDir,
6473
- sourceDir: projectRoot,
6474
- excludePatterns: entropyConfig.excludePatterns || [
6475
- "**/node_modules/**",
6476
- "**/dist/**",
6477
- "**/*.test.ts",
6478
- "**/fixtures/**"
6479
- ]
6512
+ }
6513
+ if (report.deadCode) {
6514
+ for (const dead of report.deadCode.deadExports) {
6515
+ issues.push({
6516
+ severity: "warning",
6517
+ message: `Dead export: ${dead.name}`,
6518
+ file: dead.file,
6519
+ line: dead.line
6480
6520
  });
6481
- if (!result.ok) {
6482
- issues.push({ severity: "warning", message: result.error.message });
6483
- } else if (result.value.gaps.length > 0) {
6484
- for (const gap of result.value.gaps) {
6485
- issues.push({
6486
- severity: "warning",
6487
- message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6488
- file: gap.file
6489
- });
6490
- }
6491
- }
6492
- break;
6493
6521
  }
6494
- case "entropy": {
6495
- const analyzer = new EntropyAnalyzer({
6496
- rootDir: projectRoot,
6497
- analyze: { drift: true, deadCode: true, patterns: false }
6522
+ }
6523
+ }
6524
+ return issues;
6525
+ }
6526
+ async function runSecurityCheck(projectRoot, config) {
6527
+ const issues = [];
6528
+ const securityConfig = parseSecurityConfig(config.security);
6529
+ if (!securityConfig.enabled) return issues;
6530
+ const scanner = new SecurityScanner(securityConfig);
6531
+ scanner.configureForProject(projectRoot);
6532
+ const { glob: globFn } = await import("glob");
6533
+ const sourceFiles = await globFn("**/*.{ts,tsx,js,jsx,go,py}", {
6534
+ cwd: projectRoot,
6535
+ ignore: securityConfig.exclude ?? [
6536
+ "**/node_modules/**",
6537
+ "**/dist/**",
6538
+ "**/*.test.ts",
6539
+ "**/fixtures/**"
6540
+ ],
6541
+ absolute: true
6542
+ });
6543
+ const scanResult = await scanner.scanFiles(sourceFiles);
6544
+ for (const finding of scanResult.findings) {
6545
+ issues.push({
6546
+ severity: finding.severity === "info" ? "warning" : finding.severity,
6547
+ message: `[${finding.ruleId}] ${finding.message}: ${finding.match}`,
6548
+ file: finding.file,
6549
+ line: finding.line
6550
+ });
6551
+ }
6552
+ return issues;
6553
+ }
6554
+ async function runPerfCheck(projectRoot, config) {
6555
+ const issues = [];
6556
+ const perfConfig = config.performance || {};
6557
+ const perfAnalyzer = new EntropyAnalyzer({
6558
+ rootDir: projectRoot,
6559
+ analyze: {
6560
+ complexity: perfConfig.complexity || true,
6561
+ coupling: perfConfig.coupling || true,
6562
+ sizeBudget: perfConfig.sizeBudget || false
6563
+ }
6564
+ });
6565
+ const perfResult = await perfAnalyzer.analyze();
6566
+ if (!perfResult.ok) {
6567
+ issues.push({ severity: "warning", message: perfResult.error.message });
6568
+ } else {
6569
+ const perfReport = perfResult.value;
6570
+ if (perfReport.complexity) {
6571
+ for (const v of perfReport.complexity.violations) {
6572
+ issues.push({
6573
+ severity: v.severity === "info" ? "warning" : v.severity,
6574
+ message: `[Tier ${v.tier}] ${v.metric}: ${v.function} in ${v.file} (${v.value} > ${v.threshold})`,
6575
+ file: v.file,
6576
+ line: v.line
6498
6577
  });
6499
- const result = await analyzer.analyze();
6500
- if (!result.ok) {
6501
- issues.push({ severity: "warning", message: result.error.message });
6502
- } else {
6503
- const report = result.value;
6504
- if (report.drift) {
6505
- for (const drift of report.drift.drifts) {
6506
- issues.push({
6507
- severity: "warning",
6508
- message: `Doc drift (${drift.type}): ${drift.details}`,
6509
- file: drift.docFile,
6510
- line: drift.line
6511
- });
6512
- }
6513
- }
6514
- if (report.deadCode) {
6515
- for (const dead of report.deadCode.deadExports) {
6516
- issues.push({
6517
- severity: "warning",
6518
- message: `Dead export: ${dead.name}`,
6519
- file: dead.file,
6520
- line: dead.line
6521
- });
6522
- }
6523
- }
6524
- }
6525
- break;
6526
6578
  }
6527
- case "security": {
6528
- const securityConfig = parseSecurityConfig(config.security);
6529
- if (!securityConfig.enabled) break;
6530
- const scanner = new SecurityScanner(securityConfig);
6531
- scanner.configureForProject(projectRoot);
6532
- const { glob: globFn } = await import("glob");
6533
- const sourceFiles = await globFn("**/*.{ts,tsx,js,jsx,go,py}", {
6534
- cwd: projectRoot,
6535
- ignore: securityConfig.exclude ?? [
6536
- "**/node_modules/**",
6537
- "**/dist/**",
6538
- "**/*.test.ts",
6539
- "**/fixtures/**"
6540
- ],
6541
- absolute: true
6579
+ }
6580
+ if (perfReport.coupling) {
6581
+ for (const v of perfReport.coupling.violations) {
6582
+ issues.push({
6583
+ severity: v.severity === "info" ? "warning" : v.severity,
6584
+ message: `[Tier ${v.tier}] ${v.metric}: ${v.file} (${v.value} > ${v.threshold})`,
6585
+ file: v.file
6542
6586
  });
6543
- const scanResult = await scanner.scanFiles(sourceFiles);
6544
- for (const finding of scanResult.findings) {
6545
- issues.push({
6546
- severity: finding.severity === "info" ? "warning" : finding.severity,
6547
- message: `[${finding.ruleId}] ${finding.message}: ${finding.match}`,
6548
- file: finding.file,
6549
- line: finding.line
6550
- });
6551
- }
6552
- break;
6553
6587
  }
6554
- case "perf": {
6555
- const perfConfig = config.performance || {};
6556
- const perfAnalyzer = new EntropyAnalyzer({
6557
- rootDir: projectRoot,
6558
- analyze: {
6559
- complexity: perfConfig.complexity || true,
6560
- coupling: perfConfig.coupling || true,
6561
- sizeBudget: perfConfig.sizeBudget || false
6562
- }
6588
+ }
6589
+ }
6590
+ return issues;
6591
+ }
6592
+ async function runPhaseGateCheck(_projectRoot, config) {
6593
+ const issues = [];
6594
+ const phaseGates = config.phaseGates;
6595
+ if (!phaseGates?.enabled) {
6596
+ return issues;
6597
+ }
6598
+ issues.push({
6599
+ severity: "warning",
6600
+ message: "Phase gate is enabled but requires CLI context. Run `harness check-phase-gate` separately for full validation."
6601
+ });
6602
+ return issues;
6603
+ }
6604
+ async function runArchCheck(projectRoot, config) {
6605
+ const issues = [];
6606
+ const rawArchConfig = config.architecture;
6607
+ const archConfig = ArchConfigSchema.parse(rawArchConfig ?? {});
6608
+ if (!archConfig.enabled) return issues;
6609
+ const results = await runAll(archConfig, projectRoot);
6610
+ const baselineManager = new ArchBaselineManager(projectRoot, archConfig.baselinePath);
6611
+ const baseline = baselineManager.load();
6612
+ if (baseline) {
6613
+ const diffResult = diff(results, baseline);
6614
+ if (!diffResult.passed) {
6615
+ for (const v of diffResult.newViolations) {
6616
+ issues.push({
6617
+ severity: v.severity,
6618
+ message: `[${v.category || "arch"}] NEW: ${v.detail}`,
6619
+ file: v.file
6563
6620
  });
6564
- const perfResult = await perfAnalyzer.analyze();
6565
- if (!perfResult.ok) {
6566
- issues.push({ severity: "warning", message: perfResult.error.message });
6567
- } else {
6568
- const perfReport = perfResult.value;
6569
- if (perfReport.complexity) {
6570
- for (const v of perfReport.complexity.violations) {
6571
- issues.push({
6572
- severity: v.severity === "info" ? "warning" : v.severity,
6573
- message: `[Tier ${v.tier}] ${v.metric}: ${v.function} in ${v.file} (${v.value} > ${v.threshold})`,
6574
- file: v.file,
6575
- line: v.line
6576
- });
6577
- }
6578
- }
6579
- if (perfReport.coupling) {
6580
- for (const v of perfReport.coupling.violations) {
6581
- issues.push({
6582
- severity: v.severity === "info" ? "warning" : v.severity,
6583
- message: `[Tier ${v.tier}] ${v.metric}: ${v.file} (${v.value} > ${v.threshold})`,
6584
- file: v.file
6585
- });
6586
- }
6587
- }
6588
- }
6589
- break;
6590
6621
  }
6591
- case "phase-gate": {
6592
- const phaseGates = config.phaseGates;
6593
- if (!phaseGates?.enabled) {
6594
- break;
6595
- }
6622
+ for (const r of diffResult.regressions) {
6596
6623
  issues.push({
6597
- severity: "warning",
6598
- message: "Phase gate is enabled but requires CLI context. Run `harness check-phase-gate` separately for full validation."
6624
+ severity: "error",
6625
+ message: `[${r.category}] REGRESSION: ${r.currentValue} > ${r.baselineValue} (delta: ${r.delta})`
6599
6626
  });
6600
- break;
6601
6627
  }
6602
- case "arch": {
6603
- const rawArchConfig = config.architecture;
6604
- const archConfig = ArchConfigSchema.parse(rawArchConfig ?? {});
6605
- if (!archConfig.enabled) break;
6606
- const results = await runAll(archConfig, projectRoot);
6607
- const baselineManager = new ArchBaselineManager(projectRoot, archConfig.baselinePath);
6608
- const baseline = baselineManager.load();
6609
- if (baseline) {
6610
- const diffResult = diff(results, baseline);
6611
- if (!diffResult.passed) {
6612
- for (const v of diffResult.newViolations) {
6613
- issues.push({
6614
- severity: v.severity,
6615
- message: `[${v.category || "arch"}] NEW: ${v.detail}`,
6616
- file: v.file
6617
- });
6618
- }
6619
- for (const r of diffResult.regressions) {
6620
- issues.push({
6621
- severity: "error",
6622
- message: `[${r.category}] REGRESSION: ${r.currentValue} > ${r.baselineValue} (delta: ${r.delta})`
6623
- });
6624
- }
6625
- }
6626
- } else {
6627
- for (const result of results) {
6628
- for (const v of result.violations) {
6629
- issues.push({
6630
- severity: v.severity,
6631
- message: `[${result.category}] ${v.detail}`,
6632
- file: v.file
6633
- });
6634
- }
6635
- }
6636
- }
6637
- break;
6628
+ }
6629
+ } else {
6630
+ for (const result of results) {
6631
+ for (const v of result.violations) {
6632
+ issues.push({
6633
+ severity: v.severity,
6634
+ message: `[${result.category}] ${v.detail}`,
6635
+ file: v.file
6636
+ });
6638
6637
  }
6639
6638
  }
6639
+ }
6640
+ return issues;
6641
+ }
6642
+ async function runSingleCheck(name, projectRoot, config) {
6643
+ const start = Date.now();
6644
+ const issues = [];
6645
+ try {
6646
+ switch (name) {
6647
+ case "validate":
6648
+ issues.push(...await runValidateCheck(projectRoot, config));
6649
+ break;
6650
+ case "deps":
6651
+ issues.push(...await runDepsCheck(projectRoot, config));
6652
+ break;
6653
+ case "docs":
6654
+ issues.push(...await runDocsCheck(projectRoot, config));
6655
+ break;
6656
+ case "entropy":
6657
+ issues.push(...await runEntropyCheck(projectRoot, config));
6658
+ break;
6659
+ case "security":
6660
+ issues.push(...await runSecurityCheck(projectRoot, config));
6661
+ break;
6662
+ case "perf":
6663
+ issues.push(...await runPerfCheck(projectRoot, config));
6664
+ break;
6665
+ case "phase-gate":
6666
+ issues.push(...await runPhaseGateCheck(projectRoot, config));
6667
+ break;
6668
+ case "arch":
6669
+ issues.push(...await runArchCheck(projectRoot, config));
6670
+ break;
6671
+ }
6640
6672
  } catch (error) {
6641
6673
  issues.push({
6642
6674
  severity: "error",
@@ -7011,7 +7043,7 @@ async function readContextFile(projectRoot, filePath, reason) {
7011
7043
  if (!result.ok) return null;
7012
7044
  const content = result.value;
7013
7045
  const lines = content.split("\n").length;
7014
- const relPath = path14.isAbsolute(filePath) ? path14.relative(projectRoot, filePath) : filePath;
7046
+ const relPath = path14.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
7015
7047
  return { path: relPath, content, reason, lines };
7016
7048
  }
7017
7049
  function extractImportSources(content) {
@@ -7029,7 +7061,7 @@ async function resolveImportPath(projectRoot, fromFile, importSource) {
7029
7061
  const fromDir = path14.dirname(path14.join(projectRoot, fromFile));
7030
7062
  const basePath = path14.resolve(fromDir, importSource);
7031
7063
  if (!isWithinProject(basePath, projectRoot)) return null;
7032
- const relBase = path14.relative(projectRoot, basePath);
7064
+ const relBase = relativePosix(projectRoot, basePath);
7033
7065
  const candidates = [
7034
7066
  relBase + ".ts",
7035
7067
  relBase + ".tsx",
@@ -7048,7 +7080,7 @@ async function findTestFiles(projectRoot, sourceFile) {
7048
7080
  const baseName = path14.basename(sourceFile, path14.extname(sourceFile));
7049
7081
  const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
7050
7082
  const results = await findFiles(pattern, projectRoot);
7051
- return results.map((f) => path14.relative(projectRoot, f));
7083
+ return results.map((f) => relativePosix(projectRoot, f));
7052
7084
  }
7053
7085
  async function gatherImportContext(projectRoot, changedFiles, budget) {
7054
7086
  const contextFiles = [];
@@ -8910,7 +8942,7 @@ Run "harness update" to upgrade.`;
8910
8942
  }
8911
8943
 
8912
8944
  // src/index.ts
8913
- var VERSION = "0.11.0";
8945
+ var VERSION = "0.13.0";
8914
8946
  export {
8915
8947
  AGENT_DESCRIPTORS,
8916
8948
  ARCHITECTURE_DESCRIPTOR,