@harness-engineering/core 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -3923,6 +3923,12 @@ declare function getUpdateNotification(currentVersion: string): string | null;
3923
3923
  * Core library for Harness Engineering toolkit
3924
3924
  */
3925
3925
 
3926
- declare const VERSION = "0.8.0";
3926
+ /**
3927
+ * @deprecated Read the CLI version from `@harness-engineering/cli/package.json`
3928
+ * instead. This hardcoded constant drifts from the actual CLI version on each
3929
+ * release. Kept only as a fallback for consumers that cannot resolve the CLI
3930
+ * package at runtime.
3931
+ */
3932
+ declare const VERSION = "1.8.2";
3927
3933
 
3928
3934
  export { AGENT_DESCRIPTORS, ARCHITECTURE_DESCRIPTOR, type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentReviewResult, type AgentType, type AgentsMapConfig, BUG_DETECTION_DESCRIPTOR, type BaseError, type Baseline, BaselineManager, type BaselinesFile, type BenchmarkResult, type BenchmarkRunOptions, BenchmarkRunner, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, COMPLIANCE_DESCRIPTOR, type ChangeType, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CleanupFinding, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommentedCodeBlock, type CommitFormat, type CommitHistoryEntry, type CommitValidation, type ComplexityConfig, type ComplexityReport, type ComplexityThresholds, type ComplexityViolation, type ConfigError, type ConfigPattern, type Confirmation, ConfirmationSchema, ConsoleSink, type ConstraintError, type ContextBundle, type ContextError, type ContextFile, type ContextFilterResult, type ContextScopeOptions, type Convention, type CouplingConfig, type CouplingReport, type CouplingThresholds, type CouplingViolation, type CoverageOptions, type CoverageReport, type CriticalPathEntry, CriticalPathResolver, type CriticalPathSet, type CustomRule, type CustomRuleResult, DEFAULT_PROVIDER_TIERS, DEFAULT_SECURITY_CONFIG, DEFAULT_STATE, DEFAULT_STREAM_INDEX, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DeduplicateFindingsOptions, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DiffInfo, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, type EligibilityResult, type EmitInteractionInput, EmitInteractionInputSchema, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, ExclusionSet, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FanOutOptions, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type FindingSeverity, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenImportViolation, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type GitHubInlineComment, type GraphAdapter, type GraphComplexityData, type GraphCouplingData, type GraphCoverageData, type GraphCriticalPathData, type GraphDependencyData, type GraphHarnessCheckData, type GraphImpactData, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type HotspotContext, type Import, type InlineReference, type IntegrityReport, type InteractionType, InteractionTypeSchema, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type MechanicalCheckOptions, type MechanicalCheckResult, type MechanicalCheckStatus, type MechanicalFinding, type Metric, type ModelProvider, type ModelTier, type ModelTierConfig, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type OrphanedDep, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineContext, type PipelineFlags, type PipelineOptions, type PipelineResult, type PrMetadata, type PriorReview, type ProviderDefaults, type Question, QuestionSchema, REQUIRED_SECTIONS, type ReachabilityNode, RegressionDetector, type RegressionReport, type RegressionResult, type ReviewAgentDescriptor, type ReviewAssessment, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewDomain, type ReviewFinding, type ReviewItem, type ReviewOutputOptions, type ReviewPipelineResult, type ReviewStrength, type RuleOverride, RuleRegistry, type RunCIChecksInput, type RunPipelineOptions, SECURITY_DESCRIPTOR, type SafetyLevel, type ScanResult, type SecurityCategory, type SecurityConfidence, type SecurityConfig, SecurityConfigSchema, type SecurityFinding, type SecurityRule, SecurityScanner, type SecuritySeverity, type SelfReviewConfig, type SizeBudgetConfig, type SizeBudgetReport, type SizeBudgetViolation, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StreamIndex, StreamIndexSchema, type StreamInfo, StreamInfoSchema, type StructureValidation, type Suggestion, type SuggestionReport, type SyncChange, type SyncOptions, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type Transition, TransitionSchema, type TurnExecutor, TypeScriptParser, type UnusedImport, type UpdateCheckState, VERSION, type ValidateFindingsOptions, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, applyHotspotDowngrade, archiveFailures, archiveStream, buildDependencyGraph, buildExclusionSet, buildSnapshot, checkDocCoverage, checkEligibility, classifyFinding, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createCommentedCodeFixes, createError, createFixes, createForbiddenImportFixes, createOrphanedDepFixes, createParseError, createSelfReview, createStream, cryptoRules, deduplicateCleanupFindings, deduplicateFindings, defineLayer, deserializationRules, detectChangeType, detectCircularDeps, detectCircularDepsInFiles, detectComplexityViolations, detectCouplingViolations, detectDeadCode, detectDocDrift, detectPatternViolations, detectSizeBudgetViolations, detectStack, determineAssessment, executeWorkflow, expressRules, extractMarkdownLinks, extractSections, fanOutReview, formatFindingBlock, formatGitHubComment, formatGitHubSummary, formatTerminalOutput, generateAgentsMap, generateSuggestions, getActionEmitter, getExitCode, getFeedbackConfig, getPhaseCategories, getStreamForBranch, getUpdateNotification, goRules, injectionRules, isSmallSuggestion, isUpdateCheckEnabled, listStreams, loadFailures, loadHandoff, loadRelevantLearnings, loadState, loadStreamIndex, logAgentAction, migrateToStreams, networkRules, nodeRules, parseDiff, parseRoadmap, parseSecurityConfig, parseSize, pathTraversalRules, previewFix, reactRules, readCheckState, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, resolveModelTier, resolveRuleSeverity, resolveStreamPath, runArchitectureAgent, runBugDetectionAgent, runCIChecks, runComplianceAgent, runMechanicalChecks, runMechanicalGate, runMultiTurnPipeline, runPipeline, runReviewPipeline, runSecurityAgent, saveHandoff, saveState, saveStreamIndex, scopeContext, secretRules, serializeRoadmap, setActiveStream, shouldRunCheck, spawnBackgroundCheck, syncRoadmap, touchStream, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateFindings, validateKnowledgeMap, validatePatternConfig, xssRules };
