xdebug-mcp 1.0.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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +341 -0
  3. package/dist/config.d.ts +36 -0
  4. package/dist/config.js +47 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/dbgp/connection.d.ts +52 -0
  7. package/dist/dbgp/connection.js +362 -0
  8. package/dist/dbgp/connection.js.map +1 -0
  9. package/dist/dbgp/index.d.ts +3 -0
  10. package/dist/dbgp/index.js +4 -0
  11. package/dist/dbgp/index.js.map +1 -0
  12. package/dist/dbgp/server.d.ts +34 -0
  13. package/dist/dbgp/server.js +94 -0
  14. package/dist/dbgp/server.js.map +1 -0
  15. package/dist/dbgp/types.d.ts +112 -0
  16. package/dist/dbgp/types.js +28 -0
  17. package/dist/dbgp/types.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.js +93 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/session/code-coverage.d.ts +94 -0
  22. package/dist/session/code-coverage.js +226 -0
  23. package/dist/session/code-coverage.js.map +1 -0
  24. package/dist/session/debug-config.d.ts +102 -0
  25. package/dist/session/debug-config.js +194 -0
  26. package/dist/session/debug-config.js.map +1 -0
  27. package/dist/session/index.d.ts +10 -0
  28. package/dist/session/index.js +11 -0
  29. package/dist/session/index.js.map +1 -0
  30. package/dist/session/logpoint-manager.d.ts +94 -0
  31. package/dist/session/logpoint-manager.js +167 -0
  32. package/dist/session/logpoint-manager.js.map +1 -0
  33. package/dist/session/manager.d.ts +41 -0
  34. package/dist/session/manager.js +135 -0
  35. package/dist/session/manager.js.map +1 -0
  36. package/dist/session/profiler.d.ts +89 -0
  37. package/dist/session/profiler.js +191 -0
  38. package/dist/session/profiler.js.map +1 -0
  39. package/dist/session/request-context.d.ts +50 -0
  40. package/dist/session/request-context.js +182 -0
  41. package/dist/session/request-context.js.map +1 -0
  42. package/dist/session/session-export.d.ts +83 -0
  43. package/dist/session/session-export.js +320 -0
  44. package/dist/session/session-export.js.map +1 -0
  45. package/dist/session/session.d.ts +92 -0
  46. package/dist/session/session.js +369 -0
  47. package/dist/session/session.js.map +1 -0
  48. package/dist/session/step-filter.d.ts +81 -0
  49. package/dist/session/step-filter.js +174 -0
  50. package/dist/session/step-filter.js.map +1 -0
  51. package/dist/session/watch-manager.d.ts +64 -0
  52. package/dist/session/watch-manager.js +137 -0
  53. package/dist/session/watch-manager.js.map +1 -0
  54. package/dist/tools/advanced.d.ts +26 -0
  55. package/dist/tools/advanced.js +502 -0
  56. package/dist/tools/advanced.js.map +1 -0
  57. package/dist/tools/breakpoints.d.ts +6 -0
  58. package/dist/tools/breakpoints.js +308 -0
  59. package/dist/tools/breakpoints.js.map +1 -0
  60. package/dist/tools/execution.d.ts +6 -0
  61. package/dist/tools/execution.js +283 -0
  62. package/dist/tools/execution.js.map +1 -0
  63. package/dist/tools/index.d.ts +31 -0
  64. package/dist/tools/index.js +44 -0
  65. package/dist/tools/index.js.map +1 -0
  66. package/dist/tools/inspection.d.ts +7 -0
  67. package/dist/tools/inspection.js +431 -0
  68. package/dist/tools/inspection.js.map +1 -0
  69. package/dist/tools/session.d.ts +6 -0
  70. package/dist/tools/session.js +164 -0
  71. package/dist/tools/session.js.map +1 -0
  72. package/dist/utils/logger.d.ts +16 -0
  73. package/dist/utils/logger.js +47 -0
  74. package/dist/utils/logger.js.map +1 -0
  75. package/dist/utils/path-mapper.d.ts +13 -0
  76. package/dist/utils/path-mapper.js +56 -0
  77. package/dist/utils/path-mapper.js.map +1 -0
  78. package/package.json +56 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * DBGp Protocol Types
