@dreamtree-org/graphify 1.0.0 → 1.1.2
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/README.md +110 -35
- package/dist/chunk-6JLEILYF.js +207 -0
- package/dist/chunk-6JLEILYF.js.map +1 -0
- package/dist/{chunk-DG5FECXV.js → chunk-PXVI2L45.js} +614 -39
- package/dist/chunk-PXVI2L45.js.map +1 -0
- package/dist/chunk-YT7B6DOD.js +554 -0
- package/dist/chunk-YT7B6DOD.js.map +1 -0
- package/dist/chunk-ZPB37LLQ.js +155 -0
- package/dist/chunk-ZPB37LLQ.js.map +1 -0
- package/dist/cli/index.cjs +1996 -147
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +693 -42
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1192 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +343 -5
- package/dist/index.d.ts +343 -5
- package/dist/index.js +50 -5
- package/dist/mcp/server.cjs +444 -56
- package/dist/mcp/server.cjs.map +1 -1
- package/dist/mcp/server.js +65 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/mysql-EJ6XOWR4.js +8 -0
- package/dist/mysql-EJ6XOWR4.js.map +1 -0
- package/package.json +2 -1
- package/src/skill/SKILL.md +45 -10
- package/dist/chunk-5ANIDX3G.js +0 -364
- package/dist/chunk-5ANIDX3G.js.map +0 -1
- package/dist/chunk-DG5FECXV.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -51,15 +51,22 @@ interface ExportOptions {
|
|
|
51
51
|
*/
|
|
52
52
|
declare function collectFiles(root: string): FileManifest;
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
/** `displayPath`, when given, is used for node ids/sourceFile instead of the read path — see extract(). */
|
|
55
|
+
type Extractor = (path: string, displayPath?: string) => Promise<ExtractionResult>;
|
|
55
56
|
/** File extension -> extractor module. Register new languages here. */
|
|
56
57
|
declare const EXTRACTOR_REGISTRY: Record<string, Extractor>;
|
|
57
58
|
/**
|
|
58
59
|
* Dispatch a single file to its language extractor. Returns an empty
|
|
59
60
|
* extraction (not a thrown error) for unregistered extensions so detect's
|
|
60
61
|
* file list and extract's coverage can diverge without crashing a run.
|
|
62
|
+
*
|
|
63
|
+
* `displayPath` decouples where the file is read from (relative to the
|
|
64
|
+
* process cwd) from the path used in node ids and sourceFile attributes —
|
|
65
|
+
* the pipeline passes the project-root-relative path so ids stay stable
|
|
66
|
+
* and portable no matter which directory the pipeline was launched from
|
|
67
|
+
* (this is what makes cross-project merging's namespacing meaningful).
|
|
61
68
|
*/
|
|
62
|
-
declare function extract(filePath: string): Promise<ExtractionResult>;
|
|
69
|
+
declare function extract(filePath: string, displayPath?: string): Promise<ExtractionResult>;
|
|
63
70
|
|
|
64
71
|
/**
|
|
65
72
|
* Merge per-file extraction results into one graphology graph.
|
|
@@ -83,6 +90,28 @@ declare function extract(filePath: string): Promise<ExtractionResult>;
|
|
|
83
90
|
*/
|
|
84
91
|
declare function buildGraph(extractions: ExtractionResult[]): Graph;
|
|
85
92
|
|
|
93
|
+
interface ResolveOptions {
|
|
94
|
+
/**
|
|
95
|
+
* The scanned package's own name(s) (from package.json). Tests very
|
|
96
|
+
* commonly import the package's PUBLIC entry (`import { persist } from
|
|
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).
|
|
100
|
+
*/
|
|
101
|
+
selfNames?: string[];
|
|
102
|
+
}
|
|
103
|
+
interface ResolveStats {
|
|
104
|
+
/** Edge endpoints re-pointed from a guessed id to a real node id. */
|
|
105
|
+
resolvedEndpoints: number;
|
|
106
|
+
/** Placeholder module nodes dropped because the real file node replaced them. */
|
|
107
|
+
droppedPlaceholders: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Mutates `extractions` in place: re-points guessed edge endpoints at real
|
|
111
|
+
* node ids and drops the placeholder module nodes those guesses created.
|
|
112
|
+
*/
|
|
113
|
+
declare function resolveCrossFileReferences(extractions: ExtractionResult[], options?: ResolveOptions): ResolveStats;
|
|
114
|
+
|
|
86
115
|
type ClusterAlgorithm = 'louvain' | 'leiden';
|
|
87
116
|
interface ClusterOptions {
|
|
88
117
|
/**
|
|
@@ -155,6 +184,17 @@ interface PipelineOptions {
|
|
|
155
184
|
algorithm?: ClusterAlgorithm;
|
|
156
185
|
/** Leiden-only: cap on outer iterations for very large graphs. */
|
|
157
186
|
maxIterations?: number;
|
|
187
|
+
/**
|
|
188
|
+
* Pre-computed extractions from non-filesystem sources (e.g. a MySQL
|
|
189
|
+
* schema via extractMysql()) merged into the same graph as the code.
|
|
190
|
+
*/
|
|
191
|
+
extraExtractions?: ExtractionResult[];
|
|
192
|
+
/**
|
|
193
|
+
* Incremental mode: reuse cached per-file extractions (keyed by content
|
|
194
|
+
* hash) and re-parse only changed files. The cache is warmed on every
|
|
195
|
+
* run either way — `update` only controls whether it's read.
|
|
196
|
+
*/
|
|
197
|
+
update?: boolean;
|
|
158
198
|
/** Called with a short progress message after each stage (e.g. for CLI stderr output). */
|
|
159
199
|
onProgress?: (message: string) => void;
|
|
160
200
|
}
|
|
@@ -186,7 +226,18 @@ interface NodeMatch {
|
|
|
186
226
|
label: string;
|
|
187
227
|
score: number;
|
|
188
228
|
}
|
|
189
|
-
/**
|
|
229
|
+
/**
|
|
230
|
+
* Score every node against the query's tokens. Identifier-aware and
|
|
231
|
+
* typo-tolerant, in three tiers per token (best tier wins):
|
|
232
|
+
*
|
|
233
|
+
* 1. exact subtoken match (camelCase/snake_case-split word of the label
|
|
234
|
+
* or id) — "storage" matches `fileStorage.js`;
|
|
235
|
+
* 2. plain substring of the label/id (the original v1 behavior);
|
|
236
|
+
* 3. fuzzy (Damerau-Levenshtein) match against a subtoken — "sorce"
|
|
237
|
+
* still finds `scoreNodes`.
|
|
238
|
+
*
|
|
239
|
+
* Still fully lexical and deterministic — no LLM, no randomness.
|
|
240
|
+
*/
|
|
190
241
|
declare function scoreNodes(graph: Graph, query: string): NodeMatch[];
|
|
191
242
|
/**
|
|
192
243
|
* Best-effort single-node resolution: the highest-scoring lexical match,
|
|
@@ -216,8 +267,10 @@ interface QueryResult {
|
|
|
216
267
|
}
|
|
217
268
|
interface QueryOptions {
|
|
218
269
|
dfs?: boolean;
|
|
219
|
-
/**
|
|
270
|
+
/** Hard cap on how many nodes to include. Defaults to a generous ceiling derived from `tokenBudget`. */
|
|
220
271
|
budget?: number;
|
|
272
|
+
/** Approximate cap, in tokens (~4 chars each), on the serialized size of the result. Default 2000. */
|
|
273
|
+
tokenBudget?: number;
|
|
221
274
|
maxDepth?: number;
|
|
222
275
|
maxSeeds?: number;
|
|
223
276
|
}
|
|
@@ -251,6 +304,291 @@ interface ExplainResult {
|
|
|
251
304
|
/** Plain-language-ready explanation of the node that best matches `query`. */
|
|
252
305
|
declare function explainNode(graph: Graph, query: string): ExplainResult | null;
|
|
253
306
|
|
|
307
|
+
interface AffectedNode {
|
|
308
|
+
id: string;
|
|
309
|
+
label: string;
|
|
310
|
+
sourceFile: string;
|
|
311
|
+
sourceLocation: string;
|
|
312
|
+
/** 1 = depends on the target directly, 2 = one step removed, ... */
|
|
313
|
+
depth: number;
|
|
314
|
+
/** The dependency edge that pulled this node in (this node -> something already affected). */
|
|
315
|
+
via: {
|
|
316
|
+
relation: Relation;
|
|
317
|
+
confidence: Confidence;
|
|
318
|
+
/** The already-affected node this one depends on. */
|
|
319
|
+
dependsOn: string;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
interface ImpactResult {
|
|
323
|
+
target: NodeMatch;
|
|
324
|
+
affected: AffectedNode[];
|
|
325
|
+
/** How many affected nodes there are per confidence tier of the edge that pulled each one in. */
|
|
326
|
+
byConfidence: Record<Confidence, number>;
|
|
327
|
+
maxDepth: number;
|
|
328
|
+
truncated: boolean;
|
|
329
|
+
}
|
|
330
|
+
interface ImpactOptions {
|
|
331
|
+
/** How many reverse hops to follow (default 3). */
|
|
332
|
+
maxDepth?: number;
|
|
333
|
+
/** Hard cap on affected nodes reported (default 200). */
|
|
334
|
+
limit?: number;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Resolve `nodeQuery` to its best-matching node, then reverse-BFS over
|
|
338
|
+
* incoming dependency edges. Returns null when nothing in the graph matches
|
|
339
|
+
* the query at all (same contract as explainNode()).
|
|
340
|
+
*/
|
|
341
|
+
declare function affectedBy(graph: Graph, nodeQuery: string, options?: ImpactOptions): ImpactResult | null;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Cross-project graph merging — combine several already-built graphs (one
|
|
345
|
+
* per repo/project) into a single queryable global graph.
|
|
346
|
+
*
|
|
347
|
+
* Node ids inside one project are relative-path-based (`src/a.ts::foo`), so
|
|
348
|
+
* two projects' ids would collide. Every node id and sourceFile is therefore
|
|
349
|
+
* prefixed with `<project>/` — EXCEPT `module:*` (bare package imports) and
|
|
350
|
+
* `external:*` (unresolved reference targets) nodes, which deliberately stay
|
|
351
|
+
* unprefixed and shared: two repos importing the same package meet at the
|
|
352
|
+
* same node, so cross-repo bridges emerge in the merged graph instead of
|
|
353
|
+
* each repo floating as a disconnected island.
|
|
354
|
+
*/
|
|
355
|
+
interface MergeEntry {
|
|
356
|
+
/** Project name used as the id/sourceFile namespace prefix. */
|
|
357
|
+
name: string;
|
|
358
|
+
graph: Graph;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Merge the entries into one directed graph, applying the same
|
|
362
|
+
* deterministic-ordering and duplicate-edge rules as buildGraph(): entries
|
|
363
|
+
* are processed in name order, duplicate edges (possible via shared
|
|
364
|
+
* external nodes) keep the strongest confidence, and every node carries a
|
|
365
|
+
* `project` attribute (shared external nodes get `project: '(shared)'`
|
|
366
|
+
* once more than one project touches them).
|
|
367
|
+
*/
|
|
368
|
+
declare function mergeGraphs(entries: MergeEntry[]): Graph;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* MySQL schema extraction — introspect information_schema over a
|
|
372
|
+
* user-supplied DSN and map the schema onto the same ExtractionResult shape
|
|
373
|
+
* every code extractor produces, so tables/columns/foreign keys land in the
|
|
374
|
+
* same graph as the code that talks to them.
|
|
375
|
+
*
|
|
376
|
+
* Only ever surfaces the credential-free DSN rendering (see
|
|
377
|
+
* security.validateDsn()) in node attributes; the password never leaves the
|
|
378
|
+
* connection config.
|
|
379
|
+
*/
|
|
380
|
+
/** One `SELECT` against the live connection. Injectable so tests run on canned rows, mirroring security.ts's LookupFn pattern. */
|
|
381
|
+
type DsnQueryFn = (sql: string, params: ReadonlyArray<string>) => Promise<Array<Record<string, unknown>>>;
|
|
382
|
+
/**
|
|
383
|
+
* Extract the schema graph for the database named in `dsn`.
|
|
384
|
+
*
|
|
385
|
+
* Nodes: the schema, every table/view, every column.
|
|
386
|
+
* Edges: schema `contains` table, table `contains` column, FK column
|
|
387
|
+
* `references` the referenced table (EXTRACTED), view `references` its base
|
|
388
|
+
* tables (EXTRACTED via VIEW_TABLE_USAGE on MySQL >= 8.0.13, INFERRED via a
|
|
389
|
+
* VIEW_DEFINITION text match on older servers).
|
|
390
|
+
*/
|
|
391
|
+
declare function extractMysql(dsn: string, queryFn?: DsnQueryFn): Promise<ExtractionResult>;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* The graph feedback loop — `graphify save-result` logs which graph nodes
|
|
395
|
+
* actually helped answer a question (or led nowhere), and `graphify
|
|
396
|
+
* reflect` aggregates those logs into a recency-weighted LESSONS.md an
|
|
397
|
+
* agent can read at session start. This is what turns the graph from a
|
|
398
|
+
* static map into one that learns which landmarks matter.
|
|
399
|
+
*/
|
|
400
|
+
type ResultOutcome = 'useful' | 'dead_end' | 'corrected';
|
|
401
|
+
type ResultType = 'query' | 'path' | 'explain' | 'affected';
|
|
402
|
+
interface SavedResult {
|
|
403
|
+
question: string;
|
|
404
|
+
answer: string;
|
|
405
|
+
type: ResultType;
|
|
406
|
+
outcome: ResultOutcome;
|
|
407
|
+
/** Node ids/labels cited in the answer. */
|
|
408
|
+
nodes: string[];
|
|
409
|
+
/** What the right answer was — pairs with outcome 'corrected'. */
|
|
410
|
+
correction?: string;
|
|
411
|
+
savedAt: string;
|
|
412
|
+
}
|
|
413
|
+
/** Append one result to `<memoryDir>/result-<stamp>-<hash>.json`. Returns the file path. */
|
|
414
|
+
declare function saveResult(entry: Omit<SavedResult, 'savedAt'>, memoryDir: string, now?: Date): Promise<string>;
|
|
415
|
+
interface ReflectOptions {
|
|
416
|
+
/** A result's weight halves every this many days (default 30). */
|
|
417
|
+
halfLifeDays?: number;
|
|
418
|
+
/** Injectable clock for deterministic tests. */
|
|
419
|
+
now?: Date;
|
|
420
|
+
/** Only list nodes cited usefully at least this many distinct times (default 2). */
|
|
421
|
+
minCorroboration?: number;
|
|
422
|
+
}
|
|
423
|
+
/** Read every result JSON under `memoryDir` (missing dir = no results). */
|
|
424
|
+
declare function loadResults(memoryDir: string): Promise<SavedResult[]>;
|
|
425
|
+
/** Aggregate saved results into a LESSONS.md string. Deterministic given results + options.now. */
|
|
426
|
+
declare function renderLessons(results: SavedResult[], options?: ReflectOptions): string;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* `graphify context` — the working-set pack. Instead of returning node
|
|
430
|
+
* names for the agent to chase (query -> then read whole files anyway),
|
|
431
|
+
* this fuses the two steps: the graph knows every entity's file and line,
|
|
432
|
+
* so rank the nodes relevant to the task, read just the relevant line
|
|
433
|
+
* ranges, and pack the actual code into a token budget. One call returns
|
|
434
|
+
* the code an agent needs to start a task.
|
|
435
|
+
*/
|
|
436
|
+
interface ContextSnippet {
|
|
437
|
+
nodeId: string;
|
|
438
|
+
label: string;
|
|
439
|
+
file: string;
|
|
440
|
+
startLine: number;
|
|
441
|
+
endLine: number;
|
|
442
|
+
code: string;
|
|
443
|
+
/** Why this snippet is in the pack (lexical match / neighbor-of relation). */
|
|
444
|
+
reason: string;
|
|
445
|
+
score: number;
|
|
446
|
+
}
|
|
447
|
+
interface ContextPack {
|
|
448
|
+
task: string;
|
|
449
|
+
snippets: ContextSnippet[];
|
|
450
|
+
/** Approximate tokens used out of the budget. */
|
|
451
|
+
tokens: number;
|
|
452
|
+
tokenBudget: number;
|
|
453
|
+
/** Ranked nodes that didn't fit the budget — the agent can pull them explicitly. */
|
|
454
|
+
overflow: Array<{
|
|
455
|
+
nodeId: string;
|
|
456
|
+
file: string;
|
|
457
|
+
}>;
|
|
458
|
+
}
|
|
459
|
+
interface ContextOptions {
|
|
460
|
+
/** Approximate token cap for the pack (default 4000). */
|
|
461
|
+
tokenBudget?: number;
|
|
462
|
+
maxSeeds?: number;
|
|
463
|
+
/** Cap on snippet length in lines (default 60). */
|
|
464
|
+
maxSnippetLines?: number;
|
|
465
|
+
}
|
|
466
|
+
type FileReader = (path: string) => Promise<string>;
|
|
467
|
+
interface RankedNode {
|
|
468
|
+
id: string;
|
|
469
|
+
score: number;
|
|
470
|
+
reason: string;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Rank nodes for the task: lexical seeds first (their match score), then
|
|
474
|
+
* their graph neighbors at a decayed score, labeled with the relation that
|
|
475
|
+
* connects them. Deterministic (score desc, id asc).
|
|
476
|
+
*/
|
|
477
|
+
declare function rankForTask(graph: Graph, task: string, maxSeeds?: number): RankedNode[];
|
|
478
|
+
declare function buildContextPack(graph: Graph, task: string, readFile: FileReader, options?: ContextOptions): Promise<ContextPack>;
|
|
479
|
+
/** Render a pack as agent-ready markdown. */
|
|
480
|
+
declare function renderContextPack(pack: ContextPack): string;
|
|
481
|
+
|
|
482
|
+
declare function isTestFile(path: string): boolean;
|
|
483
|
+
interface TestSelection {
|
|
484
|
+
/** What the selection was computed for (resolved node id, or the changed files). */
|
|
485
|
+
target: string;
|
|
486
|
+
/** Unique test files, most directly affected first. */
|
|
487
|
+
testFiles: Array<{
|
|
488
|
+
file: string;
|
|
489
|
+
depth: number;
|
|
490
|
+
via: string;
|
|
491
|
+
}>;
|
|
492
|
+
/** How many non-test nodes were in the blast radius (context for confidence). */
|
|
493
|
+
affectedNodeCount: number;
|
|
494
|
+
}
|
|
495
|
+
/** Test files reachable (reverse) from the node best matching `nodeQuery`. Null if nothing matches. */
|
|
496
|
+
declare function testsForNode(graph: Graph, nodeQuery: string): TestSelection | null;
|
|
497
|
+
/**
|
|
498
|
+
* Test files reachable from any of the given changed files (as reported by
|
|
499
|
+
* `git diff --name-only`). Changed test files select themselves. Unknown
|
|
500
|
+
* files (not in the graph) are skipped.
|
|
501
|
+
*/
|
|
502
|
+
declare function testsForChangedFiles(graph: Graph, changedFiles: string[]): TestSelection;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* `graphify review` — semantic graph diff between two git revisions.
|
|
506
|
+
* Full structural extraction is sub-second, so instead of parsing text
|
|
507
|
+
* diffs we build the graph at both revs and diff the graphs: which symbols
|
|
508
|
+
* appeared, disappeared, or got rewired — each with its blast radius and
|
|
509
|
+
* the test files worth running. One command answers both "what changed
|
|
510
|
+
* since I was last here" and "review this PR structurally".
|
|
511
|
+
*/
|
|
512
|
+
interface ChangedSymbol {
|
|
513
|
+
id: string;
|
|
514
|
+
label: string;
|
|
515
|
+
sourceFile: string;
|
|
516
|
+
/** Everything that depends on this symbol (computed in the graph where it exists). */
|
|
517
|
+
blastRadius: number;
|
|
518
|
+
/** Test files reachable from it. */
|
|
519
|
+
tests: string[];
|
|
520
|
+
}
|
|
521
|
+
interface RewiredSymbol extends ChangedSymbol {
|
|
522
|
+
gainedEdges: string[];
|
|
523
|
+
lostEdges: string[];
|
|
524
|
+
}
|
|
525
|
+
interface GraphDiff {
|
|
526
|
+
base: string;
|
|
527
|
+
head: string;
|
|
528
|
+
added: ChangedSymbol[];
|
|
529
|
+
removed: ChangedSymbol[];
|
|
530
|
+
rewired: RewiredSymbol[];
|
|
531
|
+
}
|
|
532
|
+
/** Extract a graph from a directory without exporting anything. */
|
|
533
|
+
declare function graphForDirectory(root: string): Promise<Graph>;
|
|
534
|
+
declare function diffGraphs(baseGraph: Graph, headGraph: Graph, base: string, head: string): GraphDiff;
|
|
535
|
+
/** Diff two revisions of the repo at `repoRoot`. `head` defaults to the working head via a second archive of HEAD. */
|
|
536
|
+
declare function reviewRevisions(repoRoot: string, base: string, head?: string): Promise<GraphDiff>;
|
|
537
|
+
declare function renderReview(diff: GraphDiff): string;
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* `graphify check` — architecture guardrails. Declarative dependency rules
|
|
541
|
+
* checked against the graph's edges, with CI-friendly results: an agent (or
|
|
542
|
+
* a pipeline) can verify an edit didn't violate the architecture before it
|
|
543
|
+
* lands. Cross-language, because the graph already is.
|
|
544
|
+
*/
|
|
545
|
+
interface DependencyRule {
|
|
546
|
+
/** Short rule name shown in violations. */
|
|
547
|
+
name: string;
|
|
548
|
+
/** Glob over the depending file (edge source's sourceFile). */
|
|
549
|
+
from: string;
|
|
550
|
+
/** Globs the dependency target's file must NOT match. */
|
|
551
|
+
disallow: string[];
|
|
552
|
+
/** Optional human explanation echoed with violations. */
|
|
553
|
+
reason?: string;
|
|
554
|
+
}
|
|
555
|
+
interface RulesConfig {
|
|
556
|
+
rules: DependencyRule[];
|
|
557
|
+
}
|
|
558
|
+
interface Violation {
|
|
559
|
+
rule: string;
|
|
560
|
+
reason?: string;
|
|
561
|
+
fromFile: string;
|
|
562
|
+
fromNode: string;
|
|
563
|
+
toFile: string;
|
|
564
|
+
toNode: string;
|
|
565
|
+
relation: string;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Minimal glob: `**` crosses directories, `*` stays within one segment.
|
|
569
|
+
* Anchored on both ends. Enough for path rules without a dependency.
|
|
570
|
+
*/
|
|
571
|
+
declare function globToRegExp(glob: string): RegExp;
|
|
572
|
+
declare function validateRules(value: unknown): RulesConfig;
|
|
573
|
+
/** Check every dependency edge in the graph against the rules. Deterministic ordering. */
|
|
574
|
+
declare function checkRules(graph: Graph, config: RulesConfig): Violation[];
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Per-file extraction cache — what makes `--update` (and every rebuild
|
|
578
|
+
* behind a git hook or --watch) incremental. Entries are keyed by a hash of
|
|
579
|
+
* the file's CONTENT plus its root-relative path: content because that's
|
|
580
|
+
* what extraction depends on, path because node ids embed it. A stale entry
|
|
581
|
+
* for content that changed simply never matches again; the whole directory
|
|
582
|
+
* can always be deleted safely.
|
|
583
|
+
*/
|
|
584
|
+
declare class ExtractionCache {
|
|
585
|
+
private readonly dir;
|
|
586
|
+
constructor(outDir: string);
|
|
587
|
+
key(relFile: string, content: Buffer | string): string;
|
|
588
|
+
get(key: string): Promise<ExtractionResult | null>;
|
|
589
|
+
put(key: string, extraction: ExtractionResult): Promise<void>;
|
|
590
|
+
}
|
|
591
|
+
|
|
254
592
|
declare const ExtractionResultSchema: z.ZodObject<{
|
|
255
593
|
nodes: z.ZodArray<z.ZodObject<{
|
|
256
594
|
id: z.ZodString;
|
|
@@ -298,4 +636,4 @@ declare class ExtractionValidationError extends Error {
|
|
|
298
636
|
*/
|
|
299
637
|
declare function validateExtraction(value: unknown, context?: string): ExtractionResult;
|
|
300
638
|
|
|
301
|
-
export { type Analysis, type ClusterAlgorithm, type ClusterOptions, type Confidence, EXTRACTOR_REGISTRY, type ExplainResult, type ExportOptions, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphEdge, type GraphNode, type NodeMatch, type PathResult, type PipelineOptions, type PipelineResult, type QueryOptions, type QueryResult, type Relation, type TraversalEdge, type VisitedNode, analyze, buildGraph, cluster, collectFiles, explainNode, exportGraph, extract, loadGraph, queryGraph, renderReport, resolveNode, runPipeline, scoreNodes, shortestPath, validateExtraction };
|
|
639
|
+
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 ExplainResult, type ExportOptions, ExtractionCache, type ExtractionResult, ExtractionResultSchema, ExtractionValidationError, type ExtractionValidationIssue, type FileCategory, type FileManifest, type GraphDiff, type GraphEdge, type GraphNode, type ImpactOptions, type ImpactResult, 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 RewiredSymbol, type RulesConfig, type SavedResult, type TestSelection, type TraversalEdge, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, diffGraphs, explainNode, exportGraph, extract, extractMysql, globToRegExp, graphForDirectory, isTestFile, loadGraph, loadResults, mergeGraphs, queryGraph, rankForTask, renderContextPack, renderLessons, renderReport, renderReview, resolveCrossFileReferences, resolveNode, reviewRevisions, runPipeline, saveResult, scoreNodes, shortestPath, testsForChangedFiles, testsForNode, validateExtraction, validateRules };
|