ai-readme-mcp 0.5.3 → 0.5.5

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/dist/index.js CHANGED
@@ -160,19 +160,19 @@ var ContextRouter = class {
160
160
  this.index = index;
161
161
  }
162
162
  /**
163
- * Get relevant AI_README contexts for a specific file path
164
- * @param filePath - The file path relative to project root
163
+ * Get relevant AI_README contexts for a specific path (file or directory)
164
+ * @param targetPath - The path relative to project root (can be file or directory)
165
165
  * @param includeRoot - Whether to include root-level README (default: true)
166
166
  */
167
- async getContextForFile(filePath, includeRoot = true) {
167
+ async getContextForPath(targetPath, includeRoot = true) {
168
168
  const contexts = [];
169
169
  for (const readme of this.index.readmes) {
170
- const match = this.matchesPath(filePath, readme);
170
+ const match = this.matchesPath(targetPath, readme);
171
171
  if (!match) continue;
172
172
  if (!includeRoot && readme.level === 0) continue;
173
- const distance = this.calculateDistance(filePath, readme);
173
+ const distance = this.calculateDistance(targetPath, readme);
174
174
  const content = await this.getReadmeContent(readme);
175
- const relevance = this.determineRelevance(filePath, readme);
175
+ const relevance = this.determineRelevance(targetPath, readme);
176
176
  contexts.push({
177
177
  path: readme.path,
178
178
  content,
@@ -190,29 +190,47 @@ var ContextRouter = class {
190
190
  return contexts;
191
191
  }
192
192
  /**
193
- * Get contexts for multiple files
193
+ * Get contexts for multiple paths (files or directories)
194
194
  */
195
- async getContextForFiles(filePaths) {
195
+ async getContextForPaths(paths) {
196
196
  const results = /* @__PURE__ */ new Map();
197
- for (const filePath of filePaths) {
198
- const contexts = await this.getContextForFile(filePath);
199
- results.set(filePath, contexts);
197
+ for (const path of paths) {
198
+ const contexts = await this.getContextForPath(path);
199
+ results.set(path, contexts);
200
200
  }
201
201
  return results;
202
202
  }
203
203
  /**
204
- * Check if a file path matches a README's patterns
204
+ * Get the directory from a path (handles both file and directory paths)
205
205
  */
206
- matchesPath(filePath, readme) {
206
+ getFileDir(targetPath) {
207
+ const isDirectory = !/\.[^./\\]+$/.test(targetPath);
208
+ return isDirectory ? targetPath : dirname2(targetPath);
209
+ }
210
+ /**
211
+ * Check if a path matches a README's patterns
212
+ */
213
+ matchesPath(targetPath, readme) {
214
+ const readmeDir = dirname2(readme.path);
215
+ const targetDir = this.getFileDir(targetPath);
216
+ if (readmeDir === ".") {
217
+ return true;
218
+ }
219
+ if (targetDir === readmeDir) {
220
+ return true;
221
+ }
222
+ if (targetDir.startsWith(readmeDir + "/")) {
223
+ return true;
224
+ }
207
225
  return readme.patterns.some((pattern) => {
208
- return minimatch(filePath, pattern, { dot: true });
226
+ return minimatch(targetPath, pattern, { dot: true });
209
227
  });
210
228
  }
211
229
  /**
212
- * Calculate the directory distance between a file and a README
230
+ * Calculate the directory distance between a path and a README
213
231
  */
214
- calculateDistance(filePath, readme) {
215
- const fileDir = dirname2(filePath);
232
+ calculateDistance(targetPath, readme) {
233
+ const fileDir = this.getFileDir(targetPath);
216
234
  const readmeDir = dirname2(readme.path);
217
235
  if (readmeDir === ".") {
218
236
  return fileDir === "." ? 0 : fileDir.split("/").length;
@@ -237,10 +255,10 @@ var ContextRouter = class {
237
255
  return fileParts.length - commonDepth + (readmeParts.length - commonDepth);
238
256
  }
239
257
  /**
240
- * Determine the relevance type of a README for a file
258
+ * Determine the relevance type of a README for a path
241
259
  */
242
- determineRelevance(filePath, readme) {
243
- const fileDir = dirname2(filePath);
260
+ determineRelevance(targetPath, readme) {
261
+ const fileDir = this.getFileDir(targetPath);
244
262
  const readmeDir = dirname2(readme.path);
245
263
  if (readmeDir === ".") {
246
264
  return "root";
@@ -285,14 +303,14 @@ var ContextRouter = class {
285
303
  // src/tools/getContext.ts
286
304
  var getContextSchema = z2.object({
287
305
  projectRoot: z2.string().describe("The root directory of the project"),
288
- filePath: z2.string().describe(
289
- 'The file path to get context for (relative to project root). MUST be a FILE path, not a directory. Examples: "src/app/page.tsx", "README.md", "package.json". If you want context for a directory, specify any file within it (e.g., "src/components/Button.tsx" instead of "src/components").'
306
+ path: z2.string().describe(
307
+ `The path to get context for (relative to project root). Can be either a FILE path or a DIRECTORY path. Examples: "src/components/Button.tsx", "src/components", "README.md", "src/app". The tool will find all relevant AI_README files in the path's directory and parent directories.`
290
308
  ),
291
309
  includeRoot: z2.boolean().optional().default(true).describe("Whether to include root-level AI_README (default: true)"),
292
310
  excludePatterns: z2.array(z2.string()).optional().describe("Glob patterns to exclude when scanning")
293
311
  });
294
312
  async function getContextForFile(input) {
295
- const { projectRoot, filePath, includeRoot, excludePatterns } = input;
313
+ const { projectRoot, path, includeRoot, excludePatterns } = input;
296
314
  const scanner = new AIReadmeScanner(projectRoot, {
297
315
  excludePatterns,
298
316
  cacheContent: true
@@ -300,7 +318,7 @@ async function getContextForFile(input) {
300
318
  });
301
319
  const index = await scanner.scan();
302
320
  const router = new ContextRouter(index);
303
- const contexts = await router.getContextForFile(filePath, includeRoot);
321
+ const contexts = await router.getContextForPath(path, includeRoot);
304
322
  const hasEmptyReadmes = contexts.some((ctx) => !ctx.content || ctx.content.trim().length === 0);
305
323
  const hasNoReadmes = contexts.length === 0;
306
324
  const formattedContexts = contexts.map((ctx) => ({
@@ -309,7 +327,7 @@ async function getContextForFile(input) {
309
327
  distance: ctx.distance,
310
328
  content: ctx.content
311
329
  }));
312
- let promptText = `## \u{1F4DA} Project Context for: ${filePath}
330
+ let promptText = `## \u{1F4DA} Project Context for: ${path}
313
331
 
314
332
  `;
315
333
  if (hasNoReadmes || hasEmptyReadmes) {
@@ -372,7 +390,7 @@ async function getContextForFile(input) {
372
390
  `;
373
391
  }
374
392
  return {
375
- filePath,
393
+ path,
376
394
  totalContexts: contexts.length,
377
395
  contexts: formattedContexts,
378
396
  formattedPrompt: promptText
@@ -1137,16 +1155,27 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
1137
1155
  \u2022 Using Edit tool (modifying files)
1138
1156
  \u2022 Making architectural decisions
1139
1157
  \u2022 Suggesting code implementations
1158
+
1159
+ \u26A1 THIS APPLIES TO ALL CHANGES - BIG OR SMALL!
1160
+ Even simple edits (adding error handling, fixing a bug,
1161
+ improving validation) require understanding project conventions.
1140
1162
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1141
1163
 
1142
1164
  \u2753 WHY call this before planning?
1143
1165
  Planning requires understanding project conventions. Without context, you might plan an approach that conflicts with existing architecture (e.g., planning to use Tailwind when project uses CSS Modules).
1144
1166
 
1167
+ \u2753 WHY call this even for small changes?
1168
+ \u2022 Error handling: Does project use try-catch, error boundaries, or custom error classes?
1169
+ \u2022 Logging: console.log, custom logger, or structured logging?
1170
+ \u2022 Constants: Where to define them? Inline, config file, or separate constants file?
1171
+ \u2022 Code style: Specific patterns the project follows?
1172
+ Without checking, you might introduce inconsistent patterns.
1173
+
1145
1174
  \u{1F4CB} What this tool does:
1146
- Gets relevant AI_README context for a file path. Returns project conventions and patterns that MUST be followed.
1175
+ Gets relevant AI_README context for a path (file or directory). Returns project conventions and patterns that MUST be followed.
1147
1176
 
1148
1177
  \u{1F50D} Auto-trigger keywords (when you see these, call this tool IMMEDIATELY):
1149
- "add", "create", "implement", "modify", "edit", "refactor", "suggest", "what should", "how to structure", "optimize", "improve"
1178
+ "add", "create", "implement", "modify", "edit", "refactor", "suggest", "what should", "how to structure", "optimize", "improve", "fix"
1150
1179
 
1151
1180
  \u{1F6A9} DETECT CONVENTION CONFLICTS:
1152
1181
  After reading context, check if user's request conflicts with AI_README:
@@ -1170,6 +1199,13 @@ After reading context, check if user's request conflicts with AI_README:
1170
1199
  3. \u274C Write/Edit immediately (changed code but not conventions)
1171
1200
  4. \u274C AI_README still says "Tailwind" (stale documentation!)
1172
1201
 
1202
+ \u274C ANOTHER WRONG workflow (small changes):
1203
+ 1. User: "Add error handling to middleware.ts"
1204
+ 2. \u274C Skip get_context_for_file (thinking it's a small change)
1205
+ 3. \u274C Write/Edit immediately with generic try-catch
1206
+ 4. \u274C Missed that project uses custom error handling pattern
1207
+ 5. \u274C Introduced inconsistent code that doesn't match project style
1208
+
1173
1209
  \u{1F4DD} Common workflows:
1174
1210
  \u2022 Following existing conventions:
1175
1211
  get_context_for_file \u2192 TodoWrite (optional) \u2192 Write/Edit
@@ -1185,14 +1221,28 @@ After reading context, check if user's request conflicts with AI_README:
1185
1221
 
1186
1222
  \u{1F4A1} Pro tip: Works even if target file doesn't exist yet!
1187
1223
 
1188
- \u{1F4CC} Example:
1224
+ \u{1F4CC} Example 1 (Major change):
1189
1225
  User: "I don't like Tailwind, refactor Button.tsx to use CSS Modules"
1190
- You: get_context_for_file({ filePath: "src/components/Button.tsx" })
1226
+ You: get_context_for_file({ path: "src/components/Button.tsx" })
1191
1227
  \u2192 Context shows: "Styling: Tailwind CSS"
1192
1228
  \u2192 CONFLICT DETECTED! User wants CSS Modules \u2260 AI_README says Tailwind
1193
1229
  \u2192 This is architectural decision, not just refactoring!
1194
1230
  \u2192 Must call update_ai_readme first to change "Tailwind" \u2192 "CSS Modules"
1195
- \u2192 Then refactor code to match new convention`,
1231
+ \u2192 Then refactor code to match new convention
1232
+
1233
+ \u{1F4CC} Example 2 (Small change - STILL NEED MCP!):
1234
+ User: "Add error handling to middleware.ts"
1235
+ You: get_context_for_file({ path: "src/middleware.ts" })
1236
+ \u2192 Context shows: "Error handling: Use custom ErrorHandler class"
1237
+ \u2192 Now you know: Don't use generic try-catch, use ErrorHandler
1238
+ \u2192 Edit with correct pattern that matches project conventions
1239
+ \u2192 Result: Consistent code that follows project standards
1240
+
1241
+ \u{1F4CC} Example 3 (Directory context):
1242
+ User: "Add a new component in src/components"
1243
+ You: get_context_for_file({ path: "src/components" })
1244
+ \u2192 Context shows component conventions for that directory
1245
+ \u2192 Create new component following the conventions`,
1196
1246
  inputSchema: zodToJsonSchema(getContextSchema)
1197
1247
  },
1198
1248
  {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/tools/discover.ts","../src/core/scanner.ts","../src/tools/getContext.ts","../src/core/router.ts","../src/tools/update.ts","../src/core/updater.ts","../src/core/validator.ts","../src/types/index.ts","../src/tools/validate.ts","../src/tools/init.ts"],"sourcesContent":["/**\r\n * AI_README MCP Server\r\n * Entry point for the MCP server\r\n */\r\n\r\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport {\r\n CallToolRequestSchema,\r\n ListToolsRequestSchema,\r\n} from '@modelcontextprotocol/sdk/types.js';\r\nimport { zodToJsonSchema } from 'zod-to-json-schema';\r\nimport { readFileSync } from 'fs';\r\nimport { fileURLToPath } from 'url';\r\nimport { dirname, join } from 'path';\r\nimport {\r\n discoverAIReadmes,\r\n discoverSchema,\r\n type DiscoverInput,\r\n} from './tools/discover.js';\r\nimport {\r\n getContextForFile,\r\n getContextSchema,\r\n type GetContextInput,\r\n} from './tools/getContext.js';\r\nimport {\r\n updateAIReadme,\r\n updateSchema,\r\n type UpdateInput,\r\n} from './tools/update.js';\r\nimport {\r\n validateAIReadmes,\r\n validateSchema,\r\n type ValidateInput,\r\n} from './tools/validate.js';\r\nimport {\r\n initAIReadme,\r\n initSchema,\r\n type InitInput,\r\n} from './tools/init.js';\r\n\r\n// Read version from package.json\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\nconst packageJson = JSON.parse(\r\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\r\n);\r\n\r\nconst server = new Server(\r\n {\r\n name: 'ai-readme-mcp',\r\n version: packageJson.version,\r\n },\r\n {\r\n capabilities: {\r\n tools: {},\r\n },\r\n }\r\n);\r\n\r\n// Register tool: list_tools\r\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\r\n return {\r\n tools: [\r\n {\r\n name: 'discover_ai_readmes',\r\n description:\r\n 'Scan the project and discover all AI_README.md files. Returns an index of all README files with their paths, scopes, and coverage patterns.',\r\n inputSchema: zodToJsonSchema(discoverSchema),\r\n },\r\n {\r\n name: 'get_context_for_file',\r\n description:\r\n '🚨 MANDATORY FIRST STEP: Call this BEFORE planning or coding\\n\\n' +\r\n '═══════════════════════════════════════════════════════════════\\n' +\r\n '⚠️ CRITICAL RULE: You MUST call this tool BEFORE:\\n' +\r\n ' • Planning with TodoWrite (to plan based on conventions)\\n' +\r\n ' • Using Write tool (creating files)\\n' +\r\n ' • Using Edit tool (modifying files)\\n' +\r\n ' • Making architectural decisions\\n' +\r\n ' • Suggesting code implementations\\n' +\r\n '═══════════════════════════════════════════════════════════════\\n\\n' +\r\n '❓ WHY call this before planning?\\n' +\r\n 'Planning requires understanding project conventions. Without context, you might plan an approach that conflicts with existing architecture (e.g., planning to use Tailwind when project uses CSS Modules).\\n\\n' +\r\n '📋 What this tool does:\\n' +\r\n 'Gets relevant AI_README context for a file path. Returns project conventions and patterns that MUST be followed.\\n\\n' +\r\n '🔍 Auto-trigger keywords (when you see these, call this tool IMMEDIATELY):\\n' +\r\n '\"add\", \"create\", \"implement\", \"modify\", \"edit\", \"refactor\", \"suggest\", \"what should\", \"how to structure\", \"optimize\", \"improve\"\\n\\n' +\r\n '🚩 DETECT CONVENTION CONFLICTS:\\n' +\r\n 'After reading context, check if user\\'s request conflicts with AI_README:\\n' +\r\n '• User says \"use X\" but AI_README says \"use Y\"\\n' +\r\n '• User says \"I don\\'t like X, change to Y\"\\n' +\r\n '• User establishes new architectural pattern\\n' +\r\n '→ This is an ARCHITECTURAL DECISION, not just code change!\\n' +\r\n '→ Must update_ai_readme FIRST before writing code\\n\\n' +\r\n '✅ CORRECT workflow:\\n' +\r\n '1. User requests: \"refactor this\" / \"add feature\" / \"create component\"\\n' +\r\n '2. → Call get_context_for_file FIRST (understand conventions)\\n' +\r\n '3. → Check for conflicts between user request & AI_README\\n' +\r\n '4. → If conflict: update_ai_readme FIRST to record new decision\\n' +\r\n '5. → Plan with TodoWrite (based on conventions learned)\\n' +\r\n '6. → Execute with Write/Edit (following the plan)\\n\\n' +\r\n '❌ WRONG workflow:\\n' +\r\n '1. User requests: \"I don\\'t like Tailwind, use CSS Modules\"\\n' +\r\n '2. ❌ get_context → see \"Tailwind\" → ignore conflict\\n' +\r\n '3. ❌ Write/Edit immediately (changed code but not conventions)\\n' +\r\n '4. ❌ AI_README still says \"Tailwind\" (stale documentation!)\\n\\n' +\r\n '📝 Common workflows:\\n' +\r\n '• Following existing conventions:\\n' +\r\n ' get_context_for_file → TodoWrite (optional) → Write/Edit\\n\\n' +\r\n '• Establishing NEW conventions (ARCHITECTURAL DECISION):\\n' +\r\n ' get_context_for_file → DETECT CONFLICT → update_ai_readme → get_context_for_file → TodoWrite → Write/Edit\\n\\n' +\r\n '• Empty README detected:\\n' +\r\n ' init_ai_readme → get_context_for_file → TodoWrite → Write/Edit\\n\\n' +\r\n '• Document discovered patterns:\\n' +\r\n ' Write/Edit → update_ai_readme\\n\\n' +\r\n '💡 Pro tip: Works even if target file doesn\\'t exist yet!\\n\\n' +\r\n '📌 Example:\\n' +\r\n 'User: \"I don\\'t like Tailwind, refactor Button.tsx to use CSS Modules\"\\n' +\r\n 'You: get_context_for_file({ filePath: \"src/components/Button.tsx\" })\\n' +\r\n '→ Context shows: \"Styling: Tailwind CSS\"\\n' +\r\n '→ CONFLICT DETECTED! User wants CSS Modules ≠ AI_README says Tailwind\\n' +\r\n '→ This is architectural decision, not just refactoring!\\n' +\r\n '→ Must call update_ai_readme first to change \"Tailwind\" → \"CSS Modules\"\\n' +\r\n '→ Then refactor code to match new convention',\r\n inputSchema: zodToJsonSchema(getContextSchema),\r\n },\r\n {\r\n name: 'update_ai_readme',\r\n description:\r\n 'Update an AI_README.md file to document conventions, patterns, or architectural decisions. Supports append, prepend, replace, insert-after, insert-before operations.\\n\\n' +\r\n '**CRITICAL: Token Efficiency Rules**\\n' +\r\n '- Keep content EXTREMELY concise (< 400 tokens ideal, < 600 warning, > 1000 error)\\n' +\r\n '- Only document ACTIONABLE conventions that affect code generation\\n' +\r\n '- NO explanations, NO examples, NO verbose descriptions\\n' +\r\n '- Use bullet points, avoid complete sentences when possible\\n' +\r\n '- Focus on: tech stack, naming rules, patterns, architectural decisions\\n' +\r\n '- AVOID: project background, how-to guides, documentation, obvious practices\\n\\n' +\r\n '**When to use:**\\n' +\r\n '1. BEFORE code changes: Establishing NEW conventions (ARCHITECTURAL DECISIONS)\\n' +\r\n ' - User requests style/approach change (e.g., \"use CSS Modules\", \"change to X\")\\n' +\r\n ' - User says \"I don\\'t like X, use Y instead\"\\n' +\r\n ' - User says \"let\\'s use X from now on\"\\n' +\r\n ' - Making architectural decisions that affect multiple files\\n' +\r\n ' - Choosing between approaches (e.g., state management, styling method)\\n' +\r\n ' - Setting up new architectural patterns\\n' +\r\n ' - 🚩 KEY SIGNALS: \"change to\", \"use instead\", \"don\\'t like\", \"prefer\", \"switch to\"\\n' +\r\n ' - Workflow: update_ai_readme → get_context_for_file → Write/Edit\\n\\n' +\r\n '2. AFTER code changes: Documenting discovered patterns\\n' +\r\n ' - Found consistent patterns in existing code\\n' +\r\n ' - Workflow: Write/Edit → update_ai_readme\\n\\n' +\r\n '**🎯 Identifying Architectural Decisions:**\\n' +\r\n 'Ask yourself:\\n' +\r\n '- Does this affect how FUTURE code should be written?\\n' +\r\n '- Does this change a TECHNOLOGY CHOICE (e.g., Tailwind → CSS Modules)?\\n' +\r\n '- Will this apply to MULTIPLE FILES/COMPONENTS?\\n' +\r\n '- Is user expressing a PREFERENCE that becomes a rule?\\n' +\r\n 'If YES to any → This is architectural, update AI_README FIRST!\\n\\n' +\r\n '**Quality checklist before updating:**\\n' +\r\n 'Is this a CONVENTION or PATTERN (not documentation)?\\n' +\r\n 'Will this help AI generate better code?\\n' +\r\n 'Is it concise (<3 words per bullet)?\\n' +\r\n 'Does it avoid obvious/general practices?\\n' +\r\n 'Reject: project descriptions, tutorials, general best practices\\n\\n' +\r\n '**Example (GOOD):**\\n' +\r\n '- Use CSS Modules\\n' +\r\n '- Components in PascalCase\\n' +\r\n '- Test coverage: 80%+\\n\\n' +\r\n '**Example (BAD - too verbose):**\\n' +\r\n '- We use CSS Modules for styling because it provides better type safety and scoping compared to Tailwind...\\n\\n' +\r\n '**Real-world example:**\\n' +\r\n 'User: \"I don\\'t like Tailwind, use CSS Modules\"\\n' +\r\n '→ This is ARCHITECTURAL DECISION (technology choice)\\n' +\r\n '→ Call update_ai_readme to change \"Styling: Tailwind\" → \"Styling: CSS Modules\"\\n' +\r\n '→ Then modify code following new convention',\r\n inputSchema: zodToJsonSchema(updateSchema),\r\n },\r\n {\r\n name: 'validate_ai_readmes',\r\n description:\r\n 'Validate all AI_README.md files in a project. Checks token count, structure, and content quality. Returns validation results with suggestions for improvement.',\r\n inputSchema: zodToJsonSchema(validateSchema),\r\n },\r\n {\r\n name: 'init_ai_readme',\r\n description:\r\n '🚀 Initialize and populate empty AI_README files in your project.\\n\\n' +\r\n 'Scans the project for empty or missing AI_README files and guides you through populating them with project conventions.\\n\\n' +\r\n '**When to use:**\\n' +\r\n '- First time setting up AI_README in a project\\n' +\r\n '- When get_context_for_file detects empty AI_README files\\n' +\r\n '- After creating new empty AI_README.md files manually\\n' +\r\n '- To populate multiple AI_README files at once\\n\\n' +\r\n '**What it does:**\\n' +\r\n '1. Scans project for empty AI_README files\\n' +\r\n '2. Creates root-level AI_README if none exist\\n' +\r\n '3. Provides step-by-step instructions to populate each file\\n' +\r\n '4. Guides analysis of tech stack, patterns, and conventions\\n\\n' +\r\n '**Workflow:**\\n' +\r\n '1. Call init_ai_readme\\n' +\r\n '2. Follow the instructions to explore directories\\n' +\r\n '3. Use update_ai_readme to populate each file\\n' +\r\n '4. Call get_context_for_file to verify and use conventions\\n\\n' +\r\n '**Example:** `init_ai_readme({ projectRoot: \"/path/to/project\" })`',\r\n inputSchema: zodToJsonSchema(initSchema),\r\n },\r\n ],\r\n };\r\n});\r\n\r\n// Register tool: call_tool\r\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n const { name, arguments: args } = request.params;\r\n\r\n try {\r\n if (name === 'discover_ai_readmes') {\r\n const input = discoverSchema.parse(args) as DiscoverInput;\r\n const result = await discoverAIReadmes(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'get_context_for_file') {\r\n const input = getContextSchema.parse(args) as GetContextInput;\r\n const result = await getContextForFile(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: result.formattedPrompt,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'update_ai_readme') {\r\n const input = updateSchema.parse(args) as UpdateInput;\r\n const result = await updateAIReadme(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'validate_ai_readmes') {\r\n const input = validateSchema.parse(args) as ValidateInput;\r\n const result = await validateAIReadmes(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'init_ai_readme') {\r\n const input = initSchema.parse(args) as InitInput;\r\n const result = await initAIReadme(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: result.instructions || JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n throw new Error(`Unknown tool: ${name}`);\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : String(error);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Error: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n});\r\n\r\nasync function main() {\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n\r\n console.error('AI_README MCP Server started');\r\n console.error('Available tools: discover_ai_readmes, get_context_for_file, update_ai_readme, validate_ai_readmes, init_ai_readme');\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Fatal error:', error);\r\n process.exit(1);\r\n});\r\n","/**\n * MCP Tool: discover_ai_readmes\n * Scans the project and discovers all AI_README.md files\n */\n\nimport { z } from 'zod';\nimport { AIReadmeScanner } from '../core/scanner.js';\n\nexport const discoverSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe(\"Glob patterns to exclude (e.g., ['node_modules/**', '.git/**'])\"),\n});\n\nexport type DiscoverInput = z.infer<typeof discoverSchema>;\n\nexport async function discoverAIReadmes(input: DiscoverInput) {\n const { projectRoot, excludePatterns } = input;\n\n // Create scanner with options\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: false, // Don't cache content in discovery phase\n });\n\n // Scan the project\n const index = await scanner.scan();\n\n // Format the response\n return {\n projectRoot: index.projectRoot,\n totalFound: index.readmes.length,\n readmeFiles: index.readmes.map((readme) => ({\n path: readme.path,\n scope: readme.scope,\n level: readme.level,\n patterns: readme.patterns,\n })),\n lastUpdated: index.lastUpdated.toISOString(),\n };\n}\n","/**\n * AIReadmeScanner - Scans project directories for AI_README.md files\n */\n\nimport { glob } from 'glob';\nimport { readFile } from 'fs/promises';\nimport { dirname, join } from 'path';\nimport type { ReadmeEntry, ReadmeIndex, ScannerOptions } from '../types/index.js';\n\nexport class AIReadmeScanner {\n private projectRoot: string;\n private options: Required<ScannerOptions>;\n\n constructor(projectRoot: string, options?: ScannerOptions) {\n this.projectRoot = projectRoot;\n this.options = {\n excludePatterns: options?.excludePatterns || [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/.next/**',\n '**/coverage/**',\n ],\n cacheContent: options?.cacheContent ?? true,\n readmeFilename: options?.readmeFilename || 'AI_README.md',\n };\n }\n\n /**\n * Scan the project directory for AI_README.md files\n */\n async scan(): Promise<ReadmeIndex> {\n const pattern = `**/${this.options.readmeFilename}`;\n const ignore = this.options.excludePatterns;\n\n // Find all AI_README.md files\n const files = await glob(pattern, {\n cwd: this.projectRoot,\n ignore,\n absolute: false,\n nodir: true,\n });\n\n // Build ReadmeEntry objects\n const readmes: ReadmeEntry[] = [];\n\n for (const file of files) {\n const entry = await this.createReadmeEntry(file);\n readmes.push(entry);\n }\n\n // Sort by level (root first, then deeper levels)\n readmes.sort((a, b) => a.level - b.level);\n\n return {\n projectRoot: this.projectRoot,\n readmes,\n lastUpdated: new Date(),\n };\n }\n\n /**\n * Create a ReadmeEntry from a file path\n */\n private async createReadmeEntry(filePath: string): Promise<ReadmeEntry> {\n // Normalize path to use forward slashes (Unix-style) for consistency\n const normalizedPath = filePath.replace(/\\\\/g, '/');\n const dir = dirname(normalizedPath);\n const level = dir === '.' ? 0 : dir.split('/').length;\n const scope = dir === '.' ? 'root' : dir.replace(/\\//g, '-');\n\n // Generate glob patterns this README covers\n const patterns = this.generatePatterns(dir);\n\n // Optionally cache content\n let content: string | undefined;\n if (this.options.cacheContent) {\n try {\n const fullPath = join(this.projectRoot, filePath);\n content = await readFile(fullPath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read ${filePath}:`, error);\n }\n }\n\n return {\n path: normalizedPath,\n scope,\n level,\n patterns,\n content,\n };\n }\n\n /**\n * Generate glob patterns that this README covers\n */\n private generatePatterns(dir: string): string[] {\n if (dir === '.') {\n return ['**/*']; // Root level covers everything\n }\n\n return [\n `${dir}/**/*`, // All files in this directory and subdirectories\n `${dir}/*`, // Direct children\n ];\n }\n\n /**\n * Refresh the scan (re-scan the project)\n */\n async refresh(): Promise<ReadmeIndex> {\n return this.scan();\n }\n\n /**\n * Get the project root directory\n */\n getProjectRoot(): string {\n return this.projectRoot;\n }\n\n /**\n * Get current scanner options\n */\n getOptions(): Required<ScannerOptions> {\n return { ...this.options };\n }\n}\n","/**\r\n * MCP Tool: get_context_for_file\r\n * Gets relevant AI_README context for a specific file path\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport { AIReadmeScanner } from '../core/scanner.js';\r\nimport { ContextRouter } from '../core/router.js';\r\n\r\nexport const getContextSchema = z.object({\r\n projectRoot: z.string().describe('The root directory of the project'),\r\n filePath: z\r\n .string()\r\n .describe(\r\n 'The file path to get context for (relative to project root). ' +\r\n 'MUST be a FILE path, not a directory. ' +\r\n 'Examples: \"src/app/page.tsx\", \"README.md\", \"package.json\". ' +\r\n 'If you want context for a directory, specify any file within it (e.g., \"src/components/Button.tsx\" instead of \"src/components\").'\r\n ),\r\n includeRoot: z\r\n .boolean()\r\n .optional()\r\n .default(true)\r\n .describe('Whether to include root-level AI_README (default: true)'),\r\n excludePatterns: z\r\n .array(z.string())\r\n .optional()\r\n .describe('Glob patterns to exclude when scanning'),\r\n});\r\n\r\nexport type GetContextInput = z.infer<typeof getContextSchema>;\r\n\r\nexport async function getContextForFile(input: GetContextInput) {\r\n const { projectRoot, filePath, includeRoot, excludePatterns } = input;\r\n\r\n // First, scan the project to build the index\r\n const scanner = new AIReadmeScanner(projectRoot, {\r\n excludePatterns,\r\n cacheContent: true, // Cache content for context retrieval\r\n });\r\n\r\n const index = await scanner.scan();\r\n\r\n // Create router and get context\r\n const router = new ContextRouter(index);\r\n const contexts = await router.getContextForFile(filePath, includeRoot);\r\n\r\n // Check for empty AI_README files\r\n const hasEmptyReadmes = contexts.some(ctx => !ctx.content || ctx.content.trim().length === 0);\r\n const hasNoReadmes = contexts.length === 0;\r\n\r\n // Format the response with a helpful prompt template\r\n const formattedContexts = contexts.map((ctx) => ({\r\n path: ctx.path,\r\n relevance: ctx.relevance,\r\n distance: ctx.distance,\r\n content: ctx.content,\r\n }));\r\n\r\n // Generate a formatted prompt for the AI\r\n let promptText = `## 📚 Project Context for: ${filePath}\\n\\n`;\r\n\r\n // Simple check: if empty or no READMEs, suggest using init tool\r\n if (hasNoReadmes || hasEmptyReadmes) {\r\n promptText += `⚠️ **Empty or missing AI_README files detected.**\\n\\n`;\r\n promptText += `**Recommended Action:** Use the \\`init_ai_readme\\` tool to automatically populate AI_README files.\\n\\n`;\r\n promptText += `\\`\\`\\`\\n`;\r\n promptText += `init_ai_readme({ projectRoot: \"${projectRoot.replace(/\\\\/g, '/')}\" })\\n`;\r\n promptText += `\\`\\`\\`\\n\\n`;\r\n promptText += `This tool will:\\n`;\r\n promptText += `- Scan the project for empty AI_README files\\n`;\r\n promptText += `- Guide you through populating them with conventions\\n`;\r\n promptText += `- Ensure consistent documentation across your project\\n\\n`;\r\n promptText += `💡 Alternatively, you can manually create and populate AI_README.md files, then call this tool again.\\n\\n`;\r\n promptText += `---\\n\\n`;\r\n }\r\n\r\n // Filter out empty contexts (content with only whitespace)\r\n const nonEmptyContexts = contexts.filter(ctx => ctx.content && ctx.content.trim().length > 0);\r\n\r\n if (nonEmptyContexts.length > 0) {\r\n // Show non-empty contexts\r\n for (const ctx of nonEmptyContexts) {\r\n if (ctx.relevance === 'root') {\r\n promptText += `### Root Conventions (${ctx.path})\\n\\n`;\r\n } else if (ctx.relevance === 'direct') {\r\n promptText += `### Direct Module Conventions (${ctx.path})\\n\\n`;\r\n } else {\r\n promptText += `### Parent Module Conventions (${ctx.path})\\n\\n`;\r\n }\r\n\r\n promptText += ctx.content + '\\n\\n';\r\n }\r\n\r\n promptText += `---\\n`;\r\n promptText += `**Important:**\\n`;\r\n promptText += `- Follow the above conventions when making changes\\n`;\r\n promptText += `- When establishing NEW conventions: update AI_README first → get context → write code\\n`;\r\n promptText += `- When discovering patterns in existing code: document them in AI_README afterward\\n`;\r\n }\r\n\r\n return {\r\n filePath,\r\n totalContexts: contexts.length,\r\n contexts: formattedContexts,\r\n formattedPrompt: promptText,\r\n };\r\n}\r\n","/**\n * ContextRouter - Routes file paths to relevant AI_README contexts\n */\n\nimport { minimatch } from 'minimatch';\nimport { dirname, join } from 'path';\nimport { readFile } from 'fs/promises';\nimport type { ReadmeContext, ReadmeIndex, ReadmeEntry } from '../types/index.js';\n\nexport class ContextRouter {\n private index: ReadmeIndex;\n\n constructor(index: ReadmeIndex) {\n this.index = index;\n }\n\n /**\n * Get relevant AI_README contexts for a specific file path\n * @param filePath - The file path relative to project root\n * @param includeRoot - Whether to include root-level README (default: true)\n */\n async getContextForFile(\n filePath: string,\n includeRoot: boolean = true\n ): Promise<ReadmeContext[]> {\n const contexts: ReadmeContext[] = [];\n\n // Find matching READMEs\n for (const readme of this.index.readmes) {\n const match = this.matchesPath(filePath, readme);\n\n if (!match) continue;\n\n // Skip root if not requested\n if (!includeRoot && readme.level === 0) continue;\n\n // Calculate distance from file to README\n const distance = this.calculateDistance(filePath, readme);\n\n // Get content\n const content = await this.getReadmeContent(readme);\n\n // Determine relevance\n const relevance = this.determineRelevance(filePath, readme);\n\n contexts.push({\n path: readme.path,\n content,\n relevance,\n distance,\n });\n }\n\n // Sort by distance (closest first) and then by relevance\n contexts.sort((a, b) => {\n if (a.distance !== b.distance) {\n return a.distance - b.distance;\n }\n // If same distance, prioritize direct > parent > root\n const relevanceOrder = { direct: 0, parent: 1, root: 2 };\n return relevanceOrder[a.relevance] - relevanceOrder[b.relevance];\n });\n\n return contexts;\n }\n\n /**\n * Get contexts for multiple files\n */\n async getContextForFiles(filePaths: string[]): Promise<Map<string, ReadmeContext[]>> {\n const results = new Map<string, ReadmeContext[]>();\n\n for (const filePath of filePaths) {\n const contexts = await this.getContextForFile(filePath);\n results.set(filePath, contexts);\n }\n\n return results;\n }\n\n /**\n * Check if a file path matches a README's patterns\n */\n private matchesPath(filePath: string, readme: ReadmeEntry): boolean {\n return readme.patterns.some(pattern => {\n return minimatch(filePath, pattern, { dot: true });\n });\n }\n\n /**\n * Calculate the directory distance between a file and a README\n */\n private calculateDistance(filePath: string, readme: ReadmeEntry): number {\n const fileDir = dirname(filePath);\n const readmeDir = dirname(readme.path);\n\n // If README is at root\n if (readmeDir === '.') {\n return fileDir === '.' ? 0 : fileDir.split('/').length;\n }\n\n // If file is in the same directory as README\n if (fileDir === readmeDir) {\n return 0;\n }\n\n // If file is in a subdirectory of README's directory\n if (fileDir.startsWith(readmeDir + '/')) {\n const subPath = fileDir.slice(readmeDir.length + 1);\n return subPath.split('/').length;\n }\n\n // Calculate levels up\n const fileParts = fileDir.split('/');\n const readmeParts = readmeDir.split('/');\n\n // Find common ancestor\n let commonDepth = 0;\n for (let i = 0; i < Math.min(fileParts.length, readmeParts.length); i++) {\n if (fileParts[i] === readmeParts[i]) {\n commonDepth++;\n } else {\n break;\n }\n }\n\n // Distance is the sum of levels to go up and down\n return (fileParts.length - commonDepth) + (readmeParts.length - commonDepth);\n }\n\n /**\n * Determine the relevance type of a README for a file\n */\n private determineRelevance(\n filePath: string,\n readme: ReadmeEntry\n ): 'root' | 'direct' | 'parent' {\n const fileDir = dirname(filePath);\n const readmeDir = dirname(readme.path);\n\n // Root level README\n if (readmeDir === '.') {\n return 'root';\n }\n\n // Direct match (same directory)\n if (fileDir === readmeDir) {\n return 'direct';\n }\n\n // Parent directory\n if (fileDir.startsWith(readmeDir + '/')) {\n return 'parent';\n }\n\n return 'parent';\n }\n\n /**\n * Get the content of a README (from cache or file system)\n */\n private async getReadmeContent(readme: ReadmeEntry): Promise<string> {\n // Return cached content if available\n if (readme.content) {\n return readme.content;\n }\n\n // Otherwise read from file system\n try {\n const fullPath = join(this.index.projectRoot, readme.path);\n return await readFile(fullPath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read ${readme.path}:`, error);\n return `[Error: Could not read ${readme.path}]`;\n }\n }\n\n /**\n * Update the index (useful after re-scanning)\n */\n updateIndex(index: ReadmeIndex): void {\n this.index = index;\n }\n\n /**\n * Get the current index\n */\n getIndex(): ReadmeIndex {\n return this.index;\n }\n}\n","import { z } from 'zod';\nimport { dirname } from 'path';\nimport { ReadmeUpdater, UpdateOperation } from '../core/updater.js';\nimport { ReadmeValidator } from '../core/validator.js';\n\n/**\n * Zod schema for update operation\n */\nconst updateOperationSchema = z.object({\n type: z.enum(['replace', 'append', 'prepend', 'insert-after', 'insert-before']).describe(\n 'Type of update operation'\n ),\n section: z.string().optional().describe(\n 'Section heading to target (e.g., \"## Coding Conventions\")'\n ),\n searchText: z.string().optional().describe(\n 'Text to search for (required for replace operation)'\n ),\n content: z.string().describe('Content to add or replace'),\n});\n\n/**\n * Zod schema for update_ai_readme tool\n */\nexport const updateSchema = z.object({\n readmePath: z.string().describe('Path to the AI_README.md file to update'),\n operations: z.array(updateOperationSchema).describe(\n 'List of update operations to perform'\n ),\n});\n\nexport type UpdateInput = z.infer<typeof updateSchema>;\n\n/**\n * Update an AI_README.md file with specified operations\n *\n * @param input - Update parameters\n * @returns Update result with changes\n *\n * @example\n * ```typescript\n * await updateAIReadme({\n * readmePath: 'apps/frontend/AI_README.md',\n * operations: [{\n * type: 'insert-after',\n * section: '## Directory Structure',\n * content: '├── src/hooks/ # Custom React hooks'\n * }]\n * });\n * ```\n *\n * Note: Changes are immediately written to the file.\n * Use git to track changes and rollback if needed.\n */\nexport async function updateAIReadme(input: UpdateInput) {\n const { readmePath, operations } = input;\n\n const updater = new ReadmeUpdater();\n\n // Perform update\n const result = await updater.update(readmePath, operations as UpdateOperation[]);\n\n if (!result.success) {\n return {\n success: false,\n readmePath,\n error: result.error,\n summary: `Failed to update ${readmePath}: ${result.error}`,\n };\n }\n\n // Auto-validate after update\n try {\n const projectRoot = dirname(dirname(readmePath)); // Approximate project root\n const config = await ReadmeValidator.loadConfig(projectRoot);\n const validator = new ReadmeValidator(config || undefined);\n const validation = await validator.validate(readmePath);\n\n // Collect validation warnings\n const warnings = validation.issues\n .filter(i => i.type === 'warning' || i.type === 'error')\n .map(i => `[${i.type.toUpperCase()}] ${i.message}`);\n\n const workflowTip = result.changes.some(c =>\n c.operation === 'replace' || c.operation === 'append' || c.operation === 'prepend'\n )\n ? '\\n\\n💡 NEXT STEP: Use get_context_for_file before writing code to ensure you\\'re following the updated conventions.'\n : '';\n\n return {\n success: true,\n readmePath,\n changes: result.changes,\n summary: `Successfully updated ${readmePath} with ${result.changes.length} operation(s). Use 'git diff' to review changes.${workflowTip}`,\n validation: {\n valid: validation.valid,\n score: validation.score,\n warnings: warnings.length > 0 ? warnings : undefined,\n stats: validation.stats,\n },\n };\n } catch (validationError) {\n // If validation fails, still return success for the update\n return {\n success: true,\n readmePath,\n changes: result.changes,\n summary: `Successfully updated ${readmePath} with ${result.changes.length} operation(s). Use 'git diff' to review changes.`,\n validation: {\n valid: false,\n error: validationError instanceof Error ? validationError.message : 'Validation failed',\n },\n };\n }\n}\n","import { readFile, writeFile } from 'fs/promises';\nimport { existsSync } from 'fs';\n\nexport interface UpdateOperation {\n type: 'replace' | 'append' | 'prepend' | 'insert-after' | 'insert-before';\n section?: string; // Section heading to target (e.g., \"## Coding Conventions\")\n searchText?: string; // Text to search for (for replace operations)\n content: string; // Content to add/replace\n}\n\nexport interface UpdateResult {\n success: boolean;\n changes: {\n operation: string;\n section?: string;\n linesAdded: number;\n linesRemoved: number;\n }[];\n error?: string;\n}\n\n/**\n * ReadmeUpdater - Handles updating AI_README.md files\n *\n * Features:\n * - Section-based updates\n * - Multiple operation types (append, prepend, replace, insert-after, insert-before)\n * - Detailed change tracking\n *\n * Note: Version control is handled by Git. Use git diff/revert for rollback.\n */\nexport class ReadmeUpdater {\n constructor() {\n // No configuration needed\n }\n\n /**\n * Update a README file with given operations\n *\n * @param readmePath - Path to the AI_README.md file\n * @param operations - List of update operations\n * @returns Update result with changes\n */\n async update(\n readmePath: string,\n operations: UpdateOperation[]\n ): Promise<UpdateResult> {\n try {\n // Read current content (empty string if file doesn't exist or is empty)\n let content = '';\n if (existsSync(readmePath)) {\n content = await readFile(readmePath, 'utf-8');\n }\n\n // Apply operations\n let updatedContent = content;\n const changes: UpdateResult['changes'] = [];\n\n for (const operation of operations) {\n const result = await this.applyOperation(updatedContent, operation);\n updatedContent = result.content;\n changes.push(result.change);\n }\n\n // Write updated content\n await writeFile(readmePath, updatedContent, 'utf-8');\n\n return {\n success: true,\n changes,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n changes: [],\n };\n }\n }\n\n /**\n * Apply a single update operation to content\n *\n * @param content - Current content\n * @param operation - Operation to apply\n * @returns Updated content and change info\n */\n private async applyOperation(\n content: string,\n operation: UpdateOperation\n ): Promise<{ content: string; change: UpdateResult['changes'][0] }> {\n const lines = content.split('\\n');\n let updatedLines = [...lines];\n let linesAdded = 0;\n let linesRemoved = 0;\n\n switch (operation.type) {\n case 'append': {\n // Add content to the end\n updatedLines.push('', operation.content);\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'prepend': {\n // Add content to the beginning\n updatedLines.unshift(operation.content, '');\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'replace': {\n // Replace specific text\n if (!operation.searchText) {\n throw new Error('searchText is required for replace operation');\n }\n\n const originalContent = updatedLines.join('\\n');\n const newContent = originalContent.replace(\n operation.searchText,\n operation.content\n );\n\n if (originalContent === newContent) {\n throw new Error(`Text not found: ${operation.searchText}`);\n }\n\n updatedLines = newContent.split('\\n');\n linesRemoved = operation.searchText.split('\\n').length;\n linesAdded = operation.content.split('\\n').length;\n break;\n }\n\n case 'insert-after': {\n // Insert content after a section\n if (!operation.section) {\n throw new Error('section is required for insert-after operation');\n }\n\n const sectionIndex = this.findSectionIndex(updatedLines, operation.section);\n if (sectionIndex === -1) {\n throw new Error(`Section not found: ${operation.section}`);\n }\n\n // Find the end of the section content\n const insertIndex = this.findSectionEnd(updatedLines, sectionIndex);\n updatedLines.splice(insertIndex, 0, '', operation.content);\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'insert-before': {\n // Insert content before a section\n if (!operation.section) {\n throw new Error('section is required for insert-before operation');\n }\n\n const sectionIndex = this.findSectionIndex(updatedLines, operation.section);\n if (sectionIndex === -1) {\n throw new Error(`Section not found: ${operation.section}`);\n }\n\n updatedLines.splice(sectionIndex, 0, operation.content, '');\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n default:\n throw new Error(`Unknown operation type: ${operation.type}`);\n }\n\n return {\n content: updatedLines.join('\\n'),\n change: {\n operation: operation.type,\n section: operation.section,\n linesAdded,\n linesRemoved,\n },\n };\n }\n\n /**\n * Find the index of a section heading\n *\n * @param lines - Content lines\n * @param section - Section heading (e.g., \"## Coding Conventions\")\n * @returns Index of the section, or -1 if not found\n */\n private findSectionIndex(lines: string[], section: string): number {\n return lines.findIndex((line) => line.trim() === section.trim());\n }\n\n /**\n * Find the end of a section (before the next section of same or higher level)\n *\n * @param lines - Content lines\n * @param startIndex - Index of the section heading\n * @returns Index where the section ends\n */\n private findSectionEnd(lines: string[], startIndex: number): number {\n const startLine = lines[startIndex];\n if (!startLine) {\n return lines.length;\n }\n\n const sectionLevel = this.getSectionLevel(startLine);\n\n for (let i = startIndex + 1; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n\n const trimmedLine = line.trim();\n if (trimmedLine.startsWith('#')) {\n const level = this.getSectionLevel(trimmedLine);\n if (level <= sectionLevel) {\n return i;\n }\n }\n }\n\n return lines.length;\n }\n\n /**\n * Get the heading level of a markdown section\n *\n * @param line - Line containing a heading\n * @returns Heading level (1-6)\n */\n private getSectionLevel(line: string): number {\n const match = line.match(/^(#{1,6})\\s/);\n return match && match[1] ? match[1].length : 0;\n }\n}\n","import { readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport type {\n ValidationConfig,\n ResolvedValidationConfig,\n ValidationResult,\n ValidationIssue,\n} from '../types/index.js';\nimport { DEFAULT_VALIDATION_CONFIG } from '../types/index.js';\n\n/**\n * ReadmeValidator - Validates AI_README.md files\n *\n * Features:\n * - Token count validation\n * - Structure validation\n * - Content quality checks\n * - Configurable rules via constructor parameter\n */\nexport class ReadmeValidator {\n private config: ResolvedValidationConfig;\n\n constructor(config?: Partial<ValidationConfig>) {\n // Merge user config with defaults\n this.config = this.mergeConfig(config || {});\n }\n\n /**\n * Merge user config with default config\n */\n private mergeConfig(userConfig: Partial<ValidationConfig>): ResolvedValidationConfig {\n return {\n maxTokens: userConfig.maxTokens ?? DEFAULT_VALIDATION_CONFIG.maxTokens,\n rules: {\n ...DEFAULT_VALIDATION_CONFIG.rules,\n ...(userConfig.rules || {}),\n },\n tokenLimits: {\n ...DEFAULT_VALIDATION_CONFIG.tokenLimits,\n ...(userConfig.tokenLimits || {}),\n },\n };\n }\n\n /**\n * Validate a single AI_README.md file\n *\n * @param readmePath - Path to the README file\n * @returns Validation result\n */\n async validate(readmePath: string): Promise<ValidationResult> {\n const issues: ValidationIssue[] = [];\n\n // Check file exists\n if (!existsSync(readmePath)) {\n return {\n valid: false,\n filePath: readmePath,\n issues: [\n {\n type: 'error',\n rule: 'structure',\n message: `File not found: ${readmePath}`,\n },\n ],\n };\n }\n\n // Read content\n const content = await readFile(readmePath, 'utf-8');\n\n // Check if file is empty\n if (content.trim().length === 0) {\n issues.push({\n type: 'error',\n rule: 'empty-content',\n message: 'README file is empty',\n suggestion: 'Add content to the README file',\n });\n }\n\n // Calculate statistics\n const lines = content.split('\\n');\n const tokens = this.estimateTokens(content);\n const characters = content.length;\n\n // Validate token count\n this.validateTokenCount(tokens, issues);\n\n // Validate structure\n this.validateStructure(content, lines, issues);\n\n // Validate line length\n this.validateLineLength(lines, issues);\n\n // Validate code blocks\n this.validateCodeBlocks(content, issues);\n\n // Calculate score\n const score = this.calculateScore(issues, tokens);\n\n return {\n valid: !issues.some((i) => i.type === 'error'),\n filePath: readmePath,\n issues,\n score,\n stats: {\n tokens,\n lines: lines.length,\n characters,\n },\n };\n }\n\n /**\n * Estimate token count (simple word-based estimation)\n * Formula: words * 1.3 (approximate token-to-word ratio)\n */\n private estimateTokens(content: string): number {\n const words = content.split(/\\s+/).filter((w) => w.length > 0).length;\n return Math.round(words * 1.3);\n }\n\n /**\n * Validate token count against limits\n */\n private validateTokenCount(tokens: number, issues: ValidationIssue[]): void {\n const { tokenLimits, maxTokens } = this.config;\n\n if (tokens > tokenLimits.error) {\n issues.push({\n type: 'error',\n rule: 'token-count',\n message: `README is too long (${tokens} tokens). Maximum recommended: ${maxTokens} tokens.`,\n suggestion: 'Remove unnecessary content, use bullet points instead of paragraphs, and avoid code examples.',\n });\n } else if (tokens > tokenLimits.warning) {\n issues.push({\n type: 'warning',\n rule: 'token-count',\n message: `README is quite long (${tokens} tokens). Consider keeping it under ${tokenLimits.good} tokens.`,\n suggestion: 'Simplify content and remove redundant information.',\n });\n } else if (tokens > tokenLimits.good) {\n issues.push({\n type: 'info',\n rule: 'token-count',\n message: `README length is acceptable (${tokens} tokens).`,\n });\n }\n }\n\n /**\n * Validate README structure\n */\n private validateStructure(_content: string, lines: string[], issues: ValidationIssue[]): void {\n // Check for H1 heading\n if (this.config.rules.requireH1) {\n const hasH1 = lines.some((line) => line.trim().match(/^#\\s+[^#]/));\n if (!hasH1) {\n issues.push({\n type: 'error',\n rule: 'require-h1',\n message: 'README must have a H1 heading (# Title)',\n suggestion: 'Add a title at the beginning of the file: # Project Name',\n });\n }\n }\n\n // Check for required sections\n if (this.config.rules.requireSections && this.config.rules.requireSections.length > 0) {\n for (const section of this.config.rules.requireSections) {\n const hasSection = lines.some((line) => line.trim() === section);\n if (!hasSection) {\n issues.push({\n type: 'warning',\n rule: 'require-sections',\n message: `Missing required section: ${section}`,\n suggestion: `Add section: ${section}`,\n });\n }\n }\n }\n }\n\n /**\n * Validate line length\n */\n private validateLineLength(lines: string[], issues: ValidationIssue[]): void {\n const { maxLineLength } = this.config.rules;\n const longLines = lines\n .map((line, index) => ({ line, index }))\n .filter(({ line }) => line.length > maxLineLength);\n\n if (longLines.length > 3) {\n // Only warn if there are many long lines\n issues.push({\n type: 'info',\n rule: 'line-length',\n message: `${longLines.length} lines exceed ${maxLineLength} characters`,\n suggestion: 'Consider breaking long lines for better readability',\n });\n }\n }\n\n /**\n * Validate code blocks\n */\n private validateCodeBlocks(content: string, issues: ValidationIssue[]): void {\n if (!this.config.rules.allowCodeBlocks) {\n const codeBlockCount = (content.match(/```/g) || []).length / 2;\n if (codeBlockCount > 0) {\n issues.push({\n type: 'warning',\n rule: 'code-blocks',\n message: `Found ${codeBlockCount} code blocks. Code examples consume many tokens.`,\n suggestion: 'Remove code examples or move them to separate documentation.',\n });\n }\n }\n }\n\n /**\n * Calculate quality score (0-100)\n */\n private calculateScore(issues: ValidationIssue[], tokens: number): number {\n let score = 100;\n\n // Deduct points for issues\n for (const issue of issues) {\n if (issue.type === 'error') score -= 20;\n else if (issue.type === 'warning') score -= 10;\n else if (issue.type === 'info') score -= 2;\n }\n\n // Deduct points for excessive length\n const { tokenLimits } = this.config;\n if (tokens > tokenLimits.error) score -= 30;\n else if (tokens > tokenLimits.warning) score -= 15;\n else if (tokens < tokenLimits.excellent) score += 10; // Bonus for concise READMEs\n\n return Math.max(0, Math.min(100, score));\n }\n\n /**\n * Load validation config from .aireadme.config.json\n *\n * @param projectRoot - Project root directory\n * @returns Validation config or null if not found\n */\n static async loadConfig(projectRoot: string): Promise<Partial<ValidationConfig> | null> {\n const configPath = join(projectRoot, '.aireadme.config.json');\n\n if (!existsSync(configPath)) {\n return null;\n }\n\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n return config.validation || config; // Support both formats\n } catch (error) {\n console.error(`Failed to load config from ${configPath}:`, error);\n return null;\n }\n }\n}\n","/**\n * Core type definitions for AI_README MCP Server\n */\n\n/**\n * Represents a single AI_README.md file entry in the index\n */\nexport interface ReadmeEntry {\n /** Absolute or relative path to the AI_README.md file */\n path: string;\n /** Scope identifier (e.g., 'root', 'frontend', 'backend') */\n scope: string;\n /** Directory level depth (0 for root) */\n level: number;\n /** Glob patterns this README covers */\n patterns: string[];\n /** Cached content of the README (optional) */\n content?: string;\n}\n\n/**\n * Index of all AI_README files in the project\n */\nexport interface ReadmeIndex {\n /** Root directory of the project */\n projectRoot: string;\n /** List of discovered README entries */\n readmes: ReadmeEntry[];\n /** Timestamp of last index update */\n lastUpdated: Date;\n}\n\n/**\n * Context information for a specific file\n */\nexport interface ReadmeContext {\n /** Path to the AI_README.md file */\n path: string;\n /** Content of the README */\n content: string;\n /** Relevance type */\n relevance: 'root' | 'direct' | 'parent';\n /** Distance in directory levels from target file */\n distance: number;\n}\n\n/**\n * Options for the scanner\n */\nexport interface ScannerOptions {\n /** Patterns to exclude from scanning */\n excludePatterns?: string[];\n /** Whether to cache README contents */\n cacheContent?: boolean;\n /** Custom README filename (default: 'AI_README.md') */\n readmeFilename?: string;\n}\n\n/**\n * Update action types for AI_README modifications\n */\nexport type UpdateAction = 'append' | 'replace' | 'delete';\n\n/**\n * Result of an update operation\n */\nexport interface UpdateResult {\n /** Whether the update succeeded */\n success: boolean;\n /** Path to the updated file */\n updatedPath: string;\n /** Path to backup file (if created) */\n backupPath?: string;\n /** Diff of changes made */\n diff: string;\n}\n\n/**\n * Options for the updater\n */\nexport interface UpdaterOptions {\n /** Directory for backups (default: '.ai_readme_history') */\n backupDir?: string;\n /** Whether to create backups */\n createBackup?: boolean;\n}\n\n/**\n * Validation configuration\n */\nexport interface ValidationConfig {\n /** Maximum tokens allowed (default: 500) */\n maxTokens?: number;\n /** Validation rules */\n rules?: {\n /** Require H1 heading (default: true) */\n requireH1?: boolean;\n /** Required sections (default: []) */\n requireSections?: string[];\n /** Allow code blocks (default: true) */\n allowCodeBlocks?: boolean;\n /** Maximum line length (default: 120) */\n maxLineLength?: number;\n };\n /** Token limit thresholds */\n tokenLimits?: {\n /** Excellent: under this many tokens (default: 300) */\n excellent?: number;\n /** Good: under this many tokens (default: 500) */\n good?: number;\n /** Warning: under this many tokens (default: 800) */\n warning?: number;\n /** Error: over this many tokens (default: 1200) */\n error?: number;\n };\n}\n\n/**\n * Fully resolved validation configuration (all properties required)\n */\nexport interface ResolvedValidationConfig {\n maxTokens: number;\n rules: {\n requireH1: boolean;\n requireSections: string[];\n allowCodeBlocks: boolean;\n maxLineLength: number;\n };\n tokenLimits: {\n excellent: number;\n good: number;\n warning: number;\n error: number;\n };\n}\n\n/**\n * Default validation configuration\n */\nexport const DEFAULT_VALIDATION_CONFIG: ResolvedValidationConfig = {\n maxTokens: 400,\n rules: {\n requireH1: true,\n requireSections: [],\n allowCodeBlocks: false,\n maxLineLength: 100,\n },\n tokenLimits: {\n excellent: 200,\n good: 400,\n warning: 600,\n error: 1000,\n },\n};\n\n/**\n * Validation issue severity\n */\nexport type ValidationSeverity = 'error' | 'warning' | 'info';\n\n/**\n * Validation rule type\n */\nexport type ValidationRule =\n | 'token-count'\n | 'require-h1'\n | 'require-sections'\n | 'code-blocks'\n | 'line-length'\n | 'empty-content'\n | 'structure';\n\n/**\n * Validation issue\n */\nexport interface ValidationIssue {\n /** Issue severity */\n type: ValidationSeverity;\n /** Rule that triggered this issue */\n rule: ValidationRule;\n /** Issue message */\n message: string;\n /** Line number (if applicable) */\n line?: number;\n /** Suggestion for fixing */\n suggestion?: string;\n}\n\n/**\n * Validation result for a single README\n */\nexport interface ValidationResult {\n /** Whether validation passed */\n valid: boolean;\n /** Path to the README file */\n filePath: string;\n /** List of issues found */\n issues: ValidationIssue[];\n /** Quality score (0-100) */\n score?: number;\n /** Token count statistics */\n stats?: {\n tokens: number;\n lines: number;\n characters: number;\n };\n}\n","import { z } from 'zod';\nimport { ReadmeValidator } from '../core/validator.js';\nimport { AIReadmeScanner } from '../core/scanner.js';\nimport type { ValidationConfig } from '../types/index.js';\n\n/**\n * Zod schema for validate_ai_readmes tool\n */\nexport const validateSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z.array(z.string()).optional().describe(\n 'Glob patterns to exclude (e.g., [\"node_modules/**\", \".git/**\"])'\n ),\n config: z.object({\n maxTokens: z.number().optional(),\n rules: z.object({\n requireH1: z.boolean().optional(),\n requireSections: z.array(z.string()).optional(),\n allowCodeBlocks: z.boolean().optional(),\n maxLineLength: z.number().optional(),\n }).optional(),\n tokenLimits: z.object({\n excellent: z.number().optional(),\n good: z.number().optional(),\n warning: z.number().optional(),\n error: z.number().optional(),\n }).optional(),\n }).optional().describe('Custom validation configuration (optional, uses defaults if not provided)'),\n});\n\nexport type ValidateInput = z.infer<typeof validateSchema>;\n\n/**\n * Validate all AI_README.md files in a project\n *\n * @param input - Validation parameters\n * @returns Validation results for all README files\n *\n * @example\n * ```typescript\n * await validateAIReadmes({\n * projectRoot: '/path/to/project',\n * excludePatterns: ['node_modules/**'],\n * config: {\n * maxTokens: 500,\n * rules: {\n * requireH1: true,\n * requireSections: ['## Architecture', '## Conventions']\n * }\n * }\n * });\n * ```\n */\nexport async function validateAIReadmes(input: ValidateInput) {\n const { projectRoot, excludePatterns, config: userConfig } = input;\n\n try {\n // Use provided config, fallback to file config if available, then defaults\n let config: Partial<ValidationConfig> | undefined = userConfig;\n\n if (!config) {\n // Optionally load from .aireadme.config.json if it exists\n const fileConfig = await ReadmeValidator.loadConfig(projectRoot);\n if (fileConfig) {\n config = fileConfig;\n }\n }\n\n // Create validator with config\n const validator = new ReadmeValidator(config);\n\n // Scan for all README files\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns: excludePatterns || [],\n cacheContent: false,\n });\n const index = await scanner.scan();\n\n // Validate each README\n const results = [];\n for (const readme of index.readmes) {\n const result = await validator.validate(readme.path);\n results.push(result);\n }\n\n // Calculate overall statistics\n const totalFiles = results.length;\n const validFiles = results.filter(r => r.valid).length;\n const totalIssues = results.reduce((sum, r) => sum + r.issues.length, 0);\n const averageScore = totalFiles > 0\n ? Math.round(results.reduce((sum, r) => sum + (r.score || 0), 0) / totalFiles)\n : 0;\n\n // Group issues by severity\n const issuesBySeverity = {\n error: 0,\n warning: 0,\n info: 0,\n };\n for (const result of results) {\n for (const issue of result.issues) {\n issuesBySeverity[issue.type]++;\n }\n }\n\n return {\n success: true,\n projectRoot,\n summary: {\n totalFiles,\n validFiles,\n invalidFiles: totalFiles - validFiles,\n totalIssues,\n averageScore,\n issuesBySeverity,\n },\n results,\n message: totalIssues === 0\n ? `All ${totalFiles} README files passed validation! Average score: ${averageScore}/100`\n : `Found ${totalIssues} issues across ${totalFiles} README files. ${validFiles} files passed validation.`,\n };\n } catch (error) {\n return {\n success: false,\n projectRoot,\n error: error instanceof Error ? error.message : String(error),\n message: `Validation failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n","/**\n * MCP Tool: init_ai_readme\n * Scans project for empty AI_README files and populates them with AI-generated content\n */\n\nimport { z } from 'zod';\nimport { writeFile, readFile } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport { AIReadmeScanner } from '../core/scanner.js';\n\nexport const initSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe('Glob patterns to exclude when scanning'),\n targetPath: z\n .string()\n .optional()\n .describe('Specific directory to initialize (optional, defaults to scanning entire project)'),\n});\n\nexport type InitInput = z.infer<typeof initSchema>;\n\ninterface EmptyReadmeInfo {\n path: string;\n dirPath: string;\n needsCreation: boolean;\n}\n\n/**\n * Initialize AI_README files in the project\n * - Scans for empty or missing AI_README files\n * - Prompts AI to populate them with project conventions\n */\nexport async function initAIReadme(input: InitInput) {\n const { projectRoot, excludePatterns, targetPath } = input;\n\n // Scan the project\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: true,\n });\n\n const index = await scanner.scan();\n\n // Find empty AI_README files\n const emptyReadmes: EmptyReadmeInfo[] = [];\n\n // Check existing AI_READMEs\n for (const readme of index.readmes) {\n if (!readme.content || readme.content.trim().length === 0) {\n emptyReadmes.push({\n path: readme.path,\n dirPath: readme.path.replace(/[\\/\\\\]AI_README\\.md$/, ''),\n needsCreation: false,\n });\n }\n }\n\n // If no AI_README exists at all, create one at project root\n if (index.readmes.length === 0) {\n const rootReadmePath = join(projectRoot, 'AI_README.md');\n\n // Create empty file if it doesn't exist\n if (!existsSync(rootReadmePath)) {\n await writeFile(rootReadmePath, '', 'utf-8');\n }\n\n emptyReadmes.push({\n path: rootReadmePath,\n dirPath: projectRoot,\n needsCreation: true,\n });\n }\n\n // If targetPath is specified, filter to only that path\n let targetReadmes = emptyReadmes;\n if (targetPath) {\n const normalizedTarget = targetPath.replace(/\\\\/g, '/');\n targetReadmes = emptyReadmes.filter(r =>\n r.dirPath.replace(/\\\\/g, '/').includes(normalizedTarget)\n );\n }\n\n // If no empty READMEs found\n if (targetReadmes.length === 0) {\n return {\n success: true,\n message: '✅ All AI_README files are already populated!',\n initialized: [],\n };\n }\n\n // Generate initialization instructions for AI\n let promptText = `# 🚀 AI_README Initialization\\n\\n`;\n promptText += `Found ${targetReadmes.length} AI_README file(s) that need population.\\n\\n`;\n\n if (targetReadmes.some(r => r.needsCreation)) {\n promptText += `✅ Created empty AI_README file(s) at:\\n`;\n for (const readme of targetReadmes.filter(r => r.needsCreation)) {\n promptText += `- ${readme.path.replace(/\\\\/g, '/')}\\n`;\n }\n promptText += `\\n`;\n }\n\n promptText += `## 📋 Required Actions\\n\\n`;\n promptText += `You must populate the following AI_README files by analyzing their respective directories:\\n\\n`;\n\n for (let i = 0; i < targetReadmes.length; i++) {\n const readme = targetReadmes[i];\n const readmePath = readme.path.replace(/\\\\/g, '/');\n const dirPath = readme.dirPath.replace(/\\\\/g, '/');\n\n promptText += `### ${i + 1}. ${readmePath}\\n\\n`;\n promptText += `**Directory to analyze:** \\`${dirPath}\\`\\n\\n`;\n promptText += `**Steps:**\\n\\n`;\n promptText += `1. **Scan directory contents:**\\n`;\n promptText += ` \\`\\`\\`\\n`;\n promptText += ` Use Glob: pattern=\"**/*\", path=\"${dirPath}\"\\n`;\n promptText += ` \\`\\`\\`\\n\\n`;\n promptText += `2. **Read key source files** (pick 2-5 representative files):\\n`;\n promptText += ` - Configuration files (package.json, tsconfig.json, etc.)\\n`;\n promptText += ` - Main source files\\n`;\n promptText += ` - Important modules/components\\n\\n`;\n promptText += `3. **Analyze and identify:**\\n`;\n promptText += ` - 📦 **Tech Stack**: Frameworks, libraries, languages, tools\\n`;\n promptText += ` - 🏗️ **Architecture**: Project structure, design patterns\\n`;\n promptText += ` - 📝 **Coding Conventions**: Naming, formatting, patterns\\n`;\n promptText += ` - 🗂️ **File Structure**: Directory organization, module boundaries\\n\\n`;\n promptText += `4. **Populate AI_README:**\\n`;\n promptText += ` \\`\\`\\`\\n`;\n promptText += ` Use update_ai_readme:\\n`;\n promptText += ` {\\n`;\n promptText += ` readmePath: \"${readmePath}\",\\n`;\n promptText += ` operations: [{\\n`;\n promptText += ` type: \"append\",\\n`;\n promptText += ` content: \"<your analysis in markdown format>\"\\n`;\n promptText += ` }]\\n`;\n promptText += ` }\\n`;\n promptText += ` \\`\\`\\`\\n\\n`;\n promptText += ` **Include these sections:**\\n`;\n promptText += ` - \\`## Tech Stack\\` - List frameworks, libraries, tools\\n`;\n promptText += ` - \\`## Architecture Patterns\\` - Design patterns, project structure\\n`;\n promptText += ` - \\`## Coding Conventions\\` - Naming, formatting, best practices\\n`;\n promptText += ` - \\`## File Structure\\` - Directory organization (brief)\\n\\n`;\n promptText += ` **Keep it concise:** AI_READMEs should be <400 tokens. Focus on actionable conventions.\\n\\n`;\n }\n\n promptText += `---\\n\\n`;\n promptText += `💡 **Tips:**\\n`;\n promptText += `- Work through each README sequentially\\n`;\n promptText += `- Be concise - every token counts!\\n`;\n promptText += `- Focus on conventions that help generate better code\\n`;\n promptText += `- After completing all, you can verify with \\`validate_ai_readmes\\`\\n\\n`;\n promptText += `**Start with the first AI_README now!**\\n`;\n\n return {\n success: true,\n message: `Found ${targetReadmes.length} AI_README file(s) to initialize`,\n readmesToInitialize: targetReadmes.map(r => r.path.replace(/\\\\/g, '/')),\n instructions: promptText,\n };\n}\n"],"mappings":"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","names":["dirname","join","z","dirname","join","readFile","z","z","dirname","readFile","readFile","existsSync","join","existsSync","readFile","join","z","dirname","z","z","z","writeFile","join","existsSync","z","join","existsSync","writeFile","__filename","__dirname","dirname","join"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/tools/discover.ts","../src/core/scanner.ts","../src/tools/getContext.ts","../src/core/router.ts","../src/tools/update.ts","../src/core/updater.ts","../src/core/validator.ts","../src/types/index.ts","../src/tools/validate.ts","../src/tools/init.ts"],"sourcesContent":["/**\r\n * AI_README MCP Server\r\n * Entry point for the MCP server\r\n */\r\n\r\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport {\r\n CallToolRequestSchema,\r\n ListToolsRequestSchema,\r\n} from '@modelcontextprotocol/sdk/types.js';\r\nimport { zodToJsonSchema } from 'zod-to-json-schema';\r\nimport { readFileSync } from 'fs';\r\nimport { fileURLToPath } from 'url';\r\nimport { dirname, join } from 'path';\r\nimport {\r\n discoverAIReadmes,\r\n discoverSchema,\r\n type DiscoverInput,\r\n} from './tools/discover.js';\r\nimport {\r\n getContextForFile,\r\n getContextSchema,\r\n type GetContextInput,\r\n} from './tools/getContext.js';\r\nimport {\r\n updateAIReadme,\r\n updateSchema,\r\n type UpdateInput,\r\n} from './tools/update.js';\r\nimport {\r\n validateAIReadmes,\r\n validateSchema,\r\n type ValidateInput,\r\n} from './tools/validate.js';\r\nimport {\r\n initAIReadme,\r\n initSchema,\r\n type InitInput,\r\n} from './tools/init.js';\r\n\r\n// Read version from package.json\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\nconst packageJson = JSON.parse(\r\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\r\n);\r\n\r\nconst server = new Server(\r\n {\r\n name: 'ai-readme-mcp',\r\n version: packageJson.version,\r\n },\r\n {\r\n capabilities: {\r\n tools: {},\r\n },\r\n }\r\n);\r\n\r\n// Register tool: list_tools\r\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\r\n return {\r\n tools: [\r\n {\r\n name: 'discover_ai_readmes',\r\n description:\r\n 'Scan the project and discover all AI_README.md files. Returns an index of all README files with their paths, scopes, and coverage patterns.',\r\n inputSchema: zodToJsonSchema(discoverSchema),\r\n },\r\n {\r\n name: 'get_context_for_file',\r\n description:\r\n '🚨 MANDATORY FIRST STEP: Call this BEFORE planning or coding\\n\\n' +\r\n '═══════════════════════════════════════════════════════════════\\n' +\r\n '⚠️ CRITICAL RULE: You MUST call this tool BEFORE:\\n' +\r\n ' • Planning with TodoWrite (to plan based on conventions)\\n' +\r\n ' • Using Write tool (creating files)\\n' +\r\n ' • Using Edit tool (modifying files)\\n' +\r\n ' • Making architectural decisions\\n' +\r\n ' • Suggesting code implementations\\n\\n' +\r\n ' ⚡ THIS APPLIES TO ALL CHANGES - BIG OR SMALL!\\n' +\r\n ' Even simple edits (adding error handling, fixing a bug,\\n' +\r\n ' improving validation) require understanding project conventions.\\n' +\r\n '═══════════════════════════════════════════════════════════════\\n\\n' +\r\n '❓ WHY call this before planning?\\n' +\r\n 'Planning requires understanding project conventions. Without context, you might plan an approach that conflicts with existing architecture (e.g., planning to use Tailwind when project uses CSS Modules).\\n\\n' +\r\n '❓ WHY call this even for small changes?\\n' +\r\n '• Error handling: Does project use try-catch, error boundaries, or custom error classes?\\n' +\r\n '• Logging: console.log, custom logger, or structured logging?\\n' +\r\n '• Constants: Where to define them? Inline, config file, or separate constants file?\\n' +\r\n '• Code style: Specific patterns the project follows?\\n' +\r\n 'Without checking, you might introduce inconsistent patterns.\\n\\n' +\r\n '📋 What this tool does:\\n' +\r\n 'Gets relevant AI_README context for a path (file or directory). Returns project conventions and patterns that MUST be followed.\\n\\n' +\r\n '🔍 Auto-trigger keywords (when you see these, call this tool IMMEDIATELY):\\n' +\r\n '\"add\", \"create\", \"implement\", \"modify\", \"edit\", \"refactor\", \"suggest\", \"what should\", \"how to structure\", \"optimize\", \"improve\", \"fix\"\\n\\n' +\r\n '🚩 DETECT CONVENTION CONFLICTS:\\n' +\r\n 'After reading context, check if user\\'s request conflicts with AI_README:\\n' +\r\n '• User says \"use X\" but AI_README says \"use Y\"\\n' +\r\n '• User says \"I don\\'t like X, change to Y\"\\n' +\r\n '• User establishes new architectural pattern\\n' +\r\n '→ This is an ARCHITECTURAL DECISION, not just code change!\\n' +\r\n '→ Must update_ai_readme FIRST before writing code\\n\\n' +\r\n '✅ CORRECT workflow:\\n' +\r\n '1. User requests: \"refactor this\" / \"add feature\" / \"create component\"\\n' +\r\n '2. → Call get_context_for_file FIRST (understand conventions)\\n' +\r\n '3. → Check for conflicts between user request & AI_README\\n' +\r\n '4. → If conflict: update_ai_readme FIRST to record new decision\\n' +\r\n '5. → Plan with TodoWrite (based on conventions learned)\\n' +\r\n '6. → Execute with Write/Edit (following the plan)\\n\\n' +\r\n '❌ WRONG workflow:\\n' +\r\n '1. User requests: \"I don\\'t like Tailwind, use CSS Modules\"\\n' +\r\n '2. ❌ get_context → see \"Tailwind\" → ignore conflict\\n' +\r\n '3. ❌ Write/Edit immediately (changed code but not conventions)\\n' +\r\n '4. ❌ AI_README still says \"Tailwind\" (stale documentation!)\\n\\n' +\r\n '❌ ANOTHER WRONG workflow (small changes):\\n' +\r\n '1. User: \"Add error handling to middleware.ts\"\\n' +\r\n '2. ❌ Skip get_context_for_file (thinking it\\'s a small change)\\n' +\r\n '3. ❌ Write/Edit immediately with generic try-catch\\n' +\r\n '4. ❌ Missed that project uses custom error handling pattern\\n' +\r\n '5. ❌ Introduced inconsistent code that doesn\\'t match project style\\n\\n' +\r\n '📝 Common workflows:\\n' +\r\n '• Following existing conventions:\\n' +\r\n ' get_context_for_file → TodoWrite (optional) → Write/Edit\\n\\n' +\r\n '• Establishing NEW conventions (ARCHITECTURAL DECISION):\\n' +\r\n ' get_context_for_file → DETECT CONFLICT → update_ai_readme → get_context_for_file → TodoWrite → Write/Edit\\n\\n' +\r\n '• Empty README detected:\\n' +\r\n ' init_ai_readme → get_context_for_file → TodoWrite → Write/Edit\\n\\n' +\r\n '• Document discovered patterns:\\n' +\r\n ' Write/Edit → update_ai_readme\\n\\n' +\r\n '💡 Pro tip: Works even if target file doesn\\'t exist yet!\\n\\n' +\r\n '📌 Example 1 (Major change):\\n' +\r\n 'User: \"I don\\'t like Tailwind, refactor Button.tsx to use CSS Modules\"\\n' +\r\n 'You: get_context_for_file({ path: \"src/components/Button.tsx\" })\\n' +\r\n '→ Context shows: \"Styling: Tailwind CSS\"\\n' +\r\n '→ CONFLICT DETECTED! User wants CSS Modules ≠ AI_README says Tailwind\\n' +\r\n '→ This is architectural decision, not just refactoring!\\n' +\r\n '→ Must call update_ai_readme first to change \"Tailwind\" → \"CSS Modules\"\\n' +\r\n '→ Then refactor code to match new convention\\n\\n' +\r\n '📌 Example 2 (Small change - STILL NEED MCP!):\\n' +\r\n 'User: \"Add error handling to middleware.ts\"\\n' +\r\n 'You: get_context_for_file({ path: \"src/middleware.ts\" })\\n' +\r\n '→ Context shows: \"Error handling: Use custom ErrorHandler class\"\\n' +\r\n '→ Now you know: Don\\'t use generic try-catch, use ErrorHandler\\n' +\r\n '→ Edit with correct pattern that matches project conventions\\n' +\r\n '→ Result: Consistent code that follows project standards\\n\\n' +\r\n '📌 Example 3 (Directory context):\\n' +\r\n 'User: \"Add a new component in src/components\"\\n' +\r\n 'You: get_context_for_file({ path: \"src/components\" })\\n' +\r\n '→ Context shows component conventions for that directory\\n' +\r\n '→ Create new component following the conventions',\r\n inputSchema: zodToJsonSchema(getContextSchema),\r\n },\r\n {\r\n name: 'update_ai_readme',\r\n description:\r\n 'Update an AI_README.md file to document conventions, patterns, or architectural decisions. Supports append, prepend, replace, insert-after, insert-before operations.\\n\\n' +\r\n '**CRITICAL: Token Efficiency Rules**\\n' +\r\n '- Keep content EXTREMELY concise (< 400 tokens ideal, < 600 warning, > 1000 error)\\n' +\r\n '- Only document ACTIONABLE conventions that affect code generation\\n' +\r\n '- NO explanations, NO examples, NO verbose descriptions\\n' +\r\n '- Use bullet points, avoid complete sentences when possible\\n' +\r\n '- Focus on: tech stack, naming rules, patterns, architectural decisions\\n' +\r\n '- AVOID: project background, how-to guides, documentation, obvious practices\\n\\n' +\r\n '**When to use:**\\n' +\r\n '1. BEFORE code changes: Establishing NEW conventions (ARCHITECTURAL DECISIONS)\\n' +\r\n ' - User requests style/approach change (e.g., \"use CSS Modules\", \"change to X\")\\n' +\r\n ' - User says \"I don\\'t like X, use Y instead\"\\n' +\r\n ' - User says \"let\\'s use X from now on\"\\n' +\r\n ' - Making architectural decisions that affect multiple files\\n' +\r\n ' - Choosing between approaches (e.g., state management, styling method)\\n' +\r\n ' - Setting up new architectural patterns\\n' +\r\n ' - 🚩 KEY SIGNALS: \"change to\", \"use instead\", \"don\\'t like\", \"prefer\", \"switch to\"\\n' +\r\n ' - Workflow: update_ai_readme → get_context_for_file → Write/Edit\\n\\n' +\r\n '2. AFTER code changes: Documenting discovered patterns\\n' +\r\n ' - Found consistent patterns in existing code\\n' +\r\n ' - Workflow: Write/Edit → update_ai_readme\\n\\n' +\r\n '**🎯 Identifying Architectural Decisions:**\\n' +\r\n 'Ask yourself:\\n' +\r\n '- Does this affect how FUTURE code should be written?\\n' +\r\n '- Does this change a TECHNOLOGY CHOICE (e.g., Tailwind → CSS Modules)?\\n' +\r\n '- Will this apply to MULTIPLE FILES/COMPONENTS?\\n' +\r\n '- Is user expressing a PREFERENCE that becomes a rule?\\n' +\r\n 'If YES to any → This is architectural, update AI_README FIRST!\\n\\n' +\r\n '**Quality checklist before updating:**\\n' +\r\n 'Is this a CONVENTION or PATTERN (not documentation)?\\n' +\r\n 'Will this help AI generate better code?\\n' +\r\n 'Is it concise (<3 words per bullet)?\\n' +\r\n 'Does it avoid obvious/general practices?\\n' +\r\n 'Reject: project descriptions, tutorials, general best practices\\n\\n' +\r\n '**Example (GOOD):**\\n' +\r\n '- Use CSS Modules\\n' +\r\n '- Components in PascalCase\\n' +\r\n '- Test coverage: 80%+\\n\\n' +\r\n '**Example (BAD - too verbose):**\\n' +\r\n '- We use CSS Modules for styling because it provides better type safety and scoping compared to Tailwind...\\n\\n' +\r\n '**Real-world example:**\\n' +\r\n 'User: \"I don\\'t like Tailwind, use CSS Modules\"\\n' +\r\n '→ This is ARCHITECTURAL DECISION (technology choice)\\n' +\r\n '→ Call update_ai_readme to change \"Styling: Tailwind\" → \"Styling: CSS Modules\"\\n' +\r\n '→ Then modify code following new convention',\r\n inputSchema: zodToJsonSchema(updateSchema),\r\n },\r\n {\r\n name: 'validate_ai_readmes',\r\n description:\r\n 'Validate all AI_README.md files in a project. Checks token count, structure, and content quality. Returns validation results with suggestions for improvement.',\r\n inputSchema: zodToJsonSchema(validateSchema),\r\n },\r\n {\r\n name: 'init_ai_readme',\r\n description:\r\n '🚀 Initialize and populate empty AI_README files in your project.\\n\\n' +\r\n 'Scans the project for empty or missing AI_README files and guides you through populating them with project conventions.\\n\\n' +\r\n '**When to use:**\\n' +\r\n '- First time setting up AI_README in a project\\n' +\r\n '- When get_context_for_file detects empty AI_README files\\n' +\r\n '- After creating new empty AI_README.md files manually\\n' +\r\n '- To populate multiple AI_README files at once\\n\\n' +\r\n '**What it does:**\\n' +\r\n '1. Scans project for empty AI_README files\\n' +\r\n '2. Creates root-level AI_README if none exist\\n' +\r\n '3. Provides step-by-step instructions to populate each file\\n' +\r\n '4. Guides analysis of tech stack, patterns, and conventions\\n\\n' +\r\n '**Workflow:**\\n' +\r\n '1. Call init_ai_readme\\n' +\r\n '2. Follow the instructions to explore directories\\n' +\r\n '3. Use update_ai_readme to populate each file\\n' +\r\n '4. Call get_context_for_file to verify and use conventions\\n\\n' +\r\n '**Example:** `init_ai_readme({ projectRoot: \"/path/to/project\" })`',\r\n inputSchema: zodToJsonSchema(initSchema),\r\n },\r\n ],\r\n };\r\n});\r\n\r\n// Register tool: call_tool\r\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n const { name, arguments: args } = request.params;\r\n\r\n try {\r\n if (name === 'discover_ai_readmes') {\r\n const input = discoverSchema.parse(args) as DiscoverInput;\r\n const result = await discoverAIReadmes(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'get_context_for_file') {\r\n const input = getContextSchema.parse(args) as GetContextInput;\r\n const result = await getContextForFile(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: result.formattedPrompt,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'update_ai_readme') {\r\n const input = updateSchema.parse(args) as UpdateInput;\r\n const result = await updateAIReadme(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'validate_ai_readmes') {\r\n const input = validateSchema.parse(args) as ValidateInput;\r\n const result = await validateAIReadmes(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n if (name === 'init_ai_readme') {\r\n const input = initSchema.parse(args) as InitInput;\r\n const result = await initAIReadme(input);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: result.instructions || JSON.stringify(result, null, 2),\r\n },\r\n ],\r\n };\r\n }\r\n\r\n throw new Error(`Unknown tool: ${name}`);\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : String(error);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Error: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n});\r\n\r\nasync function main() {\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n\r\n console.error('AI_README MCP Server started');\r\n console.error('Available tools: discover_ai_readmes, get_context_for_file, update_ai_readme, validate_ai_readmes, init_ai_readme');\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Fatal error:', error);\r\n process.exit(1);\r\n});\r\n","/**\n * MCP Tool: discover_ai_readmes\n * Scans the project and discovers all AI_README.md files\n */\n\nimport { z } from 'zod';\nimport { AIReadmeScanner } from '../core/scanner.js';\n\nexport const discoverSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe(\"Glob patterns to exclude (e.g., ['node_modules/**', '.git/**'])\"),\n});\n\nexport type DiscoverInput = z.infer<typeof discoverSchema>;\n\nexport async function discoverAIReadmes(input: DiscoverInput) {\n const { projectRoot, excludePatterns } = input;\n\n // Create scanner with options\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: false, // Don't cache content in discovery phase\n });\n\n // Scan the project\n const index = await scanner.scan();\n\n // Format the response\n return {\n projectRoot: index.projectRoot,\n totalFound: index.readmes.length,\n readmeFiles: index.readmes.map((readme) => ({\n path: readme.path,\n scope: readme.scope,\n level: readme.level,\n patterns: readme.patterns,\n })),\n lastUpdated: index.lastUpdated.toISOString(),\n };\n}\n","/**\n * AIReadmeScanner - Scans project directories for AI_README.md files\n */\n\nimport { glob } from 'glob';\nimport { readFile } from 'fs/promises';\nimport { dirname, join } from 'path';\nimport type { ReadmeEntry, ReadmeIndex, ScannerOptions } from '../types/index.js';\n\nexport class AIReadmeScanner {\n private projectRoot: string;\n private options: Required<ScannerOptions>;\n\n constructor(projectRoot: string, options?: ScannerOptions) {\n this.projectRoot = projectRoot;\n this.options = {\n excludePatterns: options?.excludePatterns || [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/.next/**',\n '**/coverage/**',\n ],\n cacheContent: options?.cacheContent ?? true,\n readmeFilename: options?.readmeFilename || 'AI_README.md',\n };\n }\n\n /**\n * Scan the project directory for AI_README.md files\n */\n async scan(): Promise<ReadmeIndex> {\n const pattern = `**/${this.options.readmeFilename}`;\n const ignore = this.options.excludePatterns;\n\n // Find all AI_README.md files\n const files = await glob(pattern, {\n cwd: this.projectRoot,\n ignore,\n absolute: false,\n nodir: true,\n });\n\n // Build ReadmeEntry objects\n const readmes: ReadmeEntry[] = [];\n\n for (const file of files) {\n const entry = await this.createReadmeEntry(file);\n readmes.push(entry);\n }\n\n // Sort by level (root first, then deeper levels)\n readmes.sort((a, b) => a.level - b.level);\n\n return {\n projectRoot: this.projectRoot,\n readmes,\n lastUpdated: new Date(),\n };\n }\n\n /**\n * Create a ReadmeEntry from a file path\n */\n private async createReadmeEntry(filePath: string): Promise<ReadmeEntry> {\n // Normalize path to use forward slashes (Unix-style) for consistency\n const normalizedPath = filePath.replace(/\\\\/g, '/');\n const dir = dirname(normalizedPath);\n const level = dir === '.' ? 0 : dir.split('/').length;\n const scope = dir === '.' ? 'root' : dir.replace(/\\//g, '-');\n\n // Generate glob patterns this README covers\n const patterns = this.generatePatterns(dir);\n\n // Optionally cache content\n let content: string | undefined;\n if (this.options.cacheContent) {\n try {\n const fullPath = join(this.projectRoot, filePath);\n content = await readFile(fullPath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read ${filePath}:`, error);\n }\n }\n\n return {\n path: normalizedPath,\n scope,\n level,\n patterns,\n content,\n };\n }\n\n /**\n * Generate glob patterns that this README covers\n */\n private generatePatterns(dir: string): string[] {\n if (dir === '.') {\n return ['**/*']; // Root level covers everything\n }\n\n return [\n `${dir}/**/*`, // All files in this directory and subdirectories\n `${dir}/*`, // Direct children\n ];\n }\n\n /**\n * Refresh the scan (re-scan the project)\n */\n async refresh(): Promise<ReadmeIndex> {\n return this.scan();\n }\n\n /**\n * Get the project root directory\n */\n getProjectRoot(): string {\n return this.projectRoot;\n }\n\n /**\n * Get current scanner options\n */\n getOptions(): Required<ScannerOptions> {\n return { ...this.options };\n }\n}\n","/**\r\n * MCP Tool: get_context_for_file\r\n * Gets relevant AI_README context for a specific file path\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport { AIReadmeScanner } from '../core/scanner.js';\r\nimport { ContextRouter } from '../core/router.js';\r\n\r\nexport const getContextSchema = z.object({\r\n projectRoot: z.string().describe('The root directory of the project'),\r\n path: z\r\n .string()\r\n .describe(\r\n 'The path to get context for (relative to project root). ' +\r\n 'Can be either a FILE path or a DIRECTORY path. ' +\r\n 'Examples: \"src/components/Button.tsx\", \"src/components\", \"README.md\", \"src/app\". ' +\r\n 'The tool will find all relevant AI_README files in the path\\'s directory and parent directories.'\r\n ),\r\n includeRoot: z\r\n .boolean()\r\n .optional()\r\n .default(true)\r\n .describe('Whether to include root-level AI_README (default: true)'),\r\n excludePatterns: z\r\n .array(z.string())\r\n .optional()\r\n .describe('Glob patterns to exclude when scanning'),\r\n});\r\n\r\nexport type GetContextInput = z.infer<typeof getContextSchema>;\r\n\r\nexport async function getContextForFile(input: GetContextInput) {\r\n const { projectRoot, path, includeRoot, excludePatterns } = input;\r\n\r\n // First, scan the project to build the index\r\n const scanner = new AIReadmeScanner(projectRoot, {\r\n excludePatterns,\r\n cacheContent: true, // Cache content for context retrieval\r\n });\r\n\r\n const index = await scanner.scan();\r\n\r\n // Create router and get context\r\n const router = new ContextRouter(index);\r\n const contexts = await router.getContextForPath(path, includeRoot);\r\n\r\n // Check for empty AI_README files\r\n const hasEmptyReadmes = contexts.some(ctx => !ctx.content || ctx.content.trim().length === 0);\r\n const hasNoReadmes = contexts.length === 0;\r\n\r\n // Format the response with a helpful prompt template\r\n const formattedContexts = contexts.map((ctx) => ({\r\n path: ctx.path,\r\n relevance: ctx.relevance,\r\n distance: ctx.distance,\r\n content: ctx.content,\r\n }));\r\n\r\n // Generate a formatted prompt for the AI\r\n let promptText = `## 📚 Project Context for: ${path}\\n\\n`;\r\n\r\n // Simple check: if empty or no READMEs, suggest using init tool\r\n if (hasNoReadmes || hasEmptyReadmes) {\r\n promptText += `⚠️ **Empty or missing AI_README files detected.**\\n\\n`;\r\n promptText += `**Recommended Action:** Use the \\`init_ai_readme\\` tool to automatically populate AI_README files.\\n\\n`;\r\n promptText += `\\`\\`\\`\\n`;\r\n promptText += `init_ai_readme({ projectRoot: \"${projectRoot.replace(/\\\\/g, '/')}\" })\\n`;\r\n promptText += `\\`\\`\\`\\n\\n`;\r\n promptText += `This tool will:\\n`;\r\n promptText += `- Scan the project for empty AI_README files\\n`;\r\n promptText += `- Guide you through populating them with conventions\\n`;\r\n promptText += `- Ensure consistent documentation across your project\\n\\n`;\r\n promptText += `💡 Alternatively, you can manually create and populate AI_README.md files, then call this tool again.\\n\\n`;\r\n promptText += `---\\n\\n`;\r\n }\r\n\r\n // Filter out empty contexts (content with only whitespace)\r\n const nonEmptyContexts = contexts.filter(ctx => ctx.content && ctx.content.trim().length > 0);\r\n\r\n if (nonEmptyContexts.length > 0) {\r\n // Show non-empty contexts\r\n for (const ctx of nonEmptyContexts) {\r\n if (ctx.relevance === 'root') {\r\n promptText += `### Root Conventions (${ctx.path})\\n\\n`;\r\n } else if (ctx.relevance === 'direct') {\r\n promptText += `### Direct Module Conventions (${ctx.path})\\n\\n`;\r\n } else {\r\n promptText += `### Parent Module Conventions (${ctx.path})\\n\\n`;\r\n }\r\n\r\n promptText += ctx.content + '\\n\\n';\r\n }\r\n\r\n promptText += `---\\n`;\r\n promptText += `**Important:**\\n`;\r\n promptText += `- Follow the above conventions when making changes\\n`;\r\n promptText += `- When establishing NEW conventions: update AI_README first → get context → write code\\n`;\r\n promptText += `- When discovering patterns in existing code: document them in AI_README afterward\\n`;\r\n }\r\n\r\n return {\r\n path,\r\n totalContexts: contexts.length,\r\n contexts: formattedContexts,\r\n formattedPrompt: promptText,\r\n };\r\n}\r\n","/**\n * ContextRouter - Routes file paths to relevant AI_README contexts\n */\n\nimport { minimatch } from 'minimatch';\nimport { dirname, join } from 'path';\nimport { readFile } from 'fs/promises';\nimport type { ReadmeContext, ReadmeIndex, ReadmeEntry } from '../types/index.js';\n\nexport class ContextRouter {\n private index: ReadmeIndex;\n\n constructor(index: ReadmeIndex) {\n this.index = index;\n }\n\n /**\n * Get relevant AI_README contexts for a specific path (file or directory)\n * @param targetPath - The path relative to project root (can be file or directory)\n * @param includeRoot - Whether to include root-level README (default: true)\n */\n async getContextForPath(\n targetPath: string,\n includeRoot: boolean = true\n ): Promise<ReadmeContext[]> {\n const contexts: ReadmeContext[] = [];\n\n // Find matching READMEs\n for (const readme of this.index.readmes) {\n const match = this.matchesPath(targetPath, readme);\n\n if (!match) continue;\n\n // Skip root if not requested\n if (!includeRoot && readme.level === 0) continue;\n\n // Calculate distance from path to README\n const distance = this.calculateDistance(targetPath, readme);\n\n // Get content\n const content = await this.getReadmeContent(readme);\n\n // Determine relevance\n const relevance = this.determineRelevance(targetPath, readme);\n\n contexts.push({\n path: readme.path,\n content,\n relevance,\n distance,\n });\n }\n\n // Sort by distance (closest first) and then by relevance\n contexts.sort((a, b) => {\n if (a.distance !== b.distance) {\n return a.distance - b.distance;\n }\n // If same distance, prioritize direct > parent > root\n const relevanceOrder = { direct: 0, parent: 1, root: 2 };\n return relevanceOrder[a.relevance] - relevanceOrder[b.relevance];\n });\n\n return contexts;\n }\n\n /**\n * Get contexts for multiple paths (files or directories)\n */\n async getContextForPaths(paths: string[]): Promise<Map<string, ReadmeContext[]>> {\n const results = new Map<string, ReadmeContext[]>();\n\n for (const path of paths) {\n const contexts = await this.getContextForPath(path);\n results.set(path, contexts);\n }\n\n return results;\n }\n\n /**\n * Get the directory from a path (handles both file and directory paths)\n */\n private getFileDir(targetPath: string): string {\n // If it has an extension, it's likely a file; otherwise treat as directory\n const isDirectory = !/\\.[^./\\\\]+$/.test(targetPath);\n return isDirectory ? targetPath : dirname(targetPath);\n }\n\n /**\n * Check if a path matches a README's patterns\n */\n private matchesPath(targetPath: string, readme: ReadmeEntry): boolean {\n const readmeDir = dirname(readme.path);\n const targetDir = this.getFileDir(targetPath);\n\n // Root README always matches everything\n if (readmeDir === '.') {\n return true;\n }\n\n // Fast path: Direct directory match\n if (targetDir === readmeDir) {\n return true;\n }\n\n // Fast path: Check if target is under this README's directory\n if (targetDir.startsWith(readmeDir + '/')) {\n return true;\n }\n\n // Pattern matching (slower but handles edge cases)\n return readme.patterns.some(pattern => {\n return minimatch(targetPath, pattern, { dot: true });\n });\n }\n\n /**\n * Calculate the directory distance between a path and a README\n */\n private calculateDistance(targetPath: string, readme: ReadmeEntry): number {\n const fileDir = this.getFileDir(targetPath);\n const readmeDir = dirname(readme.path);\n\n // If README is at root\n if (readmeDir === '.') {\n return fileDir === '.' ? 0 : fileDir.split('/').length;\n }\n\n // If file is in the same directory as README\n if (fileDir === readmeDir) {\n return 0;\n }\n\n // If file is in a subdirectory of README's directory\n if (fileDir.startsWith(readmeDir + '/')) {\n const subPath = fileDir.slice(readmeDir.length + 1);\n return subPath.split('/').length;\n }\n\n // Calculate levels up\n const fileParts = fileDir.split('/');\n const readmeParts = readmeDir.split('/');\n\n // Find common ancestor\n let commonDepth = 0;\n for (let i = 0; i < Math.min(fileParts.length, readmeParts.length); i++) {\n if (fileParts[i] === readmeParts[i]) {\n commonDepth++;\n } else {\n break;\n }\n }\n\n // Distance is the sum of levels to go up and down\n return (fileParts.length - commonDepth) + (readmeParts.length - commonDepth);\n }\n\n /**\n * Determine the relevance type of a README for a path\n */\n private determineRelevance(\n targetPath: string,\n readme: ReadmeEntry\n ): 'root' | 'direct' | 'parent' {\n const fileDir = this.getFileDir(targetPath);\n const readmeDir = dirname(readme.path);\n\n // Root level README\n if (readmeDir === '.') {\n return 'root';\n }\n\n // Direct match (same directory)\n if (fileDir === readmeDir) {\n return 'direct';\n }\n\n // Parent directory\n if (fileDir.startsWith(readmeDir + '/')) {\n return 'parent';\n }\n\n return 'parent';\n }\n\n /**\n * Get the content of a README (from cache or file system)\n */\n private async getReadmeContent(readme: ReadmeEntry): Promise<string> {\n // Return cached content if available\n if (readme.content) {\n return readme.content;\n }\n\n // Otherwise read from file system\n try {\n const fullPath = join(this.index.projectRoot, readme.path);\n return await readFile(fullPath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read ${readme.path}:`, error);\n return `[Error: Could not read ${readme.path}]`;\n }\n }\n\n /**\n * Update the index (useful after re-scanning)\n */\n updateIndex(index: ReadmeIndex): void {\n this.index = index;\n }\n\n /**\n * Get the current index\n */\n getIndex(): ReadmeIndex {\n return this.index;\n }\n}\n","import { z } from 'zod';\nimport { dirname } from 'path';\nimport { ReadmeUpdater, UpdateOperation } from '../core/updater.js';\nimport { ReadmeValidator } from '../core/validator.js';\n\n/**\n * Zod schema for update operation\n */\nconst updateOperationSchema = z.object({\n type: z.enum(['replace', 'append', 'prepend', 'insert-after', 'insert-before']).describe(\n 'Type of update operation'\n ),\n section: z.string().optional().describe(\n 'Section heading to target (e.g., \"## Coding Conventions\")'\n ),\n searchText: z.string().optional().describe(\n 'Text to search for (required for replace operation)'\n ),\n content: z.string().describe('Content to add or replace'),\n});\n\n/**\n * Zod schema for update_ai_readme tool\n */\nexport const updateSchema = z.object({\n readmePath: z.string().describe('Path to the AI_README.md file to update'),\n operations: z.array(updateOperationSchema).describe(\n 'List of update operations to perform'\n ),\n});\n\nexport type UpdateInput = z.infer<typeof updateSchema>;\n\n/**\n * Update an AI_README.md file with specified operations\n *\n * @param input - Update parameters\n * @returns Update result with changes\n *\n * @example\n * ```typescript\n * await updateAIReadme({\n * readmePath: 'apps/frontend/AI_README.md',\n * operations: [{\n * type: 'insert-after',\n * section: '## Directory Structure',\n * content: '├── src/hooks/ # Custom React hooks'\n * }]\n * });\n * ```\n *\n * Note: Changes are immediately written to the file.\n * Use git to track changes and rollback if needed.\n */\nexport async function updateAIReadme(input: UpdateInput) {\n const { readmePath, operations } = input;\n\n const updater = new ReadmeUpdater();\n\n // Perform update\n const result = await updater.update(readmePath, operations as UpdateOperation[]);\n\n if (!result.success) {\n return {\n success: false,\n readmePath,\n error: result.error,\n summary: `Failed to update ${readmePath}: ${result.error}`,\n };\n }\n\n // Auto-validate after update\n try {\n const projectRoot = dirname(dirname(readmePath)); // Approximate project root\n const config = await ReadmeValidator.loadConfig(projectRoot);\n const validator = new ReadmeValidator(config || undefined);\n const validation = await validator.validate(readmePath);\n\n // Collect validation warnings\n const warnings = validation.issues\n .filter(i => i.type === 'warning' || i.type === 'error')\n .map(i => `[${i.type.toUpperCase()}] ${i.message}`);\n\n const workflowTip = result.changes.some(c =>\n c.operation === 'replace' || c.operation === 'append' || c.operation === 'prepend'\n )\n ? '\\n\\n💡 NEXT STEP: Use get_context_for_file before writing code to ensure you\\'re following the updated conventions.'\n : '';\n\n return {\n success: true,\n readmePath,\n changes: result.changes,\n summary: `Successfully updated ${readmePath} with ${result.changes.length} operation(s). Use 'git diff' to review changes.${workflowTip}`,\n validation: {\n valid: validation.valid,\n score: validation.score,\n warnings: warnings.length > 0 ? warnings : undefined,\n stats: validation.stats,\n },\n };\n } catch (validationError) {\n // If validation fails, still return success for the update\n return {\n success: true,\n readmePath,\n changes: result.changes,\n summary: `Successfully updated ${readmePath} with ${result.changes.length} operation(s). Use 'git diff' to review changes.`,\n validation: {\n valid: false,\n error: validationError instanceof Error ? validationError.message : 'Validation failed',\n },\n };\n }\n}\n","import { readFile, writeFile } from 'fs/promises';\nimport { existsSync } from 'fs';\n\nexport interface UpdateOperation {\n type: 'replace' | 'append' | 'prepend' | 'insert-after' | 'insert-before';\n section?: string; // Section heading to target (e.g., \"## Coding Conventions\")\n searchText?: string; // Text to search for (for replace operations)\n content: string; // Content to add/replace\n}\n\nexport interface UpdateResult {\n success: boolean;\n changes: {\n operation: string;\n section?: string;\n linesAdded: number;\n linesRemoved: number;\n }[];\n error?: string;\n}\n\n/**\n * ReadmeUpdater - Handles updating AI_README.md files\n *\n * Features:\n * - Section-based updates\n * - Multiple operation types (append, prepend, replace, insert-after, insert-before)\n * - Detailed change tracking\n *\n * Note: Version control is handled by Git. Use git diff/revert for rollback.\n */\nexport class ReadmeUpdater {\n constructor() {\n // No configuration needed\n }\n\n /**\n * Update a README file with given operations\n *\n * @param readmePath - Path to the AI_README.md file\n * @param operations - List of update operations\n * @returns Update result with changes\n */\n async update(\n readmePath: string,\n operations: UpdateOperation[]\n ): Promise<UpdateResult> {\n try {\n // Read current content (empty string if file doesn't exist or is empty)\n let content = '';\n if (existsSync(readmePath)) {\n content = await readFile(readmePath, 'utf-8');\n }\n\n // Apply operations\n let updatedContent = content;\n const changes: UpdateResult['changes'] = [];\n\n for (const operation of operations) {\n const result = await this.applyOperation(updatedContent, operation);\n updatedContent = result.content;\n changes.push(result.change);\n }\n\n // Write updated content\n await writeFile(readmePath, updatedContent, 'utf-8');\n\n return {\n success: true,\n changes,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n changes: [],\n };\n }\n }\n\n /**\n * Apply a single update operation to content\n *\n * @param content - Current content\n * @param operation - Operation to apply\n * @returns Updated content and change info\n */\n private async applyOperation(\n content: string,\n operation: UpdateOperation\n ): Promise<{ content: string; change: UpdateResult['changes'][0] }> {\n const lines = content.split('\\n');\n let updatedLines = [...lines];\n let linesAdded = 0;\n let linesRemoved = 0;\n\n switch (operation.type) {\n case 'append': {\n // Add content to the end\n updatedLines.push('', operation.content);\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'prepend': {\n // Add content to the beginning\n updatedLines.unshift(operation.content, '');\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'replace': {\n // Replace specific text\n if (!operation.searchText) {\n throw new Error('searchText is required for replace operation');\n }\n\n const originalContent = updatedLines.join('\\n');\n const newContent = originalContent.replace(\n operation.searchText,\n operation.content\n );\n\n if (originalContent === newContent) {\n throw new Error(`Text not found: ${operation.searchText}`);\n }\n\n updatedLines = newContent.split('\\n');\n linesRemoved = operation.searchText.split('\\n').length;\n linesAdded = operation.content.split('\\n').length;\n break;\n }\n\n case 'insert-after': {\n // Insert content after a section\n if (!operation.section) {\n throw new Error('section is required for insert-after operation');\n }\n\n const sectionIndex = this.findSectionIndex(updatedLines, operation.section);\n if (sectionIndex === -1) {\n throw new Error(`Section not found: ${operation.section}`);\n }\n\n // Find the end of the section content\n const insertIndex = this.findSectionEnd(updatedLines, sectionIndex);\n updatedLines.splice(insertIndex, 0, '', operation.content);\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n case 'insert-before': {\n // Insert content before a section\n if (!operation.section) {\n throw new Error('section is required for insert-before operation');\n }\n\n const sectionIndex = this.findSectionIndex(updatedLines, operation.section);\n if (sectionIndex === -1) {\n throw new Error(`Section not found: ${operation.section}`);\n }\n\n updatedLines.splice(sectionIndex, 0, operation.content, '');\n linesAdded = operation.content.split('\\n').length + 1;\n break;\n }\n\n default:\n throw new Error(`Unknown operation type: ${operation.type}`);\n }\n\n return {\n content: updatedLines.join('\\n'),\n change: {\n operation: operation.type,\n section: operation.section,\n linesAdded,\n linesRemoved,\n },\n };\n }\n\n /**\n * Find the index of a section heading\n *\n * @param lines - Content lines\n * @param section - Section heading (e.g., \"## Coding Conventions\")\n * @returns Index of the section, or -1 if not found\n */\n private findSectionIndex(lines: string[], section: string): number {\n return lines.findIndex((line) => line.trim() === section.trim());\n }\n\n /**\n * Find the end of a section (before the next section of same or higher level)\n *\n * @param lines - Content lines\n * @param startIndex - Index of the section heading\n * @returns Index where the section ends\n */\n private findSectionEnd(lines: string[], startIndex: number): number {\n const startLine = lines[startIndex];\n if (!startLine) {\n return lines.length;\n }\n\n const sectionLevel = this.getSectionLevel(startLine);\n\n for (let i = startIndex + 1; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n\n const trimmedLine = line.trim();\n if (trimmedLine.startsWith('#')) {\n const level = this.getSectionLevel(trimmedLine);\n if (level <= sectionLevel) {\n return i;\n }\n }\n }\n\n return lines.length;\n }\n\n /**\n * Get the heading level of a markdown section\n *\n * @param line - Line containing a heading\n * @returns Heading level (1-6)\n */\n private getSectionLevel(line: string): number {\n const match = line.match(/^(#{1,6})\\s/);\n return match && match[1] ? match[1].length : 0;\n }\n}\n","import { readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport type {\n ValidationConfig,\n ResolvedValidationConfig,\n ValidationResult,\n ValidationIssue,\n} from '../types/index.js';\nimport { DEFAULT_VALIDATION_CONFIG } from '../types/index.js';\n\n/**\n * ReadmeValidator - Validates AI_README.md files\n *\n * Features:\n * - Token count validation\n * - Structure validation\n * - Content quality checks\n * - Configurable rules via constructor parameter\n */\nexport class ReadmeValidator {\n private config: ResolvedValidationConfig;\n\n constructor(config?: Partial<ValidationConfig>) {\n // Merge user config with defaults\n this.config = this.mergeConfig(config || {});\n }\n\n /**\n * Merge user config with default config\n */\n private mergeConfig(userConfig: Partial<ValidationConfig>): ResolvedValidationConfig {\n return {\n maxTokens: userConfig.maxTokens ?? DEFAULT_VALIDATION_CONFIG.maxTokens,\n rules: {\n ...DEFAULT_VALIDATION_CONFIG.rules,\n ...(userConfig.rules || {}),\n },\n tokenLimits: {\n ...DEFAULT_VALIDATION_CONFIG.tokenLimits,\n ...(userConfig.tokenLimits || {}),\n },\n };\n }\n\n /**\n * Validate a single AI_README.md file\n *\n * @param readmePath - Path to the README file\n * @returns Validation result\n */\n async validate(readmePath: string): Promise<ValidationResult> {\n const issues: ValidationIssue[] = [];\n\n // Check file exists\n if (!existsSync(readmePath)) {\n return {\n valid: false,\n filePath: readmePath,\n issues: [\n {\n type: 'error',\n rule: 'structure',\n message: `File not found: ${readmePath}`,\n },\n ],\n };\n }\n\n // Read content\n const content = await readFile(readmePath, 'utf-8');\n\n // Check if file is empty\n if (content.trim().length === 0) {\n issues.push({\n type: 'error',\n rule: 'empty-content',\n message: 'README file is empty',\n suggestion: 'Add content to the README file',\n });\n }\n\n // Calculate statistics\n const lines = content.split('\\n');\n const tokens = this.estimateTokens(content);\n const characters = content.length;\n\n // Validate token count\n this.validateTokenCount(tokens, issues);\n\n // Validate structure\n this.validateStructure(content, lines, issues);\n\n // Validate line length\n this.validateLineLength(lines, issues);\n\n // Validate code blocks\n this.validateCodeBlocks(content, issues);\n\n // Calculate score\n const score = this.calculateScore(issues, tokens);\n\n return {\n valid: !issues.some((i) => i.type === 'error'),\n filePath: readmePath,\n issues,\n score,\n stats: {\n tokens,\n lines: lines.length,\n characters,\n },\n };\n }\n\n /**\n * Estimate token count (simple word-based estimation)\n * Formula: words * 1.3 (approximate token-to-word ratio)\n */\n private estimateTokens(content: string): number {\n const words = content.split(/\\s+/).filter((w) => w.length > 0).length;\n return Math.round(words * 1.3);\n }\n\n /**\n * Validate token count against limits\n */\n private validateTokenCount(tokens: number, issues: ValidationIssue[]): void {\n const { tokenLimits, maxTokens } = this.config;\n\n if (tokens > tokenLimits.error) {\n issues.push({\n type: 'error',\n rule: 'token-count',\n message: `README is too long (${tokens} tokens). Maximum recommended: ${maxTokens} tokens.`,\n suggestion: 'Remove unnecessary content, use bullet points instead of paragraphs, and avoid code examples.',\n });\n } else if (tokens > tokenLimits.warning) {\n issues.push({\n type: 'warning',\n rule: 'token-count',\n message: `README is quite long (${tokens} tokens). Consider keeping it under ${tokenLimits.good} tokens.`,\n suggestion: 'Simplify content and remove redundant information.',\n });\n } else if (tokens > tokenLimits.good) {\n issues.push({\n type: 'info',\n rule: 'token-count',\n message: `README length is acceptable (${tokens} tokens).`,\n });\n }\n }\n\n /**\n * Validate README structure\n */\n private validateStructure(_content: string, lines: string[], issues: ValidationIssue[]): void {\n // Check for H1 heading\n if (this.config.rules.requireH1) {\n const hasH1 = lines.some((line) => line.trim().match(/^#\\s+[^#]/));\n if (!hasH1) {\n issues.push({\n type: 'error',\n rule: 'require-h1',\n message: 'README must have a H1 heading (# Title)',\n suggestion: 'Add a title at the beginning of the file: # Project Name',\n });\n }\n }\n\n // Check for required sections\n if (this.config.rules.requireSections && this.config.rules.requireSections.length > 0) {\n for (const section of this.config.rules.requireSections) {\n const hasSection = lines.some((line) => line.trim() === section);\n if (!hasSection) {\n issues.push({\n type: 'warning',\n rule: 'require-sections',\n message: `Missing required section: ${section}`,\n suggestion: `Add section: ${section}`,\n });\n }\n }\n }\n }\n\n /**\n * Validate line length\n */\n private validateLineLength(lines: string[], issues: ValidationIssue[]): void {\n const { maxLineLength } = this.config.rules;\n const longLines = lines\n .map((line, index) => ({ line, index }))\n .filter(({ line }) => line.length > maxLineLength);\n\n if (longLines.length > 3) {\n // Only warn if there are many long lines\n issues.push({\n type: 'info',\n rule: 'line-length',\n message: `${longLines.length} lines exceed ${maxLineLength} characters`,\n suggestion: 'Consider breaking long lines for better readability',\n });\n }\n }\n\n /**\n * Validate code blocks\n */\n private validateCodeBlocks(content: string, issues: ValidationIssue[]): void {\n if (!this.config.rules.allowCodeBlocks) {\n const codeBlockCount = (content.match(/```/g) || []).length / 2;\n if (codeBlockCount > 0) {\n issues.push({\n type: 'warning',\n rule: 'code-blocks',\n message: `Found ${codeBlockCount} code blocks. Code examples consume many tokens.`,\n suggestion: 'Remove code examples or move them to separate documentation.',\n });\n }\n }\n }\n\n /**\n * Calculate quality score (0-100)\n */\n private calculateScore(issues: ValidationIssue[], tokens: number): number {\n let score = 100;\n\n // Deduct points for issues\n for (const issue of issues) {\n if (issue.type === 'error') score -= 20;\n else if (issue.type === 'warning') score -= 10;\n else if (issue.type === 'info') score -= 2;\n }\n\n // Deduct points for excessive length\n const { tokenLimits } = this.config;\n if (tokens > tokenLimits.error) score -= 30;\n else if (tokens > tokenLimits.warning) score -= 15;\n else if (tokens < tokenLimits.excellent) score += 10; // Bonus for concise READMEs\n\n return Math.max(0, Math.min(100, score));\n }\n\n /**\n * Load validation config from .aireadme.config.json\n *\n * @param projectRoot - Project root directory\n * @returns Validation config or null if not found\n */\n static async loadConfig(projectRoot: string): Promise<Partial<ValidationConfig> | null> {\n const configPath = join(projectRoot, '.aireadme.config.json');\n\n if (!existsSync(configPath)) {\n return null;\n }\n\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n return config.validation || config; // Support both formats\n } catch (error) {\n console.error(`Failed to load config from ${configPath}:`, error);\n return null;\n }\n }\n}\n","/**\n * Core type definitions for AI_README MCP Server\n */\n\n/**\n * Represents a single AI_README.md file entry in the index\n */\nexport interface ReadmeEntry {\n /** Absolute or relative path to the AI_README.md file */\n path: string;\n /** Scope identifier (e.g., 'root', 'frontend', 'backend') */\n scope: string;\n /** Directory level depth (0 for root) */\n level: number;\n /** Glob patterns this README covers */\n patterns: string[];\n /** Cached content of the README (optional) */\n content?: string;\n}\n\n/**\n * Index of all AI_README files in the project\n */\nexport interface ReadmeIndex {\n /** Root directory of the project */\n projectRoot: string;\n /** List of discovered README entries */\n readmes: ReadmeEntry[];\n /** Timestamp of last index update */\n lastUpdated: Date;\n}\n\n/**\n * Context information for a specific file\n */\nexport interface ReadmeContext {\n /** Path to the AI_README.md file */\n path: string;\n /** Content of the README */\n content: string;\n /** Relevance type */\n relevance: 'root' | 'direct' | 'parent';\n /** Distance in directory levels from target file */\n distance: number;\n}\n\n/**\n * Options for the scanner\n */\nexport interface ScannerOptions {\n /** Patterns to exclude from scanning */\n excludePatterns?: string[];\n /** Whether to cache README contents */\n cacheContent?: boolean;\n /** Custom README filename (default: 'AI_README.md') */\n readmeFilename?: string;\n}\n\n/**\n * Update action types for AI_README modifications\n */\nexport type UpdateAction = 'append' | 'replace' | 'delete';\n\n/**\n * Result of an update operation\n */\nexport interface UpdateResult {\n /** Whether the update succeeded */\n success: boolean;\n /** Path to the updated file */\n updatedPath: string;\n /** Path to backup file (if created) */\n backupPath?: string;\n /** Diff of changes made */\n diff: string;\n}\n\n/**\n * Options for the updater\n */\nexport interface UpdaterOptions {\n /** Directory for backups (default: '.ai_readme_history') */\n backupDir?: string;\n /** Whether to create backups */\n createBackup?: boolean;\n}\n\n/**\n * Validation configuration\n */\nexport interface ValidationConfig {\n /** Maximum tokens allowed (default: 500) */\n maxTokens?: number;\n /** Validation rules */\n rules?: {\n /** Require H1 heading (default: true) */\n requireH1?: boolean;\n /** Required sections (default: []) */\n requireSections?: string[];\n /** Allow code blocks (default: true) */\n allowCodeBlocks?: boolean;\n /** Maximum line length (default: 120) */\n maxLineLength?: number;\n };\n /** Token limit thresholds */\n tokenLimits?: {\n /** Excellent: under this many tokens (default: 300) */\n excellent?: number;\n /** Good: under this many tokens (default: 500) */\n good?: number;\n /** Warning: under this many tokens (default: 800) */\n warning?: number;\n /** Error: over this many tokens (default: 1200) */\n error?: number;\n };\n}\n\n/**\n * Fully resolved validation configuration (all properties required)\n */\nexport interface ResolvedValidationConfig {\n maxTokens: number;\n rules: {\n requireH1: boolean;\n requireSections: string[];\n allowCodeBlocks: boolean;\n maxLineLength: number;\n };\n tokenLimits: {\n excellent: number;\n good: number;\n warning: number;\n error: number;\n };\n}\n\n/**\n * Default validation configuration\n */\nexport const DEFAULT_VALIDATION_CONFIG: ResolvedValidationConfig = {\n maxTokens: 400,\n rules: {\n requireH1: true,\n requireSections: [],\n allowCodeBlocks: false,\n maxLineLength: 100,\n },\n tokenLimits: {\n excellent: 200,\n good: 400,\n warning: 600,\n error: 1000,\n },\n};\n\n/**\n * Validation issue severity\n */\nexport type ValidationSeverity = 'error' | 'warning' | 'info';\n\n/**\n * Validation rule type\n */\nexport type ValidationRule =\n | 'token-count'\n | 'require-h1'\n | 'require-sections'\n | 'code-blocks'\n | 'line-length'\n | 'empty-content'\n | 'structure';\n\n/**\n * Validation issue\n */\nexport interface ValidationIssue {\n /** Issue severity */\n type: ValidationSeverity;\n /** Rule that triggered this issue */\n rule: ValidationRule;\n /** Issue message */\n message: string;\n /** Line number (if applicable) */\n line?: number;\n /** Suggestion for fixing */\n suggestion?: string;\n}\n\n/**\n * Validation result for a single README\n */\nexport interface ValidationResult {\n /** Whether validation passed */\n valid: boolean;\n /** Path to the README file */\n filePath: string;\n /** List of issues found */\n issues: ValidationIssue[];\n /** Quality score (0-100) */\n score?: number;\n /** Token count statistics */\n stats?: {\n tokens: number;\n lines: number;\n characters: number;\n };\n}\n","import { z } from 'zod';\nimport { ReadmeValidator } from '../core/validator.js';\nimport { AIReadmeScanner } from '../core/scanner.js';\nimport type { ValidationConfig } from '../types/index.js';\n\n/**\n * Zod schema for validate_ai_readmes tool\n */\nexport const validateSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z.array(z.string()).optional().describe(\n 'Glob patterns to exclude (e.g., [\"node_modules/**\", \".git/**\"])'\n ),\n config: z.object({\n maxTokens: z.number().optional(),\n rules: z.object({\n requireH1: z.boolean().optional(),\n requireSections: z.array(z.string()).optional(),\n allowCodeBlocks: z.boolean().optional(),\n maxLineLength: z.number().optional(),\n }).optional(),\n tokenLimits: z.object({\n excellent: z.number().optional(),\n good: z.number().optional(),\n warning: z.number().optional(),\n error: z.number().optional(),\n }).optional(),\n }).optional().describe('Custom validation configuration (optional, uses defaults if not provided)'),\n});\n\nexport type ValidateInput = z.infer<typeof validateSchema>;\n\n/**\n * Validate all AI_README.md files in a project\n *\n * @param input - Validation parameters\n * @returns Validation results for all README files\n *\n * @example\n * ```typescript\n * await validateAIReadmes({\n * projectRoot: '/path/to/project',\n * excludePatterns: ['node_modules/**'],\n * config: {\n * maxTokens: 500,\n * rules: {\n * requireH1: true,\n * requireSections: ['## Architecture', '## Conventions']\n * }\n * }\n * });\n * ```\n */\nexport async function validateAIReadmes(input: ValidateInput) {\n const { projectRoot, excludePatterns, config: userConfig } = input;\n\n try {\n // Use provided config, fallback to file config if available, then defaults\n let config: Partial<ValidationConfig> | undefined = userConfig;\n\n if (!config) {\n // Optionally load from .aireadme.config.json if it exists\n const fileConfig = await ReadmeValidator.loadConfig(projectRoot);\n if (fileConfig) {\n config = fileConfig;\n }\n }\n\n // Create validator with config\n const validator = new ReadmeValidator(config);\n\n // Scan for all README files\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns: excludePatterns || [],\n cacheContent: false,\n });\n const index = await scanner.scan();\n\n // Validate each README\n const results = [];\n for (const readme of index.readmes) {\n const result = await validator.validate(readme.path);\n results.push(result);\n }\n\n // Calculate overall statistics\n const totalFiles = results.length;\n const validFiles = results.filter(r => r.valid).length;\n const totalIssues = results.reduce((sum, r) => sum + r.issues.length, 0);\n const averageScore = totalFiles > 0\n ? Math.round(results.reduce((sum, r) => sum + (r.score || 0), 0) / totalFiles)\n : 0;\n\n // Group issues by severity\n const issuesBySeverity = {\n error: 0,\n warning: 0,\n info: 0,\n };\n for (const result of results) {\n for (const issue of result.issues) {\n issuesBySeverity[issue.type]++;\n }\n }\n\n return {\n success: true,\n projectRoot,\n summary: {\n totalFiles,\n validFiles,\n invalidFiles: totalFiles - validFiles,\n totalIssues,\n averageScore,\n issuesBySeverity,\n },\n results,\n message: totalIssues === 0\n ? `All ${totalFiles} README files passed validation! Average score: ${averageScore}/100`\n : `Found ${totalIssues} issues across ${totalFiles} README files. ${validFiles} files passed validation.`,\n };\n } catch (error) {\n return {\n success: false,\n projectRoot,\n error: error instanceof Error ? error.message : String(error),\n message: `Validation failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n","/**\n * MCP Tool: init_ai_readme\n * Scans project for empty AI_README files and populates them with AI-generated content\n */\n\nimport { z } from 'zod';\nimport { writeFile, readFile } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport { AIReadmeScanner } from '../core/scanner.js';\n\nexport const initSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe('Glob patterns to exclude when scanning'),\n targetPath: z\n .string()\n .optional()\n .describe('Specific directory to initialize (optional, defaults to scanning entire project)'),\n});\n\nexport type InitInput = z.infer<typeof initSchema>;\n\ninterface EmptyReadmeInfo {\n path: string;\n dirPath: string;\n needsCreation: boolean;\n}\n\n/**\n * Initialize AI_README files in the project\n * - Scans for empty or missing AI_README files\n * - Prompts AI to populate them with project conventions\n */\nexport async function initAIReadme(input: InitInput) {\n const { projectRoot, excludePatterns, targetPath } = input;\n\n // Scan the project\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: true,\n });\n\n const index = await scanner.scan();\n\n // Find empty AI_README files\n const emptyReadmes: EmptyReadmeInfo[] = [];\n\n // Check existing AI_READMEs\n for (const readme of index.readmes) {\n if (!readme.content || readme.content.trim().length === 0) {\n emptyReadmes.push({\n path: readme.path,\n dirPath: readme.path.replace(/[\\/\\\\]AI_README\\.md$/, ''),\n needsCreation: false,\n });\n }\n }\n\n // If no AI_README exists at all, create one at project root\n if (index.readmes.length === 0) {\n const rootReadmePath = join(projectRoot, 'AI_README.md');\n\n // Create empty file if it doesn't exist\n if (!existsSync(rootReadmePath)) {\n await writeFile(rootReadmePath, '', 'utf-8');\n }\n\n emptyReadmes.push({\n path: rootReadmePath,\n dirPath: projectRoot,\n needsCreation: true,\n });\n }\n\n // If targetPath is specified, filter to only that path\n let targetReadmes = emptyReadmes;\n if (targetPath) {\n const normalizedTarget = targetPath.replace(/\\\\/g, '/');\n targetReadmes = emptyReadmes.filter(r =>\n r.dirPath.replace(/\\\\/g, '/').includes(normalizedTarget)\n );\n }\n\n // If no empty READMEs found\n if (targetReadmes.length === 0) {\n return {\n success: true,\n message: '✅ All AI_README files are already populated!',\n initialized: [],\n };\n }\n\n // Generate initialization instructions for AI\n let promptText = `# 🚀 AI_README Initialization\\n\\n`;\n promptText += `Found ${targetReadmes.length} AI_README file(s) that need population.\\n\\n`;\n\n if (targetReadmes.some(r => r.needsCreation)) {\n promptText += `✅ Created empty AI_README file(s) at:\\n`;\n for (const readme of targetReadmes.filter(r => r.needsCreation)) {\n promptText += `- ${readme.path.replace(/\\\\/g, '/')}\\n`;\n }\n promptText += `\\n`;\n }\n\n promptText += `## 📋 Required Actions\\n\\n`;\n promptText += `You must populate the following AI_README files by analyzing their respective directories:\\n\\n`;\n\n for (let i = 0; i < targetReadmes.length; i++) {\n const readme = targetReadmes[i];\n const readmePath = readme.path.replace(/\\\\/g, '/');\n const dirPath = readme.dirPath.replace(/\\\\/g, '/');\n\n promptText += `### ${i + 1}. ${readmePath}\\n\\n`;\n promptText += `**Directory to analyze:** \\`${dirPath}\\`\\n\\n`;\n promptText += `**Steps:**\\n\\n`;\n promptText += `1. **Scan directory contents:**\\n`;\n promptText += ` \\`\\`\\`\\n`;\n promptText += ` Use Glob: pattern=\"**/*\", path=\"${dirPath}\"\\n`;\n promptText += ` \\`\\`\\`\\n\\n`;\n promptText += `2. **Read key source files** (pick 2-5 representative files):\\n`;\n promptText += ` - Configuration files (package.json, tsconfig.json, etc.)\\n`;\n promptText += ` - Main source files\\n`;\n promptText += ` - Important modules/components\\n\\n`;\n promptText += `3. **Analyze and identify:**\\n`;\n promptText += ` - 📦 **Tech Stack**: Frameworks, libraries, languages, tools\\n`;\n promptText += ` - 🏗️ **Architecture**: Project structure, design patterns\\n`;\n promptText += ` - 📝 **Coding Conventions**: Naming, formatting, patterns\\n`;\n promptText += ` - 🗂️ **File Structure**: Directory organization, module boundaries\\n\\n`;\n promptText += `4. **Populate AI_README:**\\n`;\n promptText += ` \\`\\`\\`\\n`;\n promptText += ` Use update_ai_readme:\\n`;\n promptText += ` {\\n`;\n promptText += ` readmePath: \"${readmePath}\",\\n`;\n promptText += ` operations: [{\\n`;\n promptText += ` type: \"append\",\\n`;\n promptText += ` content: \"<your analysis in markdown format>\"\\n`;\n promptText += ` }]\\n`;\n promptText += ` }\\n`;\n promptText += ` \\`\\`\\`\\n\\n`;\n promptText += ` **Include these sections:**\\n`;\n promptText += ` - \\`## Tech Stack\\` - List frameworks, libraries, tools\\n`;\n promptText += ` - \\`## Architecture Patterns\\` - Design patterns, project structure\\n`;\n promptText += ` - \\`## Coding Conventions\\` - Naming, formatting, best practices\\n`;\n promptText += ` - \\`## File Structure\\` - Directory organization (brief)\\n\\n`;\n promptText += ` **Keep it concise:** AI_READMEs should be <400 tokens. Focus on actionable conventions.\\n\\n`;\n }\n\n promptText += `---\\n\\n`;\n promptText += `💡 **Tips:**\\n`;\n promptText += `- Work through each README sequentially\\n`;\n promptText += `- Be concise - every token counts!\\n`;\n promptText += `- Focus on conventions that help generate better code\\n`;\n promptText += `- After completing all, you can verify with \\`validate_ai_readmes\\`\\n\\n`;\n promptText += `**Start with the first AI_README now!**\\n`;\n\n return {\n success: true,\n message: `Found ${targetReadmes.length} AI_README file(s) to initialize`,\n readmesToInitialize: targetReadmes.map(r => r.path.replace(/\\\\/g, '/')),\n instructions: promptText,\n };\n}\n"],"mappings":"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","names":["dirname","join","z","dirname","join","readFile","z","z","dirname","readFile","readFile","existsSync","join","existsSync","readFile","join","z","dirname","z","z","z","writeFile","join","existsSync","z","join","existsSync","writeFile","__filename","__dirname","dirname","join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-readme-mcp",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "MCP server for managing AI_README.md files in projects",
5
5
  "type": "module",
6
6
  "bin": {