package/dist/index.d.ts CHANGED
@@ -3923,6 +3923,12 @@ declare function getUpdateNotification(currentVersion: string): string | null;
3923
3923
  * Core library for Harness Engineering toolkit
3924
3924
  */
3925
3925
 
3926
- declare const VERSION = "0.8.0";
3926
+ /**
3927
+ * @deprecated Read the CLI version from `@harness-engineering/cli/package.json`
3928
+ * instead. This hardcoded constant drifts from the actual CLI version on each
3929
+ * release. Kept only as a fallback for consumers that cannot resolve the CLI
3930
+ * package at runtime.
3931
+ */
3932
+ declare const VERSION = "1.8.2";
3927
3933
 
3928
3934
  export { AGENT_DESCRIPTORS, ARCHITECTURE_DESCRIPTOR, type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentReviewResult, type AgentType, type AgentsMapConfig, BUG_DETECTION_DESCRIPTOR, type BaseError, type Baseline, BaselineManager, type BaselinesFile, type BenchmarkResult, type BenchmarkRunOptions, BenchmarkRunner, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, COMPLIANCE_DESCRIPTOR, type ChangeType, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CleanupFinding, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommentedCodeBlock, type CommitFormat, type CommitHistoryEntry, type CommitValidation, type ComplexityConfig, type ComplexityReport, type ComplexityThresholds, type ComplexityViolation, type ConfigError, type ConfigPattern, type Confirmation, ConfirmationSchema, ConsoleSink, type ConstraintError, type ContextBundle, type ContextError, type ContextFile, type ContextFilterResult, type ContextScopeOptions, type Convention, type CouplingConfig, type CouplingReport, type CouplingThresholds, type CouplingViolation, type CoverageOptions, type CoverageReport, type CriticalPathEntry, CriticalPathResolver, type CriticalPathSet, type CustomRule, type CustomRuleResult, DEFAULT_PROVIDER_TIERS, DEFAULT_SECURITY_CONFIG, DEFAULT_STATE, DEFAULT_STREAM_INDEX, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DeduplicateFindingsOptions, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DiffInfo, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, type EligibilityResult, type EmitInteractionInput, EmitInteractionInputSchema, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, ExclusionSet, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FanOutOptions, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type FindingSeverity, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenImportViolation, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type GitHubInlineComment, type GraphAdapter, type GraphComplexityData, type GraphCouplingData, type GraphCoverageData, type GraphCriticalPathData, type GraphDependencyData, type GraphHarnessCheckData, type GraphImpactData, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type HotspotContext, type Import, type InlineReference, type IntegrityReport, type InteractionType, InteractionTypeSchema, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type MechanicalCheckOptions, type MechanicalCheckResult, type MechanicalCheckStatus, type MechanicalFinding, type Metric, type ModelProvider, type ModelTier, type ModelTierConfig, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type OrphanedDep, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineContext, type PipelineFlags, type PipelineOptions, type PipelineResult, type PrMetadata, type PriorReview, type ProviderDefaults, type Question, QuestionSchema, REQUIRED_SECTIONS, type ReachabilityNode, RegressionDetector, type RegressionReport, type RegressionResult, type ReviewAgentDescriptor, type ReviewAssessment, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewDomain, type ReviewFinding, type ReviewItem, type ReviewOutputOptions, type ReviewPipelineResult, type ReviewStrength, type RuleOverride, RuleRegistry, type RunCIChecksInput, type RunPipelineOptions, SECURITY_DESCRIPTOR, type SafetyLevel, type ScanResult, type SecurityCategory, type SecurityConfidence, type SecurityConfig, SecurityConfigSchema, type SecurityFinding, type SecurityRule, SecurityScanner, type SecuritySeverity, type SelfReviewConfig, type SizeBudgetConfig, type SizeBudgetReport, type SizeBudgetViolation, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StreamIndex, StreamIndexSchema, type StreamInfo, StreamInfoSchema, type StructureValidation, type Suggestion, type SuggestionReport, type SyncChange, type SyncOptions, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type Transition, TransitionSchema, type TurnExecutor, TypeScriptParser, type UnusedImport, type UpdateCheckState, VERSION, type ValidateFindingsOptions, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, applyHotspotDowngrade, archiveFailures, archiveStream, buildDependencyGraph, buildExclusionSet, buildSnapshot, checkDocCoverage, checkEligibility, classifyFinding, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createCommentedCodeFixes, createError, createFixes, createForbiddenImportFixes, createOrphanedDepFixes, createParseError, createSelfReview, createStream, cryptoRules, deduplicateCleanupFindings, deduplicateFindings, defineLayer, deserializationRules, detectChangeType, detectCircularDeps, detectCircularDepsInFiles, detectComplexityViolations, detectCouplingViolations, detectDeadCode, detectDocDrift, detectPatternViolations, detectSizeBudgetViolations, detectStack, determineAssessment, executeWorkflow, expressRules, extractMarkdownLinks, extractSections, fanOutReview, formatFindingBlock, formatGitHubComment, formatGitHubSummary, formatTerminalOutput, generateAgentsMap, generateSuggestions, getActionEmitter, getExitCode, getFeedbackConfig, getPhaseCategories, getStreamForBranch, getUpdateNotification, goRules, injectionRules, isSmallSuggestion, isUpdateCheckEnabled, listStreams, loadFailures, loadHandoff, loadRelevantLearnings, loadState, loadStreamIndex, logAgentAction, migrateToStreams, networkRules, nodeRules, parseDiff, parseRoadmap, parseSecurityConfig, parseSize, pathTraversalRules, previewFix, reactRules, readCheckState, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, resolveModelTier, resolveRuleSeverity, resolveStreamPath, runArchitectureAgent, runBugDetectionAgent, runCIChecks, runComplianceAgent, runMechanicalChecks, runMechanicalGate, runMultiTurnPipeline, runPipeline, runReviewPipeline, runSecurityAgent, saveHandoff, saveState, saveStreamIndex, scopeContext, secretRules, serializeRoadmap, setActiveStream, shouldRunCheck, spawnBackgroundCheck, syncRoadmap, touchStream, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateFindings, validateKnowledgeMap, validatePatternConfig, xssRules };
