ai-readme-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,7 +28,8 @@ Think of it as a **"style guide and context manager for AI"** - ensuring every A
28
28
  - 🎯 **Smart Context Routing** - Find relevant README content based on file paths
29
29
  - 🔄 **Update & Sync** - AI can both read and update AI_README files
30
30
  - ✅ **Validation & Quality** - Ensure README consistency with token limits and structure checks
31
- - 📝 **Template System** - Initialize new AI_README files from templates
31
+ - 🤖 **Smart Initialization** - Auto-generate AI_README files based on project analysis
32
+ - 🏗️ **Monorepo Support** - Place AI_README.md files at different folder levels; the tool automatically finds and uses the most relevant one
32
33
  - 📦 **Easy Integration** - Works seamlessly with Cursor, Claude Code, and other MCP clients
33
34
 
34
35
 
@@ -36,7 +37,7 @@ Think of it as a **"style guide and context manager for AI"** - ensuring every A
36
37
 
37
38
  ### Installation
38
39
 
39
- **Option 1: Using npx (Recommended - After npm publish)**
40
+ **Option 1: Using npx (Recommended)**
40
41
 
41
42
  No installation needed! Just configure and use via npx:
42
43
 
@@ -53,7 +54,7 @@ No installation needed! Just configure and use via npx:
53
54
 
54
55
  The `-y` flag automatically accepts the npx prompt.
55
56
 
56
- **Option 2: Global Installation (After npm publish)**
57
+ **Option 2: Global Installation**
57
58
 
58
59
  ```bash
59
60
  npm install -g ai-readme-mcp
@@ -71,9 +72,9 @@ Then configure:
71
72
  }
72
73
  ```
73
74
 
74
- **Option 3: Local Development (Current)**
75
+ **Option 3: Local Development**
75
76
 
76
- > **Note:** Use this method before npm package is published.
77
+ > **Note:** Use this method if you want to modify or contribute to the source code.
77
78
 
78
79
  ```bash
79
80
  # Clone this repository to a permanent location
@@ -142,7 +143,7 @@ Add to Cursor's MCP configuration file:
142
143
  **Windows:** `%APPDATA%\Cursor\User\mcp.json`
143
144
  **macOS/Linux:** `~/.cursor/mcp.json`
144
145
 
145
- **After npm publish (Recommended):**
146
+ **Using npx (Recommended):**
146
147
 
147
148
  ```json
148
149
  {
@@ -155,7 +156,7 @@ Add to Cursor's MCP configuration file:
155
156
  }
156
157
  ```
157
158
 
158
- **Or if globally installed:**
159
+ **If globally installed:**
159
160
 
160
161
  ```json
161
162
  {
@@ -167,16 +168,14 @@ Add to Cursor's MCP configuration file:
167
168
  }
168
169
  ```
169
170
 
170
- **Current (local development):**
171
+ **For local development:**
171
172
 
172
173
  ```json
173
174
  {
174
175
  "mcpServers": {
175
176
  "ai-readme-manager": {
176
177
  "command": "node",
177
- "args": [
178
- "D:\\Home\\WorkSpace\\playground\\ai-readme-mcp\\dist\\index.js"
179
- ]
178
+ "args": ["/path/to/ai-readme-mcp/dist/index.js"]
180
179
  }
181
180
  }
182
181
  }
@@ -193,7 +192,7 @@ Add to `claude_desktop_config.json`:
193
192
  **Windows:** `%APPDATA%\claude\claude_desktop_config.json`
194
193
  **macOS/Linux:** `~/.config/claude/config.json` or `~/Library/Application Support/Claude/config.json`
195
194
 
196
- **After npm publish (Recommended):**
195
+ **Using npx (Recommended):**
197
196
 
198
197
  ```json
199
198
  {
@@ -206,7 +205,7 @@ Add to `claude_desktop_config.json`:
206
205
  }
207
206
  ```
208
207
 
209
- **Or if globally installed:**
208
+ **If globally installed:**
210
209
 
211
210
  ```json
212
211
  {
@@ -218,14 +217,14 @@ Add to `claude_desktop_config.json`:
218
217
  }
219
218
  ```
220
219
 
221
- **Current (local development):**
220
+ **For local development:**
222
221
 
223
222
  ```json
224
223
  {
225
224
  "mcpServers": {
226
225
  "ai-readme-manager": {
227
226
  "command": "node",
228
- "args": ["/absolute/path/to/ai-readme-mcp/dist/index.js"]
227
+ "args": ["/path/to/ai-readme-mcp/dist/index.js"]
229
228
  }
230
229
  }
231
230
  }
@@ -233,7 +232,20 @@ Add to `claude_desktop_config.json`:
233
232
 
234
233
  ### Create Your First AI_README
235
234
 
236
- Create `AI_README.md` in your project root:
235
+ You can use the `init_ai_readme` MCP tool to automatically generate a customized AI_README.md based on your project:
236
+
237
+ **Smart Mode (Default)**:
238
+ The tool automatically detects your project and generates relevant content:
239
+ - Detects project type (library/application/monorepo)
240
+ - Identifies language (TypeScript, Python, Go, Rust, Java, etc.)
241
+ - Recognizes framework (React, Vue, Next.js, Express, NestJS, etc.)
242
+ - Analyzes directory structure
243
+ - Generates framework-specific conventions
244
+
245
+ Ask your AI assistant:
246
+ > "Please use init_ai_readme to create an AI_README.md for this project"
247
+
248
+ Or create manually:
237
249
 
238
250
  ```markdown
239
251
  # My Project
@@ -251,13 +263,54 @@ Create `AI_README.md` in your project root:
251
263
  Run tests with: `npm test`
