@vibgrate/cli 2026.702.1 → 2026.703.1

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.
Files changed (70) hide show
  1. package/DOCS.md +521 -146
  2. package/LICENSE +202 -0
  3. package/NOTICE +40 -0
  4. package/README.md +232 -250
  5. package/dist/baseline-D2T3V76P.js +6 -0
  6. package/dist/baseline-D2T3V76P.js.map +1 -0
  7. package/dist/chunk-4M2MUQRO.js +800 -0
  8. package/dist/chunk-4M2MUQRO.js.map +1 -0
  9. package/dist/chunk-E7Q3P6V7.js +6267 -0
  10. package/dist/chunk-E7Q3P6V7.js.map +1 -0
  11. package/dist/chunk-ROWQLHEX.js +31 -0
  12. package/dist/chunk-ROWQLHEX.js.map +1 -0
  13. package/dist/chunk-RXP66R2E.js +39 -0
  14. package/dist/chunk-RXP66R2E.js.map +1 -0
  15. package/dist/chunk-TVPE5CA2.js +11389 -0
  16. package/dist/chunk-TVPE5CA2.js.map +1 -0
  17. package/dist/chunk-X5YT263H.js +912 -0
  18. package/dist/chunk-X5YT263H.js.map +1 -0
  19. package/dist/cli.d.ts +44 -1
  20. package/dist/cli.js +3816 -165
  21. package/dist/cli.js.map +1 -0
  22. package/dist/fs-7KZ4F3SB.js +3 -0
  23. package/dist/fs-7KZ4F3SB.js.map +1 -0
  24. package/dist/index.d.ts +1010 -1
  25. package/dist/index.js +42 -1
  26. package/dist/index.js.map +1 -0
  27. package/dist/parse-worker.d.ts +23 -0
  28. package/dist/parse-worker.js +32 -0
  29. package/dist/parse-worker.js.map +1 -0
  30. package/dist/types-C6ZyQpa9.d.ts +168 -0
  31. package/grammars/tree-sitter-bash.wasm +0 -0
  32. package/grammars/tree-sitter-c.wasm +0 -0
  33. package/grammars/tree-sitter-c_sharp.wasm +0 -0
  34. package/grammars/tree-sitter-cpp.wasm +0 -0
  35. package/grammars/tree-sitter-dart.wasm +0 -0
  36. package/grammars/tree-sitter-elixir.wasm +0 -0
  37. package/grammars/tree-sitter-go.wasm +0 -0
  38. package/grammars/tree-sitter-java.wasm +0 -0
  39. package/grammars/tree-sitter-javascript.wasm +0 -0
  40. package/grammars/tree-sitter-kotlin.wasm +0 -0
  41. package/grammars/tree-sitter-lua.wasm +0 -0
  42. package/grammars/tree-sitter-php.wasm +0 -0
  43. package/grammars/tree-sitter-python.wasm +0 -0
  44. package/grammars/tree-sitter-ruby.wasm +0 -0
  45. package/grammars/tree-sitter-rust.wasm +0 -0
  46. package/grammars/tree-sitter-scala.wasm +0 -0
  47. package/grammars/tree-sitter-swift.wasm +0 -0
  48. package/grammars/tree-sitter-tsx.wasm +0 -0
  49. package/grammars/tree-sitter-typescript.wasm +0 -0
  50. package/grammars/tree-sitter-zig.wasm +0 -0
  51. package/package.json +68 -33
  52. package/scripts/postinstall.mjs +84 -0
  53. package/skills/README.md +58 -0
  54. package/skills/vg/SKILL.md +42 -0
  55. package/HCS-RUNTIME-SETUP.md +0 -73
  56. package/LICENSE.md +0 -45
  57. package/dist/baseline-TJDKYSFL.js +0 -1
  58. package/dist/chunk-EK7ODJWE.js +0 -1
  59. package/dist/chunk-GGDB72YE.js +0 -323
  60. package/dist/chunk-MKDRULJ6.js +0 -1
  61. package/dist/chunk-NGFYX3CW.js +0 -2
  62. package/dist/chunk-OQSVJXWJ.js +0 -143
  63. package/dist/chunk-XTHPCEME.js +0 -2
  64. package/dist/dist-5D3BKCOR.js +0 -1
  65. package/dist/fs-PXXYZATK-ZP2RBR47.js +0 -1
  66. package/dist/hcs-wasm/package.json +0 -3
  67. package/dist/hcs-wasm/vibgrate_hcs_wasm.js +0 -450
  68. package/dist/hcs-wasm/vibgrate_hcs_wasm_bg.wasm +0 -0
  69. package/dist/hcs-worker.js +0 -374406
  70. package/dist/semver-TPPMM2NV.js +0 -1
