@j0hanz/code-review-analyst-mcp 1.7.4 → 1.7.5
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/index.js +3 -2
- package/dist/lib/diff-store.js +3 -2
- package/dist/lib/diff.js +4 -9
- package/dist/lib/env-config.js +1 -4
- package/dist/lib/errors.js +1 -2
- package/dist/lib/format.d.ts +3 -0
- package/dist/lib/format.js +9 -0
- package/dist/lib/gemini-schema.js +3 -2
- package/dist/lib/gemini.js +6 -9
- package/dist/lib/markdown.d.ts +2 -0
- package/dist/lib/markdown.js +6 -0
- package/dist/lib/model-config.d.ts +2 -2
- package/dist/lib/model-config.js +2 -3
- package/dist/lib/tool-contracts.js +11 -11
- package/dist/lib/tool-factory.d.ts +1 -0
- package/dist/lib/tool-factory.js +15 -20
- package/dist/lib/tool-response.js +6 -5
- package/dist/lib/types.d.ts +2 -1
- package/dist/prompts/index.js +6 -3
- package/dist/resources/index.js +20 -8
- package/dist/resources/instructions.js +9 -8
- package/dist/resources/server-config.js +14 -13
- package/dist/resources/tool-catalog.js +12 -11
- package/dist/resources/tool-info.js +3 -4
- package/dist/resources/workflows.js +2 -3
- package/dist/schemas/inputs.js +12 -10
- package/dist/schemas/outputs.js +3 -2
- package/dist/server.js +6 -5
- package/dist/tools/analyze-complexity.js +2 -3
- package/dist/tools/analyze-pr-impact.js +1 -3
- package/dist/tools/detect-api-breaking.js +2 -3
- package/dist/tools/generate-diff.js +8 -5
- package/dist/tools/generate-review-summary.js +1 -3
- package/dist/tools/generate-test-plan.js +1 -3
- package/dist/tools/index.js +2 -2
- package/dist/tools/inspect-code-quality.js +1 -3
- package/dist/tools/suggest-search-replace.js +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,9 +22,10 @@ const CLI_OPTIONS = {
|
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
function setStringEnv(name, value) {
|
|
25
|
-
if (typeof value
|
|
26
|
-
|
|
25
|
+
if (typeof value !== 'string') {
|
|
26
|
+
return;
|
|
27
27
|
}
|
|
28
|
+
process.env[name] = value;
|
|
28
29
|
}
|
|
29
30
|
function applyCliEnvironmentOverrides(values) {
|
|
30
31
|
for (const mapping of CLI_ENV_MAPPINGS) {
|
package/dist/lib/diff-store.js
CHANGED
|
@@ -10,9 +10,10 @@ let sendResourceUpdated;
|
|
|
10
10
|
function setDiffSlot(key, data) {
|
|
11
11
|
if (data) {
|
|
12
12
|
diffSlots.set(key, data);
|
|
13
|
-
return;
|
|
14
13
|
}
|
|
15
|
-
|
|
14
|
+
else {
|
|
15
|
+
diffSlots.delete(key);
|
|
16
|
+
}
|
|
16
17
|
}
|
|
17
18
|
function notifyDiffUpdated() {
|
|
18
19
|
void sendResourceUpdated?.({ uri: DIFF_RESOURCE_URI }).catch(() => {
|
package/dist/lib/diff.js
CHANGED
|
@@ -48,15 +48,10 @@ const GIT_BINARY_PATCH = /^GIT binary patch/m;
|
|
|
48
48
|
const HAS_HUNK = /^@@/m;
|
|
49
49
|
const HAS_OLD_MODE = /^old mode /m;
|
|
50
50
|
function shouldKeepSection(section) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (GIT_BINARY_PATCH.test(section))
|
|
56
|
-
return false;
|
|
57
|
-
if (HAS_OLD_MODE.test(section) && !HAS_HUNK.test(section))
|
|
58
|
-
return false;
|
|
59
|
-
return true;
|
|
51
|
+
return (Boolean(section.trim()) &&
|
|
52
|
+
!BINARY_FILE_LINE.test(section) &&
|
|
53
|
+
!GIT_BINARY_PATCH.test(section) &&
|
|
54
|
+
(!HAS_OLD_MODE.test(section) || HAS_HUNK.test(section)));
|
|
60
55
|
}
|
|
61
56
|
function processSection(raw, start, end, sections) {
|
|
62
57
|
if (end > start) {
|
package/dist/lib/env-config.js
CHANGED
|
@@ -4,10 +4,7 @@ function parsePositiveInteger(value) {
|
|
|
4
4
|
return undefined;
|
|
5
5
|
}
|
|
6
6
|
const parsed = Number.parseInt(normalized, 10);
|
|
7
|
-
|
|
8
|
-
return undefined;
|
|
9
|
-
}
|
|
10
|
-
return parsed;
|
|
7
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
11
8
|
}
|
|
12
9
|
function resolveEnvInt(envVar, defaultValue) {
|
|
13
10
|
const envValue = process.env[envVar] ?? '';
|
package/dist/lib/errors.js
CHANGED
|
@@ -8,8 +8,7 @@ function getStringProperty(value, key) {
|
|
|
8
8
|
if (!isObjectRecord(value) || !(key in value)) {
|
|
9
9
|
return undefined;
|
|
10
10
|
}
|
|
11
|
-
const
|
|
12
|
-
const property = record[key];
|
|
11
|
+
const property = value[key];
|
|
13
12
|
return typeof property === 'string' ? property : undefined;
|
|
14
13
|
}
|
|
15
14
|
export function getErrorMessage(error) {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function formatOptionalLine(label: string, value: string | number | undefined): string;
|
|
2
|
+
export declare function formatLanguageSegment(language: string | undefined): string;
|
|
3
|
+
export declare function formatCountLabel(count: number, singular: string, plural: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function formatOptionalLine(label, value) {
|
|
2
|
+
return value === undefined ? '' : `\n${label}: ${value}`;
|
|
3
|
+
}
|
|
4
|
+
export function formatLanguageSegment(language) {
|
|
5
|
+
return formatOptionalLine('Language', language);
|
|
6
|
+
}
|
|
7
|
+
export function formatCountLabel(count, singular, plural) {
|
|
8
|
+
return `${count} ${count === 1 ? singular : plural}`;
|
|
9
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const CONSTRAINT_KEY_VALUES = [
|
|
2
2
|
'minLength',
|
|
3
3
|
'maxLength',
|
|
4
4
|
'minimum',
|
|
@@ -10,7 +10,8 @@ const CONSTRAINT_KEYS = new Set([
|
|
|
10
10
|
'multipleOf',
|
|
11
11
|
'pattern',
|
|
12
12
|
'format',
|
|
13
|
-
]
|
|
13
|
+
];
|
|
14
|
+
const CONSTRAINT_KEYS = new Set(CONSTRAINT_KEY_VALUES);
|
|
14
15
|
const INTEGER_JSON_TYPE = 'integer';
|
|
15
16
|
const NUMBER_JSON_TYPE = 'number';
|
|
16
17
|
function isJsonRecord(value) {
|
package/dist/lib/gemini.js
CHANGED
|
@@ -17,11 +17,8 @@ const GEMINI_BATCH_MODE_ENV_VAR = 'GEMINI_BATCH_MODE';
|
|
|
17
17
|
const GEMINI_API_KEY_ENV_VAR = 'GEMINI_API_KEY';
|
|
18
18
|
const GOOGLE_API_KEY_ENV_VAR = 'GOOGLE_API_KEY';
|
|
19
19
|
function getDefaultModel() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const value = process.env[GEMINI_MODEL_ENV_VAR] ?? DEFAULT_MODEL;
|
|
23
|
-
_defaultModel = value;
|
|
24
|
-
return value;
|
|
20
|
+
_defaultModel ??= process.env[GEMINI_MODEL_ENV_VAR] ?? DEFAULT_MODEL;
|
|
21
|
+
return _defaultModel;
|
|
25
22
|
}
|
|
26
23
|
const DEFAULT_MAX_RETRIES = 3;
|
|
27
24
|
const DEFAULT_TIMEOUT_MS = 90_000;
|
|
@@ -208,10 +205,10 @@ function getSafetySettings(threshold) {
|
|
|
208
205
|
if (cached) {
|
|
209
206
|
return cached;
|
|
210
207
|
}
|
|
211
|
-
const settings =
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
208
|
+
const settings = SAFETY_CATEGORIES.map((category) => ({
|
|
209
|
+
category,
|
|
210
|
+
threshold,
|
|
211
|
+
}));
|
|
215
212
|
safetySettingsCache.set(threshold, settings);
|
|
216
213
|
return settings;
|
|
217
214
|
}
|
|
@@ -6,9 +6,9 @@ export declare const DEFAULT_LANGUAGE = "detect";
|
|
|
6
6
|
export declare const DEFAULT_FRAMEWORK = "detect";
|
|
7
7
|
/** Extended timeout for deep analysis calls (ms). */
|
|
8
8
|
export declare const DEFAULT_TIMEOUT_EXTENDED_MS = 120000;
|
|
9
|
-
export declare const MODEL_TIMEOUT_MS: {
|
|
9
|
+
export declare const MODEL_TIMEOUT_MS: Readonly<{
|
|
10
10
|
readonly extended: 120000;
|
|
11
|
-
}
|
|
11
|
+
}>;
|
|
12
12
|
/** Thinking level for Flash triage. */
|
|
13
13
|
export declare const FLASH_TRIAGE_THINKING_LEVEL: "minimal";
|
|
14
14
|
/** Thinking level for Flash analysis. */
|
package/dist/lib/model-config.js
CHANGED
|
@@ -6,10 +6,9 @@ export const DEFAULT_LANGUAGE = 'detect';
|
|
|
6
6
|
export const DEFAULT_FRAMEWORK = 'detect';
|
|
7
7
|
/** Extended timeout for deep analysis calls (ms). */
|
|
8
8
|
export const DEFAULT_TIMEOUT_EXTENDED_MS = 120_000;
|
|
9
|
-
export const MODEL_TIMEOUT_MS = {
|
|
9
|
+
export const MODEL_TIMEOUT_MS = Object.freeze({
|
|
10
10
|
extended: DEFAULT_TIMEOUT_EXTENDED_MS,
|
|
11
|
-
};
|
|
12
|
-
Object.freeze(MODEL_TIMEOUT_MS);
|
|
11
|
+
});
|
|
13
12
|
// ---------------------------------------------------------------------------
|
|
14
13
|
// Budgets (Thinking & Output)
|
|
15
14
|
// ---------------------------------------------------------------------------
|
|
@@ -10,17 +10,17 @@ export const INSPECTION_FOCUS_AREAS = [
|
|
|
10
10
|
'concurrency',
|
|
11
11
|
];
|
|
12
12
|
export function buildStructuredToolRuntimeOptions(contract) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
return {
|
|
14
|
+
...(contract.thinkingLevel !== undefined
|
|
15
|
+
? { thinkingLevel: contract.thinkingLevel }
|
|
16
|
+
: {}),
|
|
17
|
+
...(contract.temperature !== undefined
|
|
18
|
+
? { temperature: contract.temperature }
|
|
19
|
+
: {}),
|
|
20
|
+
...(contract.deterministicJson !== undefined
|
|
21
|
+
? { deterministicJson: contract.deterministicJson }
|
|
22
|
+
: {}),
|
|
23
|
+
};
|
|
24
24
|
}
|
|
25
25
|
export const TOOL_CONTRACTS = [
|
|
26
26
|
{
|
|
@@ -130,6 +130,7 @@ export declare class ToolExecutionRunner<TInput extends object, TResult extends
|
|
|
130
130
|
private storeResultSafely;
|
|
131
131
|
private executeValidation;
|
|
132
132
|
private executeModelCall;
|
|
133
|
+
private reportAndStatus;
|
|
133
134
|
run(input: unknown): Promise<CallToolResult>;
|
|
134
135
|
}
|
|
135
136
|
export declare function registerStructuredToolTask<TInput extends object, TResult extends object = Record<string, unknown>, TFinal extends TResult = TResult>(server: McpServer, config: StructuredToolTaskConfig<TInput, TResult, TFinal>): void;
|
package/dist/lib/tool-factory.js
CHANGED
|
@@ -37,11 +37,10 @@ function buildToolAnnotations(annotations) {
|
|
|
37
37
|
openWorldHint: true,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
const annotationOverrides =
|
|
41
|
-
delete annotationOverrides.destructiveHint;
|
|
40
|
+
const { destructiveHint, ...annotationOverrides } = annotations;
|
|
42
41
|
return {
|
|
43
|
-
readOnlyHint: !
|
|
44
|
-
idempotentHint: !
|
|
42
|
+
readOnlyHint: !destructiveHint,
|
|
43
|
+
idempotentHint: !destructiveHint,
|
|
45
44
|
openWorldHint: true,
|
|
46
45
|
...annotationOverrides,
|
|
47
46
|
};
|
|
@@ -395,13 +394,11 @@ export class ToolExecutionRunner {
|
|
|
395
394
|
const details = asObjectRecord(record.details);
|
|
396
395
|
const { attempt } = details;
|
|
397
396
|
const msg = `Network error. Retrying (attempt ${String(attempt)})...`;
|
|
398
|
-
await
|
|
399
|
-
await this.updateStatusMessage(msg);
|
|
397
|
+
await this.reportAndStatus(STEP_CALLING_MODEL, msg);
|
|
400
398
|
}
|
|
401
399
|
else if (record.event === 'gemini_queue_acquired') {
|
|
402
400
|
const msg = 'Model queue acquired, generating response...';
|
|
403
|
-
await
|
|
404
|
-
await this.updateStatusMessage(msg);
|
|
401
|
+
await this.reportAndStatus(STEP_CALLING_MODEL, msg);
|
|
405
402
|
}
|
|
406
403
|
}
|
|
407
404
|
setResponseSchemaOverride(responseSchema) {
|
|
@@ -469,8 +466,7 @@ export class ToolExecutionRunner {
|
|
|
469
466
|
try {
|
|
470
467
|
const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.signal));
|
|
471
468
|
if (attempt === 0) {
|
|
472
|
-
await this.
|
|
473
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'Verifying output structure...');
|
|
469
|
+
await this.reportAndStatus(STEP_VALIDATING_RESPONSE, 'Verifying output structure...');
|
|
474
470
|
}
|
|
475
471
|
parsed = this.config.resultSchema.parse(raw);
|
|
476
472
|
break;
|
|
@@ -498,6 +494,10 @@ export class ToolExecutionRunner {
|
|
|
498
494
|
}
|
|
499
495
|
return parsed;
|
|
500
496
|
}
|
|
497
|
+
async reportAndStatus(step, message) {
|
|
498
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, step, message);
|
|
499
|
+
await this.updateStatusMessage(message);
|
|
500
|
+
}
|
|
501
501
|
async run(input) {
|
|
502
502
|
try {
|
|
503
503
|
const inputRecord = parseToolInput(input, this.config.fullInputSchema);
|
|
@@ -505,23 +505,18 @@ export class ToolExecutionRunner {
|
|
|
505
505
|
const ctx = {
|
|
506
506
|
diffSlot: this.hasSnapshot ? this.diffSlotSnapshot : getDiff(),
|
|
507
507
|
};
|
|
508
|
-
await
|
|
509
|
-
await this.
|
|
510
|
-
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'Validating request parameters...');
|
|
511
|
-
await this.updateStatusMessage('Validating request parameters...');
|
|
508
|
+
await this.reportAndStatus(STEP_STARTING, 'Initializing...');
|
|
509
|
+
await this.reportAndStatus(STEP_VALIDATING, 'Validating request parameters...');
|
|
512
510
|
const validationError = await this.executeValidation(inputRecord, ctx);
|
|
513
511
|
if (validationError) {
|
|
514
512
|
return validationError;
|
|
515
513
|
}
|
|
516
|
-
await
|
|
517
|
-
await this.updateStatusMessage('Constructing analysis context...');
|
|
514
|
+
await this.reportAndStatus(STEP_BUILDING_PROMPT, 'Constructing analysis context...');
|
|
518
515
|
const promptParts = this.config.buildPrompt(inputRecord, ctx);
|
|
519
516
|
const { prompt, systemInstruction } = promptParts;
|
|
520
|
-
await
|
|
521
|
-
await this.updateStatusMessage('Querying Gemini model...');
|
|
517
|
+
await this.reportAndStatus(STEP_CALLING_MODEL, 'Querying Gemini model...');
|
|
522
518
|
const parsed = await this.executeModelCall(systemInstruction, prompt);
|
|
523
|
-
await
|
|
524
|
-
await this.updateStatusMessage('Processing results...');
|
|
519
|
+
await this.reportAndStatus(STEP_FINALIZING, 'Processing results...');
|
|
525
520
|
const finalResult = (this.config.transformResult
|
|
526
521
|
? this.config.transformResult(inputRecord, parsed, ctx)
|
|
527
522
|
: parsed);
|
|
@@ -6,16 +6,17 @@ function appendErrorMeta(error, meta) {
|
|
|
6
6
|
error.kind = meta.kind;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
+
function createToolError(code, message, meta) {
|
|
10
|
+
const error = { code, message };
|
|
11
|
+
appendErrorMeta(error, meta);
|
|
12
|
+
return error;
|
|
13
|
+
}
|
|
9
14
|
function toTextContent(structured, textContent) {
|
|
10
15
|
const text = textContent ?? JSON.stringify(structured);
|
|
11
16
|
return [{ type: 'text', text }];
|
|
12
17
|
}
|
|
13
18
|
function createErrorStructuredContent(code, message, result, meta) {
|
|
14
|
-
const error =
|
|
15
|
-
code,
|
|
16
|
-
message,
|
|
17
|
-
};
|
|
18
|
-
appendErrorMeta(error, meta);
|
|
19
|
+
const error = createToolError(code, message, meta);
|
|
19
20
|
if (result === undefined) {
|
|
20
21
|
return { ok: false, error };
|
|
21
22
|
}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export type JsonObject = Record<string, unknown>;
|
|
2
2
|
export type GeminiLogHandler = (level: string, data: unknown) => Promise<void>;
|
|
3
|
+
export type GeminiThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
|
|
3
4
|
export interface GeminiRequestExecutionOptions {
|
|
4
5
|
maxRetries?: number;
|
|
5
6
|
timeoutMs?: number;
|
|
6
7
|
temperature?: number;
|
|
7
8
|
maxOutputTokens?: number;
|
|
8
|
-
thinkingLevel?:
|
|
9
|
+
thinkingLevel?: GeminiThinkingLevel;
|
|
9
10
|
includeThoughts?: boolean;
|
|
10
11
|
signal?: AbortSignal;
|
|
11
12
|
onLog?: GeminiLogHandler;
|
package/dist/prompts/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { completable } from '@modelcontextprotocol/sdk/server/completable.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { toInlineCode } from '../lib/markdown.js';
|
|
3
4
|
import { getToolContract, getToolContractNames, INSPECTION_FOCUS_AREAS, } from '../lib/tool-contracts.js';
|
|
4
5
|
export const PROMPT_DEFINITIONS = [
|
|
5
6
|
{
|
|
@@ -34,7 +35,7 @@ function completeByPrefix(values, prefix) {
|
|
|
34
35
|
function getToolGuide(tool) {
|
|
35
36
|
const contract = getToolContract(tool);
|
|
36
37
|
if (!contract) {
|
|
37
|
-
return `Use
|
|
38
|
+
return `Use ${toInlineCode(tool)} to analyze your code changes.`;
|
|
38
39
|
}
|
|
39
40
|
const { thinkingLevel } = contract;
|
|
40
41
|
const modelLine = thinkingLevel !== undefined
|
|
@@ -66,12 +67,14 @@ function registerHelpPrompt(server, instructions) {
|
|
|
66
67
|
}));
|
|
67
68
|
}
|
|
68
69
|
function buildReviewGuideText(tool, focusArea) {
|
|
70
|
+
const toolCode = toInlineCode(tool);
|
|
71
|
+
const suggestToolCode = toInlineCode('suggest_search_replace');
|
|
69
72
|
return (`# Guide: ${tool} / ${focusArea}\n\n` +
|
|
70
|
-
`## Tool:
|
|
73
|
+
`## Tool: ${toolCode}\n${getToolGuide(tool)}\n\n` +
|
|
71
74
|
`## Focus: ${focusArea}\n${getFocusAreaGuide(focusArea)}\n\n` +
|
|
72
75
|
`## Example Fix\n` +
|
|
73
76
|
`Finding: "Uncaught promise rejection"\n` +
|
|
74
|
-
`Call
|
|
77
|
+
`Call ${suggestToolCode}:\n` +
|
|
75
78
|
'```\n' +
|
|
76
79
|
`search: " } catch {\\n }"\n` +
|
|
77
80
|
`replace: " } catch (err) {\\n logger.error(err);\\n }"\n` +
|
package/dist/resources/index.js
CHANGED
|
@@ -13,6 +13,16 @@ function completeByPrefix(values, prefix) {
|
|
|
13
13
|
function createMarkdownContent(uri, text) {
|
|
14
14
|
return { uri: uri.href, mimeType: RESOURCE_MIME_TYPE, text };
|
|
15
15
|
}
|
|
16
|
+
function formatUnknownToolMessage(name) {
|
|
17
|
+
return `Unknown tool: ${name}`;
|
|
18
|
+
}
|
|
19
|
+
function formatDiffResourceText() {
|
|
20
|
+
const slot = getDiff();
|
|
21
|
+
if (!slot) {
|
|
22
|
+
return '# No diff cached. Call generate_diff first.';
|
|
23
|
+
}
|
|
24
|
+
return `# Diff — ${slot.mode} — ${slot.generatedAt}\n# ${slot.stats.files} file(s), +${slot.stats.added} -${slot.stats.deleted}\n\n${slot.diff}`;
|
|
25
|
+
}
|
|
16
26
|
export const STATIC_RESOURCES = [
|
|
17
27
|
{
|
|
18
28
|
id: 'server-instructions',
|
|
@@ -77,7 +87,7 @@ function registerToolInfoResources(server) {
|
|
|
77
87
|
}, (uri, { toolName }) => {
|
|
78
88
|
const name = typeof toolName === 'string' ? toolName : '';
|
|
79
89
|
const info = getToolInfo(name);
|
|
80
|
-
const text = info ??
|
|
90
|
+
const text = info ?? formatUnknownToolMessage(name);
|
|
81
91
|
return { contents: [createMarkdownContent(uri, text)] };
|
|
82
92
|
});
|
|
83
93
|
}
|
|
@@ -91,13 +101,15 @@ function registerDiffResource(server) {
|
|
|
91
101
|
audience: RESOURCE_AUDIENCE,
|
|
92
102
|
priority: 1.0,
|
|
93
103
|
},
|
|
94
|
-
}, (uri) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
}, (uri) => ({
|
|
105
|
+
contents: [
|
|
106
|
+
{
|
|
107
|
+
uri: uri.href,
|
|
108
|
+
mimeType: PATCH_MIME_TYPE,
|
|
109
|
+
text: formatDiffResourceText(),
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
}));
|
|
101
113
|
}
|
|
102
114
|
export function registerAllResources(server, instructions) {
|
|
103
115
|
for (const def of STATIC_RESOURCES) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { toBulletedList, toInlineCode } from '../lib/markdown.js';
|
|
1
2
|
import { getToolContracts } from '../lib/tool-contracts.js';
|
|
2
3
|
import { PROMPT_DEFINITIONS } from '../prompts/index.js';
|
|
3
4
|
import { DIFF_RESOURCE_DESCRIPTION, STATIC_RESOURCES } from './index.js';
|
|
4
5
|
import { getSharedConstraints } from './tool-info.js';
|
|
5
|
-
const PROMPT_LIST = PROMPT_DEFINITIONS.map((def) =>
|
|
6
|
+
const PROMPT_LIST = PROMPT_DEFINITIONS.map((def) => `${toInlineCode(def.name)}: ${def.description}`);
|
|
6
7
|
const RESOURCE_LIST = [
|
|
7
|
-
...STATIC_RESOURCES.map((def) =>
|
|
8
|
-
'
|
|
9
|
-
|
|
8
|
+
...STATIC_RESOURCES.map((def) => `${toInlineCode(def.uri)}: ${def.description}`),
|
|
9
|
+
`${toInlineCode('internal://tool-info/{toolName}')}: Per-tool contract details.`,
|
|
10
|
+
`${toInlineCode('diff://current')}: ${DIFF_RESOURCE_DESCRIPTION}`,
|
|
10
11
|
];
|
|
11
12
|
function formatParameterLine(parameter) {
|
|
12
13
|
const req = parameter.required ? 'req' : 'opt';
|
|
@@ -41,7 +42,7 @@ export function buildServerInstructions() {
|
|
|
41
42
|
.map((contract) => `\`${contract.name}\``)
|
|
42
43
|
.join(', ');
|
|
43
44
|
const toolSections = contracts.map((contract) => formatToolSection(contract));
|
|
44
|
-
const constraintLines = getSharedConstraints()
|
|
45
|
+
const constraintLines = toBulletedList(getSharedConstraints());
|
|
45
46
|
return `# CODE REVIEW ANALYST MCP
|
|
46
47
|
|
|
47
48
|
## CORE
|
|
@@ -50,16 +51,16 @@ export function buildServerInstructions() {
|
|
|
50
51
|
- Tools: ${toolNames}
|
|
51
52
|
|
|
52
53
|
## PROMPTS
|
|
53
|
-
${PROMPT_LIST
|
|
54
|
+
${toBulletedList(PROMPT_LIST)}
|
|
54
55
|
|
|
55
56
|
## RESOURCES
|
|
56
|
-
${RESOURCE_LIST
|
|
57
|
+
${toBulletedList(RESOURCE_LIST)}
|
|
57
58
|
|
|
58
59
|
## TOOLS
|
|
59
60
|
${toolSections.join('\n\n')}
|
|
60
61
|
|
|
61
62
|
## CONSTRAINTS
|
|
62
|
-
${constraintLines
|
|
63
|
+
${constraintLines}
|
|
63
64
|
|
|
64
65
|
## TASK LIFECYCLE
|
|
65
66
|
- Progress steps (0–6): starting → validating input → building prompt → calling model → validating response → finalizing → done.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createCachedEnvInt } from '../lib/env-config.js';
|
|
2
|
+
import { toInlineCode } from '../lib/markdown.js';
|
|
2
3
|
import { FLASH_MODEL } from '../lib/model-config.js';
|
|
3
4
|
import { getToolContracts } from '../lib/tool-contracts.js';
|
|
4
5
|
const DEFAULT_MAX_DIFF_CHARS = 120_000;
|
|
@@ -41,7 +42,7 @@ export function buildServerConfig() {
|
|
|
41
42
|
const toolRows = getToolContracts()
|
|
42
43
|
.filter((contract) => contract.model !== 'none')
|
|
43
44
|
.map((contract) => {
|
|
44
|
-
return `|
|
|
45
|
+
return `| ${toInlineCode(contract.name)} | ${toInlineCode(contract.model)} | ${formatThinkingLevel(contract.thinkingLevel)} | ${formatTimeout(contract.timeoutMs)} | ${formatNumber(contract.maxOutputTokens)} |`;
|
|
45
46
|
})
|
|
46
47
|
.join('\n');
|
|
47
48
|
return `# Server Configuration
|
|
@@ -50,15 +51,15 @@ export function buildServerConfig() {
|
|
|
50
51
|
|
|
51
52
|
| Limit | Value | Env |
|
|
52
53
|
|-------|-------|-----|
|
|
53
|
-
| Diff limit | ${formatNumber(maxDiffChars)} chars |
|
|
54
|
-
| Concurrency limit | ${maxConcurrent} |
|
|
55
|
-
| Batch concurrency limit | ${maxConcurrentBatch} |
|
|
56
|
-
| Wait timeout | ${formatNumber(concurrentWaitMs)}ms |
|
|
57
|
-
| Batch mode | ${batchMode} |
|
|
54
|
+
| Diff limit | ${formatNumber(maxDiffChars)} chars | ${toInlineCode('MAX_DIFF_CHARS')} |
|
|
55
|
+
| Concurrency limit | ${maxConcurrent} | ${toInlineCode('MAX_CONCURRENT_CALLS')} |
|
|
56
|
+
| Batch concurrency limit | ${maxConcurrentBatch} | ${toInlineCode('MAX_CONCURRENT_BATCH_CALLS')} |
|
|
57
|
+
| Wait timeout | ${formatNumber(concurrentWaitMs)}ms | ${toInlineCode('MAX_CONCURRENT_CALLS_WAIT_MS')} |
|
|
58
|
+
| Batch mode | ${batchMode} | ${toInlineCode('GEMINI_BATCH_MODE')} |
|
|
58
59
|
|
|
59
60
|
## Model Assignments
|
|
60
61
|
|
|
61
|
-
Default model:
|
|
62
|
+
Default model: ${toInlineCode(defaultModel)} (override with ${toInlineCode('GEMINI_MODEL')})
|
|
62
63
|
|
|
63
64
|
| Tool | Model | Thinking Level | Timeout | Max Output Tokens |
|
|
64
65
|
|------|-------|----------------|---------|-------------------|
|
|
@@ -66,17 +67,17 @@ ${toolRows}
|
|
|
66
67
|
|
|
67
68
|
## Safety
|
|
68
69
|
|
|
69
|
-
- Harm block threshold:
|
|
70
|
-
- Override with
|
|
70
|
+
- Harm block threshold: ${toInlineCode(safetyThreshold)}
|
|
71
|
+
- Override with ${toInlineCode('GEMINI_HARM_BLOCK_THRESHOLD')} (BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE)
|
|
71
72
|
|
|
72
73
|
## API Keys
|
|
73
74
|
|
|
74
|
-
- Set
|
|
75
|
+
- Set ${toInlineCode('GEMINI_API_KEY')} or ${toInlineCode('GOOGLE_API_KEY')} environment variable (required)
|
|
75
76
|
|
|
76
77
|
## Batch Mode
|
|
77
78
|
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
79
|
+
- ${toInlineCode('GEMINI_BATCH_MODE')}: ${toInlineCode('off')} (default) or ${toInlineCode('inline')}
|
|
80
|
+
- ${toInlineCode('GEMINI_BATCH_POLL_INTERVAL_MS')}: poll cadence for batch status checks
|
|
81
|
+
- ${toInlineCode('GEMINI_BATCH_TIMEOUT_MS')}: max wait for batch completion
|
|
81
82
|
`;
|
|
82
83
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { toInlineCode } from '../lib/markdown.js';
|
|
1
2
|
import { buildCoreContextPack } from './tool-info.js';
|
|
2
3
|
const TOOL_CATALOG_CONTENT = `# Tool Catalog Details
|
|
3
4
|
|
|
4
5
|
## Optional Parameters
|
|
5
6
|
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
- ${toInlineCode('language')}: Primary language hint (auto-detects). All tools except ${toInlineCode('suggest_search_replace')}.
|
|
8
|
+
- ${toInlineCode('focusAreas')}: Focus tags (security, performance, etc.). ${toInlineCode('inspect_code_quality')} only.
|
|
9
|
+
- ${toInlineCode('maxFindings')}: Output cap (1–25). ${toInlineCode('inspect_code_quality')} only.
|
|
10
|
+
- ${toInlineCode('testFramework')}: Framework hint. ${toInlineCode('generate_test_plan')} only.
|
|
11
|
+
- ${toInlineCode('maxTestCases')}: Output cap (1–30). ${toInlineCode('generate_test_plan')} only.
|
|
11
12
|
|
|
12
13
|
## Cross-Tool Data Flow
|
|
13
14
|
|
|
@@ -26,12 +27,12 @@ generate_review_summary ──→ overallRisk ──────┤
|
|
|
26
27
|
|
|
27
28
|
## When to Use Each Tool
|
|
28
29
|
|
|
29
|
-
- **Triage**:
|
|
30
|
-
- **Inspection**:
|
|
31
|
-
- **Fixes**:
|
|
32
|
-
- **Tests**:
|
|
33
|
-
- **Complexity**:
|
|
34
|
-
- **Breaking API**:
|
|
30
|
+
- **Triage**: ${toInlineCode('analyze_pr_impact')}, ${toInlineCode('generate_review_summary')}.
|
|
31
|
+
- **Inspection**: ${toInlineCode('inspect_code_quality')}.
|
|
32
|
+
- **Fixes**: ${toInlineCode('suggest_search_replace')} (one finding/call).
|
|
33
|
+
- **Tests**: ${toInlineCode('generate_test_plan')}.
|
|
34
|
+
- **Complexity**: ${toInlineCode('analyze_time_space_complexity')}.
|
|
35
|
+
- **Breaking API**: ${toInlineCode('detect_api_breaking_changes')}.
|
|
35
36
|
`;
|
|
36
37
|
export function buildToolCatalog() {
|
|
37
38
|
return `${buildCoreContextPack()}\n\n${TOOL_CATALOG_CONTENT}`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toBulletedList, toInlineCode } from '../lib/markdown.js';
|
|
1
2
|
import { getToolContract, getToolContracts } from '../lib/tool-contracts.js';
|
|
2
3
|
const GLOBAL_CONSTRAINTS = [
|
|
3
4
|
'Diff budget: <= 120K chars.',
|
|
@@ -71,7 +72,7 @@ ${entry.crossToolFlow.map((f) => `- ${f}`).join('\n')}
|
|
|
71
72
|
`;
|
|
72
73
|
}
|
|
73
74
|
function formatCompactToolRow(entry) {
|
|
74
|
-
return `|
|
|
75
|
+
return `| ${toInlineCode(entry.name)} | ${entry.model} | ${entry.timeout} | ${entry.maxOutputTokens} | ${entry.purpose} |`;
|
|
75
76
|
}
|
|
76
77
|
export function buildCoreContextPack() {
|
|
77
78
|
const rows = TOOL_NAMES.flatMap((toolName) => {
|
|
@@ -91,9 +92,7 @@ export function buildCoreContextPack() {
|
|
|
91
92
|
${rows.join('\n')}
|
|
92
93
|
|
|
93
94
|
## Shared Constraints
|
|
94
|
-
${getSharedConstraints()
|
|
95
|
-
.map((constraint) => `- ${constraint}`)
|
|
96
|
-
.join('\n')}
|
|
95
|
+
${toBulletedList(getSharedConstraints())}
|
|
97
96
|
`;
|
|
98
97
|
}
|
|
99
98
|
export function getSharedConstraints() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toBulletedList } from '../lib/markdown.js';
|
|
1
2
|
import { getToolContracts } from '../lib/tool-contracts.js';
|
|
2
3
|
import { getSharedConstraints } from './tool-info.js';
|
|
3
4
|
function buildWorkflowToolReference() {
|
|
@@ -47,9 +48,7 @@ export function buildWorkflowGuide() {
|
|
|
47
48
|
> Use for algorithm or API changes. Diff-only input.
|
|
48
49
|
|
|
49
50
|
## Shared Constraints
|
|
50
|
-
${getSharedConstraints()
|
|
51
|
-
.map((constraint) => `- ${constraint}`)
|
|
52
|
-
.join('\n')}
|
|
51
|
+
${toBulletedList(getSharedConstraints())}
|
|
53
52
|
|
|
54
53
|
## Tool Reference
|
|
55
54
|
|
package/dist/schemas/inputs.js
CHANGED
|
@@ -26,17 +26,19 @@ function createRepositorySchema() {
|
|
|
26
26
|
function createOptionalBoundedInteger(min, max, description) {
|
|
27
27
|
return z.number().int().min(min).max(max).optional().describe(description);
|
|
28
28
|
}
|
|
29
|
+
const RepositorySchema = createRepositorySchema();
|
|
30
|
+
const LanguageSchema = createLanguageSchema();
|
|
29
31
|
export const AnalyzePrImpactInputSchema = z.strictObject({
|
|
30
|
-
repository:
|
|
31
|
-
language:
|
|
32
|
+
repository: RepositorySchema,
|
|
33
|
+
language: LanguageSchema,
|
|
32
34
|
});
|
|
33
35
|
export const GenerateReviewSummaryInputSchema = z.strictObject({
|
|
34
|
-
repository:
|
|
35
|
-
language:
|
|
36
|
+
repository: RepositorySchema,
|
|
37
|
+
language: LanguageSchema,
|
|
36
38
|
});
|
|
37
39
|
export const InspectCodeQualityInputSchema = z.strictObject({
|
|
38
|
-
repository:
|
|
39
|
-
language:
|
|
40
|
+
repository: RepositorySchema,
|
|
41
|
+
language: LanguageSchema,
|
|
40
42
|
focusAreas: z
|
|
41
43
|
.array(createBoundedString(INPUT_LIMITS.focusArea.min, INPUT_LIMITS.focusArea.max, 'Focus tag (e.g. security, logic).'))
|
|
42
44
|
.min(1)
|
|
@@ -50,14 +52,14 @@ export const SuggestSearchReplaceInputSchema = z.strictObject({
|
|
|
50
52
|
findingDetails: createBoundedString(INPUT_LIMITS.findingDetails.min, INPUT_LIMITS.findingDetails.max, 'Exact finding explanation from inspect_code_quality.'),
|
|
51
53
|
});
|
|
52
54
|
export const GenerateTestPlanInputSchema = z.strictObject({
|
|
53
|
-
repository:
|
|
54
|
-
language:
|
|
55
|
+
repository: RepositorySchema,
|
|
56
|
+
language: LanguageSchema,
|
|
55
57
|
testFramework: createOptionalBoundedString(INPUT_LIMITS.testFramework.min, INPUT_LIMITS.testFramework.max, 'Test framework (jest, pytest, etc). Auto-infer.'),
|
|
56
58
|
maxTestCases: createOptionalBoundedInteger(INPUT_LIMITS.maxTestCases.min, INPUT_LIMITS.maxTestCases.max, 'Max test cases (1-30). Default: 15.'),
|
|
57
59
|
});
|
|
58
60
|
export const AnalyzeComplexityInputSchema = z.strictObject({
|
|
59
|
-
language:
|
|
61
|
+
language: LanguageSchema,
|
|
60
62
|
});
|
|
61
63
|
export const DetectApiBreakingInputSchema = z.strictObject({
|
|
62
|
-
language:
|
|
64
|
+
language: LanguageSchema,
|
|
63
65
|
});
|
package/dist/schemas/outputs.js
CHANGED
|
@@ -28,6 +28,7 @@ const OUTPUT_LIMITS = {
|
|
|
28
28
|
};
|
|
29
29
|
const QUALITY_RISK_LEVELS = ['low', 'medium', 'high', 'critical'];
|
|
30
30
|
const MERGE_RISK_LEVELS = ['low', 'medium', 'high'];
|
|
31
|
+
const REVIEW_SUMMARY_LIMITS = OUTPUT_LIMITS.reviewDiffResult.summary;
|
|
31
32
|
const ERROR_KINDS = [
|
|
32
33
|
'validation',
|
|
33
34
|
'budget',
|
|
@@ -49,8 +50,8 @@ function createBoundedStringArray(itemMin, itemMax, minItems, maxItems, descript
|
|
|
49
50
|
function createReviewSummarySchema(description) {
|
|
50
51
|
return z
|
|
51
52
|
.string()
|
|
52
|
-
.min(
|
|
53
|
-
.max(
|
|
53
|
+
.min(REVIEW_SUMMARY_LIMITS.min)
|
|
54
|
+
.max(REVIEW_SUMMARY_LIMITS.max)
|
|
54
55
|
.describe(description);
|
|
55
56
|
}
|
|
56
57
|
const reviewFindingSeveritySchema = z
|
package/dist/server.js
CHANGED
|
@@ -14,6 +14,11 @@ const UTF8_ENCODING = 'utf8';
|
|
|
14
14
|
const PackageJsonSchema = z.object({
|
|
15
15
|
version: z.string().min(1),
|
|
16
16
|
});
|
|
17
|
+
const TASK_TOOL_CALL_CAPABILITY = {
|
|
18
|
+
tools: {
|
|
19
|
+
call: {},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
17
22
|
const SERVER_CAPABILITIES = {
|
|
18
23
|
logging: {},
|
|
19
24
|
completions: {},
|
|
@@ -23,11 +28,7 @@ const SERVER_CAPABILITIES = {
|
|
|
23
28
|
tasks: {
|
|
24
29
|
list: {},
|
|
25
30
|
cancel: {},
|
|
26
|
-
requests:
|
|
27
|
-
tools: {
|
|
28
|
-
call: {},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
+
requests: TASK_TOOL_CALL_CAPABILITY,
|
|
31
32
|
},
|
|
32
33
|
};
|
|
33
34
|
function readUtf8File(path) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatLanguageSegment } from '../lib/format.js';
|
|
1
2
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
2
3
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
3
4
|
import { AnalyzeComplexityInputSchema } from '../schemas/inputs.js';
|
|
@@ -42,9 +43,7 @@ export function registerAnalyzeComplexityTool(server) {
|
|
|
42
43
|
formatOutput: (result) => `Time=${result.timeComplexity}, Space=${result.spaceComplexity}. ${result.explanation}`,
|
|
43
44
|
buildPrompt: (input, ctx) => {
|
|
44
45
|
const diff = ctx.diffSlot?.diff ?? '';
|
|
45
|
-
const languageLine = input.language
|
|
46
|
-
? `\nLanguage: ${input.language}`
|
|
47
|
-
: '';
|
|
46
|
+
const languageLine = formatLanguageSegment(input.language);
|
|
48
47
|
return {
|
|
49
48
|
systemInstruction: SYSTEM_INSTRUCTION,
|
|
50
49
|
prompt: `${languageLine}\nDiff:\n${diff}\n\nBased on the diff above, analyze the Big-O time and space complexity.`.trimStart(),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeDiffStatsAndSummaryFromFiles } from '../lib/diff.js';
|
|
2
|
+
import { formatLanguageSegment } from '../lib/format.js';
|
|
2
3
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
3
4
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
4
5
|
import { AnalyzePrImpactInputSchema } from '../schemas/inputs.js';
|
|
@@ -24,9 +25,6 @@ Analyze the unified diff to assess:
|
|
|
24
25
|
</constraints>
|
|
25
26
|
`;
|
|
26
27
|
const TOOL_CONTRACT = requireToolContract('analyze_pr_impact');
|
|
27
|
-
function formatLanguageSegment(language) {
|
|
28
|
-
return language ? `\nLanguage: ${language}` : '';
|
|
29
|
-
}
|
|
30
28
|
export function registerAnalyzePrImpactTool(server) {
|
|
31
29
|
registerStructuredToolTask(server, {
|
|
32
30
|
name: 'analyze_pr_impact',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatLanguageSegment } from '../lib/format.js';
|
|
1
2
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
2
3
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
3
4
|
import { DetectApiBreakingInputSchema } from '../schemas/inputs.js';
|
|
@@ -41,9 +42,7 @@ export function registerDetectApiBreakingTool(server) {
|
|
|
41
42
|
: 'No breaking changes.',
|
|
42
43
|
buildPrompt: (input, ctx) => {
|
|
43
44
|
const diff = ctx.diffSlot?.diff ?? '';
|
|
44
|
-
const languageLine = input.language
|
|
45
|
-
? `\nLanguage: ${input.language}`
|
|
46
|
-
: '';
|
|
45
|
+
const languageLine = formatLanguageSegment(input.language);
|
|
47
46
|
return {
|
|
48
47
|
systemInstruction: SYSTEM_INSTRUCTION,
|
|
49
48
|
prompt: `${languageLine}\nDiff:\n${diff}\n\nBased on the diff above, detect any breaking API changes.`.trimStart(),
|
|
@@ -38,6 +38,13 @@ function describeModeHint(mode) {
|
|
|
38
38
|
? 'staged with git add'
|
|
39
39
|
: 'modified but not yet staged (git add)';
|
|
40
40
|
}
|
|
41
|
+
function formatGitFailureMessage(err) {
|
|
42
|
+
if (typeof err.code === 'number') {
|
|
43
|
+
const stderr = err.stderr?.trim() ?? 'unknown error';
|
|
44
|
+
return `git exited with code ${String(err.code)}: ${stderr}. Ensure the working directory is a git repository.`;
|
|
45
|
+
}
|
|
46
|
+
return `Failed to run git: ${err.message}. Ensure git is installed and the working directory is a git repository.`;
|
|
47
|
+
}
|
|
41
48
|
export function registerGenerateDiffTool(server) {
|
|
42
49
|
server.registerTool('generate_diff', {
|
|
43
50
|
title: 'Generate Diff',
|
|
@@ -90,11 +97,7 @@ export function registerGenerateDiffTool(server) {
|
|
|
90
97
|
}
|
|
91
98
|
catch (error) {
|
|
92
99
|
const err = error;
|
|
93
|
-
|
|
94
|
-
const stderr = err.stderr ? err.stderr.trim() : '';
|
|
95
|
-
return createErrorToolResponse('E_GENERATE_DIFF', `git exited with code ${String(err.code)}: ${stderr || 'unknown error'}. Ensure the working directory is a git repository.`, undefined, { retryable: false, kind: 'internal' });
|
|
96
|
-
}
|
|
97
|
-
return createErrorToolResponse('E_GENERATE_DIFF', `Failed to run git: ${err.message}. Ensure git is installed and the working directory is a git repository.`, undefined, { retryable: false, kind: 'internal' });
|
|
100
|
+
return createErrorToolResponse('E_GENERATE_DIFF', formatGitFailureMessage(err), undefined, { retryable: false, kind: 'internal' });
|
|
98
101
|
}
|
|
99
102
|
}));
|
|
100
103
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatLanguageSegment } from '../lib/format.js';
|
|
1
2
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
2
3
|
import { registerStructuredToolTask, } from '../lib/tool-factory.js';
|
|
3
4
|
import { GenerateReviewSummaryInputSchema } from '../schemas/inputs.js';
|
|
@@ -25,9 +26,6 @@ Summarize the pull request based on the diff:
|
|
|
25
26
|
- Return valid JSON matching the schema.
|
|
26
27
|
</constraints>
|
|
27
28
|
`;
|
|
28
|
-
function formatLanguageSegment(language) {
|
|
29
|
-
return language ? `\nLanguage: ${language}` : '';
|
|
30
|
-
}
|
|
31
29
|
function getDiffStats(ctx) {
|
|
32
30
|
const slot = ctx.diffSlot;
|
|
33
31
|
if (!slot) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeDiffStatsAndPathsFromFiles } from '../lib/diff.js';
|
|
2
|
+
import { formatOptionalLine } from '../lib/format.js';
|
|
2
3
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
3
4
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
4
5
|
import { GenerateTestPlanInputSchema } from '../schemas/inputs.js';
|
|
@@ -22,9 +23,6 @@ Generate a prioritized test plan for the provided diff:
|
|
|
22
23
|
</constraints>
|
|
23
24
|
`;
|
|
24
25
|
const TOOL_CONTRACT = requireToolContract('generate_test_plan');
|
|
25
|
-
function formatOptionalLine(label, value) {
|
|
26
|
-
return value === undefined ? '' : `\n${label}: ${value}`;
|
|
27
|
-
}
|
|
28
26
|
export function registerGenerateTestPlanTool(server) {
|
|
29
27
|
registerStructuredToolTask(server, {
|
|
30
28
|
name: 'generate_test_plan',
|
package/dist/tools/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeDiffStatsAndSummaryFromFiles } from '../lib/diff.js';
|
|
2
|
+
import { formatOptionalLine } from '../lib/format.js';
|
|
2
3
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
3
4
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
4
5
|
import { InspectCodeQualityInputSchema } from '../schemas/inputs.js';
|
|
@@ -25,9 +26,6 @@ Perform a deep code review of the provided diff:
|
|
|
25
26
|
</constraints>
|
|
26
27
|
`;
|
|
27
28
|
const TOOL_CONTRACT = requireToolContract('inspect_code_quality');
|
|
28
|
-
function formatOptionalLine(label, value) {
|
|
29
|
-
return value === undefined ? '' : `\n${label}: ${value}`;
|
|
30
|
-
}
|
|
31
29
|
function capFindings(findings, maxFindings) {
|
|
32
30
|
return findings.slice(0, maxFindings ?? findings.length);
|
|
33
31
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { extractChangedPathsFromFiles } from '../lib/diff.js';
|
|
2
|
+
import { formatCountLabel } from '../lib/format.js';
|
|
2
3
|
import { buildStructuredToolRuntimeOptions, requireToolContract, } from '../lib/tool-contracts.js';
|
|
3
4
|
import { registerStructuredToolTask } from '../lib/tool-factory.js';
|
|
4
5
|
import { SuggestSearchReplaceInputSchema } from '../schemas/inputs.js';
|
|
@@ -24,7 +25,7 @@ Generate minimal search-and-replace blocks to fix the described issue:
|
|
|
24
25
|
`;
|
|
25
26
|
const TOOL_CONTRACT = requireToolContract('suggest_search_replace');
|
|
26
27
|
function formatPatchCount(count) {
|
|
27
|
-
return
|
|
28
|
+
return formatCountLabel(count, 'patch', 'patches');
|
|
28
29
|
}
|
|
29
30
|
export function registerSuggestSearchReplaceTool(server) {
|
|
30
31
|
registerStructuredToolTask(server, {
|