leadcode 0.1.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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/bin/leadcode.js +2 -0
  4. package/dist/analyzers/constants.d.ts +3 -0
  5. package/dist/analyzers/constants.d.ts.map +1 -0
  6. package/dist/analyzers/constants.js +14 -0
  7. package/dist/analyzers/constants.js.map +1 -0
  8. package/dist/analyzers/dependencies.d.ts +8 -0
  9. package/dist/analyzers/dependencies.d.ts.map +1 -0
  10. package/dist/analyzers/dependencies.js +13 -0
  11. package/dist/analyzers/dependencies.js.map +1 -0
  12. package/dist/analyzers/detection.d.ts +6 -0
  13. package/dist/analyzers/detection.d.ts.map +1 -0
  14. package/dist/analyzers/detection.js +334 -0
  15. package/dist/analyzers/detection.js.map +1 -0
  16. package/dist/analyzers/patterns.d.ts +12 -0
  17. package/dist/analyzers/patterns.d.ts.map +1 -0
  18. package/dist/analyzers/patterns.js +84 -0
  19. package/dist/analyzers/patterns.js.map +1 -0
  20. package/dist/analyzers/structure.d.ts +3 -0
  21. package/dist/analyzers/structure.d.ts.map +1 -0
  22. package/dist/analyzers/structure.js +217 -0
  23. package/dist/analyzers/structure.js.map +1 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +64 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/rules/auth.d.ts +3 -0
  29. package/dist/rules/auth.d.ts.map +1 -0
  30. package/dist/rules/auth.js +48 -0
  31. package/dist/rules/auth.js.map +1 -0
  32. package/dist/rules/cross-stack.d.ts +3 -0
  33. package/dist/rules/cross-stack.d.ts.map +1 -0
  34. package/dist/rules/cross-stack.js +320 -0
  35. package/dist/rules/cross-stack.js.map +1 -0
  36. package/dist/rules/drizzle.d.ts +3 -0
  37. package/dist/rules/drizzle.d.ts.map +1 -0
  38. package/dist/rules/drizzle.js +43 -0
  39. package/dist/rules/drizzle.js.map +1 -0
  40. package/dist/rules/index.d.ts +7 -0
  41. package/dist/rules/index.d.ts.map +1 -0
  42. package/dist/rules/index.js +104 -0
  43. package/dist/rules/index.js.map +1 -0
  44. package/dist/rules/nextjs.d.ts +4 -0
  45. package/dist/rules/nextjs.d.ts.map +1 -0
  46. package/dist/rules/nextjs.js +86 -0
  47. package/dist/rules/nextjs.js.map +1 -0
  48. package/dist/rules/node.d.ts +3 -0
  49. package/dist/rules/node.d.ts.map +1 -0
  50. package/dist/rules/node.js +61 -0
  51. package/dist/rules/node.js.map +1 -0
  52. package/dist/rules/prisma.d.ts +3 -0
  53. package/dist/rules/prisma.d.ts.map +1 -0
  54. package/dist/rules/prisma.js +44 -0
  55. package/dist/rules/prisma.js.map +1 -0
  56. package/dist/rules/react.d.ts +3 -0
  57. package/dist/rules/react.d.ts.map +1 -0
  58. package/dist/rules/react.js +58 -0
  59. package/dist/rules/react.js.map +1 -0
  60. package/dist/rules/state.d.ts +3 -0
  61. package/dist/rules/state.d.ts.map +1 -0
  62. package/dist/rules/state.js +54 -0
  63. package/dist/rules/state.js.map +1 -0
  64. package/dist/rules/tailwind.d.ts +3 -0
  65. package/dist/rules/tailwind.d.ts.map +1 -0
  66. package/dist/rules/tailwind.js +41 -0
  67. package/dist/rules/tailwind.js.map +1 -0
  68. package/dist/rules/trpc.d.ts +3 -0
  69. package/dist/rules/trpc.d.ts.map +1 -0
  70. package/dist/rules/trpc.js +35 -0
  71. package/dist/rules/trpc.js.map +1 -0
  72. package/dist/rules/typescript.d.ts +3 -0
  73. package/dist/rules/typescript.d.ts.map +1 -0
  74. package/dist/rules/typescript.js +54 -0
  75. package/dist/rules/typescript.js.map +1 -0
  76. package/dist/rules/validation.d.ts +3 -0
  77. package/dist/rules/validation.d.ts.map +1 -0
  78. package/dist/rules/validation.js +38 -0
  79. package/dist/rules/validation.js.map +1 -0
  80. package/dist/templates/claude-md.d.ts +4 -0
  81. package/dist/templates/claude-md.d.ts.map +1 -0
  82. package/dist/templates/claude-md.js +309 -0
  83. package/dist/templates/claude-md.js.map +1 -0
  84. package/dist/tools/analyze-repo.d.ts +3 -0
  85. package/dist/tools/analyze-repo.d.ts.map +1 -0
  86. package/dist/tools/analyze-repo.js +68 -0
  87. package/dist/tools/analyze-repo.js.map +1 -0
  88. package/dist/tools/detect-gaps.d.ts +3 -0
  89. package/dist/tools/detect-gaps.d.ts.map +1 -0
  90. package/dist/tools/detect-gaps.js +34 -0
  91. package/dist/tools/detect-gaps.js.map +1 -0
  92. package/dist/tools/generate-claude-md.d.ts +3 -0
  93. package/dist/tools/generate-claude-md.d.ts.map +1 -0
  94. package/dist/tools/generate-claude-md.js +70 -0
  95. package/dist/tools/generate-claude-md.js.map +1 -0
  96. package/dist/tools/suggest.d.ts +3 -0
  97. package/dist/tools/suggest.d.ts.map +1 -0
  98. package/dist/tools/suggest.js +340 -0
  99. package/dist/tools/suggest.js.map +1 -0
  100. package/dist/tools/update-claude-md.d.ts +3 -0
  101. package/dist/tools/update-claude-md.d.ts.map +1 -0
  102. package/dist/tools/update-claude-md.js +108 -0
  103. package/dist/tools/update-claude-md.js.map +1 -0
  104. package/dist/tools/validate-claude-md.d.ts +3 -0
  105. package/dist/tools/validate-claude-md.d.ts.map +1 -0
  106. package/dist/tools/validate-claude-md.js +137 -0
  107. package/dist/tools/validate-claude-md.js.map +1 -0
  108. package/dist/types.d.ts +116 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +2 -0
  111. package/dist/types.js.map +1 -0
  112. package/package.json +55 -0
