import { z } from 'zod'; declare const NODE_TYPES: readonly ["repository", "module", "file", "class", "interface", "function", "method", "variable", "adr", "decision", "learning", "failure", "issue", "document", "skill", "conversation", "commit", "build", "test_result", "execution_outcome", "span", "metric", "log", "layer", "pattern", "constraint", "violation", "design_token", "aesthetic_intent", "design_constraint", "image_annotation", "requirement", "business_rule", "business_process", "business_concept", "business_term", "business_metric", "business_fact", "packed_summary"]; type NodeType = (typeof NODE_TYPES)[number]; declare const EDGE_TYPES: readonly ["contains", "imports", "calls", "implements", "inherits", "references", "applies_to", "caused_by", "resolved_by", "documents", "violates", "specifies", "decided", "co_changes_with", "triggered_by", "failed_in", "outcome_of", "executed_by", "measured_by", "uses_token", "declares_intent", "violates_design", "platform_binding", "requires", "verified_by", "tested_by", "governs", "measures", "annotates", "caches"]; type EdgeType = (typeof EDGE_TYPES)[number]; declare const OBSERVABILITY_TYPES: ReadonlySet; interface SourceLocation { readonly fileId: string; readonly startLine: number; readonly endLine: number; readonly startColumn?: number; readonly endColumn?: number; } interface GraphNode { readonly id: string; readonly type: NodeType; readonly name: string; readonly path?: string; readonly location?: SourceLocation; readonly content?: string; readonly hash?: string; readonly metadata: Record; readonly embedding?: readonly number[]; readonly lastModified?: string; } interface GraphEdge { readonly from: string; readonly to: string; readonly type: EdgeType; readonly confidence?: number; readonly metadata?: Record; } interface ContextQLParams { readonly rootNodeIds: readonly string[]; readonly maxDepth?: number; readonly includeTypes?: readonly NodeType[]; readonly excludeTypes?: readonly NodeType[]; readonly includeEdges?: readonly EdgeType[]; readonly bidirectional?: boolean; readonly pruneObservability?: boolean; } interface ContextQLResult { readonly nodes: readonly GraphNode[]; readonly edges: readonly GraphEdge[]; readonly stats: { readonly totalTraversed: number; readonly totalReturned: number; readonly pruned: number; readonly depthReached: number; }; } interface ProjectionSpec { readonly fields: readonly (keyof GraphNode)[]; } interface IngestResult { readonly nodesAdded: number; readonly nodesUpdated: number; readonly edgesAdded: number; readonly edgesUpdated: number; readonly errors: readonly string[]; readonly durationMs: number; } interface GraphMetadata { readonly schemaVersion: number; readonly lastScanTimestamp: string; readonly nodeCount: number; readonly edgeCount: number; /** * Per-NodeType counts. Populated at save time so `harness graph status` * (and other summary callers) can render counts without loading graph.json. * Optional for forward compatibility with older v2 metadata files written * before this field was added. */ readonly nodesByType?: Readonly>; } /** * On-disk graph format version. * * - v1 (legacy): `graph.json` was a single JSON object (`{"nodes":[...],"edges":[...]}`) * — read by slurping the whole file, which crashed with `RangeError: Invalid string length` * on graphs > ~512 MB (V8's hard string cap). See issue #276. * - v2 (current): `graph.json` is NDJSON — one node or edge per line, each line a * self-contained JSON object with a `kind` discriminator (`"node"` or `"edge"`). * Reader streams the file and never builds a buffer larger than one line, so the * string cap no longer applies to graph size. * * Old v1 graphs trigger `schema_mismatch` in `loadGraph` and are rebuilt on the * next scan via {@link GraphStore.load}'s existing schema-mismatch handling. */ declare const CURRENT_SCHEMA_VERSION = 2; /** Stability classification for prompt caching -- mirrors StabilityTier from @harness-engineering/types. */ type GraphStabilityTier = 'static' | 'session' | 'ephemeral'; /** * Maps graph node types to their caching stability tier. * Used by provider cache adapters to determine cache directives. * * Node types not listed here default to 'ephemeral' at resolution time. */ declare const NODE_STABILITY: Record; declare const GraphNodeSchema: z.ZodObject<{ id: z.ZodString; type: z.ZodEnum<["repository", "module", "file", "class", "interface", "function", "method", "variable", "adr", "decision", "learning", "failure", "issue", "document", "skill", "conversation", "commit", "build", "test_result", "execution_outcome", "span", "metric", "log", "layer", "pattern", "constraint", "violation", "design_token", "aesthetic_intent", "design_constraint", "image_annotation", "requirement", "business_rule", "business_process", "business_concept", "business_term", "business_metric", "business_fact", "packed_summary"]>; name: z.ZodString; path: z.ZodOptional; location: z.ZodOptional; endColumn: z.ZodOptional; }, "strip", z.ZodTypeAny, { fileId: string; startLine: number; endLine: number; startColumn?: number | undefined; endColumn?: number | undefined; }, { fileId: string; startLine: number; endLine: number; startColumn?: number | undefined; endColumn?: number | undefined; }>>; content: z.ZodOptional; hash: z.ZodOptional; metadata: z.ZodRecord; embedding: z.ZodOptional>; lastModified: z.ZodOptional; }, "strip", z.ZodTypeAny, { id: string; type: "function" | "repository" | "module" | "file" | "class" | "interface" | "method" | "variable" | "adr" | "decision" | "learning" | "failure" | "issue" | "document" | "skill" | "conversation" | "commit" | "build" | "test_result" | "execution_outcome" | "span" | "metric" | "log" | "layer" | "pattern" | "constraint" | "violation" | "design_token" | "aesthetic_intent" | "design_constraint" | "image_annotation" | "requirement" | "business_rule" | "business_process" | "business_concept" | "business_term" | "business_metric" | "business_fact" | "packed_summary"; name: string; metadata: Record; path?: string | undefined; location?: { fileId: string; startLine: number; endLine: number; startColumn?: number | undefined; endColumn?: number | undefined; } | undefined; content?: string | undefined; hash?: string | undefined; embedding?: number[] | undefined; lastModified?: string | undefined; }, { id: string; type: "function" | "repository" | "module" | "file" | "class" | "interface" | "method" | "variable" | "adr" | "decision" | "learning" | "failure" | "issue" | "document" | "skill" | "conversation" | "commit" | "build" | "test_result" | "execution_outcome" | "span" | "metric" | "log" | "layer" | "pattern" | "constraint" | "violation" | "design_token" | "aesthetic_intent" | "design_constraint" | "image_annotation" | "requirement" | "business_rule" | "business_process" | "business_concept" | "business_term" | "business_metric" | "business_fact" | "packed_summary"; name: string; metadata: Record; path?: string | undefined; location?: { fileId: string; startLine: number; endLine: number; startColumn?: number | undefined; endColumn?: number | undefined; } | undefined; content?: string | undefined; hash?: string | undefined; embedding?: number[] | undefined; lastModified?: string | undefined; }>; declare const GraphEdgeSchema: z.ZodObject<{ from: z.ZodString; to: z.ZodString; type: z.ZodEnum<["contains", "imports", "calls", "implements", "inherits", "references", "applies_to", "caused_by", "resolved_by", "documents", "violates", "specifies", "decided", "co_changes_with", "triggered_by", "failed_in", "outcome_of", "executed_by", "measured_by", "uses_token", "declares_intent", "violates_design", "platform_binding", "requires", "verified_by", "tested_by", "governs", "measures", "annotates", "caches"]>; confidence: z.ZodOptional; metadata: z.ZodOptional>; }, "strip", z.ZodTypeAny, { type: "contains" | "imports" | "calls" | "implements" | "inherits" | "references" | "applies_to" | "caused_by" | "resolved_by" | "documents" | "violates" | "specifies" | "decided" | "co_changes_with" | "triggered_by" | "failed_in" | "outcome_of" | "executed_by" | "measured_by" | "uses_token" | "declares_intent" | "violates_design" | "platform_binding" | "requires" | "verified_by" | "tested_by" | "governs" | "measures" | "annotates" | "caches"; from: string; to: string; metadata?: Record | undefined; confidence?: number | undefined; }, { type: "contains" | "imports" | "calls" | "implements" | "inherits" | "references" | "applies_to" | "caused_by" | "resolved_by" | "documents" | "violates" | "specifies" | "decided" | "co_changes_with" | "triggered_by" | "failed_in" | "outcome_of" | "executed_by" | "measured_by" | "uses_token" | "declares_intent" | "violates_design" | "platform_binding" | "requires" | "verified_by" | "tested_by" | "governs" | "measures" | "annotates" | "caches"; from: string; to: string; metadata?: Record | undefined; confidence?: number | undefined; }>; interface NodeQuery { readonly type?: NodeType; readonly name?: string; readonly path?: string; } interface EdgeQuery { readonly from?: string; readonly to?: string; readonly type?: EdgeType; } declare class GraphStore { private nodeMap; private edgeMap; private edgesByFrom; private edgesByTo; private edgesByType; addNode(node: GraphNode): void; batchAddNodes(nodes: readonly GraphNode[]): void; getNode(id: string): GraphNode | null; findNodes(query: NodeQuery): GraphNode[]; removeNode(id: string): void; addEdge(edge: GraphEdge): void; batchAddEdges(edges: readonly GraphEdge[]): void; getEdges(query: EdgeQuery): GraphEdge[]; /** Pick the most selective index to start from. */ private selectCandidates; getNeighbors(nodeId: string, direction?: 'outbound' | 'inbound' | 'both'): GraphNode[]; private collectNeighborIds; private resolveNodes; get nodeCount(): number; get edgeCount(): number; clear(): void; save(dirPath: string): Promise; load(dirPath: string): Promise; private removeEdgeInternal; } /** * Result returned from a vector similarity search. */ interface VectorSearchResult { id: string; score: number; } /** * A brute-force in-memory vector store that supports add, remove, and * top-K cosine-similarity search. */ declare class VectorStore { private readonly dimensions; private readonly vectors; constructor(dimensions: number); /** Number of vectors currently stored. */ get size(): number; /** Add a vector with the given id. Throws if dimensions do not match. */ add(id: string, vector: readonly number[]): void; /** Remove a vector by id. Returns true if the vector existed. */ remove(id: string): boolean; /** Check whether a vector with the given id exists. */ has(id: string): boolean; /** Remove all stored vectors. */ clear(): void; /** * Return the top-K most similar vectors to the query, sorted by descending * cosine similarity score. If the store contains fewer than topK vectors, * all available results are returned. */ search(query: readonly number[], topK: number): VectorSearchResult[]; /** Serialize the store to a plain object for persistence. */ serialize(): { dimensions: number; vectors: Array<{ id: string; vector: number[]; }>; }; /** Deserialize a previously-serialized store. */ static deserialize(data: { dimensions: number; vectors: Array<{ id: string; vector: number[]; }>; }): VectorStore; } interface SerializedGraph { readonly nodes: readonly GraphNode[]; readonly edges: readonly GraphEdge[]; } declare function saveGraph(dirPath: string, nodes: readonly GraphNode[], edges: readonly GraphEdge[]): Promise; type LoadGraphResult = { status: 'loaded'; graph: SerializedGraph; } | { status: 'not_found'; } | { status: 'schema_mismatch'; found: number; expected: number; }; type LoadMetadataResult = { status: 'loaded'; metadata: GraphMetadata; } | { status: 'not_found'; } | { status: 'schema_mismatch'; found: number; expected: number; }; /** * Read just `metadata.json` — fast-path for callers that only need counts/timestamps * (e.g. `harness graph status`). Avoids the streaming graph.json read entirely. * * Returns `not_found` when the metadata file is missing or unreadable. * Returns `schema_mismatch` when the graph was written by a different schema version, * letting callers either rebuild or surface the version skew without loading nodes. */ declare function loadGraphMetadata(dirPath: string): Promise; declare function loadGraph(dirPath: string): Promise; /** * Minimal PackedEnvelope shape -- avoids circular dep on @harness-engineering/core. * Canonical type: packages/core/src/compaction/envelope.ts — keep in sync. */ interface PackedEnvelope { meta: { strategy: string[]; originalTokenEstimate: number; compactedTokenEstimate: number; reductionPct: number; cached: boolean; }; sections: Array<{ source: string; content: string; }>; } /** Normalize an intent string for deterministic cache keying. */ declare function normalizeIntent(intent: string): string; /** Reads/writes PackedSummary nodes in the GraphStore. Validates via TTL + source freshness. */ declare class PackedSummaryCache { private readonly store; private readonly ttlMs; constructor(store: GraphStore, ttlMs?: number); /** Returns cached envelope with `cached: true` if valid, or null if miss/stale. */ get(intent: string): PackedEnvelope | null; /** Parse and validate createdAt. Returns epoch ms or null if missing/malformed (GC-002). */ private parseCreatedMs; /** GC-001: Checks source nodes exist and are unmodified since cache creation. */ private areSourcesFresh; /** Parse envelope JSON and set cached: true. Returns null on invalid JSON. */ private parseEnvelope; /** Write a PackedSummary node with caches edges to source nodes. */ set(intent: string, envelope: PackedEnvelope, sourceNodeIds: string[]): void; /** Explicitly invalidate a cached packed summary. */ invalidate(intent: string): void; } declare class ContextQL { private readonly store; constructor(store: GraphStore); execute(params: ContextQLParams): ContextQLResult; private seedRootNodes; private runBFS; private gatherEdges; } declare function project(nodes: readonly GraphNode[], spec: ProjectionSpec | undefined): Partial[]; type NodeCategory = 'tests' | 'docs' | 'code' | 'other'; /** Classify a graph node into an impact category. */ declare function classifyNodeCategory(node: GraphNode): NodeCategory; interface ImpactGroups { readonly tests: readonly GraphNode[]; readonly docs: readonly GraphNode[]; readonly code: readonly GraphNode[]; readonly other: readonly GraphNode[]; } /** * Group graph nodes into impact categories (tests, docs, code, other). * Excludes the root node from the results. * * Shared by both the NLQ orchestrator and the MCP get_impact handler. */ declare function groupNodesByImpact(nodes: readonly GraphNode[], excludeId?: string): ImpactGroups; /** * Options controlling which files {@link CodeIngestor} walks. Each field is optional; * defaults skip standard build artifacts, package-manager caches, AI agent sandboxes, * and IDE metadata (see {@link DEFAULT_SKIP_DIRS}). */ interface CodeIngestorOptions { /** Replace the default skip-dirs set entirely. Use sparingly — defaults are broad on purpose. */ readonly skipDirs?: Iterable; /** Add directory names to the default skip-dirs set. The common extension point. */ readonly additionalSkipDirs?: Iterable; /** Glob patterns (minimatch syntax) to exclude paths from ingestion. Evaluated against the relative POSIX-style path. */ readonly excludePatterns?: readonly string[]; /** When true, parse `/.gitignore` and use it as additional exclude patterns. Default: true. */ readonly respectGitignore?: boolean; } /** * Ingests source files into the graph via regex-based parsing. * Supports TypeScript, JavaScript, Python, Go, Rust, and Java. */ declare class CodeIngestor { private readonly store; private readonly skipDirs; private readonly excludePatterns; private readonly respectGitignore; constructor(store: GraphStore, options?: CodeIngestorOptions); ingest(rootDir: string): Promise; private processFile; private trackCallable; /** * Walk `rootDir` iteratively (BFS via an explicit queue) and return absolute paths * of every supported source file that is not excluded by the configured filters. * * Iterative on purpose: a recursive walker burns one stack frame per nested * directory and crashes with `Maximum call stack size exceeded` on deeply nested * monorepos (issue #274). The queue-based form keeps memory bounded by the * frontier size rather than the deepest path. */ private findSourceFiles; /** * Compose the exclude matchers from `excludePatterns` and (optionally) `.gitignore`. * Returns a list of minimatch-compatible patterns; an empty list means "no excludes". */ private buildExcludeMatchers; private extractSymbols; private processSymbolLine; private matchFunction; private tryExtractFunction; private matchClass; private tryExtractClass; private matchInterface; private tryExtractInterface; /** * Enter an impl block (Rust) or Java class body — sets class context without creating a node. */ private tryEnterImplBlock; /** Update brace tracking; returns true when line is consumed (class ended or tracked). */ private updateClassContext; private matchMethod; private tryExtractMethod; private matchVariable; private tryExtractVariable; /** * Find the closing brace for a construct starting at the given line. * Uses a simple brace-counting heuristic. Returns 1-indexed line number. */ private findClosingBrace; /** * Find the end of an indentation-based block (Python). * The block ends when a subsequent non-empty line has indentation <= the starting line. */ private findEndOfIndentBlock; /** * Update class context for Python using indentation tracking. */ private updatePythonClassContext; /** * Scan a file for identifiers matching known callable names, * then create file-to-file "calls" edges. Uses regex heuristic (not AST). */ private extractCallsEdgesForFile; private extractImports; private extractImportPaths; private resolveImportPath; private computeCyclomaticComplexity; private computeMaxNesting; private countParameters; private detectLanguage; /** * Scan file contents for @req annotations and create verified_by edges * linking requirement nodes to the annotated files. * Format: // @req # */ private extractReqAnnotationsForFile; } /** * Default directory names skipped during source-file walking. * * Walking into these on a populated monorepo (e.g. .turbo or .claude/worktrees) * inflates the walked-file count by orders of magnitude and is the root cause * of the recursion-depth and heap-OOM crashes reported in * https://github.com/Intense-Visions/harness-engineering/issues/274. * * Categories covered: * - VCS / repo metadata * - Package-manager caches and stores * - JS/TS framework build & dev caches * - Test, coverage, and reporter outputs * - Python virtualenvs and bytecode caches * - JVM build outputs * - IDE / editor metadata * - AI agent sandbox directories (Claude Code worktrees, Cursor, Codex, etc.) * * Consumers may extend or replace this set via {@link CodeIngestorOptions} * or the project-level `ingest.skipDirs` / `ingest.additionalSkipDirs` config. */ declare const DEFAULT_SKIP_DIRS: ReadonlySet; /** * Build an effective skip-dirs Set from optional caller overrides. * - If `skipDirs` is provided, it replaces the defaults entirely. * - If `additionalSkipDirs` is provided, it extends the defaults (or the override). */ declare function resolveSkipDirs(options?: { skipDirs?: Iterable; additionalSkipDirs?: Iterable; }): ReadonlySet; /** * Convert a skip-dirs set into minimatch glob patterns of the form * `**\//\**`. Use for tools that exclude via globs (security scan, doc * coverage, entropy analysis) rather than by reading directory names during * traversal. Defaults to {@link DEFAULT_SKIP_DIRS}. * * Returns a fresh array each call so callers may freely mutate/append * domain-specific patterns (e.g. test/fixture file globs). */ declare function skipDirGlobs(skipDirs?: ReadonlySet): string[]; type GitRunner = (rootDir: string, args: string[]) => Promise; /** * Ingests git history into the graph, creating commit nodes, * triggered_by edges (file -> commit), and co_changes_with edges * for files frequently modified together. */ declare class GitIngestor { private readonly store; private readonly gitRunner?; constructor(store: GraphStore, gitRunner?: GitRunner | undefined); ingest(rootDir: string): Promise; private ingestCommit; private ingestCoChanges; private runGit; private parseGitLog; /** * Process one line from git log output, updating the in-progress commit builder * and flushing completed commits into the accumulator. * Returns the updated current builder (null if flushed and not replaced). */ private processLogLine; private computeCoChanges; } interface LinkResult { readonly edgesAdded: number; readonly cycles: readonly string[][]; } /** * Post-ingestion linker that: * 1. Groups files into module nodes based on directory structure * 2. Detects circular dependencies in the import graph */ declare class TopologicalLinker { private readonly store; constructor(store: GraphStore); link(): LinkResult; private detectCycles; } declare class KnowledgeIngestor { private readonly store; constructor(store: GraphStore); ingestADRs(adrDir: string): Promise; ingestLearnings(projectPath: string): Promise; ingestFailures(projectPath: string): Promise; ingestGeneralDocs(projectPath: string): Promise; ingestAll(projectPath: string, opts?: { adrDir?: string; }): Promise; private linkToCode; private findMarkdownFiles; private scanDocsDir; } declare class BusinessKnowledgeIngestor { private readonly store; constructor(store: GraphStore); ingest(knowledgeDir: string): Promise; ingestSolutions(solutionsDir: string): Promise; /** * Ingest the repo-root STRATEGY.md anchor as `business_fact` nodes — one per * non-empty section. Soft-fails when the file is absent (returns empty result * with no errors) so existing projects without a strategy doc keep working. * * Each emitted node carries `metadata.domain === 'strategy'` and * `metadata.source === 'STRATEGY.md'`, making the strategy domain * discoverable through the same filters as other business-knowledge nodes. */ ingestStrategy(strategyPath: string): Promise; /** * Build a single STRATEGY.md `business_fact` node from a parsed section. * Returns null when the section is unknown, empty, or carries unfilled * template placeholder text — callers iterate and skip nulls. */ private buildStrategyNode; private createNodes; private parseAndAddNode; private createEdges; private linkToNodes; private linkToBusinessNodes; private findMarkdownFiles; } /** * Ingests ADR files from docs/knowledge/decisions/ into the knowledge graph. * * Parses YAML frontmatter with fields: number, title, date, status, tier, * source, supersedes. Creates `decision` type graph nodes with `decided` * edges to code nodes mentioned in the body. * * Also supports markdown-style ADRs written by `harness-architecture-advisor` * at `docs/architecture//ADR-.md` (no YAML frontmatter — fields are * `**Date:**`, `**Status:**`, `**Deciders:**` lines). See `ingestArchitecture`. */ declare class DecisionIngestor { private readonly store; constructor(store: GraphStore); ingest(decisionsDir: string): Promise; /** * Ingest ADRs written by `harness-architecture-advisor` from * `docs/architecture//ADR-.md`. These files do not carry YAML * frontmatter — the canonical format is: * * ``` * # ADR-: * * **Date:** <date> * **Status:** Accepted | Proposed | Superseded | Deprecated * **Deciders:** <who> * ``` * * The first directory under `architectureDir` becomes `metadata.domain` * (the "topic"), so projects whose only knowledge substrate is ADRs surface * `architecture/<topic>` as a documented domain rather than reporting empty. * * Soft-fails when the directory is absent (the common case for projects that * do not use the architecture-advisor convention). */ ingestArchitecture(architectureDir: string): Promise<IngestResult>; /** * Read, parse, and add a single architecture-advisor ADR. Returns the delta * the caller should fold into the aggregate counts. Errors are appended to * the shared `errors` array rather than thrown, matching the soft-fail * contract of `ingest()`. */ private processArchitectureAdrFile; private parseFrontmatter; private linkToCode; private findDecisionFiles; /** * Recursively find `ADR-*.md` files under `dir`. Skips default skip dirs * (node_modules etc.) to keep the scan bounded on large repos. */ private findArchitectureAdrFiles; } declare class RequirementIngestor { private readonly store; constructor(store: GraphStore); /** * Scan a specs directory for `<feature>/proposal.md` files, * extract numbered requirements from recognized sections, * and create requirement nodes with convention-based edges. */ ingestSpecs(specsDir: string): Promise<IngestResult>; private ingestFeatureDir; private ingestSpec; private ingestRequirement; /** * Parse markdown content and extract numbered items from recognized sections. */ private extractRequirements; /** * Check if a line is a section heading and return updated section state, * or return null if the line is not a heading. */ private processHeadingLine; /** * Build a requirement GraphNode from a matched numbered-item line. */ private buildRequirementNode; /** * Convention-based linking: match requirement to code/test files * by feature name in their path. */ private linkByPathPattern; /** * Convention-based linking: match requirement text to code nodes * by keyword overlap (function/class names appearing in requirement text). */ private linkByKeywordOverlap; } /** * Domain inference for graph nodes. * * Precedence (highest to lowest): * 1. node.metadata.domain (explicit) * 2. extraPatterns (config-provided) * 3. DEFAULT_PATTERNS (built-in) * 4. Generic first non-blocklisted path segment * 5. KnowledgeLinker connector source (path-less facts) * 6. 'unknown' * * Pattern format: 'prefix/<dir>'. Single-segment prefix only. <dir> captures * the segment immediately after the prefix. */ interface DomainInferenceOptions { /** Additional patterns beyond the built-in defaults. Format: 'prefix/<dir>'. */ extraPatterns?: readonly string[]; /** Additional blocklisted segments beyond the built-in defaults. */ extraBlocklist?: readonly string[]; } declare const DEFAULT_PATTERNS: readonly string[]; declare const DEFAULT_BLOCKLIST: ReadonlySet<string>; declare function inferDomain(node: { path?: string; metadata?: Record<string, unknown>; }, options?: DomainInferenceOptions): string; type DriftClassification = 'new' | 'drifted' | 'stale' | 'contradicting'; interface KnowledgeSnapshotEntry { readonly id: string; readonly type: NodeType; readonly contentHash: string; readonly source: string; readonly name: string; } interface KnowledgeSnapshot { readonly entries: readonly KnowledgeSnapshotEntry[]; readonly timestamp: string; } interface DriftFinding { readonly entryId: string; readonly classification: DriftClassification; readonly current?: KnowledgeSnapshotEntry; readonly fresh?: KnowledgeSnapshotEntry; readonly severity: 'critical' | 'high' | 'medium' | 'low'; } interface DriftResult { readonly findings: readonly DriftFinding[]; readonly driftScore: number; readonly summary: { readonly new: number; readonly drifted: number; readonly stale: number; readonly contradicting: number; }; } interface DriftDetector { detect(current: KnowledgeSnapshot, fresh: KnowledgeSnapshot): DriftResult; } declare class StructuralDriftDetector implements DriftDetector { detect(current: KnowledgeSnapshot, fresh: KnowledgeSnapshot): DriftResult; } /** * Knowledge Staging Aggregator * * Merges extraction results from multiple sources (code extractors, linkers, diagrams), * deduplicates by contentHash, writes staged JSONL, and generates gap reports. */ interface StagedEntry { readonly id: string; readonly source: 'extractor' | 'linker' | 'diagram'; readonly extractorName?: string; readonly nodeType: NodeType; readonly name: string; readonly confidence: number; readonly contentHash: string; readonly timestamp: string; } interface GapEntry { readonly nodeId: string; readonly name: string; readonly nodeType: NodeType; readonly source: string; readonly hasContent: boolean; } interface DomainCoverage { readonly domain: string; readonly entryCount: number; readonly extractedCount: number; readonly gapCount: number; readonly gapEntries: readonly GapEntry[]; } interface GapReport { readonly domains: readonly DomainCoverage[]; readonly totalEntries: number; readonly totalExtracted: number; readonly totalGaps: number; readonly generatedAt: string; } interface AggregateResult { readonly staged: number; } declare class KnowledgeStagingAggregator { private readonly projectDir; private readonly inferenceOptions; constructor(projectDir: string, inferenceOptions?: DomainInferenceOptions); aggregate(extractorResults: readonly StagedEntry[], linkerResults: readonly StagedEntry[], diagramResults: readonly StagedEntry[]): Promise<AggregateResult>; private extractDocName; generateGapReport(knowledgeDir: string, store?: GraphStore): Promise<GapReport>; writeGapReport(report: GapReport): Promise<void>; } interface AnalysisRequest { prompt: string; systemPrompt?: string; responseSchema: unknown; model?: string; maxTokens?: number; } interface AnalysisResponse<T> { result: T; tokenUsage: { inputTokens: number; outputTokens: number; totalTokens: number; }; model: string; latencyMs: number; } interface AnalysisProvider { analyze<T>(request: AnalysisRequest): Promise<AnalysisResponse<T>>; } interface DetectedElement { readonly type: string; readonly label: string; readonly confidence: number; } interface ImageAnalysisResult { readonly description: string; readonly detectedElements: readonly DetectedElement[]; readonly extractedText: readonly string[]; readonly designPatterns: readonly string[]; readonly accessibilityNotes: readonly string[]; } interface ImageAnalysisExtractorOptions { readonly analysisProvider: AnalysisProvider; readonly maxFileSizeMB?: number; } declare class ImageAnalysisExtractor { private readonly provider; /** Maximum file size in bytes. Reserved for future file-size filtering. */ readonly maxFileSizeBytes: number; constructor(options: ImageAnalysisExtractorOptions); analyze(store: GraphStore, imagePaths: readonly string[]): Promise<IngestResult>; /** Analyze a single image and add annotation + concept nodes to the store. */ private processImage; /** Link annotation to its source file node if it exists. Returns 1 if linked, 0 otherwise. */ private linkToFileNode; /** Create a business_concept node for a design pattern and link it. Returns edges added. */ private addDesignPatternConcept; } type ConflictType = 'value_mismatch' | 'definition_conflict' | 'status_divergence' | 'temporal_conflict'; interface ContradictionEntry { readonly nodeId: string; readonly source: string; readonly name: string; readonly content: string; readonly lastModified?: string | undefined; } interface Contradiction { readonly id: string; readonly entityA: ContradictionEntry; readonly entityB: ContradictionEntry; readonly similarity: number; readonly conflictType: ConflictType; readonly severity: 'critical' | 'high' | 'medium'; readonly description: string; } interface ContradictionResult { readonly contradictions: readonly Contradiction[]; readonly sourcePairCounts: Record<string, number>; readonly totalChecked: number; } declare class ContradictionDetector { detect(store: GraphStore): ContradictionResult; } interface DomainCoverageScore { readonly domain: string; readonly score: number; readonly knowledgeEntries: number; readonly codeEntities: number; readonly linkedEntities: number; readonly unlinkedEntities: number; readonly sourceBreakdown: Record<string, number>; readonly grade: 'A' | 'B' | 'C' | 'D' | 'F'; } interface CoverageReport { readonly domains: readonly DomainCoverageScore[]; readonly overallScore: number; readonly overallGrade: 'A' | 'B' | 'C' | 'D' | 'F'; readonly generatedAt: string; } declare class CoverageScorer { private readonly inferenceOptions; constructor(inferenceOptions?: DomainInferenceOptions); score(store: GraphStore): CoverageReport; } /** * Knowledge Document Materializer * * Takes GapEntry[] from the differential gap report and creates * docs/knowledge/{domain}/*.md files from graph nodes. * Frontmatter is compatible with BusinessKnowledgeIngestor's parseFrontmatter(). */ interface MaterializeOptions { readonly projectDir: string; readonly dryRun: boolean; readonly maxDocs?: number; } interface MaterializeResult { readonly created: readonly MaterializedDoc[]; readonly skipped: readonly SkippedEntry[]; } interface MaterializedDoc { readonly filePath: string; readonly nodeId: string; readonly domain: string; readonly name: string; } interface SkippedEntry { readonly nodeId: string; readonly name: string; readonly reason: 'no_content' | 'no_domain' | 'already_documented' | 'dry_run' | 'cap_reached'; } declare class KnowledgeDocMaterializer { private readonly store; private readonly inferenceOptions; constructor(store: GraphStore, inferenceOptions?: DomainInferenceOptions); materialize(gapEntries: readonly GapEntry[], options: MaterializeOptions): Promise<MaterializeResult>; private resolveEntry; inferDomain(node: GraphNode): string | null; generateFilename(name: string): string; resolveCollision(dir: string, basename: string): Promise<string>; formatDoc(node: GraphNode, domain: string): string; /** Check if a doc with a matching title already exists in the domain directory. */ private hasExistingDoc; mapNodeType(node: GraphNode): NodeType; } /** * KnowledgePipelineRunner — 4-phase convergence loop for knowledge extraction, * reconciliation, drift detection, and remediation. * * Phases: * 1. EXTRACT — Run code signal extractors, diagram parsers, image analysis, business knowledge ingestor, linker * 2. RECONCILE — Compare pre-extraction graph snapshot against post-extraction snapshot + cross-source contradiction detection * 3. DETECT — Classify findings by severity, generate gap report + coverage scoring * 4. REMEDIATE — Apply safe fixes, converge (only with `fix: true`) */ interface KnowledgePipelineOptions { readonly projectDir: string; readonly fix: boolean; readonly ci: boolean; readonly domain?: string; readonly graphDir?: string; readonly maxIterations?: number; readonly analyzeImages?: boolean; readonly analysisProvider?: AnalysisProvider; readonly imagePaths?: readonly string[]; /** * Domain-inference overrides threaded into KnowledgeStagingAggregator, * CoverageScorer, and KnowledgeDocMaterializer. Sourced by the CLI from * `harness.config.json#knowledge.domainPatterns` (→ extraPatterns) and * `knowledge.domainBlocklist` (→ extraBlocklist). Defaults to {} when absent. */ readonly inferenceOptions?: DomainInferenceOptions; } interface ExtractionCounts { readonly codeSignals: number; readonly diagrams: number; readonly linkerFacts: number; readonly businessKnowledge: number; readonly decisions: number; readonly images: number; } interface KnowledgePipelineResult { readonly verdict: 'pass' | 'warn' | 'fail'; readonly driftScore: number; readonly iterations: number; readonly findings: DriftResult['summary']; readonly extraction: ExtractionCounts; /** * Aggregated parse/skip errors from every ingestor invoked during phase 1. * Surfaces frontmatter validation, malformed-markdown, and per-file read * failures that would otherwise be silently dropped (issue #504 §1). */ readonly errors: readonly string[]; readonly gaps: GapReport; readonly remediations: readonly string[]; readonly contradictions: ContradictionResult; readonly coverage: CoverageReport; readonly materialization?: MaterializeResult; } declare class KnowledgePipelineRunner { private readonly store; constructor(store: GraphStore); /** Resolved per-`run()` inference options. Set on entry to `run()`. */ private inferenceOptions; run(options: KnowledgePipelineOptions): Promise<KnowledgePipelineResult>; /** Run the remediation convergence loop; returns iteration count and accumulated materialization. */ private runRemediationLoop; /** Assemble the final pipeline result. */ private buildResult; private extract; private buildSnapshot; private reconcile; private detect; private remediate; private stageNewFindings; private classifySource; private computeVerdict; } /** * Shared types for diagram format parsers. */ interface DiagramEntity { readonly id: string; readonly label: string; readonly type?: string; } interface DiagramRelationship { readonly from: string; readonly to: string; readonly label?: string; } interface DiagramParseResult { readonly entities: readonly DiagramEntity[]; readonly relationships: readonly DiagramRelationship[]; readonly metadata: { readonly format: 'mermaid' | 'd2' | 'plantuml'; readonly diagramType: string; }; } interface DiagramFormatParser { canParse(content: string, ext: string): boolean; parse(content: string, filePath: string): DiagramParseResult; } /** * Mermaid diagram format parser. * * Handles .mmd and .mermaid files, supporting flowchart and sequence diagram types. */ declare class MermaidParser implements DiagramFormatParser { canParse(_content: string, ext: string): boolean; parse(content: string, _filePath: string): DiagramParseResult; } /** * D2 diagram format parser. * * Handles .d2 files, extracting entities and connections from D2 architecture diagrams. */ declare class D2Parser implements DiagramFormatParser { canParse(_content: string, ext: string): boolean; parse(content: string, _filePath: string): DiagramParseResult; } /** * PlantUML diagram format parser. * * Handles .puml and .plantuml files, supporting class and component diagram types. */ declare class PlantUmlParser implements DiagramFormatParser { canParse(_content: string, ext: string): boolean; parse(content: string, _filePath: string): DiagramParseResult; } /** * Diagram-as-code parser orchestrator. * * Delegates to format-specific parsers (Mermaid, D2, PlantUML) and maps * extracted entities/relationships to the knowledge graph. * * Format-specific implementations live in ./parsers/. */ declare class DiagramParser { private readonly store; private readonly parsers; constructor(store: GraphStore); parse(content: string, filePath: string): DiagramParseResult; ingest(projectDir: string): Promise<IngestResult>; /** Map diagram entities to business_concept graph nodes. */ private addEntityNodes; /** Map diagram relationships to references graph edges. */ private addRelationshipEdges; private findDiagramFiles; } type HttpClient = (url: string, options?: { headers?: Record<string, string>; }) => Promise<{ ok: boolean; status?: number; json(): Promise<unknown>; }>; interface ConnectorConfig { apiKeyEnv?: string; baseUrlEnv?: string; schedule?: string; lookbackDays?: number; filters?: Record<string, unknown>; maxContentLength?: number; [key: string]: unknown; } interface GraphConnector { readonly name: string; readonly source: string; ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; } interface SyncMetadata { connectors: Record<string, { lastSyncTimestamp: string; lastResult: IngestResult; }>; } declare function linkToCode(store: GraphStore, content: string, sourceNodeId: string, edgeType: EdgeType, options?: { checkPaths?: boolean; }): number; declare class SyncManager { private readonly store; private readonly registrations; private readonly metadataPath; constructor(store: GraphStore, graphDir: string); registerConnector(connector: GraphConnector, config: ConnectorConfig): void; sync(connectorName: string): Promise<IngestResult>; syncAll(): Promise<IngestResult>; getMetadata(): Promise<SyncMetadata>; private loadMetadata; private saveMetadata; } declare class JiraConnector implements GraphConnector { readonly name = "jira"; readonly source = "jira"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private fetchAllIssues; private processIssue; private fetchComments; } declare class SlackConnector implements GraphConnector { readonly name = "slack"; readonly source = "slack"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private processChannel; private fetchThreadReplies; } declare class ConfluenceConnector implements GraphConnector { readonly name = "confluence"; readonly source = "confluence"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private fetchAllPagesHandled; private fetchAllPages; private processPage; } declare class CIConnector implements GraphConnector { readonly name = "ci"; readonly source = "github-actions"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private fetchAndIngestRuns; } declare class FigmaConnector implements GraphConnector { readonly name = "figma"; readonly source = "figma"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private processFile; private ingestStyles; private processStyle; private ingestComponents; private processComponent; private addComponentIntent; private addComponentConstraint; } declare class MiroConnector implements GraphConnector { readonly name = "miro"; readonly source = "miro"; private readonly httpClient; constructor(httpClient?: HttpClient); ingest(store: GraphStore, config: ConnectorConfig): Promise<IngestResult>; private processBoard; } interface FusionResult { readonly nodeId: string; readonly node: GraphNode; readonly score: number; readonly signals: { readonly keyword: number; readonly semantic: number; }; } declare class FusionLayer { private readonly store; private readonly vectorStore; private readonly keywordWeight; private readonly semanticWeight; constructor(store: GraphStore, vectorStore?: VectorStore, keywordWeight?: number, semanticWeight?: number); search(query: string, topK?: number, queryEmbedding?: readonly number[]): FusionResult[]; private buildSemanticScores; private resolveWeights; private scoreNodes; private extractKeywords; private keywordScore; private singleKeywordScore; } interface GraphDriftData { readonly staleEdges: ReadonlyArray<{ docNodeId: string; codeNodeId: string; edgeType: string; codeLastModified?: string | undefined; docLastModified?: string | undefined; }>; readonly missingTargets: readonly string[]; readonly freshEdges: number; } interface GraphDeadCodeData { readonly reachableNodeIds: ReadonlySet<string>; readonly unreachableNodes: ReadonlyArray<{ id: string; type: string; name: string; path?: string | undefined; }>; readonly entryPoints: readonly string[]; } interface GraphSnapshotSummary { readonly nodeCount: number; readonly edgeCount: number; readonly nodesByType: Record<string, number>; readonly edgesByType: Record<string, number>; } declare class GraphEntropyAdapter { private readonly store; constructor(store: GraphStore); /** * Find all `documents` edges and classify them as stale or missing-target. * * 1. Find all `documents` edges in the graph * 2. For each edge, check if the target code node still exists in the store * 3. If target doesn't exist -> add to missingTargets * 4. If target exists -> compare lastModified timestamps to determine staleness */ computeDriftData(): GraphDriftData; private classifyDocEdge; /** * BFS from entry points to find reachable vs unreachable code nodes. * * 1. Entry points: file nodes named `index.ts` or with metadata `entryPoint: true` * 2. BFS following `imports` and `calls` edges (outbound only) * 3. Unreachable = code nodes NOT in visited set */ computeDeadCodeData(): GraphDeadCodeData; private findEntryPoints; private bfsFromEntryPoints; private enqueueOutboundEdges; private collectUnreachableNodes; /** * Count all nodes and edges by type. */ computeSnapshotSummary(): GraphSnapshotSummary; } interface GraphComplexityHotspot { readonly file: string; readonly function: string; readonly changeFrequency: number; readonly complexity: number; readonly hotspotScore: number; } interface GraphComplexityResult { readonly hotspots: readonly GraphComplexityHotspot[]; readonly percentile95Score: number; } declare class GraphComplexityAdapter { private readonly store; constructor(store: GraphStore); /** * Compute complexity hotspots by combining cyclomatic complexity with change frequency. * * 1. Find all function and method nodes * 2. For each, find the containing file and count commit nodes referencing that file * 3. Compute hotspotScore = changeFrequency * cyclomaticComplexity * 4. Sort descending by score * 5. Compute 95th percentile */ computeComplexityHotspots(): GraphComplexityResult; /** * Walk the 'contains' edges to find the file node that contains a given function/method. * For methods, walks through the intermediate class node. */ private findContainingFileId; private findParentFileOfClass; private getChangeFrequency; private computePercentile; } interface GraphCouplingFileData { readonly file: string; readonly fanIn: number; readonly fanOut: number; readonly couplingRatio: number; readonly transitiveDepth: number; } interface GraphCouplingResult { readonly files: readonly GraphCouplingFileData[]; } declare class GraphCouplingAdapter { private readonly store; constructor(store: GraphStore); /** * Compute coupling data for all file nodes in the graph. * * For each file: * - fanOut: number of outbound 'imports' edges * - fanIn: number of inbound 'imports' edges from other files * - couplingRatio: fanOut / (fanIn + fanOut), rounded to 2 decimals (0 if both are 0) * - transitiveDepth: longest chain of outbound 'imports' edges via BFS */ computeCouplingData(): GraphCouplingResult; /** * BFS from a node following outbound 'imports' edges to find the maximum depth. */ private computeTransitiveDepth; } interface AnomalyDetectionOptions { threshold?: number; metrics?: string[]; } interface StatisticalOutlier { nodeId: string; nodeName: string; nodePath?: string | undefined; nodeType: string; metric: string; value: number; zScore: number; mean: number; stdDev: number; } interface ArticulationPoint { nodeId: string; nodeName: string; nodePath?: string | undefined; componentsIfRemoved: number; dependentCount: number; } interface AnomalyReport { statisticalOutliers: StatisticalOutlier[]; articulationPoints: ArticulationPoint[]; overlapping: string[]; summary: { totalNodesAnalyzed: number; outlierCount: number; articulationPointCount: number; overlapCount: number; metricsAnalyzed: string[]; warnings: string[]; threshold: number; }; } declare class GraphAnomalyAdapter { private readonly store; constructor(store: GraphStore); detect(options?: AnomalyDetectionOptions): AnomalyReport; private filterMetrics; private computeAllOutliers; private computeOverlap; private collectMetricValues; private computeZScoreOutliers; private findArticulationPoints; private computeRemovalImpact; } /** * All supported intent categories for natural language graph queries. * Runtime-accessible array mirroring NODE_TYPES / EDGE_TYPES pattern. */ declare const INTENTS: readonly ["impact", "find", "relationships", "explain", "anomaly"]; /** * Intent categories for natural language graph queries. */ type Intent = (typeof INTENTS)[number]; /** * Result of classifying a natural language question into an intent. */ interface ClassificationResult { readonly intent: Intent; readonly confidence: number; readonly signals: Readonly<Record<string, number>>; } /** * An entity mention from the query resolved to a graph node. */ interface ResolvedEntity { readonly raw: string; readonly nodeId: string; readonly node: GraphNode; readonly confidence: number; readonly method: 'exact' | 'fusion' | 'path'; } /** * Complete result from askGraph, including intent, entities, summary, and raw data. */ interface AskGraphResult { readonly intent: Intent; readonly intentConfidence: number; readonly entities: readonly ResolvedEntity[]; readonly summary: string; readonly data: unknown; readonly suggestions?: readonly string[]; } /** * Scored multi-signal intent classifier. * * Combines keyword presence, question-word matching, and verb-pattern matching * to classify natural language questions into one of 5 intents with a confidence * score between 0 and 1. */ declare class IntentClassifier { /** * Classify a natural language question into an intent. * * @param question - The natural language question to classify * @returns ClassificationResult with intent, confidence, and per-signal scores */ classify(question: string): ClassificationResult; /** * Score individual signals for an intent against the normalized query. */ private scoreIntent; /** * Score keyword signal: uses word-stem matching (checks if any word in the * query starts with the keyword). Saturates at 2 matches to avoid penalizing * intents with many keywords when only a few appear in the query. */ private scoreKeywords; /** * Score question-word signal: 1.0 if the query starts with a matching * question word, 0 otherwise. */ private scoreQuestionWord; /** * Score verb-pattern signal: any matching pattern yields a strong score. * Multiple matches increase score but saturate quickly. */ private scoreVerbPatterns; /** * Combine individual signal scores into a single confidence score * using additive weighted scoring. Each signal contributes weight * score, * and the total weights sum to 1.0 so the result is naturally bounded [0, 1]. */ private combineSignals; } declare class EntityExtractor { /** * Extract candidate entity mentions from a natural language query. * * @param query - The natural language query to extract entities from * @returns Array of raw entity strings in priority order, deduplicated */ extract(query: string): readonly string[]; /** Strategy 1: Quoted strings. Returns the set of consumed tokens. */ private extractQuoted; /** Strategy 2: PascalCase/camelCase tokens. Returns the set of consumed tokens. */ private extractCasing; /** Strategy 3: File paths. Returns the set of consumed tokens. */ private extractPaths; /** Strategy 4: Remaining significant nouns after stop-word and intent-keyword removal. */ private extractNouns; } /** * Resolves raw entity strings to graph nodes using a 3-step fuzzy cascade: * * 1. Exact name match via store.findNodes({ name }) * 2. FusionLayer search (if provided), take top result if score > 0.5 * 3. Path match on file nodes via path.includes(raw) * * Each step tags its match with method and confidence. * Unresolved entities are silently omitted from results. */ declare class EntityResolver { private readonly store; private readonly fusion; constructor(store: GraphStore, fusion?: FusionLayer); /** * Resolve an array of raw entity strings to graph nodes. * * @param raws - Raw entity strings from EntityExtractor * @returns Array of ResolvedEntity for each successfully resolved raw string */ resolve(raws: readonly string[]): readonly ResolvedEntity[]; private resolveOne; } /** * Template-based response formatter that generates human-readable summaries * from graph operation results, one template per intent. */ declare class ResponseFormatter { /** * Format graph operation results into a human-readable summary. * * @param intent - The classified intent * @param entities - Resolved entities from the query * @param data - Raw result data (shape varies per intent) * @param query - Original natural language query (optional) * @returns Human-readable summary string */ format(intent: Intent, entities: readonly ResolvedEntity[], data: unknown, query?: string): string; private formatImpact; private formatFind; private formatRelationships; private formatExplain; private formatAnomaly; private safeArrayLength; private p; } declare function askGraph(store: GraphStore, question: string): Promise<AskGraphResult>; interface AssembledContext { readonly nodes: readonly GraphNode[]; readonly edges: readonly GraphEdge[]; readonly tokenEstimate: number; readonly intent: string; readonly truncated: boolean; } interface GraphBudget { readonly total: number; readonly allocations: Record<string, number>; readonly density: Record<string, number>; } interface GraphFilterResult { readonly phase: string; readonly nodes: readonly GraphNode[]; readonly filePaths: readonly string[]; } interface GraphCoverageReport { readonly documented: readonly string[]; readonly undocumented: readonly string[]; readonly coveragePercentage: number; readonly totalCodeNodes: number; } declare class Assembler { private readonly store; private readonly vectorStore; private fusionLayer; constructor(store: GraphStore, vectorStore?: VectorStore); private getFusionLayer; /** * Assemble context relevant to an intent string within a token budget. */ assembleContext(intent: string, tokenBudget?: number): AssembledContext; private expandSearchResults; private truncateToFit; private countNodesByType; private computeModuleDensity; private computeTypeWeights; private allocateProportionally; computeBudget(totalTokens: number, phase?: string): GraphBudget; /** * Filter graph nodes relevant to a development phase. */ filterForPhase(phase: string): GraphFilterResult; private buildModuleLines; private buildEntryPointLines; generateMap(): string; /** * Check documentation coverage of code nodes. */ checkCoverage(): GraphCoverageReport; } interface TracedFile { readonly path: string; readonly confidence: number; readonly method: 'convention' | 'annotation' | 'plan-file-map'; } interface RequirementCoverage { readonly requirementId: string; readonly requirementName: string; readonly index: number; readonly codeFiles: readonly TracedFile[]; readonly testFiles: readonly TracedFile[]; readonly status: 'full' | 'code-only' | 'test-only' | 'none'; readonly maxConfidence: number; } interface TraceabilityResult { readonly specPath: string; readonly featureName: string; readonly requirements: readonly RequirementCoverage[]; readonly summary: { readonly total: number; readonly withCode: number; readonly withTests: number; readonly fullyTraced: number; readonly untraceable: number; readonly coveragePercent: number; }; } interface TraceabilityOptions { readonly specPath?: string; readonly featureName?: string; } declare function queryTraceability(store: GraphStore, options?: TraceabilityOptions): TraceabilityResult[]; interface GraphDependencyData { readonly nodes: readonly string[]; readonly edges: ReadonlyArray<{ from: string; to: string; importType: 'static' | 'dynamic' | 'type-only'; line: number; }>; } interface GraphLayerViolation { file: string; imports: string; fromLayer: string; toLayer: string; reason: 'WRONG_LAYER'; line: number; } interface LayerDef { name: string; patterns: string[]; allowedDependencies: string[]; } declare class GraphConstraintAdapter { private readonly store; constructor(store: GraphStore); computeDependencyGraph(): GraphDependencyData; private collectFileNodePaths; private collectImportEdges; computeLayerViolations(layers: LayerDef[], rootDir: string): GraphLayerViolation[]; private resolveLayer; } /** Languages supported by the code signal extractors. */ type Language = 'typescript' | 'javascript' | 'python' | 'go' | 'rust' | 'java'; /** * A single business-signal extraction record. * Written to JSONL and used to create provisional graph nodes. */ interface ExtractionRecord { /** Deterministic ID: `extracted:<extractor>:<hash(filePath+':'+patternKey)>` */ readonly id: string; /** Which extractor produced this record. */ readonly extractor: string; /** Source language of the file. */ readonly language: Language; /** File path relative to project root. */ readonly filePath: string; /** Start line of the extracted pattern (1-based). */ readonly line: number; /** Graph node type this maps to. */ readonly nodeType: NodeType; /** Human-readable label for the extracted fact. */ readonly name: string; /** Raw extracted text. */ readonly content: string; /** Extraction confidence (0.0-1.0). */ readonly confidence: number; /** Extractor-specific metadata. */ readonly metadata: Record<string, unknown>; } /** * Interface for pluggable code signal extractors. * Each extractor scans file content and returns extraction records. */ interface SignalExtractor { /** Unique extractor identifier (e.g. 'test-descriptions'). */ readonly name: string; /** File extensions this extractor can process. */ readonly supportedExtensions: readonly string[]; /** Extract signals from a single file's content. */ extract(content: string, filePath: string, language: Language): ExtractionRecord[]; } /** Detect language from a file path. Returns undefined if unsupported. */ declare function detectLanguage(filePath: string): Language | undefined; /** * Orchestrates code signal extraction across a project. * Walks files, dispatches to registered extractors, writes JSONL, * persists to graph, and handles stale detection. */ declare class ExtractionRunner { private readonly extractors; constructor(extractors: readonly SignalExtractor[]); /** * Run all extractors against a project directory. * @param projectDir - Project root directory * @param store - GraphStore for node/edge persistence * @param outputDir - Directory for JSONL output (e.g. .harness/knowledge/extracted/) */ run(projectDir: string, store: GraphStore, outputDir: string): Promise<IngestResult>; /** Write extraction records to JSONL file. */ writeJsonl(records: readonly ExtractionRecord[], outputDir: string, extractorName: string): Promise<void>; /** Create or update a graph node from an extraction record. */ private persistRecord; /** * Mark nodes from previous extractions that are no longer present as stale. * Returns the number of nodes marked stale. */ markStale(store: GraphStore, currentIds: Set<string>): number; /** Recursively find source files, skipping common non-source directories. */ findSourceFiles(dir: string): Promise<string[]>; } /** * Extracts business rules from test descriptions. * Finds describe/it/test blocks (TS/JS), test_ functions (Python), * Test* functions + t.Run subtests (Go), #[test] fns (Rust), * @Test + @DisplayName (Java). */ declare class TestDescriptionExtractor implements SignalExtractor { readonly name = "test-descriptions"; readonly supportedExtensions: string[]; extract(content: string, filePath: string, language: Language): ExtractionRecord[]; private extractJsTs; private extractPython; private extractGo; private extractRust; private extractJava; } /** * Extracts domain vocabulary from enum and constant definitions. * Finds enum declarations (all langs), as const objects (TS), * Object.freeze (JS), StrEnum/IntEnum (Python), iota (Go). */ declare class EnumConstantExtractor implements SignalExtractor { readonly name = "enum-constants"; readonly supportedExtensions: string[]; extract(content: string, filePath: string, language: Language): ExtractionRecord[]; private extractTypeScript; private extractJavaScript; private extractPython; private extractGo; private extractRust; private extractJava; private collectEnumMembers; private collectObjectKeys; private findClosingBrace; private collectPythonEnumMembers; private collectRustEnumVariants; private collectJavaEnumConstants; } /** * Extracts business constraints from validation schemas and decorators. * Finds Zod schemas (TS/JS), Pydantic models (Python), struct validate * tags (Go), #[validate] macros (Rust), Bean Validation (Java). */ declare class ValidationRuleExtractor implements SignalExtractor { readonly name = "validation-rules"; readonly supportedExtensions: string[]; extract(content: string, filePath: string, language: Language): ExtractionRecord[]; private extractZod; private collectZodConstraints; private extractPydantic; private collectPydanticConstraints; private extractGoValidate; private collectGoValidateTags; private extractRustValidate; private collectRustValidateAttrs; private extractBeanValidation; private findJavaClasses; private findClosingBrace; private collectBeanConstraints; } /** * Extracts API route definitions revealing the domain model. * Finds Express/Hono routes (TS/JS), FastAPI/Flask decorators (Python), * Gin/Echo/http handlers (Go), Actix macros (Rust), Spring annotations (Java). */ declare class ApiPathExtractor implements SignalExtractor { readonly name = "api-paths"; readonly supportedExtensions: string[]; extract(content: string, filePath: string, language: Language): ExtractionRecord[]; private extractJsTs; private extractPython; private extractGo; private extractRust; private extractJava; } /** All built-in code signal extractors. */ declare const ALL_EXTRACTORS: readonly SignalExtractor[]; /** Create an ExtractionRunner with all built-in extractors. */ declare function createExtractionRunner(): ExtractionRunner; declare class DesignIngestor { private readonly store; constructor(store: GraphStore); ingestTokens(tokensPath: string): Promise<IngestResult>; ingestDesignIntent(designPath: string): Promise<IngestResult>; ingestAll(designDir: string): Promise<IngestResult>; } interface DesignViolation { code: string; file: string; message: string; severity: 'error' | 'warn' | 'info'; value?: string; suggestion?: string; } type DesignStrictness = 'strict' | 'standard' | 'permissive'; /** * Generic finding shape accepted by `recordFindings()` — covers ANAT-* * (audit-component-anatomy, design-pipeline #2) and CRAFT-* * (harness-design-craft, design-pipeline #6) namespaces. Skills convert * their internal finding types into this shape before recording. */ interface CraftFindingRecord { /** Finding code, e.g. "ANAT-D023", "CRAFT-C001", "CRAFT-P001" */ code: string; /** Project-relative file path (becomes the `file` node id) */ file: string; /** Line number, if known */ line?: number; /** Human-readable message */ message: string; /** Severity at emission time */ severity: 'error' | 'warn' | 'info'; /** Optional evidence snippet */ evidence?: string; /** Optional run identifier so #4 verifier can detect fixpoint across runs */ runId?: string; } declare class DesignConstraintAdapter { private readonly store; constructor(store: GraphStore); checkForHardcodedColors(source: string, file: string, strictness?: DesignStrictness): DesignViolation[]; checkForHardcodedFonts(source: string, file: string, strictness?: DesignStrictness): DesignViolation[]; checkAll(source: string, file: string, strictness?: DesignStrictness): DesignViolation[]; private mapSeverity; /** * Record externally-computed craft findings (audit-component-anatomy, * harness-design-craft, etc.) as graph state. Idempotent — re-running on * the same findings produces no duplicate nodes or edges thanks to * GraphStore's keyed merge semantics. * * Each finding becomes: * • a `design_constraint` node keyed by finding code (created lazily * if absent; metadata merged on re-record so the most recent message * / severity wins) * • a `violates_design` edge from the source file (id = file path) to * the constraint node, with per-finding metadata (line, severity, * message, evidence, runId) * * The file node is NOT created here — it's assumed to already exist in * the graph from a prior ingest. If it does not, the edge will still be * created (graph stores edges by key, not by referential integrity) and * a subsequent ingest will populate the file node. */ recordFindings(findings: readonly CraftFindingRecord[]): { constraintsAdded: number; edgesAdded: number; }; private labelForCode; } interface GraphImpactData { readonly affectedTests: ReadonlyArray<{ testFile: string; coversFile: string; }>; readonly affectedDocs: ReadonlyArray<{ docFile: string; documentsFile: string; }>; readonly impactScope: number; } interface GraphHarnessCheckData { readonly graphExists: boolean; readonly nodeCount: number; readonly edgeCount: number; readonly constraintViolations: number; readonly undocumentedFiles: number; readonly unreachableNodes: number; } declare class GraphFeedbackAdapter { private readonly store; constructor(store: GraphStore); computeImpactData(changedFiles: string[]): GraphImpactData; private collectFileImpact; computeHarnessCheckData(): GraphHarnessCheckData; private countUndocumentedFiles; private countUnreachableNodes; } interface TaskDefinition { readonly id: string; readonly files: readonly string[]; } interface IndependenceCheckParams { readonly tasks: readonly TaskDefinition[]; readonly depth?: number; readonly edgeTypes?: readonly string[]; } interface OverlapDetail { readonly file: string; readonly type: 'direct' | 'transitive'; readonly via?: string; } interface PairResult { readonly taskA: string; readonly taskB: string; readonly independent: boolean; readonly overlaps: readonly OverlapDetail[]; } interface IndependenceResult { readonly tasks: readonly string[]; readonly analysisLevel: 'graph-expanded' | 'file-only'; readonly depth: number; readonly pairs: readonly PairResult[]; readonly groups: readonly (readonly string[])[]; readonly verdict: string; } declare class TaskIndependenceAnalyzer { private readonly store; constructor(store?: GraphStore); analyze(params: IndependenceCheckParams): IndependenceResult; private buildFileSets; private computeAllPairs; private validate; private expandViaGraph; private computePairOverlap; private buildGroups; private generateVerdict; } type ConflictSeverity = 'high' | 'medium' | 'low'; interface ConflictDetail { readonly taskA: string; readonly taskB: string; readonly severity: ConflictSeverity; readonly reason: string; readonly mitigation: string; readonly overlaps: readonly OverlapDetail[]; } interface ConflictPrediction { readonly tasks: readonly string[]; readonly analysisLevel: 'graph-expanded' | 'file-only'; readonly depth: number; readonly conflicts: readonly ConflictDetail[]; readonly groups: readonly (readonly string[])[]; readonly summary: { readonly high: number; readonly medium: number; readonly low: number; readonly regrouped: boolean; }; readonly verdict: string; } declare class ConflictPredictor { private readonly store; constructor(store?: GraphStore); predict(params: IndependenceCheckParams): ConflictPrediction; private buildMetricMaps; private classifyConflicts; private countBySeverity; private classifyTransitiveOverlap; private classifyPair; private severityRank; private computePercentile; private buildHighSeverityGroups; private groupsEqual; private generateVerdict; } interface ProbabilityStrategy { /** Compute failure propagation probability for a single edge (0..1). */ getEdgeProbability(edge: GraphEdge, fromNode: GraphNode, toNode: GraphNode): number; } interface CascadeSimulationOptions { /** Minimum cumulative probability to continue traversal. Default: 0.05 */ readonly probabilityFloor?: number; /** Maximum BFS depth. Default: 10 */ readonly maxDepth?: number; /** Filter to specific edge types. Default: all edge types. */ readonly edgeTypes?: readonly string[]; /** Pluggable probability strategy. Default: CompositeProbabilityStrategy. */ readonly strategy?: ProbabilityStrategy; } interface CascadeNode { readonly nodeId: string; readonly name: string; readonly path?: string; readonly type: string; readonly cumulativeProbability: number; readonly depth: number; readonly incomingEdge: string; readonly parentId: string; } interface CascadeLayer { readonly depth: number; readonly nodes: readonly CascadeNode[]; readonly categoryBreakdown: { readonly code: number; readonly tests: number; readonly docs: number; readonly other: number; }; } interface CascadeResult { readonly sourceNodeId: string; readonly sourceName: string; readonly layers: readonly CascadeLayer[]; readonly flatSummary: readonly CascadeNode[]; readonly summary: { readonly totalAffected: number; readonly maxDepthReached: number; readonly highRisk: number; readonly mediumRisk: number; readonly lowRisk: number; readonly categoryBreakdown: { readonly code: number; readonly tests: number; readonly docs: number; readonly other: number; }; readonly amplificationPoints: readonly string[]; readonly truncated: boolean; }; } /** * Default probability strategy blending three signals: * - 50% edge type base weight * - 30% normalized change frequency of target node * - 20% normalized coupling strength of target node */ declare class CompositeProbabilityStrategy implements ProbabilityStrategy { private readonly changeFreqMap; private readonly couplingMap; static readonly BASE_WEIGHTS: Record<string, number>; private static readonly FALLBACK_WEIGHT; private static readonly EDGE_TYPE_BLEND; private static readonly CHANGE_FREQ_BLEND; private static readonly COUPLING_BLEND; constructor(changeFreqMap: Map<string, number>, couplingMap: Map<string, number>); getEdgeProbability(edge: GraphEdge, _fromNode: GraphNode, toNode: GraphNode): number; } declare class CascadeSimulator { private readonly store; constructor(store: GraphStore); simulate(sourceNodeId: string, options?: CascadeSimulationOptions): CascadeResult; private seedQueue; private runBfs; private expandNode; private buildDefaultStrategy; private buildResult; } declare const VERSION = "0.9.0"; 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, type CraftFindingRecord, 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 };