@j0hanz/code-review-analyst-mcp 1.7.1 → 1.7.2

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.
@@ -123,6 +123,7 @@ export declare class ToolExecutionRunner<TInput extends object, TResult extends
123
123
  reportProgress: (payload: ProgressPayload) => Promise<void>;
124
124
  statusReporter: TaskStatusReporter;
125
125
  }, signal?: AbortSignal | undefined);
126
+ private handleInternalLog;
126
127
  setResponseSchemaOverride(responseSchema: Record<string, unknown>): void;
127
128
  setDiffSlotSnapshot(diffSlotSnapshot: DiffSlot | undefined): void;
128
129
  private updateStatusMessage;
@@ -241,7 +241,7 @@ function normalizeProgressContext(context) {
241
241
  return `${compact.slice(0, 77)}...`;
242
242
  }
243
243
  function formatProgressStep(toolName, context, metadata) {
244
- return `${toolName}: ${context} [${metadata}]`;
244
+ return `${toolName}: ${context} • ${metadata}`;
245
245
  }
246
246
  function formatProgressCompletion(toolName, context, outcome) {
247
247
  return `šŸ—’ ${toolName}: ${context} • ${outcome}`;
@@ -276,7 +276,7 @@ async function reportProgressCompletionUpdate(reportProgress, toolName, context,
276
276
  }
277
277
  async function reportSchemaRetryProgressBestEffort(reportProgress, toolName, context, retryCount, maxRetries) {
278
278
  try {
279
- await reportProgressStepUpdate(reportProgress, toolName, context, STEP_VALIDATING_RESPONSE, `schema repair ${retryCount}/${maxRetries}`);
279
+ await reportProgressStepUpdate(reportProgress, toolName, context, STEP_VALIDATING_RESPONSE, `Schema repair in progress (attempt ${retryCount}/${maxRetries})...`);
280
280
  }
281
281
  catch {
282
282
  // Progress updates are best-effort and must not interrupt retries.
@@ -370,10 +370,28 @@ export class ToolExecutionRunner {
370
370
  this.config = config;
371
371
  this.signal = signal;
372
372
  this.responseSchema = getCachedGeminiResponseSchema(config);
373
- this.onLog = dependencies.onLog;
374
373
  this.reportProgress = dependencies.reportProgress;
375
374
  this.statusReporter = dependencies.statusReporter;
376
375
  this.progressContext = DEFAULT_PROGRESS_CONTEXT;
376
+ this.onLog = async (level, data) => {
377
+ try {
378
+ await dependencies.onLog(level, data);
379
+ }
380
+ catch {
381
+ // Ignore logging failures
382
+ }
383
+ await this.handleInternalLog(data);
384
+ };
385
+ }
386
+ async handleInternalLog(data) {
387
+ const record = asObjectRecord(data);
388
+ if (record.event === 'gemini_retry') {
389
+ const details = asObjectRecord(record.details);
390
+ const { attempt } = details;
391
+ const msg = `Network error. Retrying (attempt ${String(attempt)})...`;
392
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, msg);
393
+ await this.updateStatusMessage(msg);
394
+ }
377
395
  }
378
396
  setResponseSchemaOverride(responseSchema) {
379
397
  this.responseSchema = responseSchema;
@@ -440,8 +458,8 @@ export class ToolExecutionRunner {
440
458
  try {
441
459
  const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.signal));
442
460
  if (attempt === 0) {
443
- await this.updateStatusMessage('validating response');
444
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'validating response');
461
+ await this.updateStatusMessage('Verifying output structure...');
462
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'Verifying output structure...');
445
463
  }
446
464
  parsed = this.config.resultSchema.parse(raw);
447
465
  break;
@@ -476,23 +494,23 @@ export class ToolExecutionRunner {
476
494
  const ctx = {
477
495
  diffSlot: this.hasSnapshot ? this.diffSlotSnapshot : getDiff(),
478
496
  };
479
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_STARTING, 'starting');
480
- await this.updateStatusMessage('starting');
481
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'validating input');
482
- await this.updateStatusMessage('validating input');
497
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_STARTING, 'Initializing...');
498
+ await this.updateStatusMessage('Initializing...');
499
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'Validating request parameters...');
500
+ await this.updateStatusMessage('Validating request parameters...');
483
501
  const validationError = await this.executeValidation(inputRecord, ctx);
484
502
  if (validationError) {
485
503
  return validationError;
486
504
  }
487
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, 'building prompt');
488
- await this.updateStatusMessage('building prompt');
505
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, 'Constructing analysis context...');
506
+ await this.updateStatusMessage('Constructing analysis context...');
489
507
  const promptParts = this.config.buildPrompt(inputRecord, ctx);
