codesearch-mcp 0.2.2-alpha → 0.3.0-alpha
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/CHANGELOG.md +65 -1
- package/README.md +60 -33
- package/dist/app.js +46 -22
- package/dist/src/chunking/AstChunker.d.ts +12 -0
- package/dist/src/chunking/AstChunker.js +30 -0
- package/dist/src/chunking/CharacterChunkStrategy.d.ts +8 -0
- package/dist/src/chunking/CharacterChunkStrategy.js +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.d.ts +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.js +87 -0
- package/dist/src/chunking/FragmentMerger.d.ts +11 -0
- package/dist/src/chunking/FragmentMerger.js +61 -0
- package/dist/src/chunking/ImportOnlyFilter.d.ts +5 -0
- package/dist/src/chunking/ImportOnlyFilter.js +14 -0
- package/dist/src/chunking/LangchainTextSplitter.d.ts +21 -0
- package/dist/src/chunking/LangchainTextSplitter.js +133 -0
- package/dist/src/chunking/MinSizeSplitPolicy.d.ts +9 -0
- package/dist/src/chunking/MinSizeSplitPolicy.js +18 -0
- package/dist/src/chunking/RunPacker.d.ts +12 -0
- package/dist/src/chunking/RunPacker.js +84 -0
- package/dist/src/chunking/create-chunker.d.ts +3 -0
- package/dist/src/chunking/create-chunker.js +15 -0
- package/dist/src/chunking/interfaces.d.ts +27 -0
- package/dist/src/chunking/interfaces.js +2 -0
- package/dist/src/commands/ConfigCommand.js +1 -9
- package/dist/src/commands/EvalCommand.d.ts +11 -0
- package/dist/src/commands/EvalCommand.js +264 -0
- package/dist/src/commands/IndexCommand.js +70 -66
- package/dist/src/commands/McpCommand.js +2 -8
- package/dist/src/commands/WebCommand.js +2 -5
- package/dist/src/config-error.d.ts +0 -4
- package/dist/src/config-error.js +0 -4
- package/dist/src/config-store.d.ts +1 -54
- package/dist/src/config-store.js +8 -69
- package/dist/src/config.d.ts +8 -17
- package/dist/src/config.js +35 -34
- package/dist/src/constants.d.ts +2 -28
- package/dist/src/constants.js +6 -28
- package/dist/src/container.d.ts +6 -0
- package/dist/src/container.js +12 -3
- package/dist/src/db/index.d.ts +1 -1
- package/dist/src/db/index.js +1 -2
- package/dist/src/db/schema.d.ts +22 -29
- package/dist/src/db/schema.js +3 -14
- package/dist/src/declarations/DeclarationTree.d.ts +19 -0
- package/dist/src/declarations/DeclarationTree.js +66 -0
- package/dist/src/declarations/DeclarationTreeBuilder.d.ts +22 -0
- package/dist/src/declarations/DeclarationTreeBuilder.js +179 -0
- package/dist/src/declarations/SourceLines.d.ts +37 -0
- package/dist/src/declarations/SourceLines.js +415 -0
- package/dist/src/dependency-traversal.d.ts +10 -0
- package/dist/src/dependency-traversal.js +39 -0
- package/dist/src/enriched-prompt.d.ts +0 -5
- package/dist/src/enriched-prompt.js +0 -5
- package/dist/src/error-record.d.ts +12 -0
- package/dist/src/error-record.js +248 -0
- package/dist/src/eval-corpus.d.ts +16 -0
- package/dist/src/eval-corpus.js +169 -0
- package/dist/src/eval-results.d.ts +15 -0
- package/dist/src/eval-results.js +397 -0
- package/dist/src/file-utils.d.ts +10 -0
- package/dist/src/file-utils.js +19 -1
- package/dist/src/graph.d.ts +0 -25
- package/dist/src/graph.js +0 -28
- package/dist/src/help.js +4 -1
- package/dist/src/hnsw-settings.d.ts +3 -0
- package/dist/src/hnsw-settings.js +24 -0
- package/dist/src/interfaces/IAstParser.d.ts +5 -30
- package/dist/src/interfaces/IChunker.d.ts +3 -12
- package/dist/src/interfaces/ICorpusInspector.d.ts +7 -0
- package/dist/src/interfaces/ICorpusInspector.js +2 -0
- package/dist/src/interfaces/IDatabase.d.ts +2 -36
- package/dist/src/interfaces/IEmbedder.d.ts +0 -9
- package/dist/src/interfaces/ILogger.d.ts +1 -11
- package/dist/src/interfaces/IMcpToolHandler.d.ts +0 -5
- package/dist/src/interfaces/IMonorepoResolver.d.ts +0 -22
- package/dist/src/interfaces/IProjectDiscovery.d.ts +0 -17
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +216 -0
- package/dist/src/interfaces/IRetrievalEvaluator.js +2 -0
- package/dist/src/interfaces/ISearcher.d.ts +26 -20
- package/dist/src/interfaces/index.d.ts +1 -0
- package/dist/src/interrupt.js +0 -2
- package/dist/src/owner-path.d.ts +9 -10
- package/dist/src/owner-path.js +11 -23
- package/dist/src/project-scope.d.ts +7 -0
- package/dist/src/project-scope.js +37 -0
- package/dist/src/project-selector.d.ts +1 -0
- package/dist/src/project-selector.js +13 -6
- package/dist/src/retrieval-eval.d.ts +24 -0
- package/dist/src/retrieval-eval.js +500 -0
- package/dist/src/search/result-shaping.d.ts +4 -0
- package/dist/src/search/result-shaping.js +19 -0
- package/dist/src/services/AstParserService.d.ts +28 -23
- package/dist/src/services/AstParserService.js +391 -98
- package/dist/src/services/DatabaseService.d.ts +2 -19
- package/dist/src/services/DatabaseService.js +44 -81
- package/dist/src/services/EmbedderFactory.d.ts +0 -4
- package/dist/src/services/EmbedderFactory.js +0 -5
- package/dist/src/services/IndexerService.d.ts +2 -10
- package/dist/src/services/IndexerService.js +29 -45
- package/dist/src/services/InfinityEmbedder.d.ts +0 -21
- package/dist/src/services/InfinityEmbedder.js +0 -15
- package/dist/src/services/LoggerService.d.ts +7 -5
- package/dist/src/services/LoggerService.js +37 -41
- package/dist/src/services/McpServer.d.ts +25 -10
- package/dist/src/services/McpServer.js +101 -64
- package/dist/src/services/MonorepoAwareDiscoveryService.d.ts +1 -45
- package/dist/src/services/MonorepoAwareDiscoveryService.js +1 -51
- package/dist/src/services/NxMonorepoResolver.d.ts +0 -29
- package/dist/src/services/NxMonorepoResolver.js +5 -56
- package/dist/src/services/OpenAICompatibleEmbedder.d.ts +0 -6
- package/dist/src/services/OpenAICompatibleEmbedder.js +1 -14
- package/dist/src/services/ProjectDiscoveryService.d.ts +0 -4
- package/dist/src/services/ProjectDiscoveryService.js +0 -4
- package/dist/src/services/SearcherService.d.ts +127 -70
- package/dist/src/services/SearcherService.js +526 -305
- package/dist/src/services/VoyageEmbedder.d.ts +0 -6
- package/dist/src/services/VoyageEmbedder.js +0 -6
- package/dist/src/services/WebServerService.d.ts +1 -53
- package/dist/src/services/WebServerService.js +11 -57
- package/dist/src/services/http-retry.d.ts +0 -7
- package/dist/src/services/http-retry.js +1 -10
- package/dist/src/services/infinity-provisioning.d.ts +0 -74
- package/dist/src/services/infinity-provisioning.js +5 -88
- package/dist/src/services/legacy-ollama-index.d.ts +0 -16
- package/dist/src/services/legacy-ollama-index.js +0 -23
- package/dist/src/services/reranker.d.ts +0 -9
- package/dist/src/services/reranker.js +46 -12
- package/dist/src/setup.d.ts +11 -23
- package/dist/src/setup.js +98 -71
- package/dist/src/symbol-name.d.ts +0 -12
- package/dist/src/symbol-name.js +0 -13
- package/dist/src/symbol-rows.d.ts +2 -11
- package/dist/src/symbol-rows.js +5 -13
- package/dist/src/tool-call-log.d.ts +2 -0
- package/dist/src/tool-call-log.js +24 -0
- package/dist/src/tools/FindSymbolTool.js +14 -5
- package/dist/src/tools/GetCallersTool.d.ts +3 -1
- package/dist/src/tools/GetCallersTool.js +16 -6
- package/dist/src/tools/GetDependenciesTool.d.ts +3 -1
- package/dist/src/tools/GetDependenciesTool.js +15 -8
- package/dist/src/tools/GetDependentsTool.d.ts +3 -1
- package/dist/src/tools/GetDependentsTool.js +31 -16
- package/dist/src/tools/ListFilesTool.d.ts +3 -1
- package/dist/src/tools/ListFilesTool.js +14 -12
- package/dist/src/tools/ListProjectsTool.js +5 -1
- package/dist/src/tools/ReadFileRangeTool.d.ts +3 -1
- package/dist/src/tools/ReadFileRangeTool.js +12 -11
- package/dist/src/tools/ReadFileTool.d.ts +3 -1
- package/dist/src/tools/ReadFileTool.js +12 -10
- package/dist/src/tools/SearchCodebaseTool.js +7 -2
- package/dist/src/tools/format-helpers.d.ts +10 -1
- package/dist/src/tools/format-helpers.js +145 -8
- package/dist/src/web/dashboard.d.ts +0 -8
- package/dist/src/web/dashboard.js +7 -10
- package/package.json +10 -9
- package/dist/src/services/AstChunker.d.ts +0 -42
- package/dist/src/services/AstChunker.js +0 -158
- package/docs/web-dashboard.md +0 -206
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.degradedNotices = degradedNotices;
|
|
37
|
+
exports.renderSummary = renderSummary;
|
|
38
|
+
exports.renderComparison = renderComparison;
|
|
39
|
+
exports.renderProgress = renderProgress;
|
|
40
|
+
exports.timestampSlug = timestampSlug;
|
|
41
|
+
exports.writeResultFiles = writeResultFiles;
|
|
42
|
+
exports.normaliseResultFile = normaliseResultFile;
|
|
43
|
+
exports.readResultFile = readResultFile;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const CATEGORIES = ['identifier', 'behaviour', 'concept'];
|
|
47
|
+
const STAGE_LABEL = {
|
|
48
|
+
vector: 'vector (reranker input order, not a rerank-off search)',
|
|
49
|
+
reranked: 'reranked',
|
|
50
|
+
};
|
|
51
|
+
function pct(n) {
|
|
52
|
+
return `${(n * 100).toFixed(1)}%`;
|
|
53
|
+
}
|
|
54
|
+
function signed(n, digits = 4) {
|
|
55
|
+
return (n >= 0 ? '+' : '') + n.toFixed(digits);
|
|
56
|
+
}
|
|
57
|
+
function oneCase(count) {
|
|
58
|
+
return count > 0 ? pct(1 / count) : '—';
|
|
59
|
+
}
|
|
60
|
+
function metricsRow(label, m) {
|
|
61
|
+
return `| ${label} | ${m.count} | ${oneCase(m.count)} | ${pct(m.hit1)} | ${pct(m.hit5)} | ${m.mrr10.toFixed(4)} |`;
|
|
62
|
+
}
|
|
63
|
+
function deltaRow(label, d) {
|
|
64
|
+
return `| ${label} | ${d.count.current} | ${pct(d.hit1.current)} (${signed(d.hit1.delta)}) | ${pct(d.hit5.current)} (${signed(d.hit5.delta)}) | ${d.mrr10.current.toFixed(4)} (${signed(d.mrr10.delta)}) |`;
|
|
65
|
+
}
|
|
66
|
+
function poolRow(label, p) {
|
|
67
|
+
return `| ${label} | ${p.count} | ${oneCase(p.count)} | ${pct(p.recall)} | ${p.short} |`;
|
|
68
|
+
}
|
|
69
|
+
function pairRow(label, p, count) {
|
|
70
|
+
return `| ${label} | ${p.improved} | ${p.worsened} | ${p.unchanged} | ${p.signTestP.toFixed(4)} | ${oneCase(count)} |`;
|
|
71
|
+
}
|
|
72
|
+
function poolValue(v, format, digits) {
|
|
73
|
+
if (v.baseline === null || v.delta === null)
|
|
74
|
+
return `no pool data → ${format(v.current)}`;
|
|
75
|
+
return `${format(v.baseline)} → ${format(v.current)} (${signed(v.delta, digits)})`;
|
|
76
|
+
}
|
|
77
|
+
function poolDeltaRow(label, d) {
|
|
78
|
+
return `| ${label} | ${poolValue(d.recall, pct, 4)} | ${poolValue(d.short, String, 0)} |`;
|
|
79
|
+
}
|
|
80
|
+
function degradedNotices(run) {
|
|
81
|
+
if (run.rerankFailures === 0 || !run.stages.includes('reranked'))
|
|
82
|
+
return [];
|
|
83
|
+
return [`reranked stage degraded: ${run.rerankFailures} rerank failure(s) scored on the vector-order fallback`];
|
|
84
|
+
}
|
|
85
|
+
function caseCount(change) {
|
|
86
|
+
const o = change.overall;
|
|
87
|
+
return o.improved + o.worsened + o.unchanged;
|
|
88
|
+
}
|
|
89
|
+
function categoryCount(change, category) {
|
|
90
|
+
const p = change.byCategory[category];
|
|
91
|
+
return p ? p.improved + p.worsened + p.unchanged : 0;
|
|
92
|
+
}
|
|
93
|
+
function pairTable(change) {
|
|
94
|
+
const lines = ['| Category | Improved | Worsened | Unchanged | Sign-test p | 1 case |', '|---|---|---|---|---|---|'];
|
|
95
|
+
lines.push(pairRow('Overall', change.overall, caseCount(change)));
|
|
96
|
+
for (const category of CATEGORIES) {
|
|
97
|
+
const p = change.byCategory[category];
|
|
98
|
+
if (p)
|
|
99
|
+
lines.push(pairRow(category, p, categoryCount(change, category)));
|
|
100
|
+
}
|
|
101
|
+
if (change.hit5Lost.length > 0)
|
|
102
|
+
lines.push('', `**Lost hit@5:** ${change.hit5Lost.join(', ')}`);
|
|
103
|
+
if (change.hit5Gained.length > 0)
|
|
104
|
+
lines.push('', `**Gained hit@5:** ${change.hit5Gained.join(', ')}`);
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
function formatList(values) {
|
|
108
|
+
return values.map(v => (v === null ? 'not sent' : String(v))).join(', ') || '—';
|
|
109
|
+
}
|
|
110
|
+
function corpusLines(metadata) {
|
|
111
|
+
const lines = metadata.corpora.map(c => `${c.root} @ ${c.commit} — ${c.projects.length} project(s), ${c.chunks} chunks, fingerprint ${c.fingerprint}`);
|
|
112
|
+
if (metadata.liveCases > 0)
|
|
113
|
+
lines.push(`${metadata.liveCases} live-corpus case(s) — not comparable over time`);
|
|
114
|
+
return lines.length > 0 ? lines : ['none recorded'];
|
|
115
|
+
}
|
|
116
|
+
function groupLabel(key, group) {
|
|
117
|
+
return `${key === 'live' ? 'live cases' : key} (${group.cases} case(s))`;
|
|
118
|
+
}
|
|
119
|
+
function corpusTable(stages, group) {
|
|
120
|
+
const lines = ['| Stage | Category | Cases | 1 case | hit@5 | MRR@10 |', '|---|---|---|---|---|---|'];
|
|
121
|
+
for (const stage of stages) {
|
|
122
|
+
const m = group.metrics[stage];
|
|
123
|
+
if (!m)
|
|
124
|
+
continue;
|
|
125
|
+
const row = (label, x) => `| ${stage} | ${label} | ${x.count} | ${oneCase(x.count)} | ${pct(x.hit5)} | ${x.mrr10.toFixed(4)} |`;
|
|
126
|
+
lines.push(row('Overall', m.overall));
|
|
127
|
+
for (const category of CATEGORIES) {
|
|
128
|
+
const cm = m.byCategory[category];
|
|
129
|
+
if (cm)
|
|
130
|
+
lines.push(row(category, cm));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
lines.push('', `Pool recall ${pct(group.pool.overall.recall)}, short pools ${group.pool.overall.short}.`);
|
|
134
|
+
for (const sc of group.stageChanges) {
|
|
135
|
+
const o = sc.change.overall;
|
|
136
|
+
lines.push('', `${sc.from} → ${sc.to}: improved ${o.improved}, worsened ${o.worsened}, unchanged ${o.unchanged}, p=${o.signTestP.toFixed(4)}.`);
|
|
137
|
+
}
|
|
138
|
+
return lines;
|
|
139
|
+
}
|
|
140
|
+
function renderMarkdown(result, comparison) {
|
|
141
|
+
const { metadata, run } = result;
|
|
142
|
+
const lines = [];
|
|
143
|
+
lines.push('# Retrieval Evaluation Report', '');
|
|
144
|
+
lines.push(`**Suite:** ${metadata.suitePath} (hash \`${metadata.suiteHash}\`)`);
|
|
145
|
+
lines.push(`**Model:** ${metadata.embeddingProvider}/${metadata.embeddingModel} | **Reranker:** ${metadata.rerankerModel ?? 'none'}`);
|
|
146
|
+
lines.push(`**Commit:** ${metadata.gitCommit} | **Timestamp:** ${metadata.timestamp}`);
|
|
147
|
+
if (metadata.indexMeta) {
|
|
148
|
+
lines.push(`**Index:** ${metadata.indexMeta.provider}/${metadata.indexMeta.model} (${metadata.indexMeta.dimensions} dims)`);
|
|
149
|
+
}
|
|
150
|
+
const corpora = corpusLines(metadata);
|
|
151
|
+
lines.push(corpora.length === 1 ? `**Corpus:** ${corpora[0]}` : `**Corpora:** ${corpora.join('; ')}`);
|
|
152
|
+
const c = metadata.conditions;
|
|
153
|
+
if (c) {
|
|
154
|
+
lines.push(`**Search conditions:** threshold ${c.similarityThreshold} | overfetch ${c.overfetch} | candidateFloor ${c.candidateFloor} | fetchLimit ${formatList(c.fetchLimit)} | ef_search ${formatList(c.efSearch)} | iterative scan ${formatList(c.iterativeScan)}`);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
lines.push('**Search conditions:** not recorded');
|
|
158
|
+
}
|
|
159
|
+
for (const stage of run.stages) {
|
|
160
|
+
const m = run.metrics[stage];
|
|
161
|
+
if (!m)
|
|
162
|
+
continue;
|
|
163
|
+
lines.push('', `## Metrics — ${STAGE_LABEL[stage]}`, '', '| Category | Cases | 1 case | hit@1 | hit@5 | MRR@10 |', '|---|---|---|---|---|---|');
|
|
164
|
+
lines.push(metricsRow('Overall', m.overall));
|
|
165
|
+
for (const category of CATEGORIES) {
|
|
166
|
+
const cm = m.byCategory[category];
|
|
167
|
+
if (cm)
|
|
168
|
+
lines.push(metricsRow(category, cm));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
lines.push('', '## Candidate pool', '', '| Category | Cases | 1 case | Pool recall | Short pools |', '|---|---|---|---|---|');
|
|
172
|
+
lines.push(poolRow('Overall', run.pool.overall));
|
|
173
|
+
for (const category of CATEGORIES) {
|
|
174
|
+
const p = run.pool.byCategory[category];
|
|
175
|
+
if (p)
|
|
176
|
+
lines.push(poolRow(category, p));
|
|
177
|
+
}
|
|
178
|
+
for (const sc of run.stageChanges) {
|
|
179
|
+
lines.push('', `## Stage change — ${sc.from} → ${sc.to}`, '', ...pairTable(sc.change));
|
|
180
|
+
}
|
|
181
|
+
const groups = Object.entries(run.byCorpus);
|
|
182
|
+
if (groups.length > 0) {
|
|
183
|
+
lines.push('', '## Per corpus');
|
|
184
|
+
for (const [key, group] of groups)
|
|
185
|
+
lines.push('', `### ${groupLabel(key, group)}`, '', ...corpusTable(run.stages, group));
|
|
186
|
+
}
|
|
187
|
+
const degraded = degradedNotices(run);
|
|
188
|
+
if (degraded.length > 0)
|
|
189
|
+
lines.push('', ...degraded.map(d => `> ⚠ ${d}`));
|
|
190
|
+
if (run.invalid.length > 0) {
|
|
191
|
+
lines.push('', '## Invalid cases', '', '| Case | Reason |', '|---|---|');
|
|
192
|
+
for (const ic of run.invalid)
|
|
193
|
+
lines.push(`| ${ic.id} | ${ic.reason}: ${ic.invalidExpects.map(e => e.file).join(', ')} |`);
|
|
194
|
+
}
|
|
195
|
+
if (run.warnings.length > 0) {
|
|
196
|
+
lines.push('', '## Warnings (partially invalid)', '', '| Case | Dropped |', '|---|---|');
|
|
197
|
+
for (const w of run.warnings)
|
|
198
|
+
lines.push(`| ${w.id} | ${w.droppedExpects.map(e => e.file).join(', ')} |`);
|
|
199
|
+
}
|
|
200
|
+
if (comparison) {
|
|
201
|
+
const cmp = comparison.result;
|
|
202
|
+
lines.push('', `## Comparison against ${comparison.baselinePath}`, '');
|
|
203
|
+
if (cmp.conditionWarnings.length > 0) {
|
|
204
|
+
lines.push('> ⚠ ' + cmp.conditionWarnings.join('; '), '');
|
|
205
|
+
}
|
|
206
|
+
for (const sc of cmp.stages) {
|
|
207
|
+
lines.push(`### ${sc.stage}`, '', '| Category | Cases | hit@1 (Δ) | hit@5 (Δ) | MRR@10 (Δ) |', '|---|---|---|---|---|');
|
|
208
|
+
lines.push(deltaRow('Overall', sc.overall));
|
|
209
|
+
for (const category of CATEGORIES) {
|
|
210
|
+
const d = sc.byCategory[category];
|
|
211
|
+
if (d)
|
|
212
|
+
lines.push(deltaRow(category, d));
|
|
213
|
+
}
|
|
214
|
+
lines.push('', `Paired change, baseline → current (${sc.stage}):`, '', ...pairTable(sc.change), '');
|
|
215
|
+
}
|
|
216
|
+
for (const u of cmp.unmatchedStages) {
|
|
217
|
+
lines.push(`**Stage \`${u.stage}\`** is present only in the ${u.side === 'baseline' ? 'baseline' : 'current run'}; not compared.`, '');
|
|
218
|
+
}
|
|
219
|
+
lines.push('### Candidate pool', '', '| Category | Pool recall | Short pools |', '|---|---|---|');
|
|
220
|
+
lines.push(poolDeltaRow('Overall', cmp.pool.overall));
|
|
221
|
+
for (const category of CATEGORIES) {
|
|
222
|
+
const d = cmp.pool.byCategory[category];
|
|
223
|
+
if (d)
|
|
224
|
+
lines.push(poolDeltaRow(category, d));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return lines.join('\n') + '\n';
|
|
228
|
+
}
|
|
229
|
+
function consoleMetrics(label, m) {
|
|
230
|
+
return ` ${label.padEnd(10)} — hit@1: ${pct(m.hit1)} hit@5: ${pct(m.hit5)} MRR@10: ${m.mrr10.toFixed(4)} (${m.count}, 1 case = ${oneCase(m.count)})`;
|
|
231
|
+
}
|
|
232
|
+
function consolePairs(label, p) {
|
|
233
|
+
return ` ${label.padEnd(10)} — improved ${p.improved} worsened ${p.worsened} unchanged ${p.unchanged} p=${p.signTestP.toFixed(4)}`;
|
|
234
|
+
}
|
|
235
|
+
function renderSummary(result) {
|
|
236
|
+
const { run, metadata } = result;
|
|
237
|
+
const lines = [];
|
|
238
|
+
lines.push('', `Evaluated ${run.cases.length} case(s) (${run.invalid.length} invalid) against ${metadata.embeddingProvider}/${metadata.embeddingModel}`);
|
|
239
|
+
for (const line of corpusLines(metadata))
|
|
240
|
+
lines.push(` corpus: ${line}`);
|
|
241
|
+
for (const stage of run.stages) {
|
|
242
|
+
const m = run.metrics[stage];
|
|
243
|
+
if (!m)
|
|
244
|
+
continue;
|
|
245
|
+
lines.push(`\n[${STAGE_LABEL[stage]}]`);
|
|
246
|
+
lines.push(consoleMetrics('Overall', m.overall));
|
|
247
|
+
for (const category of CATEGORIES) {
|
|
248
|
+
const cm = m.byCategory[category];
|
|
249
|
+
if (cm)
|
|
250
|
+
lines.push(consoleMetrics(category, cm));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
lines.push('\n[candidate pool]');
|
|
254
|
+
const poolLine = (label, p) => ` ${label.padEnd(10)} — recall: ${pct(p.recall)} short: ${p.short} (${p.count})`;
|
|
255
|
+
lines.push(poolLine('Overall', run.pool.overall));
|
|
256
|
+
for (const category of CATEGORIES) {
|
|
257
|
+
const p = run.pool.byCategory[category];
|
|
258
|
+
if (p)
|
|
259
|
+
lines.push(poolLine(category, p));
|
|
260
|
+
}
|
|
261
|
+
for (const sc of run.stageChanges) {
|
|
262
|
+
lines.push(`\n[${sc.from} → ${sc.to}]`);
|
|
263
|
+
lines.push(consolePairs('Overall', sc.change.overall));
|
|
264
|
+
for (const category of CATEGORIES) {
|
|
265
|
+
const p = sc.change.byCategory[category];
|
|
266
|
+
if (p)
|
|
267
|
+
lines.push(consolePairs(category, p));
|
|
268
|
+
}
|
|
269
|
+
if (sc.change.hit5Lost.length > 0)
|
|
270
|
+
lines.push(` Lost hit@5: ${sc.change.hit5Lost.join(', ')}`);
|
|
271
|
+
if (sc.change.hit5Gained.length > 0)
|
|
272
|
+
lines.push(` Gained hit@5: ${sc.change.hit5Gained.join(', ')}`);
|
|
273
|
+
}
|
|
274
|
+
for (const [key, group] of Object.entries(run.byCorpus)) {
|
|
275
|
+
lines.push(`\n[${groupLabel(key, group)}]`);
|
|
276
|
+
for (const stage of run.stages) {
|
|
277
|
+
const m = group.metrics[stage];
|
|
278
|
+
if (!m)
|
|
279
|
+
continue;
|
|
280
|
+
const cats = CATEGORIES.filter(cat => m.byCategory[cat]).map(cat => `${cat} ${m.byCategory[cat].mrr10.toFixed(4)}`).join(' ');
|
|
281
|
+
lines.push(` ${stage.padEnd(10)} — MRR@10: ${m.overall.mrr10.toFixed(4)} hit@5: ${pct(m.overall.hit5)} (${cats})`);
|
|
282
|
+
}
|
|
283
|
+
lines.push(` ${'pool'.padEnd(10)} — recall: ${pct(group.pool.overall.recall)} short: ${group.pool.overall.short}`);
|
|
284
|
+
for (const sc of group.stageChanges)
|
|
285
|
+
lines.push(consolePairs(`${sc.from}→${sc.to}`, sc.change.overall));
|
|
286
|
+
}
|
|
287
|
+
for (const d of degradedNotices(run))
|
|
288
|
+
lines.push(`\n⚠ ${d}`);
|
|
289
|
+
if (run.invalid.length > 0) {
|
|
290
|
+
lines.push('\nInvalid cases:');
|
|
291
|
+
for (const c of run.invalid)
|
|
292
|
+
lines.push(` ${c.id}: ${c.reason} — ${c.invalidExpects.map(e => e.file).join(', ')}`);
|
|
293
|
+
}
|
|
294
|
+
if (run.warnings.length > 0) {
|
|
295
|
+
lines.push('\nWarnings (scored on remaining valid answers):');
|
|
296
|
+
for (const w of run.warnings)
|
|
297
|
+
lines.push(` ${w.id}: dropped ${w.droppedExpects.map(e => e.file).join(', ')}`);
|
|
298
|
+
}
|
|
299
|
+
return lines;
|
|
300
|
+
}
|
|
301
|
+
function renderComparison(baselinePath, cmp) {
|
|
302
|
+
const lines = [`\nComparison against ${baselinePath}:`];
|
|
303
|
+
for (const w of cmp.conditionWarnings)
|
|
304
|
+
lines.push(` ⚠ ${w}`);
|
|
305
|
+
for (const sc of cmp.stages) {
|
|
306
|
+
lines.push(` [${sc.stage}]`);
|
|
307
|
+
lines.push(` MRR@10: ${sc.overall.mrr10.baseline.toFixed(4)} → ${sc.overall.mrr10.current.toFixed(4)} (${signed(sc.overall.mrr10.delta)})`);
|
|
308
|
+
lines.push(` hit@5: ${pct(sc.overall.hit5.baseline)} → ${pct(sc.overall.hit5.current)}`);
|
|
309
|
+
const o = sc.change.overall;
|
|
310
|
+
lines.push(` paired: improved ${o.improved} worsened ${o.worsened} unchanged ${o.unchanged} p=${o.signTestP.toFixed(4)}`);
|
|
311
|
+
if (sc.change.hit5Lost.length > 0)
|
|
312
|
+
lines.push(` Lost hit@5: ${sc.change.hit5Lost.join(', ')}`);
|
|
313
|
+
if (sc.change.hit5Gained.length > 0)
|
|
314
|
+
lines.push(` Gained hit@5: ${sc.change.hit5Gained.join(', ')}`);
|
|
315
|
+
}
|
|
316
|
+
for (const u of cmp.unmatchedStages) {
|
|
317
|
+
lines.push(` [${u.stage}] only in the ${u.side === 'baseline' ? 'baseline' : 'current run'} — not compared`);
|
|
318
|
+
}
|
|
319
|
+
const p = cmp.pool.overall;
|
|
320
|
+
lines.push(` pool recall: ${poolValue(p.recall, pct, 4)}`);
|
|
321
|
+
lines.push(` short pools: ${poolValue(p.short, String, 0)}`);
|
|
322
|
+
for (const category of CATEGORIES) {
|
|
323
|
+
const d = cmp.pool.byCategory[category];
|
|
324
|
+
if (d)
|
|
325
|
+
lines.push(` ${category.padEnd(10)} — recall ${poolValue(d.recall, pct, 4)} short ${poolValue(d.short, String, 0)}`);
|
|
326
|
+
}
|
|
327
|
+
return lines;
|
|
328
|
+
}
|
|
329
|
+
function renderProgress(p) {
|
|
330
|
+
const head = `[${String(p.index).padStart(String(p.total).length)}/${p.total}] ${p.id}`;
|
|
331
|
+
const secs = `(${(p.ms / 1000).toFixed(1)}s)`;
|
|
332
|
+
if (p.invalid)
|
|
333
|
+
return `${head} invalid — ${p.invalid.reason} ${secs}`;
|
|
334
|
+
const ranks = Object.keys(p.result.stages)
|
|
335
|
+
.map(stage => `${stage} ${p.result.stages[stage]?.rank ?? '—'}`)
|
|
336
|
+
.join(' → ');
|
|
337
|
+
return `${head} ${ranks}${p.result.rerankFailed ? ' (rerank failed)' : ''} ${secs}`;
|
|
338
|
+
}
|
|
339
|
+
function timestampSlug(date) {
|
|
340
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
341
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}_${pad(date.getHours())}-${pad(date.getMinutes())}`;
|
|
342
|
+
}
|
|
343
|
+
function writeResultFiles(resultsDir, suiteLabel, result, now, comparison) {
|
|
344
|
+
fs.mkdirSync(resultsDir, { recursive: true });
|
|
345
|
+
const stem = `eval_${suiteLabel}_${timestampSlug(now)}`;
|
|
346
|
+
const taken = (base) => fs.existsSync(path.join(resultsDir, `${base}.json`)) || fs.existsSync(path.join(resultsDir, `${base}.md`));
|
|
347
|
+
let base = stem;
|
|
348
|
+
for (let n = 2; taken(base); n++)
|
|
349
|
+
base = `${stem}-${n}`;
|
|
350
|
+
const jsonPath = path.join(resultsDir, `${base}.json`);
|
|
351
|
+
const mdPath = path.join(resultsDir, `${base}.md`);
|
|
352
|
+
fs.writeFileSync(jsonPath, JSON.stringify(result, null, 2) + '\n', 'utf-8');
|
|
353
|
+
fs.writeFileSync(mdPath, renderMarkdown(result, comparison), 'utf-8');
|
|
354
|
+
return { jsonPath, mdPath };
|
|
355
|
+
}
|
|
356
|
+
const EMPTY_POOL = { count: 0, recall: 0, short: 0 };
|
|
357
|
+
function normaliseResultFile(raw) {
|
|
358
|
+
const run = raw?.run;
|
|
359
|
+
if (!run || run.stages !== undefined || run.metrics?.overall === undefined)
|
|
360
|
+
return withCorpusMetadata(raw);
|
|
361
|
+
const stage = raw.metadata?.rerankerModel != null ? 'reranked' : 'vector';
|
|
362
|
+
const cases = run.cases.map(c => ({
|
|
363
|
+
id: c.id, project: c.project, category: c.category, query: c.query,
|
|
364
|
+
stages: { [stage]: { rank: c.rank, matched: c.matched } },
|
|
365
|
+
poolRank: null,
|
|
366
|
+
poolSize: 0,
|
|
367
|
+
rerankFailed: false,
|
|
368
|
+
corpus: null,
|
|
369
|
+
}));
|
|
370
|
+
return {
|
|
371
|
+
metadata: { ...raw.metadata, conditions: null, corpora: [], liveCases: cases.length },
|
|
372
|
+
run: {
|
|
373
|
+
cases,
|
|
374
|
+
invalid: run.invalid ?? [],
|
|
375
|
+
warnings: run.warnings ?? [],
|
|
376
|
+
stages: [stage],
|
|
377
|
+
metrics: { [stage]: run.metrics },
|
|
378
|
+
pool: { overall: EMPTY_POOL, byCategory: {} },
|
|
379
|
+
stageChanges: [],
|
|
380
|
+
rerankFailures: 0,
|
|
381
|
+
byCorpus: {},
|
|
382
|
+
},
|
|
383
|
+
legacy: true,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function withCorpusMetadata(file) {
|
|
387
|
+
if (!file?.metadata || file.metadata.corpora !== undefined)
|
|
388
|
+
return file;
|
|
389
|
+
return {
|
|
390
|
+
...file,
|
|
391
|
+
metadata: { ...file.metadata, corpora: [], liveCases: file.run.cases.length },
|
|
392
|
+
run: { ...file.run, cases: file.run.cases.map(c => ({ ...c, corpus: c.corpus ?? null })), byCorpus: file.run.byCorpus ?? {} },
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function readResultFile(filePath) {
|
|
396
|
+
return normaliseResultFile(JSON.parse(fs.readFileSync(filePath, 'utf-8')));
|
|
397
|
+
}
|
package/dist/src/file-utils.d.ts
CHANGED
|
@@ -10,4 +10,14 @@ export type RagMetaResult = ProjectMeta | 'missing' | 'invalid';
|
|
|
10
10
|
export declare function readRagMeta(projectDir: string): RagMetaResult;
|
|
11
11
|
export declare const IGNORE_DIRS: Set<string>;
|
|
12
12
|
export declare function loadIgnore(projectDir: string): ReturnType<typeof ignore>;
|
|
13
|
+
export declare function isIndexableFileName(name: string): boolean;
|
|
14
|
+
export type IndexingExclusion = {
|
|
15
|
+
kind: 'type';
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'ignored_dir';
|
|
18
|
+
segment: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'ragignore';
|
|
21
|
+
};
|
|
22
|
+
export declare function indexingExclusion(relPath: string, ig: ReturnType<typeof ignore>): IndexingExclusion | null;
|
|
13
23
|
export declare function collectFiles(dir: string, ig: ReturnType<typeof ignore>, rootDir: string): string[];
|
package/dist/src/file-utils.js
CHANGED
|
@@ -39,6 +39,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.IGNORE_DIRS = void 0;
|
|
40
40
|
exports.readRagMeta = readRagMeta;
|
|
41
41
|
exports.loadIgnore = loadIgnore;
|
|
42
|
+
exports.isIndexableFileName = isIndexableFileName;
|
|
43
|
+
exports.indexingExclusion = indexingExclusion;
|
|
42
44
|
exports.collectFiles = collectFiles;
|
|
43
45
|
const fs = __importStar(require("fs"));
|
|
44
46
|
const path = __importStar(require("path"));
|
|
@@ -75,6 +77,22 @@ function loadIgnore(projectDir) {
|
|
|
75
77
|
}
|
|
76
78
|
return ig;
|
|
77
79
|
}
|
|
80
|
+
function isIndexableFileName(name) {
|
|
81
|
+
return SOURCE_EXTENSIONS.test(name) && !IGNORE_EXTENSIONS.test(name);
|
|
82
|
+
}
|
|
83
|
+
function indexingExclusion(relPath, ig) {
|
|
84
|
+
const segments = relPath.split('/');
|
|
85
|
+
if (!isIndexableFileName(segments[segments.length - 1]))
|
|
86
|
+
return { kind: 'type' };
|
|
87
|
+
const ignoredDir = segments.slice(0, -1).find(s => exports.IGNORE_DIRS.has(s));
|
|
88
|
+
if (ignoredDir)
|
|
89
|
+
return { kind: 'ignored_dir', segment: ignoredDir };
|
|
90
|
+
for (let i = 1; i <= segments.length; i++) {
|
|
91
|
+
if (ig.ignores(segments.slice(0, i).join('/')))
|
|
92
|
+
return { kind: 'ragignore' };
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
78
96
|
function collectFiles(dir, ig, rootDir) {
|
|
79
97
|
const result = [];
|
|
80
98
|
let entries;
|
|
@@ -94,7 +112,7 @@ function collectFiles(dir, ig, rootDir) {
|
|
|
94
112
|
if (!exports.IGNORE_DIRS.has(file))
|
|
95
113
|
result.push(...collectFiles(fullPath, ig, rootDir));
|
|
96
114
|
}
|
|
97
|
-
else if (
|
|
115
|
+
else if (isIndexableFileName(file)) {
|
|
98
116
|
result.push(fullPath);
|
|
99
117
|
}
|
|
100
118
|
}
|
package/dist/src/graph.d.ts
CHANGED
|
@@ -12,33 +12,15 @@ export interface GraphData {
|
|
|
12
12
|
nodes: ProjectNode[];
|
|
13
13
|
edges: Edge[];
|
|
14
14
|
}
|
|
15
|
-
/** A single named graph tab (Workspace, or one per nested Nx repo). */
|
|
16
15
|
export interface GraphView {
|
|
17
16
|
name: string;
|
|
18
17
|
nodes: ProjectNode[];
|
|
19
18
|
edges: Edge[];
|
|
20
19
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Build the project graph data (nodes + relation edges) from a project list.
|
|
23
|
-
* Pure apart from reading each project's `.ragmeta.json`. Shared by the console
|
|
24
|
-
* graph, the graph views, and the web dashboard's `/api/graph`.
|
|
25
|
-
*/
|
|
26
20
|
export declare function buildGraphData(projects: {
|
|
27
21
|
name: string;
|
|
28
22
|
path: string;
|
|
29
23
|
}[]): GraphData;
|
|
30
|
-
/**
|
|
31
|
-
* Split a project list into graph tabs. A project whose name contains a `/`
|
|
32
|
-
* belongs to a nested Nx repo (`<repo>/<sub-project>`); everything else is a
|
|
33
|
-
* flat top-level project.
|
|
34
|
-
*
|
|
35
|
-
* - **Workspace** tab: flat projects + one node per Nx repo (collapsed to a
|
|
36
|
-
* single `nxRepo` node); edges from `.ragmeta.json` relations.
|
|
37
|
-
* - **One tab per Nx repo**: its sub-projects as nodes, with edges between them
|
|
38
|
-
* taken from real import dependencies (`projectEdges`, from `code_dependency`).
|
|
39
|
-
*
|
|
40
|
-
* Returns the Workspace view first, then repo views sorted by name.
|
|
41
|
-
*/
|
|
42
24
|
export declare function buildGraphViews(projects: {
|
|
43
25
|
name: string;
|
|
44
26
|
path: string;
|
|
@@ -46,13 +28,6 @@ export declare function buildGraphViews(projects: {
|
|
|
46
28
|
from: string;
|
|
47
29
|
to: string;
|
|
48
30
|
}[], workspaceRoot: string): GraphView[];
|
|
49
|
-
/**
|
|
50
|
-
* Render the full interactive graph page (vis-network + inner tabs, edge-type
|
|
51
|
-
* filters, legend, project toggle list). Used for the standalone
|
|
52
|
-
* `project-graph.html` and served by the web dashboard at `GET /graph` (embedded
|
|
53
|
-
* via iframe) so both share one implementation. Tab 0 is the Workspace view;
|
|
54
|
-
* double-clicking an Nx-repo node opens that repo's tab.
|
|
55
|
-
*/
|
|
56
31
|
export declare function buildHtml(views: GraphView[]): string;
|
|
57
32
|
export declare function generateProjectGraph(projects: {
|
|
58
33
|
name: string;
|
package/dist/src/graph.js
CHANGED
|
@@ -41,11 +41,6 @@ const fs = __importStar(require("fs"));
|
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const file_utils_1 = require("./file-utils");
|
|
43
43
|
const EMPTY_META = { description: null, stack: null, notes: null, relations: null };
|
|
44
|
-
/**
|
|
45
|
-
* Build the project graph data (nodes + relation edges) from a project list.
|
|
46
|
-
* Pure apart from reading each project's `.ragmeta.json`. Shared by the console
|
|
47
|
-
* graph, the graph views, and the web dashboard's `/api/graph`.
|
|
48
|
-
*/
|
|
49
44
|
function buildGraphData(projects) {
|
|
50
45
|
const nodes = projects.map(p => {
|
|
51
46
|
const meta = (0, file_utils_1.readRagMeta)(p.path);
|
|
@@ -53,18 +48,6 @@ function buildGraphData(projects) {
|
|
|
53
48
|
});
|
|
54
49
|
return { nodes, edges: buildEdges(nodes) };
|
|
55
50
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Split a project list into graph tabs. A project whose name contains a `/`
|
|
58
|
-
* belongs to a nested Nx repo (`<repo>/<sub-project>`); everything else is a
|
|
59
|
-
* flat top-level project.
|
|
60
|
-
*
|
|
61
|
-
* - **Workspace** tab: flat projects + one node per Nx repo (collapsed to a
|
|
62
|
-
* single `nxRepo` node); edges from `.ragmeta.json` relations.
|
|
63
|
-
* - **One tab per Nx repo**: its sub-projects as nodes, with edges between them
|
|
64
|
-
* taken from real import dependencies (`projectEdges`, from `code_dependency`).
|
|
65
|
-
*
|
|
66
|
-
* Returns the Workspace view first, then repo views sorted by name.
|
|
67
|
-
*/
|
|
68
51
|
function buildGraphViews(projects, projectEdges, workspaceRoot) {
|
|
69
52
|
const flat = [];
|
|
70
53
|
const groups = new Map();
|
|
@@ -84,7 +67,6 @@ function buildGraphViews(projects, projectEdges, workspaceRoot) {
|
|
|
84
67
|
}
|
|
85
68
|
}
|
|
86
69
|
const repoNames = [...groups.keys()].sort();
|
|
87
|
-
// Workspace: flat projects + one collapsed node per repo (reads repo-root ragmeta).
|
|
88
70
|
const workspaceProjects = [
|
|
89
71
|
...flat,
|
|
90
72
|
...repoNames.map(repo => ({ name: repo, path: path.join(workspaceRoot, repo) })),
|
|
@@ -95,7 +77,6 @@ function buildGraphViews(projects, projectEdges, workspaceRoot) {
|
|
|
95
77
|
if (repoSet.has(n.name))
|
|
96
78
|
n.nxRepo = true;
|
|
97
79
|
const workspace = { name: 'Workspace', nodes: ws.nodes, edges: ws.edges };
|
|
98
|
-
// Per-repo: sub-project nodes + intra-repo import edges.
|
|
99
80
|
const repoViews = repoNames.map(repo => {
|
|
100
81
|
const subs = groups.get(repo);
|
|
101
82
|
const { nodes } = buildGraphData(subs);
|
|
@@ -151,7 +132,6 @@ function printConsole(views, workspacePath) {
|
|
|
151
132
|
console.log(`\n Full graph: file://${path.join(workspacePath, 'project-graph.html')}`);
|
|
152
133
|
}
|
|
153
134
|
}
|
|
154
|
-
/** Prepare a view for vis-network: colored nodes (+ synthetic nodes for unknown edge targets) and indexed edges. */
|
|
155
135
|
function viewToVis(view) {
|
|
156
136
|
const nodes = view.nodes.map(n => ({
|
|
157
137
|
id: n.name,
|
|
@@ -173,13 +153,6 @@ function viewToVis(view) {
|
|
|
173
153
|
const labels = [...new Set(view.edges.map(e => e.label))].sort();
|
|
174
154
|
return { name: view.name, nodes, edges, labels };
|
|
175
155
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Render the full interactive graph page (vis-network + inner tabs, edge-type
|
|
178
|
-
* filters, legend, project toggle list). Used for the standalone
|
|
179
|
-
* `project-graph.html` and served by the web dashboard at `GET /graph` (embedded
|
|
180
|
-
* via iframe) so both share one implementation. Tab 0 is the Workspace view;
|
|
181
|
-
* double-clicking an Nx-repo node opens that repo's tab.
|
|
182
|
-
*/
|
|
183
156
|
function buildHtml(views) {
|
|
184
157
|
const visViews = views.map(viewToVis);
|
|
185
158
|
return `<!DOCTYPE html>
|
|
@@ -365,7 +338,6 @@ function buildHtml(views) {
|
|
|
365
338
|
</body>
|
|
366
339
|
</html>`;
|
|
367
340
|
}
|
|
368
|
-
// Single entry point — builds the tabbed views, prints a console summary, writes the HTML.
|
|
369
341
|
function generateProjectGraph(projects, projectEdges, workspacePath) {
|
|
370
342
|
const views = buildGraphViews(projects, projectEdges, workspacePath);
|
|
371
343
|
printConsole(views, workspacePath);
|
package/dist/src/help.js
CHANGED
|
@@ -13,6 +13,9 @@ function printHelp(command) {
|
|
|
13
13
|
console.log('Options:');
|
|
14
14
|
console.log(' --reindex Force re-index all files (ignores cached mtimes)');
|
|
15
15
|
console.log(' --select Interactively select which projects to index');
|
|
16
|
+
console.log(' --project [name] Scope this run to one discovered project or monorepo unit');
|
|
17
|
+
console.log(' by exact name, bypassing selection and pruning; omit the');
|
|
18
|
+
console.log(' name for an interactive single-choice prompt');
|
|
16
19
|
console.log(' -h, --help Show this help message');
|
|
17
20
|
break;
|
|
18
21
|
case 'rag-mcp':
|
|
@@ -72,7 +75,7 @@ function printHelp(command) {
|
|
|
72
75
|
console.log(' -h, --help Show this help message');
|
|
73
76
|
break;
|
|
74
77
|
default:
|
|
75
|
-
console.log('Usage: rag-index [--reindex] [--select]');
|
|
78
|
+
console.log('Usage: rag-index [--reindex] [--select] [--project [name]]');
|
|
76
79
|
console.log(' rag-mcp');
|
|
77
80
|
console.log(' rag-setup');
|
|
78
81
|
console.log(' rag-config <show|get|set|reset|edit>');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ITERATIVE_SCAN_MODE = void 0;
|
|
4
|
+
exports.hnswSettings = hnswSettings;
|
|
5
|
+
exports.supportsIterativeScan = supportsIterativeScan;
|
|
6
|
+
exports.ITERATIVE_SCAN_MODE = 'relaxed_order';
|
|
7
|
+
const EF_SEARCH_DEFAULT = 40;
|
|
8
|
+
const EF_SEARCH_MAX = 1000;
|
|
9
|
+
const ITERATIVE_SCAN_MIN_VERSION = [0, 8, 0];
|
|
10
|
+
function hnswSettings(dbLimit, iterative) {
|
|
11
|
+
return {
|
|
12
|
+
'hnsw.ef_search': Math.min(Math.max(dbLimit, EF_SEARCH_DEFAULT), EF_SEARCH_MAX),
|
|
13
|
+
...(iterative ? { 'hnsw.iterative_scan': exports.ITERATIVE_SCAN_MODE } : {}),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function supportsIterativeScan(version) {
|
|
17
|
+
const segments = version.split('.').map(s => parseInt(s, 10) || 0);
|
|
18
|
+
for (let i = 0; i < ITERATIVE_SCAN_MIN_VERSION.length; i++) {
|
|
19
|
+
const diff = (segments[i] ?? 0) - ITERATIVE_SCAN_MIN_VERSION[i];
|
|
20
|
+
if (diff !== 0)
|
|
21
|
+
return diff > 0;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|