@maxgfr/codeindex 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/docs/MIGRATION.md +100 -0
- package/package.json +89 -0
- package/scripts/cli.mjs +10 -0
- package/scripts/engine.d.mts +618 -0
- package/scripts/engine.mjs +10655 -0
- package/scripts/grammars/bash.wasm +0 -0
- package/scripts/grammars/c.wasm +0 -0
- package/scripts/grammars/c_sharp.wasm +0 -0
- package/scripts/grammars/cpp.wasm +0 -0
- package/scripts/grammars/go.wasm +0 -0
- package/scripts/grammars/java.wasm +0 -0
- package/scripts/grammars/javascript.wasm +0 -0
- package/scripts/grammars/lua.wasm +0 -0
- package/scripts/grammars/php.wasm +0 -0
- package/scripts/grammars/python.wasm +0 -0
- package/scripts/grammars/ruby.wasm +0 -0
- package/scripts/grammars/rust.wasm +0 -0
- package/scripts/grammars/scala.wasm +0 -0
- package/scripts/grammars/tsx.wasm +0 -0
- package/scripts/grammars/typescript.wasm +0 -0
- package/scripts/grammars/web-tree-sitter.wasm +0 -0
- package/src/ast/extract.ts +713 -0
- package/src/ast/loader.ts +104 -0
- package/src/bm25.ts +156 -0
- package/src/callers.ts +0 -0
- package/src/calls.ts +131 -0
- package/src/categorize.ts +80 -0
- package/src/centrality.ts +148 -0
- package/src/classify.ts +53 -0
- package/src/cli-entry.ts +16 -0
- package/src/community.ts +345 -0
- package/src/complexity.ts +69 -0
- package/src/coupling.ts +0 -0
- package/src/deadcode.ts +46 -0
- package/src/edit.ts +93 -0
- package/src/engine-cli.ts +278 -0
- package/src/engine.ts +148 -0
- package/src/extract/code.ts +376 -0
- package/src/extract/markdown.ts +135 -0
- package/src/git.ts +205 -0
- package/src/glob.ts +56 -0
- package/src/graph.ts +0 -0
- package/src/grep.ts +115 -0
- package/src/hash.ts +13 -0
- package/src/ignore.ts +134 -0
- package/src/lang/c.ts +26 -0
- package/src/lang/common.ts +68 -0
- package/src/lang/csharp.ts +22 -0
- package/src/lang/elixir.ts +18 -0
- package/src/lang/go.ts +22 -0
- package/src/lang/java.ts +19 -0
- package/src/lang/js-ts.ts +112 -0
- package/src/lang/kotlin.ts +20 -0
- package/src/lang/lua.ts +18 -0
- package/src/lang/php.ts +24 -0
- package/src/lang/python.ts +22 -0
- package/src/lang/registry.ts +54 -0
- package/src/lang/ruby.ts +17 -0
- package/src/lang/rust.ts +22 -0
- package/src/lang/scala.ts +19 -0
- package/src/lang/shell.ts +17 -0
- package/src/lang/swift.ts +23 -0
- package/src/mcp.ts +512 -0
- package/src/memory.ts +75 -0
- package/src/modules.ts +128 -0
- package/src/pipeline.ts +59 -0
- package/src/query.ts +118 -0
- package/src/render/graph-json.ts +16 -0
- package/src/render/symbols-json.ts +79 -0
- package/src/repomap.ts +52 -0
- package/src/resolve.ts +950 -0
- package/src/rules.ts +249 -0
- package/src/scan.ts +172 -0
- package/src/sort.ts +12 -0
- package/src/surprise.ts +58 -0
- package/src/tests-map.ts +105 -0
- package/src/types.ts +201 -0
- package/src/util.ts +169 -0
- package/src/viz.ts +44 -0
- package/src/walk.ts +216 -0
- package/src/workspaces.ts +748 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { SCHEMA_VERSION, EXTRACTOR_VERSION, type FileRecord } from "./types.js";
|
|
4
|
+
import { ENGINE_VERSION } from "./types.js";
|
|
5
|
+
import { ensureGrammars, allGrammarKeys } from "./ast/loader.js";
|
|
6
|
+
import { buildIndexArtifacts, type BuildIndexOptions } from "./pipeline.js";
|
|
7
|
+
import { renderGraphJson } from "./render/graph-json.js";
|
|
8
|
+
import { renderSymbolsJson } from "./render/symbols-json.js";
|
|
9
|
+
import { scanRepo } from "./scan.js";
|
|
10
|
+
import { buildCallerIndex } from "./callers.js";
|
|
11
|
+
import { detectWorkspaces } from "./workspaces.js";
|
|
12
|
+
import { gitChurn } from "./git.js";
|
|
13
|
+
import { grepRepo } from "./grep.js";
|
|
14
|
+
import { changeCoupling, rankHotspots } from "./coupling.js";
|
|
15
|
+
import { renderRepoMap } from "./repomap.js";
|
|
16
|
+
import { findDeadCode } from "./deadcode.js";
|
|
17
|
+
import { symbolComplexity, riskHotspots } from "./complexity.js";
|
|
18
|
+
import { renderMermaid } from "./viz.js";
|
|
19
|
+
import { searchIndex } from "./bm25.js";
|
|
20
|
+
import { checkRules, parseRules } from "./rules.js";
|
|
21
|
+
|
|
22
|
+
const HELP = `codeindex engine v${ENGINE_VERSION} — deterministic repo indexing
|
|
23
|
+
|
|
24
|
+
Usage: engine.mjs <command> [flags]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
index Build graph.json + symbols.json (+ incremental cache.json) into
|
|
28
|
+
--out <dir> in ONE pass — the fast path for repeated runs
|
|
29
|
+
scan Scan summary: file count, language histogram, capped flag
|
|
30
|
+
graph Full link-graph (graph.json bytes) to stdout or --out
|
|
31
|
+
symbols Symbol index (symbols.json bytes) to stdout or --out
|
|
32
|
+
callers Per-symbol caller index (JSON)
|
|
33
|
+
workspaces Monorepo packages + dependency graph (JSON)
|
|
34
|
+
churn Per-file git commit counts (JSON; --since <ref> to bound)
|
|
35
|
+
grep Search: cli.mjs grep <pattern> --repo <dir> (JSON hits)
|
|
36
|
+
search Keyless BM25 lexical search over symbol names, path segments,
|
|
37
|
+
markdown headings and summaries: cli.mjs search "<query>" --repo <dir>
|
|
38
|
+
rules Architecture rules (forbidden edges, cycles, orphans) validated
|
|
39
|
+
against the link-graph: --config <codeindex.rules.json>; exits 1
|
|
40
|
+
on any error-severity violation (a CI gate)
|
|
41
|
+
repomap Token-budgeted map of the highest-PageRank files (--budget-tokens)
|
|
42
|
+
hotspots Churn × size ranking of the files where work concentrates (JSON)
|
|
43
|
+
coupling Change coupling: files that change together (JSON; --since <ref>)
|
|
44
|
+
mcp Run as an MCP server over stdio (tools: scan_summary, graph,
|
|
45
|
+
symbols, callers, workspaces, churn, grep)
|
|
46
|
+
version Print the engine version
|
|
47
|
+
|
|
48
|
+
Flags:
|
|
49
|
+
--repo <dir> Repo root (default: cwd)
|
|
50
|
+
--out <file> Write output to a file instead of stdout
|
|
51
|
+
--include <glob> Only include matching paths (repeatable)
|
|
52
|
+
--exclude <glob> Exclude matching paths (repeatable)
|
|
53
|
+
--scope <dir> Restrict to one directory (sugar for --include '<dir>/**')
|
|
54
|
+
--no-gitignore Do not honor .gitignore files (default: honored)
|
|
55
|
+
--max-files <n> Cap walked files (default 20000)
|
|
56
|
+
--max-bytes <n> Skip files above this size (default 1 MiB)
|
|
57
|
+
--no-ast Skip tree-sitter grammars even when present (regex tier)
|
|
58
|
+
--config <file> Rules config for \`rules\` (JSON: [{name, from, to, …}])
|
|
59
|
+
--limit <n> Max results for \`search\` (default 20)
|
|
60
|
+
--recall \`callers\`: recall-oriented binding (issue #7) — relaxes
|
|
61
|
+
the JS/TS import gate to unique repo-wide names and labels
|
|
62
|
+
each site corroborated|unique-name
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
interface CliFlags {
|
|
66
|
+
repo: string;
|
|
67
|
+
out?: string;
|
|
68
|
+
include: string[];
|
|
69
|
+
exclude: string[];
|
|
70
|
+
scope?: string;
|
|
71
|
+
gitignore: boolean;
|
|
72
|
+
maxFiles?: number;
|
|
73
|
+
maxBytes?: number;
|
|
74
|
+
noAst: boolean;
|
|
75
|
+
since?: string;
|
|
76
|
+
ignoreCase?: boolean;
|
|
77
|
+
maxHits?: number;
|
|
78
|
+
budgetTokens?: number;
|
|
79
|
+
config?: string; // rules config path
|
|
80
|
+
limit?: number; // search result cap
|
|
81
|
+
recall?: boolean; // callers: recall-oriented binding
|
|
82
|
+
positional?: string; // e.g. the grep pattern or search query
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function parseFlags(args: string[]): CliFlags {
|
|
86
|
+
const flags: CliFlags = { repo: process.cwd(), include: [], exclude: [], gitignore: true, noAst: false };
|
|
87
|
+
for (let i = 0; i < args.length; i++) {
|
|
88
|
+
const a = args[i]!;
|
|
89
|
+
const next = (): string => {
|
|
90
|
+
const v = args[++i];
|
|
91
|
+
if (v === undefined) throw new Error(`missing value for ${a}`);
|
|
92
|
+
return v;
|
|
93
|
+
};
|
|
94
|
+
const num = (): number => {
|
|
95
|
+
const raw = next();
|
|
96
|
+
const n = Number(raw);
|
|
97
|
+
if (!Number.isFinite(n) || n <= 0) throw new Error(`${a} expects a positive number, got "${raw}"`);
|
|
98
|
+
return n;
|
|
99
|
+
};
|
|
100
|
+
if (a === "--repo") flags.repo = resolve(next());
|
|
101
|
+
else if (a === "--out") flags.out = resolve(next());
|
|
102
|
+
else if (a === "--include") flags.include.push(next());
|
|
103
|
+
else if (a === "--exclude") flags.exclude.push(next());
|
|
104
|
+
else if (a === "--scope") flags.scope = next();
|
|
105
|
+
else if (a === "--no-gitignore") flags.gitignore = false;
|
|
106
|
+
else if (a === "--max-files") flags.maxFiles = num();
|
|
107
|
+
else if (a === "--max-bytes") flags.maxBytes = num();
|
|
108
|
+
else if (a === "--ignore-case") flags.ignoreCase = true;
|
|
109
|
+
else if (a === "--max-hits") flags.maxHits = num();
|
|
110
|
+
else if (a === "--budget-tokens") flags.budgetTokens = num();
|
|
111
|
+
else if (a === "--no-ast") flags.noAst = true;
|
|
112
|
+
else if (a === "--since") flags.since = next();
|
|
113
|
+
else if (a === "--config") flags.config = resolve(next());
|
|
114
|
+
else if (a === "--limit") flags.limit = num();
|
|
115
|
+
else if (a === "--recall") flags.recall = true;
|
|
116
|
+
else if (!a.startsWith("--") && flags.positional === undefined) flags.positional = a;
|
|
117
|
+
else throw new Error(`unknown flag: ${a}`);
|
|
118
|
+
}
|
|
119
|
+
return flags;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function emit(content: string, out?: string): void {
|
|
123
|
+
if (out) writeFileSync(out, content);
|
|
124
|
+
else process.stdout.write(content);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function scanOptions(flags: CliFlags): BuildIndexOptions {
|
|
128
|
+
return {
|
|
129
|
+
include: flags.include.length ? flags.include : undefined,
|
|
130
|
+
exclude: flags.exclude.length ? flags.exclude : undefined,
|
|
131
|
+
scope: flags.scope,
|
|
132
|
+
gitignore: flags.gitignore,
|
|
133
|
+
maxFiles: flags.maxFiles,
|
|
134
|
+
maxBytes: flags.maxBytes,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function runCli(argv: string[]): Promise<void> {
|
|
139
|
+
const [cmd, ...rest] = argv;
|
|
140
|
+
if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
|
|
141
|
+
process.stdout.write(HELP);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (cmd === "version" || cmd === "--version") {
|
|
145
|
+
process.stdout.write(ENGINE_VERSION + "\n");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (cmd === "mcp") {
|
|
149
|
+
const { runMcpServer } = await import("./mcp.js");
|
|
150
|
+
await runMcpServer();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const flags = parseFlags(rest);
|
|
155
|
+
if (!existsSync(flags.repo)) throw new Error(`--repo path does not exist: ${flags.repo}`);
|
|
156
|
+
if (!flags.noAst) await ensureGrammars(allGrammarKeys());
|
|
157
|
+
|
|
158
|
+
if (cmd === "index") {
|
|
159
|
+
if (!flags.out) throw new Error("index needs --out <dir>");
|
|
160
|
+
const outDir = flags.out;
|
|
161
|
+
mkdirSync(outDir, { recursive: true });
|
|
162
|
+
// Incremental cache: reuse per-file records when (schema, extractor) match —
|
|
163
|
+
// same invalidation discipline as ultraindex's cache.json.
|
|
164
|
+
const cachePath = join(outDir, "cache.json");
|
|
165
|
+
let cache: Map<string, { hash: string; record: FileRecord; size?: number; mtimeMs?: number }> | undefined;
|
|
166
|
+
try {
|
|
167
|
+
const parsed = JSON.parse(readFileSync(cachePath, "utf8")) as {
|
|
168
|
+
schemaVersion: number;
|
|
169
|
+
extractorVersion: number;
|
|
170
|
+
files: Record<string, { hash: string; record: FileRecord; size?: number; mtimeMs?: number }>;
|
|
171
|
+
};
|
|
172
|
+
if (parsed.schemaVersion === SCHEMA_VERSION && parsed.extractorVersion === EXTRACTOR_VERSION) {
|
|
173
|
+
cache = new Map(Object.entries(parsed.files));
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
176
|
+
// no cache yet (or unreadable) — cold build
|
|
177
|
+
}
|
|
178
|
+
const { scan, graph, symbols } = buildIndexArtifacts(flags.repo, { ...scanOptions(flags), cache, out: outDir });
|
|
179
|
+
writeFileSync(join(outDir, "graph.json"), renderGraphJson(graph));
|
|
180
|
+
writeFileSync(join(outDir, "symbols.json"), renderSymbolsJson(symbols));
|
|
181
|
+
const files: Record<string, { hash: string; record: FileRecord; size?: number; mtimeMs?: number }> = {};
|
|
182
|
+
for (const f of scan.files) {
|
|
183
|
+
const entry: { hash: string; record: FileRecord; size?: number; mtimeMs?: number } = { hash: f.hash, record: f, size: f.size };
|
|
184
|
+
const mtime = scan.mtimes.get(f.rel);
|
|
185
|
+
if (mtime !== undefined) entry.mtimeMs = mtime;
|
|
186
|
+
files[f.rel] = entry;
|
|
187
|
+
}
|
|
188
|
+
writeFileSync(
|
|
189
|
+
cachePath,
|
|
190
|
+
JSON.stringify({ schemaVersion: SCHEMA_VERSION, extractorVersion: EXTRACTOR_VERSION, files }) + "\n",
|
|
191
|
+
);
|
|
192
|
+
process.stderr.write(`codeindex: ${scan.files.length} files → ${outDir}/graph.json + symbols.json${scan.capped ? " (capped)" : ""}\n`);
|
|
193
|
+
} else if (cmd === "scan") {
|
|
194
|
+
const { scan } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
195
|
+
const summary = {
|
|
196
|
+
engineVersion: ENGINE_VERSION,
|
|
197
|
+
commit: scan.commit,
|
|
198
|
+
fileCount: scan.files.length,
|
|
199
|
+
languages: scan.languages,
|
|
200
|
+
capped: scan.capped,
|
|
201
|
+
};
|
|
202
|
+
emit(JSON.stringify(summary, null, 2) + "\n", flags.out);
|
|
203
|
+
} else if (cmd === "graph") {
|
|
204
|
+
const { graph } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
205
|
+
emit(renderGraphJson(graph), flags.out);
|
|
206
|
+
} else if (cmd === "symbols") {
|
|
207
|
+
const { symbols } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
208
|
+
emit(renderSymbolsJson(symbols), flags.out);
|
|
209
|
+
} else if (cmd === "callers") {
|
|
210
|
+
const scan = scanRepo(flags.repo, scanOptions(flags));
|
|
211
|
+
const index = buildCallerIndex(scan, undefined, { recall: flags.recall });
|
|
212
|
+
const obj: Record<string, unknown> = {};
|
|
213
|
+
for (const [name, entry] of index) obj[name] = entry;
|
|
214
|
+
emit(JSON.stringify(obj, null, 2) + "\n", flags.out);
|
|
215
|
+
} else if (cmd === "search") {
|
|
216
|
+
if (!flags.positional) throw new Error('search needs a query: cli.mjs search "<query>" --repo <dir>');
|
|
217
|
+
const scan = scanRepo(flags.repo, scanOptions(flags));
|
|
218
|
+
const results = searchIndex(scan, flags.positional, { limit: flags.limit });
|
|
219
|
+
emit(JSON.stringify(results, null, 2) + "\n", flags.out);
|
|
220
|
+
} else if (cmd === "rules") {
|
|
221
|
+
if (!flags.config) throw new Error("rules needs --config <codeindex.rules.json>");
|
|
222
|
+
const rules = parseRules(JSON.parse(readFileSync(flags.config, "utf8")));
|
|
223
|
+
const { graph } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
224
|
+
const violations = checkRules(graph, rules);
|
|
225
|
+
const errors = violations.filter((v) => v.severity === "error").length;
|
|
226
|
+
emit(JSON.stringify({ errors, warnings: violations.length - errors, violations }, null, 2) + "\n", flags.out);
|
|
227
|
+
if (errors > 0) process.exitCode = 1; // the CI gate
|
|
228
|
+
} else if (cmd === "workspaces") {
|
|
229
|
+
const info = detectWorkspaces(flags.repo);
|
|
230
|
+
emit(
|
|
231
|
+
JSON.stringify(
|
|
232
|
+
{ packages: info.packages, cycle: info.cycle ?? null, topoOrder: info.topoOrder },
|
|
233
|
+
null,
|
|
234
|
+
2,
|
|
235
|
+
) + "\n",
|
|
236
|
+
flags.out,
|
|
237
|
+
);
|
|
238
|
+
} else if (cmd === "churn") {
|
|
239
|
+
const { churn, ok } = gitChurn(flags.repo, { since: flags.since });
|
|
240
|
+
const sorted: Record<string, number> = {};
|
|
241
|
+
for (const k of [...churn.keys()].sort()) sorted[k] = churn.get(k)!;
|
|
242
|
+
emit(JSON.stringify({ ok, churn: sorted }, null, 2) + "\n", flags.out);
|
|
243
|
+
} else if (cmd === "repomap") {
|
|
244
|
+
const { scan, graph } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
245
|
+
emit(renderRepoMap(scan, graph, { budgetTokens: flags.budgetTokens }), flags.out);
|
|
246
|
+
} else if (cmd === "hotspots") {
|
|
247
|
+
const scan = scanRepo(flags.repo, scanOptions(flags));
|
|
248
|
+
const { churn, ok } = gitChurn(flags.repo, { since: flags.since });
|
|
249
|
+
emit(JSON.stringify({ churnOk: ok, hotspots: rankHotspots(scan, churn) }, null, 2) + "\n", flags.out);
|
|
250
|
+
} else if (cmd === "coupling") {
|
|
251
|
+
const { ok, couplings } = changeCoupling(flags.repo, { since: flags.since });
|
|
252
|
+
emit(JSON.stringify({ ok, couplings }, null, 2) + "\n", flags.out);
|
|
253
|
+
} else if (cmd === "deadcode") {
|
|
254
|
+
emit(JSON.stringify(findDeadCode(scanRepo(flags.repo, scanOptions(flags))), null, 2) + "\n", flags.out);
|
|
255
|
+
} else if (cmd === "complexity") {
|
|
256
|
+
const scan = scanRepo(flags.repo, scanOptions(flags));
|
|
257
|
+
emit(JSON.stringify(symbolComplexity(scan, flags.positional), null, 2) + "\n", flags.out);
|
|
258
|
+
} else if (cmd === "risk") {
|
|
259
|
+
const scan = scanRepo(flags.repo, scanOptions(flags));
|
|
260
|
+
const { churn, ok } = gitChurn(flags.repo, { since: flags.since });
|
|
261
|
+
emit(JSON.stringify({ churnOk: ok, risks: riskHotspots(scan, churn) }, null, 2) + "\n", flags.out);
|
|
262
|
+
} else if (cmd === "mermaid") {
|
|
263
|
+
const { graph } = buildIndexArtifacts(flags.repo, scanOptions(flags));
|
|
264
|
+
emit(renderMermaid(graph, { module: flags.positional }), flags.out);
|
|
265
|
+
} else if (cmd === "grep") {
|
|
266
|
+
if (!flags.positional) throw new Error("grep needs a pattern: cli.mjs grep <pattern> --repo <dir>");
|
|
267
|
+
const globs = [...flags.include, ...flags.exclude.map((g) => `!${g}`)];
|
|
268
|
+
const hits = grepRepo(flags.repo, flags.positional, {
|
|
269
|
+
globs: globs.length ? globs : undefined,
|
|
270
|
+
ignoreCase: flags.ignoreCase,
|
|
271
|
+
maxHits: flags.maxHits,
|
|
272
|
+
});
|
|
273
|
+
emit(JSON.stringify(hits, null, 2) + "\n", flags.out);
|
|
274
|
+
} else {
|
|
275
|
+
process.stderr.write(`unknown command: ${cmd}\n\n${HELP}`);
|
|
276
|
+
process.exitCode = 2;
|
|
277
|
+
}
|
|
278
|
+
}
|
package/src/engine.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// codeindex — the shared, self-contained repo-indexing engine.
|
|
2
|
+
//
|
|
3
|
+
// This file is the public contract: everything a consumer may import from the
|
|
4
|
+
// vendored bundle is re-exported here, and nothing else. The bundle is dual-use:
|
|
5
|
+
// import it as an ESM library (consumers inline it into their own single-file
|
|
6
|
+
// builds), or run it directly (`node engine.mjs <cmd>`) via the guard at the
|
|
7
|
+
// bottom. Zero runtime dependencies; the tree-sitter AST tier activates only
|
|
8
|
+
// when a grammars/ directory is present next to the bundle (regex tier
|
|
9
|
+
// otherwise — see ast/loader.ts).
|
|
10
|
+
|
|
11
|
+
// Version constants — see types.ts for bump rules.
|
|
12
|
+
export { ENGINE_VERSION, SCHEMA_VERSION, EXTRACTOR_VERSION } from "./types.js";
|
|
13
|
+
export type {
|
|
14
|
+
FileKind,
|
|
15
|
+
EdgeKind,
|
|
16
|
+
Tier,
|
|
17
|
+
CodeSymbol,
|
|
18
|
+
RawRef,
|
|
19
|
+
FileRecord,
|
|
20
|
+
FileNode,
|
|
21
|
+
ModuleNode,
|
|
22
|
+
Edge,
|
|
23
|
+
Graph,
|
|
24
|
+
SurpriseEdge,
|
|
25
|
+
SymbolIndex,
|
|
26
|
+
} from "./types.js";
|
|
27
|
+
|
|
28
|
+
// Files tier: walk, read, filter, classify.
|
|
29
|
+
export { walk, readText, DEFAULT_MAX_FILES } from "./walk.js";
|
|
30
|
+
export type { WalkOptions, WalkedFile, WalkResult } from "./walk.js";
|
|
31
|
+
export { scanRepo } from "./scan.js";
|
|
32
|
+
export type { RepoScan, ScanOptions } from "./scan.js";
|
|
33
|
+
export { compileGlobs } from "./glob.js";
|
|
34
|
+
export { parseGitignore, isIgnored } from "./ignore.js";
|
|
35
|
+
export type { IgnoreRule } from "./ignore.js";
|
|
36
|
+
export { classify, isCode, isDoc, MARKDOWN_EXT } from "./classify.js";
|
|
37
|
+
export { categorize } from "./categorize.js";
|
|
38
|
+
export type { FileCategory } from "./categorize.js";
|
|
39
|
+
export { extractSymbols, languageOf, extToLang } from "./lang/registry.js";
|
|
40
|
+
|
|
41
|
+
// Extraction tier (AST-preferred with regex fallback; imports always regex).
|
|
42
|
+
export { extractCode } from "./extract/code.js";
|
|
43
|
+
export type { CodeInfo } from "./extract/code.js";
|
|
44
|
+
export { extractMarkdown } from "./extract/markdown.js";
|
|
45
|
+
export type { MarkdownInfo } from "./extract/markdown.js";
|
|
46
|
+
|
|
47
|
+
// AST tier (optional — a no-op without the grammar wasm sidecar).
|
|
48
|
+
export { ensureGrammars, allGrammarKeys, grammarKeyForExt, grammarReady } from "./ast/loader.js";
|
|
49
|
+
export { extractAst } from "./ast/extract.js";
|
|
50
|
+
|
|
51
|
+
// Resolution + modules + graph tier.
|
|
52
|
+
export { buildResolveContext, resolveImport, resolveDocLink } from "./resolve.js";
|
|
53
|
+
export type { Resolution, ResolveContext } from "./resolve.js";
|
|
54
|
+
export { buildModules, isTestFile, tierForPath } from "./modules.js";
|
|
55
|
+
export type { ModuleInfo } from "./modules.js";
|
|
56
|
+
export { buildGraph, uniqueSymbolDefs } from "./graph.js";
|
|
57
|
+
export { resolveCallEdges } from "./calls.js";
|
|
58
|
+
export { buildCallerIndex, enclosingSymbol, computeImportPairs } from "./callers.js";
|
|
59
|
+
export { symbolsOverview, findSymbol, findReferences } from "./query.js";
|
|
60
|
+
export { resolveUniqueSymbol, replaceSymbolBody, insertAfterSymbol, insertBeforeSymbol } from "./edit.js";
|
|
61
|
+
export type { EditResult } from "./edit.js";
|
|
62
|
+
export { writeMemory, readMemory, deleteMemory, listMemories } from "./memory.js";
|
|
63
|
+
export type { SymbolMatch, FindSymbolOptions, SymbolReferences } from "./query.js";
|
|
64
|
+
export type { CallerIndex, CallerEntry, CallerSite } from "./callers.js";
|
|
65
|
+
export { detectWorkspaces } from "./workspaces.js";
|
|
66
|
+
export type { WorkspaceInfo, WorkspacePackage, WorkspaceKind } from "./workspaces.js";
|
|
67
|
+
|
|
68
|
+
// Graph analytics.
|
|
69
|
+
export { applyCentrality, pagerankOf, betweennessOf } from "./centrality.js";
|
|
70
|
+
export { detectCommunities, communityOf } from "./community.js";
|
|
71
|
+
export { computeTestMap, isTestPath, testsForModule, untestedModules } from "./tests-map.js";
|
|
72
|
+
export type { TestMap } from "./tests-map.js";
|
|
73
|
+
export { computeSurprises, isSurprising } from "./surprise.js";
|
|
74
|
+
|
|
75
|
+
// Symbol index + machine renderers (render-to-string; consumers own persistence).
|
|
76
|
+
export { buildSymbolIndex, computeSymbolRefs, renderSymbolsJson } from "./render/symbols-json.js";
|
|
77
|
+
export { renderGraphJson } from "./render/graph-json.js";
|
|
78
|
+
|
|
79
|
+
// One-call pipeline.
|
|
80
|
+
export { buildIndexArtifacts } from "./pipeline.js";
|
|
81
|
+
export type { BuildIndexOptions, IndexArtifacts } from "./pipeline.js";
|
|
82
|
+
|
|
83
|
+
// Git utilities.
|
|
84
|
+
export {
|
|
85
|
+
headCommit,
|
|
86
|
+
isGitWorktree,
|
|
87
|
+
resolveBaseRef,
|
|
88
|
+
diffFiles,
|
|
89
|
+
diffHunks,
|
|
90
|
+
untrackedFiles,
|
|
91
|
+
gitChurn,
|
|
92
|
+
changedSince,
|
|
93
|
+
} from "./git.js";
|
|
94
|
+
export type { DiffFile, DiffSpec, Hunk } from "./git.js";
|
|
95
|
+
|
|
96
|
+
// Repo text search (ripgrep when available, pure-JS fallback otherwise).
|
|
97
|
+
export { grepRepo } from "./grep.js";
|
|
98
|
+
export type { SearchHit, GrepOptions } from "./grep.js";
|
|
99
|
+
|
|
100
|
+
// Keyless BM25 lexical search over symbols/paths/headings/summaries (issue #4).
|
|
101
|
+
export { searchIndex, subtokens } from "./bm25.js";
|
|
102
|
+
export type { SearchOptions, SearchResult } from "./bm25.js";
|
|
103
|
+
|
|
104
|
+
// Architecture rules: forbidden edges + cycles/orphans builtins (issue #4).
|
|
105
|
+
export { checkRules, parseRules } from "./rules.js";
|
|
106
|
+
export type { ArchRule, ForbiddenEdgeRule, BuiltinRule, RuleSeverity, RuleViolation } from "./rules.js";
|
|
107
|
+
|
|
108
|
+
// Caller-index recall mode (issue #7) — options for buildCallerIndex above.
|
|
109
|
+
export type { CallerIndexOptions } from "./callers.js";
|
|
110
|
+
|
|
111
|
+
// Behavioral analytics (git-history mining) + the token-budgeted repo map.
|
|
112
|
+
export { changeCoupling, rankHotspots } from "./coupling.js";
|
|
113
|
+
export type { ChangeCoupling, CouplingOptions, Hotspot } from "./coupling.js";
|
|
114
|
+
export { renderRepoMap } from "./repomap.js";
|
|
115
|
+
export { findDeadCode } from "./deadcode.js";
|
|
116
|
+
export type { DeadSymbol } from "./deadcode.js";
|
|
117
|
+
export { symbolComplexity, riskHotspots, complexityOfSource } from "./complexity.js";
|
|
118
|
+
export type { SymbolComplexity, RiskHotspot } from "./complexity.js";
|
|
119
|
+
export { renderMermaid } from "./viz.js";
|
|
120
|
+
export type { MermaidOptions } from "./viz.js";
|
|
121
|
+
export type { RepoMapOptions } from "./repomap.js";
|
|
122
|
+
|
|
123
|
+
// MCP server over stdio (also reachable as `engine.mjs mcp`).
|
|
124
|
+
export { runMcpServer } from "./mcp.js";
|
|
125
|
+
|
|
126
|
+
// General-purpose helpers shared by consumers (deterministic, dependency-free).
|
|
127
|
+
export { sha1, shortHash } from "./hash.js";
|
|
128
|
+
export { byStr, byKey } from "./sort.js";
|
|
129
|
+
export {
|
|
130
|
+
sh,
|
|
131
|
+
have,
|
|
132
|
+
slugify,
|
|
133
|
+
clip,
|
|
134
|
+
clipInline,
|
|
135
|
+
escapeRegExp,
|
|
136
|
+
foldText,
|
|
137
|
+
keywords,
|
|
138
|
+
rankedKeywords,
|
|
139
|
+
rrf,
|
|
140
|
+
} from "./util.js";
|
|
141
|
+
export type { ShResult } from "./util.js";
|
|
142
|
+
|
|
143
|
+
// CLI entry — exported, never self-triggered. This module MUST stay free of
|
|
144
|
+
// top-level side effects: consumers re-bundle engine.mjs into their own
|
|
145
|
+
// single-file CLIs, where a "am I the main module?" guard would misfire
|
|
146
|
+
// (import.meta.url inside their bundle IS their bundle) and hijack their argv.
|
|
147
|
+
// The standalone CLI/MCP entry is the static wrapper scripts/cli.mjs.
|
|
148
|
+
export { runCli } from "./engine-cli.js";
|