3
+ * Based on: https://xdebug.org/docs/dbgp
4
+ */
5
+ // DBGp error codes
6
+ export const DBGP_ERROR_CODES = {
7
+ PARSE_ERROR: 1,
8
+ DUPLICATE_ARGS: 2,
9
+ INVALID_OPTIONS: 3,
10
+ UNIMPLEMENTED_COMMAND: 4,
11
+ COMMAND_NOT_AVAILABLE: 5,
12
+ FILE_NOT_FOUND: 100,
13
+ STREAM_REDIRECT_FAILED: 101,
14
+ BREAKPOINT_NOT_SET: 200,
15
+ BREAKPOINT_TYPE_NOT_SUPPORTED: 201,
16
+ INVALID_BREAKPOINT_LINE: 202,
17
+ NO_CODE_ON_LINE: 203,
18
+ INVALID_BREAKPOINT_STATE: 204,
19
+ NO_SUCH_BREAKPOINT: 205,
20
+ EXPRESSION_ERROR: 206,
21
+ PROPERTY_NOT_FOUND: 300,
22
+ INVALID_STACK_DEPTH: 301,
23
+ INVALID_CONTEXT: 302,
24
+ ENCODING_NOT_SUPPORTED: 900,
25
+ INTERNAL_ERROR: 998,
26
+ UNKNOWN_ERROR: 999,
27
+ };
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dbgp/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkGH,mBAAmB;AACnB,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,CAAC;IACjB,eAAe,EAAE,CAAC;IAClB,qBAAqB,EAAE,CAAC;IACxB,qBAAqB,EAAE,CAAC;IAExB,cAAc,EAAE,GAAG;IACnB,sBAAsB,EAAE,GAAG;IAE3B,kBAAkB,EAAE,GAAG;IACvB,6BAA6B,EAAE,GAAG;IAClC,uBAAuB,EAAE,GAAG;IAC5B,eAAe,EAAE,GAAG;IACpB,wBAAwB,EAAE,GAAG;IAC7B,kBAAkB,EAAE,GAAG;IACvB,gBAAgB,EAAE,GAAG;IAErB,kBAAkB,EAAE,GAAG;IACvB,mBAAmB,EAAE,GAAG;IACxB,eAAe,EAAE,GAAG;IAEpB,sBAAsB,EAAE,GAAG;IAC3B,cAAc,EAAE,GAAG;IACnB,aAAa,EAAE,GAAG;CACV,CAAC"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Xdebug MCP Server
4
+ *
5
+ * An MCP server that provides PHP debugging capabilities through Xdebug's DBGp protocol.
6
+ */
7
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Xdebug MCP Server
4
+ *
5
+ * An MCP server that provides PHP debugging capabilities through Xdebug's DBGp protocol.
6
+ */
7
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
+ import { loadConfig } from './config.js';
10
+ import { DbgpServer } from './dbgp/server.js';
11
+ import { SessionManager } from './session/manager.js';
12
+ import { registerAllTools, createToolsContext } from './tools/index.js';
13
+ import { logger } from './utils/logger.js';
14
+ async function main() {
15
+ const config = loadConfig();
16
+ logger.info('Starting Xdebug MCP Server...');
17
+ logger.debug('Configuration:', config);
18
+ // Initialize components
19
+ const sessionManager = new SessionManager();
20
+ const dbgpServer = new DbgpServer({
21
+ host: config.dbgpHost,
22
+ port: config.dbgpPort,
23
+ commandTimeout: config.commandTimeout,
24
+ });
25
+ // Handle new Xdebug connections
26
+ dbgpServer.on('connection', async (connection) => {
27
+ logger.info(`New Xdebug connection: ${connection.id}`);
28
+ logger.info(` File: ${connection.initPacket?.fileUri}`);
29
+ logger.info(` IDE Key: ${connection.initPacket?.ideKey}`);
30
+ try {
31
+ const session = await sessionManager.createSession(connection);
32
+ logger.info(`Debug session created: ${session.id}`);
33
+ }
34
+ catch (error) {
35
+ logger.error('Failed to create session:', error);
36
+ connection.close();
37
+ }
38
+ });
39
+ dbgpServer.on('error', (err) => {
40
+ logger.error('DBGp server error:', err);
41
+ });
42
+ // Track session events
43
+ sessionManager.on('sessionEnded', (sessionId) => {
44
+ logger.info(`Session ended: ${sessionId}`);
45
+ });
46
+ // Start DBGp server
47
+ try {
48
+ await dbgpServer.start();
49
+ logger.info(`DBGp server listening on ${config.dbgpHost}:${config.dbgpPort}`);
50
+ }
51
+ catch (error) {
52
+ logger.error('Failed to start DBGp server:', error);
53
+ process.exit(1);
54
+ }
55
+ // Initialize MCP server
56
+ const mcpServer = new McpServer({
57
+ name: 'xdebug-mcp',
58
+ version: '1.0.0',
59
+ });
60
+ // Create tools context with all managers
61
+ const toolsContext = createToolsContext(sessionManager);
62
+ // Load saved debug profiles
63
+ try {
64
+ await toolsContext.configManager.loadProfiles();
65
+ logger.info('Loaded debug profiles');
66
+ }
67
+ catch {
68
+ logger.debug('No saved debug profiles found');
69
+ }
70
+ // Register all debugging tools
71
+ registerAllTools(mcpServer, toolsContext);
72
+ // Connect MCP transport (stdio)
73
+ const transport = new StdioServerTransport();
74
+ await mcpServer.connect(transport);
75
+ logger.info('MCP server connected via stdio');
76
+ // Graceful shutdown
77
+ const shutdown = async () => {
78
+ logger.info('Shutting down...');
79
+ sessionManager.closeAllSessions();
80
+ await dbgpServer.stop();
81
+ process.exit(0);
82
+ };
83
+ process.on('SIGINT', shutdown);
84
+ process.on('SIGTERM', shutdown);
85
+ // Keep the process alive
86
+ logger.info('Xdebug MCP Server is ready');
87
+ logger.info(`Waiting for Xdebug connections on port ${config.dbgpPort}...`);
88
+ }
89
+ main().catch((error) => {
90
+ console.error('Fatal error:', error);
91
+ process.exit(1);
92
+ });
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Code Coverage Tracker
3
+ * Tracks which lines were executed during debugging.
4
+ */
5
+ export interface FileCoverage {
6
+ file: string;
7
+ executedLines: Set<number>;
8
+ totalLines?: number;
9
+ coveragePercent?: number;
10
+ firstHitAt: Date;
11
+ lastHitAt: Date;
12
+ hitCounts: Map<number, number>;
13
+ }
14
+ export interface CoverageReport {
15
+ startedAt: Date;
16
+ endedAt?: Date;
17
+ files: Map<string, FileCoverage>;
18
+ totalFiles: number;
19
+ totalLinesExecuted: number;
20
+ uniqueLinesExecuted: number;
21
+ }
22
+ export declare class CodeCoverageTracker {
23
+ private currentReport;
24
+ private isTracking;
25
+ /**
26
+ * Start tracking code coverage
27
+ */
28
+ startTracking(): CoverageReport;
29
+ /**
30
+ * Stop tracking code coverage
31
+ */
32
+ stopTracking(): CoverageReport | null;
33
+ /**
34
+ * Record a line execution
35
+ */
36
+ recordLineExecution(file: string, line: number): void;
37
+ /**
38
+ * Update statistics for all files
39
+ */
40
+ private updateStatistics;
41
+ /**
42
+ * Set total lines for a file (for percentage calculation)
43
+ */
44
+ setFileTotalLines(file: string, totalLines: number): void;
45
+ /**
46
+ * Get coverage for a specific file
47
+ */
48
+ getFileCoverage(file: string): FileCoverage | undefined;
49
+ /**
50
+ * Get all file coverages
51
+ */
52
+ getAllFileCoverages(): FileCoverage[];
53
+ /**
54
+ * Get uncovered lines for a file
55
+ */
56
+ getUncoveredLines(file: string, totalLines: number): number[];
57
+ /**
58
+ * Get hot spots (most executed lines)
59
+ */
60
+ getHotSpots(limit?: number): Array<{
61
+ file: string;
62
+ line: number;
63
+ hitCount: number;
64
+ }>;
65
+ /**
66
+ * Generate coverage summary
67
+ */
68
+ getSummary(): {
69
+ isTracking: boolean;
70
+ duration?: number;
71
+ totalFiles: number;
72
+ totalLinesExecuted: number;
73
+ uniqueLinesExecuted: number;
74
+ filesSummary: Array<{
75
+ file: string;
76
+ executedLines: number;
77
+ totalLines?: number;
78
+ coveragePercent?: number;
79
+ }>;
80
+ };
81
+ /**
82
+ * Generate text report
83
+ */
84
+ generateReport(): string;
85
+ /**
86
+ * Reset coverage data
87
+ */
88
+ reset(): void;
89
+ /**
90
+ * Export coverage data as JSON
91
+ */
92
+ exportData(): object | null;
93
+ get tracking(): boolean;
94
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Code Coverage Tracker
3
+ * Tracks which lines were executed during debugging.
4
+ */
5
+ import { logger } from '../utils/logger.js';
6
+ export class CodeCoverageTracker {
7
+ currentReport = null;
8
+ isTracking = false;
9
+ /**
10
+ * Start tracking code coverage
11
+ */
12
+ startTracking() {
13
+ this.currentReport = {
14
+ startedAt: new Date(),
15
+ files: new Map(),
16
+ totalFiles: 0,
17
+ totalLinesExecuted: 0,
18
+ uniqueLinesExecuted: 0,
19
+ };
20
+ this.isTracking = true;
21
+ logger.info('Code coverage tracking started');
22
+ return this.currentReport;
23
+ }
24
+ /**
25
+ * Stop tracking code coverage
26
+ */
27
+ stopTracking() {
28
+ if (!this.currentReport)
29
+ return null;
30
+ this.currentReport.endedAt = new Date();
31
+ this.isTracking = false;
32
+ // Calculate final statistics
33
+ this.updateStatistics();
34
+ logger.info('Code coverage tracking stopped');
35
+ return this.currentReport;
36
+ }
37
+ /**
38
+ * Record a line execution
39
+ */
40
+ recordLineExecution(file, line) {
41
+ if (!this.currentReport || !this.isTracking)
42
+ return;
43
+ let fileCoverage = this.currentReport.files.get(file);
44
+ if (!fileCoverage) {
45
+ fileCoverage = {
46
+ file,
47
+ executedLines: new Set(),
48
+ firstHitAt: new Date(),
49
+ lastHitAt: new Date(),
50
+ hitCounts: new Map(),
51
+ };
52
+ this.currentReport.files.set(file, fileCoverage);
53
+ this.currentReport.totalFiles++;
54
+ }
55
+ const wasNew = !fileCoverage.executedLines.has(line);
56
+ fileCoverage.executedLines.add(line);
57
+ fileCoverage.lastHitAt = new Date();
58
+ // Update hit count
59
+ const currentCount = fileCoverage.hitCounts.get(line) || 0;
60
+ fileCoverage.hitCounts.set(line, currentCount + 1);
61
+ this.currentReport.totalLinesExecuted++;
62
+ if (wasNew) {
63
+ this.currentReport.uniqueLinesExecuted++;
64
+ }
65
+ }
66
+ /**
67
+ * Update statistics for all files
68
+ */
69
+ updateStatistics() {
70
+ if (!this.currentReport)
71
+ return;
72
+ for (const coverage of this.currentReport.files.values()) {
73
+ if (coverage.totalLines && coverage.totalLines > 0) {
74
+ coverage.coveragePercent =
75
+ (coverage.executedLines.size / coverage.totalLines) * 100;
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Set total lines for a file (for percentage calculation)
81
+ */
82
+ setFileTotalLines(file, totalLines) {
83
+ if (!this.currentReport)
84
+ return;
85
+ const coverage = this.currentReport.files.get(file);
86
+ if (coverage) {
87
+ coverage.totalLines = totalLines;
88
+ coverage.coveragePercent =
89
+ (coverage.executedLines.size / totalLines) * 100;
90
+ }
91
+ }
92
+ /**
93
+ * Get coverage for a specific file
94
+ */
95
+ getFileCoverage(file) {
96
+ return this.currentReport?.files.get(file);
97
+ }
98
+ /**
99
+ * Get all file coverages
100
+ */
101
+ getAllFileCoverages() {
102
+ if (!this.currentReport)
103
+ return [];
104
+ return Array.from(this.currentReport.files.values());
105
+ }
106
+ /**
107
+ * Get uncovered lines for a file
108
+ */
109
+ getUncoveredLines(file, totalLines) {
110
+ const coverage = this.currentReport?.files.get(file);
111
+ if (!coverage) {
112
+ return Array.from({ length: totalLines }, (_, i) => i + 1);
113
+ }
114
+ const uncovered = [];
115
+ for (let i = 1; i <= totalLines; i++) {
116
+ if (!coverage.executedLines.has(i)) {
117
+ uncovered.push(i);
118
+ }
119
+ }
120
+ return uncovered;
121
+ }
122
+ /**
123
+ * Get hot spots (most executed lines)
124
+ */
125
+ getHotSpots(limit = 10) {
126
+ if (!this.currentReport)
127
+ return [];
128
+ const hotSpots = [];
129
+ for (const [file, coverage] of this.currentReport.files) {
130
+ for (const [line, hitCount] of coverage.hitCounts) {
131
+ hotSpots.push({ file, line, hitCount });
132
+ }
133
+ }
134
+ return hotSpots
135
+ .sort((a, b) => b.hitCount - a.hitCount)
136
+ .slice(0, limit);
137
+ }
138
+ /**
139
+ * Generate coverage summary
140
+ */
141
+ getSummary() {
142
+ if (!this.currentReport) {
143
+ return {
144
+ isTracking: false,
145
+ totalFiles: 0,
146
+ totalLinesExecuted: 0,
147
+ uniqueLinesExecuted: 0,
148
+ filesSummary: [],
149
+ };
150
+ }
151
+ const duration = this.currentReport.endedAt
152
+ ? this.currentReport.endedAt.getTime() - this.currentReport.startedAt.getTime()
153
+ : Date.now() - this.currentReport.startedAt.getTime();
154
+ const filesSummary = Array.from(this.currentReport.files.values()).map((f) => ({
155
+ file: f.file,
156
+ executedLines: f.executedLines.size,
157
+ totalLines: f.totalLines,
158
+ coveragePercent: f.coveragePercent,
159
+ }));
160
+ return {
161
+ isTracking: this.isTracking,
162
+ duration,
163
+ totalFiles: this.currentReport.totalFiles,
164
+ totalLinesExecuted: this.currentReport.totalLinesExecuted,
165
+ uniqueLinesExecuted: this.currentReport.uniqueLinesExecuted,
166
+ filesSummary,
167
+ };
168
+ }
169
+ /**
170
+ * Generate text report
171
+ */
172
+ generateReport() {
173
+ const summary = this.getSummary();
174
+ const lines = [];
175
+ lines.push('=== Code Coverage Report ===');
176
+ lines.push(`Status: ${summary.isTracking ? 'Active' : 'Stopped'}`);
177
+ if (summary.duration) {
178
+ lines.push(`Duration: ${(summary.duration / 1000).toFixed(2)}s`);
179
+ }
180
+ lines.push(`Total files: ${summary.totalFiles}`);
181
+ lines.push(`Unique lines executed: ${summary.uniqueLinesExecuted}`);
182
+ lines.push(`Total line executions: ${summary.totalLinesExecuted}`);
183
+ lines.push('');
184
+ lines.push('--- Per-File Coverage ---');
185
+ for (const file of summary.filesSummary) {
186
+ let coverageStr = `${file.executedLines} lines`;
187
+ if (file.totalLines) {
188
+ coverageStr += ` / ${file.totalLines} (${file.coveragePercent?.toFixed(1)}%)`;
189
+ }
190
+ lines.push(` ${file.file}: ${coverageStr}`);
191
+ }
192
+ return lines.join('\n');
193
+ }
194
+ /**
195
+ * Reset coverage data
196
+ */
197
+ reset() {
198
+ this.currentReport = null;
199
+ this.isTracking = false;
200
+ }
201
+ /**
202
+ * Export coverage data as JSON
203
+ */
204
+ exportData() {
205
+ if (!this.currentReport)
206
+ return null;
207
+ return {
208
+ startedAt: this.currentReport.startedAt.toISOString(),
209
+ endedAt: this.currentReport.endedAt?.toISOString(),
210
+ totalFiles: this.currentReport.totalFiles,
211
+ totalLinesExecuted: this.currentReport.totalLinesExecuted,
212
+ uniqueLinesExecuted: this.currentReport.uniqueLinesExecuted,
213
+ files: Array.from(this.currentReport.files.entries()).map(([file, coverage]) => ({
214
+ file,
215
+ executedLines: Array.from(coverage.executedLines),
216
+ totalLines: coverage.totalLines,
217
+ coveragePercent: coverage.coveragePercent,
218
+ hitCounts: Object.fromEntries(coverage.hitCounts),
219
+ })),
220
+ };
221
+ }
222
+ get tracking() {
223
+ return this.isTracking;
224
+ }
225
+ }
226
+ //# sourceMappingURL=code-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-coverage.js","sourceRoot":"","sources":["../../src/session/code-coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Debug Configuration Manager
3
+ * Saves and restores debug configurations (breakpoints, watches, filters, etc.)
4
+ */
5
+ export interface BreakpointConfig {
6
+ file: string;
7
+ line: number;
8
+ condition?: string;
9
+ hitValue?: number;
10
+ hitCondition?: string;
11
+ enabled: boolean;
12
+ }
13
+ export interface DebugProfile {
14
+ name: string;
15
+ description?: string;
16
+ createdAt: Date;
17
+ updatedAt: Date;
18
+ breakpoints: BreakpointConfig[];
19
+ watchExpressions: string[];
20
+ logpoints: Array<{
21
+ file: string;
22
+ line: number;
23
+ message: string;
24
+ condition?: string;
25
+ }>;
26
+ stepFilters: Array<{
27
+ pattern: string;
28
+ type: 'include' | 'exclude';
29
+ enabled: boolean;
30
+ }>;
31
+ settings: {
32
+ maxDepth?: number;
33
+ maxChildren?: number;
34
+ skipVendor?: boolean;
35
+ };
36
+ }
37
+ export declare class DebugConfigManager {
38
+ private profiles;
39
+ private configDir;
40
+ private activeProfileName;
41
+ constructor(configDir?: string);
42
+ /**
43
+ * Create a new debug profile
44
+ */
45
+ createProfile(name: string, description?: string): DebugProfile;
46
+ /**
47
+ * Get a profile by name
48
+ */
49
+ getProfile(name: string): DebugProfile | undefined;
50
+ /**
51
+ * Get all profile names
52
+ */
53
+ getProfileNames(): string[];
54
+ /**
55
+ * Get all profiles
56
+ */
57
+ getAllProfiles(): DebugProfile[];
58
+ /**
59
+ * Update a profile
60
+ */
61
+ updateProfile(name: string, updates: Partial<DebugProfile>): boolean;
62
+ /**
63
+ * Delete a profile
64
+ */
65
+ deleteProfile(name: string): boolean;
66
+ /**
67
+ * Set the active profile
68
+ */
69
+ setActiveProfile(name: string): boolean;
70
+ /**
71
+ * Get the active profile
72
+ */
73
+ getActiveProfile(): DebugProfile | null;
74
+ /**
75
+ * Save all profiles to disk
76
+ */
77
+ saveAllProfiles(): Promise<void>;
78
+ /**
79
+ * Load profiles from disk
80
+ */
81
+ loadProfiles(): Promise<void>;
82
+ /**
83
+ * Save a single profile to its own file
84
+ */
85
+ saveProfile(name: string): Promise<void>;
86
+ /**
87
+ * Load a profile from file
88
+ */
89
+ loadProfile(filePath: string): Promise<DebugProfile>;
90
+ /**
91
+ * Export profile as JSON string
92
+ */
93
+ exportProfile(name: string): string | null;
94
+ /**
95
+ * Import profile from JSON string
96
+ */
97
+ importProfile(json: string): DebugProfile;
98
+ /**
99
+ * Clone a profile
100
+ */
101
+ cloneProfile(sourceName: string, newName: string): DebugProfile | null;
102
+ }