find_gaps
Identifies terms mentioned but not explained in manuscript markdown files to improve clarity and completeness for readers.
Instructions
Find terms mentioned but not explained
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_path | No | Path to manuscript directory (defaults to current directory) | |
| scope | No | File scope pattern | |
| limit | No | Maximum results |
Implementation Reference
- src/tools/WriterToolHandlers.ts:137-142 (handler)Primary tool handler that processes MCP args, applies pagination, and delegates to WritersAid service.private async findGaps(args: Record<string, unknown>) { const scope = args.scope as string | undefined; const limit = resolvePaginationLimit("find_gaps", args.limit as number | undefined); return this.writersAid.findGaps({ scope, limit }); }
- MCP tool schema definition including input validation.{ name: "find_gaps", description: "Find terms mentioned but not explained", inputSchema: { type: "object", properties: { project_path: { type: "string", description: "Path to manuscript directory (defaults to current directory)" }, scope: { type: "string", description: "File scope pattern" }, limit: { type: "number", description: "Maximum results", default: 20 }, }, }, },
- src/analysis/GapFinder.ts:18-62 (handler)Core implementation executing the gap-finding logic: extracts terms and definitions from files, identifies undefined terms with multiple mentions.async findGaps(options: { scope?: string; limit?: number }): Promise<TermGap[]> { const { limit } = options; const files = await this.storage.getAllFiles(); const termMentions = new Map<string, { count: number; files: Set<string> }>(); const definedTerms = new Set<string>(); // Extract terms and definitions for (const file of files) { const content = file.content; // Find potential technical terms (capitalized, or specific patterns) const terms = this.extractTerms(content); for (const term of terms) { if (!termMentions.has(term)) { termMentions.set(term, { count: 0, files: new Set() }); } const entry = termMentions.get(term); if (entry) { entry.count++; entry.files.add(file.file_path); } } // Find definitions const definitions = this.extractDefinitions(content); definitions.forEach((d) => definedTerms.add(d)); } // Find gaps (mentioned but not defined) const gaps: TermGap[] = []; for (const [term, data] of termMentions) { if (data.count >= 2 && !definedTerms.has(term)) { gaps.push({ term, mentions: data.count, files: Array.from(data.files), hasDefinition: false, }); } } const sorted = gaps.sort((a, b) => b.mentions - a.mentions); return paginateResults(sorted, limit); }
- src/WritersAid.ts:237-239 (helper)Service layer wrapper delegating to GapFinder implementation.async findGaps(options?: { scope?: string; limit?: number }) { return this.gapFinder.findGaps(options || {}); }
- src/tools/WriterToolHandlers.ts:22-23 (registration)Tool dispatch registration in the central handleTool switch statement.case "find_gaps": return this.findGaps(args);