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.
- package/LICENSE +21 -0
- package/README.md +341 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/dbgp/connection.d.ts +52 -0
- package/dist/dbgp/connection.js +362 -0
- package/dist/dbgp/connection.js.map +1 -0
- package/dist/dbgp/index.d.ts +3 -0
- package/dist/dbgp/index.js +4 -0
- package/dist/dbgp/index.js.map +1 -0
- package/dist/dbgp/server.d.ts +34 -0
- package/dist/dbgp/server.js +94 -0
- package/dist/dbgp/server.js.map +1 -0
- package/dist/dbgp/types.d.ts +112 -0
- package/dist/dbgp/types.js +28 -0
- package/dist/dbgp/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/session/code-coverage.d.ts +94 -0
- package/dist/session/code-coverage.js +226 -0
- package/dist/session/code-coverage.js.map +1 -0
- package/dist/session/debug-config.d.ts +102 -0
- package/dist/session/debug-config.js +194 -0
- package/dist/session/debug-config.js.map +1 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.js +11 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/logpoint-manager.d.ts +94 -0
- package/dist/session/logpoint-manager.js +167 -0
- package/dist/session/logpoint-manager.js.map +1 -0
- package/dist/session/manager.d.ts +41 -0
- package/dist/session/manager.js +135 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/profiler.d.ts +89 -0
- package/dist/session/profiler.js +191 -0
- package/dist/session/profiler.js.map +1 -0
- package/dist/session/request-context.d.ts +50 -0
- package/dist/session/request-context.js +182 -0
- package/dist/session/request-context.js.map +1 -0
- package/dist/session/session-export.d.ts +83 -0
- package/dist/session/session-export.js +320 -0
- package/dist/session/session-export.js.map +1 -0
- package/dist/session/session.d.ts +92 -0
- package/dist/session/session.js +369 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/step-filter.d.ts +81 -0
- package/dist/session/step-filter.js +174 -0
- package/dist/session/step-filter.js.map +1 -0
- package/dist/session/watch-manager.d.ts +64 -0
- package/dist/session/watch-manager.js +137 -0
- package/dist/session/watch-manager.js.map +1 -0
- package/dist/tools/advanced.d.ts +26 -0
- package/dist/tools/advanced.js +502 -0
- package/dist/tools/advanced.js.map +1 -0
- package/dist/tools/breakpoints.d.ts +6 -0
- package/dist/tools/breakpoints.js +308 -0
- package/dist/tools/breakpoints.js.map +1 -0
- package/dist/tools/execution.d.ts +6 -0
- package/dist/tools/execution.js +283 -0
- package/dist/tools/execution.js.map +1 -0
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.js +44 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/inspection.d.ts +7 -0
- package/dist/tools/inspection.js +431 -0
- package/dist/tools/inspection.js.map +1 -0
- package/dist/tools/session.d.ts +6 -0
- package/dist/tools/session.js +164 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +47 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path-mapper.d.ts +13 -0
- package/dist/utils/path-mapper.js +56 -0
- package/dist/utils/path-mapper.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug Configuration Manager
|
|
3
|
+
* Saves and restores debug configurations (breakpoints, watches, filters, etc.)
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs/promises';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
export class DebugConfigManager {
|
|
9
|
+
profiles = new Map();
|
|
10
|
+
configDir;
|
|
11
|
+
activeProfileName = null;
|
|
12
|
+
constructor(configDir) {
|
|
13
|
+
this.configDir = configDir || path.join(process.cwd(), '.xdebug-mcp');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a new debug profile
|
|
17
|
+
*/
|
|
18
|
+
createProfile(name, description) {
|
|
19
|
+
const profile = {
|
|
20
|
+
name,
|
|
21
|
+
description,
|
|
22
|
+
createdAt: new Date(),
|
|
23
|
+
updatedAt: new Date(),
|
|
24
|
+
breakpoints: [],
|
|
25
|
+
watchExpressions: [],
|
|
26
|
+
logpoints: [],
|
|
27
|
+
stepFilters: [],
|
|
28
|
+
settings: {},
|
|
29
|
+
};
|
|
30
|
+
this.profiles.set(name, profile);
|
|
31
|
+
logger.info(`Debug profile created: ${name}`);
|
|
32
|
+
return profile;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get a profile by name
|
|
36
|
+
*/
|
|
37
|
+
getProfile(name) {
|
|
38
|
+
return this.profiles.get(name);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get all profile names
|
|
42
|
+
*/
|
|
43
|
+
getProfileNames() {
|
|
44
|
+
return Array.from(this.profiles.keys());
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get all profiles
|
|
48
|
+
*/
|
|
49
|
+
getAllProfiles() {
|
|
50
|
+
return Array.from(this.profiles.values());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Update a profile
|
|
54
|
+
*/
|
|
55
|
+
updateProfile(name, updates) {
|
|
56
|
+
const profile = this.profiles.get(name);
|
|
57
|
+
if (!profile)
|
|
58
|
+
return false;
|
|
59
|
+
Object.assign(profile, updates, { updatedAt: new Date() });
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Delete a profile
|
|
64
|
+
*/
|
|
65
|
+
deleteProfile(name) {
|
|
66
|
+
if (this.activeProfileName === name) {
|
|
67
|
+
this.activeProfileName = null;
|
|
68
|
+
}
|
|
69
|
+
return this.profiles.delete(name);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Set the active profile
|
|
73
|
+
*/
|
|
74
|
+
setActiveProfile(name) {
|
|
75
|
+
if (this.profiles.has(name)) {
|
|
76
|
+
this.activeProfileName = name;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the active profile
|
|
83
|
+
*/
|
|
84
|
+
getActiveProfile() {
|
|
85
|
+
if (this.activeProfileName) {
|
|
86
|
+
return this.profiles.get(this.activeProfileName) || null;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Save all profiles to disk
|
|
92
|
+
*/
|
|
93
|
+
async saveAllProfiles() {
|
|
94
|
+
try {
|
|
95
|
+
await fs.mkdir(this.configDir, { recursive: true });
|
|
96
|
+
const data = {
|
|
97
|
+
activeProfile: this.activeProfileName,
|
|
98
|
+
profiles: Array.from(this.profiles.entries()).map(([, profile]) => profile),
|
|
99
|
+
};
|
|
100
|
+
const filePath = path.join(this.configDir, 'profiles.json');
|
|
101
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
102
|
+
logger.info(`Saved ${this.profiles.size} profiles to ${filePath}`);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
logger.error('Failed to save profiles:', error);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Load profiles from disk
|
|
111
|
+
*/
|
|
112
|
+
async loadProfiles() {
|
|
113
|
+
try {
|
|
114
|
+
const filePath = path.join(this.configDir, 'profiles.json');
|
|
115
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
116
|
+
const data = JSON.parse(content);
|
|
117
|
+
this.profiles.clear();
|
|
118
|
+
for (const profile of data.profiles || []) {
|
|
119
|
+
this.profiles.set(profile.name, {
|
|
120
|
+
...profile,
|
|
121
|
+
createdAt: new Date(profile.createdAt),
|
|
122
|
+
updatedAt: new Date(profile.updatedAt),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
this.activeProfileName = data.activeProfile || null;
|
|
126
|
+
logger.info(`Loaded ${this.profiles.size} profiles from ${filePath}`);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code !== 'ENOENT') {
|
|
130
|
+
logger.error('Failed to load profiles:', error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Save a single profile to its own file
|
|
136
|
+
*/
|
|
137
|
+
async saveProfile(name) {
|
|
138
|
+
const profile = this.profiles.get(name);
|
|
139
|
+
if (!profile) {
|
|
140
|
+
throw new Error(`Profile not found: ${name}`);
|
|
141
|
+
}
|
|
142
|
+
await fs.mkdir(this.configDir, { recursive: true });
|
|
143
|
+
const filePath = path.join(this.configDir, `${name}.profile.json`);
|
|
144
|
+
await fs.writeFile(filePath, JSON.stringify(profile, null, 2), 'utf8');
|
|
145
|
+
logger.info(`Saved profile to ${filePath}`);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Load a profile from file
|
|
149
|
+
*/
|
|
150
|
+
async loadProfile(filePath) {
|
|
151
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
152
|
+
const profile = JSON.parse(content);
|
|
153
|
+
profile.createdAt = new Date(profile.createdAt);
|
|
154
|
+
profile.updatedAt = new Date(profile.updatedAt);
|
|
155
|
+
this.profiles.set(profile.name, profile);
|
|
156
|
+
return profile;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Export profile as JSON string
|
|
160
|
+
*/
|
|
161
|
+
exportProfile(name) {
|
|
162
|
+
const profile = this.profiles.get(name);
|
|
163
|
+
if (!profile)
|
|
164
|
+
return null;
|
|
165
|
+
return JSON.stringify(profile, null, 2);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Import profile from JSON string
|
|
169
|
+
*/
|
|
170
|
+
importProfile(json) {
|
|
171
|
+
const profile = JSON.parse(json);
|
|
172
|
+
profile.createdAt = new Date(profile.createdAt);
|
|
173
|
+
profile.updatedAt = new Date(profile.updatedAt);
|
|
174
|
+
this.profiles.set(profile.name, profile);
|
|
175
|
+
return profile;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Clone a profile
|
|
179
|
+
*/
|
|
180
|
+
cloneProfile(sourceName, newName) {
|
|
181
|
+
const source = this.profiles.get(sourceName);
|
|
182
|
+
if (!source)
|
|
183
|
+
return null;
|
|
184
|
+
const clone = {
|
|
185
|
+
...JSON.parse(JSON.stringify(source)),
|
|
186
|
+
name: newName,
|
|
187
|
+
createdAt: new Date(),
|
|
188
|
+
updatedAt: new Date(),
|
|
189
|
+
};
|
|
190
|
+
this.profiles.set(newName, clone);
|
|
191
|
+
return clone;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=debug-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-config.js","sourceRoot":"","sources":["../../src/session/debug-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAoC5C,MAAM,OAAO,kBAAkB;IACrB,QAAQ,GAA8B,IAAI,GAAG,EAAE,CAAC;IAChD,SAAS,CAAS;IAClB,iBAAiB,GAAkB,IAAI,CAAC;IAEhD,YAAY,SAAkB;QAC5B,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;IACxE,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY,EAAE,WAAoB;QAC9C,MAAM,OAAO,GAAiB;YAC5B,IAAI;YACJ,WAAW;YACX,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,WAAW,EAAE,EAAE;YACf,gBAAgB,EAAE,EAAE;YACpB,SAAS,EAAE,EAAE;YACb,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,EAAE;SACb,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY,EAAE,OAA8B;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAE3B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACpC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAChC,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,IAAY;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAC;QAC3D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,IAAI,GAAG;gBACX,aAAa,EAAE,IAAI,CAAC,iBAAiB;gBACrC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;aAC5E,CAAC;YAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAC5D,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACpE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,IAAI,gBAAgB,QAAQ,EAAE,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEjC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;gBAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE;oBAC9B,GAAG,OAAO;oBACV,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;oBACtC,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;iBACvC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,QAAQ,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,eAAe,CAAC,CAAC;QACnE,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACvE,MAAM,CAAC,IAAI,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB;QAChC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QACpD,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;QACjD,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,UAAkB,EAAE,OAAe;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,KAAK,GAAiB;YAC1B,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE;SACtB,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './session.js';
|
|
2
|
+
export * from './manager.js';
|
|
3
|
+
export * from './watch-manager.js';
|
|
4
|
+
export * from './logpoint-manager.js';
|
|
5
|
+
export * from './profiler.js';
|
|
6
|
+
export * from './request-context.js';
|
|
7
|
+
export * from './step-filter.js';
|
|
8
|
+
export * from './debug-config.js';
|
|
9
|
+
export * from './code-coverage.js';
|
|
10
|
+
export * from './session-export.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './session.js';
|
|
2
|
+
export * from './manager.js';
|
|
3
|
+
export * from './watch-manager.js';
|
|
4
|
+
export * from './logpoint-manager.js';
|
|
5
|
+
export * from './profiler.js';
|
|
6
|
+
export * from './request-context.js';
|
|
7
|
+
export * from './step-filter.js';
|
|
8
|
+
export * from './debug-config.js';
|
|
9
|
+
export * from './code-coverage.js';
|
|
10
|
+
export * from './session-export.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logpoint Manager
|
|
3
|
+
* Manages logpoints - breakpoints that log without stopping execution.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { DebugSession } from './session.js';
|
|
7
|
+
export interface Logpoint {
|
|
8
|
+
id: string;
|
|
9
|
+
breakpointId?: string;
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
message: string;
|
|
13
|
+
condition?: string;
|
|
14
|
+
hitCount: number;
|
|
15
|
+
lastHitAt?: Date;
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
logHistory: LogEntry[];
|
|
19
|
+
}
|
|
20
|
+
export interface LogEntry {
|
|
21
|
+
timestamp: Date;
|
|
22
|
+
message: string;
|
|
23
|
+
variables: Record<string, unknown>;
|
|
24
|
+
stackDepth: number;
|
|
25
|
+
}
|
|
26
|
+
export interface LogpointHit {
|
|
27
|
+
logpoint: Logpoint;
|
|
28
|
+
entry: LogEntry;
|
|
29
|
+
}
|
|
30
|
+
export declare class LogpointManager extends EventEmitter {
|
|
31
|
+
private logpoints;
|
|
32
|
+
private logpointIdCounter;
|
|
33
|
+
private maxHistoryPerLogpoint;
|
|
34
|
+
constructor();
|
|
35
|
+
/**
|
|
36
|
+
* Create a logpoint
|
|
37
|
+
* @param file File path
|
|
38
|
+
* @param line Line number
|
|
39
|
+
* @param message Message template with {varName} placeholders
|
|
40
|
+
* @param condition Optional condition
|
|
41
|
+
*/
|
|
42
|
+
createLogpoint(file: string, line: number, message: string, condition?: string): Logpoint;
|
|
43
|
+
removeLogpoint(id: string): boolean;
|
|
44
|
+
getLogpoint(id: string): Logpoint | undefined;
|
|
45
|
+
getAllLogpoints(): Logpoint[];
|
|
46
|
+
/**
|
|
47
|
+
* Find logpoint by file and line
|
|
48
|
+
*/
|
|
49
|
+
findLogpoint(file: string, line: number): Logpoint | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Process a logpoint hit - evaluate and log the message
|
|
52
|
+
*/
|
|
53
|
+
processHit(session: DebugSession, logpoint: Logpoint, stackDepth?: number): Promise<LogEntry>;
|
|
54
|
+
/**
|
|
55
|
+
* Get hit statistics for all logpoints
|
|
56
|
+
*/
|
|
57
|
+
getStatistics(): {
|
|
58
|
+
totalLogpoints: number;
|
|
59
|
+
totalHits: number;
|
|
60
|
+
logpoints: Array<{
|
|
61
|
+
id: string;
|
|
62
|
+
file: string;
|
|
63
|
+
line: number;
|
|
64
|
+
hitCount: number;
|
|
65
|
+
lastHitAt?: Date;
|
|
66
|
+
}>;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Get log history for a specific logpoint
|
|
70
|
+
*/
|
|
71
|
+
getLogHistory(id: string, limit?: number): LogEntry[];
|
|
72
|
+
/**
|
|
73
|
+
* Clear log history for all logpoints
|
|
74
|
+
*/
|
|
75
|
+
clearHistory(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Export configuration
|
|
78
|
+
*/
|
|
79
|
+
exportConfig(): Array<{
|
|
80
|
+
file: string;
|
|
81
|
+
line: number;
|
|
82
|
+
message: string;
|
|
83
|
+
condition?: string;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Import configuration
|
|
87
|
+
*/
|
|
88
|
+
importConfig(config: Array<{
|
|
89
|
+
file: string;
|
|
90
|
+
line: number;
|
|
91
|
+
message: string;
|
|
92
|
+
condition?: string;
|
|
93
|
+
}>): void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logpoint Manager
|
|
3
|
+
* Manages logpoints - breakpoints that log without stopping execution.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
export class LogpointManager extends EventEmitter {
|
|
8
|
+
logpoints = new Map();
|
|
9
|
+
logpointIdCounter = 0;
|
|
10
|
+
maxHistoryPerLogpoint = 100;
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a logpoint
|
|
16
|
+
* @param file File path
|
|
17
|
+
* @param line Line number
|
|
18
|
+
* @param message Message template with {varName} placeholders
|
|
19
|
+
* @param condition Optional condition
|
|
20
|
+
*/
|
|
21
|
+
createLogpoint(file, line, message, condition) {
|
|
22
|
+
const id = `logpoint_${++this.logpointIdCounter}`;
|
|
23
|
+
const logpoint = {
|
|
24
|
+
id,
|
|
25
|
+
file,
|
|
26
|
+
line,
|
|
27
|
+
message,
|
|
28
|
+
condition,
|
|
29
|
+
hitCount: 0,
|
|
30
|
+
createdAt: new Date(),
|
|
31
|
+
enabled: true,
|
|
32
|
+
logHistory: [],
|
|
33
|
+
};
|
|
34
|
+
this.logpoints.set(id, logpoint);
|
|
35
|
+
logger.debug(`Logpoint created: ${id} at ${file}:${line}`);
|
|
36
|
+
return logpoint;
|
|
37
|
+
}
|
|
38
|
+
removeLogpoint(id) {
|
|
39
|
+
const removed = this.logpoints.delete(id);
|
|
40
|
+
if (removed) {
|
|
41
|
+
logger.debug(`Logpoint removed: ${id}`);
|
|
42
|
+
}
|
|
43
|
+
return removed;
|
|
44
|
+
}
|
|
45
|
+
getLogpoint(id) {
|
|
46
|
+
return this.logpoints.get(id);
|
|
47
|
+
}
|
|
48
|
+
getAllLogpoints() {
|
|
49
|
+
return Array.from(this.logpoints.values());
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find logpoint by file and line
|
|
53
|
+
*/
|
|
54
|
+
findLogpoint(file, line) {
|
|
55
|
+
for (const lp of this.logpoints.values()) {
|
|
56
|
+
if (lp.file === file && lp.line === line) {
|
|
57
|
+
return lp;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Process a logpoint hit - evaluate and log the message
|
|
64
|
+
*/
|
|
65
|
+
async processHit(session, logpoint, stackDepth = 0) {
|
|
66
|
+
// Extract variable names from message template
|
|
67
|
+
const varPattern = /\{([^}]+)\}/g;
|
|
68
|
+
const variables = {};
|
|
69
|
+
let evaluatedMessage = logpoint.message;
|
|
70
|
+
// Find all {varName} placeholders
|
|
71
|
+
let match;
|
|
72
|
+
const varNames = [];
|
|
73
|
+
while ((match = varPattern.exec(logpoint.message)) !== null) {
|
|
74
|
+
varNames.push(match[1]);
|
|
75
|
+
}
|
|
76
|
+
// Evaluate each variable
|
|
77
|
+
for (const varName of varNames) {
|
|
78
|
+
try {
|
|
79
|
+
const result = await session.evaluate(varName, stackDepth);
|
|
80
|
+
const value = result?.value ?? result?.type ?? 'undefined';
|
|
81
|
+
variables[varName] = value;
|
|
82
|
+
evaluatedMessage = evaluatedMessage.replace(`{${varName}}`, String(value));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
variables[varName] = '<error>';
|
|
86
|
+
evaluatedMessage = evaluatedMessage.replace(`{${varName}}`, '<error>');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const entry = {
|
|
90
|
+
timestamp: new Date(),
|
|
91
|
+
message: evaluatedMessage,
|
|
92
|
+
variables,
|
|
93
|
+
stackDepth,
|
|
94
|
+
};
|
|
95
|
+
// Update logpoint state
|
|
96
|
+
logpoint.hitCount++;
|
|
97
|
+
logpoint.lastHitAt = new Date();
|
|
98
|
+
logpoint.logHistory.push(entry);
|
|
99
|
+
// Trim history if too large
|
|
100
|
+
if (logpoint.logHistory.length > this.maxHistoryPerLogpoint) {
|
|
101
|
+
logpoint.logHistory = logpoint.logHistory.slice(-this.maxHistoryPerLogpoint);
|
|
102
|
+
}
|
|
103
|
+
this.emit('logpointHit', { logpoint, entry });
|
|
104
|
+
logger.info(`[Logpoint ${logpoint.id}] ${evaluatedMessage}`);
|
|
105
|
+
return entry;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get hit statistics for all logpoints
|
|
109
|
+
*/
|
|
110
|
+
getStatistics() {
|
|
111
|
+
const logpoints = this.getAllLogpoints();
|
|
112
|
+
const totalHits = logpoints.reduce((sum, lp) => sum + lp.hitCount, 0);
|
|
113
|
+
return {
|
|
114
|
+
totalLogpoints: logpoints.length,
|
|
115
|
+
totalHits,
|
|
116
|
+
logpoints: logpoints.map((lp) => ({
|
|
117
|
+
id: lp.id,
|
|
118
|
+
file: lp.file,
|
|
119
|
+
line: lp.line,
|
|
120
|
+
hitCount: lp.hitCount,
|
|
121
|
+
lastHitAt: lp.lastHitAt,
|
|
122
|
+
})),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get log history for a specific logpoint
|
|
127
|
+
*/
|
|
128
|
+
getLogHistory(id, limit) {
|
|
129
|
+
const logpoint = this.logpoints.get(id);
|
|
130
|
+
if (!logpoint)
|
|
131
|
+
return [];
|
|
132
|
+
const history = logpoint.logHistory;
|
|
133
|
+
if (limit && limit < history.length) {
|
|
134
|
+
return history.slice(-limit);
|
|
135
|
+
}
|
|
136
|
+
return history;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Clear log history for all logpoints
|
|
140
|
+
*/
|
|
141
|
+
clearHistory() {
|
|
142
|
+
for (const lp of this.logpoints.values()) {
|
|
143
|
+
lp.logHistory = [];
|
|
144
|
+
lp.hitCount = 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Export configuration
|
|
149
|
+
*/
|
|
150
|
+
exportConfig() {
|
|
151
|
+
return this.getAllLogpoints().map((lp) => ({
|
|
152
|
+
file: lp.file,
|
|
153
|
+
line: lp.line,
|
|
154
|
+
message: lp.message,
|
|
155
|
+
condition: lp.condition,
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Import configuration
|
|
160
|
+
*/
|
|
161
|
+
importConfig(config) {
|
|
162
|
+
for (const item of config) {
|
|
163
|
+
this.createLogpoint(item.file, item.line, item.message, item.condition);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=logpoint-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logpoint-manager.js","sourceRoot":"","sources":["../../src/session/logpoint-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager
|
|
3
|
+
* Manages multiple concurrent PHP debug sessions.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { DbgpConnection } from '../dbgp/connection.js';
|
|
7
|
+
import { DebugSession, SessionState } from './session.js';
|
|
8
|
+
export interface SessionManagerEvents {
|
|
9
|
+
sessionCreated: (session: DebugSession) => void;
|
|
10
|
+
sessionEnded: (sessionId: string) => void;
|
|
11
|
+
sessionStateChange: (sessionId: string, state: SessionState) => void;
|
|
12
|
+
}
|
|
13
|
+
export declare class SessionManager extends EventEmitter {
|
|
14
|
+
private sessions;
|
|
15
|
+
private activeSessionId;
|
|
16
|
+
constructor();
|
|
17
|
+
createSession(connection: DbgpConnection): Promise<DebugSession>;
|
|
18
|
+
getSession(id: string): DebugSession | undefined;
|
|
19
|
+
getAllSessions(): DebugSession[];
|
|
20
|
+
getSessionStates(): SessionState[];
|
|
21
|
+
getActiveSession(): DebugSession | undefined;
|
|
22
|
+
setActiveSession(id: string): boolean;
|
|
23
|
+
getActiveSessionId(): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Get a session by ID or return the active session if no ID provided.
|
|
26
|
+
* This is the primary method for tools to get a session.
|
|
27
|
+
*/
|
|
28
|
+
resolveSession(sessionId?: string): DebugSession | undefined;
|
|
29
|
+
closeSession(id: string): boolean;
|
|
30
|
+
closeAllSessions(): void;
|
|
31
|
+
getSessionCount(): number;
|
|
32
|
+
hasActiveSessions(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Find sessions by file being debugged
|
|
35
|
+
*/
|
|
36
|
+
findSessionsByFile(filename: string): DebugSession[];
|
|
37
|
+
/**
|
|
38
|
+
* Find sessions by IDE key
|
|
39
|
+
*/
|
|
40
|
+
findSessionsByIdeKey(ideKey: string): DebugSession[];
|
|
41
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager
|
|
3
|
+
* Manages multiple concurrent PHP debug sessions.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { DebugSession } from './session.js';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
export class SessionManager extends EventEmitter {
|
|
9
|
+
sessions = new Map();
|
|
10
|
+
activeSessionId = null;
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
async createSession(connection) {
|
|
15
|
+
const session = new DebugSession(connection);
|
|
16
|
+
// Initialize the session (negotiate features)
|
|
17
|
+
await session.initialize();
|
|
18
|
+
this.sessions.set(session.id, session);
|
|
19
|
+
// Track state changes
|
|
20
|
+
session.on('stateChange', (state) => {
|
|
21
|
+
this.emit('sessionStateChange', session.id, state);
|
|
22
|
+
// Auto-select as active if it's in break state and no active session
|
|
23
|
+
if (state.status === 'break' && !this.activeSessionId) {
|
|
24
|
+
this.activeSessionId = session.id;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
// Handle session close
|
|
28
|
+
session.on('close', () => {
|
|
29
|
+
this.sessions.delete(session.id);
|
|
30
|
+
if (this.activeSessionId === session.id) {
|
|
31
|
+
this.activeSessionId = null;
|
|
32
|
+
// Select another session if available
|
|
33
|
+
const next = this.sessions.values().next().value;
|
|
34
|
+
if (next) {
|
|
35
|
+
this.activeSessionId = next.id;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
this.emit('sessionEnded', session.id);
|
|
39
|
+
logger.info(`Session ended: ${session.id}`);
|
|
40
|
+
});
|
|
41
|
+
// Set as active if it's the first session
|
|
42
|
+
if (!this.activeSessionId) {
|
|
43
|
+
this.activeSessionId = session.id;
|
|
44
|
+
}
|
|
45
|
+
this.emit('sessionCreated', session);
|
|
46
|
+
logger.info(`Session created: ${session.id}`);
|
|
47
|
+
return session;
|
|
48
|
+
}
|
|
49
|
+
getSession(id) {
|
|
50
|
+
return this.sessions.get(id);
|
|
51
|
+
}
|
|
52
|
+
getAllSessions() {
|
|
53
|
+
return Array.from(this.sessions.values());
|
|
54
|
+
}
|
|
55
|
+
getSessionStates() {
|
|
56
|
+
return this.getAllSessions().map((s) => s.getState());
|
|
57
|
+
}
|
|
58
|
+
getActiveSession() {
|
|
59
|
+
if (this.activeSessionId) {
|
|
60
|
+
return this.sessions.get(this.activeSessionId);
|
|
61
|
+
}
|
|
62
|
+
// Return first session in 'break' state, or first available
|
|
63
|
+
for (const session of this.sessions.values()) {
|
|
64
|
+
if (session.status === 'break') {
|
|
65
|
+
this.activeSessionId = session.id;
|
|
66
|
+
return session;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Return first available session
|
|
70
|
+
const first = this.sessions.values().next().value;
|
|
71
|
+
if (first) {
|
|
72
|
+
this.activeSessionId = first.id;
|
|
73
|
+
}
|
|
74
|
+
return first;
|
|
75
|
+
}
|
|
76
|
+
setActiveSession(id) {
|
|
77
|
+
if (this.sessions.has(id)) {
|
|
78
|
+
this.activeSessionId = id;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
getActiveSessionId() {
|
|
84
|
+
return this.activeSessionId;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get a session by ID or return the active session if no ID provided.
|
|
88
|
+
* This is the primary method for tools to get a session.
|
|
89
|
+
*/
|
|
90
|
+
resolveSession(sessionId) {
|
|
91
|
+
if (sessionId) {
|
|
92
|
+
return this.getSession(sessionId);
|
|
93
|
+
}
|
|
94
|
+
return this.getActiveSession();
|
|
95
|
+
}
|
|
96
|
+
closeSession(id) {
|
|
97
|
+
const session = this.sessions.get(id);
|
|
98
|
+
if (session) {
|
|
99
|
+
session.close();
|
|
100
|
+
// The 'close' event handler will remove it from the map
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
closeAllSessions() {
|
|
106
|
+
for (const session of this.sessions.values()) {
|
|
107
|
+
session.close();
|
|
108
|
+
}
|
|
109
|
+
// The 'close' event handlers will clear the map
|
|
110
|
+
}
|
|
111
|
+
getSessionCount() {
|
|
112
|
+
return this.sessions.size;
|
|
113
|
+
}
|
|
114
|
+
hasActiveSessions() {
|
|
115
|
+
return this.sessions.size > 0;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Find sessions by file being debugged
|
|
119
|
+
*/
|
|
120
|
+
findSessionsByFile(filename) {
|
|
121
|
+
const normalized = filename.toLowerCase();
|
|
122
|
+
return this.getAllSessions().filter((session) => {
|
|
123
|
+
const initFile = session.initPacket?.fileUri?.toLowerCase() || '';
|
|
124
|
+
const currentFile = session.currentFile?.toLowerCase() || '';
|
|
125
|
+
return initFile.includes(normalized) || currentFile.includes(normalized);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Find sessions by IDE key
|
|
130
|
+
*/
|
|
131
|
+
findSessionsByIdeKey(ideKey) {
|
|
132
|
+
return this.getAllSessions().filter((session) => session.initPacket?.ideKey === ideKey);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=manager.js.map
|