Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions src/analyzers/DeepCodeReasonerV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@
private createErrorResult(error: Error, context: ClaudeCodeContext): DeepAnalysisResult {
// Extract structured error information
const errorDetails = this.extractErrorDetails(error);

return {
status: 'partial',
findings: {
Expand All @@ -261,7 +261,7 @@
newInsights: [{
type: 'error',
description: errorDetails.insight,
supporting_evidence: [error.stack || error.message]
supporting_evidence: [error.stack || error.message],
}],
validatedHypotheses: [],
ruledOutApproaches: context.attemptedApproaches,
Expand All @@ -270,13 +270,13 @@
errorType: error.name,
errorCode: errorDetails.code,
errorSource: errorDetails.source,
}
},
};
}

private extractErrorDetails(error: Error): {
description: string;
rootCauses: any[];

Check warning on line 279 in src/analyzers/DeepCodeReasonerV2.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Unexpected any. Specify a different type

Check warning on line 279 in src/analyzers/DeepCodeReasonerV2.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Unexpected any. Specify a different type

Check warning on line 279 in src/analyzers/DeepCodeReasonerV2.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

Unexpected any. Specify a different type
nextSteps: string[];
insight: string;
code?: string;
Expand All @@ -285,71 +285,71 @@
const classification = ErrorClassifier.classify(error);
const nextSteps = ErrorClassifier.getNextSteps(classification);
const message = error.message;

// Map classification to detailed error structure
switch (classification.category) {
case 'api':
return {
description: classification.description,
rootCauses: [{
type: classification.code === 'RATE_LIMIT_ERROR' ? 'performance' : 'configuration',
description: classification.code === 'RATE_LIMIT_ERROR'
description: classification.code === 'RATE_LIMIT_ERROR'
? 'API rate limit or quota exceeded'
: 'Gemini API authentication or configuration issue',
location: { file: 'ConversationalGeminiService.ts', line: 0 },
evidence: [message]
evidence: [message],
}],
nextSteps,
insight: classification.code === 'RATE_LIMIT_ERROR'
? 'The system is making too many API requests in a short time period'
: 'The Gemini API service is not properly configured or authenticated',
code: classification.code,
source: 'external_api'
source: 'external_api',
};

case 'filesystem':
return {
description: classification.description,
rootCauses: [{
type: 'architecture',
description: 'File access or permission issue',
location: { file: 'CodeReader.ts', line: 0 },
evidence: [message]
evidence: [message],
}],
nextSteps,
insight: 'The code reader cannot access required files',
code: classification.code || 'FILE_ACCESS_ERROR',
source: 'filesystem'
source: 'filesystem',
};

case 'session':
return {
description: classification.description,
rootCauses: [{
type: 'architecture',
description: 'Conversation session state issue',
location: { file: 'ConversationManager.ts', line: 0 },
evidence: [message]
evidence: [message],
}],
nextSteps,
insight: 'The conversation session is in an invalid state or does not exist',
code: classification.code || 'SESSION_ERROR',
source: 'internal'
source: 'internal',
};

default:
return {
description: classification.description,
rootCauses: [{
type: 'unknown',
description: error.name || 'Unknown error',
location: { file: 'unknown', line: 0 },
evidence: [message, error.stack || '']
evidence: [message, error.stack || ''],
}],
nextSteps,
insight: 'An unexpected error occurred during deep code analysis',
code: 'UNKNOWN_ERROR',
source: 'unknown'
source: 'unknown',
};
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
export class SessionError extends Error {
readonly code: string;
readonly sessionId?: string;

constructor(message: string, code: string = 'SESSION_ERROR', sessionId?: string) {
super(message);
this.name = 'SessionError';
Expand All @@ -18,7 +18,7 @@ export class ApiError extends Error {
readonly code: string;
readonly statusCode?: number;
readonly service: string;

constructor(message: string, code: string = 'API_ERROR', service: string = 'unknown', statusCode?: number) {
super(message);
this.name = 'ApiError';
Expand All @@ -32,7 +32,7 @@ export class FileSystemError extends Error {
readonly code: string;
readonly path?: string;
readonly operation?: string;

constructor(message: string, code: string = 'FS_ERROR', path?: string, operation?: string) {
super(message);
this.name = 'FileSystemError';
Expand All @@ -44,7 +44,7 @@ export class FileSystemError extends Error {

export class RateLimitError extends ApiError {
readonly retryAfter?: number;

constructor(message: string, service: string = 'gemini', retryAfter?: number) {
super(message, 'RATE_LIMIT_ERROR', service, 429);
this.name = 'RateLimitError';
Expand Down
42 changes: 21 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { z } from 'zod';
import * as dotenv from 'dotenv';

import { DeepCodeReasonerV2 } from './analyzers/DeepCodeReasonerV2.js';
import type { ClaudeCodeContext, CodeScope } from './models/types.js';
import type { ClaudeCodeContext } from './models/types.js';
import { ErrorClassifier } from './utils/ErrorClassifier.js';
import { InputValidator } from './utils/InputValidator.js';

Expand Down Expand Up @@ -406,10 +406,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (name) {
case 'escalate_analysis': {
const parsed = EscalateAnalysisSchema.parse(args);

// Validate and sanitize the Claude context
const validatedContext = InputValidator.validateClaudeContext(parsed.claude_context);

// Override with specific values from the parsed input
const context: ClaudeCodeContext = {
...validatedContext,
Expand All @@ -434,7 +434,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {

case 'trace_execution_path': {
const parsed = TraceExecutionPathSchema.parse(args);

// Validate the entry point file path
const validatedPath = InputValidator.validateFilePaths([parsed.entry_point.file])[0];
if (!validatedPath) {
Expand All @@ -443,7 +443,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
'Invalid entry point file path',
);
}

const result = await deepReasoner.traceExecutionPath(
{ ...parsed.entry_point, file: validatedPath },
parsed.max_depth,
Expand All @@ -462,7 +462,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {

case 'hypothesis_test': {
const parsed = HypothesisTestSchema.parse(args);

// Validate file paths
const validatedFiles = InputValidator.validateFilePaths(parsed.code_scope.files);
if (validatedFiles.length === 0) {
Expand All @@ -471,7 +471,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
'No valid file paths provided',
);
}

const result = await deepReasoner.testHypothesis(
InputValidator.validateString(parsed.hypothesis, 2000),
validatedFiles,
Expand All @@ -490,7 +490,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {

case 'cross_system_impact': {
const parsed = CrossSystemImpactSchema.parse(args);

// Validate file paths
const validatedFiles = InputValidator.validateFilePaths(parsed.change_scope.files);
if (validatedFiles.length === 0) {
Expand All @@ -499,7 +499,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
'No valid file paths provided',
);
}

const result = await deepReasoner.analyzeCrossSystemImpact(
validatedFiles,
parsed.impact_types,
Expand All @@ -517,7 +517,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {

case 'performance_bottleneck': {
const parsed = PerformanceBottleneckSchema.parse(args);

// Validate the entry point file path
const validatedPath = InputValidator.validateFilePaths([parsed.code_path.entry_point.file])[0];
if (!validatedPath) {
Expand All @@ -526,12 +526,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
'Invalid entry point file path',
);
}

const result = await deepReasoner.analyzePerformance(
{ ...parsed.code_path.entry_point, file: validatedPath },
parsed.profile_depth,
parsed.code_path.suspected_issues ?
InputValidator.validateStringArray(parsed.code_path.suspected_issues) :
parsed.code_path.suspected_issues ?
InputValidator.validateStringArray(parsed.code_path.suspected_issues) :
undefined,
);

Expand All @@ -547,10 +547,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {

case 'start_conversation': {
const parsed = StartConversationSchema.parse(args);

// Validate and sanitize the Claude context
const validatedContext = InputValidator.validateClaudeContext(parsed.claude_context);

// Override default budget
const context: ClaudeCodeContext = {
...validatedContext,
Expand Down Expand Up @@ -637,30 +637,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
`Invalid parameters: ${error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`,
);
}

// Use ErrorClassifier for consistent error handling
if (error instanceof Error) {
const classification = ErrorClassifier.classify(error);

switch (classification.category) {
case 'session':
throw new McpError(
ErrorCode.InvalidRequest,
classification.description,
);

case 'api':
throw new McpError(
ErrorCode.InternalError,
classification.description,
);

case 'filesystem':
throw new McpError(
ErrorCode.InvalidRequest,
classification.description,
);

default:
console.error('Unhandled error in request handler:', error);
throw new McpError(
Expand All @@ -669,7 +669,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
);
}
}

throw error;
}
});
Expand Down
6 changes: 3 additions & 3 deletions src/services/ConversationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,20 @@ export class ConversationManager {
acquireLock(sessionId: string): boolean {
const session = this.sessions.get(sessionId);
if (!session) return false;

// Check if session has timed out
if (Date.now() - session.lastActivity > this.SESSION_TIMEOUT_MS) {
session.status = 'abandoned';
return false;
}

// Only acquire lock if session is active
if (session.status === 'active') {
session.status = 'processing';
session.lastActivity = Date.now();
return true;
}

return false;
}

Expand Down
8 changes: 4 additions & 4 deletions src/services/ConversationalGeminiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
ClaudeCodeContext,
DeepAnalysisResult,
} from '../models/types.js';
import { SessionError, SessionNotFoundError } from '../errors/index.js';
import { SessionNotFoundError } from '../errors/index.js';
import { PromptSanitizer } from '../utils/PromptSanitizer.js';

export interface ConversationContext {
Expand Down Expand Up @@ -107,7 +107,7 @@

// Sanitize the incoming message
const sanitizedMessage = PromptSanitizer.sanitizeString(message);

// Check for potential injection attempts
if (PromptSanitizer.containsInjectionAttempt(message)) {
console.warn(`Potential injection attempt in session ${sessionId}:`, message.substring(0, 100));
Expand Down Expand Up @@ -235,7 +235,7 @@
break;
}

const userData: Record<string, any> = {

Check warning on line 238 in src/services/ConversationalGeminiService.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Unexpected any. Specify a different type

Check warning on line 238 in src/services/ConversationalGeminiService.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Unexpected any. Specify a different type

Check warning on line 238 in src/services/ConversationalGeminiService.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

Unexpected any. Specify a different type
'Code Files': codeFiles.join('\n\n'),
'Analysis Focus': analysisFocus,
};
Expand Down Expand Up @@ -329,12 +329,12 @@
const line = parseInt(lineNum);
const start = Math.max(0, line - 3);
const end = Math.min(lines.length, line + 3);

// Use safe formatting for code snippets
const snippet = lines.slice(start, end).join('\n');
enrichedParts.push(PromptSanitizer.formatFileContent(
`${file} (lines ${start + 1}-${end})`,
snippet
snippet,
));
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/services/GeminiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
Analysis type requested: ${analysisType}`;

// Prepare sanitized user data
const userData: Record<string, any> = {

Check warning on line 70 in src/services/GeminiService.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Unexpected any. Specify a different type

Check warning on line 70 in src/services/GeminiService.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Unexpected any. Specify a different type

Check warning on line 70 in src/services/GeminiService.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

Unexpected any. Specify a different type
'Attempted Approaches': PromptSanitizer.sanitizeStringArray(context.attemptedApproaches),
'Stuck Points': PromptSanitizer.sanitizeStringArray(context.stuckPoints),
'Partial Findings': PromptSanitizer.createSafeObjectRepresentation(context.partialFindings),
Expand Down Expand Up @@ -361,7 +361,7 @@
}

const userData = {
'Code Files for Analysis': codeFileData.join('\n\n')
'Code Files for Analysis': codeFileData.join('\n\n'),
};

const prompt = PromptSanitizer.createSafePrompt(systemInstructions, userData);
Expand Down Expand Up @@ -393,7 +393,7 @@

const userData = {
'Files with Changes': PromptSanitizer.sanitizeStringArray(changeScope),
'Code Files for Analysis': codeFileData.join('\n\n')
'Code Files for Analysis': codeFileData.join('\n\n'),
};

const prompt = PromptSanitizer.createSafePrompt(systemInstructions, userData);
Expand Down Expand Up @@ -426,7 +426,7 @@

const userData = {
'Suspected Issues': PromptSanitizer.sanitizeStringArray(suspectedIssues),
'Code Files for Analysis': codeFileData.join('\n\n')
'Code Files for Analysis': codeFileData.join('\n\n'),
};

const prompt = PromptSanitizer.createSafePrompt(systemInstructions, userData);
Expand Down Expand Up @@ -460,7 +460,7 @@
const userData = {
'Hypothesis': PromptSanitizer.sanitizeString(hypothesis),
'Test Approach': PromptSanitizer.sanitizeString(testApproach),
'Code Files for Analysis': codeFileData.join('\n\n')
'Code Files for Analysis': codeFileData.join('\n\n'),
};

const prompt = PromptSanitizer.createSafePrompt(systemInstructions, userData);
Expand Down
Loading