projscan 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -67
- package/dist/analyzers/deadCodeCheck.d.ts +2 -2
- package/dist/analyzers/deadCodeCheck.js +4 -4
- package/dist/analyzers/unusedDependencyCheck.js +1 -1
- package/dist/cli/index.js +95 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/core/ast.d.ts +1 -1
- package/dist/core/ast.js +2 -2
- package/dist/core/auditRunner.d.ts +1 -1
- package/dist/core/auditRunner.js +6 -6
- package/dist/core/coverageJoin.d.ts +1 -1
- package/dist/core/coverageJoin.js +1 -1
- package/dist/core/coverageParser.js +3 -3
- package/dist/core/dependencyAnalyzer.js +6 -6
- package/dist/core/embeddings.d.ts +39 -0
- package/dist/core/embeddings.js +117 -0
- package/dist/core/embeddings.js.map +1 -0
- package/dist/core/fileInspector.js +6 -6
- package/dist/core/hotspotAnalyzer.js +2 -2
- package/dist/core/importGraph.d.ts +1 -1
- package/dist/core/importGraph.js +1 -1
- package/dist/core/indexCache.d.ts +2 -2
- package/dist/core/indexCache.js +4 -4
- package/dist/core/outdatedDetector.d.ts +1 -1
- package/dist/core/outdatedDetector.js +1 -1
- package/dist/core/searchIndex.js +2 -2
- package/dist/core/semanticSearch.d.ts +53 -0
- package/dist/core/semanticSearch.js +217 -0
- package/dist/core/semanticSearch.js.map +1 -0
- package/dist/core/upgradePreview.js +1 -1
- package/dist/fixes/prettierFix.js +1 -1
- package/dist/fixes/testFix.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/chunker.d.ts +1 -1
- package/dist/mcp/chunker.js +1 -1
- package/dist/mcp/pagination.d.ts +2 -2
- package/dist/mcp/pagination.js +2 -2
- package/dist/mcp/progress.d.ts +5 -4
- package/dist/mcp/progress.js +7 -30
- package/dist/mcp/progress.js.map +1 -1
- package/dist/mcp/prompts.js +3 -3
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/tokenBudget.d.ts +1 -1
- package/dist/mcp/tokenBudget.js +2 -2
- package/dist/mcp/tools.js +92 -12
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reporters/consoleReporter.js +11 -11
- package/dist/reporters/markdownReporter.js +14 -14
- package/dist/reporters/sarifReporter.js +1 -1
- package/dist/utils/banner.d.ts +3 -3
- package/dist/utils/banner.js +12 -12
- package/dist/utils/banner.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/packageJsonLocator.d.ts +1 -1
- package/dist/utils/packageJsonLocator.js +1 -1
- package/package.json +11 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { CodeGraph } from './codeGraph.js';
|
|
2
2
|
/**
|
|
3
3
|
* Load a previously cached code graph, if present and valid. Returns undefined
|
|
4
|
-
* when there's no cache or the cache is incompatible
|
|
4
|
+
* when there's no cache or the cache is incompatible - caller should rebuild.
|
|
5
5
|
*/
|
|
6
6
|
export declare function loadCachedGraph(rootPath: string): Promise<CodeGraph | undefined>;
|
|
7
7
|
/**
|
|
8
|
-
* Persist the graph. Creates .projscan-cache/ if needed. Swallows errors
|
|
8
|
+
* Persist the graph. Creates .projscan-cache/ if needed. Swallows errors -
|
|
9
9
|
* caching is best-effort, never blocks a run.
|
|
10
10
|
*/
|
|
11
11
|
export declare function saveCachedGraph(rootPath: string, graph: CodeGraph): Promise<void>;
|
package/dist/core/indexCache.js
CHANGED
|
@@ -5,7 +5,7 @@ const CACHE_FILE = 'graph.json';
|
|
|
5
5
|
const CACHE_VERSION = 1;
|
|
6
6
|
/**
|
|
7
7
|
* Load a previously cached code graph, if present and valid. Returns undefined
|
|
8
|
-
* when there's no cache or the cache is incompatible
|
|
8
|
+
* when there's no cache or the cache is incompatible - caller should rebuild.
|
|
9
9
|
*/
|
|
10
10
|
export async function loadCachedGraph(rootPath) {
|
|
11
11
|
const cachePath = path.join(rootPath, CACHE_DIR, CACHE_FILE);
|
|
@@ -38,7 +38,7 @@ export async function loadCachedGraph(rootPath) {
|
|
|
38
38
|
parseReason: entry.parseReason,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
// Derived indexes are rebuilt on load
|
|
41
|
+
// Derived indexes are rebuilt on load - cheap compared to re-parsing.
|
|
42
42
|
// Return a partial graph the caller will rehydrate via buildCodeGraph.
|
|
43
43
|
return {
|
|
44
44
|
files,
|
|
@@ -49,7 +49,7 @@ export async function loadCachedGraph(rootPath) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
* Persist the graph. Creates .projscan-cache/ if needed. Swallows errors
|
|
52
|
+
* Persist the graph. Creates .projscan-cache/ if needed. Swallows errors -
|
|
53
53
|
* caching is best-effort, never blocks a run.
|
|
54
54
|
*/
|
|
55
55
|
export async function saveCachedGraph(rootPath, graph) {
|
|
@@ -82,7 +82,7 @@ export async function saveCachedGraph(rootPath, graph) {
|
|
|
82
82
|
await fs.writeFile(gitignorePath, '*\n', 'utf-8');
|
|
83
83
|
}
|
|
84
84
|
catch {
|
|
85
|
-
// ignore
|
|
85
|
+
// ignore - cache is best-effort
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
export async function invalidateCache(rootPath) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OutdatedReport } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Offline outdated check
|
|
3
|
+
* Offline outdated check - compares the version declared in package.json
|
|
4
4
|
* to the version installed under node_modules/<pkg>/package.json.
|
|
5
5
|
*
|
|
6
6
|
* Does not hit the npm registry. `latest` is filled in only when a node_modules
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { drift as semverDrift } from '../utils/semver.js';
|
|
4
4
|
/**
|
|
5
|
-
* Offline outdated check
|
|
5
|
+
* Offline outdated check - compares the version declared in package.json
|
|
6
6
|
* to the version installed under node_modules/<pkg>/package.json.
|
|
7
7
|
*
|
|
8
8
|
* Does not hit the npm registry. `latest` is filled in only when a node_modules
|
package/dist/core/searchIndex.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'node:path';
|
|
|
5
5
|
*
|
|
6
6
|
* We index three fields per file with different weights:
|
|
7
7
|
* - content (body tokens, BM25 baseline)
|
|
8
|
-
* - symbols (export names
|
|
8
|
+
* - symbols (export names - most informative for code search)
|
|
9
9
|
* - path (file path tokens)
|
|
10
10
|
*
|
|
11
11
|
* Scoring:
|
|
@@ -191,7 +191,7 @@ export function tokenize(input) {
|
|
|
191
191
|
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');
|
|
192
192
|
const parts = camelSplit.split(/[_\s]+/).filter(Boolean);
|
|
193
193
|
for (const part of parts) {
|
|
194
|
-
// Split embedded digits from letters
|
|
194
|
+
// Split embedded digits from letters - e.g. "v1api" → "v", "1", "api"
|
|
195
195
|
const subparts = part.split(/(\d+)/).filter(Boolean);
|
|
196
196
|
for (const sp of subparts) {
|
|
197
197
|
const lower = sp.toLowerCase();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { FileEntry } from '../types.js';
|
|
2
|
+
export interface SemanticEntry {
|
|
3
|
+
relativePath: string;
|
|
4
|
+
contentHash: string;
|
|
5
|
+
mtimeMs: number;
|
|
6
|
+
vector: Float32Array;
|
|
7
|
+
}
|
|
8
|
+
export interface SemanticIndex {
|
|
9
|
+
model: string;
|
|
10
|
+
dim: number;
|
|
11
|
+
entries: Map<string, SemanticEntry>;
|
|
12
|
+
}
|
|
13
|
+
export interface BuildOptions {
|
|
14
|
+
model?: string;
|
|
15
|
+
rebuild?: boolean;
|
|
16
|
+
onProgress?: (done: number, total: number, message?: string) => void;
|
|
17
|
+
onFirstLoad?: (message: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface SemanticHit {
|
|
20
|
+
file: string;
|
|
21
|
+
score: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build (or refresh) a semantic index. Reuses cached embeddings for files
|
|
25
|
+
* whose mtime AND content hash match - both guards are necessary because
|
|
26
|
+
* git checkouts can preserve mtime while swapping content.
|
|
27
|
+
*
|
|
28
|
+
* Returns null if the peer dep isn't available.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildSemanticIndex(rootPath: string, files: FileEntry[], options?: BuildOptions): Promise<SemanticIndex | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Query a semantic index. Returns top-K files by cosine similarity.
|
|
33
|
+
* Returns an empty array if no files are indexed.
|
|
34
|
+
*/
|
|
35
|
+
export declare function semanticSearch(index: SemanticIndex, query: string, options?: {
|
|
36
|
+
limit?: number;
|
|
37
|
+
onFirstLoad?: (m: string) => void;
|
|
38
|
+
}): Promise<SemanticHit[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Reciprocal Rank Fusion (RRF) combines two ranked lists into one. Well-
|
|
41
|
+
* established way to merge lexical (BM25) and semantic results without
|
|
42
|
+
* needing to calibrate scale between the two scoring systems.
|
|
43
|
+
*
|
|
44
|
+
* score(doc) = sum over lists L of 1 / (k + rank_L(doc))
|
|
45
|
+
*
|
|
46
|
+
* k = 60 is the standard constant.
|
|
47
|
+
*/
|
|
48
|
+
export declare function reciprocalRankFusion(lists: Array<Array<{
|
|
49
|
+
file: string;
|
|
50
|
+
}>>, k?: number): Array<{
|
|
51
|
+
file: string;
|
|
52
|
+
score: number;
|
|
53
|
+
}>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { embedBatch, embedText, cosineSimilarity, isSemanticAvailable, DEFAULT_MODEL, EMBEDDING_DIM, } from './embeddings.js';
|
|
5
|
+
/**
|
|
6
|
+
* File-level semantic search over source files.
|
|
7
|
+
*
|
|
8
|
+
* v1 design decisions:
|
|
9
|
+
* - One embedding per file. Sub-file (per-export, per-function) chunking
|
|
10
|
+
* is a bigger project; file-level is sufficient to answer "which file
|
|
11
|
+
* implements X?"
|
|
12
|
+
* - Input text is the first 4KB of the file (captures most semantic
|
|
13
|
+
* signal without blowing the context window of small embedding models).
|
|
14
|
+
* - Path is prepended as a weak signal: `<file>\n\n<content>`.
|
|
15
|
+
* - Cache persisted to .projscan-cache/embeddings.bin, keyed by
|
|
16
|
+
* (model, file mtime, content hash). Invalidates on any of those changing.
|
|
17
|
+
*/
|
|
18
|
+
const CACHE_DIR = '.projscan-cache';
|
|
19
|
+
const CACHE_FILE = 'embeddings.bin';
|
|
20
|
+
const CACHE_VERSION = 1;
|
|
21
|
+
const MAX_FILE_BYTES_FOR_EMBED = 4 * 1024;
|
|
22
|
+
const MAX_FILE_SIZE = 512 * 1024;
|
|
23
|
+
const INDEXABLE_EXTS = new Set([
|
|
24
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts',
|
|
25
|
+
'.py', '.go', '.rb', '.java', '.rs', '.php',
|
|
26
|
+
'.md', '.mdx',
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Build (or refresh) a semantic index. Reuses cached embeddings for files
|
|
30
|
+
* whose mtime AND content hash match - both guards are necessary because
|
|
31
|
+
* git checkouts can preserve mtime while swapping content.
|
|
32
|
+
*
|
|
33
|
+
* Returns null if the peer dep isn't available.
|
|
34
|
+
*/
|
|
35
|
+
export async function buildSemanticIndex(rootPath, files, options = {}) {
|
|
36
|
+
const available = await isSemanticAvailable();
|
|
37
|
+
if (!available)
|
|
38
|
+
return null;
|
|
39
|
+
const model = options.model ?? DEFAULT_MODEL;
|
|
40
|
+
const cached = options.rebuild ? null : await loadCache(rootPath, model);
|
|
41
|
+
const entries = cached?.entries ?? new Map();
|
|
42
|
+
const indexable = files.filter((f) => INDEXABLE_EXTS.has(f.extension) && f.sizeBytes <= MAX_FILE_SIZE);
|
|
43
|
+
// Determine which files still need embedding
|
|
44
|
+
const toEmbed = [];
|
|
45
|
+
const keep = new Set();
|
|
46
|
+
for (const file of indexable) {
|
|
47
|
+
const abs = path.isAbsolute(file.absolutePath)
|
|
48
|
+
? file.absolutePath
|
|
49
|
+
: path.resolve(rootPath, file.relativePath);
|
|
50
|
+
let content;
|
|
51
|
+
try {
|
|
52
|
+
content = await fs.readFile(abs, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const text = `${file.relativePath}\n\n${content.slice(0, MAX_FILE_BYTES_FOR_EMBED)}`;
|
|
58
|
+
const hash = sha256(text);
|
|
59
|
+
const existing = entries.get(file.relativePath);
|
|
60
|
+
let mtimeMs = 0;
|
|
61
|
+
try {
|
|
62
|
+
const stat = await fs.stat(abs);
|
|
63
|
+
mtimeMs = stat.mtimeMs;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// ignore
|
|
67
|
+
}
|
|
68
|
+
if (existing && existing.contentHash === hash && existing.mtimeMs === mtimeMs) {
|
|
69
|
+
keep.add(file.relativePath);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
toEmbed.push({ file, hash, text });
|
|
73
|
+
keep.add(file.relativePath);
|
|
74
|
+
}
|
|
75
|
+
// Drop cached entries for files that no longer exist
|
|
76
|
+
for (const key of [...entries.keys()]) {
|
|
77
|
+
if (!keep.has(key))
|
|
78
|
+
entries.delete(key);
|
|
79
|
+
}
|
|
80
|
+
if (toEmbed.length === 0) {
|
|
81
|
+
return { model, dim: cached?.dim ?? EMBEDDING_DIM, entries };
|
|
82
|
+
}
|
|
83
|
+
options.onProgress?.(0, toEmbed.length, 'embedding files');
|
|
84
|
+
// Batch embeddings in chunks of 32 to cap peak memory
|
|
85
|
+
const BATCH = 32;
|
|
86
|
+
for (let i = 0; i < toEmbed.length; i += BATCH) {
|
|
87
|
+
const slice = toEmbed.slice(i, i + BATCH);
|
|
88
|
+
const vectors = await embedBatch(slice.map((s) => s.text), { model, onFirstLoad: options.onFirstLoad });
|
|
89
|
+
if (!vectors) {
|
|
90
|
+
// Peer loaded at start of the build but embedBatch now returns null.
|
|
91
|
+
// This is rare (module unloaded, OOM, etc.); log to stderr so operators
|
|
92
|
+
// can diagnose instead of silently losing the semantic capability.
|
|
93
|
+
process.stderr.write(`[projscan] semantic index build aborted at batch ${Math.floor(i / BATCH) + 1}/${Math.ceil(toEmbed.length / BATCH)} (peer dep became unavailable)\n`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
for (let j = 0; j < slice.length; j++) {
|
|
97
|
+
const s = slice[j];
|
|
98
|
+
const abs = path.isAbsolute(s.file.absolutePath)
|
|
99
|
+
? s.file.absolutePath
|
|
100
|
+
: path.resolve(rootPath, s.file.relativePath);
|
|
101
|
+
let mtimeMs = 0;
|
|
102
|
+
try {
|
|
103
|
+
mtimeMs = (await fs.stat(abs)).mtimeMs;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// ignore
|
|
107
|
+
}
|
|
108
|
+
entries.set(s.file.relativePath, {
|
|
109
|
+
relativePath: s.file.relativePath,
|
|
110
|
+
contentHash: s.hash,
|
|
111
|
+
mtimeMs,
|
|
112
|
+
vector: vectors[j],
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
options.onProgress?.(Math.min(i + BATCH, toEmbed.length), toEmbed.length);
|
|
116
|
+
}
|
|
117
|
+
const index = {
|
|
118
|
+
model,
|
|
119
|
+
dim: EMBEDDING_DIM,
|
|
120
|
+
entries,
|
|
121
|
+
};
|
|
122
|
+
await saveCache(rootPath, index).catch(() => {
|
|
123
|
+
// best-effort - don't fail the search if cache write fails
|
|
124
|
+
});
|
|
125
|
+
return index;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Query a semantic index. Returns top-K files by cosine similarity.
|
|
129
|
+
* Returns an empty array if no files are indexed.
|
|
130
|
+
*/
|
|
131
|
+
export async function semanticSearch(index, query, options = {}) {
|
|
132
|
+
if (index.entries.size === 0)
|
|
133
|
+
return [];
|
|
134
|
+
const vector = await embedText(query, { model: index.model, onFirstLoad: options.onFirstLoad });
|
|
135
|
+
if (!vector)
|
|
136
|
+
return [];
|
|
137
|
+
const limit = Math.max(1, Math.min(500, options.limit ?? 20));
|
|
138
|
+
const scored = [];
|
|
139
|
+
for (const entry of index.entries.values()) {
|
|
140
|
+
const score = cosineSimilarity(vector, entry.vector);
|
|
141
|
+
scored.push({ file: entry.relativePath, score: Math.round(score * 1000) / 1000 });
|
|
142
|
+
}
|
|
143
|
+
scored.sort((a, b) => b.score - a.score);
|
|
144
|
+
return scored.slice(0, limit);
|
|
145
|
+
}
|
|
146
|
+
async function loadCache(rootPath, expectedModel) {
|
|
147
|
+
const cachePath = path.join(rootPath, CACHE_DIR, CACHE_FILE);
|
|
148
|
+
let raw;
|
|
149
|
+
try {
|
|
150
|
+
raw = await fs.readFile(cachePath, 'utf-8');
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
let parsed;
|
|
156
|
+
try {
|
|
157
|
+
parsed = JSON.parse(raw);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
if (parsed.version !== CACHE_VERSION || parsed.model !== expectedModel)
|
|
163
|
+
return null;
|
|
164
|
+
const entries = new Map();
|
|
165
|
+
for (const e of parsed.entries) {
|
|
166
|
+
entries.set(e.relativePath, {
|
|
167
|
+
relativePath: e.relativePath,
|
|
168
|
+
contentHash: e.contentHash,
|
|
169
|
+
mtimeMs: e.mtimeMs,
|
|
170
|
+
vector: new Float32Array(e.vector),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return { model: parsed.model, dim: parsed.dim, entries };
|
|
174
|
+
}
|
|
175
|
+
async function saveCache(rootPath, index) {
|
|
176
|
+
const dir = path.join(rootPath, CACHE_DIR);
|
|
177
|
+
await fs.mkdir(dir, { recursive: true });
|
|
178
|
+
const payload = {
|
|
179
|
+
version: CACHE_VERSION,
|
|
180
|
+
model: index.model,
|
|
181
|
+
dim: index.dim,
|
|
182
|
+
entries: [...index.entries.values()].map((e) => ({
|
|
183
|
+
relativePath: e.relativePath,
|
|
184
|
+
contentHash: e.contentHash,
|
|
185
|
+
mtimeMs: e.mtimeMs,
|
|
186
|
+
vector: [...e.vector],
|
|
187
|
+
})),
|
|
188
|
+
};
|
|
189
|
+
await fs.writeFile(path.join(dir, CACHE_FILE), JSON.stringify(payload), 'utf-8');
|
|
190
|
+
}
|
|
191
|
+
function sha256(s) {
|
|
192
|
+
return crypto.createHash('sha256').update(s).digest('hex').slice(0, 16);
|
|
193
|
+
}
|
|
194
|
+
// ── Hybrid ranking ────────────────────────────────────────
|
|
195
|
+
/**
|
|
196
|
+
* Reciprocal Rank Fusion (RRF) combines two ranked lists into one. Well-
|
|
197
|
+
* established way to merge lexical (BM25) and semantic results without
|
|
198
|
+
* needing to calibrate scale between the two scoring systems.
|
|
199
|
+
*
|
|
200
|
+
* score(doc) = sum over lists L of 1 / (k + rank_L(doc))
|
|
201
|
+
*
|
|
202
|
+
* k = 60 is the standard constant.
|
|
203
|
+
*/
|
|
204
|
+
export function reciprocalRankFusion(lists, k = 60) {
|
|
205
|
+
const scores = new Map();
|
|
206
|
+
for (const list of lists) {
|
|
207
|
+
for (let rank = 0; rank < list.length; rank++) {
|
|
208
|
+
const file = list[rank].file;
|
|
209
|
+
const contribution = 1 / (k + rank + 1);
|
|
210
|
+
scores.set(file, (scores.get(file) ?? 0) + contribution);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return [...scores.entries()]
|
|
214
|
+
.map(([file, score]) => ({ file, score: Math.round(score * 10000) / 10000 }))
|
|
215
|
+
.sort((a, b) => b.score - a.score);
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=semanticSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticSearch.js","sourceRoot":"","sources":["../../src/core/semanticSearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ export async function previewUpgrade(rootPath, pkgName, files) {
|
|
|
31
31
|
if (!installed) {
|
|
32
32
|
return {
|
|
33
33
|
available: false,
|
|
34
|
-
reason: `Package "${pkgName}" not installed
|
|
34
|
+
reason: `Package "${pkgName}" not installed - run npm install and retry`,
|
|
35
35
|
name: pkgName,
|
|
36
36
|
declared: declaredVersions,
|
|
37
37
|
installed: null,
|
|
@@ -34,7 +34,7 @@ export const prettierFix = {
|
|
|
34
34
|
}
|
|
35
35
|
catch (err) {
|
|
36
36
|
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
|
|
37
|
-
return; // No package.json
|
|
37
|
+
return; // No package.json - nothing to update
|
|
38
38
|
}
|
|
39
39
|
throw err; // Re-throw JSON parse errors or unexpected failures
|
|
40
40
|
}
|
package/dist/fixes/testFix.js
CHANGED
|
@@ -30,7 +30,7 @@ export const testFix = {
|
|
|
30
30
|
}
|
|
31
31
|
catch (err) {
|
|
32
32
|
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
|
|
33
|
-
return; // No package.json
|
|
33
|
+
return; // No package.json - nothing to update
|
|
34
34
|
}
|
|
35
35
|
throw err; // Re-throw JSON parse errors or unexpected failures
|
|
36
36
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export { paginate, encodeCursor, decodeCursor, listChecksum, readPageParams } fr
|
|
|
19
19
|
export { toContentBlocks } from './mcp/chunker.js';
|
|
20
20
|
export { emitProgress, withProgress } from './mcp/progress.js';
|
|
21
21
|
export { buildSearchIndex, search, tokenize, expandQuery, attachExcerpts, } from './core/searchIndex.js';
|
|
22
|
+
export { isSemanticAvailable, embedText, embedBatch, cosineSimilarity, DEFAULT_MODEL, EMBEDDING_DIM, } from './core/embeddings.js';
|
|
23
|
+
export { buildSemanticIndex, semanticSearch, reciprocalRankFusion, } from './core/semanticSearch.js';
|
|
22
24
|
export { findDependencyLines } from './utils/packageJsonLocator.js';
|
|
23
25
|
export { parse as parseSemver, compare as compareSemver, drift as semverDrift } from './utils/semver.js';
|
|
24
26
|
export { walkFiles } from './utils/fileWalker.js';
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,8 @@ export { paginate, encodeCursor, decodeCursor, listChecksum, readPageParams } fr
|
|
|
19
19
|
export { toContentBlocks } from './mcp/chunker.js';
|
|
20
20
|
export { emitProgress, withProgress } from './mcp/progress.js';
|
|
21
21
|
export { buildSearchIndex, search, tokenize, expandQuery, attachExcerpts, } from './core/searchIndex.js';
|
|
22
|
+
export { isSemanticAvailable, embedText, embedBatch, cosineSimilarity, DEFAULT_MODEL, EMBEDDING_DIM, } from './core/embeddings.js';
|
|
23
|
+
export { buildSemanticIndex, semanticSearch, reciprocalRankFusion, } from './core/semanticSearch.js';
|
|
22
24
|
export { findDependencyLines } from './utils/packageJsonLocator.js';
|
|
23
25
|
export { parse as parseSemver, compare as compareSemver, drift as semverDrift } from './utils/semver.js';
|
|
24
26
|
export { walkFiles } from './utils/fileWalker.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvG,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,OAAO,IAAI,aAAa,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvG,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,OAAO,IAAI,aAAa,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/mcp/chunker.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* emit chunk blocks each containing a slice of the array.
|
|
9
9
|
* - Otherwise, emit a single block.
|
|
10
10
|
*
|
|
11
|
-
* Chunk size defaults to 20 records per block
|
|
11
|
+
* Chunk size defaults to 20 records per block - small enough to be a
|
|
12
12
|
* meaningful streaming unit, big enough to avoid pathological block counts.
|
|
13
13
|
*/
|
|
14
14
|
export interface ContentBlock {
|
package/dist/mcp/chunker.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* emit chunk blocks each containing a slice of the array.
|
|
9
9
|
* - Otherwise, emit a single block.
|
|
10
10
|
*
|
|
11
|
-
* Chunk size defaults to 20 records per block
|
|
11
|
+
* Chunk size defaults to 20 records per block - small enough to be a
|
|
12
12
|
* meaningful streaming unit, big enough to avoid pathological block counts.
|
|
13
13
|
*/
|
|
14
14
|
const DEFAULT_CHUNK_SIZE = 20;
|
package/dist/mcp/pagination.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface Page<T> {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Slice an array into a page. `checksum` should be a cheap identifier of
|
|
22
|
-
* the result-set shape (e.g., `items.length`)
|
|
22
|
+
* the result-set shape (e.g., `items.length`) - if it mismatches a cursor's
|
|
23
23
|
* captured checksum we treat the page as fresh (offset=0) rather than risk
|
|
24
24
|
* returning stale offsets.
|
|
25
25
|
*/
|
|
@@ -31,7 +31,7 @@ interface DecodedCursor {
|
|
|
31
31
|
export declare function encodeCursor(cursor: DecodedCursor): string;
|
|
32
32
|
export declare function decodeCursor(cursor?: string): DecodedCursor | null;
|
|
33
33
|
/**
|
|
34
|
-
* Compute a lightweight checksum for a list. Deliberately weak
|
|
34
|
+
* Compute a lightweight checksum for a list. Deliberately weak - we want
|
|
35
35
|
* cursor invalidation on shape changes (length) but not on micro-changes
|
|
36
36
|
* within items (scores that shift slightly between runs). Agents already
|
|
37
37
|
* handle eventual consistency.
|
package/dist/mcp/pagination.js
CHANGED
|
@@ -12,7 +12,7 @@ const DEFAULT_PAGE_SIZE = 50;
|
|
|
12
12
|
const MAX_PAGE_SIZE = 500;
|
|
13
13
|
/**
|
|
14
14
|
* Slice an array into a page. `checksum` should be a cheap identifier of
|
|
15
|
-
* the result-set shape (e.g., `items.length`)
|
|
15
|
+
* the result-set shape (e.g., `items.length`) - if it mismatches a cursor's
|
|
16
16
|
* captured checksum we treat the page as fresh (offset=0) rather than risk
|
|
17
17
|
* returning stale offsets.
|
|
18
18
|
*/
|
|
@@ -49,7 +49,7 @@ export function decodeCursor(cursor) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
* Compute a lightweight checksum for a list. Deliberately weak
|
|
52
|
+
* Compute a lightweight checksum for a list. Deliberately weak - we want
|
|
53
53
|
* cursor invalidation on shape changes (length) but not on micro-changes
|
|
54
54
|
* within items (scores that shift slightly between runs). Agents already
|
|
55
55
|
* handle eventual consistency.
|
package/dist/mcp/progress.d.ts
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Per MCP spec, a client that wants progress sets `_meta.progressToken` on
|
|
5
5
|
* the tool-call request. We capture it at dispatch time and expose a
|
|
6
|
-
* `notify(progress, total?)` callback to the tool handler via
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* `notify(progress, total?, message?)` callback to the tool handler via an
|
|
7
|
+
* AsyncLocalStorage context - which means concurrent tool calls get their
|
|
8
|
+
* own isolated emitters (the naive module-level-variable approach had tools
|
|
9
|
+
* clobbering each other's progress streams under pipelined requests).
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* Wire format (MCP 2024-11-05 + 2025-03-26):
|
|
11
12
|
* { "jsonrpc": "2.0", "method": "notifications/progress",
|
|
12
13
|
* "params": { "progressToken": <token>, "progress": <n>, "total"?: <n>, "message"?: "..." } }
|
|
13
14
|
*/
|
package/dist/mcp/progress.js
CHANGED
|
@@ -1,39 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
* Progress notification plumbing for long-running MCP tools.
|
|
3
|
-
*
|
|
4
|
-
* Per MCP spec, a client that wants progress sets `_meta.progressToken` on
|
|
5
|
-
* the tool-call request. We capture it at dispatch time and expose a
|
|
6
|
-
* `notify(progress, total?)` callback to the tool handler via the rootPath
|
|
7
|
-
* extension — which is awkward but keeps the handler signature unchanged
|
|
8
|
-
* for tools that don't care.
|
|
9
|
-
*
|
|
10
|
-
* The notification wire format (MCP 2024-11-05 + 2025-03-26):
|
|
11
|
-
* { "jsonrpc": "2.0", "method": "notifications/progress",
|
|
12
|
-
* "params": { "progressToken": <token>, "progress": <n>, "total"?: <n>, "message"?: "..." } }
|
|
13
|
-
*/
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
14
2
|
const NOOP = () => { };
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
const emitters = new Map();
|
|
3
|
+
// AsyncLocalStorage isolates the emitter per async context. Each tools/call
|
|
4
|
+
// dispatch starts a fresh context via `withProgress`, so concurrent tool
|
|
5
|
+
// calls never see each other's emitters.
|
|
6
|
+
const storage = new AsyncLocalStorage();
|
|
21
7
|
export function withProgress(emit, fn) {
|
|
22
8
|
if (!emit)
|
|
23
9
|
return fn();
|
|
24
|
-
|
|
25
|
-
emitters.set(key, emit);
|
|
26
|
-
currentKey = key;
|
|
27
|
-
return fn().finally(() => {
|
|
28
|
-
emitters.delete(key);
|
|
29
|
-
currentKey = null;
|
|
30
|
-
});
|
|
10
|
+
return storage.run(emit, fn);
|
|
31
11
|
}
|
|
32
|
-
let currentKey = null;
|
|
33
12
|
export function emitProgress(progress, total, message) {
|
|
34
|
-
|
|
35
|
-
return;
|
|
36
|
-
const emit = emitters.get(currentKey);
|
|
13
|
+
const emit = storage.getStore();
|
|
37
14
|
if (!emit)
|
|
38
15
|
return;
|
|
39
16
|
try {
|
package/dist/mcp/progress.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/mcp/progress.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/mcp/progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAmBrD,MAAM,IAAI,GAAoB,GAAG,EAAE,GAAE,CAAC,CAAC;AAEvC,4EAA4E;AAC5E,yEAAyE;AACzE,yCAAyC;AACzC,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAmB,CAAC;AAEzD,MAAM,UAAU,YAAY,CAC1B,IAAiC,EACjC,EAAoB;IAEpB,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,CAAC;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,KAAc,EAAE,OAAgB;IAC7E,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;IAC7D,CAAC;AACH,CAAC;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/mcp/prompts.js
CHANGED
|
@@ -53,10 +53,10 @@ async function prioritizeRefactoringPrompt(args, rootPath) {
|
|
|
53
53
|
const ownership = h.busFactorOne && h.primaryAuthor
|
|
54
54
|
? ` [BUS FACTOR 1: ${h.primaryAuthor}]`
|
|
55
55
|
: '';
|
|
56
|
-
return `${i + 1}. ${h.relativePath}
|
|
56
|
+
return `${i + 1}. ${h.relativePath} - risk ${h.riskScore.toFixed(1)} (${reasons})${ownership}`;
|
|
57
57
|
})
|
|
58
58
|
.join('\n')
|
|
59
|
-
: '(no hotspots available
|
|
59
|
+
: '(no hotspots available - project may not be a git repository)';
|
|
60
60
|
const topIssues = issues
|
|
61
61
|
.slice(0, 15)
|
|
62
62
|
.map((issue) => `- [${issue.severity}] ${issue.title}`)
|
|
@@ -104,7 +104,7 @@ async function investigateFilePrompt(args, rootPath) {
|
|
|
104
104
|
'Explain in order:',
|
|
105
105
|
'1. What this file does and how it fits in the codebase.',
|
|
106
106
|
'2. What is risky about it right now (cite evidence from the report).',
|
|
107
|
-
'3. Concrete next actions
|
|
107
|
+
'3. Concrete next actions - questions to ask, tests to add, or refactors to attempt.',
|
|
108
108
|
'4. Who to involve (based on ownership, if available).',
|
|
109
109
|
].join('\n');
|
|
110
110
|
return {
|
package/dist/mcp/server.js
CHANGED
|
@@ -32,7 +32,7 @@ export function createMcpServer(rootPath, options = {}) {
|
|
|
32
32
|
let initialized = false;
|
|
33
33
|
async function dispatch(request) {
|
|
34
34
|
const id = request.id ?? null;
|
|
35
|
-
// Notifications (no id)
|
|
35
|
+
// Notifications (no id) - no response expected.
|
|
36
36
|
const isNotification = request.id === undefined || request.id === null;
|
|
37
37
|
try {
|
|
38
38
|
switch (request.method) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Rough token estimator and record-aware truncator for MCP tool output.
|
|
3
3
|
*
|
|
4
4
|
* Uses the widely-used "~4 chars per token" heuristic. Good enough for
|
|
5
|
-
* prioritization
|
|
5
|
+
* prioritization - absolute accuracy is not required.
|
|
6
6
|
*/
|
|
7
7
|
export declare const CHARS_PER_TOKEN = 4;
|
|
8
8
|
export declare function estimateTokens(value: string): number;
|
package/dist/mcp/tokenBudget.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Rough token estimator and record-aware truncator for MCP tool output.
|
|
3
3
|
*
|
|
4
4
|
* Uses the widely-used "~4 chars per token" heuristic. Good enough for
|
|
5
|
-
* prioritization
|
|
5
|
+
* prioritization - absolute accuracy is not required.
|
|
6
6
|
*/
|
|
7
7
|
export const CHARS_PER_TOKEN = 4;
|
|
8
8
|
export function estimateTokens(value) {
|
|
@@ -55,7 +55,7 @@ function safeStringify(value) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Find top-level array field names
|
|
58
|
+
* Find top-level array field names - our convention is that MCP results
|
|
59
59
|
* expose a primary array (hotspots, entries, findings, files) worth
|
|
60
60
|
* trimming before scalar fields.
|
|
61
61
|
*/
|