mcp-server-debug-thinking
Version:
Graph-based MCP server for systematic debugging using Problem-Solution Trees and Hypothesis-Experiment-Learning cycles
777 lines • 32.8 kB
JavaScript
import path from 'path';
import os from 'os';
import chalk from 'chalk';
import { SearchIndex } from './SearchIndex.js';
import { logger } from '../utils/logger.js';
import { formatDebugStep, createJsonResponse } from '../utils/format.js';
import { ensureDirectory, writeJsonFile, appendJsonLine, readJsonLines, readJsonLinesStream, fileExists } from '../utils/storage.js';
import { DATA_DIR_NAME, METADATA_FILE, ERROR_MESSAGES, DEFAULT_SEARCH_LIMIT, MIN_SEARCH_LIMIT, MAX_SEARCH_LIMIT, SESSIONS_JSONL_FILE, ERROR_PATTERNS_JSONL_FILE, SUCCESSFUL_FIXES_JSONL_FILE } from '../constants.js';
import { createThinkingWorkflow } from '../utils/sequentialThinkingIntegration.js';
export class DebugServer {
debugSessions = new Map();
errorPatterns = [];
successfulFixes = [];
currentSessionId = null;
dataDir;
searchIndex = new SearchIndex();
constructor() {
const baseDir = process.env.DEBUG_DATA_DIR || os.homedir();
this.dataDir = path.join(baseDir, DATA_DIR_NAME);
}
async initialize() {
await this.initializeStorage();
}
async initializeStorage() {
try {
await ensureDirectory(this.dataDir);
await this.loadKnowledge();
logger.dim(`📁 Using data directory: ${this.dataDir}`);
}
catch (error) {
logger.error('Failed to initialize storage:', error);
}
}
async loadKnowledge() {
// Load error patterns from JSONL
const errorPatternsPath = path.join(this.dataDir, ERROR_PATTERNS_JSONL_FILE);
this.errorPatterns = await readJsonLines(errorPatternsPath);
if (this.errorPatterns.length > 0) {
logger.success(`✓ Loaded ${this.errorPatterns.length} error patterns`);
}
// Load successful fixes from JSONL
const fixesPath = path.join(this.dataDir, SUCCESSFUL_FIXES_JSONL_FILE);
this.successfulFixes = await readJsonLines(fixesPath);
if (this.successfulFixes.length > 0) {
logger.success(`✓ Loaded ${this.successfulFixes.length} successful fixes`);
}
// Load saved sessions into search index
await this.loadSessionsIntoIndex();
}
async loadSessionsIntoIndex() {
let loadedSessions = 0;
// Load from JSONL file
const sessionsJsonlPath = path.join(this.dataDir, SESSIONS_JSONL_FILE);
if (await fileExists(sessionsJsonlPath)) {
for await (const savedSession of readJsonLinesStream(sessionsJsonlPath)) {
try {
const session = {
id: savedSession.id,
startTime: new Date(savedSession.startTime),
problem: savedSession.problem,
steps: savedSession.steps.map((step) => ({
...step,
timestamp: new Date(step.timestamp)
})),
metadata: savedSession.metadata,
thoughtHistory: savedSession.thoughtHistory || [],
branches: savedSession.branches || {},
currentBranch: savedSession.currentBranch
};
this.searchIndex.addSession(session.id, session);
loadedSessions++;
}
catch (err) {
logger.warn(`Failed to load session from JSONL:`, err);
}
}
}
if (loadedSessions > 0) {
logger.success(`✓ Loaded ${loadedSessions} sessions into search index`);
}
}
async saveKnowledge() {
// Note: With JSONL, we append data incrementally in learnFromResult
// This method now only updates metadata
await writeJsonFile(path.join(this.dataDir, METADATA_FILE), {
lastUpdated: new Date().toISOString(),
totalPatterns: this.errorPatterns.length,
totalFixes: this.successfulFixes.length,
totalSessions: await this.countSessions(),
});
}
async countSessions() {
const sessionsPath = path.join(this.dataDir, SESSIONS_JSONL_FILE);
if (!await fileExists(sessionsPath))
return 0;
let count = 0;
for await (const _ of readJsonLinesStream(sessionsPath)) {
count++;
}
return count;
}
async saveSession(sessionId) {
const session = this.debugSessions.get(sessionId);
if (!session)
return;
const sessionData = {
id: sessionId,
startTime: session.startTime,
endTime: new Date(),
problem: session.problem,
steps: session.steps,
metadata: session.metadata,
summary: {
totalSteps: session.steps.length,
successfulFixes: session.steps.filter((s) => s.result?.success).length,
finalStatus: session.steps[session.steps.length - 1]?.nextAction || 'incomplete',
},
};
// Append to JSONL file
const sessionsPath = path.join(this.dataDir, SESSIONS_JSONL_FILE);
await appendJsonLine(sessionsPath, sessionData);
}
generateId() {
return `debug-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
}
async learnFromResult(step, sessionProblem) {
if (!step.result)
return;
const problem = step.problem || sessionProblem;
// Learn from errors
if (problem?.errorMessage && !step.result.success && step.hypothesis && step.experiment) {
const existingPattern = this.errorPatterns.find((p) => p.pattern === problem.errorMessage);
if (existingPattern) {
existingPattern.occurrences++;
// For JSONL, we need to rewrite the entire file to update occurrences
// In a production system, you might want to use a database instead
}
else {
const newPattern = {
pattern: problem.errorMessage,
commonCause: step.hypothesis.cause,
suggestedFix: step.experiment?.changes[0]?.reasoning || '',
occurrences: 1,
};
this.errorPatterns.push(newPattern);
// Append to JSONL file
const errorPatternsPath = path.join(this.dataDir, ERROR_PATTERNS_JSONL_FILE);
await appendJsonLine(errorPatternsPath, newPattern);
}
}
// Record successful fixes
if (step.result.success && step.experiment) {
const newFix = {
problemId: step.id,
solution: step.result.learning,
changes: step.experiment.changes,
verified: true,
};
this.successfulFixes.push(newFix);
// Append to JSONL file
const fixesPath = path.join(this.dataDir, SUCCESSFUL_FIXES_JSONL_FILE);
await appendJsonLine(fixesPath, newFix);
}
// Update metadata
await this.saveKnowledge().catch(error => logger.error('Failed to save knowledge:', error));
}
startSession(sessionId, problem, metadata) {
const id = sessionId || this.generateId();
// Normalize metadata
const normalizedMetadata = metadata ? {
language: metadata.language?.toLowerCase(),
framework: metadata.framework?.toLowerCase(),
tags: metadata.tags?.map(tag => tag.toLowerCase())
} : undefined;
const session = {
id,
startTime: new Date(),
problem,
steps: [],
metadata: normalizedMetadata,
thoughtHistory: [],
branches: {},
currentBranch: undefined
};
this.debugSessions.set(id, session);
this.currentSessionId = id;
this.searchIndex.addSession(id, session);
logger.session('start', id);
if (problem) {
logger.info(chalk.yellow(`📋 Problem: ${problem.description}`));
}
if (normalizedMetadata) {
const metaInfo = [];
if (normalizedMetadata.language)
metaInfo.push(`Lang: ${normalizedMetadata.language}`);
if (normalizedMetadata.framework)
metaInfo.push(`Framework: ${normalizedMetadata.framework}`);
if (normalizedMetadata.tags?.length)
metaInfo.push(`Tags: ${normalizedMetadata.tags.join(', ')}`);
if (metaInfo.length > 0) {
logger.dim(`🏷️ ${metaInfo.join(' | ')}`);
}
}
return id;
}
async recordStep(input) {
try {
const data = input;
if (!this.currentSessionId) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
solution: "Please start a session first with action: 'start_session'",
}, true);
}
const step = {
id: this.generateId(),
timestamp: new Date(),
};
if (data.problem)
step.problem = data.problem;
if (data.hypothesis)
step.hypothesis = data.hypothesis;
if (data.experiment)
step.experiment = data.experiment;
if (data.result)
step.result = data.result;
if (data.nextAction)
step.nextAction = data.nextAction;
if (!step.problem && !step.hypothesis && !step.experiment && !step.result) {
throw new Error(ERROR_MESSAGES.AT_LEAST_ONE_FIELD_REQUIRED);
}
const validStep = step;
const session = this.debugSessions.get(this.currentSessionId);
if (!session) {
throw new Error(ERROR_MESSAGES.SESSION_NOT_FOUND);
}
session.steps.push(validStep);
// Update search index
this.searchIndex.removeSession(this.currentSessionId);
this.searchIndex.addSession(this.currentSessionId, session);
if (validStep.result) {
await this.learnFromResult(validStep, session.problem);
}
if (validStep.hypothesis || validStep.experiment) {
logger.info(formatDebugStep(validStep, session.problem));
}
// Check for known patterns
let patternMatch = null;
const problemToCheck = validStep.problem || session.problem;
if (problemToCheck?.errorMessage) {
patternMatch = this.errorPatterns.find((p) => problemToCheck.errorMessage?.includes(p.pattern));
}
return createJsonResponse({
stepId: step.id,
sessionId: this.currentSessionId,
recorded: true,
nextAction: step.nextAction,
patternMatch: patternMatch ? {
pattern: patternMatch.pattern,
suggestedCause: patternMatch.commonCause,
previousOccurrences: patternMatch.occurrences,
} : null,
sessionSteps: session?.steps.length || 0,
knownPatterns: this.errorPatterns.length,
successfulFixes: this.successfulFixes.length,
});
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error('Error in recordStep:', errorMessage);
return createJsonResponse({
error: errorMessage,
status: 'failed',
details: 'Please ensure all required fields are provided',
}, true);
}
}
async getSessionSummary(sessionId) {
const id = sessionId || this.currentSessionId;
if (!id) {
return createJsonResponse({ error: ERROR_MESSAGES.NO_ACTIVE_SESSION });
}
let session = this.debugSessions.get(id);
if (!session) {
// Try to find in JSONL file
const sessionsPath = path.join(this.dataDir, SESSIONS_JSONL_FILE);
if (await fileExists(sessionsPath)) {
for await (const savedSession of readJsonLinesStream(sessionsPath)) {
if (savedSession.id === id) {
session = {
id: savedSession.id,
startTime: new Date(savedSession.startTime),
problem: savedSession.problem,
steps: savedSession.steps.map((step) => ({
...step,
timestamp: new Date(step.timestamp)
})),
metadata: savedSession.metadata,
thoughtHistory: savedSession.thoughtHistory || [],
branches: savedSession.branches || {},
currentBranch: savedSession.currentBranch
};
break;
}
}
}
}
if (!session) {
return createJsonResponse({
error: ERROR_MESSAGES.SESSION_NOT_FOUND,
sessionId: id,
hint: 'Session not found in active sessions or saved history'
});
}
const summary = {
sessionId: id,
sessionProblem: session.problem,
totalSteps: session.steps.length,
successfulFixes: session.steps.filter((s) => s.result?.success).length,
experimentsRepeated: session.steps.filter((s) => s.nextAction === 'iterate').length,
pivots: session.steps.filter((s) => s.nextAction === 'pivot').length,
averageConfidence: session.steps.length > 0
? session.steps.reduce((acc, s) => acc + (s.hypothesis?.confidence || 0), 0) /
session.steps.length
: 0,
problemsSolved: session.steps
.filter((s) => s.nextAction === 'fixed')
.map((s) => ({
hypothesis: s.hypothesis?.cause,
solution: s.result?.learning,
})),
};
return createJsonResponse(summary);
}
async endSession(sessionId) {
const id = sessionId || this.currentSessionId;
if (!id) {
return createJsonResponse({ error: ERROR_MESSAGES.NO_SESSION_TO_END });
}
try {
await this.saveSession(id);
await this.saveKnowledge();
const session = this.debugSessions.get(id);
const summary = {
sessionId: id,
ended: new Date().toISOString(),
totalSteps: session?.steps.length || 0,
saved: true,
dataLocation: this.dataDir,
};
// Remove from active sessions only (keep in search index)
this.debugSessions.delete(id);
if (this.currentSessionId === id) {
this.currentSessionId = null;
}
logger.session('end', id);
return createJsonResponse(summary);
}
catch (error) {
return createJsonResponse({
error: error instanceof Error ? error.message : String(error),
status: 'failed',
});
}
}
async listSessions() {
try {
const sessionsPath = path.join(this.dataDir, SESSIONS_JSONL_FILE);
const sessions = [];
if (await fileExists(sessionsPath)) {
for await (const session of readJsonLinesStream(sessionsPath)) {
sessions.push({
id: session.id,
startTime: session.startTime,
endTime: session.endTime,
totalSteps: session.summary.totalSteps,
status: session.summary.finalStatus,
});
}
}
return createJsonResponse({
activeSessions: Array.from(this.debugSessions.keys()),
savedSessions: sessions,
totalSessions: sessions.length,
});
}
catch (error) {
return createJsonResponse({
error: error instanceof Error ? error.message : String(error),
sessions: [],
});
}
}
searchPatterns(query) {
try {
logger.search(query, 0);
// Validate query
if (!query || typeof query !== 'object') {
return createJsonResponse({
error: ERROR_MESSAGES.INVALID_SEARCH_QUERY,
status: 'failed',
example: {
errorType: 'TypeError',
keywords: ['undefined', 'property'],
language: 'javascript',
searchMode: 'fuzzy',
includeDebugInfo: true
}
});
}
// Check if query has at least one search criterion
const hasSearchCriteria = query.errorType ||
(query.keywords && query.keywords.length > 0) ||
query.language ||
query.framework ||
query.confidence_threshold !== undefined;
if (!hasSearchCriteria) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_SEARCH_CRITERIA,
status: 'failed',
providedQuery: query
});
}
const limit = query.limit || DEFAULT_SEARCH_LIMIT;
// Validate limit
if (limit < MIN_SEARCH_LIMIT || limit > MAX_SEARCH_LIMIT) {
return createJsonResponse({
error: ERROR_MESSAGES.INVALID_LIMIT,
status: 'failed',
providedLimit: limit
});
}
const matches = this.searchIndex.search(query, limit);
if (query.includeDebugInfo && matches.length > 0) {
const debugInfo = matches[0].debugInfo;
if (debugInfo) {
logger.dim(` Total searched: ${debugInfo.totalSessionsSearched}`);
logger.dim(` Keyword matches: ${debugInfo.keywordMatches}`);
logger.dim(` Filtered by metadata: ${debugInfo.filteredByMetadata}`);
logger.dim(` Filtered by confidence: ${debugInfo.filteredByConfidence}`);
}
}
logger.success(`✓ Found ${matches.length} matches`);
return createJsonResponse({
query,
matches,
totalMatches: matches.length,
status: 'success'
});
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error('Error in searchPatterns:', errorMessage);
return createJsonResponse({
error: errorMessage,
status: 'failed',
hint: 'Check the error message and ensure your search query is properly formatted.'
});
}
}
getActiveSessionIds() {
return Array.from(this.debugSessions.keys());
}
async saveAllKnowledge() {
return this.saveKnowledge();
}
recordThinking(sessionId, thinkingSteps) {
const id = sessionId || this.currentSessionId;
if (!id) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
hint: "Start a session first before recording thinking steps"
}, true);
}
const session = this.debugSessions.get(id);
if (!session) {
return createJsonResponse({ error: ERROR_MESSAGES.SESSION_NOT_FOUND }, true);
}
// Add thinking steps to the latest step or create a new one
const lastStep = session.steps[session.steps.length - 1];
if (lastStep && !lastStep.result) {
// Add to existing step if it doesn't have a result yet
lastStep.thinkingSteps = [...(lastStep.thinkingSteps || []), ...thinkingSteps];
}
else {
// Create a new step with just thinking steps
const newStep = {
id: this.generateId(),
timestamp: new Date(),
thinkingSteps: thinkingSteps
};
session.steps.push(newStep);
}
// Update search index
this.searchIndex.removeSession(id);
this.searchIndex.addSession(id, session);
return createJsonResponse({
sessionId: id,
recorded: true,
thinkingStepsCount: thinkingSteps.length,
totalSteps: session.steps.length
});
}
convertThinkingToHypothesis(sessionId, thinkingConclusion, confidence) {
const id = sessionId || this.currentSessionId;
if (!id) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
hint: "Start a session first"
}, true);
}
const session = this.debugSessions.get(id);
if (!session) {
return createJsonResponse({ error: ERROR_MESSAGES.SESSION_NOT_FOUND }, true);
}
// Find the latest step with thinking steps but no hypothesis
const stepWithThinking = [...session.steps].reverse().find(step => step.thinkingSteps && step.thinkingSteps.length > 0 && !step.hypothesis);
if (!stepWithThinking) {
return createJsonResponse({
error: "No thinking steps found to convert to hypothesis",
hint: "Record thinking steps first using record_thinking action"
}, true);
}
// Create hypothesis from thinking conclusion
const hypothesis = {
cause: thinkingConclusion,
affectedCode: [], // To be filled by the user
confidence: confidence || 70, // Default confidence
thinkingChain: stepWithThinking.thinkingSteps,
thoughtConclusion: thinkingConclusion
};
stepWithThinking.hypothesis = hypothesis;
// Update search index
this.searchIndex.removeSession(id);
this.searchIndex.addSession(id, session);
return createJsonResponse({
sessionId: id,
stepId: stepWithThinking.id,
hypothesis: hypothesis,
hint: "Now add affected code and create an experiment to test this hypothesis"
});
}
// New simplified methods
start(params) {
const sessionId = this.generateId();
const problem = params.problem ? {
description: params.problem,
errorMessage: params.context?.error || '',
expectedBehavior: '',
actualBehavior: ''
} : undefined;
const metadata = params.context ? {
language: params.context.language,
framework: params.context.framework,
tags: params.context.tags
} : undefined;
this.startSession(sessionId, problem, metadata);
return createJsonResponse({
sessionId,
status: 'started',
message: `Debug session ${sessionId} started`
});
}
think(params) {
if (!this.currentSessionId) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
hint: "Start a session first"
}, true);
}
const session = this.debugSessions.get(this.currentSessionId);
if (!session) {
return createJsonResponse({ error: ERROR_MESSAGES.SESSION_NOT_FOUND }, true);
}
// Validate thought number sequence
if (params.thoughtNumber !== session.thoughtHistory.length + 1 && !params.isRevision && !params.branchFromThought) {
return createJsonResponse({
error: `Invalid thought number. Expected ${session.thoughtHistory.length + 1}, got ${params.thoughtNumber}`,
hint: "Thoughts must be sequential unless revising or branching"
}, true);
}
// Create thinking step
const thinkingStep = {
thought: params.thought,
thoughtNumber: params.thoughtNumber,
totalThoughts: params.totalThoughts,
timestamp: new Date(),
isRevision: params.isRevision,
revisesThought: params.revisesThought,
branchFromThought: params.branchFromThought,
branchId: params.branchId
};
// Handle branching
if (params.branchFromThought && params.branchId) {
if (!session.branches[params.branchId]) {
session.branches[params.branchId] = [];
}
session.branches[params.branchId].push(thinkingStep);
session.currentBranch = params.branchId;
}
else {
// Add to main thought history
session.thoughtHistory.push(thinkingStep);
}
// If this is the last thought, generate hypothesis
if (!params.nextThoughtNeeded) {
// Use the utility function to create hypothesis from thought history
const allThoughts = session.currentBranch
? [...session.thoughtHistory, ...session.branches[session.currentBranch]]
: session.thoughtHistory;
const { hypothesis } = createThinkingWorkflow(allThoughts.map(t => ({
thought: t.thought,
nextThoughtNeeded: false,
thoughtNumber: t.thoughtNumber,
totalThoughts: t.totalThoughts,
isRevision: t.isRevision,
revisesThought: t.revisesThought,
branchFromThought: t.branchFromThought,
branchId: t.branchId
})));
// Create a new step with the hypothesis
const step = {
id: this.generateId(),
timestamp: new Date(),
thinkingSteps: allThoughts,
hypothesis: hypothesis
};
session.steps.push(step);
// Update search index
this.searchIndex.removeSession(this.currentSessionId);
this.searchIndex.addSession(this.currentSessionId, session);
return createJsonResponse({
thoughtNumber: params.thoughtNumber,
totalThoughts: params.totalThoughts,
nextThoughtNeeded: false,
hypothesis: hypothesis.cause,
confidence: hypothesis.confidence,
affectedCode: hypothesis.affectedCode,
suggestedAction: hypothesis.affectedCode.length > 0 ? 'experiment' : 'add affected code',
branches: Object.keys(session.branches),
thoughtHistoryLength: session.thoughtHistory.length
});
}
// Update search index
this.searchIndex.removeSession(this.currentSessionId);
this.searchIndex.addSession(this.currentSessionId, session);
return createJsonResponse({
thoughtNumber: params.thoughtNumber,
totalThoughts: params.totalThoughts,
nextThoughtNeeded: true,
branches: Object.keys(session.branches),
thoughtHistoryLength: session.thoughtHistory.length
});
}
experiment(params) {
if (!this.currentSessionId) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
hint: "Start a session first"
}, true);
}
const session = this.debugSessions.get(this.currentSessionId);
if (!session) {
return createJsonResponse({ error: ERROR_MESSAGES.SESSION_NOT_FOUND }, true);
}
// Find the latest step with hypothesis but no experiment
const stepForExperiment = [...session.steps].reverse().find(step => step.hypothesis && !step.experiment);
if (!stepForExperiment) {
return createJsonResponse({
error: "No hypothesis found to experiment on",
hint: "Use 'think' action first to create a hypothesis"
}, true);
}
const experiment = {
changes: params.changes.map(c => ({
file: c.file,
lineRange: [0, 0], // Simplified - not tracking line ranges
oldCode: '',
newCode: c.change,
reasoning: c.reason
})),
expectedOutcome: params.expected
};
stepForExperiment.experiment = experiment;
// Update search index
this.searchIndex.removeSession(this.currentSessionId);
this.searchIndex.addSession(this.currentSessionId, session);
return createJsonResponse({
stepId: stepForExperiment.id,
experiment: params.description,
changes: params.changes.length,
expected: params.expected
});
}
async observe(params) {
if (!this.currentSessionId) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_ACTIVE_SESSION,
hint: "Start a session first"
}, true);
}
const session = this.debugSessions.get(this.currentSessionId);
if (!session) {
return createJsonResponse({ error: ERROR_MESSAGES.SESSION_NOT_FOUND }, true);
}
// Find the latest step with experiment but no result
const stepForResult = [...session.steps].reverse().find(step => step.experiment && !step.result);
if (!stepForResult) {
return createJsonResponse({
error: "No experiment found to observe results for",
hint: "Use 'experiment' action first"
}, true);
}
const result = {
success: params.success,
output: params.output,
learning: params.learning,
newErrors: []
};
stepForResult.result = result;
stepForResult.nextAction = params.next || (params.success ? 'fixed' : 'iterate');
// Learn from result
await this.learnFromResult(stepForResult, session.problem);
// Update search index
this.searchIndex.removeSession(this.currentSessionId);
this.searchIndex.addSession(this.currentSessionId, session);
return createJsonResponse({
stepId: stepForResult.id,
success: params.success,
learning: params.learning,
nextAction: stepForResult.nextAction,
sessionComplete: stepForResult.nextAction === 'fixed'
});
}
search(params) {
// Convert simplified params to SearchQuery
const searchQuery = {
keywords: params.query.split(' '),
confidence_threshold: params.filters?.confidence,
language: params.filters?.language,
searchMode: 'fuzzy',
keywordLogic: 'OR',
includeDebugInfo: false
};
const limit = params.filters?.limit || DEFAULT_SEARCH_LIMIT;
const matches = this.searchIndex.search(searchQuery, limit);
return createJsonResponse({
query: params.query,
matches: matches.map(m => ({
sessionId: m.sessionId,
similarity: m.similarity,
problem: m.problem.description,
solution: m.solution.learning,
confidence: m.metadata.confidence
})),
total: matches.length
});
}
async end(summary = false) {
if (!this.currentSessionId) {
return createJsonResponse({
error: ERROR_MESSAGES.NO_SESSION_TO_END
}, true);
}
const sessionId = this.currentSessionId;
const session = this.debugSessions.get(sessionId);
if (summary && session) {
const summaryData = await this.getSessionSummary(sessionId);
await this.endSession(sessionId);
return summaryData;
}
else {
return await this.endSession(sessionId);
}
}
}
//# sourceMappingURL=DebugServer.js.map