@j0hanz/code-review-analyst-mcp 1.7.1 → 1.7.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 +54 -12
- package/dist/lib/tool-factory.d.ts +1 -0
- package/dist/lib/tool-factory.js +39 -16
- package/dist/prompts/index.js +7 -7
- package/dist/tools/analyze-complexity.js +17 -4
- package/dist/tools/analyze-pr-impact.js +17 -3
- package/dist/tools/detect-api-breaking.js +16 -4
- package/dist/tools/generate-review-summary.js +16 -3
- package/dist/tools/generate-test-plan.js +15 -4
- package/dist/tools/inspect-code-quality.js +24 -5
- package/dist/tools/suggest-search-replace.js +16 -4
- package/package.json +1 -1
package/dist/lib/gemini.js
CHANGED
|
@@ -514,12 +514,27 @@ async function throwGeminiFailure(attemptsMade, lastError, onLog) {
|
|
|
514
514
|
async function runWithRetries(request, model, timeoutMs, maxRetries, onLog) {
|
|
515
515
|
let lastError;
|
|
516
516
|
let attempt = 0;
|
|
517
|
+
let currentModel = model;
|
|
517
518
|
for (; attempt <= maxRetries; attempt += 1) {
|
|
518
519
|
try {
|
|
519
|
-
return await executeAttempt(request,
|
|
520
|
+
return await executeAttempt(request, currentModel, timeoutMs, attempt, onLog);
|
|
520
521
|
}
|
|
521
522
|
catch (error) {
|
|
522
523
|
lastError = error;
|
|
524
|
+
if (getNumericErrorCode(error) === 404 &&
|
|
525
|
+
currentModel === 'gemini-3-flash-preview') {
|
|
526
|
+
currentModel = 'gemini-2.5-flash';
|
|
527
|
+
delete request.thinkingLevel;
|
|
528
|
+
await emitGeminiLog(onLog, 'warning', {
|
|
529
|
+
event: 'gemini_model_fallback',
|
|
530
|
+
details: {
|
|
531
|
+
from: 'gemini-3-flash-preview',
|
|
532
|
+
to: 'gemini-2.5-flash',
|
|
533
|
+
reason: 'Model not found (404)',
|
|
534
|
+
},
|
|
535
|
+
});
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
523
538
|
if (!canRetryAttempt(attempt, maxRetries, error)) {
|
|
524
539
|
attempt += 1; // Count this attempt before breaking
|
|
525
540
|
break;
|
|
@@ -737,6 +752,43 @@ async function cancelBatchIfNeeded(request, batches, batchName, onLog, completed
|
|
|
737
752
|
});
|
|
738
753
|
}
|
|
739
754
|
}
|
|
755
|
+
async function createBatchJobWithFallback(request, batches, model, onLog) {
|
|
756
|
+
let currentModel = model;
|
|
757
|
+
const createSignal = request.signal ?? NEVER_ABORT_SIGNAL;
|
|
758
|
+
for (let attempt = 0; attempt <= 1; attempt += 1) {
|
|
759
|
+
try {
|
|
760
|
+
const createPayload = {
|
|
761
|
+
model: currentModel,
|
|
762
|
+
src: [
|
|
763
|
+
{
|
|
764
|
+
contents: [{ role: 'user', parts: [{ text: request.prompt }] }],
|
|
765
|
+
config: buildGenerationConfig(request, createSignal),
|
|
766
|
+
},
|
|
767
|
+
],
|
|
768
|
+
};
|
|
769
|
+
return await batches.create(createPayload);
|
|
770
|
+
}
|
|
771
|
+
catch (error) {
|
|
772
|
+
if (attempt === 0 &&
|
|
773
|
+
getNumericErrorCode(error) === 404 &&
|
|
774
|
+
currentModel === 'gemini-3-flash-preview') {
|
|
775
|
+
currentModel = 'gemini-2.5-flash';
|
|
776
|
+
delete request.thinkingLevel;
|
|
777
|
+
await emitGeminiLog(onLog, 'warning', {
|
|
778
|
+
event: 'gemini_model_fallback',
|
|
779
|
+
details: {
|
|
780
|
+
from: 'gemini-3-flash-preview',
|
|
781
|
+
to: 'gemini-2.5-flash',
|
|
782
|
+
reason: 'Model not found (404) during batch create',
|
|
783
|
+
},
|
|
784
|
+
});
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
throw error;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
throw new Error('Unexpected state: batch creation loop exited without returning or throwing.');
|
|
791
|
+
}
|
|
740
792
|
async function runInlineBatchWithPolling(request, model, onLog) {
|
|
741
793
|
const client = getClient();
|
|
742
794
|
const { batches } = client;
|
|
@@ -747,17 +799,7 @@ async function runInlineBatchWithPolling(request, model, onLog) {
|
|
|
747
799
|
let completed = false;
|
|
748
800
|
let timedOut = false;
|
|
749
801
|
try {
|
|
750
|
-
const
|
|
751
|
-
const createPayload = {
|
|
752
|
-
model,
|
|
753
|
-
src: [
|
|
754
|
-
{
|
|
755
|
-
contents: [{ role: 'user', parts: [{ text: request.prompt }] }],
|
|
756
|
-
config: buildGenerationConfig(request, createSignal),
|
|
757
|
-
},
|
|
758
|
-
],
|
|
759
|
-
};
|
|
760
|
-
const createdJob = await batches.create(createPayload);
|
|
802
|
+
const createdJob = await createBatchJobWithFallback(request, batches, model, onLog);
|
|
761
803
|
const createdRecord = toRecord(createdJob);
|
|
762
804
|
batchName =
|
|
763
805
|
typeof createdRecord?.name === 'string' ? createdRecord.name : undefined;
|
|
@@ -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;
|
package/dist/lib/tool-factory.js
CHANGED
|
@@ -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}
|
|
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, `
|
|
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,33 @@ 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
|
+
}
|
|
395
|
+
else if (record.event === 'gemini_queue_acquired') {
|
|
396
|
+
const msg = 'Model queue acquired, generating response...';
|
|
397
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, msg);
|
|
398
|
+
await this.updateStatusMessage(msg);
|
|
399
|
+
}
|
|
377
400
|
}
|
|
378
401
|
setResponseSchemaOverride(responseSchema) {
|
|
379
402
|
this.responseSchema = responseSchema;
|
|
@@ -440,8 +463,8 @@ export class ToolExecutionRunner {
|
|
|
440
463
|
try {
|
|
441
464
|
const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.signal));
|
|
442
465
|
if (attempt === 0) {
|
|
443
|
-
await this.updateStatusMessage('
|
|
444
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, '
|
|
466
|
+
await this.updateStatusMessage('Verifying output structure...');
|
|
467
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'Verifying output structure...');
|
|
445
468
|
}
|
|
446
469
|
parsed = this.config.resultSchema.parse(raw);
|
|
447
470
|
break;
|
|
@@ -476,23 +499,23 @@ export class ToolExecutionRunner {
|
|
|
476
499
|
const ctx = {
|
|
477
500
|
diffSlot: this.hasSnapshot ? this.diffSlotSnapshot : getDiff(),
|
|
478
501
|
};
|
|
479
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_STARTING, '
|
|
480
|
-
await this.updateStatusMessage('
|
|
481
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, '
|
|
482
|
-
await this.updateStatusMessage('
|
|
502
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_STARTING, 'Initializing...');
|
|
503
|
+
await this.updateStatusMessage('Initializing...');
|
|
504
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'Validating request parameters...');
|
|
505
|
+
await this.updateStatusMessage('Validating request parameters...');
|
|
483
506
|
const validationError = await this.executeValidation(inputRecord, ctx);
|
|
484
507
|
if (validationError) {
|
|
485
508
|
return validationError;
|
|
486
509
|
}
|
|
487
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, '
|
|
488
|
-
await this.updateStatusMessage('
|
|
510
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, 'Constructing analysis context...');
|
|
511
|
+
await this.updateStatusMessage('Constructing analysis context...');
|
|
489
512
|
const promptParts = this.config.buildPrompt(inputRecord, ctx);
|
|
490
513
|
const { prompt, systemInstruction } = promptParts;
|
|
491
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, '
|
|
492
|
-
await this.updateStatusMessage('
|
|
514
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, 'Querying Gemini model...');
|
|
515
|
+
await this.updateStatusMessage('Querying Gemini model...');
|
|
493
516
|
const parsed = await this.executeModelCall(systemInstruction, prompt);
|
|
494
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, '
|
|
495
|
-
await this.updateStatusMessage('
|
|
517
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, 'Processing results...');
|
|
518
|
+
await this.updateStatusMessage('Processing results...');
|
|
496
519
|
const finalResult = (this.config.transformResult
|
|
497
520
|
? this.config.transformResult(inputRecord, parsed, ctx)
|
|
498
521
|
: parsed);
|
|
@@ -503,7 +526,7 @@ export class ToolExecutionRunner {
|
|
|
503
526
|
const ageMs = Date.now() - new Date(ctx.diffSlot.generatedAt).getTime();
|
|
504
527
|
if (ageMs > diffStaleWarningMs.get()) {
|
|
505
528
|
const ageMinutes = Math.round(ageMs / 60_000);
|
|
506
|
-
const warning = `\n\
|
|
529
|
+
const warning = `\n\nWarning: The analyzed diff is over ${ageMinutes} minutes old. If you have made recent changes, please run generate_diff again.`;
|
|
507
530
|
textContent = textContent ? textContent + warning : warning;
|
|
508
531
|
}
|
|
509
532
|
}
|
package/dist/prompts/index.js
CHANGED
|
@@ -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
|
|
21
|
-
correctness: 'Focus: Logic
|
|
22
|
-
performance: 'Focus:
|
|
23
|
-
regressions: 'Focus: Behavior
|
|
24
|
-
tests: 'Focus:
|
|
25
|
-
maintainability: 'Focus:
|
|
26
|
-
concurrency: 'Focus:
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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) {
|