490
508
  const { prompt, systemInstruction } = promptParts;
491
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, 'calling model');
492
- await this.updateStatusMessage('calling model');
509
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, 'Querying Gemini model...');
510
+ await this.updateStatusMessage('Querying Gemini model...');
493
511
  const parsed = await this.executeModelCall(systemInstruction, prompt);
494
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, 'finalizing');
495
- await this.updateStatusMessage('finalizing');
512
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, 'Processing results...');
513
+ await this.updateStatusMessage('Processing results...');
496
514
  const finalResult = (this.config.transformResult
497
515
  ? this.config.transformResult(inputRecord, parsed, ctx)
498
516
  : parsed);
@@ -503,7 +521,7 @@ export class ToolExecutionRunner {
503
521
  const ageMs = Date.now() - new Date(ctx.diffSlot.generatedAt).getTime();
504
522
  if (ageMs > diffStaleWarningMs.get()) {
505
523
  const ageMinutes = Math.round(ageMs / 60_000);
506
- const warning = `\n\nāš ļø Warning: The analyzed diff is over ${ageMinutes} minutes old. If you have made recent changes, please run generate_diff again.`;
524
+ const warning = `\n\nWarning: The analyzed diff is over ${ageMinutes} minutes old. If you have made recent changes, please run generate_diff again.`;
507
525
  textContent = textContent ? textContent + warning : warning;
508
526
  }
509
527
  }
@@ -17,13 +17,13 @@ const TOOLS = getToolContractNames();
17
17
  const TOOL_DESCRIPTION_TEXT = 'Select tool for review guide.';
18
18
  const FOCUS_DESCRIPTION_TEXT = 'Select focus area.';
19
19
  const FOCUS_AREA_GUIDES = {
20
- security: 'Focus: Injection (SQL/XSS), auth, crypto, OWASP Top 10.',
21
- correctness: 'Focus: Logic errors, edge cases, algorithm validity, type safety.',
22
- performance: 'Focus: Big-O complexity, memory allocations, I/O latency, N+1 queries.',
23
- regressions: 'Focus: Behavior changes, missing guards, breaking API changes.',
24
- tests: 'Focus: Missing coverage, flaky tests, error paths.',
25
- maintainability: 'Focus: Code complexity, readability, DRY violations, patterns.',
26
- concurrency: 'Focus: Race conditions, deadlocks, lack of atomicity.',
20
+ security: 'Focus: Injection, Auth, Crypto, OWASP.',
21
+ correctness: 'Focus: Logic, Edge Cases, Types.',
22
+ performance: 'Focus: Complexity, Memory, Latency.',
23
+ regressions: 'Focus: Behavior Changes, Breaking APIs.',
24
+ tests: 'Focus: Coverage, Error Paths.',
25
+ maintainability: 'Focus: Complexity, Readability, Patterns.',
26
+ concurrency: 'Focus: Races, Deadlocks, Atomicity.',
27
27
  };
