@dreamtree-org/graphify 1.1.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -172,6 +172,30 @@ declare function renderReport(graph: Graph, analysis: Analysis, now?: Date): str
172
172
  */
173
173
  declare function exportGraph(graph: Graph, options: ExportOptions, report?: string): Promise<void>;
174
174
 
175
+ /**
176
+ * Graphology's node-link JSON — exactly the shape `graph.json` has always
177
+ * contained, derived from Graph#export() rather than imported from
178
+ * graphology-types so consumers of our .d.ts don't need that package.
179
+ */
180
+ type SerializedGraph = ReturnType<Graph['export']>;
181
+ /**
182
+ * Where a graph lives between runs. Graphify defines the interface and
183
+ * ships LocalFileGraphStore (the classic graphify-out/ behavior); callers
184
+ * that persist graphs elsewhere — a DB row, an object-store key, anything
185
+ * that can hold JSON — implement it over their own storage with
186
+ * serializeGraph()/deserializeGraph(). Graphify never instantiates a
187
+ * remote store itself (see docs/KB-PROVIDER.md).
188
+ *
189
+ * `ref` is an opaque caller-defined locator. For LocalFileGraphStore it is
190
+ * an outDir path; for a provider it is whatever routes to one graph, e.g.
191
+ * `${companyId}/${knowledgeBaseId}`.
192
+ */
193
+ interface GraphStore {
194
+ /** Resolves null when no graph exists yet at `ref` — not an error. */
195
+ load(ref: string): Promise<Graph | null>;
196
+ save(ref: string, graph: Graph): Promise<void>;
197
+ }
198
+
175
199
  interface PipelineOptions {
176
200
  /** Where to write graph.json/graph.html/GRAPH_REPORT.md. Defaults to `<root>/graphify-out`. */
177
201
  outDir?: string;
@@ -197,6 +221,13 @@ interface PipelineOptions {
197
221
  update?: boolean;
198
222
  /** Called with a short progress message after each stage (e.g. for CLI stderr output). */
199
223
  onProgress?: (message: string) => void;
224
+ /**
225
+ * Also save the built graph through a caller-supplied GraphStore (e.g. a
226
+ * DB-backed store — see docs/KB-PROVIDER.md), in addition to the regular
227
+ * graphify-out/ export. Keyed by `storeRef` (defaults to the outDir path).
228
+ */
229
+ store?: GraphStore;
230
+ storeRef?: string;
200
231
  }
201
232
  interface PipelineResult {
202
233
  manifest: FileManifest;
@@ -215,12 +246,35 @@ declare function runPipeline(root: string, options?: PipelineOptions): Promise<P
215
246
 
216
247
  /**
217
248
  * Load a previously-exported graph.json back into a graphology Graph.
218
- * Always goes through security.validateGraphPath() (path-traversal guard —
219
- * see SECURITY.md) so a caller-supplied `outDir`/CLI arg can never make
220
- * this read outside the graphify-out/ directory it resolves to.
249
+ * Thin wrapper over LocalFileGraphStore (which enforces the path-traversal
250
+ * guard — see SECURITY.md) that throws when no graph exists, because every
251
+ * CLI/MCP caller treats "no graph yet" as a hard error. Library callers who
252
+ * want the null-on-missing contract should use a GraphStore directly.
221
253
  */
222
254
  declare function loadGraph(outDir?: string): Promise<Graph>;
223
255
 
256
+ /**
257
+ * The reference GraphStore: one graph.json per directory, `ref` = the
258
+ * outDir path. Reproduces the classic graphify-out/ behavior byte-for-byte
259
+ * (same pretty-printed JSON exportGraph() writes) and routes every path
260
+ * through security.validateGraphPath(), so a caller-supplied ref — or a
261
+ * symlinked graph.json — can never read or write outside the directory it
262
+ * resolves to.
263
+ */
264
+ declare class LocalFileGraphStore implements GraphStore {
265
+ load(ref: string): Promise<Graph | null>;
266
+ save(ref: string, graph: Graph): Promise<void>;
267
+ }
268
+
269
+ /**
270
+ * The stable serialization contract for graphs at rest: graphology's
271
+ * node-link JSON. exportGraph() has always written exactly this shape to
272
+ * graph.json, so anything serialized here stays loadable by every existing
273
+ * consumer (and vice versa).
274
+ */
275
+ declare function serializeGraph(graph: Graph): SerializedGraph;
276
+ declare function deserializeGraph(data: SerializedGraph): Graph;
277
+
224
278
  interface NodeMatch {
225
279
  id: string;
226
280
  label: string;
@@ -651,4 +705,4 @@ declare class ExtractionValidationError extends Error {
651
705
  */
652
706
  declare function validateExtraction(value: unknown, context?: string): ExtractionResult;
653
707
 
654
- 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 };
708
+ 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 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 RewiredSymbol, type RulesConfig, type SavedResult, type SerializedGraph, type TestSelection, type TraversalEdge, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, 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 };
package/dist/index.d.ts CHANGED
@@ -172,6 +172,30 @@ declare function renderReport(graph: Graph, analysis: Analysis, now?: Date): str
172
172
  */
173
173
  declare function exportGraph(graph: Graph, options: ExportOptions, report?: string): Promise<void>;
174
174
 
175
+ /**
176
+ * Graphology's node-link JSON — exactly the shape `graph.json` has always
177
+ * contained, derived from Graph#export() rather than imported from
178
+ * graphology-types so consumers of our .d.ts don't need that package.
179
+ */
180
+ type SerializedGraph = ReturnType<Graph['export']>;
181
+ /**
182
+ * Where a graph lives between runs. Graphify defines the interface and
183
+ * ships LocalFileGraphStore (the classic graphify-out/ behavior); callers
184
+ * that persist graphs elsewhere — a DB row, an object-store key, anything
185
+ * that can hold JSON — implement it over their own storage with
186
+ * serializeGraph()/deserializeGraph(). Graphify never instantiates a
187
+ * remote store itself (see docs/KB-PROVIDER.md).
188
+ *
189
+ * `ref` is an opaque caller-defined locator. For LocalFileGraphStore it is
190
+ * an outDir path; for a provider it is whatever routes to one graph, e.g.
191
+ * `${companyId}/${knowledgeBaseId}`.
192
+ */
193
+ interface GraphStore {
194
+ /** Resolves null when no graph exists yet at `ref` — not an error. */
195
+ load(ref: string): Promise<Graph | null>;
196
+ save(ref: string, graph: Graph): Promise<void>;
197
+ }
198
+
175
199
  interface PipelineOptions {
176
200
  /** Where to write graph.json/graph.html/GRAPH_REPORT.md. Defaults to `<root>/graphify-out`. */
177
201
  outDir?: string;
@@ -197,6 +221,13 @@ interface PipelineOptions {
197
221
  update?: boolean;
198
222
  /** Called with a short progress message after each stage (e.g. for CLI stderr output). */
199
223
  onProgress?: (message: string) => void;
224
+ /**
225
+ * Also save the built graph through a caller-supplied GraphStore (e.g. a
226
+ * DB-backed store — see docs/KB-PROVIDER.md), in addition to the regular
227
+ * graphify-out/ export. Keyed by `storeRef` (defaults to the outDir path).
228
+ */
229
+ store?: GraphStore;
230
+ storeRef?: string;
200
231
  }
201
232
  interface PipelineResult {
202
233
  manifest: FileManifest;
@@ -215,12 +246,35 @@ declare function runPipeline(root: string, options?: PipelineOptions): Promise<P
215
246
 
216
247
  /**
217
248
  * Load a previously-exported graph.json back into a graphology Graph.
218
- * Always goes through security.validateGraphPath() (path-traversal guard —
219
- * see SECURITY.md) so a caller-supplied `outDir`/CLI arg can never make
220
- * this read outside the graphify-out/ directory it resolves to.
249
+ * Thin wrapper over LocalFileGraphStore (which enforces the path-traversal
250
+ * guard — see SECURITY.md) that throws when no graph exists, because every
251
+ * CLI/MCP caller treats "no graph yet" as a hard error. Library callers who
252
+ * want the null-on-missing contract should use a GraphStore directly.
221
253
  */
222
254
  declare function loadGraph(outDir?: string): Promise<Graph>;
223
255
 
256
+ /**
257
+ * The reference GraphStore: one graph.json per directory, `ref` = the
258
+ * outDir path. Reproduces the classic graphify-out/ behavior byte-for-byte
259
+ * (same pretty-printed JSON exportGraph() writes) and routes every path
260
+ * through security.validateGraphPath(), so a caller-supplied ref — or a
261
+ * symlinked graph.json — can never read or write outside the directory it
262
+ * resolves to.
263
+ */
264
+ declare class LocalFileGraphStore implements GraphStore {
265
+ load(ref: string): Promise<Graph | null>;
266
+ save(ref: string, graph: Graph): Promise<void>;
267
+ }
268
+
269
+ /**
270
+ * The stable serialization contract for graphs at rest: graphology's
271
+ * node-link JSON. exportGraph() has always written exactly this shape to
272
+ * graph.json, so anything serialized here stays loadable by every existing
273
+ * consumer (and vice versa).
274
+ */
275
+ declare function serializeGraph(graph: Graph): SerializedGraph;
276
+ declare function deserializeGraph(data: SerializedGraph): Graph;
277
+
224
278
  interface NodeMatch {
225
279
  id: string;
226
280
  label: string;
@@ -651,4 +705,4 @@ declare class ExtractionValidationError extends Error {
651
705
  */
652
706
  declare function validateExtraction(value: unknown, context?: string): ExtractionResult;
653
707
 
654
- 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 };
708
+ 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 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 RewiredSymbol, type RulesConfig, type SavedResult, type SerializedGraph, type TestSelection, type TraversalEdge, type Violation, type VisitedNode, affectedBy, analyze, buildContextPack, buildGraph, checkRules, cluster, collectFiles, deserializeGraph, diffGraphs, 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 };
package/dist/index.js CHANGED
@@ -24,10 +24,12 @@ import {
24
24
  saveResult,
25
25
  validateExtraction,
26
26
  validateRules
27
- } from "./chunk-NS5HB65S.js";
27
+ } from "./chunk-UBXYMMXJ.js";
28
28
  import {
29
+ LocalFileGraphStore,
29
30
  affectedBy,
30
31
  buildContextPack,
32
+ deserializeGraph,
31
33
  explainNode,
32
34
  isTestFile,
33
35
  loadGraph,
@@ -36,10 +38,11 @@ import {
36
38
  renderContextPack,
37
39
  resolveNode,
38
40
  scoreNodes,
41
+ serializeGraph,
39
42
  shortestPath,
40
43
  testsForChangedFiles,
41
44
  testsForNode
42
- } from "./chunk-ZK3TA6FW.js";
45
+ } from "./chunk-K322XB4U.js";
43
46
  import {
44
47
  extractMysql
45
48
  } from "./chunk-ZPB37LLQ.js";
@@ -49,6 +52,7 @@ export {
49
52
  ExtractionCache,
50
53
  ExtractionResultSchema,
51
54
  ExtractionValidationError,
55
+ LocalFileGraphStore,
52
56
  affectedBy,
53
57
  analyze,
54
58
  buildContextPack,
@@ -56,6 +60,7 @@ export {
56
60
  checkRules,
57
61
  cluster,
58
62
  collectFiles,
63
+ deserializeGraph,
59
64
  diffGraphs,
60
65
  explainNode,
61
66
  exportGraph,
@@ -79,6 +84,7 @@ export {
79
84
  runPipeline,
80
85
  saveResult,
81
86
  scoreNodes,
87
+ serializeGraph,
82
88
  shortestPath,
83
89
  testsForChangedFiles,
84
90
  testsForNode,
@@ -442,9 +442,10 @@ function renderContextPack(pack) {
442
442
  }
443
443
 
444
444
  // src/graphStore.ts
445
- var fs2 = __toESM(require("fs/promises"), 1);
446
445
  var path = __toESM(require("path"), 1);
447
- var import_graphology = __toESM(require("graphology"), 1);
446
+
447
+ // src/store/localFile.ts
448
+ var fs2 = __toESM(require("fs/promises"), 1);
448
449
 
449
450
  // src/security.ts
450
451
  var import_node_crypto = require("crypto");
@@ -479,12 +480,48 @@ function validateGraphPath(path3, base) {
479
480
  return realCandidate;
480
481
  }
481
482
 
483
+ // src/store/serialize.ts
484
+ var import_graphology = __toESM(require("graphology"), 1);
485
+ function serializeGraph(graph) {
486
+ return graph.export();
487
+ }
488
+ function deserializeGraph(data) {
489
+ return import_graphology.default.from(data);
490
+ }
491
+
492
+ // src/store/localFile.ts
493
+ var LocalFileGraphStore = class {
494
+ async load(ref) {
495
+ let jsonPath;
496
+ try {
497
+ jsonPath = validateGraphPath("graph.json", ref);
498
+ } catch (error) {
499
+ if (error.message.startsWith("Base directory does not exist")) return null;
500
+ throw error;
501
+ }
502
+ let raw;
503
+ try {
504
+ raw = await fs2.readFile(jsonPath, "utf-8");
505
+ } catch (error) {
506
+ if (error.code === "ENOENT") return null;
507
+ throw error;
508
+ }
509
+ return deserializeGraph(JSON.parse(raw));
510
+ }
511
+ async save(ref, graph) {
512
+ await fs2.mkdir(ref, { recursive: true });
513
+ const jsonPath = validateGraphPath("graph.json", ref);
514
+ await fs2.writeFile(jsonPath, JSON.stringify(serializeGraph(graph), null, 2), "utf-8");
515
+ }
516
+ };
517
+
482
518
  // src/graphStore.ts
483
519
  async function loadGraph(outDir = path.join(process.cwd(), "graphify-out")) {
484
- const jsonPath = validateGraphPath("graph.json", outDir);
485
- const raw = await fs2.readFile(jsonPath, "utf-8");
486
- const data = JSON.parse(raw);
487
- return import_graphology.default.from(data);
520
+ const graph = await new LocalFileGraphStore().load(outDir);
521
+ if (graph === null) {
522
+ throw new Error(`No graph found in ${outDir} \u2014 run \`graphify <path>\` to build one first.`);
523
+ }
524
+ return graph;
488
525
  }
489
526
 
490
527
  // src/impact.ts