package/dist/index.d.ts CHANGED
@@ -1 +1,1010 @@
1
- export { DependencyRow, DriftScore, Finding, ProjectScan, RiskLevel, ScanArtifact, ScanOptions, VibgrateConfig, computeDriftScore, formatMarkdown, formatSarif, formatText, generateFindings, runScan } from '@vibgrate/core';
1
+ import { G as GraphNode, a as GraphEdge, A as Area, R as ResolverKind, V as VgGraph, F as FileParse, E as EdgeKind, b as Fact, c as GroundingKind, d as GroundingEdge } from './types-C6ZyQpa9.js';
2
+ export { C as Centrality, D as DerivedBy, e as FactConfidence, f as FactKind, g as GraphMeta, N as NodeKind, P as Provenance, S as SCHEMA_VERSION, h as Span } from './types-C6ZyQpa9.js';
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+
5
+ declare const VERSION = "2026.703.1";
6
+
7
+ /**
8
+ * Analysis stage: importance, centrality, hubs, communities, and surprise.
9
+ *
10
+ * - **Centrality** blends PageRank + betweenness + eigenvector + degree over the
11
+ * dependency graph (call/import/extends/implements/references), catching
12
+ * high-fan-in critical nodes that degree-only ranking (Graphify) misses.
13
+ * - **Communities** via Louvain (`graphology-communities-louvain`, MIT), seeded
14
+ * and single-pass for determinism. Leiden (via a permissive WASM impl) is a
15
+ * later enhancement; the cluster mode is reported honestly, never silent.
16
+ * - **Hubs** are centrality outliers (importance ≥ mean + 2σ).
17
+ * - **Surprise** flags improbable cross-area edges (architectural smells),
18
+ * surfaced by `vg oddities`.
19
+ *
20
+ * Pure and deterministic: identical (nodes, edges) → identical result.
21
+ */
22
+ type ClusterMode = 'leiden' | 'louvain' | 'none';
23
+ interface AnalyzeOptions {
24
+ cluster?: ClusterMode;
25
+ /** Skip betweenness above this node count (O(V·E) — too slow for huge graphs). */
26
+ betweennessLimit?: number;
27
+ }
28
+ interface AnalyzeResult {
29
+ nodes: GraphNode[];
30
+ edges: GraphEdge[];
31
+ areas: Area[];
32
+ cluster: ClusterMode;
33
+ }
34
+ declare function analyze(nodes: GraphNode[], edges: GraphEdge[], options?: AnalyzeOptions): AnalyzeResult;
35
+
36
+ /**
37
+ * Module resolution for import edges. Resolves an import specifier (relative,
38
+ * `tsconfig` path alias, or workspace-package name) to a repo-relative file —
39
+ * the fix for alias-heavy TS monorepos (Nx/Turborepo) where every cross-package
40
+ * import looked "external" and tanked call resolution.
41
+ *
42
+ * Deterministic: it reads the repo's tsconfig(s) and workspace manifests once at
43
+ * construction, then `resolve()` is pure over those in-memory maps. Still the
44
+ * heuristic rung — precise SCIP/stack-graphs slot above it later — but now
45
+ * scope-aware of the project's own module map.
46
+ */
47
+ interface ModuleResolver {
48
+ /** Resolve `source` imported from `fromRel`; returns a repo-rel path or null (external). */
49
+ resolve(fromRel: string, source: string): string | null;
50
+ }
51
+ declare function buildModuleResolver(root: string, relSet: Set<string>): ModuleResolver;
52
+ /** A resolver that only handles relative imports (no fs) — for tests/embedding. */
53
+ declare function relativeResolver(relSet: Set<string>): ModuleResolver;
54
+ declare function parseJsonc<T = unknown>(text: string): T;
55
+
56
+ /**
57
+ * Resolution: turn per-file symbol/edge tables into a connected graph of nodes
58
+ * and typed, id'd edges.
59
+ *
60
+ * The Phase-0 resolver is the deterministic **heuristic** rung of the ladder
61
+ * (VG-ENGINE-TEARDOWN §3.2). It is already well beyond Graphify's
62
+ * single-candidate label match: it is scope-aware (same-file first), import-aware
63
+ * (callees reachable through imported files next), and arity/visibility-honest
64
+ * (records its confidence and resolution rung per edge rather than silently
65
+ * dropping ambiguity). SCIP/stack-graphs rungs slot in above it later, recorded
66
+ * via `edge.resolution`.
67
+ */
68
+ interface ResolveResult {
69
+ nodes: GraphNode[];
70
+ edges: GraphEdge[];
71
+ /** Diagnostic counts, surfaced by `vg status`. */
72
+ stats: {
73
+ callsResolved: number;
74
+ callsUnresolved: number;
75
+ importsResolvedToFile: number;
76
+ importsExternal: number;
77
+ resolvers: ResolverKind[];
78
+ };
79
+ }
80
+
81
+ interface BuildOptions {
82
+ /** Directory to build (default cwd). */
83
+ root: string;
84
+ /** Restrict to language ids. */
85
+ only?: string[];
86
+ /** Extra ignore globs (gitignore syntax). */
87
+ exclude?: string[];
88
+ /** Sub-paths to scope to. */
89
+ paths?: string[];
90
+ /** Worker count; 1 forces inline. */
91
+ jobs?: number;
92
+ /** Force single-threaded parsing. */
93
+ inline?: boolean;
94
+ /** Disable the incremental cache (full rebuild). */
95
+ noCache?: boolean;
96
+ /** Heavier open passes (recorded in provenance; Phase 1+ wires the analyses). */
97
+ deep?: boolean;
98
+ /** Community detection mode (default 'louvain'). */
99
+ cluster?: ClusterMode;
100
+ /** Coverage report paths (default: auto-detect lcov/istanbul). */
101
+ coverage?: string[];
102
+ /** Skip coverage ingestion. */
103
+ noCoverage?: boolean;
104
+ /** Skip grounding (free knowledge pack). Default: grounding on. */
105
+ noGround?: boolean;
106
+ /** Path to a SCIP index to ingest (default: auto-detect index.scip). */
107
+ scip?: string;
108
+ /** Skip SCIP ingestion even if an index is present. */
109
+ noScip?: boolean;
110
+ /** Skip the in-process TypeScript Compiler API resolver (heuristic floor only). */
111
+ noTsc?: boolean;
112
+ /** Pin the artifact timestamp for byte-deterministic output. */
113
+ generatedAt?: string;
114
+ /** Live progress during the parse phase (files done of total). */
115
+ onParseProgress?: (done: number, total: number) => void;
116
+ /** Override directory for grammar .wasm files (offline / air-gapped). */
117
+ grammarsDir?: string;
118
+ }
119
+ /** Stat + content hash of one corpus file at build time. */
120
+ interface FileStat {
121
+ rel: string;
122
+ size: number;
123
+ mtimeMs: number;
124
+ hash: string;
125
+ }
126
+ interface BuildResult {
127
+ graph: VgGraph;
128
+ timing: {
129
+ totalMs: number;
130
+ };
131
+ reparsed: number;
132
+ reused: number;
133
+ totalFiles: number;
134
+ /** Stat+hash of every file in the corpus — input for the freshness snapshot. */
135
+ fileStats: FileStat[];
136
+ resolveStats: ResolveResult['stats'];
137
+ /** Present when the TypeScript Compiler API resolver ran (TS/JS files). */
138
+ tsc?: {
139
+ files: number;
140
+ calls: number;
141
+ jsx: number;
142
+ heritage: number;
143
+ resolved: number;
144
+ };
145
+ /** Present when a SCIP index was ingested. */
146
+ scip?: {
147
+ documents: number;
148
+ references: number;
149
+ resolved: number;
150
+ tool?: string;
151
+ };
152
+ warnings: string[];
153
+ }
154
+ declare function buildGraph(options: BuildOptions): Promise<BuildResult>;
155
+
156
+ /** Load a committed `graph.json`. Returns null if none exists at the path. */
157
+ declare function loadGraph(root: string, graphPath?: string): VgGraph | null;
158
+
159
+ /**
160
+ * Deterministic serialization of `graph.json`.
161
+ *
162
+ * Object keys are sorted recursively and arrays are emitted in the (already
163
+ * stable) order the engine produced them, so two runs over identical content
164
+ * yield byte-identical output — the determinism contract (VG-CLI-SPEC §1.3).
165
+ * Pretty-printed (2-space) and newline-terminated so the committed artifact is
166
+ * human-diffable and plays well with the union merge driver.
167
+ */
168
+ declare function serializeGraph(graph: VgGraph): string;
169
+ declare function stableStringify(value: unknown, indent?: number): string;
170
+ declare function parseGraph(json: string): VgGraph;
171
+
172
+ /**
173
+ * Write the build artifacts under `.vibgrate/`. `graph.json` is the committable
174
+ * map; `GRAPH_REPORT.md` and `graph.html` are convenience artifacts (volatile —
175
+ * gitignored by default via `vg share`).
176
+ */
177
+ interface WriteOptions {
178
+ root: string;
179
+ html?: boolean;
180
+ report?: boolean;
181
+ graphPath?: string;
182
+ }
183
+ interface WrittenArtifacts {
184
+ graphPath: string;
185
+ reportPath?: string;
186
+ htmlPath?: string;
187
+ factsPath?: string;
188
+ }
189
+ declare function vibgrateDir(root: string): string;
190
+ declare function defaultGraphPath(root: string): string;
191
+ declare function writeArtifacts(graph: VgGraph, options: WriteOptions): WrittenArtifacts;
192
+
193
+ interface VerifyResult {
194
+ ok: boolean;
195
+ checks: {
196
+ name: string;
197
+ ok: boolean;
198
+ detail?: string;
199
+ }[];
200
+ digest: string;
201
+ }
202
+ declare function verifyDeterminism(opts: {
203
+ root: string;
204
+ only?: string[];
205
+ exclude?: string[];
206
+ jobs?: number;
207
+ }): Promise<VerifyResult>;
208
+
209
+ /**
210
+ * Deterministic Markdown summary (`GRAPH_REPORT.md`). Given a pinned
211
+ * `generatedAt`, the report is byte-stable. Numbers are derived purely from the
212
+ * graph, so the report can be regenerated from a committed `graph.json`.
213
+ */
214
+ declare function renderReport(graph: VgGraph): string;
215
+
216
+ /**
217
+ * Phase-0 `graph.html`: a self-contained, dependency-free, deterministic
218
+ * overview (summary + most-connected definitions + per-file breakdown), with the
219
+ * full graph embedded as JSON for tooling. The interactive WebGL view (sigma.js
220
+ * over a ForceAtlas2 layout, scaling past ~5k nodes — VG-ENGINE-TEARDOWN §3.12)
221
+ * lands in Phase 1; this keeps the artifact present, honest, and byte-stable now.
222
+ */
223
+ declare function renderHtml(graph: VgGraph): string;
224
+
225
+ /**
226
+ * SCIP ingestion — the precise resolution rung (VG-ENGINE-TEARDOWN §3.2).
227
+ *
228
+ * Reads a real SCIP index (`index.scip`) produced by a language indexer
229
+ * (scip-typescript, scip-python, scip-java, rust-analyzer→SCIP, …) and turns its
230
+ * precise occurrences into call/reference edges at `resolution: "scip"`,
231
+ * confidence 1.0 — the genuine "real SCIP vs Graphify's fake-SCIP" win. vg does
232
+ * NOT bundle indexers; it consumes an index the user/CI generates (deterministic,
233
+ * offline). The heuristic resolver remains the floor for files SCIP didn't cover.
234
+ *
235
+ * A small, dependency-free protobuf reader decodes only the fields we need, so
236
+ * the core stays lean.
237
+ */
238
+
239
+ interface ScipOccurrence {
240
+ /** [startLine, startChar, endLine, endChar] or [startLine, startChar, endChar], 0-based. */
241
+ range: number[];
242
+ symbol: string;
243
+ roles: number;
244
+ }
245
+ interface ScipDocument {
246
+ relativePath: string;
247
+ occurrences: ScipOccurrence[];
248
+ }
249
+ interface ScipIndex {
250
+ documents: ScipDocument[];
251
+ toolName?: string;
252
+ toolVersion?: string;
253
+ }
254
+ declare function decodeScipIndex(buf: Uint8Array): ScipIndex;
255
+ interface ScipResult {
256
+ edges: GraphEdge[];
257
+ /** Repo-relative files SCIP covered (it is authoritative for these). */
258
+ coveredFiles: Set<string>;
259
+ /** counts for status/provenance. */
260
+ stats: {
261
+ documents: number;
262
+ references: number;
263
+ resolved: number;
264
+ };
265
+ }
266
+ /**
267
+ * Build precise edges from a SCIP index, mapped onto our nodes by (file, line).
268
+ * A reference occurrence's enclosing node → the node where its symbol is defined.
269
+ */
270
+ declare function scipEdges(index: ScipIndex, nodes: GraphNode[], relForScip: (p: string) => string): ScipResult;
271
+
272
+ /**
273
+ * Language registry: 20 supported languages (first wave + the Phase-3 expansion).
274
+ *
275
+ * Each language maps to a tree-sitter grammar shipped (pre-compiled to .wasm) by
276
+ * `tree-sitter-wasms`. `grammarFile` is the base name under that package's `out/`
277
+ * directory (and our bundled `grammars/` copy). The grammar *version* is recorded
278
+ * in provenance so the determinism contract is explicit about its inputs.
279
+ */
280
+ interface LanguageDef {
281
+ /** Canonical short id used in the schema (`lang` field) and `--only`. */
282
+ id: string;
283
+ /** Human label. */
284
+ label: string;
285
+ /** File extensions (lowercase, with leading dot). */
286
+ extensions: string[];
287
+ /** tree-sitter-wasms grammar base name, e.g. `tree-sitter-typescript`. */
288
+ grammarFile: string;
289
+ }
290
+ declare const LANGUAGES: LanguageDef[];
291
+ declare function langForExtension(ext: string): LanguageDef | undefined;
292
+ declare function langById(id: string): LanguageDef | undefined;
293
+ declare function allLanguageIds(): string[];
294
+
295
+ /**
296
+ * Deterministic file discovery.
297
+ *
298
+ * Respects `.gitignore` (including nested ones), explicit config excludes, and a
299
+ * built-in SKIP_DIRS set consistent with the scanner. Results are returned
300
+ * sorted by relative POSIX path so the build is order-independent of the
301
+ * filesystem.
302
+ */
303
+ declare const SKIP_DIRS: Set<string>;
304
+ interface DiscoverOptions {
305
+ /** Absolute root directory. */
306
+ root: string;
307
+ /** Restrict to these language ids (e.g. ['ts','py']). Empty = all. */
308
+ only?: string[];
309
+ /** Additional ignore globs (gitignore syntax), e.g. from config `exclude`. */
310
+ exclude?: string[];
311
+ /** Explicit sub-paths to scope to (relative or absolute). */
312
+ paths?: string[];
313
+ }
314
+ interface DiscoveredFile {
315
+ /** Relative POSIX path from root. */
316
+ rel: string;
317
+ /** Absolute path. */
318
+ abs: string;
319
+ lang: LanguageDef;
320
+ }
321
+ declare function discover(options: DiscoverOptions): DiscoveredFile[];
322
+ /** A usage error that maps to exit code 5 at the CLI boundary. */
323
+ declare class UsageError extends Error {
324
+ readonly isUsageError = true;
325
+ constructor(message: string);
326
+ }
327
+
328
+ declare function parseSource(rel: string, langId: string, source: string): Promise<FileParse>;
329
+
330
+ /**
331
+ * Local-embedding semantic search for `vg ask --semantic`/`--deep` (no API key).
332
+ *
333
+ * The embedding backend is an OPTIONAL, lazily-loaded dependency (`fastembed`,
334
+ * Apache-2.0, local ONNX) so the core install stays lean and `ask` never breaks:
335
+ * if the backend or model isn't available it degrades to (prefix-fuzzy) lexical
336
+ * search with a clear note. Embeddings are query-time + cached under
337
+ * `.vibgrate/cache/` (keyed by node-text hash); they are NEVER written into the
338
+ * committed `graph.json`, so the artifact stays byte-deterministic.
339
+ *
340
+ * `--local` disables the model download (semantic is skipped unless already
341
+ * cached via an injected backend), keeping the air-gapped guarantee.
342
+ */
343
+ interface Embedder {
344
+ /** Stable model id (recorded with cached vectors so a model change invalidates them). */
345
+ id: string;
346
+ /** Embed documents → unit-or-raw vectors (cosine handles normalization). */
347
+ embed(texts: string[]): Promise<number[][]>;
348
+ /** Embed a single query string. */
349
+ embedQuery(text: string): Promise<number[]>;
350
+ }
351
+ /** Why semantic fell back to lexical — for calm, specific messaging. */
352
+ type EmbedUnavailable = 'not-installed' | 'no-permission' | 'download-failed' | 'init-failed';
353
+ interface LoadEmbedderOptions {
354
+ local?: boolean;
355
+ model?: string;
356
+ noDownload?: boolean;
357
+ showDownloadProgress?: boolean;
358
+ onUnavailable?: (reason: EmbedUnavailable) => void;
359
+ }
360
+ /**
361
+ * Try to load the optional local embedding backend. Returns null (→ caller falls
362
+ * back to lexical) when running `--local`, when the dependency isn't installed,
363
+ * or when the model can't initialize.
364
+ */
365
+ declare function loadEmbedder(options?: LoadEmbedderOptions): Promise<Embedder | null>;
366
+ /**
367
+ * The text we embed for a node. Alongside identity + signature we add the
368
+ * strongest available signal — the node's **doc-comment / docstring** summary —
369
+ * plus lightweight context already on the graph (file-path words, area label), so
370
+ * a tersely-named symbol (`Table`, `NotificationJob`) a concept query can reach.
371
+ * Only the short, truncated doc summary is used (captured at build time); no full
372
+ * file bodies, so the graph artifact stays deterministic.
373
+ */
374
+ declare function nodeEmbedText(node: GraphNode, areaLabel?: string): string;
375
+ declare function cosine(a: number[], b: number[]): number;
376
+ /** Reports embedding progress: how many of `total` nodes are done so far. */
377
+ type EmbedProgress = (done: number, total: number) => void;
378
+ /**
379
+ * Node embeddings for the searchable (non-file/external) nodes, cache-backed:
380
+ * only nodes whose embed-text changed are re-embedded. The first run embeds in
381
+ * chunks, **persists the cache incrementally** (so an interrupted/timed-out run
382
+ * resumes instead of wasting the work), and reports progress via `onProgress`.
383
+ */
384
+ declare function getNodeEmbeddings(graph: VgGraph, embedder: Embedder, root: string, onProgress?: EmbedProgress): Promise<Map<string, number[]>>;
385
+
386
+ /**
387
+ * Deterministic retrieval for `vg ask` (VG-CLI-SPEC §3.2).
388
+ *
389
+ * Builds a structured, fact-annotated, budget-bounded context block for a
390
+ * question — designed to drop straight into an assistant's context. The default
391
+ * is deterministic lexical+structural retrieval (identifier/term matching with
392
+ * morphological prefix-fuzzing, ranked by importance). `--semantic`/`--deep` adds
393
+ * a hybrid local-embedding pass (`queryGraphSemantic`) that surfaces conceptually
394
+ * related code even when no word is shared — still no API key.
395
+ */
396
+ interface QueryOptions {
397
+ budget?: number;
398
+ limit?: number;
399
+ }
400
+ interface QueryMatch {
401
+ node: GraphNode;
402
+ score: number;
403
+ why: string;
404
+ }
405
+ interface QueryResult {
406
+ question: string;
407
+ matches: QueryMatch[];
408
+ context: string;
409
+ tokensEstimate: number;
410
+ }
411
+ declare function queryGraph(graph: VgGraph, question: string, options?: QueryOptions): QueryResult;
412
+ interface SemanticQueryOptions extends QueryOptions {
413
+ embedder: Embedder;
414
+ /** Precomputed node vectors (from getNodeEmbeddings); falls back to lexical for nodes without one. */
415
+ nodeVectors: Map<string, number[]>;
416
+ }
417
+ /**
418
+ * Hybrid lexical + local-embedding retrieval. Blends the normalized lexical score
419
+ * with cosine similarity to the query embedding (50/50), so a question like
420
+ * "where do we handle auth failures?" can surface `verify_token` even with no
421
+ * shared identifier. Deterministic given the same model + cached vectors;
422
+ * embeddings live only in the cache, never in `graph.json`.
423
+ */
424
+ declare function queryGraphSemantic(graph: VgGraph, question: string, options: SemanticQueryOptions): Promise<QueryResult>;
425
+ /** camelCase / snake_case / kebab split of an identifier → lowercased parts. */
426
+ declare function identifierParts(name: string): Set<string>;
427
+
428
+ /**
429
+ * Lenient node resolution (VG-CLI-SPEC §3.3): resolve `<name>` by content-hash
430
+ * id, qualified name, `file:line`, short name, or glob. Returns candidates
431
+ * ranked by importance so the best match is first; ambiguity is surfaced (the
432
+ * caller offers `--pick`). Deterministic ordering throughout.
433
+ */
434
+ declare function findNodes(graph: VgGraph, query: string): GraphNode[];
435
+ /** Resolve to a single node, honoring a 1-based `--pick`. */
436
+ declare function resolveOne(graph: VgGraph, query: string, pick?: number): {
437
+ node?: GraphNode;
438
+ candidates: GraphNode[];
439
+ };
440
+ declare function nodeById(graph: VgGraph, id: string): GraphNode | undefined;
441
+
442
+ interface ImpactItem {
443
+ id: string;
444
+ name: string;
445
+ kind: string;
446
+ file: string;
447
+ line: number;
448
+ depth: number;
449
+ confidence: number;
450
+ }
451
+ interface ImpactResult {
452
+ root: {
453
+ id: string;
454
+ name: string;
455
+ };
456
+ depth: number;
457
+ affected: ImpactItem[];
458
+ direct: number;
459
+ transitive: number;
460
+ /** Lowest edge confidence encountered (e.g. a dynamic-dispatch edge). */
461
+ minEdgeConfidence: number;
462
+ }
463
+ declare function impactOf(graph: VgGraph, rootId: string, opts?: {
464
+ depth?: number;
465
+ }): ImpactResult;
466
+
467
+ /**
468
+ * Shortest connection between two nodes (`vg path`). Uses graphology's
469
+ * bidirectional BFS over the directed graph; falls back to the reverse direction
470
+ * so "how does A connect to B" still answers when the dependency arrow runs B→A.
471
+ */
472
+ interface PathResult {
473
+ ids: string[];
474
+ direction: 'forward' | 'reverse';
475
+ }
476
+ declare function shortestPath(graph: VgGraph, srcId: string, dstId: string): PathResult | null;
477
+
478
+ /** Indexes over a graph for O(1) neighbor lookups (built once per command). */
479
+ declare class GraphIndex {
480
+ readonly graph: VgGraph;
481
+ readonly nodeById: Map<string, GraphNode>;
482
+ private outById;
483
+ private inById;
484
+ constructor(graph: VgGraph);
485
+ out(id: string, kind?: EdgeKind): GraphEdge[];
486
+ in(id: string, kind?: EdgeKind): GraphEdge[];
487
+ node(id: string): GraphNode | undefined;
488
+ /** Resolved nodes called by `id`. */
489
+ callees(id: string): {
490
+ edge: GraphEdge;
491
+ node: GraphNode;
492
+ }[];
493
+ /** Resolved nodes that call `id`. */
494
+ callers(id: string): {
495
+ edge: GraphEdge;
496
+ node: GraphNode;
497
+ }[];
498
+ private resolveTargets;
499
+ }
500
+
501
+ /**
502
+ * The read-only tool set for the LOCAL `vg serve` MCP. Every tool is
503
+ * side-effect-free and `readOnlyHint: true` (auto-approvable), and independent of
504
+ * Vibgrate's hosted cloud MCP. The server is local-first; network access is
505
+ * limited to the embedder's one-time model fetch, `upgrade_impact`'s `changelog`
506
+ * option, and `library_docs`' hosted-catalog fall-through on a thin/missing local
507
+ * doc — all disabled under `--local` (the hard airgap).
508
+ *
509
+ * Phase 2/3 add `tests_for`, `get_facts`, `guide_node`, `check_drift`,
510
+ * `list_models`, `resolve_library`, `library_docs`.
511
+ */
512
+ interface ToolContext {
513
+ /** Project root (for filesystem-backed tools: drift, models). */
514
+ root: string;
515
+ /** `--local`: keep the server air-gapped — no model download, lexical only. */
516
+ local?: boolean;
517
+ /** `--dedup`: collapse a node's heavy relation lists on repeat reads this session. */
518
+ dedup?: boolean;
519
+ /** Per-session set of node ids already returned in full (drives `--dedup`). */
520
+ seen?: Set<string>;
521
+ }
522
+ interface VgTool {
523
+ name: string;
524
+ description: string;
525
+ inputSchema: Record<string, unknown>;
526
+ handler: (graph: VgGraph, args: Record<string, unknown>, ctx: ToolContext) => unknown | Promise<unknown>;
527
+ }
528
+ declare const TOOLS: VgTool[];
529
+
530
+ interface ServeOptions {
531
+ /** Record local, counts-only usage savings (opt-in). */
532
+ savings?: boolean;
533
+ /** Air-gapped mode (no model downloads). */
534
+ local?: boolean;
535
+ /** Collapse repeat heavy relation lists within a session (opt-in). */
536
+ dedup?: boolean;
537
+ /** Auto-refresh the map when the working tree drifts (default true). */
538
+ refresh?: boolean;
539
+ }
540
+ declare class GraphSource {
541
+ readonly graphPath: string;
542
+ private readonly refresh;
543
+ /** Timing overrides (tests only). */
544
+ private readonly tuning;
545
+ private cachedMtimeMs;
546
+ private cached;
547
+ private readonly root;
548
+ private lastProbeAt;
549
+ private failedUntil;
550
+ private inflight;
551
+ /** Self-tuned: grows with measured probe cost so huge repos aren't penalized. */
552
+ private probeIntervalMs;
553
+ constructor(graphPath: string, refresh?: boolean,
554
+ /** Timing overrides (tests only). */
555
+ tuning?: {
556
+ probeIntervalMs?: number;
557
+ refreshBudgetMs?: number;
558
+ });
559
+ /** Current graph: auto-refreshed if the tree drifted, reloaded if the file changed. */
560
+ get(): Promise<VgGraph>;
561
+ /**
562
+ * Debounced, single-flight refresh. Never throws — a refresh problem must
563
+ * degrade to "answer from the current map", not break the tool call.
564
+ */
565
+ private maybeRefresh;
566
+ }
567
+ declare function createServer(source: GraphSource, opts?: ServeOptions): Server;
568
+ declare function serveStdio(graphPath: string, opts?: ServeOptions): Promise<void>;
569
+
570
+ /** The graph-affecting discovery/build scope, replayed verbatim on refresh. */
571
+ interface BuildScope {
572
+ only?: string[];
573
+ exclude?: string[];
574
+ paths?: string[];
575
+ deep?: boolean;
576
+ noGround?: boolean;
577
+ scip?: string;
578
+ noScip?: boolean;
579
+ noTsc?: boolean;
580
+ cluster?: string;
581
+ grammarsDir?: string;
582
+ }
583
+ interface SnapshotFile {
584
+ version: string;
585
+ /** corpusHash of the build this snapshot belongs to. */
586
+ corpusHash: string;
587
+ scope: BuildScope;
588
+ files: Record<string, {
589
+ size: number;
590
+ mtimeMs: number;
591
+ hash: string;
592
+ }>;
593
+ }
594
+ interface Drift {
595
+ /** Files whose *content* changed (stat moved AND hash differs). */
596
+ changed: string[];
597
+ /** Files present now but absent from the snapshot. */
598
+ added: string[];
599
+ /** Snapshot files no longer present. */
600
+ removed: string[];
601
+ }
602
+ interface ProbeResult {
603
+ drift: Drift;
604
+ /** The recorded build scope — what a refresh must replay. */
605
+ scope: BuildScope;
606
+ /** corpusHash the current map was built from. */
607
+ corpusHash: string;
608
+ }
609
+ /** Persist the snapshot after a successful build. Best-effort (cache-only). */
610
+ declare function writeSnapshot(root: string, corpusHash: string, fileStats: FileStat[], scope?: BuildScope): void;
611
+ declare function loadSnapshot(root: string): SnapshotFile | null;
612
+ declare function hasDrift(drift: Drift): boolean;
613
+ /** Total drifted files — the number shown to humans. */
614
+ declare function driftCount(drift: Drift): number;
615
+ /**
616
+ * Compare the working tree to the snapshot. Returns null when no snapshot
617
+ * exists (nothing was ever built on this machine — auto-refresh stays off
618
+ * rather than guessing the build scope). Stat-only except for files whose
619
+ * stat moved; touch-only moves are absorbed back into the snapshot.
620
+ */
621
+ declare function probeFreshness(root: string): ProbeResult | null;
622
+
623
+ /**
624
+ * Auto-refresh: bring the code map back in sync with the working tree when the
625
+ * freshness probe says it drifted. The rebuild is the ordinary incremental
626
+ * `buildGraph` (warm parse cache → only changed files re-parse), replaying the
627
+ * scope recorded at the last explicit build, guarded by a cross-process lock
628
+ * so a serving MCP process and a foreground command never write at once.
629
+ *
630
+ * Two properties keep this safe to run implicitly:
631
+ * - **No git churn**: if the rebuilt corpusHash equals the snapshot's (e.g. a
632
+ * drift that reverted itself), `graph.json` is left untouched — the artifact
633
+ * stays byte-identical.
634
+ * - **No surprise artifacts**: `GRAPH_REPORT.md`/`graph.html` are rewritten
635
+ * only if they already exist; a refresh never adds files a user's explicit
636
+ * build chose not to produce.
637
+ */
638
+ interface RefreshOptions {
639
+ /** Force single-threaded parsing (tests / constrained hosts). */
640
+ inline?: boolean;
641
+ /** Worker count for the parse pool. */
642
+ jobs?: number;
643
+ }
644
+ type RefreshOutcome =
645
+ /** Map already matches the working tree. */
646
+ {
647
+ status: 'fresh';
648
+ }
649
+ /** No freshness snapshot — no build ever ran here, so scope is unknown. */
650
+ | {
651
+ status: 'no-snapshot';
652
+ }
653
+ /** Another vg process is rebuilding right now; its write will land shortly. */
654
+ | {
655
+ status: 'locked';
656
+ }
657
+ /** Rebuilt. `wrote` is false when the corpus turned out unchanged. */
658
+ | {
659
+ status: 'refreshed';
660
+ drift: Drift;
661
+ ms: number;
662
+ reparsed: number;
663
+ totalFiles: number;
664
+ wrote: boolean;
665
+ } | {
666
+ status: 'error';
667
+ message: string;
668
+ };
669
+ /**
670
+ * Probe, and rebuild incrementally if the tree drifted from the map.
671
+ * Silent (no output) — callers own the messaging for their surface.
672
+ */
673
+ declare function refreshIfStale(root: string, opts?: RefreshOptions): Promise<RefreshOutcome>;
674
+
675
+ /**
676
+ * Test-awareness (VG-ENGINE-TEARDOWN §3.6) — the wedge Graphify has no answer to.
677
+ *
678
+ * Deterministic, two signals:
679
+ * 1. **Static linkage** — calls from a test file into product code become `test`
680
+ * edges (test file → covered node), so we can answer "which tests exercise
681
+ * this" from structure alone, no runner needed.
682
+ * 2. **Coverage** (coverage.ts) — runtime-grounded line coverage applied as
683
+ * `coverage` on nodes (stronger than static linkage when present).
684
+ *
685
+ * A node's `tested` flag is true when it has any incoming test/coverage signal;
686
+ * false for analyzable code with none; null for non-analyzable kinds.
687
+ */
688
+ declare function isTestFile(rel: string): boolean;
689
+ interface TestAwarenessResult {
690
+ nodes: GraphNode[];
691
+ edges: GraphEdge[];
692
+ testFiles: string[];
693
+ testEdgeCount: number;
694
+ }
695
+ /**
696
+ * Apply static test linkage. Adds `test` edges from each test file node to the
697
+ * product-code nodes its functions call, and sets `tested` on analyzable nodes.
698
+ */
699
+ declare function applyStaticTestLinkage(nodes: GraphNode[], edges: GraphEdge[]): TestAwarenessResult;
700
+
701
+ /**
702
+ * Answering the wedge questions: "which tests cover X" (`vg tests`) and "which
703
+ * tests must I run if I change X" (`vg impact --tests`). Deterministic, from the
704
+ * `test` edges + coverage produced at build time.
705
+ */
706
+ interface CoveringTest {
707
+ file: string;
708
+ basis: 'call' | 'coverage';
709
+ confidence: number;
710
+ }
711
+ declare function coveringTests(graph: VgGraph, node: GraphNode, index?: GraphIndex): CoveringTest[];
712
+ interface TestImpact {
713
+ affectedTestFiles: string[];
714
+ untestedAffected: {
715
+ id: string;
716
+ name: string;
717
+ file: string;
718
+ }[];
719
+ }
720
+ /** The test files that exercise any node in the impact set of `rootId`. */
721
+ declare function testsToRun(graph: VgGraph, rootId: string, depth?: number): TestImpact;
722
+ interface Runner {
723
+ name: string;
724
+ command: (testFiles: string[]) => string;
725
+ }
726
+ declare function detectRunner(root: string, lang?: string): Runner;
727
+
728
+ /**
729
+ * Coverage ingestion (VG-ENGINE-TEARDOWN §3.6) — runtime-grounded test linkage.
730
+ * Parses LCOV (`coverage/lcov.info`) and Istanbul (`coverage-final.json`) into a
731
+ * per-file line→hits map, then sets each node's `coverage` (fraction of its span
732
+ * that ran) and `tested` flag. Stronger than static linkage where present.
733
+ */
734
+ type LineHits = Map<number, number>;
735
+ type CoverageMap = Map<string, LineHits>;
736
+ /** Find and parse coverage reports under root. Returns null if none found. */
737
+ declare function loadCoverage(root: string, explicit?: string[]): CoverageMap | null;
738
+ /** Apply coverage to nodes: set `coverage` fraction over the node's span + `tested`. */
739
+ declare function applyCoverage(nodes: GraphNode[], coverage: CoverageMap): GraphNode[];
740
+
741
+ /**
742
+ * The open facts subset (VG-PACKAGE-AND-SCHEMA §5) — reimplemented fresh in the
743
+ * open engine: deterministic, no runtime, no corpus, no LLM, no hidden pipeline.
744
+ * Three commodity fact kinds, each epistemic-typed so it never claims more than
745
+ * the open layer can prove:
746
+ *
747
+ * - **contract** — from a public signature/type (declared → Observed)
748
+ * - **invariant** — from a static assert/guard (static → Derived)
749
+ * - **characterization** — from existing test linkage (static → Observed)
750
+ *
751
+ * Emitted with `--deep`.
752
+ */
753
+ declare function buildFacts(parses: FileParse[], nodes: GraphNode[], edges: GraphEdge[]): Fact[];
754
+
755
+ /**
756
+ * The free knowledge pack shipped in the open CLI (VG-PACKAGE-AND-SCHEMA §6):
757
+ * our own paraphrased guidance + openly-licensed standards (OWASP Top 10 2021,
758
+ * CWE). Never verbatim proprietary text; every entry cites a public source.
759
+ * Matching is deterministic (imports / called APIs / identifier keywords).
760
+ */
761
+ interface MatchRule {
762
+ imports?: string[];
763
+ calls?: string[];
764
+ keywords?: string[];
765
+ }
766
+ interface PackEntry {
767
+ id: string;
768
+ topic: string;
769
+ summary: string;
770
+ citation: {
771
+ title: string;
772
+ url: string;
773
+ };
774
+ kind: GroundingKind;
775
+ rationale: 'recommended' | 'conjectured';
776
+ match: MatchRule;
777
+ }
778
+ interface KnowledgePack {
779
+ id: string;
780
+ version: string;
781
+ license: string;
782
+ entries: PackEntry[];
783
+ }
784
+ declare const FREE_PACK: KnowledgePack;
785
+
786
+ /**
787
+ * Grounding (VG-PACKAGE-AND-SCHEMA §6) — match nodes to knowledge-pack entries by
788
+ * deterministic signals (file imports, called APIs, identifier keywords) and
789
+ * attach cited framing edges. Closed-world tools can't follow without building a
790
+ * corpus. Deterministic-first; the free pack ships in the open CLI.
791
+ */
792
+ declare function groundGraph(nodes: GraphNode[], edges: GraphEdge[], parses: FileParse[], packs?: KnowledgePack[]): GroundingEdge[];
793
+
794
+ /**
795
+ * Dependency currency (VG-LOCAL-MODELS §9 / VG-DEVELOPMENT-PLAN Phase 2.4).
796
+ *
797
+ * Default path is **offline and deterministic**: inventory dependencies from
798
+ * manifests and resolve installed versions from node_modules. Currency against
799
+ * "latest/EOL/CVE" needs data, so it is strictly **opt-in** (`--online`, which
800
+ * queries the public npm registry) — the offline core never touches the network.
801
+ * Full DriftScore/CVE/EOL governance is the Vibgrate platform (the funnel).
802
+ */
803
+ /** Supported dependency ecosystems (manifest + lockfile). Extend this list to widen coverage. */
804
+ declare const ECOSYSTEMS: readonly ["npm", "pypi", "go", "rust", "ruby", "php", "dotnet", "swift", "dart", "java"];
805
+ type Ecosystem = (typeof ECOSYSTEMS)[number];
806
+ interface DepRecord {
807
+ name: string;
808
+ ecosystem: Ecosystem;
809
+ declared: string;
810
+ installed?: string;
811
+ latest?: string;
812
+ drift?: 'major' | 'minor' | 'patch' | 'current' | 'unknown';
813
+ }
814
+ interface DriftInventory {
815
+ records: DepRecord[];
816
+ counts: {
817
+ total: number;
818
+ } & Record<Ecosystem, number>;
819
+ }
820
+ declare function inventory(root: string): DriftInventory;
821
+ /** Opt-in online enrichment: query npm for `latest` and classify drift. */
822
+ declare function enrichOnline(records: DepRecord[], fetchImpl?: typeof fetch): Promise<void>;
823
+
824
+ /**
825
+ * Local-model discovery (VG-LOCAL-MODELS §9.2) — be a no-key *consumer* of the
826
+ * developer's local model fleet. Fully offline and deterministic: inspect the
827
+ * on-disk layouts of Ollama / LM Studio / llama.cpp, never the network. No
828
+ * runtime is built or launched.
829
+ */
830
+ interface LocalModel {
831
+ runtime: 'ollama' | 'lm-studio' | 'gguf';
832
+ name: string;
833
+ path: string;
834
+ }
835
+ declare function discoverModels(home?: string): LocalModel[];
836
+
837
+ interface SavingEntry {
838
+ ts: number;
839
+ tool: string;
840
+ vgTokens: number;
841
+ baselineTokens: number;
842
+ }
843
+ /** Whether a savings ledger exists for this repo (i.e. `vg serve --savings` has recorded). */
844
+ declare function savingsRecorded(root: string): boolean;
845
+ declare function recordSaving(root: string, entry: Omit<SavingEntry, 'ts'>, now: number): void;
846
+ interface SavingsReport {
847
+ enabled: boolean;
848
+ days: number;
849
+ queries: number;
850
+ vgTokens: number;
851
+ baselineTokens: number;
852
+ ratio: number;
853
+ estCostVg: number;
854
+ estCostBaseline: number;
855
+ saved: number;
856
+ rateLabel: string;
857
+ }
858
+ declare function readSavings(root: string, days: number, now: number, ratePerM?: number): SavingsReport;
859
+
860
+ /**
861
+ * `vg lib` — a deterministic, on-disk library-currency catalog: version-correct
862
+ * usage docs for the **exact version in your lockfile**, drift-annotated, from
863
+ * on-disk sources (no key).
864
+ *
865
+ * The catalog (`vibgrate.lib.json`) is small and committable; doc bodies live in
866
+ * `.vibgrate/lib/<id>.md` so the team shares them on pull. Ingestion is
867
+ * deterministic from local sources; URL/llms.txt ingestion is opt-in network.
868
+ */
869
+ declare const LIB_SCHEMA: "vg-lib/1.0";
870
+ interface LibSource {
871
+ type: 'local' | 'llms.txt' | 'website' | 'openapi' | 'git';
872
+ location: string;
873
+ }
874
+ interface LibEntry {
875
+ id: string;
876
+ name: string;
877
+ version: string;
878
+ source: LibSource;
879
+ docFile: string;
880
+ docHash: string;
881
+ bytes: number;
882
+ }
883
+ interface LibCatalog {
884
+ schemaVersion: typeof LIB_SCHEMA;
885
+ libraries: Record<string, LibEntry>;
886
+ }
887
+ declare function libId(name: string): string;
888
+ declare function loadCatalog(root: string): LibCatalog;
889
+ declare function saveCatalog(root: string, catalog: LibCatalog): void;
890
+ /** Resolve a fuzzy name to a catalog entry (exact id, name, or substring). */
891
+ declare function resolveLib(catalog: LibCatalog, name: string): LibEntry | undefined;
892
+ interface DriftNote {
893
+ cataloged: string;
894
+ installed?: string;
895
+ drift: 'current' | 'behind' | 'ahead' | 'unknown';
896
+ }
897
+ declare function driftFor(root: string, entry: LibEntry): DriftNote;
898
+ interface AddOptions {
899
+ root: string;
900
+ name?: string;
901
+ version?: string;
902
+ /** Allow network for URL/llms.txt sources. */
903
+ allowNetwork?: boolean;
904
+ fetchImpl?: typeof globalThis.fetch;
905
+ }
906
+ /** Ingest docs for a library from a local path, a git repo, or (opt-in) a URL. */
907
+ declare function addLibrary(source: string, opts: AddOptions): Promise<LibEntry>;
908
+ declare function readDoc(root: string, entry: LibEntry): string;
909
+
910
+ interface ServeLaunch {
911
+ command: string;
912
+ args: string[];
913
+ /** Human-readable explanation when the launch is not the plain `vg serve`. */
914
+ note?: string;
915
+ }
916
+
917
+ /**
918
+ * Per-assistant install registry (a focused subset of VG-ASSISTANT-INSTALL §2;
919
+ * the remaining 20+ assistants are added in Phase 3). All paths are repo-local
920
+ * (the team-shareable, safe default); writes are idempotent.
921
+ */
922
+ interface McpTarget {
923
+ file: string;
924
+ key: 'mcpServers' | 'servers';
925
+ vscode?: boolean;
926
+ }
927
+ interface NudgeTarget {
928
+ file: string;
929
+ kind: 'block' | 'file';
930
+ }
931
+ interface Assistant {
932
+ id: string;
933
+ label: string;
934
+ skill?: string;
935
+ mcp?: McpTarget;
936
+ nudge?: NudgeTarget;
937
+ }
938
+ declare const ASSISTANTS: Assistant[];
939
+ declare function assistantById(id: string): Assistant | undefined;
940
+ interface InstallOptions {
941
+ root: string;
942
+ hook?: boolean;
943
+ smallRepo: boolean;
944
+ /** Resolved MCP launch command; defaults to detectServeLaunch(). */
945
+ launch?: ServeLaunch;
946
+ }
947
+ interface InstallAction {
948
+ wrote: string[];
949
+ skipped: string[];
950
+ /** Explanation when the MCP entry is not the plain `vg serve` (e.g. PATH fallback). */
951
+ note?: string;
952
+ }
953
+ declare function installAssistant(a: Assistant, opts: InstallOptions): InstallAction;
954
+ declare function uninstallAssistant(a: Assistant, root: string, purge: boolean): string[];
955
+
956
+ /**
957
+ * Deterministic exporters (VG-CLI-SPEC §4.2). One `vg export <file>` verb, format
958
+ * inferred from the extension. Live graph-DB push is deliberately out (a file
959
+ * import covers the same need offline). CycloneDX/SPDX power the SBOM/AI-BOM seam
960
+ * (VG-LOCAL-MODELS §9.4).
961
+ */
962
+ type ExportFormat = 'json' | 'ndjson' | 'graphml' | 'dot' | 'cypher' | 'md' | 'html' | 'cyclonedx' | 'spdx';
963
+ declare function formatForExt(ext: string): ExportFormat | null;
964
+ interface ExportContext {
965
+ graph: VgGraph;
966
+ deps?: DepRecord[];
967
+ models?: LocalModel[];
968
+ generatedAt: string;
969
+ }
970
+ declare function exportGraph(format: ExportFormat, ctx: ExportContext): string;
971
+
972
+ /**
973
+ * The deferred, decoupled push envelope (VG-PACKAGE-AND-SCHEMA §7). In the open
974
+ * CLI `vg push` is **specified but not built**: it assembles and redacts the
975
+ * envelope and prints a notice, but performs **no network upload**. Nothing in
976
+ * the free path depends on it. Drift-over-time/governance is the separate
977
+ * commercial product.
978
+ */
979
+ interface GraphUploadEnvelope {
980
+ schemaVersion: 'vg-graph/1.0';
981
+ artifactType: 'graph';
982
+ scanIngestId?: string;
983
+ vcs: {
984
+ sha: string;
985
+ shortSha: string;
986
+ branch: string;
987
+ };
988
+ repository?: {
989
+ name?: string;
990
+ remoteUrl?: string;
991
+ };
992
+ generatedAt: string;
993
+ graph: VgGraph;
994
+ }
995
+ declare function buildEnvelope(root: string, graph: VgGraph, scanIngestId?: string): GraphUploadEnvelope;
996
+ /**
997
+ * Redaction pass (GUARDRAILS §1: redact before storage). The graph is structure,
998
+ * not content, but we defensively scrub any signature/name that matches a
999
+ * credential-shaped pattern, and strip credentials from the remote URL.
1000
+ */
1001
+ declare function redactGraph(graph: VgGraph): VgGraph;
1002
+
1003
+ /**
1004
+ * The first existing directory that holds a grammar .wasm set. Skips the
1005
+ * vendor overlays — they hold single replacement files, never a full set.
1006
+ * For a complete per-language resolution use resolvedGrammarFiles().
1007
+ */
1008
+ declare function grammarsSourceDir(): string | null;
1009
+
1010
+ export { ASSISTANTS, type AnalyzeOptions, type AnalyzeResult, Area, type Assistant, type BuildOptions, type BuildResult, type BuildScope, type ClusterMode, type DepRecord, type DiscoverOptions, type DiscoveredFile, type Drift, type DriftInventory, type DriftNote, EdgeKind, type Embedder, type ExportContext, type ExportFormat, FREE_PACK, Fact, FileParse, GraphEdge, GraphIndex, GraphNode, GraphSource, type GraphUploadEnvelope, GroundingEdge, GroundingKind, type ImpactItem, type ImpactResult, type KnowledgePack, LANGUAGES, type LanguageDef, type LibCatalog, type LibEntry, type LibSource, type LoadEmbedderOptions, type LocalModel, type ModuleResolver, type PackEntry, type PathResult, type ProbeResult, type QueryMatch, type QueryOptions, type QueryResult, type RefreshOptions, type RefreshOutcome, ResolverKind, SKIP_DIRS, type SavingsReport, type ScipDocument, type ScipIndex, type ScipOccurrence, type SemanticQueryOptions, type ServeOptions, TOOLS, UsageError, VERSION, type VerifyResult, VgGraph, type VgTool, type WriteOptions, type WrittenArtifacts, addLibrary, allLanguageIds, analyze, applyCoverage, applyStaticTestLinkage, assistantById, buildEnvelope, buildFacts, buildGraph, buildModuleResolver, cosine, coveringTests, createServer, decodeScipIndex, defaultGraphPath, inventory as dependencyInventory, detectRunner, discover, discoverModels, driftCount, driftFor, enrichOnline, exportGraph, findNodes, formatForExt, getNodeEmbeddings, grammarsSourceDir, groundGraph, hasDrift, identifierParts, impactOf, installAssistant, isTestFile, langById, langForExtension, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, nodeById, nodeEmbedText, parseGraph, parseJsonc, parseSource, probeFreshness, queryGraph, queryGraphSemantic, readDoc, readSavings, recordSaving, redactGraph, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveLib, resolveOne, saveCatalog, savingsRecorded, scipEdges, serializeGraph, serveStdio, shortestPath, stableStringify, testsToRun, uninstallAssistant, verifyDeterminism, vibgrateDir, writeArtifacts, writeSnapshot };