28
28
  function isFocusArea(value) {
29
29
  return INSPECTION_FOCUS_AREAS.includes(value);
@@ -3,11 +3,23 @@ import { registerStructuredToolTask } from '../lib/tool-factory.js';
3
3
  import { AnalyzeComplexityInputSchema } from '../schemas/inputs.js';
4
4
  import { AnalyzeComplexityResultSchema } from '../schemas/outputs.js';
5
5
  const SYSTEM_INSTRUCTION = `
6
+ <role>
6
7
  Algorithm Complexity Analyst.
7
- Analyze Big-O time/space complexity for changes.
8
- Detect performance degradation vs original.
9
- Identify bottlenecks: nested loops, unbounded recursion, heavy allocations.
10
- Return strict JSON.
8
+ You are an expert in Big-O analysis and performance optimization.
9
+ </role>
10
+
11
+ <task>
12
+ Analyze the time and space complexity of the code changes:
13
+ - Compare new complexity vs. original implementation.
14
+ - Detect performance degradation (regression).
15
+ - Identify bottlenecks (nested loops, recursion, allocations).
16
+ </task>
17
+
18
+ <constraints>
19
+ - Focus on the changed code paths.
20
+ - Flag degradation only if complexity class worsens (e.g., O(n) -> O(n^2)).
21
+ - Return valid JSON matching the schema.
22
+ </constraints>
11
23
  `;
12
24
  const TOOL_CONTRACT = requireToolContract('analyze_time_space_complexity');
13
25
  export function registerAnalyzeComplexityTool(server) {
@@ -23,6 +35,7 @@ export function registerAnalyzeComplexityTool(server) {
23
35
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
24
36
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
25
37
  requiresDiff: true,
38
+ progressContext: (input) => input.language ?? 'auto-detect',
26
39
  formatOutcome: (result) => result.isDegradation
27
40
  ? 'Performance degradation detected'
28
41
  : 'No degradation',
@@ -4,10 +4,24 @@ import { registerStructuredToolTask } from '../lib/tool-factory.js';
4
4
  import { AnalyzePrImpactInputSchema } from '../schemas/inputs.js';
5
5
  import { PrImpactResultSchema } from '../schemas/outputs.js';
6
6
  const SYSTEM_INSTRUCTION = `
7
+ <role>
7
8
  Technical Change Analyst.
8
- Assess objective impact: severity, risk categories, breaking changes, rollback cost.
9
- Strictly diff-based; no inference.
10
- Return strict JSON.
9
+ You are a strict, objective auditor of code changes.
10
+ </role>
11
+
12
+ <task>
13
+ Analyze the unified diff to assess:
14
+ - Severity (low/medium/high/critical)
15
+ - Risk categories (security, stability, etc.)
16
+ - Breaking changes (API, contract, schema)
17
+ - Rollback complexity
18
+ </task>
19
+
20
+ <constraints>
21
+ - Base analysis ONLY on the provided diff. No external inference.
22
+ - Ignore formatting/style changes unless they affect logic.
23
+ - Return valid JSON matching the schema.
24
+ </constraints>
11
25
  `;
12
26
  const TOOL_CONTRACT = requireToolContract('analyze_pr_impact');
13
27
  function formatLanguageSegment(language) {
@@ -3,11 +3,22 @@ import { registerStructuredToolTask } from '../lib/tool-factory.js';
3
3
  import { DetectApiBreakingInputSchema } from '../schemas/inputs.js';
4
4
  import { DetectApiBreakingResultSchema } from '../schemas/outputs.js';
5
5
  const SYSTEM_INSTRUCTION = `
6
+ <role>
6
7
  API Compatibility Analyst.
7
- Detect breaking changes to public APIs/contracts/interfaces.
8
- Definition: Breaking change = requires consumer code modification.
9
- Output: element, nature, impact, mitigation.
10
- Return strict JSON.
8
+ You are a strict guardian of public interfaces and contracts.
9
+ </role>
10
+
11
+ <task>
12
+ Detect breaking changes in public APIs, interfaces, or schemas:
13
+ - Identify changes that require consumer code modification.
14
+ - classify the nature, impact, and mitigation for each break.
15
+ </task>
16
+
17
+ <constraints>
18
+ - Definition: Breaking change = backwards-incompatible modification.
19
+ - Ignore internal/private APIs unless exported.
20
+ - Return valid JSON matching the schema.
21
+ </constraints>
11
22
  `;
12
23
  const TOOL_CONTRACT = requireToolContract('detect_api_breaking_changes');
13
24
  export function registerDetectApiBreakingTool(server) {
@@ -23,6 +34,7 @@ export function registerDetectApiBreakingTool(server) {
23
34
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
24
35
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
25
36
  requiresDiff: true,
37
+ progressContext: (input) => input.language ?? 'auto-detect',
26
38
  formatOutcome: (result) => `${result.breakingChanges.length} breaking change(s) found`,
27
39
  formatOutput: (result) => result.hasBreakingChanges
28
40
  ? `${result.breakingChanges.length} breaking changes found.`
@@ -7,10 +7,23 @@ const ReviewSummaryModelSchema = ReviewSummaryResultSchema.omit({
7
7
  });
8
8
  const TOOL_CONTRACT = requireToolContract('generate_review_summary');
9
9
  const SYSTEM_INSTRUCTION = `
10
+ <role>
10
11
  Senior Code Reviewer.
11
- Summarize PR: risk, key changes, merge recommendation (merge/squash/block).
12
- Focus: Logic/behavior changes. Ignore: formatting/style/typos.
13
- Return strict JSON.
12
+ You are a pragmatic engineer focused on stability and maintainability.
13
+ </role>
14
+
15
+ <task>
16
+ Summarize the pull request based on the diff:
17
+ - Assess overall risk (low/medium/high).
18
+ - Highlight key logic/behavior changes.
19
+ - Recommend action: merge, squash, or block.
20
+ </task>
21
+
22
+ <constraints>
23
+ - Focus on logic and behavior; ignore style, formatting, and typos.
24
+ - Be concise and actionable.
25
+ - Return valid JSON matching the schema.
26
+ </constraints>
14
27
  `;
15
28
  function formatLanguageSegment(language) {
16
29
  return language ? `\nLanguage: ${language}` : '';
@@ -4,11 +4,22 @@ import { registerStructuredToolTask } from '../lib/tool-factory.js';
4
4
  import { GenerateTestPlanInputSchema } from '../schemas/inputs.js';
5
5
  import { TestPlanResultSchema } from '../schemas/outputs.js';
6
6
  const SYSTEM_INSTRUCTION = `
7
+ <role>
7
8
  QA Automation Architect.
8
- Generate test plan for diff.
9
- Prioritize: negative cases, edge cases, branch coverage, integration points.
10
- Focus: observable behavior only.
11
- Return strict JSON.
9
+ You are an expert in test strategy and coverage analysis.
10
+ </role>
11
+
12
+ <task>
13
+ Generate a prioritized test plan for the provided diff:
14
+ - Focus on negative cases, edge cases, and boundary conditions.
15
+ - Target branch coverage and integration points.
16
+ </task>
17
+
18
+ <constraints>
19
+ - Focus on observable behavior changes.
20
+ - Ignore internal refactors that do not affect contract.
21
+ - Return valid JSON matching the schema.
22
+ </constraints>
12
23
  `;
13
24
  const TOOL_CONTRACT = requireToolContract('generate_test_plan');
14
25
  function formatOptionalLine(label, value) {
@@ -5,11 +5,24 @@ import { InspectCodeQualityInputSchema } from '../schemas/inputs.js';
5
5
  import { CodeQualityOutputSchema, CodeQualityResultSchema, } from '../schemas/outputs.js';
6
6
  const DEFAULT_FOCUS_AREAS = 'General';
7
7
  const SYSTEM_INSTRUCTION = `
8
- Principal Engineer Code Review.
9
- Source: Unified diff.
10
- Goal: Identify bugs, security, performance, maintainability.
11
- Constraint: Ignore style/formatting. Prioritize correctness/failure modes.
12
- Return strict JSON.
8
+ <role>
9
+ Principal Engineer.
10
+ You are an expert in code quality, security, and performance.
11
+ </role>
12
+
13
+ <task>
14
+ Perform a deep code review of the provided diff:
15
+ - Identify bugs, security vulnerabilities, and performance issues.
16
+ - Assess maintainability and clarity.
17
+ - Provide contextual insights if full file content is available.
18
+ </task>
19
+
20
+ <constraints>
21
+ - Ignore style/formatting/whitespace changes.
22
+ - Prioritize correctness and failure modes over opinionated patterns.
23
+ - Findings must be actionable and specific to the diff.
24
+ - Return valid JSON matching the schema.
25
+ </constraints>
13
26
  `;
14
27
  const TOOL_CONTRACT = requireToolContract('inspect_code_quality');
15
28
  function formatOptionalLine(label, value) {
@@ -32,6 +45,12 @@ export function registerInspectCodeQualityTool(server) {
32
45
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
33
46
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
34
47
  requiresDiff: true,
48
+ progressContext: (input) => {
49
+ const focus = input.focusAreas
50
+ ? `[${input.focusAreas.join(',')}]`
51
+ : 'general';
52
+ return `${input.repository} ${focus}`;
53
+ },
35
54
  formatOutcome: (result) => `${result.findings.length} findings, risk: ${result.overallRisk}`,
36
55
  formatOutput: (result) => {
37
56
  const count = result.findings.length;
@@ -4,11 +4,23 @@ import { registerStructuredToolTask } from '../lib/tool-factory.js';
4
4
  import { SuggestSearchReplaceInputSchema } from '../schemas/inputs.js';
5
5
  import { SearchReplaceResultSchema } from '../schemas/outputs.js';
6
6
  const SYSTEM_INSTRUCTION = `
7
+ <role>
7
8
  Code Remediation Expert.
8
- Generate minimal search/replace blocks for described issue.
9
- Constraint: 'search' must be verbatim (exact whitespace/indentation).
10
- Constraint: No context drift. Omit patch if exact match uncertain.
11
- Return strict JSON.
9
+ You are a precise tool for generating automated code fixes.
10
+ </role>
11
+
12
+ <task>
13
+ Generate minimal search-and-replace blocks to fix the described issue:
14
+ - 'search' block must match the existing code EXACTLY (including whitespace).
15
+ - 'replace' block must be syntactically correct and follow local style.
16
+ </task>
17
+
18
+ <constraints>
19
+ - Verbatim match required: preserve all indentation and newlines in 'search'.
20
+ - Do not include surrounding code unless necessary for uniqueness.
21
+ - If exact match is ambiguous, return an empty block list.
22
+ - Return valid JSON matching the schema.
23
+ </constraints>
12
24
  `;
13
25
  const TOOL_CONTRACT = requireToolContract('suggest_search_replace');
14
26
  function formatPatchCount(count) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j0hanz/code-review-analyst-mcp",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "mcpName": "io.github.j0hanz/code-review-analyst",
5
5
  "description": "Gemini-powered MCP server for code review analysis.",
6
6
  "type": "module",