variables.ts•4.76 kB
import { z } from 'zod';
import { Logger } from '../server/logger';
import { MetricsCollector } from '../server/metrics';
import { DapVariablesRequest, DapVariablesResponse, Variable } from '../schemas/dap-tools.schemas';
/**
* dap.variables tool implementation
*
* Retrieves variables for a given variables reference
*/
export class DapVariablesTool {
private logger: Logger;
private metrics: MetricsCollector;
constructor() {
this.logger = new Logger('dap.variables');
this.metrics = MetricsCollector.getInstance();
}
/**
* Execute the dap.variables tool
*/
async execute(args: any): Promise<DapVariablesResponse> {
this.metrics.startTimer('dap.variables.tool');
this.metrics.increment('dap.variables.count');
try {
// Validate input
const validatedArgs = this.validateArgs(args);
this.logger.debug('Getting variables', {
variablesReference: validatedArgs.variablesReference,
filter: validatedArgs.filter,
start: validatedArgs.start,
count: validatedArgs.count,
});
// Get variables from debugging adapter
const variables = await this.getVariables(validatedArgs);
this.logger.info('Variables retrieved', {
variablesReference: validatedArgs.variablesReference,
variableCount: variables.length,
});
this.metrics.stopTimer('dap.variables.tool');
return this.createSuccessResponse({
variables,
});
} catch (error) {
this.logger.error('dap.variables failed:', error);
this.metrics.increment('dap.variables.error.count');
this.metrics.stopTimer('dap.variables.tool');
return this.createErrorResponse((error as Error).message);
}
}
/**
* Validate input arguments
*/
private validateArgs(args: any): DapVariablesRequest['arguments'] {
const schema = z.object({
variablesReference: z.number(),
filter: z.enum(['indexed', 'named']).optional(),
start: z.number().default(0),
count: z.number().optional(),
});
const parsed = schema.parse(args);
return {
...parsed,
__type__: 'VariablesArguments' as const,
};
}
/**
* Get variables from debugging session
*/
private async getVariables(args: DapVariablesRequest['arguments']): Promise<Variable[]> {
// Mock implementation - in real implementation this would query the debugging adapter
const variables: Variable[] = [
{
name: 'this',
value: 'Object',
type: 'Object',
variablesReference: 1,
evaluateName: 'this',
presentationHint: { kind: 'class' },
},
{
name: 'message',
value: '"Hello, World!"',
type: 'String',
variablesReference: 0,
evaluateName: 'message',
presentationHint: { kind: 'data' },
},
{
name: 'count',
value: '42',
type: 'Number',
variablesReference: 0,
evaluateName: 'count',
presentationHint: { kind: 'data' },
},
{
name: 'isActive',
value: 'true',
type: 'Boolean',
variablesReference: 0,
evaluateName: 'isActive',
presentationHint: { kind: 'data' },
},
{
name: 'users',
value: 'Array[3]',
type: 'Array',
variablesReference: 2,
evaluateName: 'users',
indexedVariables: 3,
namedVariables: 0,
presentationHint: { kind: 'data' },
},
];
// Apply filter if specified
if (args.filter === 'indexed') {
return variables.filter(v => v.variablesReference === 0);
} else if (args.filter === 'named') {
return variables.filter(v => v.variablesReference > 0);
}
// Apply pagination if requested
if (args.count && args.count > 0) {
return variables.slice(args.start || 0, (args.start || 0) + args.count);
}
return variables;
}
/**
* Create success response
*/
private createSuccessResponse(body: any): DapVariablesResponse {
return {
type: 'response' as const,
seq: 1,
command: 'variables',
request_seq: 1,
success: true,
body,
};
}
/**
* Create error response
*/
private createErrorResponse(message: string): DapVariablesResponse {
return {
type: 'response' as const,
seq: 1,
command: 'variables',
request_seq: 1,
success: false,
message,
body: {
variables: [],
},
};
}
}
// Singleton instance
export const dapVariablesTool = new DapVariablesTool();
// Tool execution function
export async function executeDapVariables(args: any): Promise<DapVariablesResponse> {
return await dapVariablesTool.execute(args);
}