package/dist/index.js CHANGED
@@ -5239,6 +5239,15 @@ var FAILURES_FILE = "failures.md";
5239
5239
  var HANDOFF_FILE = "handoff.json";
5240
5240
  var GATE_CONFIG_FILE = "gate.json";
5241
5241
  var INDEX_FILE2 = "index.json";
5242
+ var MAX_CACHE_ENTRIES = 8;
5243
+ var learningsCacheMap = /* @__PURE__ */ new Map();
5244
+ var failuresCacheMap = /* @__PURE__ */ new Map();
5245
+ function evictIfNeeded(map) {
5246
+ if (map.size > MAX_CACHE_ENTRIES) {
5247
+ const oldest = map.keys().next().value;
5248
+ if (oldest !== void 0) map.delete(oldest);
5249
+ }
5250
+ }
5242
5251
  async function getStateDir(projectPath, stream) {
5243
5252
  const streamsIndexPath = path3.join(projectPath, HARNESS_DIR2, "streams", INDEX_FILE2);
5244
5253
  const hasStreams = fs4.existsSync(streamsIndexPath);
@@ -5336,25 +5345,35 @@ async function loadRelevantLearnings(projectPath, skillName, stream) {
5336
5345
  if (!fs4.existsSync(learningsPath)) {
5337
5346
  return (0, import_types.Ok)([]);
5338
5347
  }
5339
- const content = fs4.readFileSync(learningsPath, "utf-8");
5340
- const lines = content.split("\n");
5341
- const entries = [];
5342
- let currentBlock = [];
5343
- for (const line of lines) {
5344
- if (line.startsWith("# ")) continue;
5345
- const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
5346
- const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
5347
- if (isDatedBullet || isHeading) {
5348
- if (currentBlock.length > 0) {
5349
- entries.push(currentBlock.join("\n"));
5348
+ const stats = fs4.statSync(learningsPath);
5349
+ const cacheKey = learningsPath;
5350
+ const cached = learningsCacheMap.get(cacheKey);
5351
+ let entries;
5352
+ if (cached && cached.mtimeMs === stats.mtimeMs) {
5353
+ entries = cached.entries;
5354
+ } else {
5355
+ const content = fs4.readFileSync(learningsPath, "utf-8");
5356
+ const lines = content.split("\n");
5357
+ entries = [];
5358
+ let currentBlock = [];
5359
+ for (const line of lines) {
5360
+ if (line.startsWith("# ")) continue;
5361
+ const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
5362
+ const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
5363
+ if (isDatedBullet || isHeading) {
5364
+ if (currentBlock.length > 0) {
5365
+ entries.push(currentBlock.join("\n"));
5366
+ }
5367
+ currentBlock = [line];
5368
+ } else if (line.trim() !== "" && currentBlock.length > 0) {
5369
+ currentBlock.push(line);
5350
5370
  }
5351
- currentBlock = [line];
5352
- } else if (line.trim() !== "" && currentBlock.length > 0) {
5353
- currentBlock.push(line);
5354
5371
  }
5355
- }
5356
- if (currentBlock.length > 0) {
5357
- entries.push(currentBlock.join("\n"));
5372
+ if (currentBlock.length > 0) {
5373
+ entries.push(currentBlock.join("\n"));
5374
+ }
5375
+ learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
5376
+ evictIfNeeded(learningsCacheMap);
5358
5377
  }
5359
5378
  if (!skillName) {
5360
5379
  return (0, import_types.Ok)(entries);
@@ -5405,6 +5424,12 @@ async function loadFailures(projectPath, stream) {
5405
5424
  if (!fs4.existsSync(failuresPath)) {
5406
5425
  return (0, import_types.Ok)([]);
5407
5426
  }
5427
+ const stats = fs4.statSync(failuresPath);
5428
+ const cacheKey = failuresPath;
5429
+ const cached = failuresCacheMap.get(cacheKey);
5430
+ if (cached && cached.mtimeMs === stats.mtimeMs) {
5431
+ return (0, import_types.Ok)(cached.entries);
5432
+ }
5408
5433
  const content = fs4.readFileSync(failuresPath, "utf-8");
5409
5434
  const entries = [];
5410
5435
  for (const line of content.split("\n")) {
@@ -5418,6 +5443,8 @@ async function loadFailures(projectPath, stream) {
5418
5443
  });
5419
5444
  }
5420
5445
  }
5446
+ failuresCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
5447
+ evictIfNeeded(failuresCacheMap);
5421
5448
  return (0, import_types.Ok)(entries);
5422
5449
  } catch (error) {
5423
5450
  return (0, import_types.Err)(
@@ -6516,14 +6543,22 @@ async function runCIChecks(input) {
6516
6543
  const { projectRoot, config, skip = [], failOn = "error" } = input;
6517
6544
  try {
6518
6545
  const checks = [];
6519
- for (const name of ALL_CHECKS) {
6520
- if (skip.includes(name)) {
6521
- checks.push({ name, status: "skip", issues: [], durationMs: 0 });
6522
- } else {
6523
- const result = await runSingleCheck(name, projectRoot, config);
6524
- checks.push(result);
6525
- }
6546
+ const skippedSet = new Set(skip);
6547
+ if (skippedSet.has("validate")) {
6548
+ checks.push({ name: "validate", status: "skip", issues: [], durationMs: 0 });
6549
+ } else {
6550
+ checks.push(await runSingleCheck("validate", projectRoot, config));
6526
6551
  }
6552
+ const remainingChecks = ALL_CHECKS.slice(1);
6553
+ const phase2Results = await Promise.all(
6554
+ remainingChecks.map(async (name) => {
6555
+ if (skippedSet.has(name)) {
6556
+ return { name, status: "skip", issues: [], durationMs: 0 };
6557
+ }
6558
+ return runSingleCheck(name, projectRoot, config);
6559
+ })
6560
+ );
6561
+ checks.push(...phase2Results);
6527
6562
  const summary = buildSummary(checks);
6528
6563
  const exitCode = determineExitCode(summary, failOn);
6529
6564
  const report = {
@@ -6648,76 +6683,93 @@ async function runMechanicalChecks(options) {
6648
6683
  });
6649
6684
  }
6650
6685
  }
6686
+ const parallelChecks = [];
6651
6687
  if (!skip.includes("check-docs")) {
6652
- try {
6653
- const docsDir = path6.join(projectRoot, config.docsDir ?? "docs");
6654
- const result = await checkDocCoverage("project", { docsDir });
6655
- if (!result.ok) {
6656
- statuses["check-docs"] = "warn";
6657
- findings.push({
6658
- tool: "check-docs",
6659
- file: docsDir,
6660
- message: result.error.message,
6661
- severity: "warning"
6662
- });
6663
- } else if (result.value.gaps && result.value.gaps.length > 0) {
6664
- statuses["check-docs"] = "warn";
6665
- for (const gap of result.value.gaps) {
6666
- findings.push({
6688
+ parallelChecks.push(
6689
+ (async () => {
6690
+ const localFindings = [];
6691
+ try {
6692
+ const docsDir = path6.join(projectRoot, config.docsDir ?? "docs");
6693
+ const result = await checkDocCoverage("project", { docsDir });
6694
+ if (!result.ok) {
6695
+ statuses["check-docs"] = "warn";
6696
+ localFindings.push({
6697
+ tool: "check-docs",
6698
+ file: docsDir,
6699
+ message: result.error.message,
6700
+ severity: "warning"
6701
+ });
6702
+ } else if (result.value.gaps && result.value.gaps.length > 0) {
6703
+ statuses["check-docs"] = "warn";
6704
+ for (const gap of result.value.gaps) {
6705
+ localFindings.push({
6706
+ tool: "check-docs",
6707
+ file: gap.file,
6708
+ message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6709
+ severity: "warning"
6710
+ });
6711
+ }
6712
+ } else {
6713
+ statuses["check-docs"] = "pass";
6714
+ }
6715
+ } catch (err) {
6716
+ statuses["check-docs"] = "warn";
6717
+ localFindings.push({
6667
6718
  tool: "check-docs",
6668
- file: gap.file,
6669
- message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6719
+ file: path6.join(projectRoot, "docs"),
6720
+ message: err instanceof Error ? err.message : String(err),
6670
6721
  severity: "warning"
6671
6722
  });
6672
6723
  }
6673
- } else {
6674
- statuses["check-docs"] = "pass";
6675
- }
6676
- } catch (err) {
6677
- statuses["check-docs"] = "warn";
6678
- findings.push({
6679
- tool: "check-docs",
6680
- file: path6.join(projectRoot, "docs"),
6681
- message: err instanceof Error ? err.message : String(err),
6682
- severity: "warning"
6683
- });
6684
- }
6724
+ return localFindings;
6725
+ })()
6726
+ );
6685
6727
  }
6686
6728
  if (!skip.includes("security-scan")) {
6687
- try {
6688
- const securityConfig = parseSecurityConfig(config.security);
6689
- if (!securityConfig.enabled) {
6690
- statuses["security-scan"] = "skip";
6691
- } else {
6692
- const scanner = new SecurityScanner(securityConfig);
6693
- scanner.configureForProject(projectRoot);
6694
- const filesToScan = changedFiles ?? [];
6695
- const scanResult = await scanner.scanFiles(filesToScan);
6696
- if (scanResult.findings.length > 0) {
6697
- statuses["security-scan"] = "warn";
6698
- for (const f of scanResult.findings) {
6699
- findings.push({
6700
- tool: "security-scan",
6701
- file: f.file,
6702
- line: f.line,
6703
- ruleId: f.ruleId,
6704
- message: f.message,
6705
- severity: f.severity === "info" ? "warning" : f.severity
6706
- });
6729
+ parallelChecks.push(
6730
+ (async () => {
6731
+ const localFindings = [];
6732
+ try {
6733
+ const securityConfig = parseSecurityConfig(config.security);
6734
+ if (!securityConfig.enabled) {
6735
+ statuses["security-scan"] = "skip";
6736
+ } else {
6737
+ const scanner = new SecurityScanner(securityConfig);
6738
+ scanner.configureForProject(projectRoot);
6739
+ const filesToScan = changedFiles ?? [];
6740
+ const scanResult = await scanner.scanFiles(filesToScan);
6741
+ if (scanResult.findings.length > 0) {
6742
+ statuses["security-scan"] = "warn";
6743
+ for (const f of scanResult.findings) {
6744
+ localFindings.push({
6745
+ tool: "security-scan",
6746
+ file: f.file,
6747
+ line: f.line,
6748
+ ruleId: f.ruleId,
6749
+ message: f.message,
6750
+ severity: f.severity === "info" ? "warning" : f.severity
6751
+ });
6752
+ }
6753
+ } else {
6754
+ statuses["security-scan"] = "pass";
6755
+ }
6707
6756
  }
6708
- } else {
6709
- statuses["security-scan"] = "pass";
6757
+ } catch (err) {
6758
+ statuses["security-scan"] = "warn";
6759
+ localFindings.push({
6760
+ tool: "security-scan",
6761
+ file: projectRoot,
6762
+ message: err instanceof Error ? err.message : String(err),
6763
+ severity: "warning"
6764
+ });
6710
6765
  }
6711
- }
6712
- } catch (err) {
6713
- statuses["security-scan"] = "warn";
6714
- findings.push({
6715
- tool: "security-scan",
6716
- file: projectRoot,
6717
- message: err instanceof Error ? err.message : String(err),
6718
- severity: "warning"
6719
- });
6720
- }
6766
+ return localFindings;
6767
+ })()
6768
+ );
6769
+ }
6770
+ const parallelResults = await Promise.all(parallelChecks);
6771
+ for (const result of parallelResults) {
6772
+ findings.push(...result);
6721
6773
  }
6722
6774
  const hasErrors = findings.some((f) => f.severity === "error");
6723
6775
  const stopPipeline = statuses.validate === "fail" || statuses["check-deps"] === "fail";
@@ -8579,7 +8631,7 @@ Run "harness update" to upgrade.`;
8579
8631
  }
8580
8632
 
8581
8633
  // src/index.ts
8582
- var VERSION = "0.8.0";
8634
+ var VERSION = "1.8.2";
8583
8635
  // Annotate the CommonJS export names for ESM import in node:
8584
8636
  0 && (module.exports = {
8585
8637
  AGENT_DESCRIPTORS,
package/dist/index.mjs CHANGED
@@ -5044,6 +5044,15 @@ var FAILURES_FILE = "failures.md";
5044
5044
  var HANDOFF_FILE = "handoff.json";
5045
5045
  var GATE_CONFIG_FILE = "gate.json";
5046
5046
  var INDEX_FILE2 = "index.json";
5047
+ var MAX_CACHE_ENTRIES = 8;
5048
+ var learningsCacheMap = /* @__PURE__ */ new Map();
5049
+ var failuresCacheMap = /* @__PURE__ */ new Map();
5050
+ function evictIfNeeded(map) {
5051
+ if (map.size > MAX_CACHE_ENTRIES) {
5052
+ const oldest = map.keys().next().value;
5053
+ if (oldest !== void 0) map.delete(oldest);
5054
+ }
5055
+ }
5047
5056
  async function getStateDir(projectPath, stream) {
5048
5057
  const streamsIndexPath = path3.join(projectPath, HARNESS_DIR2, "streams", INDEX_FILE2);
5049
5058
  const hasStreams = fs4.existsSync(streamsIndexPath);
@@ -5141,25 +5150,35 @@ async function loadRelevantLearnings(projectPath, skillName, stream) {
5141
5150
  if (!fs4.existsSync(learningsPath)) {
5142
5151
  return Ok([]);
5143
5152
  }
5144
- const content = fs4.readFileSync(learningsPath, "utf-8");
5145
- const lines = content.split("\n");
5146
- const entries = [];
5147
- let currentBlock = [];
5148
- for (const line of lines) {
5149
- if (line.startsWith("# ")) continue;
5150
- const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
5151
- const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
5152
- if (isDatedBullet || isHeading) {
5153
- if (currentBlock.length > 0) {
5154
- entries.push(currentBlock.join("\n"));
5153
+ const stats = fs4.statSync(learningsPath);
5154
+ const cacheKey = learningsPath;
5155
+ const cached = learningsCacheMap.get(cacheKey);
5156
+ let entries;
5157
+ if (cached && cached.mtimeMs === stats.mtimeMs) {
5158
+ entries = cached.entries;
5159
+ } else {
5160
+ const content = fs4.readFileSync(learningsPath, "utf-8");
5161
+ const lines = content.split("\n");
5162
+ entries = [];
5163
+ let currentBlock = [];
5164
+ for (const line of lines) {
5165
+ if (line.startsWith("# ")) continue;
5166
+ const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
5167
+ const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
5168
+ if (isDatedBullet || isHeading) {
5169
+ if (currentBlock.length > 0) {
5170
+ entries.push(currentBlock.join("\n"));
5171
+ }
5172
+ currentBlock = [line];
5173
+ } else if (line.trim() !== "" && currentBlock.length > 0) {
5174
+ currentBlock.push(line);
5155
5175
  }
5156
- currentBlock = [line];
5157
- } else if (line.trim() !== "" && currentBlock.length > 0) {
5158
- currentBlock.push(line);
5159
5176
  }
5160
- }
5161
- if (currentBlock.length > 0) {
5162
- entries.push(currentBlock.join("\n"));
5177
+ if (currentBlock.length > 0) {
5178
+ entries.push(currentBlock.join("\n"));
5179
+ }
5180
+ learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
5181
+ evictIfNeeded(learningsCacheMap);
5163
5182
  }
5164
5183
  if (!skillName) {
5165
5184
  return Ok(entries);
@@ -5210,6 +5229,12 @@ async function loadFailures(projectPath, stream) {
5210
5229
  if (!fs4.existsSync(failuresPath)) {
5211
5230
  return Ok([]);
5212
5231
  }
5232
+ const stats = fs4.statSync(failuresPath);
5233
+ const cacheKey = failuresPath;
5234
+ const cached = failuresCacheMap.get(cacheKey);
5235
+ if (cached && cached.mtimeMs === stats.mtimeMs) {
5236
+ return Ok(cached.entries);
5237
+ }
5213
5238
  const content = fs4.readFileSync(failuresPath, "utf-8");
5214
5239
  const entries = [];
5215
5240
  for (const line of content.split("\n")) {
@@ -5223,6 +5248,8 @@ async function loadFailures(projectPath, stream) {
5223
5248
  });
5224
5249
  }
5225
5250
  }
5251
+ failuresCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
5252
+ evictIfNeeded(failuresCacheMap);
5226
5253
  return Ok(entries);
5227
5254
  } catch (error) {
5228
5255
  return Err(
@@ -6321,14 +6348,22 @@ async function runCIChecks(input) {
6321
6348
  const { projectRoot, config, skip = [], failOn = "error" } = input;
6322
6349
  try {
6323
6350
  const checks = [];
6324
- for (const name of ALL_CHECKS) {
6325
- if (skip.includes(name)) {
6326
- checks.push({ name, status: "skip", issues: [], durationMs: 0 });
6327
- } else {
6328
- const result = await runSingleCheck(name, projectRoot, config);
6329
- checks.push(result);
6330
- }
6351
+ const skippedSet = new Set(skip);
6352
+ if (skippedSet.has("validate")) {
6353
+ checks.push({ name: "validate", status: "skip", issues: [], durationMs: 0 });
6354
+ } else {
6355
+ checks.push(await runSingleCheck("validate", projectRoot, config));
6331
6356
  }
6357
+ const remainingChecks = ALL_CHECKS.slice(1);
6358
+ const phase2Results = await Promise.all(
6359
+ remainingChecks.map(async (name) => {
6360
+ if (skippedSet.has(name)) {
6361
+ return { name, status: "skip", issues: [], durationMs: 0 };
6362
+ }
6363
+ return runSingleCheck(name, projectRoot, config);
6364
+ })
6365
+ );
6366
+ checks.push(...phase2Results);
6332
6367
  const summary = buildSummary(checks);
6333
6368
  const exitCode = determineExitCode(summary, failOn);
6334
6369
  const report = {
@@ -6453,76 +6488,93 @@ async function runMechanicalChecks(options) {
6453
6488
  });
6454
6489
  }
6455
6490
  }
6491
+ const parallelChecks = [];
6456
6492
  if (!skip.includes("check-docs")) {
6457
- try {
6458
- const docsDir = path6.join(projectRoot, config.docsDir ?? "docs");
6459
- const result = await checkDocCoverage("project", { docsDir });
6460
- if (!result.ok) {
6461
- statuses["check-docs"] = "warn";
6462
- findings.push({
6463
- tool: "check-docs",
6464
- file: docsDir,
6465
- message: result.error.message,
6466
- severity: "warning"
6467
- });
6468
- } else if (result.value.gaps && result.value.gaps.length > 0) {
6469
- statuses["check-docs"] = "warn";
6470
- for (const gap of result.value.gaps) {
6471
- findings.push({
6493
+ parallelChecks.push(
6494
+ (async () => {
6495
+ const localFindings = [];
6496
+ try {
6497
+ const docsDir = path6.join(projectRoot, config.docsDir ?? "docs");
6498
+ const result = await checkDocCoverage("project", { docsDir });
6499
+ if (!result.ok) {
6500
+ statuses["check-docs"] = "warn";
6501
+ localFindings.push({
6502
+ tool: "check-docs",
6503
+ file: docsDir,
6504
+ message: result.error.message,
6505
+ severity: "warning"
6506
+ });
6507
+ } else if (result.value.gaps && result.value.gaps.length > 0) {
6508
+ statuses["check-docs"] = "warn";
6509
+ for (const gap of result.value.gaps) {
6510
+ localFindings.push({
6511
+ tool: "check-docs",
6512
+ file: gap.file,
6513
+ message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6514
+ severity: "warning"
6515
+ });
6516
+ }
6517
+ } else {
6518
+ statuses["check-docs"] = "pass";
6519
+ }
6520
+ } catch (err) {
6521
+ statuses["check-docs"] = "warn";
6522
+ localFindings.push({
6472
6523
  tool: "check-docs",
6473
- file: gap.file,
6474
- message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
6524
+ file: path6.join(projectRoot, "docs"),
6525
+ message: err instanceof Error ? err.message : String(err),
6475
6526
  severity: "warning"
6476
6527
  });
6477
6528
  }
6478
- } else {
6479
- statuses["check-docs"] = "pass";
6480
- }
6481
- } catch (err) {
6482
- statuses["check-docs"] = "warn";
6483
- findings.push({
6484
- tool: "check-docs",
6485
- file: path6.join(projectRoot, "docs"),
6486
- message: err instanceof Error ? err.message : String(err),
6487
- severity: "warning"
6488
- });
6489
- }
6529
+ return localFindings;
6530
+ })()
6531
+ );
6490
6532
  }
6491
6533
  if (!skip.includes("security-scan")) {
6492
- try {
6493
- const securityConfig = parseSecurityConfig(config.security);
6494
- if (!securityConfig.enabled) {
6495
- statuses["security-scan"] = "skip";
6496
- } else {
6497
- const scanner = new SecurityScanner(securityConfig);
6498
- scanner.configureForProject(projectRoot);
6499
- const filesToScan = changedFiles ?? [];
6500
- const scanResult = await scanner.scanFiles(filesToScan);
6501
- if (scanResult.findings.length > 0) {
6502
- statuses["security-scan"] = "warn";
6503
- for (const f of scanResult.findings) {
6504
- findings.push({
6505
- tool: "security-scan",
6506
- file: f.file,
6507
- line: f.line,
6508
- ruleId: f.ruleId,
6509
- message: f.message,
6510
- severity: f.severity === "info" ? "warning" : f.severity
6511
- });
6534
+ parallelChecks.push(
6535
+ (async () => {
6536
+ const localFindings = [];
6537
+ try {
6538
+ const securityConfig = parseSecurityConfig(config.security);
6539
+ if (!securityConfig.enabled) {
6540
+ statuses["security-scan"] = "skip";
6541
+ } else {
6542
+ const scanner = new SecurityScanner(securityConfig);
6543
+ scanner.configureForProject(projectRoot);
6544
+ const filesToScan = changedFiles ?? [];
6545
+ const scanResult = await scanner.scanFiles(filesToScan);
6546
+ if (scanResult.findings.length > 0) {
6547
+ statuses["security-scan"] = "warn";
6548
+ for (const f of scanResult.findings) {
6549
+ localFindings.push({
6550
+ tool: "security-scan",
6551
+ file: f.file,
6552
+ line: f.line,
6553
+ ruleId: f.ruleId,
6554
+ message: f.message,
6555
+ severity: f.severity === "info" ? "warning" : f.severity
6556
+ });
6557
+ }
6558
+ } else {
6559
+ statuses["security-scan"] = "pass";
6560
+ }
6512
6561
  }
6513
- } else {
6514
- statuses["security-scan"] = "pass";
6562
+ } catch (err) {
6563
+ statuses["security-scan"] = "warn";
6564
+ localFindings.push({
6565
+ tool: "security-scan",
6566
+ file: projectRoot,
6567
+ message: err instanceof Error ? err.message : String(err),
6568
+ severity: "warning"
6569
+ });
6515
6570
  }
6516
- }
6517
- } catch (err) {
6518
- statuses["security-scan"] = "warn";
6519
- findings.push({
6520
- tool: "security-scan",
6521
- file: projectRoot,
6522
- message: err instanceof Error ? err.message : String(err),
6523
- severity: "warning"
6524
- });
6525
- }
6571
+ return localFindings;
6572
+ })()
6573
+ );
6574
+ }
6575
+ const parallelResults = await Promise.all(parallelChecks);
6576
+ for (const result of parallelResults) {
6577
+ findings.push(...result);
6526
6578
  }
6527
6579
  const hasErrors = findings.some((f) => f.severity === "error");
6528
6580
  const stopPipeline = statuses.validate === "fail" || statuses["check-deps"] === "fail";
@@ -8384,7 +8436,7 @@ Run "harness update" to upgrade.`;
8384
8436
  }
8385
8437
 
8386
8438
  // src/index.ts
8387
- var VERSION = "0.8.0";
8439
+ var VERSION = "1.8.2";
8388
8440
  export {
8389
8441
  AGENT_DESCRIPTORS,
8390
8442
  ARCHITECTURE_DESCRIPTOR,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/core",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "Core library for Harness Engineering toolkit",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",