@@ -0,0 +1,340 @@
1
+ import * as z from "zod";
2
+ function buildSuggestions(analysis, gaps) {
3
+ const suggestions = [];
4
+ for (const gap of gaps) {
5
+ switch (gap.category) {
6
+ case "testing":
7
+ suggestions.push({
8
+ topic: "Testing Strategy",
9
+ options: [
10
+ {
11
+ level: "simple",
12
+ description: "Add Vitest for unit tests only",
13
+ pros: ["Fast setup", "Lightweight", "Great DX"],
14
+ cons: ["No E2E coverage"],
15
+ claudeImpact: "Claude will generate unit tests alongside new functions when asked.",
16
+ },
17
+ {
18
+ level: "clean",
19
+ description: "Vitest + Testing Library for component tests",
20
+ pros: ["Unit + component coverage", "Tests user behavior"],
21
+ cons: ["More setup", "Slower component tests"],
22
+ claudeImpact: "Claude will generate both unit and component tests with proper render/assert patterns.",
23
+ },
24
+ {
25
+ level: "scalable",
26
+ description: "Vitest + Testing Library + Playwright for E2E",
27
+ pros: ["Full coverage pyramid", "Catches integration bugs"],
28
+ cons: ["Significant setup", "Slower CI"],
29
+ claudeImpact: "Claude will generate tests at all levels and respect the testing pyramid.",
30
+ },
31
+ ],
32
+ });
33
+ break;
34
+ case "input-validation":
35
+ suggestions.push({
36
+ topic: "Input Validation",
37
+ options: [
38
+ {
39
+ level: "simple",
40
+ description: "Add Zod for manual validation in API routes",
41
+ pros: ["Minimal", "TypeScript-native"],
42
+ cons: ["Must remember to validate each route"],
43
+ claudeImpact: "Claude will add z.object().parse() in API routes when reminded.",
44
+ },
45
+ {
46
+ level: "clean",
47
+ description: "Zod with shared schemas directory and middleware",
48
+ pros: ["DRY schemas", "Consistent validation"],
49
+ cons: ["More structure upfront"],
50
+ claudeImpact: "Claude will import shared schemas and validate automatically in every route.",
51
+ },
52
+ ],
53
+ });
54
+ break;
55
+ case "error-handling":
56
+ suggestions.push({
57
+ topic: "Error Handling",
58
+ options: [
59
+ {
60
+ level: "simple",
61
+ description: "Add error.tsx in each route segment",
62
+ pros: ["Quick", "Follows Next.js conventions"],
63
+ cons: ["No structured error logging"],
64
+ claudeImpact: "Claude will create error.tsx files and handle errors gracefully.",
65
+ },
66
+ {
67
+ level: "clean",
68
+ description: "Error boundaries + centralized error utilities + structured logging",
69
+ pros: ["Consistent error format", "Debuggable"],
70
+ cons: ["More setup"],
71
+ claudeImpact: "Claude will use the error utilities consistently and produce debuggable error responses.",
72
+ },
73
+ ],
74
+ });
75
+ break;
76
+ case "shared-schemas":
77
+ suggestions.push({
78
+ topic: "Schema Organization",
79
+ options: [
80
+ {
81
+ level: "simple",
82
+ description: "Co-locate schemas next to their API routes",
83
+ pros: ["Easy to find", "No indirection"],
84
+ cons: ["Schemas get duplicated across routes"],
85
+ claudeImpact: "Claude will duplicate schemas when the same data is used in multiple routes.",
86
+ },
87
+ {
88
+ level: "clean",
89
+ description: "Shared /lib/schemas/ directory",
90
+ pros: ["Single source of truth", "DRY"],
91
+ cons: ["One more directory to manage"],
92
+ claudeImpact: "Claude will find and reuse schemas consistently across routes and forms.",
93
+ },
94
+ ],
95
+ });
96
+ break;
97
+ case "component-structure":
98
+ suggestions.push({
99
+ topic: "Component Organization",
100
+ options: [
101
+ {
102
+ level: "simple",
103
+ description: "Flat /components directory",
104
+ pros: ["Simple", "Works for small projects"],
105
+ cons: ["Gets messy at scale"],
106
+ claudeImpact: "Claude will place all components in one directory.",
107
+ },
108
+ {
109
+ level: "clean",
110
+ description: "Feature-based organization: /components/ui/ + /components/[feature]/",
111
+ pros: ["Scales well", "Clear ownership"],
112
+ cons: ["More directories"],
113
+ claudeImpact: "Claude will organize components by feature and reuse UI primitives.",
114
+ },
115
+ ],
116
+ });
117
+ break;
118
+ case "auth-middleware":
119
+ suggestions.push({
120
+ topic: "Route Protection",
121
+ options: [
122
+ {
123
+ level: "simple",
124
+ description: "Check auth in each Server Component/route handler",
125
+ pros: ["Explicit", "Easy to understand"],
126
+ cons: ["Easy to forget on new routes"],
127
+ claudeImpact: "Claude may forget auth checks on new routes unless reminded.",
128
+ },
129
+ {
130
+ level: "clean",
131
+ description: "middleware.ts with route matcher + per-route checks as backup",
132
+ pros: ["Centralized", "Defense in depth"],
133
+ cons: ["Middleware can be tricky to debug"],
134
+ claudeImpact: "Claude will add routes to the protected matcher and still add server-side checks.",
135
+ },
136
+ ],
137
+ });
138
+ break;
139
+ case "loading-states":
140
+ suggestions.push({
141
+ topic: "Loading States",
142
+ options: [
143
+ {
144
+ level: "simple",
145
+ description: "Add a single loading.tsx at the root app/ level",
146
+ pros: ["Quick", "Covers all routes"],
147
+ cons: ["Same loading UI everywhere"],
148
+ claudeImpact: "Claude will see the pattern and create loading.tsx for new route segments.",
149
+ },
150
+ {
151
+ level: "clean",
152
+ description: "Per-segment loading.tsx with skeleton UIs matching each page layout",
153
+ pros: ["Better UX", "Layout-aware skeletons"],
154
+ cons: ["More files to maintain"],
155
+ claudeImpact: "Claude will create matching skeleton UIs for each new route segment.",
156
+ },
157
+ ],
158
+ });
159
+ break;
160
+ case "metadata":
161
+ suggestions.push({
162
+ topic: "SEO & Metadata",
163
+ options: [
164
+ {
165
+ level: "simple",
166
+ description: "Static metadata export in each page.tsx",
167
+ pros: ["Simple", "Covers basic SEO"],
168
+ cons: ["No dynamic metadata for dynamic routes"],
169
+ claudeImpact: "Claude will add export const metadata to new pages.",
170
+ },
171
+ {
172
+ level: "clean",
173
+ description: "generateMetadata for dynamic pages + static metadata for others",
174
+ pros: ["Dynamic title/description per route", "Full SEO control"],
175
+ cons: ["More boilerplate per page"],
176
+ claudeImpact: "Claude will generate proper generateMetadata functions with dynamic data.",
177
+ },
178
+ ],
179
+ });
180
+ break;
181
+ case "prisma-client-singleton":
182
+ suggestions.push({
183
+ topic: "Prisma Client Singleton",
184
+ options: [
185
+ {
186
+ level: "simple",
187
+ description: "globalThis pattern in lib/prisma.ts",
188
+ pros: ["Standard approach", "Prevents hot-reload leaks"],
189
+ cons: ["Requires discipline to always import from there"],
190
+ claudeImpact: "Claude will import from lib/prisma.ts consistently.",
191
+ },
192
+ ],
193
+ });
194
+ break;
195
+ case "auth-session":
196
+ suggestions.push({
197
+ topic: "Auth Utility",
198
+ options: [
199
+ {
200
+ level: "simple",
201
+ description: "Create lib/auth.ts with getCurrentUser() function",
202
+ pros: ["Centralized", "Easy to use"],
203
+ cons: ["Must remember to use it"],
204
+ claudeImpact: "Claude will call getCurrentUser() in Server Components and Route Handlers.",
205
+ },
206
+ {
207
+ level: "clean",
208
+ description: "lib/auth.ts with getCurrentUser() + requireAuth() that throws on no session",
209
+ pros: ["Fail-safe", "Clear intent"],
210
+ cons: ["Slightly more code"],
211
+ claudeImpact: "Claude will use requireAuth() at the top of protected routes automatically.",
212
+ },
213
+ ],
214
+ });
215
+ break;
216
+ case "env-validation":
217
+ suggestions.push({
218
+ topic: "Environment Variable Validation",
219
+ options: [
220
+ {
221
+ level: "simple",
222
+ description: "Manual Zod validation in env.ts",
223
+ pros: ["No extra deps", "Full control"],
224
+ cons: ["Manual maintenance"],
225
+ claudeImpact: "Claude will import env vars from env.ts and never use process.env directly.",
226
+ },
227
+ {
228
+ level: "clean",
229
+ description: "Use @t3-oss/env-nextjs for type-safe env with client/server separation",
230
+ pros: ["Type-safe", "Client/server boundary enforcement"],
231
+ cons: ["Extra dependency"],
232
+ claudeImpact: "Claude will import from env.mjs and respect client/server env boundaries.",
233
+ },
234
+ ],
235
+ });
236
+ break;
237
+ case "types-dir":
238
+ suggestions.push({
239
+ topic: "Shared Types Organization",
240
+ options: [
241
+ {
242
+ level: "simple",
243
+ description: "Create a types/ directory with domain-specific type files",
244
+ pros: ["Clear location for shared types"],
245
+ cons: ["One more directory"],
246
+ claudeImpact: "Claude will place shared types in types/ and import from there.",
247
+ },
248
+ ],
249
+ });
250
+ break;
251
+ case "store-organization":
252
+ suggestions.push({
253
+ topic: "Store Organization",
254
+ options: [
255
+ {
256
+ level: "simple",
257
+ description: "Create a store/ directory with one file per store",
258
+ pros: ["Simple", "Easy to find"],
259
+ cons: ["Flat structure"],
260
+ claudeImpact: "Claude will create stores in store/ with clear naming.",
261
+ },
262
+ ],
263
+ });
264
+ break;
265
+ case "drizzle-schema-org":
266
+ suggestions.push({
267
+ topic: "Drizzle Schema Organization",
268
+ options: [
269
+ {
270
+ level: "simple",
271
+ description: "All schemas in db/schema.ts",
272
+ pros: ["Simple for small projects"],
273
+ cons: ["Gets large fast"],
274
+ claudeImpact: "Claude will add new tables to the single schema file.",
275
+ },
276
+ {
277
+ level: "clean",
278
+ description: "db/schema/ directory with one file per domain entity + index.ts barrel",
279
+ pros: ["Scales well", "Easy to find"],
280
+ cons: ["More files"],
281
+ claudeImpact: "Claude will create new schema files per entity and export from index.ts.",
282
+ },
283
+ ],
284
+ });
285
+ break;
286
+ default:
287
+ // Generic suggestion for uncategorized gaps
288
+ suggestions.push({
289
+ topic: gap.message,
290
+ options: [
291
+ {
292
+ level: "simple",
293
+ description: `Address: ${gap.message}`,
294
+ pros: ["Fixes the gap"],
295
+ cons: ["May need further refinement"],
296
+ claudeImpact: "Claude will follow the convention once documented in CLAUDE.md.",
297
+ },
298
+ ],
299
+ });
300
+ break;
301
+ }
302
+ }
303
+ return suggestions;
304
+ }
305
+ export function registerSuggest(server) {
306
+ server.registerTool("suggest-conventions", {
307
+ title: "Suggest Conventions",
308
+ description: "Given a repo analysis and detected gaps, proposes structured options (simple / clean / scalable) for each gap. Each option includes pros, cons, and impact on Claude Code behavior.",
309
+ inputSchema: {
310
+ analysis: z
311
+ .string()
312
+ .describe("JSON string of RepoAnalysis"),
313
+ gaps: z
314
+ .string()
315
+ .describe("JSON string of gaps array (output of detect-gaps)"),
316
+ },
317
+ }, async ({ analysis: analysisStr, gaps: gapsStr }) => {
318
+ try {
319
+ const analysis = JSON.parse(analysisStr);
320
+ const { gaps } = JSON.parse(gapsStr);
321
+ const suggestions = buildSuggestions(analysis, gaps);
322
+ return {
323
+ content: [
324
+ {
325
+ type: "text",
326
+ text: JSON.stringify({ suggestions }, null, 2),
327
+ },
328
+ ],
329
+ };
330
+ }
331
+ catch (err) {
332
+ const message = err instanceof Error ? err.message : String(err);
333
+ return {
334
+ isError: true,
335
+ content: [{ type: "text", text: `suggest-conventions failed: ${message}` }],
336
+ };
337
+ }
338
+ });
339
+ }
340
+ //# sourceMappingURL=suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest.js","sourceRoot":"","sources":["../../src/tools/suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerUpdateClaudeMd(server: McpServer): void;
3
+ //# sourceMappingURL=update-claude-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-claude-md.d.ts","sourceRoot":"","sources":["../../src/tools/update-claude-md.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmCzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoG9D"}
@@ -0,0 +1,108 @@
1
+ import { readFile, writeFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import * as z from "zod";
4
+ import { analyzeDependencies } from "../analyzers/dependencies.js";
5
+ import { analyzeStructure } from "../analyzers/structure.js";
6
+ import { detectFramework, detectStack } from "../analyzers/detection.js";
7
+ import { analyzePatterns } from "../analyzers/patterns.js";
8
+ import { getConventions, getInterdictions, getActiveCrossRefs, } from "../rules/index.js";
9
+ import { generateClaudeMd } from "../templates/claude-md.js";
10
+ /**
11
+ * Extract user-added sections from an existing CLAUDE.md.
12
+ * Preserves "Project Decisions" and any section not generated by LeadCode.
13
+ */
14
+ function extractUserChoices(existingContent) {
15
+ const choices = {};
16
+ const decisionsMatch = existingContent.match(/## Project Decisions\n+([\s\S]*?)(?=\n## |$)/);
17
+ if (decisionsMatch) {
18
+ const lines = decisionsMatch[1].trim().split("\n");
19
+ for (const line of lines) {
20
+ const m = line.match(/^- \*\*(.+?)\*\*: (.+)$/);
21
+ if (m) {
22
+ choices[m[1]] = m[2];
23
+ }
24
+ }
25
+ }
26
+ return choices;
27
+ }
28
+ export function registerUpdateClaudeMd(server) {
29
+ server.registerTool("update-claude-md", {
30
+ title: "Update CLAUDE.md",
31
+ description: "Re-analyzes the project and regenerates CLAUDE.md while preserving user choices from the Project Decisions section. Use this after adding dependencies, changing structure, or updating the stack.",
32
+ inputSchema: {
33
+ projectPath: z
34
+ .string()
35
+ .describe("Absolute path to the project root directory"),
36
+ },
37
+ }, async ({ projectPath }) => {
38
+ try {
39
+ // Verify project path
40
+ try {
41
+ await stat(projectPath);
42
+ }
43
+ catch {
44
+ return {
45
+ isError: true,
46
+ content: [{ type: "text", text: `Project directory not found: ${projectPath}` }],
47
+ };
48
+ }
49
+ const claudeMdPath = join(projectPath, "CLAUDE.md");
50
+ // Extract existing choices if CLAUDE.md exists
51
+ let previousChoices = {};
52
+ try {
53
+ const existing = await readFile(claudeMdPath, "utf-8");
54
+ previousChoices = extractUserChoices(existing);
55
+ }
56
+ catch {
57
+ // No existing file — that's fine
58
+ }
59
+ // Re-analyze
60
+ const pkg = await analyzeDependencies(projectPath);
61
+ const structure = await analyzeStructure(projectPath);
62
+ const framework = detectFramework(pkg.dependencies, pkg.devDependencies, structure);
63
+ const detected = detectStack(pkg.dependencies, pkg.devDependencies);
64
+ detected.runtime = structure.detectedRuntime;
65
+ const patterns = await analyzePatterns(projectPath);
66
+ const analysis = {
67
+ projectPath,
68
+ projectName: pkg.name,
69
+ framework,
70
+ dependencies: pkg.dependencies,
71
+ devDependencies: pkg.devDependencies,
72
+ scripts: pkg.scripts,
73
+ structure,
74
+ detected,
75
+ };
76
+ const conventions = getConventions(analysis);
77
+ const interdictions = getInterdictions(analysis);
78
+ const crossRefs = getActiveCrossRefs(analysis);
79
+ const content = generateClaudeMd(analysis, conventions, interdictions, crossRefs, previousChoices, patterns);
80
+ await writeFile(claudeMdPath, content, "utf-8");
81
+ return {
82
+ content: [
83
+ {
84
+ type: "text",
85
+ text: JSON.stringify({
86
+ path: claudeMdPath,
87
+ message: "CLAUDE.md updated successfully",
88
+ preservedChoices: Object.keys(previousChoices).length,
89
+ sections: {
90
+ conventions: conventions.length,
91
+ interdictions: interdictions.length,
92
+ crossStackRules: crossRefs.length,
93
+ },
94
+ }, null, 2),
95
+ },
96
+ ],
97
+ };
98
+ }
99
+ catch (err) {
100
+ const message = err instanceof Error ? err.message : String(err);
101
+ return {
102
+ isError: true,
103
+ content: [{ type: "text", text: `update-claude-md failed: ${message}` }],
104
+ };
105
+ }
106
+ });
107
+ }
108
+ //# sourceMappingURL=update-claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-claude-md.js","sourceRoot":"","sources":["../../src/tools/update-claude-md.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerValidateClaudeMd(server: McpServer): void;
3
+ //# sourceMappingURL=validate-claude-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-claude-md.d.ts","sourceRoot":"","sources":["../../src/tools/validate-claude-md.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkJhE"}
@@ -0,0 +1,137 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import * as z from "zod";
4
+ import { analyzeDependencies } from "../analyzers/dependencies.js";
5
+ import { analyzeStructure } from "../analyzers/structure.js";
6
+ import { detectFramework, detectStack } from "../analyzers/detection.js";
7
+ import { getConventions, getActiveCrossRefs, detectGaps, } from "../rules/index.js";
8
+ export function registerValidateClaudeMd(server) {
9
+ server.registerTool("validate-claude-md", {
10
+ title: "Validate CLAUDE.md",
11
+ description: "Checks if an existing CLAUDE.md is still in sync with the actual project. Detects drifts: missing conventions, outdated stack info, new gaps not covered.",
12
+ inputSchema: {
13
+ projectPath: z
14
+ .string()
15
+ .describe("Absolute path to the project root directory"),
16
+ },
17
+ }, async ({ projectPath }) => {
18
+ try {
19
+ const claudeMdPath = join(projectPath, "CLAUDE.md");
20
+ try {
21
+ await stat(claudeMdPath);
22
+ }
23
+ catch {
24
+ return {
25
+ isError: true,
26
+ content: [{ type: "text", text: `No CLAUDE.md found at ${claudeMdPath}. Use generate-claude-md first.` }],
27
+ };
28
+ }
29
+ const claudeMd = await readFile(claudeMdPath, "utf-8");
30
+ // Re-analyze the project
31
+ const pkg = await analyzeDependencies(projectPath);
32
+ const structure = await analyzeStructure(projectPath);
33
+ const framework = detectFramework(pkg.dependencies, pkg.devDependencies, structure);
34
+ const detected = detectStack(pkg.dependencies, pkg.devDependencies);
35
+ detected.runtime = structure.detectedRuntime;
36
+ const analysis = {
37
+ projectPath,
38
+ projectName: pkg.name,
39
+ framework,
40
+ dependencies: pkg.dependencies,
41
+ devDependencies: pkg.devDependencies,
42
+ scripts: pkg.scripts,
43
+ structure,
44
+ detected,
45
+ };
46
+ const drifts = [];
47
+ // Check framework version
48
+ if (framework) {
49
+ const versionInDoc = claudeMd.includes(framework.version);
50
+ if (!versionInDoc) {
51
+ drifts.push({
52
+ type: "outdated",
53
+ section: "Stack",
54
+ message: `Framework version ${framework.version} not found in CLAUDE.md. Version may have been updated.`,
55
+ });
56
+ }
57
+ }
58
+ // Check for new techs not mentioned
59
+ const techFields = [
60
+ ["ORM", detected.orm],
61
+ ["Auth", detected.auth],
62
+ ["Validation", detected.validation],
63
+ ["CSS", detected.css],
64
+ ["Testing", detected.testing],
65
+ ["i18n", detected.i18n],
66
+ ["Payments", detected.payments],
67
+ ["State Management", detected.stateManagement],
68
+ ["UI Components", detected.uiComponents],
69
+ ];
70
+ for (const [label, value] of techFields) {
71
+ if (value && !claudeMd.toLowerCase().includes(value.toLowerCase())) {
72
+ drifts.push({
73
+ type: "missing",
74
+ section: "Stack",
75
+ message: `${label}: ${value} is in the project but not mentioned in CLAUDE.md.`,
76
+ });
77
+ }
78
+ }
79
+ // Check for conventions not present
80
+ const conventions = getConventions(analysis);
81
+ for (const conv of conventions) {
82
+ if (!claudeMd.includes(conv.id) && !claudeMd.includes(conv.description)) {
83
+ drifts.push({
84
+ type: "missing",
85
+ section: "Conventions",
86
+ message: `Convention "${conv.description}" is applicable but not in CLAUDE.md.`,
87
+ });
88
+ }
89
+ }
90
+ // Check for cross-refs
91
+ const crossRefs = getActiveCrossRefs(analysis);
92
+ for (const cr of crossRefs) {
93
+ const combo = cr.techs.join(" + ");
94
+ if (!claudeMd.includes(combo)) {
95
+ drifts.push({
96
+ type: "missing",
97
+ section: "Cross-Stack Rules",
98
+ message: `Cross-stack rule for ${combo} is applicable but not in CLAUDE.md.`,
99
+ });
100
+ }
101
+ }
102
+ // Check for gaps
103
+ const gaps = detectGaps(analysis);
104
+ const highGaps = gaps.filter((g) => g.severity === "high");
105
+ for (const gap of highGaps) {
106
+ drifts.push({
107
+ type: "missing",
108
+ section: "Gaps",
109
+ message: `High-severity gap still exists: ${gap.message}`,
110
+ });
111
+ }
112
+ return {
113
+ content: [
114
+ {
115
+ type: "text",
116
+ text: JSON.stringify({
117
+ valid: drifts.length === 0,
118
+ drifts,
119
+ total: drifts.length,
120
+ summary: drifts.length === 0
121
+ ? "CLAUDE.md is in sync with the project."
122
+ : `Found ${drifts.length} drift(s). Consider running generate-claude-md to update.`,
123
+ }, null, 2),
124
+ },
125
+ ],
126
+ };
127
+ }
128
+ catch (err) {
129
+ const message = err instanceof Error ? err.message : String(err);
130
+ return {
131
+ isError: true,
132
+ content: [{ type: "text", text: `validate-claude-md failed: ${message}` }],
133
+ };
134
+ }
135
+ });
136
+ }
137
+ //# sourceMappingURL=validate-claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-claude-md.js","sourceRoot":"","sources":["../../src/tools/validate-claude-md.ts"],"names":[],"mappings":"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"}