@j0hanz/code-review-analyst-mcp 1.4.2 → 1.4.3
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/gemini.js +7 -1
- package/dist/lib/model-config.d.ts +1 -1
- package/dist/lib/model-config.js +1 -1
- package/dist/lib/tool-contracts.d.ts +4 -3
- package/dist/lib/tool-contracts.js +10 -1
- package/dist/prompts/index.d.ts +9 -0
- package/dist/prompts/index.js +25 -22
- package/dist/resources/index.d.ts +10 -0
- package/dist/resources/index.js +3 -2
- package/dist/resources/instructions.js +5 -9
- package/dist/schemas/inputs.js +1 -1
- package/package.json +1 -1
package/dist/lib/gemini.js
CHANGED
|
@@ -4,7 +4,7 @@ import { EventEmitter } from 'node:events';
|
|
|
4
4
|
import { performance } from 'node:perf_hooks';
|
|
5
5
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
6
6
|
import { debuglog } from 'node:util';
|
|
7
|
-
import { GoogleGenAI, HarmBlockThreshold, HarmCategory } from '@google/genai';
|
|
7
|
+
import { FinishReason, GoogleGenAI, HarmBlockThreshold, HarmCategory, } from '@google/genai';
|
|
8
8
|
import { createCachedEnvInt } from './env-config.js';
|
|
9
9
|
import { getErrorMessage, RETRYABLE_UPSTREAM_ERROR_PATTERN } from './errors.js';
|
|
10
10
|
// Lazy-cached: first call happens after parseCommandLineArgs() sets GEMINI_MODEL.
|
|
@@ -370,14 +370,20 @@ async function executeAttempt(request, model, timeoutMs, attempt, onLog) {
|
|
|
370
370
|
const startedAt = performance.now();
|
|
371
371
|
const response = await generateContentWithTimeout(request, model, timeoutMs);
|
|
372
372
|
const latencyMs = Math.round(performance.now() - startedAt);
|
|
373
|
+
const finishReason = response.candidates?.[0]?.finishReason;
|
|
373
374
|
await emitGeminiLog(onLog, 'info', {
|
|
374
375
|
event: 'gemini_call',
|
|
375
376
|
details: {
|
|
376
377
|
attempt,
|
|
377
378
|
latencyMs,
|
|
379
|
+
finishReason: finishReason ?? null,
|
|
378
380
|
usageMetadata: response.usageMetadata ?? null,
|
|
379
381
|
},
|
|
380
382
|
});
|
|
383
|
+
if (finishReason === FinishReason.MAX_TOKENS) {
|
|
384
|
+
const limit = request.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
|
|
385
|
+
throw new Error(`Response truncated: model output exceeds limit (maxOutputTokens=${formatNumber(limit)}). Increase maxOutputTokens or reduce prompt complexity.`);
|
|
386
|
+
}
|
|
381
387
|
return parseStructuredResponse(response.text);
|
|
382
388
|
}
|
|
383
389
|
async function waitBeforeRetry(attempt, error, onLog, requestSignal) {
|
|
@@ -7,7 +7,7 @@ export declare const FLASH_THINKING_BUDGET: 8192;
|
|
|
7
7
|
/** Thinking budget (tokens) for Pro model deep-analysis tasks (code quality inspection). */
|
|
8
8
|
export declare const PRO_THINKING_BUDGET: 16384;
|
|
9
9
|
/** Output cap for Flash triage tools (impact, summary). */
|
|
10
|
-
export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS:
|
|
10
|
+
export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS: 4096;
|
|
11
11
|
/** Output cap for API breaking-change detection (migration guidance needs room). */
|
|
12
12
|
export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS: 4096;
|
|
13
13
|
/** Output cap for test-plan generation (includes pseudocode snippets). */
|
package/dist/lib/model-config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const INSPECTION_FOCUS_AREAS: readonly ["security", "correctness", "performance", "regressions", "tests", "maintainability", "concurrency"];
|
|
1
2
|
export interface ToolParameterContract {
|
|
2
3
|
name: string;
|
|
3
4
|
type: string;
|
|
@@ -42,7 +43,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
42
43
|
readonly purpose: "Assess severity, categories, breaking changes, and rollback complexity.";
|
|
43
44
|
readonly model: "gemini-2.5-flash";
|
|
44
45
|
readonly timeoutMs: 90000;
|
|
45
|
-
readonly maxOutputTokens:
|
|
46
|
+
readonly maxOutputTokens: 4096;
|
|
46
47
|
readonly params: readonly [{
|
|
47
48
|
readonly name: "repository";
|
|
48
49
|
readonly type: "string";
|
|
@@ -64,7 +65,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
64
65
|
readonly purpose: "Produce PR summary, risk rating, and merge recommendation.";
|
|
65
66
|
readonly model: "gemini-2.5-flash";
|
|
66
67
|
readonly timeoutMs: 90000;
|
|
67
|
-
readonly maxOutputTokens:
|
|
68
|
+
readonly maxOutputTokens: 4096;
|
|
68
69
|
readonly params: readonly [{
|
|
69
70
|
readonly name: "repository";
|
|
70
71
|
readonly type: "string";
|
|
@@ -105,7 +106,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
105
106
|
readonly type: "string[]";
|
|
106
107
|
readonly required: false;
|
|
107
108
|
readonly constraints: "1-12 items, 2-80 chars each";
|
|
108
|
-
readonly description:
|
|
109
|
+
readonly description: `Focused inspection categories (e.g. ${string}).`;
|
|
109
110
|
}, {
|
|
110
111
|
readonly name: "maxFindings";
|
|
111
112
|
readonly type: "number";
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { DEFAULT_TIMEOUT_PRO_MS, FLASH_API_BREAKING_MAX_OUTPUT_TOKENS, FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS, FLASH_MODEL, FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS, FLASH_THINKING_BUDGET, FLASH_TRIAGE_MAX_OUTPUT_TOKENS, PRO_MODEL, PRO_PATCH_MAX_OUTPUT_TOKENS, PRO_REVIEW_MAX_OUTPUT_TOKENS, PRO_THINKING_BUDGET, } from './model-config.js';
|
|
2
2
|
const DEFAULT_TIMEOUT_FLASH_MS = 90_000;
|
|
3
|
+
export const INSPECTION_FOCUS_AREAS = [
|
|
4
|
+
'security',
|
|
5
|
+
'correctness',
|
|
6
|
+
'performance',
|
|
7
|
+
'regressions',
|
|
8
|
+
'tests',
|
|
9
|
+
'maintainability',
|
|
10
|
+
'concurrency',
|
|
11
|
+
];
|
|
3
12
|
export const TOOL_CONTRACTS = [
|
|
4
13
|
{
|
|
5
14
|
name: 'generate_diff',
|
|
@@ -115,7 +124,7 @@ export const TOOL_CONTRACTS = [
|
|
|
115
124
|
type: 'string[]',
|
|
116
125
|
required: false,
|
|
117
126
|
constraints: '1-12 items, 2-80 chars each',
|
|
118
|
-
description:
|
|
127
|
+
description: `Focused inspection categories (e.g. ${INSPECTION_FOCUS_AREAS.join(', ')}).`,
|
|
119
128
|
},
|
|
120
129
|
{
|
|
121
130
|
name: 'maxFindings',
|
package/dist/prompts/index.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export declare const PROMPT_DEFINITIONS: readonly [{
|
|
3
|
+
readonly name: "get-help";
|
|
4
|
+
readonly title: "Get Help";
|
|
5
|
+
readonly description: "Server instructions.";
|
|
6
|
+
}, {
|
|
7
|
+
readonly name: "review-guide";
|
|
8
|
+
readonly title: "Review Guide";
|
|
9
|
+
readonly description: "Workflow guide for tool/focus area.";
|
|
10
|
+
}];
|
|
2
11
|
export declare function registerAllPrompts(server: McpServer, instructions: string): void;
|
package/dist/prompts/index.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { completable } from '@modelcontextprotocol/sdk/server/completable.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getToolContract, getToolContractNames, } from '../lib/tool-contracts.js';
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'regressions',
|
|
16
|
-
'tests',
|
|
3
|
+
import { getToolContract, getToolContractNames, INSPECTION_FOCUS_AREAS, } from '../lib/tool-contracts.js';
|
|
4
|
+
export const PROMPT_DEFINITIONS = [
|
|
5
|
+
{
|
|
6
|
+
name: 'get-help',
|
|
7
|
+
title: 'Get Help',
|
|
8
|
+
description: 'Server instructions.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'review-guide',
|
|
12
|
+
title: 'Review Guide',
|
|
13
|
+
description: 'Workflow guide for tool/focus area.',
|
|
14
|
+
},
|
|
17
15
|
];
|
|
16
|
+
const TOOLS = getToolContractNames();
|
|
18
17
|
const TOOL_DESCRIPTION_TEXT = 'Select tool for review guide.';
|
|
19
18
|
const FOCUS_DESCRIPTION_TEXT = 'Select focus area.';
|
|
20
19
|
const FOCUS_AREA_GUIDES = {
|
|
@@ -23,6 +22,8 @@ const FOCUS_AREA_GUIDES = {
|
|
|
23
22
|
performance: 'Focus: Complexity, allocations, I/O, queries.',
|
|
24
23
|
regressions: 'Focus: Behavior changes, guards, types, breaks.',
|
|
25
24
|
tests: 'Focus: Coverage, edge cases, flakes, error paths.',
|
|
25
|
+
maintainability: 'Focus: Complexity, readability, structure, patterns.',
|
|
26
|
+
concurrency: 'Focus: Race conditions, deadlocks, shared state.',
|
|
26
27
|
};
|
|
27
28
|
function completeByPrefix(values, prefix) {
|
|
28
29
|
const matches = [];
|
|
@@ -52,11 +53,12 @@ function getFocusAreaGuide(focusArea) {
|
|
|
52
53
|
return getGuide(FOCUS_AREA_GUIDES, focusArea, (area) => `Focus on ${area} concerns.`);
|
|
53
54
|
}
|
|
54
55
|
function registerHelpPrompt(server, instructions) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
const def = PROMPT_DEFINITIONS[0];
|
|
57
|
+
server.registerPrompt(def.name, {
|
|
58
|
+
title: def.title,
|
|
59
|
+
description: def.description,
|
|
58
60
|
}, () => ({
|
|
59
|
-
description:
|
|
61
|
+
description: def.description,
|
|
60
62
|
messages: [
|
|
61
63
|
{
|
|
62
64
|
role: 'user',
|
|
@@ -85,12 +87,13 @@ function buildReviewGuideText(tool, focusArea) {
|
|
|
85
87
|
`> Tip: Run \`get-help\` for full server documentation.`);
|
|
86
88
|
}
|
|
87
89
|
function registerReviewGuidePrompt(server) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
const def = PROMPT_DEFINITIONS[1];
|
|
91
|
+
server.registerPrompt(def.name, {
|
|
92
|
+
title: def.title,
|
|
93
|
+
description: def.description,
|
|
91
94
|
argsSchema: {
|
|
92
95
|
tool: completable(z.string().describe(TOOL_DESCRIPTION_TEXT), (value) => completeByPrefix(TOOLS, value)),
|
|
93
|
-
focusArea: completable(z.string().describe(FOCUS_DESCRIPTION_TEXT), (value) => completeByPrefix(
|
|
96
|
+
focusArea: completable(z.string().describe(FOCUS_DESCRIPTION_TEXT), (value) => completeByPrefix(INSPECTION_FOCUS_AREAS, value)),
|
|
94
97
|
},
|
|
95
98
|
}, ({ tool, focusArea }) => ({
|
|
96
99
|
description: `Code review guide: ${tool} / ${focusArea}`,
|
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export interface StaticResourceDef {
|
|
3
|
+
id: string;
|
|
4
|
+
uri: string;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
priority: number;
|
|
8
|
+
content: () => string;
|
|
9
|
+
}
|
|
10
|
+
export declare const STATIC_RESOURCES: readonly StaticResourceDef[];
|
|
11
|
+
export declare const DIFF_RESOURCE_DESCRIPTION = "The most recently generated diff, cached by generate_diff. Read by all review tools automatically.";
|
|
2
12
|
export declare function registerAllResources(server: McpServer, instructions: string): void;
|
package/dist/resources/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const RESOURCE_AUDIENCE = ['assistant'];
|
|
|
9
9
|
function createMarkdownContent(uri, text) {
|
|
10
10
|
return { uri: uri.href, mimeType: RESOURCE_MIME_TYPE, text };
|
|
11
11
|
}
|
|
12
|
-
const STATIC_RESOURCES = [
|
|
12
|
+
export const STATIC_RESOURCES = [
|
|
13
13
|
{
|
|
14
14
|
id: 'server-instructions',
|
|
15
15
|
uri: 'internal://instructions',
|
|
@@ -77,10 +77,11 @@ function registerToolInfoResources(server) {
|
|
|
77
77
|
return { contents: [createMarkdownContent(uri, text)] };
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
+
export const DIFF_RESOURCE_DESCRIPTION = 'The most recently generated diff, cached by generate_diff. Read by all review tools automatically.';
|
|
80
81
|
function registerDiffResource(server) {
|
|
81
82
|
server.registerResource('diff-current', new ResourceTemplate(DIFF_RESOURCE_URI, { list: undefined }), {
|
|
82
83
|
title: 'Current Diff',
|
|
83
|
-
description:
|
|
84
|
+
description: DIFF_RESOURCE_DESCRIPTION,
|
|
84
85
|
mimeType: 'text/x-patch',
|
|
85
86
|
annotations: {
|
|
86
87
|
audience: ['assistant'],
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { getToolContracts } from '../lib/tool-contracts.js';
|
|
2
|
+
import { PROMPT_DEFINITIONS } from '../prompts/index.js';
|
|
3
|
+
import { DIFF_RESOURCE_DESCRIPTION, STATIC_RESOURCES } from './index.js';
|
|
2
4
|
import { getSharedConstraints } from './tool-info.js';
|
|
3
|
-
const PROMPT_LIST =
|
|
4
|
-
'- `get-help`: Returns these server instructions.',
|
|
5
|
-
'- `review-guide`: Workflow guide for a selected tool and focus area.',
|
|
6
|
-
];
|
|
5
|
+
const PROMPT_LIST = PROMPT_DEFINITIONS.map((def) => `- \`${def.name}\`: ${def.description}`);
|
|
7
6
|
const RESOURCE_LIST = [
|
|
8
|
-
|
|
9
|
-
'- `internal://tool-catalog`: Tool matrix and cross-tool data flow.',
|
|
10
|
-
'- `internal://workflows`: Recommended multi-step tool workflows.',
|
|
11
|
-
'- `internal://server-config`: Runtime limits and model configuration.',
|
|
7
|
+
...STATIC_RESOURCES.map((def) => `- \`${def.uri}\`: ${def.description}`),
|
|
12
8
|
'- `internal://tool-info/{toolName}`: Per-tool contract details.',
|
|
13
|
-
|
|
9
|
+
`- \`diff://current\`: ${DIFF_RESOURCE_DESCRIPTION}`,
|
|
14
10
|
];
|
|
15
11
|
function formatParameterLine(parameter) {
|
|
16
12
|
const required = parameter.required ? 'required' : 'optional';
|
package/dist/schemas/inputs.js
CHANGED
|
@@ -51,7 +51,7 @@ export const InspectCodeQualityInputSchema = z.strictObject({
|
|
|
51
51
|
.min(1)
|
|
52
52
|
.max(INPUT_LIMITS.focusArea.maxItems)
|
|
53
53
|
.optional()
|
|
54
|
-
.describe('Review focus areas. Standard tags: security, performance,
|
|
54
|
+
.describe('Review focus areas. Standard tags: security, correctness, performance, regressions, tests, maintainability, concurrency. Omit for general review.'),
|
|
55
55
|
maxFindings: createOptionalBoundedInteger(INPUT_LIMITS.maxFindings.min, INPUT_LIMITS.maxFindings.max, 'Max findings (1-25). Default: 10.'),
|
|
56
56
|
files: z
|
|
57
57
|
.array(FileContextSchema)
|