252
264
  ```
253
265
 
266
+ ### Multi-Level AI_README (Not Just for Monorepos!)
267
+
268
+ **The power of this tool is multi-level documentation** - not just for monorepos, but for **any project** that wants to organize conventions by module or feature.
269
+
270
+ **Why multi-level?**
271
+ - 🎯 **Avoid bloated root README** - Keep each README focused and concise
272
+ - 📍 **Precise context** - AI gets only the relevant conventions for the code it's working on
273
+ - 🔧 **Flexible organization** - Organize by feature, module, or any structure that makes sense
274
+
275
+ Simply place `AI_README.md` files at different folder levels:
276
+
277
+ ```
278
+ my-monorepo/
279
+ ├── AI_README.md # Root-level conventions (applies to all)
280
+ ├── apps/
281
+ │ ├── frontend/
282
+ │ │ ├── AI_README.md # Frontend-specific conventions
283
+ │ │ └── src/components/Button.tsx
284
+ │ └── backend/
285
+ │ ├── AI_README.md # Backend-specific conventions
286
+ │ └── src/api/users.ts
287
+ └── packages/
288
+ └── shared/
289
+ ├── AI_README.md # Shared library conventions
290
+ └── src/utils.ts
291
+ ```
292
+
293
+ **Smart Empty README Handling:**
294
+ - 📝 If you create an empty `AI_README.md` in a subdirectory, the tool can auto-fill it with relevant conventions
295
+ - 🔗 For subdirectories with parent READMEs, generates differential content (only module-specific conventions)
296
+ - 📋 For root directories, generates full project analysis
297
+ - Ask your AI: "This AI_README.md is empty, can you help fill it?"
298
+
299
+ When AI works on a file, it automatically gets:
300
+ - The **most relevant** AI_README (closest parent directory)
301
+ - Plus the **root-level** AI_README (for project-wide standards)
302
+
303
+ For example, when editing `apps/frontend/src/components/Button.tsx`:
304
+ - ✅ Gets `apps/frontend/AI_README.md` (React component standards)
305
+ - ✅ Gets root `AI_README.md` (project-wide Git, testing conventions)
306
+
254
307
  ### Test the Integration
255
308
 
256
- Restart Claude Code, then ask:
309
+ Restart your IDE, then ask your AI assistant:
257
310
 
258
311
  > "I'm about to create a new component. What conventions should I follow?"
259
312
 
260
- Claude will use the MCP server to retrieve your AI_README context!
313
+ The AI will automatically retrieve your AI_README context!
261
314
 
262
315
  For detailed setup instructions, see [Quick Start Guide](./docs/QUICK_START.md).
263
316
 
@@ -314,10 +367,64 @@ npm run dev
314
367
  - **[Quick Start Guide](./docs/QUICK_START.md)** - Get started in 10 minutes
315
368
  - **[Contributing Guide](./CONTRIBUTING.md)** - How to contribute
316
369
  - [Project Specification](./docs/SPEC.md) - Complete technical specification
317
- - [AI_README Templates](./docs/templates/) - Example templates for your projects
318
370
 
319
371
  ## 🛠️ Available MCP Tools
320
372
 
373
+ ### `init_ai_readme`
374
+
375
+ Initialize a new AI_README.md file with smart content generation based on project analysis.
376
+
377
+ ```typescript
378
+ // Parameters
379
+ {
380
+ targetPath: string; // Required: Directory where AI_README.md will be created
381
+ projectName?: string; // Optional: Project name (auto-detected if not provided)
382
+ overwrite?: boolean; // Optional: Overwrite existing file (default: false)
383
+ smart?: boolean; // Optional: Enable smart content generation (default: true)
384
+ }
385
+
386
+ // Returns
387
+ {
388
+ success: boolean;
389
+ readmePath: string;
390
+ action: 'created' | 'filled' | 'overwritten';
391
+ projectInfo?: {
392
+ projectName: string;
393
+ projectType: 'library' | 'application' | 'monorepo' | 'unknown';
394
+ language: string;
395
+ framework?: string;
396
+ packageManager?: string;
397
+ hasTests: boolean;
398
+ mainDirs: string[];
399
+ };
400
+ message: string;
401
+ }
402
+ ```
403
+
404
+ **Smart Mode Features**:
405
+ - Auto-detects project type, language, and framework
406
+ - Generates framework-specific conventions (React, Vue, Python, etc.)
407
+ - For subdirectories with parent READMEs, generates differential content
408
+ - Handles empty files (< 50 chars) by auto-filling them
409
+ - Analyzes directory structure and dependencies
410
+
411
+ **Example Usage**:
412
+
413
+ ```typescript
414
+ // Create smart README for React project
415
+ {
416
+ targetPath: "/path/to/react-app",
417
+ smart: true
418
+ }
419
+ // Result: Auto-detects React, generates component naming conventions, etc.
420
+
421
+ // Fill empty subdirectory README
422
+ {
423
+ targetPath: "/path/to/monorepo/apps/frontend"
424
+ }
425
+ // Result: Generates differential content extending root README
426
+ ```
427
+
321
428
  ### `discover_ai_readmes`
322
429
 
323
430
  Scans your project and discovers all AI_README.md files.
@@ -440,6 +547,61 @@ Update an AI_README.md file with specified operations.
440
547
  }
441
548
  ```
442
549
 
550
+ ### `validate_ai_readmes`
551
+
552
+ Validate all AI_README.md files in your project for quality and token efficiency.
553
+
554
+ ```typescript
555
+ // Parameters
556
+ {
557
+ projectRoot: string; // Required: Project root directory
558
+ excludePatterns?: string[]; // Optional: Glob patterns to exclude
559
+ config?: { // Optional: Custom validation config
560
+ maxTokens?: number;
561
+ rules?: {
562
+ requireH1?: boolean;
563
+ requireSections?: string[];
564
+ allowCodeBlocks?: boolean;
565
+ maxLineLength?: number;
566
+ };
567
+ tokenLimits?: {
568
+ excellent?: number; // Default: 200
569
+ good?: number; // Default: 400
570
+ warning?: number; // Default: 600
571
+ error?: number; // Default: 1000
572
+ };
573
+ };
574
+ }
575
+
576
+ // Returns
577
+ {
578
+ valid: boolean;
579
+ totalFiles: number;
580
+ results: Array<{
581
+ path: string;
582
+ valid: boolean;
583
+ tokens: number;
584
+ rating: 'excellent' | 'good' | 'needs-improvement' | 'too-long';
585
+ issues: string[];
586
+ suggestions: string[];
587
+ }>;
588
+ summary: string;
589
+ }
590
+ ```
591
+
592
+ **Validation Features**:
593
+ - Token counting for AI consumption optimization
594
+ - Structure validation (H1 heading, sections)
595
+ - Line length checks (default: 100 chars)
596
+ - Code block detection (disabled by default for strict mode)
597
+ - Quality ratings based on token count
598
+
599
+ **Default Token Limits (Strict Mode)**:
600
+ - 🌟 Excellent: < 200 tokens
601
+ - ✅ Good: < 400 tokens
602
+ - ⚠️ Needs improvement: < 600 tokens
603
+ - ❌ Too long: > 1000 tokens
604
+
443
605
  ## 🚀 What's Next
444
606
 
445
607
  We're actively working on new features:
@@ -472,4 +634,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
472
634
 
473
635
  ---
474
636
 
