@iderouter/index-mcp 0.2.0-beta.1 → 0.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/index.js +223 -8
package/README.md
CHANGED
|
@@ -75,6 +75,7 @@ client skill catalog automatically.
|
|
|
75
75
|
## Tools
|
|
76
76
|
|
|
77
77
|
- `index_codebase`: index a local directory.
|
|
78
|
+
- `summarize_codebase`: produce a fast project overview from the local index while background fine indexing continues.
|
|
78
79
|
- `search_code`: semantic search against the local index.
|
|
79
80
|
- `ask_codebase`: answer a repository question from indexed code and cite matching snippets.
|
|
80
81
|
- `clear_index`: delete an index.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -314,6 +314,7 @@ const searchResultCache = new Map();
|
|
|
314
314
|
const SEARCH_RESULT_CACHE_TTL_MS = Number(process.env.IDEROUTER_SEARCH_RESULT_CACHE_TTL_MS || 120000);
|
|
315
315
|
const queryAnalysisCache = new Map();
|
|
316
316
|
const QUERY_ANALYSIS_CACHE_TTL_MS = Number(process.env.IDEROUTER_QUERY_ANALYSIS_CACHE_TTL_MS || 300000);
|
|
317
|
+
const contextProbeCache = new Map();
|
|
317
318
|
|
|
318
319
|
function log(message) {
|
|
319
320
|
process.stderr.write(`[${SERVER_NAME}] ${message}\n`);
|
|
@@ -341,8 +342,9 @@ Use this skill when a repository has the \`iderouter-index\` MCP configured.
|
|
|
341
342
|
|
|
342
343
|
1. Run \`index_codebase(path=...)\` when the repository is new or stale.
|
|
343
344
|
2. Use \`get_indexing_status(path=...)\` to wait for coarse or priority-semantic readiness.
|
|
344
|
-
3. Use \`
|
|
345
|
-
4. Use \`
|
|
345
|
+
3. Use \`summarize_codebase(path=...)\` for a fast project overview while background fine indexing continues.
|
|
346
|
+
4. Use \`ask_codebase(path=..., question=...)\` for repository questions.
|
|
347
|
+
5. Use \`search_code(path=..., query=...)\` when you need ranked snippets or exact evidence.
|
|
346
348
|
|
|
347
349
|
## Notes
|
|
348
350
|
|
|
@@ -352,6 +354,88 @@ Use this skill when a repository has the \`iderouter-index\` MCP configured.
|
|
|
352
354
|
`;
|
|
353
355
|
}
|
|
354
356
|
|
|
357
|
+
function userCodexConfigPath() {
|
|
358
|
+
const codexHome = String(process.env.CODEX_HOME || "").trim();
|
|
359
|
+
if (codexHome) {
|
|
360
|
+
return path.join(codexHome, "config.toml");
|
|
361
|
+
}
|
|
362
|
+
return path.join(os.homedir(), ".codex", "config.toml");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function contextProbeCacheKey(codebasePath) {
|
|
366
|
+
return `context:${codebasePath}`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function summarizeContextText(text, maxLines = 8) {
|
|
370
|
+
return String(text || "")
|
|
371
|
+
.split("\n")
|
|
372
|
+
.map((line) => line.trim())
|
|
373
|
+
.filter(Boolean)
|
|
374
|
+
.filter((line) => !/^#/.test(line))
|
|
375
|
+
.slice(0, maxLines)
|
|
376
|
+
.join(" ");
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async function readOptionalFileProbe(filePath, kind) {
|
|
380
|
+
try {
|
|
381
|
+
const stat = await fs.stat(filePath);
|
|
382
|
+
if (!stat.isFile()) return null;
|
|
383
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
384
|
+
return {
|
|
385
|
+
kind,
|
|
386
|
+
filePath,
|
|
387
|
+
mtimeMs: Math.trunc(stat.mtimeMs),
|
|
388
|
+
size: stat.size,
|
|
389
|
+
excerpt: summarizeContextText(content),
|
|
390
|
+
};
|
|
391
|
+
} catch {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function probeAgentContext(codebasePath) {
|
|
397
|
+
const cacheKey = contextProbeCacheKey(codebasePath);
|
|
398
|
+
const repoAgentsPath = path.join(codebasePath, "AGENTS.md");
|
|
399
|
+
const repoClaudePath = path.join(codebasePath, "CLAUDE.md");
|
|
400
|
+
const codexConfigPath = userCodexConfigPath();
|
|
401
|
+
const [agentsProbe, claudeProbe, codexProbe] = await Promise.all([
|
|
402
|
+
readOptionalFileProbe(repoAgentsPath, "repo_agents"),
|
|
403
|
+
readOptionalFileProbe(repoClaudePath, "repo_claude"),
|
|
404
|
+
readOptionalFileProbe(codexConfigPath, "codex_config"),
|
|
405
|
+
]);
|
|
406
|
+
const fingerprint = [
|
|
407
|
+
agentsProbe ? `${agentsProbe.filePath}:${agentsProbe.mtimeMs}:${agentsProbe.size}` : "",
|
|
408
|
+
claudeProbe ? `${claudeProbe.filePath}:${claudeProbe.mtimeMs}:${claudeProbe.size}` : "",
|
|
409
|
+
codexProbe ? `${codexProbe.filePath}:${codexProbe.mtimeMs}:${codexProbe.size}` : "",
|
|
410
|
+
].join("|");
|
|
411
|
+
const cached = contextProbeCache.get(cacheKey);
|
|
412
|
+
if (cached && cached.fingerprint === fingerprint) {
|
|
413
|
+
return cached.value;
|
|
414
|
+
}
|
|
415
|
+
const value = {
|
|
416
|
+
found: [agentsProbe, claudeProbe, codexProbe].filter(Boolean),
|
|
417
|
+
hasRepoAgents: Boolean(agentsProbe),
|
|
418
|
+
hasRepoClaude: Boolean(claudeProbe),
|
|
419
|
+
hasCodexConfig: Boolean(codexProbe),
|
|
420
|
+
summary: [agentsProbe, claudeProbe, codexProbe]
|
|
421
|
+
.filter(Boolean)
|
|
422
|
+
.map((item) => `${item.kind}:${item.excerpt}`)
|
|
423
|
+
.join(" | "),
|
|
424
|
+
};
|
|
425
|
+
contextProbeCache.set(cacheKey, { fingerprint, value });
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function contextProbeNotice(contextProbe) {
|
|
430
|
+
if (!contextProbe) return "";
|
|
431
|
+
const found = [];
|
|
432
|
+
if (contextProbe.hasRepoAgents) found.push("AGENTS.md");
|
|
433
|
+
if (contextProbe.hasRepoClaude) found.push("CLAUDE.md");
|
|
434
|
+
if (contextProbe.hasCodexConfig) found.push("Codex config");
|
|
435
|
+
if (found.length === 0) return "";
|
|
436
|
+
return ` Agent context detected: ${found.join(", ")}.`;
|
|
437
|
+
}
|
|
438
|
+
|
|
355
439
|
async function initCodexSkill() {
|
|
356
440
|
const skillDir = codexSkillDir();
|
|
357
441
|
await fs.mkdir(skillDir, { recursive: true });
|
|
@@ -1063,6 +1147,7 @@ function buildIndexMetaPayload(fullIndex) {
|
|
|
1063
1147
|
updatedAt: fullIndex.updatedAt,
|
|
1064
1148
|
embeddingModel: fullIndex.embeddingModel,
|
|
1065
1149
|
embeddingModelsUsed: fullIndex.embeddingModelsUsed,
|
|
1150
|
+
strategySource: fullIndex.strategySource || "",
|
|
1066
1151
|
complete: fullIndex.complete,
|
|
1067
1152
|
indexStage: fullIndex.indexStage,
|
|
1068
1153
|
coarseReady: fullIndex.coarseReady,
|
|
@@ -3262,6 +3347,7 @@ async function saveIndex(codebasePath, files, chunks, options = {}) {
|
|
|
3262
3347
|
.filter((chunk) => chunk.granularity !== "coarse" && Array.isArray(chunk.vector) && chunk.vector.length > 0)
|
|
3263
3348
|
.map((chunk) => chunkVectorModel(chunk, options.embeddingModel || DEFAULT_EMBEDDING_MODEL)),
|
|
3264
3349
|
),
|
|
3350
|
+
strategySource: options.strategySource || lastStrategySource || "local_fallback",
|
|
3265
3351
|
complete: options.complete !== false,
|
|
3266
3352
|
indexStage: options.indexStage || (options.complete === false ? "fine_partial" : "fine"),
|
|
3267
3353
|
coarseReady: Boolean(options.coarseReady),
|
|
@@ -3638,6 +3724,16 @@ function formatIndexDiagnostics(diagnostics) {
|
|
|
3638
3724
|
].join(", ");
|
|
3639
3725
|
}
|
|
3640
3726
|
|
|
3727
|
+
function effectiveStrategySource(...sources) {
|
|
3728
|
+
for (const source of sources) {
|
|
3729
|
+
const value = String(source || "").trim();
|
|
3730
|
+
if (!value) continue;
|
|
3731
|
+
if (value === "local_fallback") continue;
|
|
3732
|
+
return value;
|
|
3733
|
+
}
|
|
3734
|
+
return "local_fallback";
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3641
3737
|
async function indexCodebase(args, precomputedFiles) {
|
|
3642
3738
|
const codebasePath = normalizePath(args.path);
|
|
3643
3739
|
const job = args.__jobId ? indexJobs.get(args.__jobId) : null;
|
|
@@ -6324,7 +6420,11 @@ async function exactAnchorSearch(codebasePath, args, indexedKeys) {
|
|
|
6324
6420
|
? args.extensionFilter.map((ext) => (ext.startsWith(".") ? ext : `.${ext}`))
|
|
6325
6421
|
: [],
|
|
6326
6422
|
);
|
|
6327
|
-
const
|
|
6423
|
+
const existingIndex = args.__searchIndex || null;
|
|
6424
|
+
const prepared = existingIndex
|
|
6425
|
+
? await prepareFilesFast(codebasePath, existingIndex, args.customExtensions, args.ignorePatterns)
|
|
6426
|
+
: null;
|
|
6427
|
+
const files = prepared?.files || await collectFiles(codebasePath, args.customExtensions, args.ignorePatterns);
|
|
6328
6428
|
const prioritizedFiles = files
|
|
6329
6429
|
.map((file) => ({
|
|
6330
6430
|
file,
|
|
@@ -6697,14 +6797,15 @@ async function searchCode(args) {
|
|
|
6697
6797
|
async function collectSearchState(codebasePath, args, query, limit) {
|
|
6698
6798
|
const loadedIndex = await loadExistingIndex(codebasePath);
|
|
6699
6799
|
let job = await loadLatestJobForPath(codebasePath);
|
|
6800
|
+
const contextProbe = await probeAgentContext(codebasePath);
|
|
6700
6801
|
if (!loadedIndex) {
|
|
6701
6802
|
if (isActiveJobStatus(job?.status)) {
|
|
6702
|
-
return `No local index file is ready yet for ${codebasePath}. Index job ${job.id} is ${job.status}: ${job.progress}% (${job.embeddedCount}/${job.totalChunks} changed chunks), step=${job.currentStep}
|
|
6803
|
+
return `No local index file is ready yet for ${codebasePath}. Index job ${job.id} is ${job.status}: ${job.progress}% (${job.embeddedCount}/${job.totalChunks} changed chunks), step=${job.currentStep}.${contextProbeNotice(contextProbe)} ${AGENT_INDEX_NOTICE}`;
|
|
6703
6804
|
}
|
|
6704
6805
|
if (job?.status === "failed") {
|
|
6705
|
-
return `No local index file is available for ${codebasePath}. Last index job ${job.id} failed at ${job.progress}%: ${cleanDiagnosticMessage(job.error)}
|
|
6806
|
+
return `No local index file is available for ${codebasePath}. Last index job ${job.id} failed at ${job.progress}%: ${cleanDiagnosticMessage(job.error)}.${contextProbeNotice(contextProbe)} ${AGENT_INDEX_NOTICE}`;
|
|
6706
6807
|
}
|
|
6707
|
-
return `No local index found for ${codebasePath}. Run index_codebase first
|
|
6808
|
+
return `No local index found for ${codebasePath}. Run index_codebase first, then use summarize_codebase(path=...) for a fast project overview.${contextProbeNotice(contextProbe)} ${COMPANION_PROMPT_NOTICE} ${AGENT_INDEX_NOTICE}`;
|
|
6708
6809
|
}
|
|
6709
6810
|
const usingPartialIndex = loadedIndex.complete === false;
|
|
6710
6811
|
let resumed = null;
|
|
@@ -6718,7 +6819,10 @@ async function collectSearchState(codebasePath, args, query, limit) {
|
|
|
6718
6819
|
const index = refresh.index;
|
|
6719
6820
|
const indexEmbeddingModel = index.embeddingModel || DEFAULT_EMBEDDING_MODEL;
|
|
6720
6821
|
const anchorVariants = anchorIdentifierVariants(query);
|
|
6721
|
-
const
|
|
6822
|
+
const activeJobRunning = isActiveJobStatus(job?.status);
|
|
6823
|
+
const skipQueryEmbedding =
|
|
6824
|
+
(usingPartialIndex && anchorVariants.length > 0) ||
|
|
6825
|
+
((usingPartialIndex || activeJobRunning) && !isImplementationLocatorQuery(query) && !isRemoveDisabledFieldsQuery(query));
|
|
6722
6826
|
const queryVectors = new Map();
|
|
6723
6827
|
const indexedVectorModels = mergeStringSets(
|
|
6724
6828
|
index.chunks
|
|
@@ -6772,7 +6876,7 @@ async function collectSearchState(codebasePath, args, query, limit) {
|
|
|
6772
6876
|
.filter((chunk) => chunk.score > 0 && querySpecificChunkAllowed(query, chunk));
|
|
6773
6877
|
|
|
6774
6878
|
const indexedKeys = new Set(indexedResults.map((chunk) => `${chunk.relativePath}:${chunk.startLine}:${chunk.endLine}`));
|
|
6775
|
-
const anchorResults = (await exactAnchorSearch(codebasePath, args, indexedKeys))
|
|
6879
|
+
const anchorResults = (await exactAnchorSearch(codebasePath, { ...args, __searchIndex: index }, indexedKeys))
|
|
6776
6880
|
.filter((chunk) => querySpecificChunkAllowed(query, chunk));
|
|
6777
6881
|
let results = await expandResultSnippetsToBoundaries(codebasePath, query, diversifyResults(
|
|
6778
6882
|
query,
|
|
@@ -6844,6 +6948,71 @@ function summarizeAnswerFromResults(question, results, limit) {
|
|
|
6844
6948
|
].join("\n");
|
|
6845
6949
|
}
|
|
6846
6950
|
|
|
6951
|
+
function summarizeRepoDomains(results) {
|
|
6952
|
+
const domains = new Set();
|
|
6953
|
+
for (const result of results || []) {
|
|
6954
|
+
const relativePath = String(result.relativePath || "").toLowerCase();
|
|
6955
|
+
if (relativePath.startsWith("controller/")) domains.add("controller");
|
|
6956
|
+
else if (relativePath.startsWith("service/")) domains.add("service");
|
|
6957
|
+
else if (relativePath.startsWith("model/")) domains.add("model");
|
|
6958
|
+
else if (relativePath.startsWith("router/")) domains.add("router");
|
|
6959
|
+
else if (relativePath.startsWith("relay/")) domains.add("relay");
|
|
6960
|
+
else if (relativePath.startsWith("pkg/")) domains.add("pkg");
|
|
6961
|
+
else if (relativePath.startsWith("setting/")) domains.add("setting");
|
|
6962
|
+
else if (relativePath.startsWith("dto/")) domains.add("dto");
|
|
6963
|
+
else if (relativePath.startsWith("web/") || relativePath.startsWith("iderouter_frontend/")) domains.add("frontend");
|
|
6964
|
+
else if (relativePath.startsWith("common/")) domains.add("common");
|
|
6965
|
+
}
|
|
6966
|
+
return [...domains];
|
|
6967
|
+
}
|
|
6968
|
+
|
|
6969
|
+
function summarizeRepoTechStack(results) {
|
|
6970
|
+
const files = (results || []).map((result) => String(result.relativePath || "").toLowerCase());
|
|
6971
|
+
const stack = [];
|
|
6972
|
+
if (files.some((file) => file.endsWith(".go"))) stack.push("Go backend");
|
|
6973
|
+
if (files.some((file) => file.includes("web/") || file.includes("iderouter_frontend/") || file.endsWith(".tsx") || file.endsWith(".ts"))) {
|
|
6974
|
+
stack.push("TypeScript/React frontend");
|
|
6975
|
+
}
|
|
6976
|
+
if (files.some((file) => file.endsWith(".sql"))) stack.push("SQL schema or migrations");
|
|
6977
|
+
if (files.some((file) => file.endsWith(".yml") || file.endsWith(".yaml"))) stack.push("YAML workflow/config");
|
|
6978
|
+
return stack;
|
|
6979
|
+
}
|
|
6980
|
+
|
|
6981
|
+
function repoSummaryLines(codebasePath, state, contextProbe) {
|
|
6982
|
+
const results = Array.isArray(state?.results) ? state.results : [];
|
|
6983
|
+
const topResults = results.slice(0, 8);
|
|
6984
|
+
const domains = summarizeRepoDomains(topResults);
|
|
6985
|
+
const stack = summarizeRepoTechStack(topResults);
|
|
6986
|
+
const lines = [
|
|
6987
|
+
`Fast repository summary for ${codebasePath}:`,
|
|
6988
|
+
"",
|
|
6989
|
+
`Status: ${state?.usingPartialIndex ? "searchable partial index" : "ready index"}${state?.refresh?.skippedDueToActiveJob ? " while background indexing continues" : ""}.`,
|
|
6990
|
+
];
|
|
6991
|
+
if (stack.length > 0) {
|
|
6992
|
+
lines.push(`Likely stack: ${stack.join(", ")}.`);
|
|
6993
|
+
}
|
|
6994
|
+
if (domains.length > 0) {
|
|
6995
|
+
lines.push(`Indexed layers present: ${domains.join(", ")}.`);
|
|
6996
|
+
}
|
|
6997
|
+
if (contextProbe?.found?.length) {
|
|
6998
|
+
lines.push("");
|
|
6999
|
+
lines.push("Agent Context:");
|
|
7000
|
+
for (const item of contextProbe.found.slice(0, 3)) {
|
|
7001
|
+
lines.push(`- ${path.basename(item.filePath)}: ${item.excerpt || "context file detected"}`);
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
if (topResults.length > 0) {
|
|
7005
|
+
lines.push("");
|
|
7006
|
+
lines.push("Key entrypoints:");
|
|
7007
|
+
for (const result of topResults.slice(0, 5)) {
|
|
7008
|
+
lines.push(`- ${result.relativePath}:${result.startLine}-${result.endLine}`);
|
|
7009
|
+
}
|
|
7010
|
+
}
|
|
7011
|
+
lines.push("");
|
|
7012
|
+
lines.push("Use get_indexing_status(path=...) to check background fine indexing progress.");
|
|
7013
|
+
return lines.join("\n");
|
|
7014
|
+
}
|
|
7015
|
+
|
|
6847
7016
|
async function askCodebase(args) {
|
|
6848
7017
|
const codebasePath = normalizePath(args.path);
|
|
6849
7018
|
const question = String(args.question || "").trim();
|
|
@@ -6885,6 +7054,25 @@ async function askCodebase(args) {
|
|
|
6885
7054
|
return summarizeAnswerFromResults(question, state.results, limit);
|
|
6886
7055
|
}
|
|
6887
7056
|
|
|
7057
|
+
async function summarizeCodebase(args) {
|
|
7058
|
+
const codebasePath = normalizePath(args.path);
|
|
7059
|
+
const summaryQuery = "repository overview architecture core modules backend frontend key entrypoints";
|
|
7060
|
+
const contextProbe = await probeAgentContext(codebasePath);
|
|
7061
|
+
const state = await collectSearchState(
|
|
7062
|
+
codebasePath,
|
|
7063
|
+
{ ...args, query: summaryQuery, __skipSearchCache: true },
|
|
7064
|
+
summaryQuery,
|
|
7065
|
+
Math.min(Number(args.limit || 8), 12),
|
|
7066
|
+
);
|
|
7067
|
+
if (typeof state === "string") {
|
|
7068
|
+
return `${state}${contextProbeNotice(contextProbe)}`;
|
|
7069
|
+
}
|
|
7070
|
+
if (!Array.isArray(state.results) || state.results.length === 0) {
|
|
7071
|
+
return `I could not build a repository summary for ${codebasePath} from the current index.${contextProbeNotice(contextProbe)}`;
|
|
7072
|
+
}
|
|
7073
|
+
return `${repoSummaryLines(codebasePath, state, contextProbe)}${contextProbeNotice(contextProbe)}`;
|
|
7074
|
+
}
|
|
7075
|
+
|
|
6888
7076
|
function latestJobForPath(codebasePath) {
|
|
6889
7077
|
let latest = null;
|
|
6890
7078
|
for (const job of indexJobs.values()) {
|
|
@@ -7601,6 +7789,19 @@ async function getIndexingStatus(args) {
|
|
|
7601
7789
|
job = await ensureDeferredCloudState(codebasePath, currentIndex, job, args);
|
|
7602
7790
|
const resumed = await maybeResumeOrphanedIndexJob(codebasePath, args, currentIndex, job);
|
|
7603
7791
|
if (resumed?.job) job = resumed.job;
|
|
7792
|
+
const resolvedStrategySource = effectiveStrategySource(
|
|
7793
|
+
lastStrategySource,
|
|
7794
|
+
currentIndex?.strategySource,
|
|
7795
|
+
job?.strategySource,
|
|
7796
|
+
currentIndex?.diagnostics?.strategySource,
|
|
7797
|
+
job?.diagnostics?.strategySource,
|
|
7798
|
+
);
|
|
7799
|
+
if (job?.diagnostics) {
|
|
7800
|
+
job.diagnostics = {
|
|
7801
|
+
...job.diagnostics,
|
|
7802
|
+
strategySource: effectiveStrategySource(job.diagnostics.strategySource, resolvedStrategySource),
|
|
7803
|
+
};
|
|
7804
|
+
}
|
|
7604
7805
|
const cloudSuffix = cloudStatusSuffix(job);
|
|
7605
7806
|
const diagnosticsSuffix = job?.diagnostics ? ` Diagnostics: ${formatIndexDiagnostics(job.diagnostics)}.` : "";
|
|
7606
7807
|
const readinessSuffix = job ? ` Readiness: ${summarizeReadiness(job)}.` : "";
|
|
@@ -7734,6 +7935,18 @@ const tools = [
|
|
|
7734
7935
|
required: ["path", "query"],
|
|
7735
7936
|
},
|
|
7736
7937
|
},
|
|
7938
|
+
{
|
|
7939
|
+
name: "summarize_codebase",
|
|
7940
|
+
description: "Produce a fast repository overview from the local index while background fine indexing may still be running.",
|
|
7941
|
+
inputSchema: {
|
|
7942
|
+
type: "object",
|
|
7943
|
+
properties: {
|
|
7944
|
+
path: { type: "string" },
|
|
7945
|
+
limit: { type: "number" },
|
|
7946
|
+
},
|
|
7947
|
+
required: ["path"],
|
|
7948
|
+
},
|
|
7949
|
+
},
|
|
7737
7950
|
{
|
|
7738
7951
|
name: "ask_codebase",
|
|
7739
7952
|
description: "Answer a repository question using the indexed local code context and cite the strongest matching snippets.",
|
|
@@ -7774,6 +7987,8 @@ async function callTool(name, args) {
|
|
|
7774
7987
|
return args?.wait ? indexCodebase(args || {}) : startIndexJob(args || {});
|
|
7775
7988
|
case "search_code":
|
|
7776
7989
|
return searchCode(args || {});
|
|
7990
|
+
case "summarize_codebase":
|
|
7991
|
+
return summarizeCodebase(args || {});
|
|
7777
7992
|
case "ask_codebase":
|
|
7778
7993
|
return askCodebase(args || {});
|
|
7779
7994
|
case "clear_index":
|