@vibgrate/cli 2026.702.2 → 2026.703.3
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/DOCS.md +521 -146
- package/LICENSE +202 -0
- package/NOTICE +40 -0
- package/README.md +232 -250
- package/dist/baseline-ZBXJONQ6.js +6 -0
- package/dist/baseline-ZBXJONQ6.js.map +1 -0
- package/dist/chunk-2PJRXVUW.js +11389 -0
- package/dist/chunk-2PJRXVUW.js.map +1 -0
- package/dist/chunk-4M2MUQRO.js +800 -0
- package/dist/chunk-4M2MUQRO.js.map +1 -0
- package/dist/chunk-FPUNJNXD.js +31 -0
- package/dist/chunk-FPUNJNXD.js.map +1 -0
- package/dist/chunk-J4DFLN2Q.js +6267 -0
- package/dist/chunk-J4DFLN2Q.js.map +1 -0
- package/dist/chunk-RXP66R2E.js +39 -0
- package/dist/chunk-RXP66R2E.js.map +1 -0
- package/dist/chunk-X5YT263H.js +912 -0
- package/dist/chunk-X5YT263H.js.map +1 -0
- package/dist/cli.d.ts +44 -1
- package/dist/cli.js +3816 -165
- package/dist/cli.js.map +1 -0
- package/dist/fs-7KZ4F3SB.js +3 -0
- package/dist/fs-7KZ4F3SB.js.map +1 -0
- package/dist/index.d.ts +1010 -1
- package/dist/index.js +42 -1
- package/dist/index.js.map +1 -0
- package/dist/parse-worker.d.ts +23 -0
- package/dist/parse-worker.js +32 -0
- package/dist/parse-worker.js.map +1 -0
- package/dist/types-C6ZyQpa9.d.ts +168 -0
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-dart.wasm +0 -0
- package/grammars/tree-sitter-elixir.wasm +0 -0
- package/grammars/tree-sitter-go.wasm +0 -0
- package/grammars/tree-sitter-java.wasm +0 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-lua.wasm +0 -0
- package/grammars/tree-sitter-php.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-ruby.wasm +0 -0
- package/grammars/tree-sitter-rust.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/grammars/tree-sitter-zig.wasm +0 -0
- package/package.json +68 -33
- package/scripts/postinstall.mjs +84 -0
- package/skills/README.md +58 -0
- package/skills/vg/SKILL.md +42 -0
- package/HCS-RUNTIME-SETUP.md +0 -73
- package/LICENSE.md +0 -45
- package/dist/baseline-TJDKYSFL.js +0 -1
- package/dist/chunk-EK7ODJWE.js +0 -1
- package/dist/chunk-GGDB72YE.js +0 -323
- package/dist/chunk-MKDRULJ6.js +0 -1
- package/dist/chunk-NGFYX3CW.js +0 -2
- package/dist/chunk-OQSVJXWJ.js +0 -143
- package/dist/chunk-XTHPCEME.js +0 -2
- package/dist/dist-5D3BKCOR.js +0 -1
- package/dist/fs-PXXYZATK-ZP2RBR47.js +0 -1
- package/dist/hcs-wasm/package.json +0 -3
- package/dist/hcs-wasm/vibgrate_hcs_wasm.js +0 -450
- package/dist/hcs-wasm/vibgrate_hcs_wasm_bg.wasm +0 -0
- package/dist/hcs-worker.js +0 -374406
- package/dist/semver-TPPMM2NV.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,1010 @@
|
|
|
1
|
-
|
|
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.3";
|
|
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 };
|