mine_changed_files
Re-index files modified after the last commit to keep the codebase search index current. Call after making code changes.
Instructions
Re-index files changed since last commit into MemPalace. Call after making code changes to keep the search index current.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/managers/CodeSearchManager.ts:51-81 (handler)The mineChangedFiles function that executes the core logic: gets committed and working-tree changed files via GitAccess, deduplicates, filters mineable paths via FileFilterEngine, and mines each file individually via MemPalaceAccess.mineFile.
async function mineChangedFiles( repoDir: string, ): Promise<{ mined: string[]; skipped: string[] }> { // Combine committed changes (HEAD~1..HEAD) and uncommitted working-tree changes, // deduplicating by path so each file is only mined once. const [committedFiles, workingTreeFiles, gitRoot] = await Promise.all([ git.getChangedFiles(repoDir), git.getWorkingTreeFiles(repoDir), git.getGitRoot(repoDir), ]); const seen = new Set<string>(); const merged = [...committedFiles, ...workingTreeFiles].filter(({ path }) => { if (seen.has(path)) return false; seen.add(path); return true; }); // git returns paths relative to the git toplevel (where .git lives), which may differ // from repoDir — use gitRoot to construct correct absolute paths. const allPaths = merged.map((f) => `${gitRoot}/${f.path}`); const mineable = fileFilter.filterPaths(allPaths); const skipped = allPaths.filter((p) => !mineable.includes(p)); if (mineable.length > 0) { // Mine each changed file individually so we get targeted re-indexing for (const path of mineable) { await memPalace.mineFile(path, palaceWing); } } return { mined: mineable, skipped }; } - src/tools/code-search.tool.ts:11-11 (schema)Zod schema for mine_changed_files (empty object, no inputs needed).
export const MineChangedFilesSchema = z.object({}); - src/tools/code-search.tool.ts:37-47 (registration)Registers the 'mine_changed_files' tool on the MCP server with its schema and handler that calls manager.mineChangedFiles(repoDir).
server.tool('mine_changed_files', 'Re-index files changed since last commit into MemPalace. Call after making code changes to keep the search index current.', MineChangedFilesSchema.shape, async () => { const result = await manager.mineChangedFiles(repoDir); return { content: [ { type: 'text' as const, text: JSON.stringify({ mined: result.mined, skipped: result.skipped }), }, ], }; }); - src/access/GitAccess.ts:52-55 (helper)GitAccess.getGitRoot returns the git top-level directory via 'git rev-parse --show-toplevel'.
async function getGitRoot(repoDir: string): Promise<string> { const { stdout } = await execFileAsync('git', ['-C', repoDir, 'rev-parse', '--show-toplevel']); return stdout.trim(); } - src/access/GitAccess.ts:57-87 (helper)GitAccess.getChangedFiles returns files changed between HEAD~1 and HEAD via 'git diff --name-status'.
async function getChangedFiles(repoDir: string, base?: string): Promise<ChangedFile[]> { const ref = base ?? 'HEAD~1'; const { stdout } = await execFileAsync('git', [ '-C', repoDir, 'diff', '--name-status', ref, 'HEAD', ]); return stdout .trim() .split('\n') .filter(Boolean) .map((line) => { const [rawStatus, ...parts] = line.split('\t'); const path = parts[parts.length - 1] ?? ''; const statusChar = (rawStatus ?? '')[0] ?? 'M'; const statusMap: Record<string, ChangedFile['status']> = { A: 'added', M: 'modified', D: 'deleted', R: 'renamed', }; return { path, status: statusMap[statusChar] ?? 'modified', }; }); }