@maxgfr/codeindex 2.8.1 → 2.10.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 +39 -0
- package/docs/MIGRATION.md +38 -0
- package/package.json +1 -1
- package/scripts/engine.d.mts +59 -2
- package/scripts/engine.mjs +560 -32
- package/src/bm25.ts +118 -9
- package/src/embed/encode.ts +133 -0
- package/src/embed/endpoint.ts +55 -0
- package/src/embed/index.ts +125 -0
- package/src/embed/model.ts +117 -0
- package/src/embed/search.ts +90 -0
- package/src/engine-cli.ts +111 -5
- package/src/engine.ts +21 -0
- package/src/mcp.ts +48 -5
- package/src/types.ts +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,45 @@ codeindex callers --repo . # per-symbol caller index
|
|
|
75
75
|
codeindex grep 'pattern' --repo .
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
## Search
|
|
79
|
+
|
|
80
|
+
`codeindex search "<query>" --repo .` ranks files with keyless BM25 over symbol
|
|
81
|
+
names, path segments, markdown headings and summaries. A query term that
|
|
82
|
+
matches nothing in the corpus (zero document frequency) gets a deterministic
|
|
83
|
+
**trigram fuzzy fallback** — typo tolerance without embeddings: the term is
|
|
84
|
+
compared to the corpus vocabulary by character-trigram Dice similarity
|
|
85
|
+
(threshold 0.6, top-3 candidates, contribution scaled by the Dice score so a
|
|
86
|
+
near-miss always ranks below an exact hit). Terms that already match anything
|
|
87
|
+
are never touched, so an existing query stays byte-identical. Enabled by
|
|
88
|
+
default; disable with `--no-fuzzy` (CLI) or `fuzzy: false` (library/MCP
|
|
89
|
+
`SearchOptions.fuzzy`); results carry an additive `fuzzyTerms` field when the
|
|
90
|
+
fallback contributed.
|
|
91
|
+
|
|
92
|
+
### Semantic search (deterministic static-embedding tier)
|
|
93
|
+
|
|
94
|
+
`codeindex search "<query>" --repo . --semantic` RRF-fuses lexical BM25 with a
|
|
95
|
+
**keyless, byte-deterministic** embedding tier. It uses a *static* embedding
|
|
96
|
+
model (a `token → vector` lookup table, no neural forward pass, no wasm): the
|
|
97
|
+
pure-JS encoder tokenizes → mean-pools → L2-normalizes → int8-quantizes
|
|
98
|
+
(round-half-to-even), and ranking is a **pure integer dot product** — so encode
|
|
99
|
+
and the `embeddings.bin` artifact are byte-identical across builds and platforms.
|
|
100
|
+
|
|
101
|
+
It is **opt-in by asset**: with no model on disk the engine silently stays
|
|
102
|
+
lexical, and `--semantic` without a model returns lexical results on **exit 0**
|
|
103
|
+
(a stderr note only). Models are **never** shipped in the package; a model is
|
|
104
|
+
resolved from `CODEINDEX_EMBED_DIR` or `<repo>/.codeindex/models/`.
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
codeindex embed status --repo . # is a model active? (JSON)
|
|
108
|
+
codeindex embed build --repo . --out .codeindex # write embeddings.bin
|
|
109
|
+
codeindex search "http client retry" --repo . --semantic
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`codeindex index` also writes `embeddings.bin` next to `graph.json` when a model
|
|
113
|
+
is present. Fusion reuses the engine's `rrf` helper (k=60); `SCHEMA_VERSION` is
|
|
114
|
+
untouched (a dedicated `EMBED_VERSION` keys the sidecar). Full details:
|
|
115
|
+
[docs/SEMANTIC.md](./docs/SEMANTIC.md).
|
|
116
|
+
|
|
78
117
|
## Use as an MCP server
|
|
79
118
|
|
|
80
119
|
`codeindex mcp` (or `node scripts/cli.mjs mcp`) serves the engine over stdio —
|
package/docs/MIGRATION.md
CHANGED
|
@@ -55,6 +55,44 @@ does; nobody else should).
|
|
|
55
55
|
`meta: { version, schemaVersion }` so a consumer stamps its own identity into
|
|
56
56
|
artifacts it persists (ultraindex does this to keep its graph.json lineage).
|
|
57
57
|
|
|
58
|
+
## v2.9.0 — `search` trigram fuzzy fallback
|
|
59
|
+
|
|
60
|
+
New, purely additive: `SearchOptions.fuzzy?: boolean` (default `true`) and
|
|
61
|
+
`SearchResult.fuzzyTerms?: string[]` (present only when the fallback
|
|
62
|
+
contributed). A query term is only ever expanded when it has zero document
|
|
63
|
+
frequency in the corpus, so any query where every term already matched keeps
|
|
64
|
+
producing byte-identical output — **no re-pin required**, no action needed
|
|
65
|
+
from existing consumers. Pass `fuzzy: false` (or CLI `--no-fuzzy`) to opt out.
|
|
66
|
+
|
|
67
|
+
## v2.10.0 — deterministic static-embedding tier (opt-in)
|
|
68
|
+
|
|
69
|
+
New, purely additive, and **opt-in by asset presence** — nothing changes for a
|
|
70
|
+
consumer that does not place a model. `SCHEMA_VERSION` is **untouched**;
|
|
71
|
+
embeddings live in a separate `embeddings.bin` sidecar keyed by a dedicated
|
|
72
|
+
`EMBED_VERSION`, so `graph.json` / `symbols.json` consumers are unaffected and
|
|
73
|
+
**no re-pin is required**.
|
|
74
|
+
|
|
75
|
+
- Activation mirrors the grammar tier: a model asset resolved via
|
|
76
|
+
`CODEINDEX_EMBED_DIR` or `<repo>/.codeindex/models/` (`resolveEmbedModelDir`).
|
|
77
|
+
No model → the engine stays lexical, silently. Models are **never** shipped in
|
|
78
|
+
the npm tarball (`files` unchanged; pack-smoke asserts no model asset).
|
|
79
|
+
- `codeindex index` writes `embeddings.bin` next to `graph.json` **only** when a
|
|
80
|
+
model is present. `codeindex embed {status,build,pull}` and
|
|
81
|
+
`codeindex search --semantic` are the CLI surface; MCP gains `embed_status`
|
|
82
|
+
and a `semantic` property on `search`.
|
|
83
|
+
- Determinism is the point: the pure-JS encoder (fold+lowercase → wordpiece →
|
|
84
|
+
mean-pool → L2-norm → int8 round-half-to-even at a fixed 1/127 scale) and the
|
|
85
|
+
**integer** dot-product ranking make encode and `embeddings.bin` byte-identical
|
|
86
|
+
across builds and platforms — goldens are possible. Fusion with lexical uses
|
|
87
|
+
the existing `rrf` helper (k=60), never a linear score blend.
|
|
88
|
+
- New exports: `EMBED_VERSION`, `resolveEmbedModelDir`, `hasEmbedModel`,
|
|
89
|
+
`loadEmbedModel`, `encode`, `buildEmbeddingIndex`, `serializeEmbeddings`,
|
|
90
|
+
`deserializeEmbeddings`, `searchSemantic`, plus the v2.11-preview
|
|
91
|
+
`embedViaEndpoint`. See `docs/SEMANTIC.md`.
|
|
92
|
+
|
|
93
|
+
`--semantic` without a model degrades to lexical results on **exit 0** (a stderr
|
|
94
|
+
note only) — so wiring it on is safe before an asset exists.
|
|
95
|
+
|
|
58
96
|
## Per-skill mapping (what to replace with what)
|
|
59
97
|
|
|
60
98
|
| Skill | Replace | With (engine export) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maxgfr/codeindex",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "Self-contained, deterministic repo-indexing engine: walk + language detection + symbol/import extraction (tree-sitter AST with regex fallback) + import resolution + typed cross-file link-graph + analytics. Ships as a single zero-dependency engine.mjs that consumer tools vendor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.33.0",
|
package/scripts/engine.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const ENGINE_VERSION = "2.
|
|
1
|
+
declare const ENGINE_VERSION = "2.10.0";
|
|
2
2
|
declare const SCHEMA_VERSION = 4;
|
|
3
3
|
declare const EXTRACTOR_VERSION = 6;
|
|
4
4
|
type FileKind = "code" | "doc" | "config" | "asset" | "other";
|
|
@@ -487,16 +487,73 @@ declare function grepRepo(root: string, pattern: string, opts?: GrepOptions): Se
|
|
|
487
487
|
|
|
488
488
|
interface SearchOptions {
|
|
489
489
|
limit?: number;
|
|
490
|
+
fuzzy?: boolean;
|
|
490
491
|
}
|
|
491
492
|
interface SearchResult {
|
|
492
493
|
file: string;
|
|
493
494
|
score: number;
|
|
494
495
|
matchedTerms: string[];
|
|
495
496
|
topSymbols: string[];
|
|
497
|
+
fuzzyTerms?: string[];
|
|
496
498
|
}
|
|
497
499
|
declare function subtokens(raw: string): string[];
|
|
498
500
|
declare function searchIndex(scan: RepoScan, query: string, opts?: SearchOptions): SearchResult[];
|
|
499
501
|
|
|
502
|
+
declare const EMBED_VERSION = 1;
|
|
503
|
+
interface StaticEmbedModel {
|
|
504
|
+
modelId: string;
|
|
505
|
+
dim: number;
|
|
506
|
+
unk: string;
|
|
507
|
+
unkId: number;
|
|
508
|
+
vocabSize: number;
|
|
509
|
+
vocab: Map<string, number>;
|
|
510
|
+
weights: Float64Array;
|
|
511
|
+
}
|
|
512
|
+
declare function resolveEmbedModelDir(repo?: string): string | undefined;
|
|
513
|
+
declare function hasEmbedModel(repo?: string): boolean;
|
|
514
|
+
declare function loadEmbedModel(dir?: string): StaticEmbedModel | undefined;
|
|
515
|
+
declare function resolveEmbedPullUrl(): string | undefined;
|
|
516
|
+
|
|
517
|
+
declare function basicTokenize(text: string): string[];
|
|
518
|
+
declare function wordpiece(word: string, model: StaticEmbedModel): number[];
|
|
519
|
+
declare function tokenize(text: string, model: StaticEmbedModel): number[];
|
|
520
|
+
declare function roundHalfToEven(x: number): number;
|
|
521
|
+
declare function encode(model: StaticEmbedModel, text: string): Int8Array;
|
|
522
|
+
declare function intDot(a: Int8Array, b: Int8Array): number;
|
|
523
|
+
|
|
524
|
+
interface EmbeddingRecord {
|
|
525
|
+
file: string;
|
|
526
|
+
symbol?: string;
|
|
527
|
+
line?: number;
|
|
528
|
+
vec: Int8Array;
|
|
529
|
+
}
|
|
530
|
+
interface EmbeddingIndex {
|
|
531
|
+
embedVersion: number;
|
|
532
|
+
modelId: string;
|
|
533
|
+
dim: number;
|
|
534
|
+
records: EmbeddingRecord[];
|
|
535
|
+
}
|
|
536
|
+
declare function buildEmbeddingIndex(scan: RepoScan, model: StaticEmbedModel): EmbeddingIndex;
|
|
537
|
+
declare function serializeEmbeddings(index: EmbeddingIndex): Uint8Array;
|
|
538
|
+
declare function deserializeEmbeddings(bytes: Uint8Array): EmbeddingIndex;
|
|
539
|
+
|
|
540
|
+
interface SemanticSearchOptions extends SearchOptions {
|
|
541
|
+
model?: StaticEmbedModel;
|
|
542
|
+
rrfK?: number;
|
|
543
|
+
}
|
|
544
|
+
interface SemanticSearchResult extends SearchResult {
|
|
545
|
+
semanticSymbol?: string;
|
|
546
|
+
}
|
|
547
|
+
declare function searchSemantic(scan: RepoScan, query: string, index: EmbeddingIndex | undefined, opts?: SemanticSearchOptions): SemanticSearchResult[];
|
|
548
|
+
|
|
549
|
+
interface EmbedEndpointOptions {
|
|
550
|
+
url?: string;
|
|
551
|
+
timeoutMs?: number;
|
|
552
|
+
headers?: Record<string, string>;
|
|
553
|
+
}
|
|
554
|
+
declare function resolveEmbedEndpoint(opts?: EmbedEndpointOptions): string | undefined;
|
|
555
|
+
declare function embedViaEndpoint(texts: string[], opts?: EmbedEndpointOptions): Promise<number[][]>;
|
|
556
|
+
|
|
500
557
|
type RuleSeverity = "error" | "warn";
|
|
501
558
|
interface ForbiddenEdgeRule {
|
|
502
559
|
name: string;
|
|
@@ -621,4 +678,4 @@ declare function rrf<T>(lists: T[][], keyOf: (item: T) => string, k?: number): M
|
|
|
621
678
|
|
|
622
679
|
declare function runCli(argv: string[]): Promise<void>;
|
|
623
680
|
|
|
624
|
-
export { type ArchRule, type BuildIndexOptions, type BuiltinRule, type CallerEntry, type CallerIndex, type CallerIndexOptions, type CallerSite, type ChangeCoupling, type CodeInfo, type CodeSymbol, type CouplingOptions, DEFAULT_MAX_FILES, type DeadSymbol, type DiffFile, type DiffSpec, ENGINE_VERSION, EXTRACTOR_VERSION, type Edge, type EdgeKind, type EditResult, type FileCategory, type FileKind, type FileNode, type FileRecord, type FindSymbolOptions, type ForbiddenEdgeRule, type Graph, type GrepOptions, type Hotspot, type Hunk, type IgnoreRule, type IndexArtifacts, MARKDOWN_EXT, type MarkdownInfo, type MermaidOptions, type ModuleInfo, type ModuleNode, type RawRef, type RenderScipOptions, type RepoMapOptions, type RepoScan, type Resolution, type ResolveContext, type RiskHotspot, type RuleSeverity, type RuleViolation, SCHEMA_VERSION, type ScanOptions, type SearchHit, type SearchOptions, type SearchResult, type ShResult, type SurpriseEdge, type SymbolComplexity, type SymbolIndex, type SymbolMatch, type SymbolReferences, type TestMap, type Tier, type WalkOptions, type WalkResult, type WalkedFile, type WorkspaceInfo, type WorkspaceKind, type WorkspacePackage, allGrammarKeys, applyCentrality, betweennessOf, buildCallerIndex, buildGraph, buildIndexArtifacts, buildModules, buildResolveContext, buildSymbolIndex, byKey, byStr, categorize, changeCoupling, changedSince, checkRules, classify, clip, clipInline, communityOf, compileGlobs, complexityOfSource, computeImportPairs, computeSurprises, computeSymbolRefs, computeTestMap, deleteMemory, detectCommunities, detectWorkspaces, diffFiles, diffHunks, enclosingSymbol, ensureGrammars, escapeRegExp, extToLang, extractAst, extractCode, extractMarkdown, extractSymbols, findDeadCode, findReferences, findSymbol, foldText, gitChurn, grammarKeyForExt, grammarReady, grepRepo, have, headCommit, insertAfterSymbol, insertBeforeSymbol, isCode, isDoc, isGitWorktree, isIgnored, isSurprising, isTestFile, isTestPath, keywords, languageOf, listMemories, pagerankOf, parseGitignore, parseRules, rankHotspots, rankedKeywords, readMemory, readText, renderGraphJson, renderMermaid, renderRepoMap, renderScip, renderSymbolsJson, replaceSymbolBody, resolveBaseRef, resolveCallEdges, resolveDocLink, resolveImport, resolveUniqueSymbol, riskHotspots, rrf, runCli, runMcpServer, scanRepo, searchIndex, sh, sha1, shortHash, slugify, subtokens, symbolComplexity, symbolsOverview, testsForModule, tierForPath, uniqueSymbolDefs, untestedModules, untrackedFiles, walk, writeMemory };
|
|
681
|
+
export { type ArchRule, type BuildIndexOptions, type BuiltinRule, type CallerEntry, type CallerIndex, type CallerIndexOptions, type CallerSite, type ChangeCoupling, type CodeInfo, type CodeSymbol, type CouplingOptions, DEFAULT_MAX_FILES, type DeadSymbol, type DiffFile, type DiffSpec, EMBED_VERSION, ENGINE_VERSION, EXTRACTOR_VERSION, type Edge, type EdgeKind, type EditResult, type EmbedEndpointOptions, type EmbeddingIndex, type EmbeddingRecord, type FileCategory, type FileKind, type FileNode, type FileRecord, type FindSymbolOptions, type ForbiddenEdgeRule, type Graph, type GrepOptions, type Hotspot, type Hunk, type IgnoreRule, type IndexArtifacts, MARKDOWN_EXT, type MarkdownInfo, type MermaidOptions, type ModuleInfo, type ModuleNode, type RawRef, type RenderScipOptions, type RepoMapOptions, type RepoScan, type Resolution, type ResolveContext, type RiskHotspot, type RuleSeverity, type RuleViolation, SCHEMA_VERSION, type ScanOptions, type SearchHit, type SearchOptions, type SearchResult, type SemanticSearchOptions, type SemanticSearchResult, type ShResult, type StaticEmbedModel, type SurpriseEdge, type SymbolComplexity, type SymbolIndex, type SymbolMatch, type SymbolReferences, type TestMap, type Tier, type WalkOptions, type WalkResult, type WalkedFile, type WorkspaceInfo, type WorkspaceKind, type WorkspacePackage, allGrammarKeys, applyCentrality, basicTokenize, betweennessOf, buildCallerIndex, buildEmbeddingIndex, buildGraph, buildIndexArtifacts, buildModules, buildResolveContext, buildSymbolIndex, byKey, byStr, categorize, changeCoupling, changedSince, checkRules, classify, clip, clipInline, communityOf, compileGlobs, complexityOfSource, computeImportPairs, computeSurprises, computeSymbolRefs, computeTestMap, deleteMemory, deserializeEmbeddings, detectCommunities, detectWorkspaces, diffFiles, diffHunks, embedViaEndpoint, enclosingSymbol, encode, ensureGrammars, escapeRegExp, extToLang, extractAst, extractCode, extractMarkdown, extractSymbols, findDeadCode, findReferences, findSymbol, foldText, gitChurn, grammarKeyForExt, grammarReady, grepRepo, hasEmbedModel, have, headCommit, insertAfterSymbol, insertBeforeSymbol, intDot, isCode, isDoc, isGitWorktree, isIgnored, isSurprising, isTestFile, isTestPath, keywords, languageOf, listMemories, loadEmbedModel, pagerankOf, parseGitignore, parseRules, rankHotspots, rankedKeywords, readMemory, readText, renderGraphJson, renderMermaid, renderRepoMap, renderScip, renderSymbolsJson, replaceSymbolBody, resolveBaseRef, resolveCallEdges, resolveDocLink, resolveEmbedEndpoint, resolveEmbedModelDir, resolveEmbedPullUrl, resolveImport, resolveUniqueSymbol, riskHotspots, roundHalfToEven, rrf, runCli, runMcpServer, scanRepo, searchIndex, searchSemantic, serializeEmbeddings, sh, sha1, shortHash, slugify, subtokens, symbolComplexity, symbolsOverview, testsForModule, tierForPath, tokenize, uniqueSymbolDefs, untestedModules, untrackedFiles, walk, wordpiece, writeMemory };
|