@j0hanz/code-assistant 0.9.0
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/README.md +437 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +72 -0
- package/dist/lib/concurrency.d.ts +13 -0
- package/dist/lib/concurrency.js +77 -0
- package/dist/lib/config.d.ts +43 -0
- package/dist/lib/config.js +87 -0
- package/dist/lib/diff.d.ts +49 -0
- package/dist/lib/diff.js +241 -0
- package/dist/lib/errors.d.ts +8 -0
- package/dist/lib/errors.js +69 -0
- package/dist/lib/format.d.ts +14 -0
- package/dist/lib/format.js +33 -0
- package/dist/lib/gemini.d.ts +45 -0
- package/dist/lib/gemini.js +833 -0
- package/dist/lib/progress.d.ts +72 -0
- package/dist/lib/progress.js +204 -0
- package/dist/lib/tools.d.ts +274 -0
- package/dist/lib/tools.js +646 -0
- package/dist/prompts/index.d.ts +11 -0
- package/dist/prompts/index.js +96 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.js +115 -0
- package/dist/resources/instructions.d.ts +1 -0
- package/dist/resources/instructions.js +71 -0
- package/dist/resources/server-config.d.ts +1 -0
- package/dist/resources/server-config.js +75 -0
- package/dist/resources/tool-catalog.d.ts +1 -0
- package/dist/resources/tool-catalog.js +30 -0
- package/dist/resources/tool-info.d.ts +5 -0
- package/dist/resources/tool-info.js +105 -0
- package/dist/resources/workflows.d.ts +1 -0
- package/dist/resources/workflows.js +59 -0
- package/dist/schemas/inputs.d.ts +21 -0
- package/dist/schemas/inputs.js +46 -0
- package/dist/schemas/outputs.d.ts +121 -0
- package/dist/schemas/outputs.js +162 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +88 -0
- package/dist/tools/analyze-complexity.d.ts +2 -0
- package/dist/tools/analyze-complexity.js +50 -0
- package/dist/tools/analyze-pr-impact.d.ts +2 -0
- package/dist/tools/analyze-pr-impact.js +62 -0
- package/dist/tools/detect-api-breaking.d.ts +2 -0
- package/dist/tools/detect-api-breaking.js +49 -0
- package/dist/tools/generate-diff.d.ts +2 -0
- package/dist/tools/generate-diff.js +140 -0
- package/dist/tools/generate-review-summary.d.ts +2 -0
- package/dist/tools/generate-review-summary.js +71 -0
- package/dist/tools/generate-test-plan.d.ts +2 -0
- package/dist/tools/generate-test-plan.js +67 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +19 -0
- package/package.json +79 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { createErrorToolResponse } from './tools.js';
|
|
2
|
+
export declare const STEP_STARTING = 0;
|
|
3
|
+
export declare const STEP_VALIDATING = 1;
|
|
4
|
+
export declare const STEP_BUILDING_PROMPT = 2;
|
|
5
|
+
export declare const STEP_CALLING_MODEL = 3;
|
|
6
|
+
export declare const STEP_VALIDATING_RESPONSE = 4;
|
|
7
|
+
export declare const STEP_FINALIZING = 5;
|
|
8
|
+
export declare const TASK_PROGRESS_TOTAL: number;
|
|
9
|
+
export declare const INPUT_VALIDATION_FAILED = "Input validation failed";
|
|
10
|
+
export declare const DEFAULT_PROGRESS_CONTEXT = "request";
|
|
11
|
+
type ProgressToken = string | number;
|
|
12
|
+
interface ProgressNotificationParams {
|
|
13
|
+
progressToken: ProgressToken;
|
|
14
|
+
progress: number;
|
|
15
|
+
total?: number;
|
|
16
|
+
message?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ProgressPayload {
|
|
19
|
+
current: number;
|
|
20
|
+
total?: number;
|
|
21
|
+
message?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ProgressExtra {
|
|
24
|
+
_meta?: {
|
|
25
|
+
progressToken?: unknown;
|
|
26
|
+
};
|
|
27
|
+
sendNotification: (notification: {
|
|
28
|
+
method: 'notifications/progress';
|
|
29
|
+
params: ProgressNotificationParams;
|
|
30
|
+
}) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare function getOrCreateProgressReporter(extra: ProgressExtra): (payload: ProgressPayload) => Promise<void>;
|
|
33
|
+
export declare function normalizeProgressContext(context: string | undefined): string;
|
|
34
|
+
export declare function formatProgressStep(toolName: string, context: string, metadata: string): string;
|
|
35
|
+
export declare function formatProgressCompletion(toolName: string, context: string, outcome: string): string;
|
|
36
|
+
export declare function createFailureStatusMessage(outcome: 'failed' | 'cancelled', errorMessage: string): string;
|
|
37
|
+
export declare function extractValidationMessage(validationError: ReturnType<typeof createErrorToolResponse>): string;
|
|
38
|
+
export declare function sendSingleStepProgress(extra: ProgressExtra, toolName: string, context: string, current: 0 | 1, state: 'starting' | 'completed' | 'failed' | 'cancelled'): Promise<void>;
|
|
39
|
+
export declare function reportProgressStepUpdate(reportProgress: (payload: ProgressPayload) => Promise<void>, toolName: string, context: string, current: number, metadata: string): Promise<void>;
|
|
40
|
+
export declare function reportProgressCompletionUpdate(reportProgress: (payload: ProgressPayload) => Promise<void>, toolName: string, context: string, outcome: string): Promise<void>;
|
|
41
|
+
export declare function reportSchemaRetryProgressBestEffort(reportProgress: (payload: ProgressPayload) => Promise<void>, toolName: string, context: string, retryCount: number, maxRetries: number): Promise<void>;
|
|
42
|
+
export interface TaskStatusReporter {
|
|
43
|
+
updateStatus: (message: string) => Promise<void>;
|
|
44
|
+
storeResult?: (status: 'completed' | 'failed', result: {
|
|
45
|
+
isError?: boolean;
|
|
46
|
+
content: {
|
|
47
|
+
type: string;
|
|
48
|
+
text: string;
|
|
49
|
+
}[];
|
|
50
|
+
}) => Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export declare class RunReporter {
|
|
53
|
+
private readonly toolName;
|
|
54
|
+
private readonly reportProgress;
|
|
55
|
+
private readonly statusReporter;
|
|
56
|
+
private progressContext;
|
|
57
|
+
private lastStatusMessage;
|
|
58
|
+
constructor(toolName: string, reportProgress: (payload: ProgressPayload) => Promise<void>, statusReporter: TaskStatusReporter, progressContext: string);
|
|
59
|
+
updateStatus(message: string): Promise<void>;
|
|
60
|
+
storeResultSafely(status: 'completed' | 'failed', result: {
|
|
61
|
+
isError?: boolean;
|
|
62
|
+
content: {
|
|
63
|
+
type: string;
|
|
64
|
+
text: string;
|
|
65
|
+
}[];
|
|
66
|
+
}, onLog: (level: string, data: unknown) => Promise<void>): Promise<void>;
|
|
67
|
+
reportStep(step: number, message: string): Promise<void>;
|
|
68
|
+
reportCompletion(outcome: string): Promise<void>;
|
|
69
|
+
reportSchemaRetry(retryCount: number, maxRetries: number): Promise<void>;
|
|
70
|
+
updateContext(newContext: string): void;
|
|
71
|
+
}
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { getErrorMessage } from './errors.js';
|
|
2
|
+
// Named progress step indices for 7-step progress (0–6).
|
|
3
|
+
export const STEP_STARTING = 0;
|
|
4
|
+
export const STEP_VALIDATING = 1;
|
|
5
|
+
export const STEP_BUILDING_PROMPT = 2;
|
|
6
|
+
export const STEP_CALLING_MODEL = 3;
|
|
7
|
+
export const STEP_VALIDATING_RESPONSE = 4;
|
|
8
|
+
export const STEP_FINALIZING = 5;
|
|
9
|
+
export const TASK_PROGRESS_TOTAL = STEP_FINALIZING + 1;
|
|
10
|
+
export const INPUT_VALIDATION_FAILED = 'Input validation failed';
|
|
11
|
+
export const DEFAULT_PROGRESS_CONTEXT = 'request';
|
|
12
|
+
const progressReporterCache = new WeakMap();
|
|
13
|
+
class ProgressReporter {
|
|
14
|
+
extra;
|
|
15
|
+
progressToken;
|
|
16
|
+
lastCurrent = -1;
|
|
17
|
+
didSendTerminal = false;
|
|
18
|
+
constructor(extra, progressToken) {
|
|
19
|
+
this.extra = extra;
|
|
20
|
+
this.progressToken = progressToken;
|
|
21
|
+
}
|
|
22
|
+
async report(payload) {
|
|
23
|
+
if (this.didSendTerminal) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let { current } = payload;
|
|
27
|
+
if (current <= this.lastCurrent && current < (payload.total ?? Infinity)) {
|
|
28
|
+
current = this.lastCurrent + 0.01;
|
|
29
|
+
}
|
|
30
|
+
current = Math.max(current, this.lastCurrent);
|
|
31
|
+
const total = payload.total !== undefined
|
|
32
|
+
? Math.max(payload.total, current)
|
|
33
|
+
: undefined;
|
|
34
|
+
const progressPayload = { current };
|
|
35
|
+
if (total !== undefined) {
|
|
36
|
+
progressPayload.total = total;
|
|
37
|
+
}
|
|
38
|
+
if (payload.message !== undefined) {
|
|
39
|
+
progressPayload.message = payload.message;
|
|
40
|
+
}
|
|
41
|
+
const params = {
|
|
42
|
+
progressToken: this.progressToken,
|
|
43
|
+
progress: progressPayload.current,
|
|
44
|
+
...(progressPayload.total !== undefined
|
|
45
|
+
? { total: progressPayload.total }
|
|
46
|
+
: {}),
|
|
47
|
+
...(progressPayload.message !== undefined
|
|
48
|
+
? { message: progressPayload.message }
|
|
49
|
+
: {}),
|
|
50
|
+
};
|
|
51
|
+
await this.extra
|
|
52
|
+
.sendNotification({ method: 'notifications/progress', params })
|
|
53
|
+
.catch(() => {
|
|
54
|
+
// Progress notifications are best-effort; never fail tool execution.
|
|
55
|
+
});
|
|
56
|
+
this.lastCurrent = current;
|
|
57
|
+
if (total !== undefined && total === current) {
|
|
58
|
+
this.didSendTerminal = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function createProgressReporter(extra) {
|
|
63
|
+
const rawToken = extra._meta?.progressToken;
|
|
64
|
+
if (typeof rawToken !== 'string' && typeof rawToken !== 'number') {
|
|
65
|
+
return async () => {
|
|
66
|
+
// Request did not provide a progress token.
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const reporter = new ProgressReporter(extra, rawToken);
|
|
70
|
+
return (payload) => reporter.report(payload);
|
|
71
|
+
}
|
|
72
|
+
export function getOrCreateProgressReporter(extra) {
|
|
73
|
+
const cached = progressReporterCache.get(extra);
|
|
74
|
+
if (cached) {
|
|
75
|
+
return cached;
|
|
76
|
+
}
|
|
77
|
+
const created = createProgressReporter(extra);
|
|
78
|
+
progressReporterCache.set(extra, created);
|
|
79
|
+
return created;
|
|
80
|
+
}
|
|
81
|
+
export function normalizeProgressContext(context) {
|
|
82
|
+
const compact = context?.replace(/\s+/g, ' ').trim();
|
|
83
|
+
if (!compact) {
|
|
84
|
+
return DEFAULT_PROGRESS_CONTEXT;
|
|
85
|
+
}
|
|
86
|
+
if (compact.length <= 80) {
|
|
87
|
+
return compact;
|
|
88
|
+
}
|
|
89
|
+
return `${compact.slice(0, 77)}...`;
|
|
90
|
+
}
|
|
91
|
+
export function formatProgressStep(toolName, context, metadata) {
|
|
92
|
+
return formatProgressMessage(toolName, context, metadata);
|
|
93
|
+
}
|
|
94
|
+
export function formatProgressCompletion(toolName, context, outcome) {
|
|
95
|
+
return formatProgressMessage(toolName, context, outcome);
|
|
96
|
+
}
|
|
97
|
+
function formatProgressMessage(toolName, context, metadata) {
|
|
98
|
+
return `${toolName}: ${context} [${metadata}]`;
|
|
99
|
+
}
|
|
100
|
+
export function createFailureStatusMessage(outcome, errorMessage) {
|
|
101
|
+
if (outcome === 'cancelled') {
|
|
102
|
+
return `cancelled: ${errorMessage}`;
|
|
103
|
+
}
|
|
104
|
+
return errorMessage;
|
|
105
|
+
}
|
|
106
|
+
function tryParseErrorMessage(text) {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(text);
|
|
109
|
+
return parsed.error?.message;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function extractValidationMessage(validationError) {
|
|
116
|
+
const text = validationError.content.at(0)?.text;
|
|
117
|
+
if (!text)
|
|
118
|
+
return INPUT_VALIDATION_FAILED;
|
|
119
|
+
return tryParseErrorMessage(text) ?? INPUT_VALIDATION_FAILED;
|
|
120
|
+
}
|
|
121
|
+
export async function sendSingleStepProgress(extra, toolName, context, current, state) {
|
|
122
|
+
const reporter = getOrCreateProgressReporter(extra);
|
|
123
|
+
await reporter({
|
|
124
|
+
current,
|
|
125
|
+
total: 1,
|
|
126
|
+
message: current === 0
|
|
127
|
+
? formatProgressStep(toolName, context, state)
|
|
128
|
+
: formatProgressCompletion(toolName, context, state),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
export async function reportProgressStepUpdate(reportProgress, toolName, context, current, metadata) {
|
|
132
|
+
await reportProgress({
|
|
133
|
+
current,
|
|
134
|
+
total: TASK_PROGRESS_TOTAL,
|
|
135
|
+
message: formatProgressStep(toolName, context, metadata),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
export async function reportProgressCompletionUpdate(reportProgress, toolName, context, outcome) {
|
|
139
|
+
await reportProgress({
|
|
140
|
+
current: TASK_PROGRESS_TOTAL,
|
|
141
|
+
total: TASK_PROGRESS_TOTAL,
|
|
142
|
+
message: formatProgressCompletion(toolName, context, outcome),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
export async function reportSchemaRetryProgressBestEffort(reportProgress, toolName, context, retryCount, maxRetries) {
|
|
146
|
+
try {
|
|
147
|
+
await reportProgressStepUpdate(reportProgress, toolName, context, STEP_VALIDATING_RESPONSE + retryCount / (maxRetries + 1), `Schema repair in progress (attempt ${retryCount}/${maxRetries})...`);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Progress updates are best-effort and must not interrupt retries.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export class RunReporter {
|
|
154
|
+
toolName;
|
|
155
|
+
reportProgress;
|
|
156
|
+
statusReporter;
|
|
157
|
+
progressContext;
|
|
158
|
+
lastStatusMessage;
|
|
159
|
+
constructor(toolName, reportProgress, statusReporter, progressContext) {
|
|
160
|
+
this.toolName = toolName;
|
|
161
|
+
this.reportProgress = reportProgress;
|
|
162
|
+
this.statusReporter = statusReporter;
|
|
163
|
+
this.progressContext = progressContext;
|
|
164
|
+
}
|
|
165
|
+
async updateStatus(message) {
|
|
166
|
+
if (this.lastStatusMessage === message) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
await this.statusReporter.updateStatus(message);
|
|
171
|
+
this.lastStatusMessage = message;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Best-effort
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async storeResultSafely(status, result, onLog) {
|
|
178
|
+
if (!this.statusReporter.storeResult) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await this.statusReporter.storeResult(status, result);
|
|
183
|
+
}
|
|
184
|
+
catch (storeErr) {
|
|
185
|
+
await onLog('error', {
|
|
186
|
+
event: 'store_result_failed',
|
|
187
|
+
error: getErrorMessage(storeErr),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async reportStep(step, message) {
|
|
192
|
+
await reportProgressStepUpdate(this.reportProgress, this.toolName, this.progressContext, step, message);
|
|
193
|
+
await this.updateStatus(message);
|
|
194
|
+
}
|
|
195
|
+
async reportCompletion(outcome) {
|
|
196
|
+
await reportProgressCompletionUpdate(this.reportProgress, this.toolName, this.progressContext, outcome);
|
|
197
|
+
}
|
|
198
|
+
async reportSchemaRetry(retryCount, maxRetries) {
|
|
199
|
+
await reportSchemaRetryProgressBestEffort(this.reportProgress, this.toolName, this.progressContext, retryCount, maxRetries);
|
|
200
|
+
}
|
|
201
|
+
updateContext(newContext) {
|
|
202
|
+
this.progressContext = newContext;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZodRawShapeCompat } from '@modelcontextprotocol/sdk/server/zod-compat.js';
|
|
3
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { type DiffSlot } from './diff.js';
|
|
6
|
+
import { type DiffStats, type ParsedFile } from './diff.js';
|
|
7
|
+
import { type ProgressExtra, type ProgressPayload, type TaskStatusReporter } from './progress.js';
|
|
8
|
+
export type ErrorKind = 'validation' | 'budget' | 'upstream' | 'timeout' | 'cancelled' | 'internal' | 'busy';
|
|
9
|
+
export interface ErrorMeta {
|
|
10
|
+
retryable?: boolean;
|
|
11
|
+
kind?: ErrorKind;
|
|
12
|
+
}
|
|
13
|
+
interface ToolError {
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
retryable?: boolean;
|
|
17
|
+
kind?: ErrorKind;
|
|
18
|
+
}
|
|
19
|
+
interface ToolTextContent {
|
|
20
|
+
type: 'text';
|
|
21
|
+
text: string;
|
|
22
|
+
}
|
|
23
|
+
interface ToolStructuredContent {
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
ok: boolean;
|
|
26
|
+
result?: unknown;
|
|
27
|
+
error?: ToolError;
|
|
28
|
+
}
|
|
29
|
+
interface ToolResponse<TStructuredContent extends ToolStructuredContent> {
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
content: ToolTextContent[];
|
|
32
|
+
structuredContent: TStructuredContent;
|
|
33
|
+
}
|
|
34
|
+
interface ErrorToolResponse {
|
|
35
|
+
[key: string]: unknown;
|
|
36
|
+
content: ToolTextContent[];
|
|
37
|
+
isError: true;
|
|
38
|
+
}
|
|
39
|
+
export declare function createToolResponse<TStructuredContent extends ToolStructuredContent>(structured: TStructuredContent, textContent?: string): ToolResponse<TStructuredContent>;
|
|
40
|
+
export declare function createErrorToolResponse(code: string, message: string, result?: unknown, meta?: ErrorMeta): ErrorToolResponse;
|
|
41
|
+
export declare const INSPECTION_FOCUS_AREAS: readonly ["security", "correctness", "performance", "regressions", "tests", "maintainability", "concurrency"];
|
|
42
|
+
export interface ToolParameterContract {
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
required: boolean;
|
|
46
|
+
constraints: string;
|
|
47
|
+
description: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ToolContract {
|
|
50
|
+
name: string;
|
|
51
|
+
purpose: string;
|
|
52
|
+
/** Set to 'none' for synchronous (non-Gemini) tools. */
|
|
53
|
+
model: string;
|
|
54
|
+
/** Set to 0 for synchronous (non-Gemini) tools. */
|
|
55
|
+
timeoutMs: number;
|
|
56
|
+
thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
|
|
57
|
+
/** Set to 0 for synchronous (non-Gemini) tools. */
|
|
58
|
+
maxOutputTokens: number;
|
|
59
|
+
/**
|
|
60
|
+
* Sampling temperature for the Gemini call.
|
|
61
|
+
* Gemini 3 recommends 1.0 for all tasks.
|
|
62
|
+
*/
|
|
63
|
+
temperature?: number;
|
|
64
|
+
/** Enables deterministic JSON guidance and schema key ordering. */
|
|
65
|
+
deterministicJson?: boolean;
|
|
66
|
+
params: readonly ToolParameterContract[];
|
|
67
|
+
outputShape: string;
|
|
68
|
+
gotchas: readonly string[];
|
|
69
|
+
crossToolFlow: readonly string[];
|
|
70
|
+
constraints?: readonly string[];
|
|
71
|
+
}
|
|
72
|
+
interface StructuredToolRuntimeOptions {
|
|
73
|
+
thinkingLevel?: NonNullable<ToolContract['thinkingLevel']>;
|
|
74
|
+
temperature?: NonNullable<ToolContract['temperature']>;
|
|
75
|
+
deterministicJson?: NonNullable<ToolContract['deterministicJson']>;
|
|
76
|
+
}
|
|
77
|
+
interface StructuredToolExecutionOptions extends StructuredToolRuntimeOptions {
|
|
78
|
+
timeoutMs: ToolContract['timeoutMs'];
|
|
79
|
+
maxOutputTokens: ToolContract['maxOutputTokens'];
|
|
80
|
+
}
|
|
81
|
+
export declare function buildStructuredToolRuntimeOptions(contract: Pick<ToolContract, 'thinkingLevel' | 'temperature' | 'deterministicJson'>): StructuredToolRuntimeOptions;
|
|
82
|
+
export declare function buildStructuredToolExecutionOptions(contract: Pick<ToolContract, 'timeoutMs' | 'maxOutputTokens' | 'thinkingLevel' | 'temperature' | 'deterministicJson'>): StructuredToolExecutionOptions;
|
|
83
|
+
export declare const TOOL_CONTRACTS: readonly [{
|
|
84
|
+
readonly name: "generate_diff";
|
|
85
|
+
readonly purpose: "Generate a diff of current changes and cache it server-side. MUST be called before any other tool. Uses git to capture unstaged or staged changes in the current working directory.";
|
|
86
|
+
readonly model: "none";
|
|
87
|
+
readonly timeoutMs: 0;
|
|
88
|
+
readonly maxOutputTokens: 0;
|
|
89
|
+
readonly params: ToolParameterContract[];
|
|
90
|
+
readonly outputShape: "{ok, result: {diffRef, stats{files, added, deleted}, generatedAt, mode, message}}";
|
|
91
|
+
readonly gotchas: readonly ["Must be called first — all other tools return E_NO_DIFF if no diff is cached.", "Noisy files (lock files, dist/, build/, minified assets) are excluded automatically.", "Empty diff (no changes) returns E_NO_CHANGES."];
|
|
92
|
+
readonly crossToolFlow: readonly ["Caches diff at diff://current — consumed automatically by all review tools."];
|
|
93
|
+
}, {
|
|
94
|
+
readonly name: "analyze_pr_impact";
|
|
95
|
+
readonly purpose: "Assess severity, categories, breaking changes, and rollback complexity.";
|
|
96
|
+
readonly model: "gemini-3-flash-preview";
|
|
97
|
+
readonly timeoutMs: 90000;
|
|
98
|
+
readonly thinkingLevel: "minimal";
|
|
99
|
+
readonly maxOutputTokens: 65536;
|
|
100
|
+
readonly temperature: 1;
|
|
101
|
+
readonly deterministicJson: true;
|
|
102
|
+
readonly params: ToolParameterContract[];
|
|
103
|
+
readonly outputShape: "{severity, categories[], summary, breakingChanges[], affectedAreas[], rollbackComplexity}";
|
|
104
|
+
readonly gotchas: readonly ["Requires generate_diff to be called first.", "Flash triage tool optimized for speed."];
|
|
105
|
+
readonly crossToolFlow: readonly ["severity/categories feed triage and merge-gate decisions."];
|
|
106
|
+
}, {
|
|
107
|
+
readonly name: "generate_review_summary";
|
|
108
|
+
readonly purpose: "Produce PR summary, risk rating, and merge recommendation.";
|
|
109
|
+
readonly model: "gemini-3-flash-preview";
|
|
110
|
+
readonly timeoutMs: 90000;
|
|
111
|
+
readonly thinkingLevel: "minimal";
|
|
112
|
+
readonly maxOutputTokens: 65536;
|
|
113
|
+
readonly temperature: 1;
|
|
114
|
+
readonly deterministicJson: true;
|
|
115
|
+
readonly params: ToolParameterContract[];
|
|
116
|
+
readonly outputShape: "{summary, overallRisk, keyChanges[], recommendation, stats{filesChanged, linesAdded, linesRemoved}}";
|
|
117
|
+
readonly gotchas: readonly ["Requires generate_diff to be called first.", "stats are computed locally from the diff."];
|
|
118
|
+
readonly crossToolFlow: readonly ["Use before deep review to decide whether Pro analysis is needed."];
|
|
119
|
+
}, {
|
|
120
|
+
readonly name: "generate_test_plan";
|
|
121
|
+
readonly purpose: "Generate prioritized test cases and coverage guidance.";
|
|
122
|
+
readonly model: "gemini-3-flash-preview";
|
|
123
|
+
readonly timeoutMs: 90000;
|
|
124
|
+
readonly thinkingLevel: "medium";
|
|
125
|
+
readonly maxOutputTokens: 65536;
|
|
126
|
+
readonly temperature: 1;
|
|
127
|
+
readonly deterministicJson: true;
|
|
128
|
+
readonly params: ToolParameterContract[];
|
|
129
|
+
readonly outputShape: "{summary, testCases[], coverageSummary}";
|
|
130
|
+
readonly gotchas: readonly ["Requires generate_diff to be called first.", "maxTestCases caps output after generation."];
|
|
131
|
+
readonly crossToolFlow: readonly ["Pair with review tools to validate high-risk paths."];
|
|
132
|
+
}, {
|
|
133
|
+
readonly name: "analyze_time_space_complexity";
|
|
134
|
+
readonly purpose: "Analyze Big-O complexity and detect degradations in changed code.";
|
|
135
|
+
readonly model: "gemini-3-flash-preview";
|
|
136
|
+
readonly timeoutMs: 90000;
|
|
137
|
+
readonly thinkingLevel: "medium";
|
|
138
|
+
readonly maxOutputTokens: 65536;
|
|
139
|
+
readonly temperature: 1;
|
|
140
|
+
readonly deterministicJson: true;
|
|
141
|
+
readonly params: ToolParameterContract[];
|
|
142
|
+
readonly outputShape: "{timeComplexity, spaceComplexity, explanation, potentialBottlenecks[], isDegradation}";
|
|
143
|
+
readonly gotchas: readonly ["Requires generate_diff to be called first.", "Analyzes only changed code visible in the diff."];
|
|
144
|
+
readonly crossToolFlow: readonly ["Use for algorithmic/performance-sensitive changes."];
|
|
145
|
+
}, {
|
|
146
|
+
readonly name: "detect_api_breaking_changes";
|
|
147
|
+
readonly purpose: "Detect breaking API/interface changes in a diff.";
|
|
148
|
+
readonly model: "gemini-3-flash-preview";
|
|
149
|
+
readonly timeoutMs: 90000;
|
|
150
|
+
readonly thinkingLevel: "minimal";
|
|
151
|
+
readonly maxOutputTokens: 65536;
|
|
152
|
+
readonly temperature: 1;
|
|
153
|
+
readonly deterministicJson: true;
|
|
154
|
+
readonly params: ToolParameterContract[];
|
|
155
|
+
readonly outputShape: "{hasBreakingChanges, breakingChanges[]}";
|
|
156
|
+
readonly gotchas: readonly ["Requires generate_diff to be called first.", "Targets public API contracts over internal refactors."];
|
|
157
|
+
readonly crossToolFlow: readonly ["Run before merge for API-surface-sensitive changes."];
|
|
158
|
+
}];
|
|
159
|
+
export declare function getToolContracts(): readonly ToolContract[];
|
|
160
|
+
export declare function getToolContract(toolName: string): ToolContract | undefined;
|
|
161
|
+
export declare function requireToolContract(toolName: string): ToolContract;
|
|
162
|
+
export declare function getToolContractNames(): string[];
|
|
163
|
+
export interface PromptParts {
|
|
164
|
+
systemInstruction: string;
|
|
165
|
+
prompt: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Immutable snapshot of server-side state captured once at the start of a
|
|
169
|
+
* tool execution, before `validateInput` runs. Threading it through both
|
|
170
|
+
* `validateInput` and `buildPrompt` eliminates the TOCTOU gap that would
|
|
171
|
+
* otherwise allow a concurrent `generate_diff` call to replace the cached
|
|
172
|
+
* diff between the budget check and prompt assembly.
|
|
173
|
+
*/
|
|
174
|
+
export interface ToolExecutionContext {
|
|
175
|
+
readonly diffSlot: DiffSlot | undefined;
|
|
176
|
+
}
|
|
177
|
+
export interface ToolAnnotations {
|
|
178
|
+
readOnlyHint?: boolean;
|
|
179
|
+
idempotentHint?: boolean;
|
|
180
|
+
openWorldHint?: boolean;
|
|
181
|
+
destructiveHint?: boolean;
|
|
182
|
+
}
|
|
183
|
+
export interface StructuredToolTaskConfig<TInput extends object = Record<string, unknown>, TResult extends object = Record<string, unknown>, TFinal extends TResult = TResult> {
|
|
184
|
+
/** Tool name registered with the MCP server (e.g. 'analyze_pr_impact'). */
|
|
185
|
+
name: string;
|
|
186
|
+
/** Human-readable title shown to clients. */
|
|
187
|
+
title: string;
|
|
188
|
+
/** Short description of the tool's purpose. */
|
|
189
|
+
description: string;
|
|
190
|
+
/** Zod schema or raw shape for MCP request validation at the transport boundary. */
|
|
191
|
+
inputSchema: z.ZodType<TInput> | ZodRawShapeCompat;
|
|
192
|
+
/** Zod schema for validating the complete tool input inside the handler. */
|
|
193
|
+
fullInputSchema: z.ZodType<TInput>;
|
|
194
|
+
/** Zod schema for parsing and validating the Gemini structured response. */
|
|
195
|
+
resultSchema: z.ZodType<TResult>;
|
|
196
|
+
/** Optional Zod schema used specifically for Gemini response validation. */
|
|
197
|
+
geminiSchema?: z.ZodType;
|
|
198
|
+
/** Stable error code returned on failure (e.g. 'E_INSPECT_QUALITY'). */
|
|
199
|
+
errorCode: string;
|
|
200
|
+
/** Optional post-processing hook called after resultSchema.parse(). The return value replaces the parsed result. */
|
|
201
|
+
transformResult?: (input: TInput, result: TResult, ctx: ToolExecutionContext) => TFinal;
|
|
202
|
+
/** Optional validation hook for input parameters. */
|
|
203
|
+
validateInput?: (input: TInput, ctx: ToolExecutionContext) => Promise<ReturnType<typeof createErrorToolResponse> | undefined>;
|
|
204
|
+
/** Optional flag to enforce diff presence and budget check before tool execution. */
|
|
205
|
+
requiresDiff?: boolean;
|
|
206
|
+
/** Optional override for schema validation retries. Defaults to GEMINI_SCHEMA_RETRIES env var. */
|
|
207
|
+
schemaRetries?: number;
|
|
208
|
+
/** Optional thinking level. */
|
|
209
|
+
thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
|
|
210
|
+
/** Optional timeout in ms for the Gemini call. Defaults to 90,000 ms. Use DEFAULT_TIMEOUT_PRO_MS for Pro model calls. */
|
|
211
|
+
timeoutMs?: number;
|
|
212
|
+
/** Optional max output tokens for Gemini. */
|
|
213
|
+
maxOutputTokens?: number;
|
|
214
|
+
/**
|
|
215
|
+
* Optional sampling temperature for this tool's Gemini call.
|
|
216
|
+
* Gemini 3 recommends 1.0 for all tasks.
|
|
217
|
+
*/
|
|
218
|
+
temperature?: number;
|
|
219
|
+
/** Optional opt-in to Gemini thought output. Defaults to false. */
|
|
220
|
+
includeThoughts?: boolean;
|
|
221
|
+
/** Optional deterministic JSON mode for stricter key ordering and repair prompting. */
|
|
222
|
+
deterministicJson?: boolean;
|
|
223
|
+
/** Optional batch execution mode. Defaults to runtime setting. */
|
|
224
|
+
batchMode?: 'off' | 'inline';
|
|
225
|
+
/** Optional formatter for human-readable text output. */
|
|
226
|
+
formatOutput?: (result: TFinal) => string;
|
|
227
|
+
/** Optional context text used in progress messages. */
|
|
228
|
+
progressContext?: (input: TInput) => string;
|
|
229
|
+
/** Optional short outcome suffix for the completion progress message (e.g., "3 findings"). */
|
|
230
|
+
formatOutcome?: (result: TFinal) => string;
|
|
231
|
+
/** Optional MCP annotation overrides for this tool. */
|
|
232
|
+
annotations?: ToolAnnotations;
|
|
233
|
+
/** Builds the system instruction and user prompt from parsed tool input. */
|
|
234
|
+
buildPrompt: (input: TInput, ctx: ToolExecutionContext) => PromptParts;
|
|
235
|
+
}
|
|
236
|
+
export declare function summarizeSchemaValidationErrorForRetry(errorMessage: string): string;
|
|
237
|
+
export declare function wrapToolHandler<TInput, TResult extends CallToolResult>(options: {
|
|
238
|
+
toolName: string;
|
|
239
|
+
progressContext?: (input: TInput) => string;
|
|
240
|
+
}, handler: (input: TInput, extra: ProgressExtra) => Promise<TResult> | TResult): (input: TInput, extra: ProgressExtra) => Promise<TResult>;
|
|
241
|
+
export declare class ToolExecutionRunner<TInput extends object, TResult extends object, TFinal extends TResult> {
|
|
242
|
+
private readonly config;
|
|
243
|
+
private readonly signal?;
|
|
244
|
+
private diffSlotSnapshot;
|
|
245
|
+
private hasSnapshot;
|
|
246
|
+
private responseSchema;
|
|
247
|
+
private readonly onLog;
|
|
248
|
+
private reporter;
|
|
249
|
+
constructor(config: StructuredToolTaskConfig<TInput, TResult, TFinal>, dependencies: {
|
|
250
|
+
onLog: (level: string, data: unknown) => Promise<void>;
|
|
251
|
+
reportProgress: (payload: ProgressPayload) => Promise<void>;
|
|
252
|
+
statusReporter: TaskStatusReporter;
|
|
253
|
+
}, signal?: AbortSignal | undefined);
|
|
254
|
+
private handleInternalLog;
|
|
255
|
+
setResponseSchemaOverride(responseSchema: Record<string, unknown>): void;
|
|
256
|
+
setDiffSlotSnapshot(diffSlotSnapshot: DiffSlot | undefined): void;
|
|
257
|
+
private executeValidation;
|
|
258
|
+
private executeModelCallAttempt;
|
|
259
|
+
private executeModelCall;
|
|
260
|
+
private createExecutionContext;
|
|
261
|
+
private applyResultTransform;
|
|
262
|
+
private formatResultText;
|
|
263
|
+
private finalizeSuccessfulRun;
|
|
264
|
+
private handleRunFailure;
|
|
265
|
+
run(input: unknown): Promise<CallToolResult>;
|
|
266
|
+
}
|
|
267
|
+
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;
|
|
268
|
+
export interface DiffContextSnapshot {
|
|
269
|
+
diff: string;
|
|
270
|
+
parsedFiles: readonly ParsedFile[];
|
|
271
|
+
stats: Readonly<DiffStats>;
|
|
272
|
+
}
|
|
273
|
+
export declare function getDiffContextSnapshot(ctx: ToolExecutionContext): DiffContextSnapshot;
|
|
274
|
+
export {};
|