@harness-engineering/graph 0.8.0 → 0.9.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
@@ -497,6 +497,16 @@ declare function resolveSkipDirs(options?: {
497
497
  skipDirs?: Iterable<string>;
498
498
  additionalSkipDirs?: Iterable<string>;
499
499
  }): ReadonlySet<string>;
500
+ /**
501
+ * Convert a skip-dirs set into minimatch glob patterns of the form
502
+ * `**\/<name>/\**`. Use for tools that exclude via globs (security scan, doc
503
+ * coverage, entropy analysis) rather than by reading directory names during
504
+ * traversal. Defaults to {@link DEFAULT_SKIP_DIRS}.
505
+ *
506
+ * Returns a fresh array each call so callers may freely mutate/append
507
+ * domain-specific patterns (e.g. test/fixture file globs).
508
+ */
509
+ declare function skipDirGlobs(skipDirs?: ReadonlySet<string>): string[];
500
510
 
501
511
  type GitRunner = (rootDir: string, args: string[]) => Promise<string>;
502
512
  /**
@@ -544,11 +554,13 @@ declare class KnowledgeIngestor {
544
554
  ingestADRs(adrDir: string): Promise<IngestResult>;
545
555
  ingestLearnings(projectPath: string): Promise<IngestResult>;
546
556
  ingestFailures(projectPath: string): Promise<IngestResult>;
557
+ ingestGeneralDocs(projectPath: string): Promise<IngestResult>;
547
558
  ingestAll(projectPath: string, opts?: {
548
559
  adrDir?: string;
549
560
  }): Promise<IngestResult>;
550
561
  private linkToCode;
551
562
  private findMarkdownFiles;
563
+ private scanDocsDir;
552
564
  }
553
565
 
554
566
  declare class BusinessKnowledgeIngestor {
@@ -1971,4 +1983,4 @@ declare class CascadeSimulator {
1971
1983
 
1972
1984
  declare const VERSION = "0.6.0";
1973
1985
 
1974
- export { ALL_EXTRACTORS, type AggregateResult, type AnomalyDetectionOptions, type AnomalyReport, ApiPathExtractor, type ArticulationPoint, type AskGraphResult, type AssembledContext, Assembler, BusinessKnowledgeIngestor, CIConnector, CURRENT_SCHEMA_VERSION, type PackedEnvelope as CacheableEnvelope, type CascadeLayer, type CascadeNode, type CascadeResult, type CascadeSimulationOptions, CascadeSimulator, type ClassificationResult, CodeIngestor, type CodeIngestorOptions, CompositeProbabilityStrategy, type ConflictDetail, type ConflictPrediction, ConflictPredictor, type ConflictSeverity, type ConflictType, ConfluenceConnector, type ConnectorConfig, ContextQL, type ContextQLParams, type ContextQLResult, type Contradiction, ContradictionDetector, type ContradictionEntry, type ContradictionResult, type CoverageReport, CoverageScorer, D2Parser, DEFAULT_BLOCKLIST, DEFAULT_PATTERNS, DEFAULT_SKIP_DIRS, DecisionIngestor, DesignConstraintAdapter, DesignIngestor, type DesignStrictness, type DesignViolation, type DetectedElement, type DiagramEntity, type DiagramFormatParser, type DiagramParseResult, DiagramParser, type DiagramRelationship, type DomainCoverage, type DomainCoverageScore, type DomainInferenceOptions, type DriftClassification, type DriftDetector, type DriftFinding, type DriftResult, EDGE_TYPES, type EdgeQuery, type EdgeType, EntityExtractor, EntityResolver, EnumConstantExtractor, type ExtractionCounts, type ExtractionRecord, ExtractionRunner, FigmaConnector, FusionLayer, type FusionResult, type GapEntry, type GapReport, GitIngestor, type GitRunner, GraphAnomalyAdapter, type GraphBudget, GraphComplexityAdapter, type GraphComplexityHotspot, type GraphComplexityResult, type GraphConnector, GraphConstraintAdapter, GraphCouplingAdapter, type GraphCouplingFileData, type GraphCouplingResult, type GraphCoverageReport, type GraphDeadCodeData, type GraphDependencyData, type GraphDriftData, type GraphEdge, GraphEdgeSchema, GraphEntropyAdapter, GraphFeedbackAdapter, type GraphFilterResult, type GraphHarnessCheckData, type GraphImpactData, type GraphLayerViolation, type GraphMetadata, type GraphNode, GraphNodeSchema, type GraphSnapshotSummary, type GraphStabilityTier, GraphStore, type HttpClient, INTENTS, ImageAnalysisExtractor, type ImageAnalysisExtractorOptions, type AnalysisProvider as ImageAnalysisProvider, type ImageAnalysisResult, type ImpactGroups, type IndependenceCheckParams, type IndependenceResult, type IngestResult, type Intent, IntentClassifier, JiraConnector, KnowledgeDocMaterializer, KnowledgeIngestor, type KnowledgePipelineOptions, type KnowledgePipelineResult, KnowledgePipelineRunner, type KnowledgeSnapshot, type KnowledgeSnapshotEntry, KnowledgeStagingAggregator, type Language, type LinkResult, type LoadGraphResult, type LoadMetadataResult, type MaterializeOptions, type MaterializeResult, type MaterializedDoc, MermaidParser, MiroConnector, NODE_STABILITY, NODE_TYPES, type NodeCategory, type NodeQuery, type NodeType, OBSERVABILITY_TYPES, type OverlapDetail, PackedSummaryCache, type PairResult, PlantUmlParser, type ProbabilityStrategy, type ProjectionSpec, type RequirementCoverage, RequirementIngestor, type ResolvedEntity, ResponseFormatter, type SignalExtractor, type SkippedEntry, SlackConnector, type SourceLocation, type StagedEntry, type StatisticalOutlier, StructuralDriftDetector, SyncManager, type SyncMetadata, type TaskDefinition, TaskIndependenceAnalyzer, TestDescriptionExtractor, TopologicalLinker, type TraceabilityOptions, type TraceabilityResult, type TracedFile, VERSION, ValidationRuleExtractor, type VectorSearchResult, VectorStore, askGraph, classifyNodeCategory, createExtractionRunner, detectLanguage, groupNodesByImpact, inferDomain, linkToCode, loadGraph, loadGraphMetadata, normalizeIntent, project, queryTraceability, resolveSkipDirs, saveGraph };
1986
+ export { ALL_EXTRACTORS, type AggregateResult, type AnomalyDetectionOptions, type AnomalyReport, ApiPathExtractor, type ArticulationPoint, type AskGraphResult, type AssembledContext, Assembler, BusinessKnowledgeIngestor, CIConnector, CURRENT_SCHEMA_VERSION, type PackedEnvelope as CacheableEnvelope, type CascadeLayer, type CascadeNode, type CascadeResult, type CascadeSimulationOptions, CascadeSimulator, type ClassificationResult, CodeIngestor, type CodeIngestorOptions, CompositeProbabilityStrategy, type ConflictDetail, type ConflictPrediction, ConflictPredictor, type ConflictSeverity, type ConflictType, ConfluenceConnector, type ConnectorConfig, ContextQL, type ContextQLParams, type ContextQLResult, type Contradiction, ContradictionDetector, type ContradictionEntry, type ContradictionResult, type CoverageReport, CoverageScorer, D2Parser, DEFAULT_BLOCKLIST, DEFAULT_PATTERNS, DEFAULT_SKIP_DIRS, DecisionIngestor, DesignConstraintAdapter, DesignIngestor, type DesignStrictness, type DesignViolation, type DetectedElement, type DiagramEntity, type DiagramFormatParser, type DiagramParseResult, DiagramParser, type DiagramRelationship, type DomainCoverage, type DomainCoverageScore, type DomainInferenceOptions, type DriftClassification, type DriftDetector, type DriftFinding, type DriftResult, EDGE_TYPES, type EdgeQuery, type EdgeType, EntityExtractor, EntityResolver, EnumConstantExtractor, type ExtractionCounts, type ExtractionRecord, ExtractionRunner, FigmaConnector, FusionLayer, type FusionResult, type GapEntry, type GapReport, GitIngestor, type GitRunner, GraphAnomalyAdapter, type GraphBudget, GraphComplexityAdapter, type GraphComplexityHotspot, type GraphComplexityResult, type GraphConnector, GraphConstraintAdapter, GraphCouplingAdapter, type GraphCouplingFileData, type GraphCouplingResult, type GraphCoverageReport, type GraphDeadCodeData, type GraphDependencyData, type GraphDriftData, type GraphEdge, GraphEdgeSchema, GraphEntropyAdapter, GraphFeedbackAdapter, type GraphFilterResult, type GraphHarnessCheckData, type GraphImpactData, type GraphLayerViolation, type GraphMetadata, type GraphNode, GraphNodeSchema, type GraphSnapshotSummary, type GraphStabilityTier, GraphStore, type HttpClient, INTENTS, ImageAnalysisExtractor, type ImageAnalysisExtractorOptions, type AnalysisProvider as ImageAnalysisProvider, type ImageAnalysisResult, type ImpactGroups, type IndependenceCheckParams, type IndependenceResult, type IngestResult, type Intent, IntentClassifier, JiraConnector, KnowledgeDocMaterializer, KnowledgeIngestor, type KnowledgePipelineOptions, type KnowledgePipelineResult, KnowledgePipelineRunner, type KnowledgeSnapshot, type KnowledgeSnapshotEntry, KnowledgeStagingAggregator, type Language, type LinkResult, type LoadGraphResult, type LoadMetadataResult, type MaterializeOptions, type MaterializeResult, type MaterializedDoc, MermaidParser, MiroConnector, NODE_STABILITY, NODE_TYPES, type NodeCategory, type NodeQuery, type NodeType, OBSERVABILITY_TYPES, type OverlapDetail, PackedSummaryCache, type PairResult, PlantUmlParser, type ProbabilityStrategy, type ProjectionSpec, type RequirementCoverage, RequirementIngestor, type ResolvedEntity, ResponseFormatter, type SignalExtractor, type SkippedEntry, SlackConnector, type SourceLocation, type StagedEntry, type StatisticalOutlier, StructuralDriftDetector, SyncManager, type SyncMetadata, type TaskDefinition, TaskIndependenceAnalyzer, TestDescriptionExtractor, TopologicalLinker, type TraceabilityOptions, type TraceabilityResult, type TracedFile, VERSION, ValidationRuleExtractor, type VectorSearchResult, VectorStore, askGraph, classifyNodeCategory, createExtractionRunner, detectLanguage, groupNodesByImpact, inferDomain, linkToCode, loadGraph, loadGraphMetadata, normalizeIntent, project, queryTraceability, resolveSkipDirs, saveGraph, skipDirGlobs };
package/dist/index.d.ts CHANGED
@@ -497,6 +497,16 @@ declare function resolveSkipDirs(options?: {
497
497
  skipDirs?: Iterable<string>;
498
498
  additionalSkipDirs?: Iterable<string>;
499
499
  }): ReadonlySet<string>;
500
+ /**
501
+ * Convert a skip-dirs set into minimatch glob patterns of the form
502
+ * `**\/<name>/\**`. Use for tools that exclude via globs (security scan, doc
503
+ * coverage, entropy analysis) rather than by reading directory names during
504
+ * traversal. Defaults to {@link DEFAULT_SKIP_DIRS}.
505
+ *
506
+ * Returns a fresh array each call so callers may freely mutate/append
507
+ * domain-specific patterns (e.g. test/fixture file globs).
508
+ */
509
+ declare function skipDirGlobs(skipDirs?: ReadonlySet<string>): string[];
500
510
 
