stack.ts•4.55 kB
import { z } from 'zod';
import { Logger } from '../server/logger';
import { MetricsCollector } from '../server/metrics';
import { DapStackTraceRequest } from '../schemas/dap-tools.schemas';
// Type definitions for missing exports
interface StackFrame {
id: number;
name: string;
source: {
name?: string;
path?: string;
};
line: number;
column: number;
endLine?: number;
endColumn?: number;
}
interface DapStackTraceResponse {
type: 'response';
seq: number;
command: 'stackTrace';
request_seq: number;
success: boolean;
message?: string;
body: {
stackFrames: StackFrame[];
totalFrames?: number;
error?: string;
};
}
/**
* dap.stackTrace tool implementation
*
* Retrieves stack trace for a given thread
*/
export class DapStackTraceTool {
private logger: Logger;
private metrics: MetricsCollector;
constructor() {
this.logger = new Logger('dap.stackTrace');
this.metrics = MetricsCollector.getInstance();
}
/**
* Execute the dap.stackTrace tool
*/
async execute(args: any): Promise<any> {
this.metrics.startTimer('dap.stackTrace.tool');
this.metrics.increment('dap.stackTrace.count');
try {
// Validate input
const validatedArgs = this.validateArgs(args);
this.logger.debug('Getting stack trace', {
threadId: validatedArgs.threadId,
startFrame: validatedArgs.startFrame,
levels: validatedArgs.levels,
});
// Get stack trace from debugging adapter
const stackFrames = await this.getStackTrace(validatedArgs);
this.logger.info('Stack trace retrieved', {
threadId: validatedArgs.threadId,
frameCount: stackFrames.length,
});
this.metrics.stopTimer('dap.stackTrace.tool');
return this.createSuccessResponse({
stackFrames,
totalFrames: stackFrames.length,
});
} catch (error) {
this.logger.error('dap.stackTrace failed:', error);
this.metrics.increment('dap.stackTrace.error.count');
this.metrics.stopTimer('dap.stackTrace.tool');
return this.createErrorResponse((error as Error).message);
}
}
/**
* Validate input arguments
*/
private validateArgs(args: any): DapStackTraceRequest['arguments'] {
const schema = z.object({
threadId: z.number(),
startFrame: z.number().default(0),
levels: z.number().optional(),
});
const parsed = schema.parse(args);
return {
...parsed,
__type__: 'StackTraceArguments' as const,
};
}
/**
* Get stack trace from debugging session
*/
private async getStackTrace(args: DapStackTraceRequest['arguments']): Promise<StackFrame[]> {
// Mock implementation - in real implementation this would query the debugging adapter
const stackFrames: StackFrame[] = [
{
id: 0,
name: 'main',
source: {
path: '/project/main.js',
name: 'main.js',
},
line: 1,
column: 1,
endLine: 1,
endColumn: 10,
},
{
id: 1,
name: 'processData',
source: {
path: '/project/utils.js',
name: 'utils.js',
},
line: 25,
column: 5,
endLine: 30,
endColumn: 15,
},
{
id: 2,
name: 'handleRequest',
source: {
path: '/project/server.js',
name: 'server.js',
},
line: 50,
column: 8,
endLine: 55,
endColumn: 20,
},
];
// Apply pagination if requested
if (args.levels && args.levels > 0) {
return stackFrames.slice(0, args.levels);
}
return stackFrames;
}
/**
* Create success response
*/
private createSuccessResponse(body: any): DapStackTraceResponse {
return {
type: 'response',
seq: 1,
command: 'stackTrace',
request_seq: 1,
success: true,
body,
};
}
/**
* Create error response
*/
private createErrorResponse(message: string): DapStackTraceResponse {
return {
type: 'response',
seq: 1,
command: 'stackTrace',
request_seq: 1,
success: false,
message,
body: {
stackFrames: [],
error: 'Failed to get stack trace',
},
};
}
}
// Singleton instance
export const dapStackTraceTool = new DapStackTraceTool();
// Tool execution function
export async function executeDapStackTrace(args: any): Promise<DapStackTraceResponse> {
return await dapStackTraceTool.execute(args);
}