ai-readme-mcp 0.2.0 → 0.3.1
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 +235 -30
- package/dist/index.js +361 -42
- package/dist/index.js.map +1 -1
- package/docs/templates/basic.md +55 -0
- package/package.json +3 -2
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
|
-
|
|
309
|
-
|
|
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
|
-
|
|
314
|
-
|
|
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
|
-
|
|
318
|
-
|
|
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 +=
|
|
323
|
-
}
|
|
324
|
-
promptText += `---
|
|
350
|
+
promptText += `---
|
|
325
351
|
**Important Reminders:**
|
|
326
352
|
`;
|
|
327
|
-
|
|
353
|
+
promptText += `- Follow the above conventions when making changes
|
|
328
354
|
`;
|
|
329
|
-
|
|
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
|
|
887
|
-
import { join as
|
|
888
|
-
import { existsSync as
|
|
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 (!
|
|
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 =
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
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
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
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
|
-
|
|
932
|
-
|
|
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 creating or editing files to understand conventions - works even if the file does not exist yet.",
|
|
966
1285
|
inputSchema: zodToJsonSchema(getContextSchema)
|
|
967
1286
|
},
|
|
968
1287
|
{
|
|
969
1288
|
name: "update_ai_readme",
|
|
970
|
-
description: "Update an AI_README.md file with
|
|
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. Note: Only update when you find NEW conventions not already documented - avoid duplicate updates.",
|
|
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
|
|
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
|
]
|