@j0hanz/code-review-analyst-mcp 1.3.0 → 1.4.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/dist/lib/diff-cleaner.d.ts +12 -0
- package/dist/lib/diff-cleaner.js +51 -0
- package/dist/lib/diff-store.d.ts +22 -0
- package/dist/lib/diff-store.js +28 -0
- package/dist/lib/tool-contracts.d.ts +26 -49
- package/dist/lib/tool-contracts.js +41 -54
- package/dist/lib/tool-factory.d.ts +14 -3
- package/dist/lib/tool-factory.js +9 -3
- package/dist/resources/index.js +19 -0
- package/dist/resources/instructions.js +10 -0
- package/dist/resources/server-config.js +1 -0
- package/dist/schemas/inputs.d.ts +0 -7
- package/dist/schemas/inputs.js +20 -32
- package/dist/server.js +3 -1
- package/dist/tools/analyze-complexity.js +18 -13
- package/dist/tools/analyze-pr-impact.js +26 -20
- package/dist/tools/detect-api-breaking.js +18 -13
- package/dist/tools/generate-diff.d.ts +2 -0
- package/dist/tools/generate-diff.js +71 -0
- package/dist/tools/generate-review-summary.js +32 -34
- package/dist/tools/generate-test-plan.js +26 -23
- package/dist/tools/index.js +2 -0
- package/dist/tools/inspect-code-quality.js +33 -29
- package/dist/tools/suggest-search-replace.js +24 -18
- package/package.json +1 -2
- package/dist/instructions.md +0 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { validateContextBudget } from '../lib/context-budget.js';
|
|
2
2
|
import { validateDiffBudget } from '../lib/diff-budget.js';
|
|
3
3
|
import { computeDiffStatsAndSummaryFromFiles, parseDiffFiles, } from '../lib/diff-parser.js';
|
|
4
|
+
import { createNoDiffError } from '../lib/diff-store.js';
|
|
4
5
|
import { requireToolContract } from '../lib/tool-contracts.js';
|
|
5
6
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
6
7
|
import { InspectCodeQualityInputSchema } from '../schemas/inputs.js';
|
|
@@ -49,31 +50,11 @@ ${sanitizeContent(file.content)}
|
|
|
49
50
|
}
|
|
50
51
|
return `${FILE_CONTEXT_HEADING}${fileBlocks.join('\n')}`;
|
|
51
52
|
}
|
|
52
|
-
function buildInspectPrompt(input) {
|
|
53
|
-
const parsedFiles = parseDiffFiles(input.diff);
|
|
54
|
-
const { summary: fileSummary } = computeDiffStatsAndSummaryFromFiles(parsedFiles);
|
|
55
|
-
const fileContext = formatFileContext(input.files);
|
|
56
|
-
const languageLine = formatOptionalLine('Language', input.language);
|
|
57
|
-
const maxFindingsLine = formatOptionalLine('Max Findings', input.maxFindings);
|
|
58
|
-
const noFilesNote = !input.files?.length
|
|
59
|
-
? '\nNote: No file context provided. Leave contextualInsights empty.'
|
|
60
|
-
: '';
|
|
61
|
-
return `
|
|
62
|
-
Repository: ${input.repository}${languageLine}
|
|
63
|
-
Focus Areas: ${input.focusAreas?.join(', ') ?? DEFAULT_FOCUS_AREAS}${maxFindingsLine}${noFilesNote}
|
|
64
|
-
Changed Files:
|
|
65
|
-
${fileSummary}
|
|
66
|
-
|
|
67
|
-
Diff:
|
|
68
|
-
${input.diff}
|
|
69
|
-
${fileContext}
|
|
70
|
-
`;
|
|
71
|
-
}
|
|
72
53
|
export function registerInspectCodeQualityTool(server) {
|
|
73
54
|
registerStructuredToolTask(server, {
|
|
74
55
|
name: 'inspect_code_quality',
|
|
75
56
|
title: 'Inspect Code Quality',
|
|
76
|
-
description: 'Deep
|
|
57
|
+
description: 'Deep code review. Prerequisite: generate_diff. Auto-infer repo/language/focus. Provide file content for best results.',
|
|
77
58
|
inputSchema: InspectCodeQualityInputSchema,
|
|
78
59
|
fullInputSchema: InspectCodeQualityInputSchema,
|
|
79
60
|
resultSchema: CodeQualityOutputSchema,
|
|
@@ -89,13 +70,16 @@ export function registerInspectCodeQualityTool(server) {
|
|
|
89
70
|
const fileCount = input.files?.length;
|
|
90
71
|
return fileCount ? `+${fileCount} files` : '';
|
|
91
72
|
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
73
|
+
validateInput: (input, ctx) => {
|
|
74
|
+
const slot = ctx.diffSlot;
|
|
75
|
+
if (!slot)
|
|
76
|
+
return createNoDiffError();
|
|
77
|
+
const diffError = validateDiffBudget(slot.diff);
|
|
95
78
|
if (diffError)
|
|
96
79
|
return diffError;
|
|
97
|
-
return validateContextBudget(
|
|
80
|
+
return validateContextBudget(slot.diff, input.files);
|
|
98
81
|
},
|
|
82
|
+
formatOutcome: (result) => `${result.findings.length} findings, risk: ${result.overallRisk}`,
|
|
99
83
|
formatOutput: (result) => {
|
|
100
84
|
const count = result.findings.length;
|
|
101
85
|
const total = result.totalFindings ?? count;
|
|
@@ -109,9 +93,29 @@ export function registerInspectCodeQualityTool(server) {
|
|
|
109
93
|
const cappedFindings = capFindings(result.findings, input.maxFindings);
|
|
110
94
|
return { ...result, findings: cappedFindings, totalFindings };
|
|
111
95
|
},
|
|
112
|
-
buildPrompt: (input) =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
96
|
+
buildPrompt: (input, ctx) => {
|
|
97
|
+
const diff = ctx.diffSlot?.diff ?? '';
|
|
98
|
+
const parsedFiles = parseDiffFiles(diff);
|
|
99
|
+
const { summary: fileSummary } = computeDiffStatsAndSummaryFromFiles(parsedFiles);
|
|
100
|
+
const fileContext = formatFileContext(input.files);
|
|
101
|
+
const languageLine = formatOptionalLine('Language', input.language);
|
|
102
|
+
const maxFindingsLine = formatOptionalLine('Max Findings', input.maxFindings);
|
|
103
|
+
const noFilesNote = !input.files?.length
|
|
104
|
+
? '\nNote: No file context provided. Leave contextualInsights empty.'
|
|
105
|
+
: '';
|
|
106
|
+
return {
|
|
107
|
+
systemInstruction: SYSTEM_INSTRUCTION,
|
|
108
|
+
prompt: `
|
|
109
|
+
Repository: ${input.repository}${languageLine}
|
|
110
|
+
Focus Areas: ${input.focusAreas?.join(', ') ?? DEFAULT_FOCUS_AREAS}${maxFindingsLine}${noFilesNote}
|
|
111
|
+
Changed Files:
|
|
112
|
+
${fileSummary}
|
|
113
|
+
|
|
114
|
+
Diff:
|
|
115
|
+
${diff}
|
|
116
|
+
${fileContext}
|
|
117
|
+
`,
|
|
118
|
+
};
|
|
119
|
+
},
|
|
116
120
|
});
|
|
117
121
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { validateDiffBudget } from '../lib/diff-budget.js';
|
|
2
2
|
import { extractChangedPathsFromFiles, parseDiffFiles, } from '../lib/diff-parser.js';
|
|
3
|
+
import { createNoDiffError } from '../lib/diff-store.js';
|
|
3
4
|
import { requireToolContract } from '../lib/tool-contracts.js';
|
|
4
5
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
5
6
|
import { SuggestSearchReplaceInputSchema } from '../schemas/inputs.js';
|
|
@@ -14,23 +15,11 @@ const TOOL_CONTRACT = requireToolContract('suggest_search_replace');
|
|
|
14
15
|
function formatPatchCount(count) {
|
|
15
16
|
return `${count} ${count === 1 ? 'patch' : 'patches'}`;
|
|
16
17
|
}
|
|
17
|
-
function buildSuggestSearchReplacePrompt(input) {
|
|
18
|
-
const files = parseDiffFiles(input.diff);
|
|
19
|
-
const paths = extractChangedPathsFromFiles(files);
|
|
20
|
-
return `
|
|
21
|
-
Finding: ${input.findingTitle}
|
|
22
|
-
Details: ${input.findingDetails}
|
|
23
|
-
Changed Files: ${paths.join(', ')}
|
|
24
|
-
|
|
25
|
-
Diff:
|
|
26
|
-
${input.diff}
|
|
27
|
-
`;
|
|
28
|
-
}
|
|
29
18
|
export function registerSuggestSearchReplaceTool(server) {
|
|
30
19
|
registerStructuredToolTask(server, {
|
|
31
20
|
name: 'suggest_search_replace',
|
|
32
21
|
title: 'Suggest Search & Replace',
|
|
33
|
-
description: 'Generate
|
|
22
|
+
description: 'Generate fix patches. Prerequisite: inspect_code_quality findings. Pass verbatim finding title/details.',
|
|
34
23
|
inputSchema: SuggestSearchReplaceInputSchema,
|
|
35
24
|
fullInputSchema: SuggestSearchReplaceInputSchema,
|
|
36
25
|
resultSchema: SearchReplaceResultSchema,
|
|
@@ -41,16 +30,33 @@ export function registerSuggestSearchReplaceTool(server) {
|
|
|
41
30
|
...(TOOL_CONTRACT.thinkingBudget !== undefined
|
|
42
31
|
? { thinkingBudget: TOOL_CONTRACT.thinkingBudget }
|
|
43
32
|
: undefined),
|
|
44
|
-
validateInput: (
|
|
33
|
+
validateInput: (_input, ctx) => {
|
|
34
|
+
const slot = ctx.diffSlot;
|
|
35
|
+
if (!slot)
|
|
36
|
+
return createNoDiffError();
|
|
37
|
+
return validateDiffBudget(slot.diff);
|
|
38
|
+
},
|
|
45
39
|
formatOutcome: (result) => formatPatchCount(result.blocks.length),
|
|
46
40
|
formatOutput: (result) => {
|
|
47
41
|
const count = result.blocks.length;
|
|
48
42
|
const patches = formatPatchCount(count);
|
|
49
43
|
return `${result.summary}\n${patches} • Checklist: ${result.validationChecklist.join(' | ')}`;
|
|
50
44
|
},
|
|
51
|
-
buildPrompt: (input) =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
buildPrompt: (input, ctx) => {
|
|
46
|
+
const diff = ctx.diffSlot?.diff ?? '';
|
|
47
|
+
const files = parseDiffFiles(diff);
|
|
48
|
+
const paths = extractChangedPathsFromFiles(files);
|
|
49
|
+
return {
|
|
50
|
+
systemInstruction: SYSTEM_INSTRUCTION,
|
|
51
|
+
prompt: `
|
|
52
|
+
Finding: ${input.findingTitle}
|
|
53
|
+
Details: ${input.findingDetails}
|
|
54
|
+
Changed Files: ${paths.join(', ')}
|
|
55
|
+
|
|
56
|
+
Diff:
|
|
57
|
+
${diff}
|
|
58
|
+
`,
|
|
59
|
+
};
|
|
60
|
+
},
|
|
55
61
|
});
|
|
56
62
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@j0hanz/code-review-analyst-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"mcpName": "io.github.j0hanz/code-review-analyst",
|
|
5
5
|
"description": "Gemini-powered MCP server for code review analysis.",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"clean": "node scripts/tasks.mjs clean",
|
|
35
|
-
"validate:instructions": "node scripts/tasks.mjs validate:instructions",
|
|
36
35
|
"build": "node scripts/tasks.mjs build",
|
|
37
36
|
"copy:assets": "node scripts/tasks.mjs copy:assets",
|
|
38
37
|
"prepare": "npm run build",
|
package/dist/instructions.md
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# CODE REVIEW ANALYST MCP INSTRUCTIONS
|
|
2
|
-
|
|
3
|
-
Runtime instructions are generated from `src/lib/tool-contracts.ts` by
|
|
4
|
-
`buildServerInstructions()` in `src/resources/instructions.ts`.
|
|
5
|
-
|
|
6
|
-
This file is kept as a packaging placeholder for build pipelines that expect an
|
|
7
|
-
`instructions.md` artifact in `dist/`.
|