mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-14 18:23:25 +08:00
A language's file count says what the files are, not whether anything came of them, so a language with nothing in the graph could read as healthy. `codegraph status` and `codegraph_status` now show how many of a language's files yielded symbols when that isn't all of them, and warn about a language where none did. `status --json` gains filesByLanguage, parsedFilesByLanguage and unparsedLanguages. `status --strict` exits 1 unless the index is finished, up to date and every language that should yield symbols did. The count stays out of getStats(), which every explore runs. A plain EXISTS probe per file would have doubled getStats() on a 14,569-file index, from about 40 ms to about 80 ms. The query status runs instead takes 4.3 ms there, because the stored node count settles nearly every row, and only status runs it. The gate covers more than a zero count because a grammar that can't load no longer leaves one: since PR 2335 nothing is stored for such a file, the language drops out of the rows, and the only trace is pending files. A gate checking zeroes alone would pass that. Text changes: a language row gains " (N with symbols)" only when the two numbers differ, and a warning line appears for a language with no symbols. Every other line, and every existing JSON field, is unchanged. Across 115 real indexes, 9 repos have a code language with no symbols, all of them stubs in languages with at most 3 files, such as ripgrep's .nvim.lua. A file-count threshold would have hidden a real failure in a small smoke-test project, so the rule stays plain and the warning names the files instead. Reimplements PR 1658 by @ferrine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
742 lines
19 KiB
TypeScript
742 lines
19 KiB
TypeScript
/**
|
|
* CodeGraph Type Definitions
|
|
*
|
|
* Core types for the semantic knowledge graph system.
|
|
*/
|
|
|
|
// =============================================================================
|
|
// Union Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Types of nodes in the knowledge graph.
|
|
*
|
|
* Defined as a runtime-iterable `as const` array so the same source
|
|
* of truth backs both the TS type and any runtime validation
|
|
* (e.g. the search query parser).
|
|
*
|
|
* The ARRAY ORDER is part of the native kernel's wire contract (kinds cross
|
|
* the boundary as indexes — see src/extraction/kernel/layout.ts); append new
|
|
* kinds, never reorder.
|
|
*/
|
|
export const NODE_KINDS = [
|
|
'file',
|
|
'module',
|
|
'class',
|
|
'struct',
|
|
'interface',
|
|
'trait',
|
|
'protocol',
|
|
'function',
|
|
'method',
|
|
'property',
|
|
'field',
|
|
'variable',
|
|
'constant',
|
|
'enum',
|
|
'enum_member',
|
|
'type_alias',
|
|
'namespace',
|
|
'parameter',
|
|
'import',
|
|
'export',
|
|
'route',
|
|
'component',
|
|
'union',
|
|
] as const;
|
|
|
|
export type NodeKind = (typeof NODE_KINDS)[number];
|
|
|
|
/**
|
|
* The docstring both engines give a Java record's implicit component accessor
|
|
* (languages/java.ts, codegraph-kernel/src/java.rs). The resolver reaches one
|
|
* only through what types its receiver, never by a name-only guess.
|
|
*/
|
|
export const IMPLICIT_RECORD_ACCESSOR_DOC = 'Implicit record component accessor';
|
|
|
|
/**
|
|
* Types of edges (relationships) between nodes.
|
|
*
|
|
* Runtime-iterable like NODE_KINDS. The ARRAY ORDER is part of the native
|
|
* kernel's wire contract (kinds cross the boundary as indexes — see
|
|
* src/extraction/kernel/layout.ts); append new kinds, never reorder.
|
|
*/
|
|
export const EDGE_KINDS = [
|
|
'contains', // Parent contains child (file→class, class→method)
|
|
'calls', // Function/method calls another
|
|
'imports', // File imports from another
|
|
'exports', // File exports a symbol
|
|
'extends', // Class/interface extends another
|
|
'implements', // Class implements interface
|
|
'references', // Generic reference to another symbol
|
|
'type_of', // Variable/parameter has type
|
|
'returns', // Function returns type
|
|
'instantiates', // Creates instance of class
|
|
'overrides', // Method overrides parent method
|
|
'decorates', // Decorator applied to symbol
|
|
'navigates', // Navigates to a screen/route (Expo Router `router.push('/x')`)
|
|
] as const;
|
|
|
|
export type EdgeKind = (typeof EDGE_KINDS)[number];
|
|
|
|
/**
|
|
* Supported programming languages. See NODE_KINDS for why this is a
|
|
* runtime-iterable const array.
|
|
*/
|
|
export const LANGUAGES = [
|
|
'typescript',
|
|
'javascript',
|
|
'tsx',
|
|
'jsx',
|
|
'arkts',
|
|
'python',
|
|
'go',
|
|
'rust',
|
|
'java',
|
|
'c',
|
|
'cpp',
|
|
'csharp',
|
|
'razor',
|
|
'php',
|
|
'ruby',
|
|
'swift',
|
|
'kotlin',
|
|
'dart',
|
|
'svelte',
|
|
'vue',
|
|
'astro',
|
|
'liquid',
|
|
'pascal',
|
|
'scala',
|
|
'lua',
|
|
'luau',
|
|
'objc',
|
|
'r',
|
|
'solidity',
|
|
'nix',
|
|
'yaml',
|
|
'twig',
|
|
'xml',
|
|
'properties',
|
|
'cfml',
|
|
'cfscript',
|
|
'cfquery',
|
|
'cobol',
|
|
'vbnet',
|
|
'erlang',
|
|
'terraform',
|
|
'unknown',
|
|
] as const;
|
|
|
|
export type Language = (typeof LANGUAGES)[number];
|
|
|
|
// =============================================================================
|
|
// Core Graph Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* A node in the knowledge graph representing a code symbol
|
|
*/
|
|
export interface Node {
|
|
/** Unique identifier (hash of file path + qualified name) */
|
|
id: string;
|
|
|
|
/** Type of code element */
|
|
kind: NodeKind;
|
|
|
|
/** Simple name (e.g., "calculateTotal") */
|
|
name: string;
|
|
|
|
/** Fully qualified name (e.g., "src/utils.ts::MathHelper.calculateTotal") */
|
|
qualifiedName: string;
|
|
|
|
/** File path relative to project root */
|
|
filePath: string;
|
|
|
|
/** Programming language */
|
|
language: Language;
|
|
|
|
/** Starting line number (1-indexed) */
|
|
startLine: number;
|
|
|
|
/** Ending line number (1-indexed) */
|
|
endLine: number;
|
|
|
|
/** Starting column (0-indexed) */
|
|
startColumn: number;
|
|
|
|
/** Ending column (0-indexed) */
|
|
endColumn: number;
|
|
|
|
/** Documentation string if present */
|
|
docstring?: string;
|
|
|
|
/** Function/method signature */
|
|
signature?: string;
|
|
|
|
/** Visibility modifier */
|
|
visibility?: 'public' | 'private' | 'protected' | 'internal';
|
|
|
|
/** Whether symbol is exported */
|
|
isExported?: boolean;
|
|
|
|
/** Whether symbol is async */
|
|
isAsync?: boolean;
|
|
|
|
/** Whether symbol is static */
|
|
isStatic?: boolean;
|
|
|
|
/** Whether symbol is abstract */
|
|
isAbstract?: boolean;
|
|
|
|
/** Decorators/annotations applied */
|
|
decorators?: string[];
|
|
|
|
/** Generic type parameters */
|
|
typeParameters?: string[];
|
|
|
|
/**
|
|
* Normalized return/result type name for a function/method (the bare class
|
|
* name, smart-pointer pointee unwrapped). Captured for C/C++ so resolution
|
|
* can infer a chained receiver's type from what the inner call returns —
|
|
* `Foo::instance().bar()` resolves `bar` on `Foo` (issue #645). Undefined for
|
|
* languages/symbols where it isn't captured.
|
|
*/
|
|
returnType?: string;
|
|
|
|
/** When the node was last updated */
|
|
updatedAt: number;
|
|
}
|
|
|
|
/**
|
|
* An edge representing a relationship between two nodes
|
|
*/
|
|
export interface Edge {
|
|
/** Source node ID */
|
|
source: string;
|
|
|
|
/** Target node ID */
|
|
target: string;
|
|
|
|
/** Type of relationship */
|
|
kind: EdgeKind;
|
|
|
|
/** Additional context about the relationship */
|
|
metadata?: Record<string, unknown>;
|
|
|
|
/** Line number where relationship occurs (e.g., call site) */
|
|
line?: number;
|
|
|
|
/** Column number where relationship occurs */
|
|
column?: number;
|
|
|
|
/** How this edge was created */
|
|
provenance?: 'tree-sitter' | 'scip' | 'heuristic';
|
|
}
|
|
|
|
/**
|
|
* Metadata about a tracked file
|
|
*/
|
|
export interface FileRecord {
|
|
/** File path relative to project root */
|
|
path: string;
|
|
|
|
/** Content hash for change detection */
|
|
contentHash: string;
|
|
|
|
/** Detected language */
|
|
language: Language;
|
|
|
|
/** File size in bytes */
|
|
size: number;
|
|
|
|
/** Last modification timestamp */
|
|
modifiedAt: number;
|
|
|
|
/** When last indexed */
|
|
indexedAt: number;
|
|
|
|
/** Number of nodes extracted */
|
|
nodeCount: number;
|
|
|
|
/** Any extraction errors */
|
|
errors?: ExtractionError[];
|
|
|
|
/**
|
|
* Tool-generated source, decided at index time from the filename
|
|
* convention OR a generation banner in the file's header (see
|
|
* extraction/generated-detection.ts). A relevance hint for ranking, not a
|
|
* hard filter. Absent on indexes built before schema v9 — treat
|
|
* `undefined` as "content signal unknown, fall back to the path check".
|
|
*/
|
|
generated?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Files found against files that yielded symbols, by language, for `status`.
|
|
* `GraphStats.filesByLanguage` counts files by what they are, so on its own it
|
|
* reads the same for a language that parsed and one that yielded nothing.
|
|
*/
|
|
export interface LanguageCoverage {
|
|
/**
|
|
* Files that yielded a symbol, for the languages expected to. A language
|
|
* tracked at file level (yaml, most xml) has no entry: nothing is missing.
|
|
*/
|
|
parsedFilesByLanguage: Partial<Record<Language, number>>;
|
|
/** Languages expected to yield symbols that have files, none of which did. */
|
|
unparsedLanguages: Language[];
|
|
}
|
|
|
|
/**
|
|
* Indexed files whose symbols are missing even though their content hash is
|
|
* current — what a hash comparison alone calls "up to date" (#2336). Paths are
|
|
* project-relative and sorted.
|
|
*/
|
|
export interface IndexHealth {
|
|
/**
|
|
* Files `sync` re-indexes: stored while their grammar could not load (#2335)
|
|
* or stored with no nodes and no recorded reason (#1541).
|
|
*/
|
|
needsReindex: string[];
|
|
/**
|
|
* Files with a recorded parse error and no symbols from it. Deterministic:
|
|
* they stay this way until the file (or the parser) changes.
|
|
*/
|
|
parseErrors: string[];
|
|
}
|
|
|
|
// =============================================================================
|
|
// Extraction Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Result from parsing a source file
|
|
*/
|
|
export interface ExtractionResult {
|
|
/** Extracted nodes */
|
|
nodes: Node[];
|
|
|
|
/** Extracted edges */
|
|
edges: Edge[];
|
|
|
|
/** References that couldn't be resolved yet */
|
|
unresolvedReferences: UnresolvedReference[];
|
|
|
|
/** Any errors during extraction */
|
|
errors: ExtractionError[];
|
|
|
|
/** Extraction duration in milliseconds */
|
|
durationMs: number;
|
|
|
|
/**
|
|
* Deferred-decode transport (native kernel, bulk-index path): when present,
|
|
* `nodes`/`edges`/`unresolvedReferences` are EMPTY and the file's tables
|
|
* ride as flat buffers to be decoded at the store boundary (the store
|
|
* worker), so the MAIN thread never materializes per-node objects.
|
|
* `kernelCounts` carries the table sizes for bookkeeping. Decode into a
|
|
* plain result with `materializeKernelResult` (src/extraction/kernel).
|
|
*/
|
|
kernelBuffers?: {
|
|
meta: Uint8Array;
|
|
nodes: Uint8Array;
|
|
edges: Uint8Array;
|
|
refs: Uint8Array;
|
|
arena: Uint8Array;
|
|
};
|
|
kernelCounts?: { nodes: number; edges: number; refs: number };
|
|
}
|
|
|
|
/**
|
|
* Error during code extraction
|
|
*/
|
|
export interface ExtractionError {
|
|
/** Error message */
|
|
message: string;
|
|
|
|
/** File path where the error occurred */
|
|
filePath?: string;
|
|
|
|
/** Line number if available */
|
|
line?: number;
|
|
|
|
/** Column number if available */
|
|
column?: number;
|
|
|
|
/** Error severity */
|
|
severity: 'error' | 'warning';
|
|
|
|
/** Error code for categorization */
|
|
code?: string;
|
|
}
|
|
|
|
/**
|
|
* Kinds an unresolved reference can carry. `function_ref` is internal-only —
|
|
* a function name used as a VALUE (callback registration, #756). It never
|
|
* becomes an edge kind: resolution maps it to a `references` edge targeting
|
|
* function/method nodes only (see `matchFunctionRef`).
|
|
*/
|
|
export type ReferenceKind = EdgeKind | 'function_ref';
|
|
|
|
/**
|
|
* A reference that couldn't be resolved during extraction
|
|
*/
|
|
export interface UnresolvedReference {
|
|
/** ID of the node containing the reference */
|
|
fromNodeId: string;
|
|
|
|
/** Name being referenced */
|
|
referenceName: string;
|
|
|
|
/** Type of reference (call, type, import, etc.) */
|
|
referenceKind: ReferenceKind;
|
|
|
|
/** Location of the reference */
|
|
line: number;
|
|
column: number;
|
|
|
|
/** File path where reference occurs (denormalized for performance) */
|
|
filePath?: string;
|
|
|
|
/** Language of the source file (denormalized for performance) */
|
|
language?: Language;
|
|
|
|
/** Possible qualified names it might resolve to */
|
|
candidates?: string[];
|
|
|
|
/**
|
|
* `unresolved_refs.id` when this ref was loaded from the database. Post-pass
|
|
* cleanup (delete-on-resolve / park-as-failed) targets exactly this row.
|
|
* Without it, cleanup falls back to deleting by (fromNodeId, referenceName,
|
|
* referenceKind) — which also removes SIBLING rows (same caller calling the
|
|
* same callee at other lines) that a later batch hasn't attempted yet, so
|
|
* their edges were silently never created when a batch boundary split the
|
|
* call sites (#1269).
|
|
*/
|
|
rowId?: number;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Query Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* A subgraph containing a subset of the knowledge graph
|
|
*/
|
|
export interface Subgraph {
|
|
/** Nodes in this subgraph */
|
|
nodes: Map<string, Node>;
|
|
|
|
/** Edges in this subgraph */
|
|
edges: Edge[];
|
|
|
|
/** Root node IDs (entry points) */
|
|
roots: string[];
|
|
|
|
/**
|
|
* Retrieval confidence for context-style queries. `'low'` means the query
|
|
* resolved only to isolated common-word matches (no entry point corroborated
|
|
* by 2+ distinct query terms) — callers should surface an honest handoff to
|
|
* explore/trace rather than present the results as comprehensive. Undefined
|
|
* for graph traversals that don't run the search-ranking path.
|
|
*/
|
|
confidence?: 'high' | 'low';
|
|
}
|
|
|
|
/**
|
|
* Options for graph traversal
|
|
*/
|
|
export interface TraversalOptions {
|
|
/** Maximum depth to traverse (default: Infinity) */
|
|
maxDepth?: number;
|
|
|
|
/** Edge types to follow (default: all) */
|
|
edgeKinds?: EdgeKind[];
|
|
|
|
/** Node types to include (default: all) */
|
|
nodeKinds?: NodeKind[];
|
|
|
|
/** Direction of traversal */
|
|
direction?: 'outgoing' | 'incoming' | 'both';
|
|
|
|
/** Maximum nodes to return */
|
|
limit?: number;
|
|
|
|
/** Whether to include the starting node */
|
|
includeStart?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Options for searching the graph
|
|
*/
|
|
export interface SearchOptions {
|
|
/** Node types to search */
|
|
kinds?: NodeKind[];
|
|
|
|
/** Languages to include */
|
|
languages?: Language[];
|
|
|
|
/** File path patterns to include */
|
|
includePatterns?: string[];
|
|
|
|
/** File path patterns to exclude */
|
|
excludePatterns?: string[];
|
|
|
|
/** Maximum results to return */
|
|
limit?: number;
|
|
|
|
/** Offset for pagination */
|
|
offset?: number;
|
|
|
|
/** Whether search is case-sensitive */
|
|
caseSensitive?: boolean;
|
|
}
|
|
|
|
/**
|
|
* A search result with relevance scoring
|
|
*/
|
|
export interface SearchResult {
|
|
/** Matching node */
|
|
node: Node;
|
|
|
|
/**
|
|
* Relevance score for relative ranking only — higher is more relevant.
|
|
* NOT normalized and NOT a 0-1 fraction: the FTS path returns an unbounded
|
|
* BM25 magnitude (often in the tens or hundreds), while the fuzzy/exact
|
|
* paths return ~0-1. Use it to order results, not as an absolute percentage.
|
|
*/
|
|
score: number;
|
|
|
|
/** Matched text snippets for highlighting */
|
|
highlights?: string[];
|
|
}
|
|
|
|
/**
|
|
* A symbol whose name-segments match prose words from a prompt — the
|
|
* graph-derived signal behind the front-load hook's medium tier
|
|
* (CodeGraph.getSegmentMatches). Always verified to exist in `nodes` at the
|
|
* time it is returned.
|
|
*/
|
|
export interface SegmentMatch {
|
|
/** Symbol name as indexed (e.g. `OrderStateMachine`). */
|
|
name: string;
|
|
/** Kind of the representative definition. */
|
|
kind: NodeKind;
|
|
/** File of the representative definition. */
|
|
filePath: string;
|
|
/** 1-based start line of the representative definition. */
|
|
startLine: number;
|
|
/** The prompt words (normalized) that matched this name's segments. */
|
|
matchedWords: string[];
|
|
}
|
|
|
|
// =============================================================================
|
|
// Context Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Context information for code understanding
|
|
*/
|
|
export interface Context {
|
|
/** Primary node being examined */
|
|
focal: Node;
|
|
|
|
/** Nodes containing the focal node (file, class, etc.) */
|
|
ancestors: Node[];
|
|
|
|
/** Nodes directly contained by focal node */
|
|
children: Node[];
|
|
|
|
/** Incoming references (who calls/uses this) */
|
|
incomingRefs: Array<{ node: Node; edge: Edge }>;
|
|
|
|
/** Outgoing references (what this calls/uses) */
|
|
outgoingRefs: Array<{ node: Node; edge: Edge }>;
|
|
|
|
/** Related type information */
|
|
types: Node[];
|
|
|
|
/** Relevant imports */
|
|
imports: Node[];
|
|
}
|
|
|
|
/**
|
|
* A block of code with context
|
|
*/
|
|
export interface CodeBlock {
|
|
/** The code content */
|
|
content: string;
|
|
|
|
/** File path */
|
|
filePath: string;
|
|
|
|
/** Starting line */
|
|
startLine: number;
|
|
|
|
/** Ending line */
|
|
endLine: number;
|
|
|
|
/** Language for syntax highlighting */
|
|
language: Language;
|
|
|
|
/** Associated node if extracted */
|
|
node?: Node;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Database Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Database schema version info
|
|
*/
|
|
export interface SchemaVersion {
|
|
/** Current schema version */
|
|
version: number;
|
|
|
|
/** When schema was created/updated */
|
|
appliedAt: number;
|
|
|
|
/** Description of this version */
|
|
description?: string;
|
|
}
|
|
|
|
/**
|
|
* Statistics about the knowledge graph
|
|
*/
|
|
export interface GraphStats {
|
|
/** Total number of nodes */
|
|
nodeCount: number;
|
|
|
|
/** Total number of edges */
|
|
edgeCount: number;
|
|
|
|
/** Number of tracked files */
|
|
fileCount: number;
|
|
|
|
/** Node counts by kind */
|
|
nodesByKind: Record<NodeKind, number>;
|
|
|
|
/** Edge counts by kind */
|
|
edgesByKind: Record<EdgeKind, number>;
|
|
|
|
/** File counts by language */
|
|
filesByLanguage: Record<Language, number>;
|
|
|
|
/** Database size in bytes */
|
|
dbSizeBytes: number;
|
|
|
|
/** Size of the SQLite `-wal` sidecar in bytes (0 when absent). A WAL far
|
|
* larger than the DB at rest means killed sessions left it behind (#1431). */
|
|
walSizeBytes: number;
|
|
|
|
/** Last update timestamp */
|
|
lastUpdated: number;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Task Context Types (for buildContext)
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Input for building task context
|
|
*/
|
|
export type TaskInput = string | { title: string; description?: string };
|
|
|
|
/**
|
|
* Options for building task context
|
|
*/
|
|
export interface BuildContextOptions {
|
|
/** Maximum number of nodes to include (default: 50) */
|
|
maxNodes?: number;
|
|
|
|
/** Maximum number of code blocks to include (default: 10) */
|
|
maxCodeBlocks?: number;
|
|
|
|
/** Maximum characters per code block (default: 2000) */
|
|
maxCodeBlockSize?: number;
|
|
|
|
/** Whether to include code blocks (default: true) */
|
|
includeCode?: boolean;
|
|
|
|
/** Output format (default: 'markdown') */
|
|
format?: 'markdown' | 'json';
|
|
|
|
/** Number of semantic search results (default: 5) */
|
|
searchLimit?: number;
|
|
|
|
/** Graph traversal depth from entry points (default: 2) */
|
|
traversalDepth?: number;
|
|
|
|
/** Minimum semantic similarity score (default: 0.3) */
|
|
minScore?: number;
|
|
}
|
|
|
|
/**
|
|
* Full context for a task, ready for Claude
|
|
*/
|
|
export interface TaskContext {
|
|
/** The original query/task */
|
|
query: string;
|
|
|
|
/** Subgraph of relevant nodes and edges */
|
|
subgraph: Subgraph;
|
|
|
|
/** Entry point nodes (from semantic search) */
|
|
entryPoints: Node[];
|
|
|
|
/** Code blocks extracted from key nodes */
|
|
codeBlocks: CodeBlock[];
|
|
|
|
/** Files involved in this context */
|
|
relatedFiles: string[];
|
|
|
|
/** Brief summary of the context */
|
|
summary: string;
|
|
|
|
/** Statistics about the context */
|
|
stats: {
|
|
/** Number of nodes included */
|
|
nodeCount: number;
|
|
/** Number of edges included */
|
|
edgeCount: number;
|
|
/** Number of files touched */
|
|
fileCount: number;
|
|
/** Number of code blocks included */
|
|
codeBlockCount: number;
|
|
/** Total characters in code blocks */
|
|
totalCodeSize: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Options for finding relevant context
|
|
*/
|
|
export interface FindRelevantContextOptions {
|
|
/** Number of semantic search results (default: 5) */
|
|
searchLimit?: number;
|
|
|
|
/** Graph traversal depth (default: 2) */
|
|
traversalDepth?: number;
|
|
|
|
/** Maximum nodes in result (default: 50) */
|
|
maxNodes?: number;
|
|
|
|
/** Minimum semantic similarity score (default: 0.3) */
|
|
minScore?: number;
|
|
|
|
/** Edge types to follow in traversal */
|
|
edgeKinds?: EdgeKind[];
|
|
|
|
/** Node types to include */
|
|
nodeKinds?: NodeKind[];
|
|
|
|
/**
|
|
* Extra symbol names to merge in as exact-name search candidates, at a
|
|
* dampened score. Fed by the segment-vocabulary supplement (CodeGraph.
|
|
* findRelevantContext): word-level query terms can't reach camelCase names
|
|
* through FTS — `pinFeedIfNearBottom` is one FTS token — so names whose
|
|
* SEGMENTS the query's words name are seeded here instead.
|
|
*/
|
|
seedNames?: string[];
|
|
}
|