501
511
  type GitRunner = (rootDir: string, args: string[]) => Promise<string>;
502
512
  /**
@@ -544,11 +554,13 @@ declare class KnowledgeIngestor {
544
554
  ingestADRs(adrDir: string): Promise<IngestResult>;
545
555
  ingestLearnings(projectPath: string): Promise<IngestResult>;
546
556
  ingestFailures(projectPath: string): Promise<IngestResult>;
557
+ ingestGeneralDocs(projectPath: string): Promise<IngestResult>;
547
558
  ingestAll(projectPath: string, opts?: {
548
559
  adrDir?: string;
549
560
  }): Promise<IngestResult>;
550
561
  private linkToCode;
551
562
  private findMarkdownFiles;
563
+ private scanDocsDir;
552
564
  }
553
565
 
554
566
  declare class BusinessKnowledgeIngestor {
@@ -1971,4 +1983,4 @@ declare class CascadeSimulator {
1971
1983
 
1972
1984
  declare const VERSION = "0.6.0";
1973
1985
 
1974
- export { ALL_EXTRACTORS, type AggregateResult, type AnomalyDetectionOptions, type AnomalyReport, ApiPathExtractor, type ArticulationPoint, type AskGraphResult, type AssembledContext, Assembler, BusinessKnowledgeIngestor, CIConnector, CURRENT_SCHEMA_VERSION, type PackedEnvelope as CacheableEnvelope, type CascadeLayer, type CascadeNode, type CascadeResult, type CascadeSimulationOptions, CascadeSimulator, type ClassificationResult, CodeIngestor, type CodeIngestorOptions, CompositeProbabilityStrategy, type ConflictDetail, type ConflictPrediction, ConflictPredictor, type ConflictSeverity, type ConflictType, ConfluenceConnector, type ConnectorConfig, ContextQL, type ContextQLParams, type ContextQLResult, type Contradiction, ContradictionDetector, type ContradictionEntry, type ContradictionResult, type CoverageReport, CoverageScorer, D2Parser, DEFAULT_BLOCKLIST, DEFAULT_PATTERNS, DEFAULT_SKIP_DIRS, DecisionIngestor, DesignConstraintAdapter, DesignIngestor, type DesignStrictness, type DesignViolation, type DetectedElement, type DiagramEntity, type DiagramFormatParser, type DiagramParseResult, DiagramParser, type DiagramRelationship, type DomainCoverage, type DomainCoverageScore, type DomainInferenceOptions, type DriftClassification, type DriftDetector, type DriftFinding, type DriftResult, EDGE_TYPES, type EdgeQuery, type EdgeType, EntityExtractor, EntityResolver, EnumConstantExtractor, type ExtractionCounts, type ExtractionRecord, ExtractionRunner, FigmaConnector, FusionLayer, type FusionResult, type GapEntry, type GapReport, GitIngestor, type GitRunner, GraphAnomalyAdapter, type GraphBudget, GraphComplexityAdapter, type GraphComplexityHotspot, type GraphComplexityResult, type GraphConnector, GraphConstraintAdapter, GraphCouplingAdapter, type GraphCouplingFileData, type GraphCouplingResult, type GraphCoverageReport, type GraphDeadCodeData, type GraphDependencyData, type GraphDriftData, type GraphEdge, GraphEdgeSchema, GraphEntropyAdapter, GraphFeedbackAdapter, type GraphFilterResult, type GraphHarnessCheckData, type GraphImpactData, type GraphLayerViolation, type GraphMetadata, type GraphNode, GraphNodeSchema, type GraphSnapshotSummary, type GraphStabilityTier, GraphStore, type HttpClient, INTENTS, ImageAnalysisExtractor, type ImageAnalysisExtractorOptions, type AnalysisProvider as ImageAnalysisProvider, type ImageAnalysisResult, type ImpactGroups, type IndependenceCheckParams, type IndependenceResult, type IngestResult, type Intent, IntentClassifier, JiraConnector, KnowledgeDocMaterializer, KnowledgeIngestor, type KnowledgePipelineOptions, type KnowledgePipelineResult, KnowledgePipelineRunner, type KnowledgeSnapshot, type KnowledgeSnapshotEntry, KnowledgeStagingAggregator, type Language, type LinkResult, type LoadGraphResult, type LoadMetadataResult, type MaterializeOptions, type MaterializeResult, type MaterializedDoc, MermaidParser, MiroConnector, NODE_STABILITY, NODE_TYPES, type NodeCategory, type NodeQuery, type NodeType, OBSERVABILITY_TYPES, type OverlapDetail, PackedSummaryCache, type PairResult, PlantUmlParser, type ProbabilityStrategy, type ProjectionSpec, type RequirementCoverage, RequirementIngestor, type ResolvedEntity, ResponseFormatter, type SignalExtractor, type SkippedEntry, SlackConnector, type SourceLocation, type StagedEntry, type StatisticalOutlier, StructuralDriftDetector, SyncManager, type SyncMetadata, type TaskDefinition, TaskIndependenceAnalyzer, TestDescriptionExtractor, TopologicalLinker, type TraceabilityOptions, type TraceabilityResult, type TracedFile, VERSION, ValidationRuleExtractor, type VectorSearchResult, VectorStore, askGraph, classifyNodeCategory, createExtractionRunner, detectLanguage, groupNodesByImpact, inferDomain, linkToCode, loadGraph, loadGraphMetadata, normalizeIntent, project, queryTraceability, resolveSkipDirs, saveGraph };
1986
+ export { ALL_EXTRACTORS, type AggregateResult, type AnomalyDetectionOptions, type AnomalyReport, ApiPathExtractor, type ArticulationPoint, type AskGraphResult, type AssembledContext, Assembler, BusinessKnowledgeIngestor, CIConnector, CURRENT_SCHEMA_VERSION, type PackedEnvelope as CacheableEnvelope, type CascadeLayer, type CascadeNode, type CascadeResult, type CascadeSimulationOptions, CascadeSimulator, type ClassificationResult, CodeIngestor, type CodeIngestorOptions, CompositeProbabilityStrategy, type ConflictDetail, type ConflictPrediction, ConflictPredictor, type ConflictSeverity, type ConflictType, ConfluenceConnector, type ConnectorConfig, ContextQL, type ContextQLParams, type ContextQLResult, type Contradiction, ContradictionDetector, type ContradictionEntry, type ContradictionResult, type CoverageReport, CoverageScorer, D2Parser, DEFAULT_BLOCKLIST, DEFAULT_PATTERNS, DEFAULT_SKIP_DIRS, DecisionIngestor, DesignConstraintAdapter, DesignIngestor, type DesignStrictness, type DesignViolation, type DetectedElement, type DiagramEntity, type DiagramFormatParser, type DiagramParseResult, DiagramParser, type DiagramRelationship, type DomainCoverage, type DomainCoverageScore, type DomainInferenceOptions, type DriftClassification, type DriftDetector, type DriftFinding, type DriftResult, EDGE_TYPES, type EdgeQuery, type EdgeType, EntityExtractor, EntityResolver, EnumConstantExtractor, type ExtractionCounts, type ExtractionRecord, ExtractionRunner, FigmaConnector, FusionLayer, type FusionResult, type GapEntry, type GapReport, GitIngestor, type GitRunner, GraphAnomalyAdapter, type GraphBudget, GraphComplexityAdapter, type GraphComplexityHotspot, type GraphComplexityResult, type GraphConnector, GraphConstraintAdapter, GraphCouplingAdapter, type GraphCouplingFileData, type GraphCouplingResult, type GraphCoverageReport, type GraphDeadCodeData, type GraphDependencyData, type GraphDriftData, type GraphEdge, GraphEdgeSchema, GraphEntropyAdapter, GraphFeedbackAdapter, type GraphFilterResult, type GraphHarnessCheckData, type GraphImpactData, type GraphLayerViolation, type GraphMetadata, type GraphNode, GraphNodeSchema, type GraphSnapshotSummary, type GraphStabilityTier, GraphStore, type HttpClient, INTENTS, ImageAnalysisExtractor, type ImageAnalysisExtractorOptions, type AnalysisProvider as ImageAnalysisProvider, type ImageAnalysisResult, type ImpactGroups, type IndependenceCheckParams, type IndependenceResult, type IngestResult, type Intent, IntentClassifier, JiraConnector, KnowledgeDocMaterializer, KnowledgeIngestor, type KnowledgePipelineOptions, type KnowledgePipelineResult, KnowledgePipelineRunner, type KnowledgeSnapshot, type KnowledgeSnapshotEntry, KnowledgeStagingAggregator, type Language, type LinkResult, type LoadGraphResult, type LoadMetadataResult, type MaterializeOptions, type MaterializeResult, type MaterializedDoc, MermaidParser, MiroConnector, NODE_STABILITY, NODE_TYPES, type NodeCategory, type NodeQuery, type NodeType, OBSERVABILITY_TYPES, type OverlapDetail, PackedSummaryCache, type PairResult, PlantUmlParser, type ProbabilityStrategy, type ProjectionSpec, type RequirementCoverage, RequirementIngestor, type ResolvedEntity, ResponseFormatter, type SignalExtractor, type SkippedEntry, SlackConnector, type SourceLocation, type StagedEntry, type StatisticalOutlier, StructuralDriftDetector, SyncManager, type SyncMetadata, type TaskDefinition, TaskIndependenceAnalyzer, TestDescriptionExtractor, TopologicalLinker, type TraceabilityOptions, type TraceabilityResult, type TracedFile, VERSION, ValidationRuleExtractor, type VectorSearchResult, VectorStore, askGraph, classifyNodeCategory, createExtractionRunner, detectLanguage, groupNodesByImpact, inferDomain, linkToCode, loadGraph, loadGraphMetadata, normalizeIntent, project, queryTraceability, resolveSkipDirs, saveGraph, skipDirGlobs };
package/dist/index.js CHANGED
@@ -108,7 +108,8 @@ __export(index_exports, {
108
108
  project: () => project,
109
109
  queryTraceability: () => queryTraceability,
110
110
  resolveSkipDirs: () => resolveSkipDirs,
111
- saveGraph: () => saveGraph
111
+ saveGraph: () => saveGraph,
112
+ skipDirGlobs: () => skipDirGlobs
112
113
  });
113
114
  module.exports = __toCommonJS(index_exports);
114
115
 
@@ -978,6 +979,9 @@ function resolveSkipDirs(options) {
978
979
  }
979
980
  return base;
980
981
  }
982
+ function skipDirGlobs(skipDirs = DEFAULT_SKIP_DIRS) {
983
+ return Array.from(skipDirs, (name) => `**/${name}/**`);
984
+ }
981
985
 
982
986
  // src/ingest/CodeIngestor.ts
983
987
  var SKIP_METHOD_NAMES = /* @__PURE__ */ new Set(["constructor", "if", "for", "while", "switch"]);
