@dreamtree-org/graphify 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-QEB7A5KB.js → chunk-5Q4BCTMF.js} +116 -103
- package/dist/chunk-5Q4BCTMF.js.map +1 -0
- package/dist/{chunk-ZPB37LLQ.js → chunk-FZ23C67J.js} +2 -2
- package/dist/{chunk-6JLEILYF.js → chunk-N3VOEXK3.js} +32 -2
- package/dist/{chunk-6JLEILYF.js.map → chunk-N3VOEXK3.js.map} +1 -1
- package/dist/{chunk-7LTO76UD.js → chunk-OHN5UO6W.js} +2 -2
- package/dist/cli/index.cjs +19 -7
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/index.cjs +646 -181
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +229 -17
- package/dist/index.d.ts +229 -17
- package/dist/index.js +424 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mysql-DJMXLP3O.js +8 -0
- package/package.json +1 -1
- package/dist/chunk-QEB7A5KB.js.map +0 -1
- package/dist/mysql-EJ6XOWR4.js +0 -8
- /package/dist/{chunk-ZPB37LLQ.js.map → chunk-FZ23C67J.js.map} +0 -0
- /package/dist/{chunk-7LTO76UD.js.map → chunk-OHN5UO6W.js.map} +0 -0
- /package/dist/{mysql-EJ6XOWR4.js.map → mysql-DJMXLP3O.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -2,12 +2,18 @@ import Graph from 'graphology';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
type Confidence = 'EXTRACTED' | 'INFERRED' | 'AMBIGUOUS';
|
|
5
|
-
type Relation = 'calls' | 'imports' | 'imports_from' | 'inherits' | 'implements' | 'mixes_in' | 'embeds' | 'references' | 'contains' | 'method' | 're_exports';
|
|
5
|
+
type Relation = 'calls' | 'imports' | 'imports_from' | 'inherits' | 'implements' | 'mixes_in' | 'embeds' | 'references' | 'contains' | 'method' | 're_exports' | 'follows';
|
|
6
6
|
interface GraphNode {
|
|
7
7
|
id: string;
|
|
8
8
|
label: string;
|
|
9
9
|
sourceFile: string;
|
|
10
10
|
sourceLocation: string;
|
|
11
|
+
/**
|
|
12
|
+
* Node kind for document graphs (document|section|chunk|entity — see
|
|
13
|
+
* docs/KB-PROVIDER.md §5). Optional and schema-additive: classic code
|
|
14
|
+
* nodes encode kind inside the label ("class Foo") and omit this.
|
|
15
|
+
*/
|
|
16
|
+
kind?: string;
|
|
11
17
|
}
|
|
12
18
|
interface GraphEdge {
|
|
13
19
|
source: string;
|
|
@@ -89,28 +95,111 @@ declare function extract(filePath: string, displayPath?: string): Promise<Extrac
|
|
|
89
95
|
* same module) are kept as separate edges.
|
|
90
96
|
*/
|
|
91
97
|
declare function buildGraph(extractions: ExtractionResult[]): Graph;
|
|
98
|
+
/**
|
|
99
|
+
* The merge loop shared by buildGraph() (fresh graph) and
|
|
100
|
+
* updateCorpusGraph() (incremental, src/ingest/corpus.ts). Callers validate
|
|
101
|
+
* first — this assumes well-formed extractions. A node that already exists
|
|
102
|
+
* only as an auto-vivified placeholder (sourceFile '<unknown>') is upgraded
|
|
103
|
+
* in place when an extraction supplies the real node.
|
|
104
|
+
*/
|
|
105
|
+
declare function mergeExtractionsInto(graph: Graph, validated: ExtractionResult[]): void;
|
|
92
106
|
|
|
93
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Provider-agnostic interface for the semantic (LLM-driven) extraction
|
|
109
|
+
* pass. The first-class, tested path is Anthropic (see anthropic.ts) —
|
|
110
|
+
* this interface exists so an OpenAI-compatible endpoint can be swapped in
|
|
111
|
+
* later without redesigning callers. Do not build out a large provider
|
|
112
|
+
* matrix for v1 (see master prompt §7 v2 ideas).
|
|
113
|
+
*/
|
|
114
|
+
interface SemanticExtractor {
|
|
115
|
+
extractSemantic(path: string, content: string): Promise<ExtractionResult>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Smart document ingestion (docs/KB-PROVIDER.md §5): replaces the flat
|
|
120
|
+
* `text -> string[]` chunker contract with `document -> { chunks + graph
|
|
121
|
+
* fragment }`. One document per call — providers ingest from queue workers
|
|
122
|
+
* a page at a time; updateCorpusGraph() (corpus.ts) folds each fragment
|
|
123
|
+
* into the corpus graph. Structural pass only: sections, chunks,
|
|
124
|
+
* contains/follows edges, and explicit relative markdown links — fully
|
|
125
|
+
* offline and deterministic. Entities in prose need the optional
|
|
126
|
+
* caller-injected SemanticExtractor.
|
|
127
|
+
*/
|
|
128
|
+
interface DocumentInput {
|
|
94
129
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* 'zustand/middleware'`) rather than a relative path — without this,
|
|
98
|
-
* those land on an opaque `module:` node and the test never connects to
|
|
99
|
-
* the source it exercises (so `graphify tests` under-selects).
|
|
130
|
+
* Plain text or markdown. Binary parsing (PDF/DOCX/...) is the caller's
|
|
131
|
+
* job — this API takes extracted text.
|
|
100
132
|
*/
|
|
101
|
-
|
|
133
|
+
text: string;
|
|
134
|
+
/**
|
|
135
|
+
* Stable caller-side identity — becomes GraphNode.sourceFile and the id
|
|
136
|
+
* prefix for every node from this document. Re-ingesting the same
|
|
137
|
+
* sourceRef through updateCorpusGraph() replaces that document's subgraph.
|
|
138
|
+
*/
|
|
139
|
+
sourceRef: string;
|
|
140
|
+
/** Routes the structural pass. Markdown headings are honored unless this says text/plain. */
|
|
141
|
+
mimeType?: string;
|
|
142
|
+
title?: string;
|
|
143
|
+
/** Echoed onto every chunk, never interpreted. */
|
|
144
|
+
metadata?: Record<string, string>;
|
|
145
|
+
}
|
|
146
|
+
interface ChunkOptions {
|
|
147
|
+
/** Soft target per chunk, in estimated tokens (~4 chars each). Default 400. */
|
|
148
|
+
targetTokens?: number;
|
|
149
|
+
/** Hard cap — over-long paragraphs are split to fit. Default 512. */
|
|
150
|
+
maxTokens?: number;
|
|
151
|
+
/**
|
|
152
|
+
* Overlap is OFF by default: `follows` edges + expandRetrieval() replace
|
|
153
|
+
* what sliding-window overlap approximates. Callers migrating from
|
|
154
|
+
* window-chunkers can turn it back on.
|
|
155
|
+
*/
|
|
156
|
+
overlapTokens?: number;
|
|
102
157
|
}
|
|
103
|
-
interface
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
158
|
+
interface IngestOptions {
|
|
159
|
+
chunking?: ChunkOptions;
|
|
160
|
+
/**
|
|
161
|
+
* Optional semantic pass for entities/relationships in prose. Injected,
|
|
162
|
+
* never built-in — same stance as embeddings (docs/KB-PROVIDER.md §6).
|
|
163
|
+
* Omitted = structural-only, no LLM, no API key.
|
|
164
|
+
*/
|
|
165
|
+
semanticExtractor?: SemanticExtractor;
|
|
166
|
+
}
|
|
167
|
+
interface IngestedChunk {
|
|
168
|
+
/**
|
|
169
|
+
* Graph node id of this chunk — store it next to the chunk row: it is
|
|
170
|
+
* what makes expandRetrieval() hits O(1) instead of lexical.
|
|
171
|
+
*/
|
|
172
|
+
nodeId: string;
|
|
173
|
+
/** What the caller embeds and stores. */
|
|
174
|
+
content: string;
|
|
175
|
+
tokenEstimate: number;
|
|
176
|
+
/** Reading order within the document. */
|
|
177
|
+
index: number;
|
|
178
|
+
/** Heading trail, e.g. ["Q3 Results", "Revenue"]. Empty for plain text. */
|
|
179
|
+
sectionPath: string[];
|
|
180
|
+
/** sha256 of normalized content — caller-side dedup across sources. */
|
|
181
|
+
contentHash: string;
|
|
182
|
+
metadata: Record<string, string>;
|
|
183
|
+
}
|
|
184
|
+
interface IngestResult {
|
|
185
|
+
chunks: IngestedChunk[];
|
|
186
|
+
/** Graph fragment for this document — feed to updateCorpusGraph() or runPipeline's extraExtractions. */
|
|
187
|
+
extraction: ExtractionResult;
|
|
188
|
+
stats: {
|
|
189
|
+
sections: number;
|
|
190
|
+
entities: number;
|
|
191
|
+
tokenTotal: number;
|
|
192
|
+
};
|
|
108
193
|
}
|
|
109
194
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
195
|
+
* Turn one document into structure-aware chunks plus a typed graph
|
|
196
|
+
* fragment: a `document` node, `section` nodes nested via `contains`,
|
|
197
|
+
* `chunk` nodes under their section (`contains`), chained in reading order
|
|
198
|
+
* (`follows`), with relative markdown links as `references` edges. The
|
|
199
|
+
* chunks are graph nodes — the caller stores each chunk's nodeId, which is
|
|
200
|
+
* what fuses their vector search with expandRetrieval() at query time.
|
|
112
201
|
*/
|
|
113
|
-
declare function
|
|
202
|
+
declare function ingestDocument(input: DocumentInput, options?: IngestOptions): Promise<IngestResult>;
|
|
114
203
|
|
|
115
204
|
type ClusterAlgorithm = 'louvain' | 'leiden';
|
|
116
205
|
interface ClusterOptions {
|
|
@@ -144,6 +233,127 @@ interface ClusterOptions {
|
|
|
144
233
|
*/
|
|
145
234
|
declare function cluster(graph: Graph, options?: ClusterOptions): Graph;
|
|
146
235
|
|
|
236
|
+
interface UpdateCorpusOptions {
|
|
237
|
+
algorithm?: ClusterAlgorithm;
|
|
238
|
+
/**
|
|
239
|
+
* Clustering strategy per update. `'auto'` (default) keeps bulk loading
|
|
240
|
+
* safe without the caller thinking about it: new nodes adopt the majority
|
|
241
|
+
* community of their neighbors (cheap, local, deterministic), and a full
|
|
242
|
+
* global re-cluster runs only when accumulated churn since the last full
|
|
243
|
+
* pass exceeds `reclusterRatio` of the graph — or on a never-clustered
|
|
244
|
+
* graph. `true` forces a full re-cluster now (e.g. once after a batch);
|
|
245
|
+
* `false` skips community maintenance entirely for this call (churn is
|
|
246
|
+
* still tracked, so a later `'auto'` call sees the backlog).
|
|
247
|
+
*/
|
|
248
|
+
recluster?: boolean | 'auto';
|
|
249
|
+
/**
|
|
250
|
+
* Auto mode only: fraction of the graph's nodes that must have churned
|
|
251
|
+
* since the last full clustering before one is triggered. Default 0.1.
|
|
252
|
+
*/
|
|
253
|
+
reclusterRatio?: number;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Fold one document's extraction into an existing corpus graph — the
|
|
257
|
+
* streaming-ingestion companion to ingestDocument() (docs/KB-PROVIDER.md
|
|
258
|
+
* §5). Pass null for the store.load() no-graph-yet case. Re-ingesting a
|
|
259
|
+
* document is replace-not-duplicate: every node whose sourceFile matches
|
|
260
|
+
* one of the extraction's sourceFiles is dropped (with its edges) before
|
|
261
|
+
* the fragment is merged. Placeholder nodes that earlier documents' link
|
|
262
|
+
* edges auto-vivified are upgraded in place when this document is the real
|
|
263
|
+
* thing. Community upkeep is incremental by default and self-tunes to bulk
|
|
264
|
+
* loads — see UpdateCorpusOptions.recluster. Mutates and returns the graph.
|
|
265
|
+
*/
|
|
266
|
+
declare function updateCorpusGraph(graph: Graph | null, extraction: ExtractionResult, options?: UpdateCorpusOptions): Graph;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The slice of the Anthropic client this extractor uses — injectable so
|
|
270
|
+
* tests (and callers with pre-configured clients, custom base URLs, etc.)
|
|
271
|
+
* can substitute their own. Same DI pattern as DsnQueryFn / FileReader.
|
|
272
|
+
*/
|
|
273
|
+
interface SemanticModelClient {
|
|
274
|
+
messages: {
|
|
275
|
+
create(params: {
|
|
276
|
+
model: string;
|
|
277
|
+
max_tokens: number;
|
|
278
|
+
system: string;
|
|
279
|
+
thinking: {
|
|
280
|
+
type: 'adaptive';
|
|
281
|
+
};
|
|
282
|
+
output_config: {
|
|
283
|
+
format: {
|
|
284
|
+
type: 'json_schema';
|
|
285
|
+
schema: Record<string, unknown>;
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
messages: Array<{
|
|
289
|
+
role: 'user';
|
|
290
|
+
content: string;
|
|
291
|
+
}>;
|
|
292
|
+
}): Promise<{
|
|
293
|
+
stop_reason: string | null;
|
|
294
|
+
content: Array<{
|
|
295
|
+
type: string;
|
|
296
|
+
text?: string;
|
|
297
|
+
}>;
|
|
298
|
+
}>;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
interface AnthropicSemanticExtractorOptions {
|
|
302
|
+
/** Pre-configured client (or a fake for tests). Wins over apiKey. */
|
|
303
|
+
client?: SemanticModelClient;
|
|
304
|
+
/**
|
|
305
|
+
* Explicit API key. Omitted = the SDK's own resolution (ANTHROPIC_API_KEY
|
|
306
|
+
* env var, auth token, or an `ant auth login` profile) — graphify never
|
|
307
|
+
* stores or defaults a key of its own.
|
|
308
|
+
*/
|
|
309
|
+
apiKey?: string;
|
|
310
|
+
model?: string;
|
|
311
|
+
maxTokens?: number;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Direct-API semantic extraction via @anthropic-ai/sdk, for non-agent
|
|
315
|
+
* environments (e.g. a KB provider's ingest worker calling
|
|
316
|
+
* ingestDocument({semanticExtractor}) — docs/KB-PROVIDER.md §5). The
|
|
317
|
+
* default flow (Claude Code driving this CLI via the installed skill)
|
|
318
|
+
* still does its semantic pass through the assistant itself.
|
|
319
|
+
*
|
|
320
|
+
* Emits: one `entity`-kind node per extracted entity, an INFERRED
|
|
321
|
+
* `references` edge from the document node (id = `path`, matching
|
|
322
|
+
* ingestDocument's document node) to each entity, and INFERRED
|
|
323
|
+
* `references` edges between entities the document connects. Document
|
|
324
|
+
* content goes through security.wrapUntrustedSource() — never spliced raw
|
|
325
|
+
* into the prompt.
|
|
326
|
+
*/
|
|
327
|
+
declare class AnthropicSemanticExtractor implements SemanticExtractor {
|
|
328
|
+
private readonly client;
|
|
329
|
+
private readonly model;
|
|
330
|
+
private readonly maxTokens;
|
|
331
|
+
constructor(options?: AnthropicSemanticExtractorOptions);
|
|
332
|
+
extractSemantic(path: string, content: string): Promise<ExtractionResult>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface ResolveOptions {
|
|
336
|
+
/**
|
|
337
|
+
* The scanned package's own name(s) (from package.json). Tests very
|
|
338
|
+
* commonly import the package's PUBLIC entry (`import { persist } from
|
|
339
|
+
* 'zustand/middleware'`) rather than a relative path — without this,
|
|
340
|
+
* those land on an opaque `module:` node and the test never connects to
|
|
341
|
+
* the source it exercises (so `graphify tests` under-selects).
|
|
342
|
+
*/
|
|
343
|
+
selfNames?: string[];
|
|
344
|
+
}
|
|
345
|
+
interface ResolveStats {
|
|
346
|
+
/** Edge endpoints re-pointed from a guessed id to a real node id. */
|
|
347
|
+
resolvedEndpoints: number;
|
|
348
|
+
/** Placeholder module nodes dropped because the real file node replaced them. */
|
|
349
|
+
droppedPlaceholders: number;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Mutates `extractions` in place: re-points guessed edge endpoints at real
|
|
353
|
+
* node ids and drops the placeholder module nodes those guesses created.
|
|
354
|
+
*/
|
|
355
|
+
declare function resolveCrossFileReferences(extractions: ExtractionResult[], options?: ResolveOptions): ResolveStats;
|
|
356
|
+
|
|
147
357
|
/**
|
|
148
358
|
* Surface god-nodes (excessive fan-in/out), structural surprises (self
|
|
149
359
|
* references, AMBIGUOUS edges), and open questions (isolated nodes,
|
|
@@ -731,6 +941,7 @@ declare const ExtractionResultSchema: z.ZodObject<{
|
|
|
731
941
|
label: z.ZodString;
|
|
732
942
|
sourceFile: z.ZodString;
|
|
733
943
|
sourceLocation: z.ZodString;
|
|
944
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
734
945
|
}, z.core.$strip>>;
|
|
735
946
|
edges: z.ZodArray<z.ZodObject<{
|
|
736
947
|
source: z.ZodString;
|
|
@@ -747,6 +958,7 @@ declare const ExtractionResultSchema: z.ZodObject<{
|
|
|
747
958
|
contains: "contains";
|
|
748
959
|
method: "method";
|
|
749
960
|
re_exports: "re_exports";
|
|
961
|
+
follows: "follows";
|
|
750
962
|
}>;
|
|
751
963
|
confidence: z.ZodEnum<{
|
|
752
964
|
EXTRACTED: "EXTRACTED";
|
|
@@ -772,4 +984,4 @@ declare class ExtractionValidationError extends Error {
|
|
|
772
984
|
*/
|
|
773
985
|
declare function validateExtraction(value: unknown, context?: string): ExtractionResult;
|
|
774
986
|
|
|
775
|
-
export { type AffectedNode, type Analysis, type ChangedSymbol, type ClusterAlgorithm, type ClusterOptions, type Confidence, type ContextOptions, type ContextPack, type ContextSnippet, type DependencyRule, type DsnQueryFn, EXTRACTOR_REGISTRY, type ExpandOptions, type ExpandedContext, type ExpandedNode, type ExplainResult, type ExportOptions, ExtractionCache, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphDiff, type GraphEdge, type GraphNode, type GraphStore, type ImpactOptions, type ImpactResult, LocalFileGraphStore, type MergeEntry, type NodeMatch, type PathResult, type PipelineOptions, type PipelineResult, type QueryOptions, type QueryResult, type ReflectOptions, type Relation, type ResolveStats, type ResultOutcome, type ResultType, type RetrievalHit, type RewiredSymbol, type RulesConfig, type SavedResult, type SerializedGraph, type TestSelection, type TraversalEdge, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, expandRetrieval, explainNode, exportGraph, extract, extractMysql, globToRegExp, graphForDirectory, isTestFile, loadGraph, loadResults, mergeGraphs, queryGraph, rankForTask, renderContextPack, renderLessons, renderReport, renderReview, resolveCrossFileReferences, resolveNode, reviewRevisions, runPipeline, saveResult, scoreNodes, serializeGraph, shortestPath, testsForChangedFiles, testsForNode, validateExtraction, validateRules };
|
|
987
|
+
export { type AffectedNode, type Analysis, AnthropicSemanticExtractor, type AnthropicSemanticExtractorOptions, type ChangedSymbol, type ChunkOptions, type ClusterAlgorithm, type ClusterOptions, type Confidence, type ContextOptions, type ContextPack, type ContextSnippet, type DependencyRule, type DocumentInput, type DsnQueryFn, EXTRACTOR_REGISTRY, type ExpandOptions, type ExpandedContext, type ExpandedNode, type ExplainResult, type ExportOptions, ExtractionCache, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphDiff, type GraphEdge, type GraphNode, type GraphStore, type ImpactOptions, type ImpactResult, type IngestOptions, type IngestResult, type IngestedChunk, LocalFileGraphStore, type MergeEntry, type NodeMatch, type PathResult, type PipelineOptions, type PipelineResult, type QueryOptions, type QueryResult, type ReflectOptions, type Relation, type ResolveStats, type ResultOutcome, type ResultType, type RetrievalHit, type RewiredSymbol, type RulesConfig, type SavedResult, type SemanticExtractor, type SemanticModelClient, type SerializedGraph, type TestSelection, type TraversalEdge, type UpdateCorpusOptions, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, expandRetrieval, explainNode, exportGraph, extract, extractMysql, globToRegExp, graphForDirectory, ingestDocument, isTestFile, loadGraph, loadResults, mergeExtractionsInto, mergeGraphs, queryGraph, rankForTask, renderContextPack, renderLessons, renderReport, renderReview, resolveCrossFileReferences, resolveNode, reviewRevisions, runPipeline, saveResult, scoreNodes, serializeGraph, shortestPath, testsForChangedFiles, testsForNode, updateCorpusGraph, validateExtraction, validateRules };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,18 @@ import Graph from 'graphology';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
type Confidence = 'EXTRACTED' | 'INFERRED' | 'AMBIGUOUS';
|
|
5
|
-
type Relation = 'calls' | 'imports' | 'imports_from' | 'inherits' | 'implements' | 'mixes_in' | 'embeds' | 'references' | 'contains' | 'method' | 're_exports';
|
|
5
|
+
type Relation = 'calls' | 'imports' | 'imports_from' | 'inherits' | 'implements' | 'mixes_in' | 'embeds' | 'references' | 'contains' | 'method' | 're_exports' | 'follows';
|
|
6
6
|
interface GraphNode {
|
|
7
7
|
id: string;
|
|
8
8
|
label: string;
|
|
9
9
|
sourceFile: string;
|
|
10
10
|
sourceLocation: string;
|
|
11
|
+
/**
|
|
12
|
+
* Node kind for document graphs (document|section|chunk|entity — see
|
|
13
|
+
* docs/KB-PROVIDER.md §5). Optional and schema-additive: classic code
|
|
14
|
+
* nodes encode kind inside the label ("class Foo") and omit this.
|
|
15
|
+
*/
|
|
16
|
+
kind?: string;
|
|
11
17
|
}
|
|
12
18
|
interface GraphEdge {
|
|
13
19
|
source: string;
|
|
@@ -89,28 +95,111 @@ declare function extract(filePath: string, displayPath?: string): Promise<Extrac
|
|
|
89
95
|
* same module) are kept as separate edges.
|
|
90
96
|
*/
|
|
91
97
|
declare function buildGraph(extractions: ExtractionResult[]): Graph;
|
|
98
|
+
/**
|
|
99
|
+
* The merge loop shared by buildGraph() (fresh graph) and
|
|
100
|
+
* updateCorpusGraph() (incremental, src/ingest/corpus.ts). Callers validate
|
|
101
|
+
* first — this assumes well-formed extractions. A node that already exists
|
|
102
|
+
* only as an auto-vivified placeholder (sourceFile '<unknown>') is upgraded
|
|
103
|
+
* in place when an extraction supplies the real node.
|
|
104
|
+
*/
|
|
105
|
+
declare function mergeExtractionsInto(graph: Graph, validated: ExtractionResult[]): void;
|
|
92
106
|
|
|
93
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Provider-agnostic interface for the semantic (LLM-driven) extraction
|
|
109
|
+
* pass. The first-class, tested path is Anthropic (see anthropic.ts) —
|
|
110
|
+
* this interface exists so an OpenAI-compatible endpoint can be swapped in
|
|
111
|
+
* later without redesigning callers. Do not build out a large provider
|
|
112
|
+
* matrix for v1 (see master prompt §7 v2 ideas).
|
|
113
|
+
*/
|
|
114
|
+
interface SemanticExtractor {
|
|
115
|
+
extractSemantic(path: string, content: string): Promise<ExtractionResult>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Smart document ingestion (docs/KB-PROVIDER.md §5): replaces the flat
|
|
120
|
+
* `text -> string[]` chunker contract with `document -> { chunks + graph
|
|
121
|
+
* fragment }`. One document per call — providers ingest from queue workers
|
|
122
|
+
* a page at a time; updateCorpusGraph() (corpus.ts) folds each fragment
|
|
123
|
+
* into the corpus graph. Structural pass only: sections, chunks,
|
|
124
|
+
* contains/follows edges, and explicit relative markdown links — fully
|
|
125
|
+
* offline and deterministic. Entities in prose need the optional
|
|
126
|
+
* caller-injected SemanticExtractor.
|
|
127
|
+
*/
|
|
128
|
+
interface DocumentInput {
|
|
94
129
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* 'zustand/middleware'`) rather than a relative path — without this,
|
|
98
|
-
* those land on an opaque `module:` node and the test never connects to
|
|
99
|
-
* the source it exercises (so `graphify tests` under-selects).
|
|
130
|
+
* Plain text or markdown. Binary parsing (PDF/DOCX/...) is the caller's
|
|
131
|
+
* job — this API takes extracted text.
|
|
100
132
|
*/
|
|
101
|
-
|
|
133
|
+
text: string;
|
|
134
|
+
/**
|
|
135
|
+
* Stable caller-side identity — becomes GraphNode.sourceFile and the id
|
|
136
|
+
* prefix for every node from this document. Re-ingesting the same
|
|
137
|
+
* sourceRef through updateCorpusGraph() replaces that document's subgraph.
|
|
138
|
+
*/
|
|
139
|
+
sourceRef: string;
|
|
140
|
+
/** Routes the structural pass. Markdown headings are honored unless this says text/plain. */
|
|
141
|
+
mimeType?: string;
|
|
142
|
+
title?: string;
|
|
143
|
+
/** Echoed onto every chunk, never interpreted. */
|
|
144
|
+
metadata?: Record<string, string>;
|
|
145
|
+
}
|
|
146
|
+
interface ChunkOptions {
|
|
147
|
+
/** Soft target per chunk, in estimated tokens (~4 chars each). Default 400. */
|
|
148
|
+
targetTokens?: number;
|
|
149
|
+
/** Hard cap — over-long paragraphs are split to fit. Default 512. */
|
|
150
|
+
maxTokens?: number;
|
|
151
|
+
/**
|
|
152
|
+
* Overlap is OFF by default: `follows` edges + expandRetrieval() replace
|
|
153
|
+
* what sliding-window overlap approximates. Callers migrating from
|
|
154
|
+
* window-chunkers can turn it back on.
|
|
155
|
+
*/
|
|
156
|
+
overlapTokens?: number;
|
|
102
157
|
}
|
|
103
|
-
interface
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
158
|
+
interface IngestOptions {
|
|
159
|
+
chunking?: ChunkOptions;
|
|
160
|
+
/**
|
|
161
|
+
* Optional semantic pass for entities/relationships in prose. Injected,
|
|
162
|
+
* never built-in — same stance as embeddings (docs/KB-PROVIDER.md §6).
|
|
163
|
+
* Omitted = structural-only, no LLM, no API key.
|
|
164
|
+
*/
|
|
165
|
+
semanticExtractor?: SemanticExtractor;
|
|
166
|
+
}
|
|
167
|
+
interface IngestedChunk {
|
|
168
|
+
/**
|
|
169
|
+
* Graph node id of this chunk — store it next to the chunk row: it is
|
|
170
|
+
* what makes expandRetrieval() hits O(1) instead of lexical.
|
|
171
|
+
*/
|
|
172
|
+
nodeId: string;
|
|
173
|
+
/** What the caller embeds and stores. */
|
|
174
|
+
content: string;
|
|
175
|
+
tokenEstimate: number;
|
|
176
|
+
/** Reading order within the document. */
|
|
177
|
+
index: number;
|
|
178
|
+
/** Heading trail, e.g. ["Q3 Results", "Revenue"]. Empty for plain text. */
|
|
179
|
+
sectionPath: string[];
|
|
180
|
+
/** sha256 of normalized content — caller-side dedup across sources. */
|
|
181
|
+
contentHash: string;
|
|
182
|
+
metadata: Record<string, string>;
|
|
183
|
+
}
|
|
184
|
+
interface IngestResult {
|
|
185
|
+
chunks: IngestedChunk[];
|
|
186
|
+
/** Graph fragment for this document — feed to updateCorpusGraph() or runPipeline's extraExtractions. */
|
|
187
|
+
extraction: ExtractionResult;
|
|
188
|
+
stats: {
|
|
189
|
+
sections: number;
|
|
190
|
+
entities: number;
|
|
191
|
+
tokenTotal: number;
|
|
192
|
+
};
|
|
108
193
|
}
|
|
109
194
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
195
|
+
* Turn one document into structure-aware chunks plus a typed graph
|
|
196
|
+
* fragment: a `document` node, `section` nodes nested via `contains`,
|
|
197
|
+
* `chunk` nodes under their section (`contains`), chained in reading order
|
|
198
|
+
* (`follows`), with relative markdown links as `references` edges. The
|
|
199
|
+
* chunks are graph nodes — the caller stores each chunk's nodeId, which is
|
|
200
|
+
* what fuses their vector search with expandRetrieval() at query time.
|
|
112
201
|
*/
|
|
113
|
-
declare function
|
|
202
|
+
declare function ingestDocument(input: DocumentInput, options?: IngestOptions): Promise<IngestResult>;
|
|
114
203
|
|
|
115
204
|
type ClusterAlgorithm = 'louvain' | 'leiden';
|
|
116
205
|
interface ClusterOptions {
|
|
@@ -144,6 +233,127 @@ interface ClusterOptions {
|
|
|
144
233
|
*/
|
|
145
234
|
declare function cluster(graph: Graph, options?: ClusterOptions): Graph;
|
|
146
235
|
|
|
236
|
+
interface UpdateCorpusOptions {
|
|
237
|
+
algorithm?: ClusterAlgorithm;
|
|
238
|
+
/**
|
|
239
|
+
* Clustering strategy per update. `'auto'` (default) keeps bulk loading
|
|
240
|
+
* safe without the caller thinking about it: new nodes adopt the majority
|
|
241
|
+
* community of their neighbors (cheap, local, deterministic), and a full
|
|
242
|
+
* global re-cluster runs only when accumulated churn since the last full
|
|
243
|
+
* pass exceeds `reclusterRatio` of the graph — or on a never-clustered
|
|
244
|
+
* graph. `true` forces a full re-cluster now (e.g. once after a batch);
|
|
245
|
+
* `false` skips community maintenance entirely for this call (churn is
|
|
246
|
+
* still tracked, so a later `'auto'` call sees the backlog).
|
|
247
|
+
*/
|
|
248
|
+
recluster?: boolean | 'auto';
|
|
249
|
+
/**
|
|
250
|
+
* Auto mode only: fraction of the graph's nodes that must have churned
|
|
251
|
+
* since the last full clustering before one is triggered. Default 0.1.
|
|
252
|
+
*/
|
|
253
|
+
reclusterRatio?: number;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Fold one document's extraction into an existing corpus graph — the
|
|
257
|
+
* streaming-ingestion companion to ingestDocument() (docs/KB-PROVIDER.md
|
|
258
|
+
* §5). Pass null for the store.load() no-graph-yet case. Re-ingesting a
|
|
259
|
+
* document is replace-not-duplicate: every node whose sourceFile matches
|
|
260
|
+
* one of the extraction's sourceFiles is dropped (with its edges) before
|
|
261
|
+
* the fragment is merged. Placeholder nodes that earlier documents' link
|
|
262
|
+
* edges auto-vivified are upgraded in place when this document is the real
|
|
263
|
+
* thing. Community upkeep is incremental by default and self-tunes to bulk
|
|
264
|
+
* loads — see UpdateCorpusOptions.recluster. Mutates and returns the graph.
|
|
265
|
+
*/
|
|
266
|
+
declare function updateCorpusGraph(graph: Graph | null, extraction: ExtractionResult, options?: UpdateCorpusOptions): Graph;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The slice of the Anthropic client this extractor uses — injectable so
|
|
270
|
+
* tests (and callers with pre-configured clients, custom base URLs, etc.)
|
|
271
|
+
* can substitute their own. Same DI pattern as DsnQueryFn / FileReader.
|
|
272
|
+
*/
|
|
273
|
+
interface SemanticModelClient {
|
|
274
|
+
messages: {
|
|
275
|
+
create(params: {
|
|
276
|
+
model: string;
|
|
277
|
+
max_tokens: number;
|
|
278
|
+
system: string;
|
|
279
|
+
thinking: {
|
|
280
|
+
type: 'adaptive';
|
|
281
|
+
};
|
|
282
|
+
output_config: {
|
|
283
|
+
format: {
|
|
284
|
+
type: 'json_schema';
|
|
285
|
+
schema: Record<string, unknown>;
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
messages: Array<{
|
|
289
|
+
role: 'user';
|
|
290
|
+
content: string;
|
|
291
|
+
}>;
|
|
292
|
+
}): Promise<{
|
|
293
|
+
stop_reason: string | null;
|
|
294
|
+
content: Array<{
|
|
295
|
+
type: string;
|
|
296
|
+
text?: string;
|
|
297
|
+
}>;
|
|
298
|
+
}>;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
interface AnthropicSemanticExtractorOptions {
|
|
302
|
+
/** Pre-configured client (or a fake for tests). Wins over apiKey. */
|
|
303
|
+
client?: SemanticModelClient;
|
|
304
|
+
/**
|
|
305
|
+
* Explicit API key. Omitted = the SDK's own resolution (ANTHROPIC_API_KEY
|
|
306
|
+
* env var, auth token, or an `ant auth login` profile) — graphify never
|
|
307
|
+
* stores or defaults a key of its own.
|
|
308
|
+
*/
|
|
309
|
+
apiKey?: string;
|
|
310
|
+
model?: string;
|
|
311
|
+
maxTokens?: number;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Direct-API semantic extraction via @anthropic-ai/sdk, for non-agent
|
|
315
|
+
* environments (e.g. a KB provider's ingest worker calling
|
|
316
|
+
* ingestDocument({semanticExtractor}) — docs/KB-PROVIDER.md §5). The
|
|
317
|
+
* default flow (Claude Code driving this CLI via the installed skill)
|
|
318
|
+
* still does its semantic pass through the assistant itself.
|
|
319
|
+
*
|
|
320
|
+
* Emits: one `entity`-kind node per extracted entity, an INFERRED
|
|
321
|
+
* `references` edge from the document node (id = `path`, matching
|
|
322
|
+
* ingestDocument's document node) to each entity, and INFERRED
|
|
323
|
+
* `references` edges between entities the document connects. Document
|
|
324
|
+
* content goes through security.wrapUntrustedSource() — never spliced raw
|
|
325
|
+
* into the prompt.
|
|
326
|
+
*/
|
|
327
|
+
declare class AnthropicSemanticExtractor implements SemanticExtractor {
|
|
328
|
+
private readonly client;
|
|
329
|
+
private readonly model;
|
|
330
|
+
private readonly maxTokens;
|
|
331
|
+
constructor(options?: AnthropicSemanticExtractorOptions);
|
|
332
|
+
extractSemantic(path: string, content: string): Promise<ExtractionResult>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface ResolveOptions {
|
|
336
|
+
/**
|
|
337
|
+
* The scanned package's own name(s) (from package.json). Tests very
|
|
338
|
+
* commonly import the package's PUBLIC entry (`import { persist } from
|
|
339
|
+
* 'zustand/middleware'`) rather than a relative path — without this,
|
|
340
|
+
* those land on an opaque `module:` node and the test never connects to
|
|
341
|
+
* the source it exercises (so `graphify tests` under-selects).
|
|
342
|
+
*/
|
|
343
|
+
selfNames?: string[];
|
|
344
|
+
}
|
|
345
|
+
interface ResolveStats {
|
|
346
|
+
/** Edge endpoints re-pointed from a guessed id to a real node id. */
|
|
347
|
+
resolvedEndpoints: number;
|
|
348
|
+
/** Placeholder module nodes dropped because the real file node replaced them. */
|
|
349
|
+
droppedPlaceholders: number;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Mutates `extractions` in place: re-points guessed edge endpoints at real
|
|
353
|
+
* node ids and drops the placeholder module nodes those guesses created.
|
|
354
|
+
*/
|
|
355
|
+
declare function resolveCrossFileReferences(extractions: ExtractionResult[], options?: ResolveOptions): ResolveStats;
|
|
356
|
+
|
|
147
357
|
/**
|
|
148
358
|
* Surface god-nodes (excessive fan-in/out), structural surprises (self
|
|
149
359
|
* references, AMBIGUOUS edges), and open questions (isolated nodes,
|
|
@@ -731,6 +941,7 @@ declare const ExtractionResultSchema: z.ZodObject<{
|
|
|
731
941
|
label: z.ZodString;
|
|
732
942
|
sourceFile: z.ZodString;
|
|
733
943
|
sourceLocation: z.ZodString;
|
|
944
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
734
945
|
}, z.core.$strip>>;
|
|
735
946
|
edges: z.ZodArray<z.ZodObject<{
|
|
736
947
|
source: z.ZodString;
|
|
@@ -747,6 +958,7 @@ declare const ExtractionResultSchema: z.ZodObject<{
|
|
|
747
958
|
contains: "contains";
|
|
748
959
|
method: "method";
|
|
749
960
|
re_exports: "re_exports";
|
|
961
|
+
follows: "follows";
|
|
750
962
|
}>;
|
|
751
963
|
confidence: z.ZodEnum<{
|
|
752
964
|
EXTRACTED: "EXTRACTED";
|
|
@@ -772,4 +984,4 @@ declare class ExtractionValidationError extends Error {
|
|
|
772
984
|
*/
|
|
773
985
|
declare function validateExtraction(value: unknown, context?: string): ExtractionResult;
|
|
774
986
|
|
|
775
|
-
export { type AffectedNode, type Analysis, type ChangedSymbol, type ClusterAlgorithm, type ClusterOptions, type Confidence, type ContextOptions, type ContextPack, type ContextSnippet, type DependencyRule, type DsnQueryFn, EXTRACTOR_REGISTRY, type ExpandOptions, type ExpandedContext, type ExpandedNode, type ExplainResult, type ExportOptions, ExtractionCache, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphDiff, type GraphEdge, type GraphNode, type GraphStore, type ImpactOptions, type ImpactResult, LocalFileGraphStore, type MergeEntry, type NodeMatch, type PathResult, type PipelineOptions, type PipelineResult, type QueryOptions, type QueryResult, type ReflectOptions, type Relation, type ResolveStats, type ResultOutcome, type ResultType, type RetrievalHit, type RewiredSymbol, type RulesConfig, type SavedResult, type SerializedGraph, type TestSelection, type TraversalEdge, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, expandRetrieval, explainNode, exportGraph, extract, extractMysql, globToRegExp, graphForDirectory, isTestFile, loadGraph, loadResults, mergeGraphs, queryGraph, rankForTask, renderContextPack, renderLessons, renderReport, renderReview, resolveCrossFileReferences, resolveNode, reviewRevisions, runPipeline, saveResult, scoreNodes, serializeGraph, shortestPath, testsForChangedFiles, testsForNode, validateExtraction, validateRules };
|
|
987
|
+
export { type AffectedNode, type Analysis, AnthropicSemanticExtractor, type AnthropicSemanticExtractorOptions, type ChangedSymbol, type ChunkOptions, type ClusterAlgorithm, type ClusterOptions, type Confidence, type ContextOptions, type ContextPack, type ContextSnippet, type DependencyRule, type DocumentInput, type DsnQueryFn, EXTRACTOR_REGISTRY, type ExpandOptions, type ExpandedContext, type ExpandedNode, type ExplainResult, type ExportOptions, ExtractionCache, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphDiff, type GraphEdge, type GraphNode, type GraphStore, type ImpactOptions, type ImpactResult, type IngestOptions, type IngestResult, type IngestedChunk, LocalFileGraphStore, type MergeEntry, type NodeMatch, type PathResult, type PipelineOptions, type PipelineResult, type QueryOptions, type QueryResult, type ReflectOptions, type Relation, type ResolveStats, type ResultOutcome, type ResultType, type RetrievalHit, type RewiredSymbol, type RulesConfig, type SavedResult, type SemanticExtractor, type SemanticModelClient, type SerializedGraph, type TestSelection, type TraversalEdge, type UpdateCorpusOptions, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, expandRetrieval, explainNode, exportGraph, extract, extractMysql, globToRegExp, graphForDirectory, ingestDocument, isTestFile, loadGraph, loadResults, mergeExtractionsInto, mergeGraphs, queryGraph, rankForTask, renderContextPack, renderLessons, renderReport, renderReview, resolveCrossFileReferences, resolveNode, reviewRevisions, runPipeline, saveResult, scoreNodes, serializeGraph, shortestPath, testsForChangedFiles, testsForNode, updateCorpusGraph, validateExtraction, validateRules };
|