475
- **Status:** ✅ Published | **Version:** 0.2.0 | **Last Updated:** 2025-11-07
637
+ **Status:** ✅ Published | **Version:** 0.3.0 | **Last Updated:** 2025-11-08
package/dist/index.js CHANGED
@@ -305,29 +305,56 @@ async function getContextForFile(input) {
305
305
  let promptText = `## \u{1F4DA} Project Context for: ${filePath}
306
306
 
307
307
  `;
308
- for (const ctx of formattedContexts) {
309
- if (ctx.relevance === "root") {
310
- promptText += `### Root Conventions (${ctx.path})
308
+ if (contexts.length === 0) {
309
+ promptText += `\u26A0\uFE0F **No AI_README.md files found in this project.**
311
310
 
312
311
  `;
313
- } else if (ctx.relevance === "direct") {
314
- promptText += `### Direct Module Conventions (${ctx.path})
312
+ promptText += `To get the most out of AI assistance, consider creating an AI_README.md file to document:
313
+ `;
314
+ promptText += `- Project architecture and conventions
315
+ `;
316
+ promptText += `- Coding standards and best practices
317
+ `;
318
+ promptText += `- Testing requirements
319
+ `;
320
+ promptText += `- Common patterns to follow
315
321
 
316
322
  `;
317
- } else {
318
- promptText += `### Parent Module Conventions (${ctx.path})
323
+ promptText += `**Quick Start:**
324
+ `;
325
+ promptText += `Use the \`init_ai_readme\` tool to create a template:
326
+ `;
327
+ promptText += `- Creates AI_README.md from a customizable template
328
+ `;
329
+ promptText += `- Helps maintain consistency across your team
330
+ `;
331
+ promptText += `- Improves AI output quality
332
+ `;
333
+ } else {
334
+ for (const ctx of formattedContexts) {
335
+ if (ctx.relevance === "root") {
336
+ promptText += `### Root Conventions (${ctx.path})
319
337
 
320
338
  `;
339
+ } else if (ctx.relevance === "direct") {
340
+ promptText += `### Direct Module Conventions (${ctx.path})
341
+
342
+ `;
343
+ } else {
344
+ promptText += `### Parent Module Conventions (${ctx.path})
345
+
346
+ `;
347
+ }
348
+ promptText += ctx.content + "\n\n";
321
349
  }
322
- promptText += ctx.content + "\n\n";
323
- }
324
- promptText += `---
350
+ promptText += `---
325
351
  **Important Reminders:**
326
352
  `;
327
- promptText += `- Follow the above conventions when making changes
353
+ promptText += `- Follow the above conventions when making changes
328
354
  `;
329
- promptText += `- If your changes affect architecture or conventions, consider updating the relevant AI_README
355
+ promptText += `- If your changes affect architecture or conventions, consider updating the relevant AI_README
330
356
  `;
357
+ }
331
358
  return {
332
359
  filePath,
333
360
  totalContexts: contexts.length,
@@ -883,53 +910,199 @@ async function validateAIReadmes(input) {
883
910
 
884
911
  // src/tools/init.ts
885
912
  import { z as z5 } from "zod";
886
- import { readFile as readFile5, writeFile as writeFile2 } from "fs/promises";
887
- import { join as join4, dirname as dirname4 } from "path";
888
- import { existsSync as existsSync3 } from "fs";
913
+ import { readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
914
+ import { join as join5, dirname as dirname4, relative } from "path";
915
+ import { existsSync as existsSync4 } from "fs";
889
916
  import { fileURLToPath } from "url";
917
+
918
+ // src/core/detector.ts
919
+ import { readFile as readFile5, readdir, stat } from "fs/promises";
920
+ import { join as join4 } from "path";
921
+ import { existsSync as existsSync3 } from "fs";
922
+ var ProjectDetector = class {
923
+ constructor(targetPath) {
924
+ this.targetPath = targetPath;
925
+ }
926
+ /**
927
+ * Detect project information by analyzing files and structure
928
+ */
929
+ async detect() {
930
+ const info = {
931
+ projectName: "Project",
932
+ projectType: "unknown",
933
+ language: "JavaScript",
934
+ hasTests: false,
935
+ mainDirs: []
936
+ };
937
+ const packageJsonPath = join4(this.targetPath, "package.json");
938
+ if (existsSync3(packageJsonPath)) {
939
+ await this.analyzePackageJson(packageJsonPath, info);
940
+ }
941
+ if (existsSync3(join4(this.targetPath, "requirements.txt")) || existsSync3(join4(this.targetPath, "setup.py")) || existsSync3(join4(this.targetPath, "pyproject.toml"))) {
942
+ info.language = "Python";
943
+ }
944
+ if (existsSync3(join4(this.targetPath, "go.mod"))) {
945
+ info.language = "Go";
946
+ }
947
+ if (existsSync3(join4(this.targetPath, "Cargo.toml"))) {
948
+ info.language = "Rust";
949
+ }
950
+ if (existsSync3(join4(this.targetPath, "pom.xml")) || existsSync3(join4(this.targetPath, "build.gradle"))) {
951
+ info.language = "Java";
952
+ }
953
+ await this.analyzeStructure(info);
954
+ return info;
955
+ }
956
+ /**
957
+ * Analyze package.json to extract project information
958
+ */
959
+ async analyzePackageJson(path, info) {
960
+ try {
961
+ const content = await readFile5(path, "utf-8");
962
+ const pkg = JSON.parse(content);
963
+ if (pkg.name) {
964
+ info.projectName = pkg.name;
965
+ }
966
+ if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript) {
967
+ info.language = "TypeScript";
968
+ }
969
+ if (pkg.dependencies?.react || pkg.devDependencies?.react) {
970
+ info.framework = "React";
971
+ } else if (pkg.dependencies?.vue || pkg.devDependencies?.vue) {
972
+ info.framework = "Vue";
973
+ } else if (pkg.dependencies?.["@angular/core"]) {
974
+ info.framework = "Angular";
975
+ } else if (pkg.dependencies?.next) {
976
+ info.framework = "Next.js";
977
+ } else if (pkg.dependencies?.express) {
978
+ info.framework = "Express";
979
+ } else if (pkg.dependencies?.nestjs || pkg.dependencies?.["@nestjs/core"]) {
980
+ info.framework = "NestJS";
981
+ }
982
+ const lockFiles = await readdir(this.targetPath);
983
+ if (lockFiles.includes("pnpm-lock.yaml")) {
984
+ info.packageManager = "pnpm";
985
+ } else if (lockFiles.includes("yarn.lock")) {
986
+ info.packageManager = "yarn";
987
+ } else if (lockFiles.includes("bun.lockb")) {
988
+ info.packageManager = "bun";
989
+ } else if (lockFiles.includes("package-lock.json")) {
990
+ info.packageManager = "npm";
991
+ }
992
+ if (pkg.workspaces || existsSync3(join4(this.targetPath, "pnpm-workspace.yaml"))) {
993
+ info.projectType = "monorepo";
994
+ }
995
+ if (!info.projectType || info.projectType === "unknown") {
996
+ if (pkg.main || pkg.exports) {
997
+ info.projectType = "library";
998
+ } else {
999
+ info.projectType = "application";
1000
+ }
1001
+ }
1002
+ if (pkg.dependencies) {
1003
+ info.dependencies = Object.keys(pkg.dependencies).slice(0, 5);
1004
+ }
1005
+ } catch (error) {
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Analyze directory structure
1010
+ */
1011
+ async analyzeStructure(info) {
1012
+ try {
1013
+ const entries = await readdir(this.targetPath);
1014
+ const dirs = [];
1015
+ for (const entry of entries) {
1016
+ try {
1017
+ const entryPath = join4(this.targetPath, entry);
1018
+ const stats = await stat(entryPath);
1019
+ if (stats.isDirectory()) {
1020
+ if (["src", "lib", "app", "pages", "components", "api", "server", "client"].includes(entry)) {
1021
+ dirs.push(entry);
1022
+ }
1023
+ if (["test", "tests", "__tests__", "spec"].includes(entry)) {
1024
+ info.hasTests = true;
1025
+ }
1026
+ if (["apps", "packages", "modules"].includes(entry)) {
1027
+ info.projectType = "monorepo";
1028
+ dirs.push(entry);
1029
+ }
1030
+ }
1031
+ } catch {
1032
+ }
1033
+ }
1034
+ info.mainDirs = dirs;
1035
+ } catch (error) {
1036
+ }
1037
+ }
1038
+ };
1039
+
1040
+ // src/tools/init.ts
890
1041
  var initSchema = z5.object({
891
1042
  targetPath: z5.string().describe("Directory where AI_README.md will be created"),
892
1043
  projectName: z5.string().optional().describe("Project name to use in the template (optional)"),
893
- overwrite: z5.boolean().optional().describe("Whether to overwrite existing AI_README.md (default: false)")
1044
+ overwrite: z5.boolean().optional().describe("Whether to overwrite existing AI_README.md (default: false)"),
1045
+ smart: z5.boolean().optional().describe("Enable smart content generation based on project analysis (default: true)")
894
1046
  });
895
1047
  async function initAIReadme(input) {
896
1048
  const { targetPath, projectName, overwrite = false } = input;
1049
+ const smart = input.smart !== false;
1050
+ console.error(`[DEBUG] init_ai_readme: smart=${smart}, input.smart=${input.smart}`);
897
1051
  try {
898
- if (!existsSync3(targetPath)) {
1052
+ if (!existsSync4(targetPath)) {
899
1053
  return {
900
1054
  success: false,
901
1055
  error: `Target directory does not exist: ${targetPath}`,
902
1056
  message: `Failed to create AI_README.md: Directory not found`
903
1057
  };
904
1058
  }
905
- const readmePath = join4(targetPath, "AI_README.md");
906
- if (existsSync3(readmePath) && !overwrite) {
907
- return {
908
- success: false,
909
- error: "AI_README.md already exists",
910
- message: `AI_README.md already exists at ${readmePath}. Use overwrite: true to replace it.`,
911
- existingPath: readmePath
912
- };
1059
+ const readmePath = join5(targetPath, "AI_README.md");
1060
+ const fileExists = existsSync4(readmePath);
1061
+ let isEmpty = false;
1062
+ if (fileExists) {
1063
+ const existingContent = await readFile6(readmePath, "utf-8");
1064
+ isEmpty = existingContent.trim().length < 50;
1065
+ if (!isEmpty && !overwrite) {
1066
+ return {
1067
+ success: false,
1068
+ error: "AI_README.md already exists with content",
1069
+ message: `AI_README.md already exists at ${readmePath}. Use overwrite: true to replace it.`,
1070
+ existingPath: readmePath
1071
+ };
1072
+ }
913
1073
  }
914
- const __filename2 = fileURLToPath(import.meta.url);
915
- const __dirname2 = dirname4(__filename2);
916
- const templatePath = join4(__dirname2, "..", "..", "docs", "templates", "basic.md");
917
- if (!existsSync3(templatePath)) {
918
- return {
919
- success: false,
920
- error: `Template file not found: ${templatePath}`,
921
- message: "Template file is missing. Please check installation."
922
- };
1074
+ let content;
1075
+ let detectedInfo = {};
1076
+ if (smart) {
1077
+ const detector = new ProjectDetector(targetPath);
1078
+ const projectInfo = await detector.detect();
1079
+ detectedInfo = projectInfo;
1080
+ const parentReadme = await findParentReadme(targetPath);
1081
+ const isSubdirectory = parentReadme !== null;
1082
+ content = await generateSmartContent(projectInfo, targetPath, isSubdirectory, parentReadme);
1083
+ } else {
1084
+ const __filename2 = fileURLToPath(import.meta.url);
1085
+ const __dirname2 = dirname4(__filename2);
1086
+ const templatePath = join5(__dirname2, "..", "..", "docs", "templates", "basic.md");
1087
+ if (!existsSync4(templatePath)) {
1088
+ return {
1089
+ success: false,
1090
+ error: `Template file not found: ${templatePath}`,
1091
+ message: "Template file is missing. Please check installation."
1092
+ };
1093
+ }
1094
+ content = await readFile6(templatePath, "utf-8");
1095
+ const finalProjectName = projectName || "Project Name";
1096
+ content = content.replace(/\{\{PROJECT_NAME\}\}/g, finalProjectName);
923
1097
  }
924
- let content = await readFile5(templatePath, "utf-8");
925
- const finalProjectName = projectName || "Project Name";
926
- content = content.replace(/\{\{PROJECT_NAME\}\}/g, finalProjectName);
927
1098
  await writeFile2(readmePath, content, "utf-8");
1099
+ const action = fileExists ? isEmpty ? "filled" : "overwritten" : "created";
928
1100
  return {
929
1101
  success: true,
930
1102
  readmePath,
931
- projectName: finalProjectName,
932
- message: `Successfully created AI_README.md at ${readmePath}. Edit the file to customize it for your project.`
1103
+ action,
1104
+ projectInfo: smart ? detectedInfo : void 0,
1105
+ message: `Successfully ${action} AI_README.md at ${readmePath}. ${smart ? "Content generated based on project analysis." : "Edit the file to customize it for your project."}`
933
1106
  };
934
1107
  } catch (error) {
935
1108
  return {
@@ -939,6 +1112,152 @@ async function initAIReadme(input) {
939
1112
  };
940
1113
  }
941
1114
  }
1115
+ async function findParentReadme(targetPath) {
1116
+ let currentPath = dirname4(targetPath);
1117
+ const root = "/";
1118
+ while (currentPath !== root) {
1119
+ const readmePath = join5(currentPath, "AI_README.md");
1120
+ if (existsSync4(readmePath)) {
1121
+ const content = await readFile6(readmePath, "utf-8");
1122
+ if (content.trim().length > 50) {
1123
+ return currentPath;
1124
+ }
1125
+ }
1126
+ const parentPath = dirname4(currentPath);
1127
+ if (parentPath === currentPath) break;
1128
+ currentPath = parentPath;
1129
+ }
1130
+ return null;
1131
+ }
1132
+ async function generateSmartContent(projectInfo, targetPath, isSubdirectory, parentPath) {
1133
+ let content = `# ${projectInfo.projectName}
1134
+
1135
+ `;
1136
+ if (isSubdirectory && parentPath) {
1137
+ const relativePath = relative(parentPath, targetPath);
1138
+ content += `> This README extends the root AI_README.md with ${relativePath}-specific conventions.
1139
+
1140
+ `;
1141
+ }
1142
+ content += `## Architecture
1143
+
1144
+ `;
1145
+ content += `- **Type:** ${projectInfo.projectType}
1146
+ `;
1147
+ content += `- **Language:** ${projectInfo.language}
1148
+ `;
1149
+ if (projectInfo.framework) {
1150
+ content += `- **Framework:** ${projectInfo.framework}
1151
+ `;
1152
+ }
1153
+ content += `
1154
+ `;
1155
+ if (projectInfo.mainDirs && projectInfo.mainDirs.length > 0) {
1156
+ content += `## Directory Structure
1157
+
1158
+ `;
1159
+ for (const dir of projectInfo.mainDirs) {
1160
+ content += `- ${dir}/ - [Add description]
1161
+ `;
1162
+ }
1163
+ content += `
1164
+ `;
1165
+ }
1166
+ content += `## Coding Conventions
1167
+
1168
+ `;
1169
+ content += `### File Naming
1170
+ `;
1171
+ content += `- [Add your file naming conventions here]
1172
+
1173
+ `;
1174
+ content += `### Code Style
1175
+ `;
1176
+ if (projectInfo.language === "TypeScript") {
1177
+ content += `- Use TypeScript strict mode
1178
+ `;
1179
+ content += `- Prefer interfaces over types for object shapes
1180
+ `;
1181
+ } else if (projectInfo.language === "Python") {
1182
+ content += `- Follow PEP 8 style guide
1183
+ `;
1184
+ content += `- Use type hints
1185
+ `;
1186
+ }
1187
+ content += `- [Add more style guidelines]
1188
+
1189
+ `;
1190
+ if (projectInfo.framework) {
1191
+ content += `### ${projectInfo.framework} Conventions
1192
+ `;
1193
+ if (projectInfo.framework === "React") {
1194
+ content += `- Component naming: PascalCase
1195
+ `;
1196
+ content += `- Hooks naming: use prefix 'use'
1197
+ `;
1198
+ content += `- Prefer functional components
1199
+ `;
1200
+ } else if (projectInfo.framework === "Vue") {
1201
+ content += `- Component naming: PascalCase or kebab-case
1202
+ `;
1203
+ content += `- Use Composition API
1204
+ `;
1205
+ }
1206
+ content += `
1207
+ `;
1208
+ }
1209
+ content += `## Testing
1210
+
1211
+ `;
1212
+ if (projectInfo.hasTests) {
1213
+ content += `- Tests are located in test directories
1214
+ `;
1215
+ }
1216
+ if (projectInfo.packageManager) {
1217
+ content += `- Run: \`${projectInfo.packageManager} test\`
1218
+ `;
1219
+ } else {
1220
+ content += `- Run: [Add test command]
1221
+ `;
1222
+ }
1223
+ content += `- Coverage target: [Add target or "not enforced"]
1224
+
1225
+ `;
1226
+ if (projectInfo.dependencies && projectInfo.dependencies.length > 0) {
1227
+ content += `## Key Dependencies
1228
+
1229
+ `;
1230
+ for (const dep of projectInfo.dependencies) {
1231
+ content += `- ${dep} - [Add purpose]
1232
+ `;
1233
+ }
1234
+ content += `
1235
+ `;
1236
+ }
1237
+ content += `## Development
1238
+
1239
+ `;
1240
+ if (projectInfo.packageManager) {
1241
+ content += `- Install: \`${projectInfo.packageManager} install\`
1242
+ `;
1243
+ content += `- Dev: \`${projectInfo.packageManager} run dev\`
1244
+ `;
1245
+ content += `- Build: \`${projectInfo.packageManager} run build\`
1246
+ `;
1247
+ }
1248
+ content += `
1249
+ `;
1250
+ content += `## Important Notes
1251
+
1252
+ `;
1253
+ content += `- [Add critical information that AI should know]
1254
+ `;
1255
+ content += `- [Security considerations]
1256
+ `;
1257
+ content += `- [Performance considerations]
1258
+ `;
1259
+ return content;
1260
+ }
942
1261
 