@@ -2005,6 +2009,7 @@ function emptyResult(durationMs = 0) {
2005
2009
 
2006
2010
  // src/ingest/KnowledgeIngestor.ts
2007
2011
  var CODE_NODE_TYPES = ["file", "function", "class", "method", "interface", "variable"];
2012
+ var DOCS_OWNED_BY_OTHER_INGESTORS = /* @__PURE__ */ new Set(["adr", "knowledge", "changes", "solutions"]);
2008
2013
  var KnowledgeIngestor = class {
2009
2014
  constructor(store) {
2010
2015
  this.store = store;
@@ -2076,15 +2081,53 @@ var KnowledgeIngestor = class {
2076
2081
  }
2077
2082
  return buildResult(nodesAdded, edgesAdded, [], start);
2078
2083
  }
2084
+ async ingestGeneralDocs(projectPath) {
2085
+ const start = Date.now();
2086
+ const errors = [];
2087
+ let nodesAdded = 0;
2088
+ let edgesAdded = 0;
2089
+ const files = /* @__PURE__ */ new Set();
2090
+ try {
2091
+ const entries = await fs2.readdir(projectPath, { withFileTypes: true });
2092
+ for (const entry of entries) {
2093
+ if (entry.isFile() && entry.name.endsWith(".md")) {
2094
+ files.add(path3.join(projectPath, entry.name));
2095
+ }
2096
+ }
2097
+ } catch {
2098
+ return emptyResult(Date.now() - start);
2099
+ }
2100
+ const docsRoot = path3.join(projectPath, "docs");
2101
+ try {
2102
+ const scanned = await this.scanDocsDir(docsRoot);
2103
+ for (const f of scanned) files.add(f);
2104
+ } catch {
2105
+ }
2106
+ for (const filePath of files) {
2107
+ try {
2108
+ const content = await fs2.readFile(filePath, "utf-8");
2109
+ const relPath = path3.relative(projectPath, filePath).replaceAll("\\", "/");
2110
+ const nodeId = `doc:${relPath}`;
2111
+ if (this.store.getNode(nodeId)) continue;
2112
+ this.store.addNode(parseDocumentNode(nodeId, filePath, relPath, content));
2113
+ nodesAdded++;
2114
+ edgesAdded += this.linkToCode(content, nodeId, "documents");
2115
+ } catch (err) {
2116
+ errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
2117
+ }
2118
+ }
2119
+ return buildResult(nodesAdded, edgesAdded, errors, start);
2120
+ }
2079
2121
  async ingestAll(projectPath, opts) {
2080
2122
  const start = Date.now();
2081
2123
  const adrDir = opts?.adrDir ?? path3.join(projectPath, "docs", "adr");
2082
- const [adrResult, learningsResult, failuresResult] = await Promise.all([
2124
+ const [adrResult, learningsResult, failuresResult, docsResult] = await Promise.all([
2083
2125
  this.ingestADRs(adrDir),
2084
2126
  this.ingestLearnings(projectPath),
2085
- this.ingestFailures(projectPath)
2127
+ this.ingestFailures(projectPath),
2128
+ this.ingestGeneralDocs(projectPath)
2086
2129
  ]);
2087
- const merged = mergeResults(adrResult, learningsResult, failuresResult);
2130
+ const merged = mergeResults(adrResult, learningsResult, failuresResult, docsResult);
2088
2131
  return { ...merged, durationMs: Date.now() - start };
2089
2132
  }
2090
2133
  linkToCode(content, sourceNodeId, edgeType) {
@@ -2119,7 +2162,22 @@ var KnowledgeIngestor = class {
2119
2162
  const entries = await fs2.readdir(dir, { withFileTypes: true });
2120
2163
  for (const entry of entries) {
2121
2164
  const fullPath = path3.join(dir, entry.name);
2122
- if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
2165
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
2166
+ results.push(...await this.findMarkdownFiles(fullPath));
2167
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
2168
+ results.push(fullPath);
2169
+ }
2170
+ }
2171
+ return results;
2172
+ }
2173
+ async scanDocsDir(docsRoot) {
2174
+ const results = [];
2175
+ const rootEntries = await fs2.readdir(docsRoot, { withFileTypes: true });
2176
+ for (const entry of rootEntries) {
2177
+ const fullPath = path3.join(docsRoot, entry.name);
2178
+ if (entry.isDirectory()) {
2179
+ if (DEFAULT_SKIP_DIRS.has(entry.name)) continue;
2180
+ if (DOCS_OWNED_BY_OTHER_INGESTORS.has(entry.name)) continue;
2123
2181
  results.push(...await this.findMarkdownFiles(fullPath));
2124
2182
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
2125
2183
  results.push(fullPath);
@@ -2145,6 +2203,17 @@ function buildResult(nodesAdded, edgesAdded, errors, start) {
2145
2203
  durationMs: Date.now() - start
2146
2204
  };
2147
2205
  }
2206
+ function parseDocumentNode(nodeId, filePath, relPath, content) {
2207
+ const titleMatch = content.match(/^#\s+(.+)$/m);
2208
+ const title = titleMatch ? titleMatch[1].trim() : path3.basename(filePath, ".md");
2209
+ return {
2210
+ id: nodeId,
2211
+ type: "document",
2212
+ name: title,
2213
+ path: filePath,
2214
+ metadata: { relPath }
2215
+ };
2216
+ }
2148
2217
  function parseADRNode(nodeId, filePath, filename, content) {
2149
2218
  const titleMatch = content.match(/^#\s+(.+)$/m);
2150
2219
  const title = titleMatch ? titleMatch[1].trim() : filename;
@@ -2431,7 +2500,7 @@ var BusinessKnowledgeIngestor = class {
2431
2500
  const entries = await fs3.readdir(dir, { withFileTypes: true });
2432
2501
  for (const entry of entries) {
2433
2502
  const fullPath = path4.join(dir, entry.name);
2434
- if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
2503
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
2435
2504
  results.push(...await this.findMarkdownFiles(fullPath));
2436
2505
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
2437
2506
  results.push(fullPath);
@@ -3275,7 +3344,6 @@ var PlantUmlParser = class {
3275
3344
 
3276
3345
  // src/ingest/DiagramParser.ts
3277
3346
  var DIAGRAM_EXTENSIONS = /* @__PURE__ */ new Set([".mmd", ".mermaid", ".d2", ".puml", ".plantuml"]);
3278
- var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".harness"]);
3279
3347
  var DiagramParser = class {
3280
3348
  constructor(store) {
3281
3349
  this.store = store;
@@ -3380,7 +3448,7 @@ var DiagramParser = class {
3380
3448
  }
3381
3449
  for (const entry of entries) {
3382
3450
  if (entry.isDirectory()) {
3383
- if (!SKIP_DIRS.has(entry.name)) {
3451
+ if (!DEFAULT_SKIP_DIRS.has(entry.name)) {
3384
3452
  await walk(path7.join(currentDir, entry.name));
3385
3453
  }
3386
3454
  } else if (entry.isFile()) {
@@ -3904,31 +3972,6 @@ var KnowledgeStagingAggregator = class {
3904
3972
  // src/ingest/extractors/ExtractionRunner.ts
3905
3973
  var fs9 = __toESM(require("fs/promises"));
3906
3974
  var path10 = __toESM(require("path"));
3907
- var SKIP_DIRS2 = /* @__PURE__ */ new Set([
3908
- "node_modules",
3909
- "dist",
3910
- "target",
3911
- "build",
3912
- ".git",
3913
- "__pycache__",
3914
- ".venv",
3915
- ".turbo",
3916
- ".harness",
3917
- ".next",
3918
- ".vscode",
3919
- ".idea",
3920
- "vendor",
3921
- "out",
3922
- ".gradle",
3923
- ".gradle-home",
3924
- "bin",
3925
- "obj",
3926
- "venv",
3927
- "_build",
3928
- "deps",
3929
- "coverage",
3930
- ".nyc_output"
3931
- ]);
3932
3975
  var EXT_TO_LANGUAGE = {
3933
3976
  ".ts": "typescript",
3934
3977
  ".tsx": "typescript",
@@ -4107,7 +4150,7 @@ var ExtractionRunner = class {
4107
4150
  }
4108
4151
  for (const entry of entries) {
4109
4152
  const fullPath = path10.join(dir, entry.name);
4110
- if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
4153
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
4111
4154
  results.push(...await this.findSourceFiles(fullPath));
4112
4155
  } else if (entry.isFile() && detectLanguage(fullPath) !== void 0) {
4113
4156
  results.push(fullPath);
@@ -10029,5 +10072,6 @@ var VERSION = "0.6.0";
10029
10072
  project,
10030
10073
  queryTraceability,
10031
10074
  resolveSkipDirs,
10032
- saveGraph
10075
+ saveGraph,
10076
+ skipDirGlobs
10033
10077
  });
package/dist/index.mjs CHANGED
@@ -864,6 +864,9 @@ function resolveSkipDirs(options) {
864
864
  }
865
865
  return base;
866
866
  }
867
+ function skipDirGlobs(skipDirs = DEFAULT_SKIP_DIRS) {
868
+ return Array.from(skipDirs, (name) => `**/${name}/**`);
869
+ }
867
870
 
868
871
  // src/ingest/CodeIngestor.ts
869
872
  var SKIP_METHOD_NAMES = /* @__PURE__ */ new Set(["constructor", "if", "for", "while", "switch"]);
@@ -1891,6 +1894,7 @@ function emptyResult(durationMs = 0) {
1891
1894
 
1892
1895
  // src/ingest/KnowledgeIngestor.ts
1893
1896
  var CODE_NODE_TYPES = ["file", "function", "class", "method", "interface", "variable"];
1897
+ var DOCS_OWNED_BY_OTHER_INGESTORS = /* @__PURE__ */ new Set(["adr", "knowledge", "changes", "solutions"]);
1894
1898
  var KnowledgeIngestor = class {
1895
1899
  constructor(store) {
1896
1900
  this.store = store;
@@ -1962,15 +1966,53 @@ var KnowledgeIngestor = class {
1962
1966
  }
1963
1967
  return buildResult(nodesAdded, edgesAdded, [], start);
1964
1968
  }
1969
+ async ingestGeneralDocs(projectPath) {
1970
+ const start = Date.now();
1971
+ const errors = [];
1972
+ let nodesAdded = 0;
1973
+ let edgesAdded = 0;
1974
+ const files = /* @__PURE__ */ new Set();
1975
+ try {
1976
+ const entries = await fs2.readdir(projectPath, { withFileTypes: true });
1977
+ for (const entry of entries) {
1978
+ if (entry.isFile() && entry.name.endsWith(".md")) {
1979
+ files.add(path3.join(projectPath, entry.name));
1980
+ }
1981
+ }
1982
+ } catch {
1983
+ return emptyResult(Date.now() - start);
1984
+ }
1985
+ const docsRoot = path3.join(projectPath, "docs");
1986
+ try {
1987
+ const scanned = await this.scanDocsDir(docsRoot);
1988
+ for (const f of scanned) files.add(f);
1989
+ } catch {
1990
+ }
1991
+ for (const filePath of files) {
1992
+ try {
1993
+ const content = await fs2.readFile(filePath, "utf-8");
1994
+ const relPath = path3.relative(projectPath, filePath).replaceAll("\\", "/");
1995
+ const nodeId = `doc:${relPath}`;
1996
+ if (this.store.getNode(nodeId)) continue;
1997
+ this.store.addNode(parseDocumentNode(nodeId, filePath, relPath, content));
1998
+ nodesAdded++;
1999
+ edgesAdded += this.linkToCode(content, nodeId, "documents");
2000
+ } catch (err) {
2001
+ errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
2002
+ }
2003
+ }
2004
+ return buildResult(nodesAdded, edgesAdded, errors, start);
2005
+ }
1965
2006
  async ingestAll(projectPath, opts) {
1966
2007
  const start = Date.now();
1967
2008
  const adrDir = opts?.adrDir ?? path3.join(projectPath, "docs", "adr");
1968
- const [adrResult, learningsResult, failuresResult] = await Promise.all([
2009
+ const [adrResult, learningsResult, failuresResult, docsResult] = await Promise.all([
1969
2010
  this.ingestADRs(adrDir),
1970
2011
  this.ingestLearnings(projectPath),
1971
- this.ingestFailures(projectPath)
2012
+ this.ingestFailures(projectPath),
2013
+ this.ingestGeneralDocs(projectPath)
1972
2014
  ]);
1973
- const merged = mergeResults(adrResult, learningsResult, failuresResult);
2015
+ const merged = mergeResults(adrResult, learningsResult, failuresResult, docsResult);
1974
2016
  return { ...merged, durationMs: Date.now() - start };
1975
2017
  }
1976
2018
  linkToCode(content, sourceNodeId, edgeType) {
@@ -2005,7 +2047,22 @@ var KnowledgeIngestor = class {
2005
2047
  const entries = await fs2.readdir(dir, { withFileTypes: true });
2006
2048
  for (const entry of entries) {
2007
2049
  const fullPath = path3.join(dir, entry.name);
2008
- if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
2050
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
2051
+ results.push(...await this.findMarkdownFiles(fullPath));
2052
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
2053
+ results.push(fullPath);
2054
+ }
2055
+ }
2056
+ return results;
2057
+ }
2058
+ async scanDocsDir(docsRoot) {
2059
+ const results = [];
2060
+ const rootEntries = await fs2.readdir(docsRoot, { withFileTypes: true });
2061
+ for (const entry of rootEntries) {
2062
+ const fullPath = path3.join(docsRoot, entry.name);
2063
+ if (entry.isDirectory()) {
2064
+ if (DEFAULT_SKIP_DIRS.has(entry.name)) continue;
2065
+ if (DOCS_OWNED_BY_OTHER_INGESTORS.has(entry.name)) continue;
2009
2066
  results.push(...await this.findMarkdownFiles(fullPath));
2010
2067
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
2011
2068
  results.push(fullPath);
@@ -2031,6 +2088,17 @@ function buildResult(nodesAdded, edgesAdded, errors, start) {
2031
2088
  durationMs: Date.now() - start
2032
2089
  };
2033
2090
  }
2091
+ function parseDocumentNode(nodeId, filePath, relPath, content) {
2092
+ const titleMatch = content.match(/^#\s+(.+)$/m);
2093
+ const title = titleMatch ? titleMatch[1].trim() : path3.basename(filePath, ".md");
2094
+ return {
2095
+ id: nodeId,
2096
+ type: "document",
2097
+ name: title,
2098
+ path: filePath,
2099
+ metadata: { relPath }
2100
+ };
2101
+ }
2034
2102
  function parseADRNode(nodeId, filePath, filename, content) {
2035
2103
  const titleMatch = content.match(/^#\s+(.+)$/m);
2036
2104
  const title = titleMatch ? titleMatch[1].trim() : filename;
@@ -2317,7 +2385,7 @@ var BusinessKnowledgeIngestor = class {
2317
2385
  const entries = await fs3.readdir(dir, { withFileTypes: true });
2318
2386
  for (const entry of entries) {
2319
2387
  const fullPath = path4.join(dir, entry.name);
2320
- if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
2388
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
2321
2389
  results.push(...await this.findMarkdownFiles(fullPath));
2322
2390
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
2323
2391
  results.push(fullPath);
@@ -3161,7 +3229,6 @@ var PlantUmlParser = class {
3161
3229
 
3162
3230
  // src/ingest/DiagramParser.ts
3163
3231
  var DIAGRAM_EXTENSIONS = /* @__PURE__ */ new Set([".mmd", ".mermaid", ".d2", ".puml", ".plantuml"]);
3164
- var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".harness"]);
3165
3232
  var DiagramParser = class {
3166
3233
  constructor(store) {
3167
3234
  this.store = store;
@@ -3266,7 +3333,7 @@ var DiagramParser = class {
3266
3333
  }
3267
3334
  for (const entry of entries) {
3268
3335
  if (entry.isDirectory()) {
3269
- if (!SKIP_DIRS.has(entry.name)) {
3336
+ if (!DEFAULT_SKIP_DIRS.has(entry.name)) {
3270
3337
  await walk(path7.join(currentDir, entry.name));
3271
3338
  }
3272
3339
  } else if (entry.isFile()) {
@@ -3790,31 +3857,6 @@ var KnowledgeStagingAggregator = class {
3790
3857
  // src/ingest/extractors/ExtractionRunner.ts
3791
3858
  import * as fs9 from "fs/promises";
3792
3859
  import * as path10 from "path";
3793
- var SKIP_DIRS2 = /* @__PURE__ */ new Set([
3794
- "node_modules",
3795
- "dist",
3796
- "target",
3797
- "build",
3798
- ".git",
3799
- "__pycache__",
3800
- ".venv",
3801
- ".turbo",
3802
- ".harness",
3803
- ".next",
3804
- ".vscode",
3805
- ".idea",
3806
- "vendor",
3807
- "out",
3808
- ".gradle",
3809
- ".gradle-home",
3810
- "bin",
3811
- "obj",
3812
- "venv",
3813
- "_build",
3814
- "deps",
3815
- "coverage",
3816
- ".nyc_output"
3817
- ]);
3818
3860
  var EXT_TO_LANGUAGE = {
3819
3861
  ".ts": "typescript",
3820
3862
  ".tsx": "typescript",
@@ -3993,7 +4035,7 @@ var ExtractionRunner = class {
3993
4035
  }
3994
4036
  for (const entry of entries) {
3995
4037
  const fullPath = path10.join(dir, entry.name);
3996
- if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
4038
+ if (entry.isDirectory() && !DEFAULT_SKIP_DIRS.has(entry.name)) {
3997
4039
  results.push(...await this.findSourceFiles(fullPath));
3998
4040
  } else if (entry.isFile() && detectLanguage(fullPath) !== void 0) {
3999
4041
  results.push(fullPath);
@@ -9003,7 +9045,7 @@ function queryTraceability(store, options) {
9003
9045
 
9004
9046
  // src/constraints/GraphConstraintAdapter.ts
9005
9047
  import { minimatch as minimatch2 } from "minimatch";
9006
- import { relative as relative5 } from "path";
9048
+ import { relative as relative6 } from "path";
9007
9049
  var GraphConstraintAdapter = class {
9008
9050
  constructor(store) {
9009
9051
  this.store = store;
@@ -9032,8 +9074,8 @@ var GraphConstraintAdapter = class {
9032
9074
  const { edges } = this.computeDependencyGraph();
9033
9075
  const violations = [];
9034
9076
  for (const edge of edges) {
9035
- const fromRelative = relative5(rootDir, edge.from).replaceAll("\\", "/");
9036
- const toRelative = relative5(rootDir, edge.to).replaceAll("\\", "/");
9077
+ const fromRelative = relative6(rootDir, edge.from).replaceAll("\\", "/");
9078
+ const toRelative = relative6(rootDir, edge.to).replaceAll("\\", "/");
9037
9079
  const fromLayer = this.resolveLayer(fromRelative, layers);
9038
9080
  const toLayer = this.resolveLayer(toRelative, layers);
9039
9081
  if (!fromLayer || !toLayer) continue;
@@ -9914,5 +9956,6 @@ export {
9914
9956
  project,
9915
9957
  queryTraceability,
9916
9958
  resolveSkipDirs,
9917
- saveGraph
9959
+ saveGraph,
9960
+ skipDirGlobs
9918
9961
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/graph",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "description": "Knowledge graph for context assembly in Harness Engineering",
6
6
  "main": "./dist/index.js",