943
1262
  // src/index.ts
944
1263
  var server = new Server(
@@ -962,12 +1281,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
962
1281
  },
963
1282
  {
964
1283
  name: "get_context_for_file",
965
- description: "Get relevant AI_README context for a specific file path. Returns formatted context from relevant README files to help understand project conventions.",
1284
+ description: "Get relevant AI_README context for a specific file path. Returns formatted context from relevant README files to help understand project conventions. Use this BEFORE editing files to understand conventions.",
966
1285
  inputSchema: zodToJsonSchema(getContextSchema)
967
1286
  },
968
1287
  {
969
1288
  name: "update_ai_readme",
970
- description: "Update an AI_README.md file with specified operations (append, prepend, replace, insert-after, insert-before). Auto-validates after update. Changes are written directly; use Git for version control.",
1289
+ description: "Update an AI_README.md file when you discover important conventions, patterns, or rules while editing code. Use this to keep documentation in sync with code changes. Supports append, prepend, replace, insert-after, insert-before operations. Auto-validates after update.",
971
1290
  inputSchema: zodToJsonSchema(updateSchema)
972
1291
  },
973
1292
  {
@@ -977,7 +1296,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
977
1296
  },
978
1297
  {
979
1298
  name: "init_ai_readme",
980
- description: "Initialize a new AI_README.md file from a template. Creates a basic structure with common sections to help you get started quickly.",
1299
+ description: "Initialize or fill an AI_README.md file with smart content based on project analysis. Auto-detects project type, language, and framework. Use this to create new READMEs or fill empty ones.",
981
1300
  inputSchema: zodToJsonSchema(initSchema)
982
1301
  }
983
1302
  ]
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":["/**\n * AI_README MCP Server\n * Entry point for the MCP server\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport {\n discoverAIReadmes,\n discoverSchema,\n type DiscoverInput,\n} from './tools/discover.js';\nimport {\n getContextForFile,\n getContextSchema,\n type GetContextInput,\n} from './tools/getContext.js';\nimport {\n updateAIReadme,\n updateSchema,\n type UpdateInput,\n} from './tools/update.js';\nimport {\n validateAIReadmes,\n validateSchema,\n type ValidateInput,\n} from './tools/validate.js';\nimport {\n initAIReadme,\n initSchema,\n type InitInput,\n} from './tools/init.js';\n\nconst server = new Server(\n {\n name: 'ai-readme-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n);\n\n// Register tool: list_tools\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [\n {\n name: 'discover_ai_readmes',\n description:\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.',\n inputSchema: zodToJsonSchema(discoverSchema),\n },\n {\n name: 'get_context_for_file',\n description:\n 'Get relevant AI_README context for a specific file path. Returns formatted context from relevant README files to help understand project conventions.',\n inputSchema: zodToJsonSchema(getContextSchema),\n },\n {\n name: 'update_ai_readme',\n description:\n 'Update an AI_README.md file with specified operations (append, prepend, replace, insert-after, insert-before). Auto-validates after update. Changes are written directly; use Git for version control.',\n inputSchema: zodToJsonSchema(updateSchema),\n },\n {\n name: 'validate_ai_readmes',\n description:\n 'Validate all AI_README.md files in a project. Checks token count, structure, and content quality. Returns validation results with suggestions for improvement.',\n inputSchema: zodToJsonSchema(validateSchema),\n },\n {\n name: 'init_ai_readme',\n description:\n 'Initialize a new AI_README.md file from a template. Creates a basic structure with common sections to help you get started quickly.',\n inputSchema: zodToJsonSchema(initSchema),\n },\n ],\n };\n});\n\n// Register tool: call_tool\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n if (name === 'discover_ai_readmes') {\n const input = discoverSchema.parse(args) as DiscoverInput;\n const result = await discoverAIReadmes(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'get_context_for_file') {\n const input = getContextSchema.parse(args) as GetContextInput;\n const result = await getContextForFile(input);\n return {\n content: [\n {\n type: 'text',\n text: result.formattedPrompt,\n },\n ],\n };\n }\n\n if (name === 'update_ai_readme') {\n const input = updateSchema.parse(args) as UpdateInput;\n const result = await updateAIReadme(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'validate_ai_readmes') {\n const input = validateSchema.parse(args) as ValidateInput;\n const result = await validateAIReadmes(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'init_ai_readme') {\n const input = initSchema.parse(args) as InitInput;\n const result = await initAIReadme(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n throw new Error(`Unknown tool: ${name}`);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n});\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error('AI_README MCP Server started');\n console.error('Available tools: discover_ai_readmes, get_context_for_file, update_ai_readme, validate_ai_readmes, init_ai_readme');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\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","/**\n * MCP Tool: get_context_for_file\n * Gets relevant AI_README context for a specific file path\n */\n\nimport { z } from 'zod';\nimport { AIReadmeScanner } from '../core/scanner.js';\nimport { ContextRouter } from '../core/router.js';\n\nexport const getContextSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n filePath: z\n .string()\n .describe('The file path to get context for (relative to project root)'),\n includeRoot: z\n .boolean()\n .optional()\n .default(true)\n .describe('Whether to include root-level AI_README (default: true)'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe('Glob patterns to exclude when scanning'),\n});\n\nexport type GetContextInput = z.infer<typeof getContextSchema>;\n\nexport async function getContextForFile(input: GetContextInput) {\n const { projectRoot, filePath, includeRoot, excludePatterns } = input;\n\n // First, scan the project to build the index\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: true, // Cache content for context retrieval\n });\n\n const index = await scanner.scan();\n\n // Create router and get context\n const router = new ContextRouter(index);\n const contexts = await router.getContextForFile(filePath, includeRoot);\n\n // Format the response with a helpful prompt template\n const formattedContexts = contexts.map((ctx) => ({\n path: ctx.path,\n relevance: ctx.relevance,\n distance: ctx.distance,\n content: ctx.content,\n }));\n\n // Generate a formatted prompt for the AI\n let promptText = `## 📚 Project Context for: ${filePath}\\n\\n`;\n\n for (const ctx of formattedContexts) {\n if (ctx.relevance === 'root') {\n promptText += `### Root Conventions (${ctx.path})\\n\\n`;\n } else if (ctx.relevance === 'direct') {\n promptText += `### Direct Module Conventions (${ctx.path})\\n\\n`;\n } else {\n promptText += `### Parent Module Conventions (${ctx.path})\\n\\n`;\n }\n\n promptText += ctx.content + '\\n\\n';\n }\n\n promptText += `---\\n**Important Reminders:**\\n`;\n promptText += `- Follow the above conventions when making changes\\n`;\n promptText += `- If your changes affect architecture or conventions, consider updating the relevant AI_README\\n`;\n\n return {\n filePath,\n totalContexts: contexts.length,\n contexts: formattedContexts,\n formattedPrompt: promptText,\n };\n}\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 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: 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 // Check if file exists\n if (!existsSync(readmePath)) {\n return {\n success: false,\n error: `File not found: ${readmePath}`,\n changes: [],\n };\n }\n\n // Read current content\n const content = await readFile(readmePath, 'utf-8');\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","import { z } from 'zod';\nimport { readFile, writeFile } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport { existsSync } from 'fs';\nimport { fileURLToPath } from 'url';\n\n/**\n * Zod schema for init_ai_readme tool\n */\nexport const initSchema = z.object({\n targetPath: z.string().describe('Directory where AI_README.md will be created'),\n projectName: z.string().optional().describe('Project name to use in the template (optional)'),\n overwrite: z.boolean().optional().describe('Whether to overwrite existing AI_README.md (default: false)'),\n});\n\nexport type InitInput = z.infer<typeof initSchema>;\n\n/**\n * Initialize a new AI_README.md file from template\n *\n * @param input - Initialization parameters\n * @returns Result with created file path\n *\n * @example\n * ```typescript\n * await initAIReadme({\n * targetPath: '/path/to/project',\n * projectName: 'My Awesome Project',\n * overwrite: false\n * });\n * ```\n */\nexport async function initAIReadme(input: InitInput) {\n const { targetPath, projectName, overwrite = false } = input;\n\n try {\n // Validate target path\n if (!existsSync(targetPath)) {\n return {\n success: false,\n error: `Target directory does not exist: ${targetPath}`,\n message: `Failed to create AI_README.md: Directory not found`,\n };\n }\n\n const readmePath = join(targetPath, 'AI_README.md');\n\n // Check if file already exists\n if (existsSync(readmePath) && !overwrite) {\n return {\n success: false,\n error: 'AI_README.md already exists',\n message: `AI_README.md already exists at ${readmePath}. Use overwrite: true to replace it.`,\n existingPath: readmePath,\n };\n }\n\n // Get template path\n // In production (dist/), template is at ../../docs/templates/basic.md\n // In development (src/), template is at ../../docs/templates/basic.md\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const templatePath = join(__dirname, '..', '..', 'docs', 'templates', 'basic.md');\n\n if (!existsSync(templatePath)) {\n return {\n success: false,\n error: `Template file not found: ${templatePath}`,\n message: 'Template file is missing. Please check installation.',\n };\n }\n\n // Read template\n let content = await readFile(templatePath, 'utf-8');\n\n // Replace placeholders\n const finalProjectName = projectName || 'Project Name';\n content = content.replace(/\\{\\{PROJECT_NAME\\}\\}/g, finalProjectName);\n\n // Write to target\n await writeFile(readmePath, content, 'utf-8');\n\n return {\n success: true,\n readmePath,\n projectName: finalProjectName,\n message: `Successfully created AI_README.md at ${readmePath}. Edit the file to customize it for your project.`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n message: `Failed to create AI_README.md: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n"],"mappings":"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","names":["z","dirname","join","readFile","z","z","dirname","readFile","readFile","existsSync","join","existsSync","readFile","join","z","dirname","z","z","z","readFile","writeFile","join","dirname","existsSync","__filename","__dirname"]}
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","../src/core/detector.ts"],"sourcesContent":["/**\n * AI_README MCP Server\n * Entry point for the MCP server\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport {\n discoverAIReadmes,\n discoverSchema,\n type DiscoverInput,\n} from './tools/discover.js';\nimport {\n getContextForFile,\n getContextSchema,\n type GetContextInput,\n} from './tools/getContext.js';\nimport {\n updateAIReadme,\n updateSchema,\n type UpdateInput,\n} from './tools/update.js';\nimport {\n validateAIReadmes,\n validateSchema,\n type ValidateInput,\n} from './tools/validate.js';\nimport {\n initAIReadme,\n initSchema,\n type InitInput,\n} from './tools/init.js';\n\nconst server = new Server(\n {\n name: 'ai-readme-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n);\n\n// Register tool: list_tools\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [\n {\n name: 'discover_ai_readmes',\n description:\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.',\n inputSchema: zodToJsonSchema(discoverSchema),\n },\n {\n name: 'get_context_for_file',\n description:\n 'Get relevant AI_README context for a specific file path. Returns formatted context from relevant README files to help understand project conventions. Use this BEFORE editing files to understand conventions.',\n inputSchema: zodToJsonSchema(getContextSchema),\n },\n {\n name: 'update_ai_readme',\n description:\n 'Update an AI_README.md file when you discover important conventions, patterns, or rules while editing code. Use this to keep documentation in sync with code changes. Supports append, prepend, replace, insert-after, insert-before operations. Auto-validates after update.',\n inputSchema: zodToJsonSchema(updateSchema),\n },\n {\n name: 'validate_ai_readmes',\n description:\n 'Validate all AI_README.md files in a project. Checks token count, structure, and content quality. Returns validation results with suggestions for improvement.',\n inputSchema: zodToJsonSchema(validateSchema),\n },\n {\n name: 'init_ai_readme',\n description:\n 'Initialize or fill an AI_README.md file with smart content based on project analysis. Auto-detects project type, language, and framework. Use this to create new READMEs or fill empty ones.',\n inputSchema: zodToJsonSchema(initSchema),\n },\n ],\n };\n});\n\n// Register tool: call_tool\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n if (name === 'discover_ai_readmes') {\n const input = discoverSchema.parse(args) as DiscoverInput;\n const result = await discoverAIReadmes(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'get_context_for_file') {\n const input = getContextSchema.parse(args) as GetContextInput;\n const result = await getContextForFile(input);\n return {\n content: [\n {\n type: 'text',\n text: result.formattedPrompt,\n },\n ],\n };\n }\n\n if (name === 'update_ai_readme') {\n const input = updateSchema.parse(args) as UpdateInput;\n const result = await updateAIReadme(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'validate_ai_readmes') {\n const input = validateSchema.parse(args) as ValidateInput;\n const result = await validateAIReadmes(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'init_ai_readme') {\n const input = initSchema.parse(args) as InitInput;\n const result = await initAIReadme(input);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n throw new Error(`Unknown tool: ${name}`);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n});\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error('AI_README MCP Server started');\n console.error('Available tools: discover_ai_readmes, get_context_for_file, update_ai_readme, validate_ai_readmes, init_ai_readme');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\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","/**\n * MCP Tool: get_context_for_file\n * Gets relevant AI_README context for a specific file path\n */\n\nimport { z } from 'zod';\nimport { AIReadmeScanner } from '../core/scanner.js';\nimport { ContextRouter } from '../core/router.js';\n\nexport const getContextSchema = z.object({\n projectRoot: z.string().describe('The root directory of the project'),\n filePath: z\n .string()\n .describe('The file path to get context for (relative to project root)'),\n includeRoot: z\n .boolean()\n .optional()\n .default(true)\n .describe('Whether to include root-level AI_README (default: true)'),\n excludePatterns: z\n .array(z.string())\n .optional()\n .describe('Glob patterns to exclude when scanning'),\n});\n\nexport type GetContextInput = z.infer<typeof getContextSchema>;\n\nexport async function getContextForFile(input: GetContextInput) {\n const { projectRoot, filePath, includeRoot, excludePatterns } = input;\n\n // First, scan the project to build the index\n const scanner = new AIReadmeScanner(projectRoot, {\n excludePatterns,\n cacheContent: true, // Cache content for context retrieval\n });\n\n const index = await scanner.scan();\n\n // Create router and get context\n const router = new ContextRouter(index);\n const contexts = await router.getContextForFile(filePath, includeRoot);\n\n // Format the response with a helpful prompt template\n const formattedContexts = contexts.map((ctx) => ({\n path: ctx.path,\n relevance: ctx.relevance,\n distance: ctx.distance,\n content: ctx.content,\n }));\n\n // Generate a formatted prompt for the AI\n let promptText = `## 📚 Project Context for: ${filePath}\\n\\n`;\n\n if (contexts.length === 0) {\n // No AI_README found - provide helpful guidance\n promptText += `⚠️ **No AI_README.md files found in this project.**\\n\\n`;\n promptText += `To get the most out of AI assistance, consider creating an AI_README.md file to document:\\n`;\n promptText += `- Project architecture and conventions\\n`;\n promptText += `- Coding standards and best practices\\n`;\n promptText += `- Testing requirements\\n`;\n promptText += `- Common patterns to follow\\n\\n`;\n promptText += `**Quick Start:**\\n`;\n promptText += `Use the \\`init_ai_readme\\` tool to create a template:\\n`;\n promptText += `- Creates AI_README.md from a customizable template\\n`;\n promptText += `- Helps maintain consistency across your team\\n`;\n promptText += `- Improves AI output quality\\n`;\n } else {\n for (const ctx of formattedContexts) {\n if (ctx.relevance === 'root') {\n promptText += `### Root Conventions (${ctx.path})\\n\\n`;\n } else if (ctx.relevance === 'direct') {\n promptText += `### Direct Module Conventions (${ctx.path})\\n\\n`;\n } else {\n promptText += `### Parent Module Conventions (${ctx.path})\\n\\n`;\n }\n\n promptText += ctx.content + '\\n\\n';\n }\n\n promptText += `---\\n**Important Reminders:**\\n`;\n promptText += `- Follow the above conventions when making changes\\n`;\n promptText += `- If your changes affect architecture or conventions, consider updating the relevant AI_README\\n`;\n }\n\n return {\n filePath,\n totalContexts: contexts.length,\n contexts: formattedContexts,\n formattedPrompt: promptText,\n };\n}\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 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: 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 // Check if file exists\n if (!existsSync(readmePath)) {\n return {\n success: false,\n error: `File not found: ${readmePath}`,\n changes: [],\n };\n }\n\n // Read current content\n const content = await readFile(readmePath, 'utf-8');\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","import { z } from 'zod';\nimport { readFile, writeFile } from 'fs/promises';\nimport { join, dirname, relative } from 'path';\nimport { existsSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { ProjectDetector } from '../core/detector.js';\nimport { AIReadmeScanner } from '../core/scanner.js';\n\n/**\n * Zod schema for init_ai_readme tool\n */\nexport const initSchema = z.object({\n targetPath: z.string().describe('Directory where AI_README.md will be created'),\n projectName: z.string().optional().describe('Project name to use in the template (optional)'),\n overwrite: z.boolean().optional().describe('Whether to overwrite existing AI_README.md (default: false)'),\n smart: z.boolean().optional().describe('Enable smart content generation based on project analysis (default: true)'),\n});\n\nexport type InitInput = z.infer<typeof initSchema>;\n\n/**\n * Initialize a new AI_README.md file from template\n *\n * @param input - Initialization parameters\n * @returns Result with created file path\n *\n * @example\n * ```typescript\n * await initAIReadme({\n * targetPath: '/path/to/project',\n * projectName: 'My Awesome Project',\n * overwrite: false\n * });\n * ```\n */\nexport async function initAIReadme(input: InitInput) {\n const { targetPath, projectName, overwrite = false } = input;\n const smart = input.smart !== false; // Default to true unless explicitly set to false\n\n console.error(`[DEBUG] init_ai_readme: smart=${smart}, input.smart=${input.smart}`);\n\n try {\n // Validate target path\n if (!existsSync(targetPath)) {\n return {\n success: false,\n error: `Target directory does not exist: ${targetPath}`,\n message: `Failed to create AI_README.md: Directory not found`,\n };\n }\n\n const readmePath = join(targetPath, 'AI_README.md');\n\n // Check if file exists and is empty\n const fileExists = existsSync(readmePath);\n let isEmpty = false;\n\n if (fileExists) {\n const existingContent = await readFile(readmePath, 'utf-8');\n isEmpty = existingContent.trim().length < 50; // Consider empty if less than 50 characters\n\n if (!isEmpty && !overwrite) {\n return {\n success: false,\n error: 'AI_README.md already exists with content',\n message: `AI_README.md already exists at ${readmePath}. Use overwrite: true to replace it.`,\n existingPath: readmePath,\n };\n }\n }\n\n let content: string;\n let detectedInfo: any = {};\n\n if (smart) {\n // Smart mode: detect project and generate customized content\n const detector = new ProjectDetector(targetPath);\n const projectInfo = await detector.detect();\n detectedInfo = projectInfo;\n\n // Check if there's a parent AI_README\n const parentReadme = await findParentReadme(targetPath);\n const isSubdirectory = parentReadme !== null;\n\n // Generate smart content\n content = await generateSmartContent(projectInfo, targetPath, isSubdirectory, parentReadme);\n } else {\n // Basic mode: use template\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const templatePath = join(__dirname, '..', '..', 'docs', 'templates', 'basic.md');\n\n if (!existsSync(templatePath)) {\n return {\n success: false,\n error: `Template file not found: ${templatePath}`,\n message: 'Template file is missing. Please check installation.',\n };\n }\n\n content = await readFile(templatePath, 'utf-8');\n const finalProjectName = projectName || 'Project Name';\n content = content.replace(/\\{\\{PROJECT_NAME\\}\\}/g, finalProjectName);\n }\n\n // Write to target\n await writeFile(readmePath, content, 'utf-8');\n\n const action = fileExists ? (isEmpty ? 'filled' : 'overwritten') : 'created';\n\n return {\n success: true,\n readmePath,\n action,\n projectInfo: smart ? detectedInfo : undefined,\n message: `Successfully ${action} AI_README.md at ${readmePath}. ${smart ? 'Content generated based on project analysis.' : 'Edit the file to customize it for your project.'}`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n message: `Failed to create AI_README.md: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\n/**\n * Find parent AI_README.md by traversing up the directory tree\n */\nasync function findParentReadme(targetPath: string): Promise<string | null> {\n let currentPath = dirname(targetPath);\n const root = '/';\n\n while (currentPath !== root) {\n const readmePath = join(currentPath, 'AI_README.md');\n if (existsSync(readmePath)) {\n const content = await readFile(readmePath, 'utf-8');\n // Only consider it a parent if it has content\n if (content.trim().length > 50) {\n return currentPath;\n }\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) break; // Reached filesystem root\n currentPath = parentPath;\n }\n\n return null;\n}\n\n/**\n * Generate smart content based on project analysis\n */\nasync function generateSmartContent(\n projectInfo: any,\n targetPath: string,\n isSubdirectory: boolean,\n parentPath: string | null\n): Promise<string> {\n let content = `# ${projectInfo.projectName}\\n\\n`;\n\n // Add subdirectory note if applicable\n if (isSubdirectory && parentPath) {\n const relativePath = relative(parentPath, targetPath);\n content += `> This README extends the root AI_README.md with ${relativePath}-specific conventions.\\n\\n`;\n }\n\n // Architecture section\n content += `## Architecture\\n\\n`;\n content += `- **Type:** ${projectInfo.projectType}\\n`;\n content += `- **Language:** ${projectInfo.language}\\n`;\n if (projectInfo.framework) {\n content += `- **Framework:** ${projectInfo.framework}\\n`;\n }\n content += `\\n`;\n\n // Directory Structure\n if (projectInfo.mainDirs && projectInfo.mainDirs.length > 0) {\n content += `## Directory Structure\\n\\n`;\n for (const dir of projectInfo.mainDirs) {\n content += `- ${dir}/ - [Add description]\\n`;\n }\n content += `\\n`;\n }\n\n // Coding Conventions\n content += `## Coding Conventions\\n\\n`;\n content += `### File Naming\\n`;\n content += `- [Add your file naming conventions here]\\n\\n`;\n\n content += `### Code Style\\n`;\n if (projectInfo.language === 'TypeScript') {\n content += `- Use TypeScript strict mode\\n`;\n content += `- Prefer interfaces over types for object shapes\\n`;\n } else if (projectInfo.language === 'Python') {\n content += `- Follow PEP 8 style guide\\n`;\n content += `- Use type hints\\n`;\n }\n content += `- [Add more style guidelines]\\n\\n`;\n\n // Framework-specific conventions\n if (projectInfo.framework) {\n content += `### ${projectInfo.framework} Conventions\\n`;\n if (projectInfo.framework === 'React') {\n content += `- Component naming: PascalCase\\n`;\n content += `- Hooks naming: use prefix 'use'\\n`;\n content += `- Prefer functional components\\n`;\n } else if (projectInfo.framework === 'Vue') {\n content += `- Component naming: PascalCase or kebab-case\\n`;\n content += `- Use Composition API\\n`;\n }\n content += `\\n`;\n }\n\n // Testing\n content += `## Testing\\n\\n`;\n if (projectInfo.hasTests) {\n content += `- Tests are located in test directories\\n`;\n }\n if (projectInfo.packageManager) {\n content += `- Run: \\`${projectInfo.packageManager} test\\`\\n`;\n } else {\n content += `- Run: [Add test command]\\n`;\n }\n content += `- Coverage target: [Add target or \"not enforced\"]\\n\\n`;\n\n // Dependencies\n if (projectInfo.dependencies && projectInfo.dependencies.length > 0) {\n content += `## Key Dependencies\\n\\n`;\n for (const dep of projectInfo.dependencies) {\n content += `- ${dep} - [Add purpose]\\n`;\n }\n content += `\\n`;\n }\n\n // Development\n content += `## Development\\n\\n`;\n if (projectInfo.packageManager) {\n content += `- Install: \\`${projectInfo.packageManager} install\\`\\n`;\n content += `- Dev: \\`${projectInfo.packageManager} run dev\\`\\n`;\n content += `- Build: \\`${projectInfo.packageManager} run build\\`\\n`;\n }\n content += `\\n`;\n\n // Important Notes\n content += `## Important Notes\\n\\n`;\n content += `- [Add critical information that AI should know]\\n`;\n content += `- [Security considerations]\\n`;\n content += `- [Performance considerations]\\n`;\n\n return content;\n}\n","/**\r\n * ProjectDetector - Analyzes project directory to detect type, framework, and structure\r\n */\r\n\r\nimport { readFile, readdir, stat } from 'fs/promises';\r\nimport { join } from 'path';\r\nimport { existsSync } from 'fs';\r\n\r\nexport interface ProjectInfo {\r\n projectName: string;\r\n projectType: 'library' | 'application' | 'monorepo' | 'unknown';\r\n language: string;\r\n framework?: string;\r\n packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';\r\n hasTests: boolean;\r\n mainDirs: string[];\r\n dependencies?: string[];\r\n}\r\n\r\nexport class ProjectDetector {\r\n constructor(private targetPath: string) {}\r\n\r\n /**\r\n * Detect project information by analyzing files and structure\r\n */\r\n async detect(): Promise<ProjectInfo> {\r\n const info: ProjectInfo = {\r\n projectName: 'Project',\r\n projectType: 'unknown',\r\n language: 'JavaScript',\r\n hasTests: false,\r\n mainDirs: [],\r\n };\r\n\r\n // Check package.json\r\n const packageJsonPath = join(this.targetPath, 'package.json');\r\n if (existsSync(packageJsonPath)) {\r\n await this.analyzePackageJson(packageJsonPath, info);\r\n }\r\n\r\n // Check for Python\r\n if (existsSync(join(this.targetPath, 'requirements.txt')) ||\r\n existsSync(join(this.targetPath, 'setup.py')) ||\r\n existsSync(join(this.targetPath, 'pyproject.toml'))) {\r\n info.language = 'Python';\r\n }\r\n\r\n // Check for Go\r\n if (existsSync(join(this.targetPath, 'go.mod'))) {\r\n info.language = 'Go';\r\n }\r\n\r\n // Check for Rust\r\n if (existsSync(join(this.targetPath, 'Cargo.toml'))) {\r\n info.language = 'Rust';\r\n }\r\n\r\n // Check for Java\r\n if (existsSync(join(this.targetPath, 'pom.xml')) ||\r\n existsSync(join(this.targetPath, 'build.gradle'))) {\r\n info.language = 'Java';\r\n }\r\n\r\n // Analyze directory structure\r\n await this.analyzeStructure(info);\r\n\r\n return info;\r\n }\r\n\r\n /**\r\n * Analyze package.json to extract project information\r\n */\r\n private async analyzePackageJson(path: string, info: ProjectInfo): Promise<void> {\r\n try {\r\n const content = await readFile(path, 'utf-8');\r\n const pkg = JSON.parse(content);\r\n\r\n // Project name\r\n if (pkg.name) {\r\n info.projectName = pkg.name;\r\n }\r\n\r\n // Detect TypeScript\r\n if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript) {\r\n info.language = 'TypeScript';\r\n }\r\n\r\n // Detect framework\r\n if (pkg.dependencies?.react || pkg.devDependencies?.react) {\r\n info.framework = 'React';\r\n } else if (pkg.dependencies?.vue || pkg.devDependencies?.vue) {\r\n info.framework = 'Vue';\r\n } else if (pkg.dependencies?.['@angular/core']) {\r\n info.framework = 'Angular';\r\n } else if (pkg.dependencies?.next) {\r\n info.framework = 'Next.js';\r\n } else if (pkg.dependencies?.express) {\r\n info.framework = 'Express';\r\n } else if (pkg.dependencies?.nestjs || pkg.dependencies?.['@nestjs/core']) {\r\n info.framework = 'NestJS';\r\n }\r\n\r\n // Detect package manager\r\n const lockFiles = await readdir(this.targetPath);\r\n if (lockFiles.includes('pnpm-lock.yaml')) {\r\n info.packageManager = 'pnpm';\r\n } else if (lockFiles.includes('yarn.lock')) {\r\n info.packageManager = 'yarn';\r\n } else if (lockFiles.includes('bun.lockb')) {\r\n info.packageManager = 'bun';\r\n } else if (lockFiles.includes('package-lock.json')) {\r\n info.packageManager = 'npm';\r\n }\r\n\r\n // Detect monorepo\r\n if (pkg.workspaces || existsSync(join(this.targetPath, 'pnpm-workspace.yaml'))) {\r\n info.projectType = 'monorepo';\r\n }\r\n\r\n // Detect project type\r\n if (!info.projectType || info.projectType === 'unknown') {\r\n if (pkg.main || pkg.exports) {\r\n info.projectType = 'library';\r\n } else {\r\n info.projectType = 'application';\r\n }\r\n }\r\n\r\n // Get main dependencies\r\n if (pkg.dependencies) {\r\n info.dependencies = Object.keys(pkg.dependencies).slice(0, 5);\r\n }\r\n } catch (error) {\r\n // Ignore parsing errors\r\n }\r\n }\r\n\r\n /**\r\n * Analyze directory structure\r\n */\r\n private async analyzeStructure(info: ProjectInfo): Promise<void> {\r\n try {\r\n const entries = await readdir(this.targetPath);\r\n const dirs: string[] = [];\r\n\r\n for (const entry of entries) {\r\n try {\r\n const entryPath = join(this.targetPath, entry);\r\n const stats = await stat(entryPath);\r\n\r\n if (stats.isDirectory()) {\r\n // Check for common directories\r\n if (['src', 'lib', 'app', 'pages', 'components', 'api', 'server', 'client'].includes(entry)) {\r\n dirs.push(entry);\r\n }\r\n\r\n // Check for tests\r\n if (['test', 'tests', '__tests__', 'spec'].includes(entry)) {\r\n info.hasTests = true;\r\n }\r\n\r\n // Check for monorepo patterns\r\n if (['apps', 'packages', 'modules'].includes(entry)) {\r\n info.projectType = 'monorepo';\r\n dirs.push(entry);\r\n }\r\n }\r\n } catch {\r\n // Skip entries we can't access\r\n }\r\n }\r\n\r\n info.mainDirs = dirs;\r\n } catch (error) {\r\n // Ignore directory read errors\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["z","dirname","join","readFile","z","z","dirname","readFile","readFile","existsSync","join","existsSync","readFile","join","z","dirname","z","z","z","readFile","writeFile","join","dirname","existsSync","readFile","join","existsSync","z","existsSync","join","readFile","__filename","__dirname","dirname","writeFile"]}
@@ -0,0 +1,55 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ Brief description of this module or component.
4
+
5
+ ## Architecture
6
+
7
+ - **Type:** [Library/Service/Application/Component]
8
+ - **Language:** [TypeScript/JavaScript/Python/Java/Go/Rust/etc]
9
+ - **Framework:** [React/Vue/Django/Spring/Gin/etc]
10
+
11
+ ## Directory Structure
12
+
13
+ - Main entry: [path]
14
+ - Core logic: [path]
15
+ - Utilities: [path]
16
+
17
+ ## Coding Conventions
18
+
19
+ ### File Naming
20
+ - [snake_case/camelCase/PascalCase/kebab-case]
21
+
22
+ ### Code Style
23
+ - Formatting: [Prettier/Black/gofmt/rustfmt/etc]
24
+ - Linting: [ESLint/Pylint/golangci-lint/Clippy/etc]
25
+
26
+ ### Important Patterns
27
+ - Key architectural patterns or design decisions
28
+ - Project-specific best practices
29
+ - Common patterns to follow
30
+
31
+ ## Testing
32
+
33
+ - **Framework:** [Jest/Pytest/JUnit/Go testing/etc]
34
+ - **Run Command:** [command]
35
+ - **Coverage Target:** [percentage or "not enforced"]
36
+
37
+ ## Dependencies
38
+
39
+ ### Key Libraries
40
+ - [Library name] - Purpose and why used
41
+ - [Library name] - Purpose and why used
42
+
43
+ ## Development Workflow
44
+
45
+ - Installation: [command]
46
+ - Dev mode: [command]
47
+ - Build: [command]
48
+ - Run: [command]
49
+
50
+ ## Important Notes
51
+
52
+ - Critical information AI should know
53
+ - Security considerations
54
+ - Performance considerations
55
+ - Known limitations or gotchas
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-readme-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for managing AI_README.md files in projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,8 @@
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "docs/templates"
13
14
  ],
14
15
  "scripts": {
15
16
  "dev": "tsup --watch",